Add managers for galaxy/globular details to avoid destructor issues on exit

pull/1288/head
Andrew Tribick 2021-12-29 19:30:49 +01:00 committed by ajtribick
parent c632aea62d
commit fd9ea94377
2 changed files with 136 additions and 82 deletions

View File

@ -53,9 +53,6 @@ bool operator<(const Blob& b1, const Blob& b2)
using BlobVector = std::vector<Blob>;
} // end unnamed namespace
class GalacticForm
{
public:
@ -63,10 +60,6 @@ public:
Eigen::Vector3f scale;
};
namespace
{
constexpr int width = 128;
constexpr int height = 128;
constexpr unsigned int GALAXY_POINTS = 3500;
@ -78,11 +71,6 @@ constexpr float MAX_SPIRAL_THICKNESS = 0.06f;
bool formsInitialized = false;
constexpr std::size_t GalacticFormsReserve = 32;
std::vector<std::optional<GalacticForm>> galacticForms;
std::map<fs::path, std::size_t> customForms;
Texture* galaxyTex = nullptr;
Texture* colorTex = nullptr;
@ -258,7 +246,50 @@ std::optional<GalacticForm> buildGalacticForm(const fs::path& filename)
return galacticForm;
}
void initializeForms()
class GalacticFormManager
{
private:
static constexpr std::size_t GalacticFormsReserve = 32;
public:
GalacticFormManager()
{
initializeStandardForms();
}
const GalacticForm* getForm(std::size_t) const;
std::size_t getCustomForm(const fs::path& path);
private:
void initializeStandardForms();
std::vector<std::optional<GalacticForm>> galacticForms{ };
std::map<fs::path, std::size_t> customForms{ };
};
const GalacticForm* GalacticFormManager::getForm(std::size_t form) const
{
assert(form < galacticForms.size());
return galacticForms[form].has_value()
? &*galacticForms[form]
: nullptr;
}
std::size_t GalacticFormManager::getCustomForm(const fs::path& path)
{
auto iter = customForms.find(path);
if (iter != customForms.end())
{
return iter->second;
}
std::size_t result = galacticForms.size();
customForms[path] = result;
galacticForms.push_back(buildGalacticForm(path));
return result;
}
void GalacticFormManager::initializeStandardForms()
{
// Irregular Galaxies
unsigned int galaxySize = GALAXY_POINTS, ip = 0;
@ -290,14 +321,12 @@ void initializeForms()
}
}
GalacticForm& irregularForm = *galacticForms.emplace_back(std::in_place);
irregularForm.blobs = std::move(irregularPoints);
irregularForm.scale = Eigen::Vector3f::Constant(0.5f);
std::optional<GalacticForm>& irregularForm = galacticForms.emplace_back(std::in_place);
irregularForm->blobs = std::move(irregularPoints);
irregularForm->scale = Eigen::Vector3f::Constant(0.5f);
// Spiral Galaxies, 7 classical Hubble types
galacticForms.reserve(GalacticFormsReserve);
galacticForms.push_back(buildGalacticForm("models/S0.png"));
galacticForms.push_back(buildGalacticForm("models/Sa.png"));
galacticForms.push_back(buildGalacticForm("models/Sb.png"));
@ -317,34 +346,27 @@ void initializeForms()
// note the correct x,y-alignment of 'ell' scaling!!
// build all elliptical templates from rescaling E0
galacticForms.push_back(buildGalacticForm("models/E0.png"));
if (!galacticForms.back().has_value()) { continue; }
GalacticForm& ellipticalForm = *galacticForms.back();
ellipticalForm.scale = Eigen::Vector3f(ell, ell, 1.0f);
for (Blob& blob : ellipticalForm.blobs)
std::optional<GalacticForm> ellipticalForm = buildGalacticForm("models/E0.png");
if (ellipticalForm.has_value())
{
blob.colorIndex = static_cast<unsigned int>(std::ceil(0.76f * static_cast<float>(blob.colorIndex)));
ellipticalForm->scale = Eigen::Vector3f(ell, ell, 1.0f);
for (Blob& blob : ellipticalForm->blobs)
{
blob.colorIndex = static_cast<unsigned int>(std::ceil(0.76f * static_cast<float>(blob.colorIndex)));
}
}
galacticForms.push_back(std::move(ellipticalForm));
}
formsInitialized = true;
}
std::size_t customForm(const fs::path& path)
GalacticFormManager* getGalacticFormManager()
{
auto iter = customForms.find(path);
if (iter != customForms.end())
{
return iter->second;
}
std::size_t result = galacticForms.size();
customForms[path] = result;
galacticForms.push_back(buildGalacticForm(path));
return result;
static GalacticFormManager* galacticFormManager = new GalacticFormManager();
return galacticFormManager;
}
} // end unnamed namespace
@ -378,16 +400,13 @@ void Galaxy::setType(const std::string& typeStr)
void Galaxy::setForm(const std::string& customTmpName)
{
if (!formsInitialized)
initializeForms();
if (customTmpName.empty())
{
form = static_cast<std::size_t>(type);
}
else
{
form = customForm(fs::path("models") / customTmpName);
form = getGalacticFormManager()->getCustomForm(fs::path("models") / customTmpName);
}
}
@ -405,22 +424,20 @@ bool Galaxy::pick(const Eigen::ParametrizedLine<double, 3>& ray,
double& distanceToPicker,
double& cosAngleToBoundCenter) const
{
if (!galacticForms[form].has_value() || !isVisible())
return false;
GalacticForm& galacticForm = *galacticForms[form];
const GalacticForm* galacticForm = getGalacticFormManager()->getForm(form);
if (galacticForm == nullptr || !isVisible()) { return false; }
// The ellipsoid should be slightly larger to compensate for the fact
// that blobs are considered points when galaxies are built, but have size
// when they are drawn.
float yscale = (type > GalaxyType::Irr && type < GalaxyType::E0)
? MAX_SPIRAL_THICKNESS
: galacticForm.scale.y() + RADIUS_CORRECTION;
Eigen::Vector3d ellipsoidAxes(getRadius()*(galacticForm.scale.x() + RADIUS_CORRECTION),
: galacticForm->scale.y() + RADIUS_CORRECTION;
Eigen::Vector3d ellipsoidAxes(getRadius()*(galacticForm->scale.x() + RADIUS_CORRECTION),
getRadius()* yscale,
getRadius()*(galacticForm.scale.z() + RADIUS_CORRECTION));
getRadius()*(galacticForm->scale.z() + RADIUS_CORRECTION));
Eigen::Matrix3d rotation = getOrientation().cast<double>().toRotationMatrix();
return celmath::testIntersection(
celmath::transformRay(Eigen::ParametrizedLine<double, 3>(ray.origin() - getPosition(), ray.direction()),
rotation),
@ -453,10 +470,8 @@ void Galaxy::render(const Eigen::Vector3f& offset,
const Matrices& ms,
Renderer* renderer)
{
if (!galacticForms[form].has_value())
return;
const GalacticForm& galacticForm = *galacticForms[form];
const GalacticForm* galacticForm = getGalacticFormManager()->getForm(form);
if (galacticForm == nullptr) { return; }
/* We'll first see if the galaxy's apparent size is big enough to
be noticeable on screen; if it's not we'll break right here,
@ -507,7 +522,7 @@ void Galaxy::render(const Eigen::Vector3f& offset,
v3.head(3) = viewMat * Eigen::Vector3f(-1, 1, 0) * size;
Eigen::Quaternionf orientation = getOrientation().conjugate();
Eigen::Matrix3f mScale = galacticForm.scale.asDiagonal() * size;
Eigen::Matrix3f mScale = galacticForm->scale.asDiagonal() * size;
Eigen::Matrix3f mLinear = orientation.toRotationMatrix() * mScale;
Eigen::Matrix4f m = Eigen::Matrix4f::Identity();
@ -516,7 +531,7 @@ void Galaxy::render(const Eigen::Vector3f& offset,
int pow2 = 1;
const BlobVector& points = galacticForm.blobs;
const BlobVector& points = galacticForm->blobs;
unsigned int nPoints = static_cast<unsigned int>(points.size() * std::clamp(getDetail(), 0.0f, 1.0f));
// corrections to avoid excessive brightening if viewed e.g. edge-on

View File

@ -45,8 +45,8 @@ struct GlobularForm
float radius_2d;
};
std::vector<Blob> gblobs;
Eigen::Vector3f scale;
std::vector<Blob> gblobs{ };
Eigen::Vector3f scale{ };
};
@ -330,9 +330,60 @@ GlobularForm buildGlobularForm(float c)
return globularForm;
}
std::vector<GlobularForm> initializeForms()
class GlobularInfoManager
{
public:
GlobularInfoManager()
{
initializeForms();
centerTex.fill(nullptr);
}
const GlobularForm* getForm(unsigned int) const;
Texture* getCenterTex(unsigned int);
Texture* getGlobularTex();
private:
void initializeForms();
std::array<GlobularForm, GlobularBuckets> globularForms{ };
std::array<Texture*, GlobularBuckets> centerTex{ };
Texture* globularTex{ nullptr };
};
const GlobularForm* GlobularInfoManager::getForm(unsigned int form) const
{
assert(form < globularForms.size());
return &globularForms[form];
}
Texture* GlobularInfoManager::getCenterTex(unsigned int form)
{
if(centerTex[form] == nullptr)
{
centerTex[form] = CreateProceduralTexture(cntrTexWidth, cntrTexHeight,
celestia::PixelFormat::RGBA,
centerCloudTexEval);
}
assert(centerTex[form] != nullptr);
return centerTex[form];
}
Texture* GlobularInfoManager::getGlobularTex()
{
if (globularTex == nullptr)
{
globularTex = CreateProceduralTexture(starTexWidth, starTexHeight,
celestia::PixelFormat::RGBA,
globularTextureEval);
}
assert(globularTex != nullptr);
return globularTex;
}
void GlobularInfoManager::initializeForms()
{
// Build RGB color table, using hue, saturation, value as input.
// Hue in degrees.
@ -373,16 +424,17 @@ std::vector<GlobularForm> initializeForms()
}
// Define globularForms corresponding to 8 different bins of King concentration c
std::vector<GlobularForm> globularForms;
globularForms.reserve(GlobularBuckets);
for (unsigned int ic = 0; ic <= 7; ++ic)
for (unsigned int ic = 0; ic < GlobularBuckets; ++ic)
{
float CBin = MinC + (static_cast<float>(ic) + 0.5f) * BinWidth;
globularForms.push_back(buildGlobularForm(CBin));
globularForms[ic] = buildGlobularForm(CBin);
}
}
return globularForms;
GlobularInfoManager* getGlobularInfoManager()
{
static GlobularInfoManager* globularInfoManager = new GlobularInfoManager();
return globularInfoManager;
}
} // end unnamed namespace
@ -454,8 +506,7 @@ void Globular::setConcentration(const float conc)
c = conc;
// For saving time, account for the c dependence via 8 bins only,
static const std::vector<GlobularForm> globularForms = initializeForms();
form = &globularForms[cSlot(conc)];
form = getGlobularInfoManager()->getForm(cSlot(conc));
recomputeTidalRadius();
}
@ -568,19 +619,7 @@ void Globular::render(const Eigen::Vector3f& offset,
RRatio = std::pow(10.0f, CBin);
XI = 1.0f / std::sqrt(1.0f + RRatio * RRatio);
static Texture* centerTex[GlobularBuckets] = {nullptr};
if(centerTex[ic] == nullptr)
{
centerTex[ic] = CreateProceduralTexture(cntrTexWidth, cntrTexHeight,
celestia::PixelFormat::RGBA,
centerCloudTexEval);
}
assert(centerTex[ic] != nullptr);
static Texture* globularTex = CreateProceduralTexture(starTexWidth, starTexHeight,
celestia::PixelFormat::RGBA,
globularTextureEval);
assert(globularTex != nullptr);
GlobularInfoManager* globularInfoManager = getGlobularInfoManager();
renderer->enableBlending();
renderer->setBlendingFactors(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@ -605,7 +644,7 @@ void Globular::render(const Eigen::Vector3f& offset,
}
tidalProg->use();
centerTex[ic]->bind();
globularInfoManager->getCenterTex(ic)->bind();
tidalProg->setMVPMatrices(*m.projection, *m.modelview);
@ -630,7 +669,7 @@ void Globular::render(const Eigen::Vector3f& offset,
globProg->use();
globularTex->bind();
globularInfoManager->getGlobularTex()->bind();
globProg->setMVPMatrices(*m.projection, *m.modelview);
// TODO: model view matrix should not be reset here
globProg->ModelViewMatrix = vecgl::translate(*m.modelview, offset);