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

View File

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