mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-11 14:14:01 -06:00
Don't include Voyager and Pioneer in the base asset as it takes too long to load Ensure that the webgui asset can load without the dashboard Fix scripting issue in Rosetta scene with trails Fix issue with Dashboards that would actually render one line too far down causing trouble with multiline text Set the render option for renderablebillboards to view direction by default as the normal mode has some issues (see #1342) Set more sensible maximum value for RenderablePlanesCloud Correctly show the number of significant digits in the altitude Replace setPropertyValue with setPropertyValueSingle when clicking on the friction "buttons" on screen Add a new script function hasProperty to check whether a property exits
1355 lines
46 KiB
C++
1355 lines
46 KiB
C++
/*****************************************************************************************
|
|
* *
|
|
* OpenSpace *
|
|
* *
|
|
* Copyright (c) 2014-2020 *
|
|
* *
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
|
* software and associated documentation files (the "Software"), to deal in the Software *
|
|
* without restriction, including without limitation the rights to use, copy, modify, *
|
|
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
|
* permit persons to whom the Software is furnished to do so, subject to the following *
|
|
* conditions: *
|
|
* *
|
|
* The above copyright notice and this permission notice shall be included in all copies *
|
|
* or substantial portions of the Software. *
|
|
* *
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
|
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
|
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
|
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
|
****************************************************************************************/
|
|
|
|
#include <modules/digitaluniverse/rendering/renderableplanescloud.h>
|
|
|
|
#include <modules/digitaluniverse/digitaluniversemodule.h>
|
|
#include <openspace/documentation/documentation.h>
|
|
#include <openspace/documentation/verifier.h>
|
|
#include <openspace/engine/globals.h>
|
|
#include <openspace/rendering/renderengine.h>
|
|
#include <openspace/util/updatestructures.h>
|
|
#include <ghoul/filesystem/filesystem.h>
|
|
#include <ghoul/font/fontmanager.h>
|
|
#include <ghoul/font/fontrenderer.h>
|
|
#include <ghoul/io/texture/texturereader.h>
|
|
#include <ghoul/logging/logmanager.h>
|
|
#include <ghoul/misc/profiling.h>
|
|
#include <ghoul/opengl/openglstatecache.h>
|
|
#include <ghoul/opengl/programobject.h>
|
|
#include <ghoul/opengl/texture.h>
|
|
#include <ghoul/opengl/textureunit.h>
|
|
#include <array>
|
|
#include <fstream>
|
|
#include <string>
|
|
|
|
namespace {
|
|
constexpr const char* _loggerCat = "RenderablePlanesCloud";
|
|
constexpr const char* ProgramObjectName = "RenderablePlanesCloud";
|
|
|
|
constexpr std::array<const char*, 4> UniformNames = {
|
|
"modelViewProjectionTransform", "alphaValue", "fadeInValue", "galaxyTexture"
|
|
};
|
|
|
|
constexpr const char* KeyFile = "File";
|
|
constexpr const char* keyUnit = "Unit";
|
|
constexpr const char* MeterUnit = "m";
|
|
constexpr const char* KilometerUnit = "Km";
|
|
constexpr const char* ParsecUnit = "pc";
|
|
constexpr const char* KiloparsecUnit = "Kpc";
|
|
constexpr const char* MegaparsecUnit = "Mpc";
|
|
constexpr const char* GigaparsecUnit = "Gpc";
|
|
constexpr const char* GigalightyearUnit = "Gly";
|
|
|
|
constexpr int8_t CurrentCacheVersion = 2;
|
|
constexpr double PARSEC = 0.308567756E17;
|
|
|
|
enum BlendMode {
|
|
BlendModeNormal = 0,
|
|
BlendModeAdditive
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo ScaleFactorInfo = {
|
|
"ScaleFactor",
|
|
"Scale Factor",
|
|
"This value is used as a multiplicative factor that is applied to the apparent "
|
|
"size of each point."
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo TextColorInfo = {
|
|
"TextColor",
|
|
"Text Color",
|
|
"The text color for the astronomical object."
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo TextOpacityInfo = {
|
|
"TextOpacity",
|
|
"Text Opacity",
|
|
"Determines the transparency of the text label, where 1 is completely opaque "
|
|
"and 0 fully transparent."
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo TextSizeInfo = {
|
|
"TextSize",
|
|
"Text Size",
|
|
"The text size for the astronomical object labels."
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo LabelFileInfo = {
|
|
"LabelFile",
|
|
"Label File",
|
|
"The path to the label file that contains information about the astronomical "
|
|
"objects being rendered."
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo LabelMinSizeInfo = {
|
|
"TextMinSize",
|
|
"Text Min Size",
|
|
"The minimal size (in pixels) of the text for the labels for the astronomical "
|
|
"objects being rendered."
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo LabelMaxSizeInfo = {
|
|
"TextMaxSize",
|
|
"Text Max Size",
|
|
"The maximum size (in pixels) of the text for the labels for the astronomical "
|
|
"objects being rendered."
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo DrawElementsInfo = {
|
|
"DrawElements",
|
|
"Draw Elements",
|
|
"Enables/Disables the drawing of the astronomical objects."
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo TransformationMatrixInfo = {
|
|
"TransformationMatrix",
|
|
"Transformation Matrix",
|
|
"Transformation matrix to be applied to each astronomical object."
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo BlendModeInfo = {
|
|
"BlendMode",
|
|
"Blending Mode",
|
|
"This determines the blending mode that is applied to this plane."
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo TexturePathInfo = {
|
|
"TexturePath",
|
|
"Texture Path",
|
|
"This value specifies the path for the textures in disk."
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo LuminosityInfo = {
|
|
"Luminosity",
|
|
"Luminosity variable",
|
|
"Datavar variable to control the luminosity/size of the astronomical objects."
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo ScaleLuminosityInfo = {
|
|
"ScaleLuminosity",
|
|
"ScaleLuminosity variable",
|
|
"Scaling control for the luminosity/size of the astronomical objects."
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo RenderOptionInfo = {
|
|
"RenderOption",
|
|
"Render Option",
|
|
"Debug option for rendering of billboards and texts."
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo FadeInDistancesInfo = {
|
|
"FadeInDistances",
|
|
"Fade-In Start and End Distances",
|
|
"These values determine the initial and final distances from the center of "
|
|
"our galaxy from which the astronomical object will start and end "
|
|
"fading-in."
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo DisableFadeInInfo = {
|
|
"DisableFadeIn",
|
|
"Disable Fade-in effect",
|
|
"Enables/Disables the Fade-in effect."
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo PlaneMinSizeInfo = {
|
|
"PlaneMinSize",
|
|
"Plane Min Size in Pixels",
|
|
"The min size (in pixels) for the plane representing the astronomical "
|
|
"object."
|
|
};
|
|
|
|
} // namespace
|
|
|
|
namespace openspace {
|
|
|
|
documentation::Documentation RenderablePlanesCloud::Documentation() {
|
|
using namespace documentation;
|
|
return {
|
|
"RenderablePlanesCloud",
|
|
"digitaluniverse_RenderablePlanesCloud",
|
|
{
|
|
{
|
|
"Type",
|
|
new StringEqualVerifier("RenderablePlanesCloud"),
|
|
Optional::No
|
|
},
|
|
{
|
|
KeyFile,
|
|
new StringVerifier,
|
|
Optional::Yes,
|
|
"The path to the SPECK file that contains information about the "
|
|
"astronomical object being rendered."
|
|
},
|
|
{
|
|
ScaleFactorInfo.identifier,
|
|
new DoubleVerifier,
|
|
Optional::Yes,
|
|
ScaleFactorInfo.description
|
|
},
|
|
{
|
|
TextColorInfo.identifier,
|
|
new DoubleVector3Verifier,
|
|
Optional::Yes,
|
|
TextColorInfo.description
|
|
},
|
|
{
|
|
TextOpacityInfo.identifier,
|
|
new DoubleVerifier,
|
|
Optional::Yes,
|
|
TextOpacityInfo.description
|
|
},
|
|
{
|
|
TextSizeInfo.identifier,
|
|
new DoubleVerifier,
|
|
Optional::Yes,
|
|
TextSizeInfo.description
|
|
},
|
|
{
|
|
LabelFileInfo.identifier,
|
|
new StringVerifier,
|
|
Optional::Yes,
|
|
LabelFileInfo.description
|
|
},
|
|
{
|
|
LabelMinSizeInfo.identifier,
|
|
new IntVerifier,
|
|
Optional::Yes,
|
|
LabelMinSizeInfo.description
|
|
},
|
|
{
|
|
LabelMaxSizeInfo.identifier,
|
|
new IntVerifier,
|
|
Optional::Yes,
|
|
LabelMaxSizeInfo.description
|
|
},
|
|
{
|
|
TransformationMatrixInfo.identifier,
|
|
new Matrix4x4Verifier<double>,
|
|
Optional::Yes,
|
|
TransformationMatrixInfo.description
|
|
},
|
|
{
|
|
BlendModeInfo.identifier,
|
|
new StringInListVerifier({ "Normal", "Additive" }),
|
|
Optional::Yes,
|
|
BlendModeInfo.description, // + " The default value is 'Normal'.",
|
|
},
|
|
{
|
|
TexturePathInfo.identifier,
|
|
new StringVerifier,
|
|
Optional::No,
|
|
TexturePathInfo.description,
|
|
},
|
|
{
|
|
LuminosityInfo.identifier,
|
|
new StringVerifier,
|
|
Optional::Yes,
|
|
LuminosityInfo.description,
|
|
},
|
|
{
|
|
ScaleFactorInfo.identifier,
|
|
new DoubleVerifier,
|
|
Optional::Yes,
|
|
ScaleFactorInfo.description,
|
|
},
|
|
{
|
|
FadeInDistancesInfo.identifier,
|
|
new Vector2Verifier<float>,
|
|
Optional::Yes,
|
|
FadeInDistancesInfo.description
|
|
},
|
|
{
|
|
DisableFadeInInfo.identifier,
|
|
new BoolVerifier,
|
|
Optional::Yes,
|
|
DisableFadeInInfo.description
|
|
},
|
|
{
|
|
PlaneMinSizeInfo.identifier,
|
|
new DoubleVerifier,
|
|
Optional::Yes,
|
|
PlaneMinSizeInfo.description
|
|
},
|
|
}
|
|
};
|
|
}
|
|
|
|
|
|
RenderablePlanesCloud::RenderablePlanesCloud(const ghoul::Dictionary& dictionary)
|
|
: Renderable(dictionary)
|
|
, _scaleFactor(ScaleFactorInfo, 1.f, 0.f, 100.f)
|
|
, _textColor(TextColorInfo, glm::vec3(1.f), glm::vec3(0.f), glm::vec3(1.f))
|
|
, _textOpacity(TextOpacityInfo, 1.f, 0.f, 1.f)
|
|
, _textSize(TextSizeInfo, 8.0, 0.5, 24.0)
|
|
, _drawElements(DrawElementsInfo, true)
|
|
, _blendMode(BlendModeInfo, properties::OptionProperty::DisplayType::Dropdown)
|
|
, _fadeInDistance(
|
|
FadeInDistancesInfo,
|
|
glm::vec2(0.f),
|
|
glm::vec2(0.f),
|
|
glm::vec2(200000.f)
|
|
)
|
|
, _disableFadeInDistance(DisableFadeInInfo, true)
|
|
, _planeMinSize(PlaneMinSizeInfo, 0.5, 0.0, 500.0)
|
|
, _renderOption(RenderOptionInfo, properties::OptionProperty::DisplayType::Dropdown)
|
|
{
|
|
documentation::testSpecificationAndThrow(
|
|
Documentation(),
|
|
dictionary,
|
|
"RenderablePlanesCloud"
|
|
);
|
|
|
|
addProperty(_opacity);
|
|
|
|
if (dictionary.hasKey(KeyFile)) {
|
|
_speckFile = absPath(dictionary.value<std::string>(KeyFile));
|
|
_hasSpeckFile = true;
|
|
_drawElements.onChange([&]() { _hasSpeckFile = !_hasSpeckFile; });
|
|
addProperty(_drawElements);
|
|
}
|
|
|
|
// DEBUG:
|
|
_renderOption.addOption(0, "Camera View Direction");
|
|
_renderOption.addOption(1, "Camera Position Normal");
|
|
_renderOption.addOption(2, "Screen center Position Normal");
|
|
addProperty(_renderOption);
|
|
//_renderOption.set(1);
|
|
|
|
if (dictionary.hasKey(keyUnit)) {
|
|
const std::string& unit = dictionary.value<std::string>(keyUnit);
|
|
if (unit == MeterUnit) {
|
|
_unit = Meter;
|
|
}
|
|
else if (unit == KilometerUnit) {
|
|
_unit = Kilometer;
|
|
}
|
|
else if (unit == ParsecUnit) {
|
|
_unit = Parsec;
|
|
}
|
|
else if (unit == KiloparsecUnit) {
|
|
_unit = Kiloparsec;
|
|
}
|
|
else if (unit == MegaparsecUnit) {
|
|
_unit = Megaparsec;
|
|
}
|
|
else if (unit == GigaparsecUnit) {
|
|
_unit = Gigaparsec;
|
|
}
|
|
else if (unit == GigalightyearUnit) {
|
|
_unit = GigalightYears;
|
|
}
|
|
else {
|
|
LWARNING("No unit given for RenderablePlanesCloud. Using meters as units.");
|
|
_unit = Meter;
|
|
}
|
|
}
|
|
else {
|
|
LWARNING("No unit given for RenderablePlanesCloud. Using meters as units.");
|
|
_unit = Meter;
|
|
}
|
|
|
|
if (dictionary.hasKey(ScaleFactorInfo.identifier)) {
|
|
_scaleFactor = static_cast<float>(
|
|
dictionary.value<double>(ScaleFactorInfo.identifier)
|
|
);
|
|
}
|
|
addProperty(_scaleFactor);
|
|
_scaleFactor.onChange([&]() {
|
|
_dataIsDirty = true;
|
|
});
|
|
|
|
if (dictionary.hasKey(LabelFileInfo.identifier)) {
|
|
_labelFile = absPath(dictionary.value<std::string>(LabelFileInfo.identifier));
|
|
_hasLabel = true;
|
|
|
|
if (dictionary.hasKey(TextColorInfo.identifier)) {
|
|
_textColor = dictionary.value<glm::vec3>(TextColorInfo.identifier);
|
|
_hasLabel = true;
|
|
}
|
|
_textColor.setViewOption(properties::Property::ViewOptions::Color);
|
|
addProperty(_textColor);
|
|
_textColor.onChange([&]() { _textColorIsDirty = true; });
|
|
|
|
if (dictionary.hasKey(TextOpacityInfo.identifier)) {
|
|
_textOpacity = dictionary.value<float>(TextOpacityInfo.identifier);
|
|
}
|
|
addProperty(_textOpacity);
|
|
|
|
if (dictionary.hasKey(TextSizeInfo.identifier)) {
|
|
_textSize = dictionary.value<float>(TextSizeInfo.identifier);
|
|
}
|
|
addProperty(_textSize);
|
|
|
|
if (dictionary.hasKey(LabelMinSizeInfo.identifier)) {
|
|
_textMinSize = static_cast<int>(
|
|
dictionary.value<float>(LabelMinSizeInfo.identifier)
|
|
);
|
|
}
|
|
|
|
if (dictionary.hasKey(LabelMaxSizeInfo.identifier)) {
|
|
_textMaxSize = static_cast<int>(
|
|
dictionary.value<float>(LabelMaxSizeInfo.identifier)
|
|
);
|
|
}
|
|
}
|
|
|
|
if (dictionary.hasKey(TransformationMatrixInfo.identifier)) {
|
|
_transformationMatrix = dictionary.value<glm::dmat4>(
|
|
TransformationMatrixInfo.identifier
|
|
);
|
|
}
|
|
|
|
_blendMode.addOptions({
|
|
{ BlendModeNormal, "Normal" },
|
|
{ BlendModeAdditive, "Additive" }
|
|
});
|
|
_blendMode.onChange([&]() {
|
|
switch (_blendMode) {
|
|
case BlendModeNormal:
|
|
setRenderBin(Renderable::RenderBin::Opaque);
|
|
break;
|
|
case BlendModeAdditive:
|
|
setRenderBin(Renderable::RenderBin::PreDeferredTransparent);
|
|
break;
|
|
default:
|
|
throw ghoul::MissingCaseException();
|
|
}
|
|
});
|
|
|
|
if (dictionary.hasKey(BlendModeInfo.identifier)) {
|
|
const std::string& v = dictionary.value<std::string>(BlendModeInfo.identifier);
|
|
if (v == "Normal") {
|
|
_blendMode = BlendModeNormal;
|
|
}
|
|
else if (v == "Additive") {
|
|
_blendMode = BlendModeAdditive;
|
|
}
|
|
}
|
|
|
|
_texturesPath = absPath(dictionary.value<std::string>(TexturePathInfo.identifier));
|
|
|
|
if (dictionary.hasKey(LuminosityInfo.identifier)) {
|
|
_luminosityVar = dictionary.value<std::string>(LuminosityInfo.identifier);
|
|
}
|
|
|
|
if (dictionary.hasKey(ScaleLuminosityInfo.identifier)) {
|
|
_sluminosity = static_cast<float>(
|
|
dictionary.value<double>(ScaleLuminosityInfo.identifier)
|
|
);
|
|
}
|
|
|
|
if (dictionary.hasKey(FadeInDistancesInfo.identifier)) {
|
|
_fadeInDistance = dictionary.value<glm::vec2>(FadeInDistancesInfo.identifier);
|
|
_disableFadeInDistance = false;
|
|
addProperty(_fadeInDistance);
|
|
addProperty(_disableFadeInDistance);
|
|
}
|
|
|
|
if (dictionary.hasKey(PlaneMinSizeInfo.identifier)) {
|
|
_planeMinSize = static_cast<float>(
|
|
dictionary.value<double>(PlaneMinSizeInfo.identifier)
|
|
);
|
|
addProperty(_planeMinSize);
|
|
}
|
|
}
|
|
|
|
bool RenderablePlanesCloud::isReady() const {
|
|
return ((_program != nullptr) && (!_fullData.empty())) || (!_labelData.empty());
|
|
}
|
|
|
|
void RenderablePlanesCloud::initialize() {
|
|
ZoneScoped
|
|
|
|
const bool success = loadData();
|
|
if (!success) {
|
|
throw ghoul::RuntimeError("Error loading data");
|
|
}
|
|
}
|
|
|
|
void RenderablePlanesCloud::initializeGL() {
|
|
ZoneScoped
|
|
|
|
_program = DigitalUniverseModule::ProgramObjectManager.request(
|
|
ProgramObjectName,
|
|
[]() -> std::unique_ptr<ghoul::opengl::ProgramObject> {
|
|
return global::renderEngine.buildRenderProgram(
|
|
"RenderablePlanesCloud",
|
|
absPath("${MODULE_DIGITALUNIVERSE}/shaders/plane_vs.glsl"),
|
|
absPath("${MODULE_DIGITALUNIVERSE}/shaders/plane_fs.glsl")
|
|
);
|
|
}
|
|
);
|
|
|
|
ghoul::opengl::updateUniformLocations(*_program, _uniformCache, UniformNames);
|
|
|
|
createPlanes();
|
|
|
|
loadTextures();
|
|
|
|
if (_hasLabel) {
|
|
if (!_font) {
|
|
constexpr const int FontSize = 30;
|
|
_font = global::fontManager.font(
|
|
"Mono",
|
|
static_cast<float>(FontSize),
|
|
ghoul::fontrendering::FontManager::Outline::Yes,
|
|
ghoul::fontrendering::FontManager::LoadGlyphs::No
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void RenderablePlanesCloud::deleteDataGPUAndCPU() {
|
|
for (std::unordered_map<int, PlaneAggregate>::reference pAMapItem : _planesMap) {
|
|
glDeleteBuffers(1, &pAMapItem.second.vbo);
|
|
glDeleteVertexArrays(1, &pAMapItem.second.vao);
|
|
pAMapItem.second.planesCoordinates.clear();
|
|
}
|
|
_planesMap.clear();
|
|
}
|
|
|
|
void RenderablePlanesCloud::deinitializeGL() {
|
|
deleteDataGPUAndCPU();
|
|
|
|
DigitalUniverseModule::ProgramObjectManager.release(
|
|
ProgramObjectName,
|
|
[](ghoul::opengl::ProgramObject* p) {
|
|
global::renderEngine.removeRenderProgram(p);
|
|
}
|
|
);
|
|
}
|
|
|
|
void RenderablePlanesCloud::renderPlanes(const RenderData&,
|
|
const glm::dmat4& modelViewMatrix,
|
|
const glm::dmat4& projectionMatrix,
|
|
const float fadeInVariable)
|
|
{
|
|
glEnablei(GL_BLEND, 0);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
|
//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glDepthMask(false);
|
|
|
|
_program->activate();
|
|
|
|
glm::dmat4 modelViewProjectionMatrix = glm::dmat4(projectionMatrix) * modelViewMatrix;
|
|
_program->setUniform(
|
|
_uniformCache.modelViewProjectionTransform,
|
|
modelViewProjectionMatrix
|
|
);
|
|
_program->setUniform(_uniformCache.alphaValue, _opacity);
|
|
_program->setUniform(_uniformCache.fadeInValue, fadeInVariable);
|
|
|
|
GLint viewport[4];
|
|
glGetIntegerv(GL_VIEWPORT, viewport);
|
|
|
|
ghoul::opengl::TextureUnit unit;
|
|
unit.activate();
|
|
_program->setUniform(_uniformCache.galaxyTexture, unit);
|
|
int currentTextureIndex = -1;
|
|
|
|
for (std::unordered_map<int, PlaneAggregate>::reference pAMapItem : _planesMap)
|
|
{
|
|
// For planes with undefined textures references
|
|
if (pAMapItem.first == 30) {
|
|
continue;
|
|
}
|
|
|
|
// We only bind a new texture when it is needed
|
|
if (currentTextureIndex != pAMapItem.first) {
|
|
_textureMap[pAMapItem.first]->bind();
|
|
currentTextureIndex = pAMapItem.first;
|
|
}
|
|
glBindVertexArray(pAMapItem.second.vao);
|
|
glDrawArrays(GL_TRIANGLES, 0, 6 * pAMapItem.second.numberOfPlanes);
|
|
}
|
|
|
|
glBindVertexArray(0);
|
|
_program->deactivate();
|
|
|
|
// Restores OpenGL Rendering State
|
|
global::renderEngine.openglStateCache().resetBlendState();
|
|
global::renderEngine.openglStateCache().resetDepthState();
|
|
}
|
|
|
|
void RenderablePlanesCloud::renderLabels(const RenderData& data,
|
|
const glm::dmat4& modelViewProjectionMatrix,
|
|
const glm::dvec3& orthoRight,
|
|
const glm::dvec3& orthoUp, float fadeInVariable)
|
|
{
|
|
float scale = 0.f;
|
|
switch (_unit) {
|
|
case Meter:
|
|
scale = 1.f;
|
|
break;
|
|
case Kilometer:
|
|
scale = 1e3f;
|
|
break;
|
|
case Parsec:
|
|
scale = static_cast<float>(PARSEC);
|
|
break;
|
|
case Kiloparsec:
|
|
scale = static_cast<float>(1e3 * PARSEC);
|
|
break;
|
|
case Megaparsec:
|
|
scale = static_cast<float>(1e6 * PARSEC);
|
|
break;
|
|
case Gigaparsec:
|
|
scale = static_cast<float>(1e9 * PARSEC);
|
|
break;
|
|
case GigalightYears:
|
|
scale = static_cast<float>(306391534.73091 * PARSEC);
|
|
break;
|
|
}
|
|
|
|
glm::vec4 textColor = glm::vec4(
|
|
glm::vec3(_textColor),
|
|
_textOpacity * fadeInVariable
|
|
);
|
|
|
|
ghoul::fontrendering::FontRenderer::ProjectedLabelsInformation labelInfo;
|
|
labelInfo.orthoRight = orthoRight;
|
|
labelInfo.orthoUp = orthoUp;
|
|
labelInfo.minSize = static_cast<int>(_textMinSize);
|
|
labelInfo.maxSize = static_cast<int>(_textMaxSize);
|
|
labelInfo.cameraPos = data.camera.positionVec3();
|
|
labelInfo.cameraLookUp = data.camera.lookUpVectorWorldSpace();
|
|
labelInfo.renderType = _renderOption;
|
|
labelInfo.mvpMatrix = modelViewProjectionMatrix;
|
|
labelInfo.scale = pow(10.f, _textSize);
|
|
labelInfo.enableDepth = true;
|
|
labelInfo.enableFalseDepth = false;
|
|
|
|
for (const std::pair<glm::vec3, std::string>& pair : _labelData) {
|
|
//glm::vec3 scaledPos(_transformationMatrix * glm::dvec4(pair.first, 1.0));
|
|
glm::vec3 scaledPos(pair.first);
|
|
scaledPos *= scale;
|
|
ghoul::fontrendering::FontRenderer::defaultProjectionRenderer().render(
|
|
*_font,
|
|
scaledPos,
|
|
pair.second,
|
|
textColor,
|
|
labelInfo
|
|
);
|
|
}
|
|
}
|
|
|
|
void RenderablePlanesCloud::render(const RenderData& data, RendererTasks&) {
|
|
float scale = 0.f;
|
|
switch (_unit) {
|
|
case Meter:
|
|
scale = 1.f;
|
|
break;
|
|
case Kilometer:
|
|
scale = 1e3f;
|
|
break;
|
|
case Parsec:
|
|
scale = static_cast<float>(PARSEC);
|
|
break;
|
|
case Kiloparsec:
|
|
scale = static_cast<float>(1e3 * PARSEC);
|
|
break;
|
|
case Megaparsec:
|
|
scale = static_cast<float>(1e6 * PARSEC);
|
|
break;
|
|
case Gigaparsec:
|
|
scale = static_cast<float>(1e9 * PARSEC);
|
|
break;
|
|
case GigalightYears:
|
|
scale = static_cast<float>(306391534.73091 * PARSEC);
|
|
break;
|
|
}
|
|
|
|
float fadeInVariable = 1.f;
|
|
if (!_disableFadeInDistance) {
|
|
float distCamera = static_cast<float>(glm::length(data.camera.positionVec3()));
|
|
distCamera /= scale;
|
|
const glm::vec2 fadeRange = _fadeInDistance;
|
|
//const float a = 1.f / ((fadeRange.y - fadeRange.x) * scale);
|
|
const float a = 1.f / ((fadeRange.y - fadeRange.x));
|
|
const float b = -(fadeRange.x / (fadeRange.y - fadeRange.x));
|
|
const float funcValue = a * distCamera + b;
|
|
fadeInVariable *= funcValue > 1.f ? 1.f : funcValue;
|
|
|
|
if (funcValue < 0.01f) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
const glm::dmat4 modelMatrix =
|
|
glm::translate(glm::dmat4(1.0), data.modelTransform.translation) * // Translation
|
|
glm::dmat4(data.modelTransform.rotation) * // Spice rotation
|
|
glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale));
|
|
|
|
const glm::dmat4 modelViewMatrix = data.camera.combinedViewMatrix() * modelMatrix;
|
|
const glm::mat4 projectionMatrix = data.camera.projectionMatrix();
|
|
const glm::dmat4 modelViewProjectionMatrix = glm::dmat4(projectionMatrix) *
|
|
modelViewMatrix;
|
|
|
|
const glm::dmat4 invMVPParts = glm::inverse(modelMatrix) *
|
|
glm::inverse(data.camera.combinedViewMatrix()) *
|
|
glm::inverse(glm::dmat4(projectionMatrix));
|
|
const glm::dvec3 orthoRight = glm::normalize(
|
|
glm::dvec3(invMVPParts * glm::dvec4(1.0, 0.0, 0.0, 0.0))
|
|
);
|
|
const glm::dvec3 orthoUp = glm::normalize(
|
|
glm::dvec3(invMVPParts * glm::dvec4(0.0, 1.0, 0.0, 0.0))
|
|
);
|
|
|
|
if (_hasSpeckFile) {
|
|
renderPlanes(data, modelViewMatrix, projectionMatrix, fadeInVariable);
|
|
}
|
|
|
|
if (_hasLabel) {
|
|
renderLabels(
|
|
data,
|
|
modelViewProjectionMatrix,
|
|
orthoRight,
|
|
orthoUp,
|
|
fadeInVariable
|
|
);
|
|
}
|
|
}
|
|
|
|
void RenderablePlanesCloud::update(const UpdateData&) {
|
|
if (_dataIsDirty && _hasSpeckFile) {
|
|
deleteDataGPUAndCPU();
|
|
createPlanes();
|
|
_dataIsDirty = false;
|
|
}
|
|
|
|
if (_program->isDirty()) {
|
|
_program->rebuildFromFile();
|
|
ghoul::opengl::updateUniformLocations(*_program, _uniformCache, UniformNames);
|
|
}
|
|
}
|
|
|
|
bool RenderablePlanesCloud::loadData() {
|
|
bool success = false;
|
|
if (_hasSpeckFile) {
|
|
// I disabled the cache as it didn't work on Mac --- abock
|
|
// std::string cachedFile = FileSys.cacheManager()->cachedFilename(
|
|
// _speckFile,
|
|
// ghoul::filesystem::CacheManager::Persistent::Yes
|
|
// );
|
|
|
|
// bool hasCachedFile = FileSys.fileExists(cachedFile);
|
|
// if (hasCachedFile) {
|
|
// LINFO(
|
|
// "Cached file '" << cachedFile <<
|
|
// "' used for Speck file '" << _speckFile << "'"
|
|
// );
|
|
|
|
// success = loadCachedFile(cachedFile);
|
|
// if (!success) {
|
|
// FileSys.cacheManager()->removeCacheFile(_speckFile);
|
|
// // Intentional fall-through to the 'else' to generate the cache
|
|
// // file for the next run
|
|
// }
|
|
// }
|
|
// else
|
|
// {
|
|
// LINFO("Cache for Speck file '" << _speckFile << "' not found");
|
|
LINFO(fmt::format("Loading Speck file '{}'", _speckFile));
|
|
|
|
success = readSpeckFile();
|
|
if (!success) {
|
|
return false;
|
|
}
|
|
|
|
// LINFO("Saving cache");
|
|
//success &= saveCachedFile(cachedFile);
|
|
// }
|
|
}
|
|
|
|
if (!_labelFile.empty()) {
|
|
// I disabled the cache as it didn't work on Mac --- abock
|
|
// std::string cachedFile = FileSys.cacheManager()->cachedFilename(
|
|
// _labelFile,
|
|
// ghoul::filesystem::CacheManager::Persistent::Yes
|
|
// );
|
|
// bool hasCachedFile = FileSys.fileExists(cachedFile);
|
|
// if (hasCachedFile) {
|
|
// LINFO(
|
|
// "Cached file '" << cachedFile <<
|
|
// "' used for Label file '" << _labelFile << "'"
|
|
// );
|
|
//
|
|
// success &= loadCachedFile(cachedFile);
|
|
// if (!success) {
|
|
// FileSys.cacheManager()->removeCacheFile(_labelFile);
|
|
// // Intentional fall-through to the 'else' to generate the cache
|
|
// // file for the next run
|
|
// }
|
|
// }
|
|
// else
|
|
// {
|
|
// LINFO("Cache for Label file '" << _labelFile << "' not found");
|
|
LINFO(fmt::format("Loading Label file '{}'", _labelFile));
|
|
|
|
success &= readLabelFile();
|
|
if (!success) {
|
|
return false;
|
|
}
|
|
|
|
// }
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
bool RenderablePlanesCloud::loadTextures() {
|
|
if (!_textureFileMap.empty()) {
|
|
for (const std::pair<const int, std::string>& pair : _textureFileMap) {
|
|
const auto& p = _textureMap.insert(std::make_pair(
|
|
pair.first,
|
|
ghoul::io::TextureReader::ref().loadTexture(pair.second)
|
|
));
|
|
if (p.second) {
|
|
LINFOC(
|
|
"RenderablePlanesCloud",
|
|
fmt::format("Loaded texture from '{}'", pair.second)
|
|
);
|
|
p.first->second->uploadTexture();
|
|
p.first->second->setFilter(
|
|
ghoul::opengl::Texture::FilterMode::LinearMipMap
|
|
);
|
|
p.first->second->purgeFromRAM();
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool RenderablePlanesCloud::readSpeckFile() {
|
|
std::ifstream file(_speckFile);
|
|
if (!file.good()) {
|
|
LERROR(fmt::format("Failed to open Speck file '{}'", _speckFile));
|
|
return false;
|
|
}
|
|
|
|
_nValuesPerAstronomicalObject = 0;
|
|
|
|
// The beginning of the speck file has a header that either contains comments
|
|
// (signaled by a preceding '#') or information about the structure of the file
|
|
// (signaled by the keywords 'datavar', 'texturevar', and 'texture')
|
|
std::string line;
|
|
while (true) {
|
|
std::getline(file, line);
|
|
|
|
// Guard against wrong line endings (copying files from Windows to Mac) causes
|
|
// lines to have a final \r
|
|
if (!line.empty() && line.back() == '\r') {
|
|
line = line.substr(0, line.length() -1);
|
|
}
|
|
|
|
if (line.empty() || line[0] == '#') {
|
|
continue;
|
|
}
|
|
|
|
if (line.substr(0, 7) != "datavar" &&
|
|
line.substr(0, 10) != "texturevar" &&
|
|
line.substr(0, 7) != "texture" &&
|
|
line.substr(0, 10) != "polyorivar" &&
|
|
line.substr(0, 10) != "maxcomment")
|
|
{
|
|
// Started reading data
|
|
break;
|
|
}
|
|
|
|
if (line.substr(0, 7) == "datavar") {
|
|
// datavar lines are structured as follows:
|
|
// datavar # description
|
|
// where # is the index of the data variable; so if we repeatedly overwrite
|
|
// the 'nValues' variable with the latest index, we will end up with the total
|
|
// number of values (+3 since X Y Z are not counted in the Speck file index)
|
|
std::stringstream str(line);
|
|
|
|
std::string dummy;
|
|
str >> dummy; // command
|
|
str >> _nValuesPerAstronomicalObject; // variable index
|
|
dummy.clear();
|
|
str >> dummy; // variable name
|
|
|
|
// +3 because of the x, y and z at the begining of each line.
|
|
_variableDataPositionMap.insert({ dummy, _nValuesPerAstronomicalObject + 3});
|
|
|
|
if ((dummy == "orientation") || (dummy == "ori")) { // 3d vectors u and v
|
|
// We want the number, but the index is 0 based
|
|
_nValuesPerAstronomicalObject += 6;
|
|
}
|
|
else {
|
|
// We want the number, but the index is 0 based
|
|
_nValuesPerAstronomicalObject += 1;
|
|
}
|
|
}
|
|
|
|
if (line.substr(0, 10) == "polyorivar") {
|
|
_planeStartingIndexPos = 0;
|
|
std::stringstream str(line);
|
|
|
|
std::string dummy;
|
|
str >> dummy; // command
|
|
str >> _planeStartingIndexPos;
|
|
_planeStartingIndexPos += 3; // 3 for xyz
|
|
}
|
|
|
|
if (line.substr(0, 10) == "texturevar") {
|
|
_textureVariableIndex = 0;
|
|
std::stringstream str(line);
|
|
|
|
std::string dummy;
|
|
str >> dummy; // command
|
|
str >> _textureVariableIndex;
|
|
_textureVariableIndex += 3; // 3 for xyz
|
|
}
|
|
|
|
if (line.substr(0, 8) == "texture ") {
|
|
std::stringstream str(line);
|
|
|
|
std::size_t found = line.find('-');
|
|
|
|
int textureIndex = 0;
|
|
|
|
std::string dummy;
|
|
str >> dummy; // command
|
|
|
|
if (found != std::string::npos) {
|
|
std::string option; // Not being used right now.
|
|
str >> option;
|
|
}
|
|
|
|
str >> textureIndex;
|
|
std::string fileName;
|
|
str >> fileName; // texture file name
|
|
|
|
std::string fullPath = absPath(_texturesPath + '/' + fileName);
|
|
std::string pngPath =
|
|
ghoul::filesystem::File(fullPath).fullBaseName() + ".png";
|
|
|
|
if (FileSys.fileExists(fullPath)) {
|
|
_textureFileMap.insert({ textureIndex, fullPath });
|
|
|
|
}
|
|
else if (FileSys.fileExists(pngPath)) {
|
|
_textureFileMap.insert({ textureIndex, pngPath });
|
|
}
|
|
else {
|
|
LWARNING(fmt::format("Could not find image file {}", fileName));
|
|
_textureFileMap.insert({ textureIndex, "" });
|
|
}
|
|
}
|
|
}
|
|
|
|
_nValuesPerAstronomicalObject += 3; // X Y Z are not counted in the Speck file indices
|
|
|
|
do {
|
|
|
|
// Guard against wrong line endings (copying files from Windows to Mac) causes
|
|
// lines to have a final \r
|
|
if (!line.empty() && line.back() == '\r') {
|
|
line = line.substr(0, line.length() -1);
|
|
}
|
|
|
|
if (line.empty()) {
|
|
std::getline(file, line);
|
|
continue;
|
|
}
|
|
else if (line[0] == '#') {
|
|
std::getline(file, line);
|
|
continue;
|
|
}
|
|
|
|
std::stringstream str(line);
|
|
|
|
glm::vec3 u(0.f);
|
|
glm::vec3 v(0.f);
|
|
int textureIndex = 0;
|
|
|
|
std::vector<float> values(_nValuesPerAstronomicalObject);
|
|
|
|
for (int i = 0; i < _nValuesPerAstronomicalObject; ++i) {
|
|
str >> values[i];
|
|
if ((i >= _planeStartingIndexPos) &&
|
|
(i <= _planeStartingIndexPos + 6)) { // vectors u and v
|
|
int index = i - _planeStartingIndexPos;
|
|
switch (index) {
|
|
case 0:
|
|
u.x = values[i];
|
|
break;
|
|
case 1:
|
|
u.y = values[i];
|
|
break;
|
|
case 2:
|
|
u.z = values[i];
|
|
break;
|
|
case 3:
|
|
v.x = values[i];
|
|
break;
|
|
case 4:
|
|
v.y = values[i];
|
|
break;
|
|
case 5:
|
|
v.z = values[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
// JCC: This should be moved to the RenderablePlanesCloud:
|
|
if (i == _textureVariableIndex) {
|
|
textureIndex = static_cast<int>(values[i]);
|
|
}
|
|
}
|
|
_fullData.insert(_fullData.end(), values.begin(), values.end());
|
|
|
|
// reads new line
|
|
std::getline(file, line);
|
|
} while (!file.eof());
|
|
|
|
return true;
|
|
}
|
|
|
|
bool RenderablePlanesCloud::readLabelFile() {
|
|
std::ifstream file(_labelFile);
|
|
if (!file.good()) {
|
|
LERROR(fmt::format("Failed to open Label file '{}'", _labelFile));
|
|
return false;
|
|
}
|
|
|
|
// The beginning of the speck file has a header that either contains comments
|
|
// (signaled by a preceding '#') or information about the structure of the file
|
|
// (signaled by the keywords 'datavar', 'texturevar', and 'texture')
|
|
std::string line;
|
|
while (true) {
|
|
std::streampos position = file.tellg();
|
|
std::getline(file, line);
|
|
|
|
// Guard against wrong line endings (copying files from Windows to Mac) causes
|
|
// lines to have a final \r
|
|
if (!line.empty() && line.back() == '\r') {
|
|
line = line.substr(0, line.length() -1);
|
|
}
|
|
|
|
if (line.empty() || line[0] == '#') {
|
|
continue;
|
|
}
|
|
|
|
if (line.substr(0, 9) != "textcolor") {
|
|
// we read a line that doesn't belong to the header, so we have to jump back
|
|
// before the beginning of the current line
|
|
file.seekg(position);
|
|
continue;
|
|
}
|
|
|
|
if (line.substr(0, 9) == "textcolor") {
|
|
// textcolor lines are structured as follows:
|
|
// textcolor # description
|
|
// where # is color text defined in configuration file
|
|
std::stringstream str(line);
|
|
|
|
// TODO: handle cases of labels with different colors
|
|
break;
|
|
}
|
|
}
|
|
|
|
do {
|
|
std::vector<float> values(_nValuesPerAstronomicalObject);
|
|
|
|
std::getline(file, line);
|
|
|
|
// Guard against wrong line endings (copying files from Windows to Mac) causes
|
|
// lines to have a final \r
|
|
if (!line.empty() && line.back() == '\r') {
|
|
line = line.substr(0, line.length() -1);
|
|
}
|
|
|
|
if (line.empty()) {
|
|
continue;
|
|
}
|
|
|
|
std::stringstream str(line);
|
|
|
|
glm::vec3 position = glm::vec3(0.f);
|
|
for (int j = 0; j < 3; ++j) {
|
|
str >> position[j];
|
|
}
|
|
|
|
std::string dummy;
|
|
str >> dummy; // text keyword
|
|
|
|
std::string label;
|
|
str >> label;
|
|
dummy.clear();
|
|
|
|
while (str >> dummy) {
|
|
label += " " + dummy;
|
|
dummy.clear();
|
|
}
|
|
|
|
glm::vec3 transformedPos = glm::vec3(
|
|
_transformationMatrix * glm::dvec4(position, 1.0)
|
|
);
|
|
_labelData.emplace_back(std::make_pair(transformedPos, label));
|
|
|
|
} while (!file.eof());
|
|
|
|
return true;
|
|
}
|
|
|
|
bool RenderablePlanesCloud::loadCachedFile(const std::string& file) {
|
|
std::ifstream fileStream(file, std::ifstream::binary);
|
|
if (fileStream.good()) {
|
|
int8_t version = 0;
|
|
fileStream.read(reinterpret_cast<char*>(&version), sizeof(int8_t));
|
|
if (version != CurrentCacheVersion) {
|
|
LINFO("The format of the cached file has changed: deleting old cache");
|
|
fileStream.close();
|
|
FileSys.deleteFile(file);
|
|
return false;
|
|
}
|
|
|
|
int32_t nValues = 0;
|
|
fileStream.read(reinterpret_cast<char*>(&nValues), sizeof(int32_t));
|
|
fileStream.read(reinterpret_cast<char*>(
|
|
&_nValuesPerAstronomicalObject),
|
|
sizeof(int32_t)
|
|
);
|
|
|
|
_fullData.resize(nValues);
|
|
fileStream.read(reinterpret_cast<char*>(&_fullData[0]),
|
|
nValues * sizeof(_fullData[0]));
|
|
|
|
bool success = fileStream.good();
|
|
return success;
|
|
}
|
|
else {
|
|
LERROR(fmt::format("Error opening file '{}' for loading cache file", file));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool RenderablePlanesCloud::saveCachedFile(const std::string& file) const {
|
|
std::ofstream fileStream(file, std::ofstream::binary);
|
|
if (fileStream.good()) {
|
|
fileStream.write(reinterpret_cast<const char*>(&CurrentCacheVersion),
|
|
sizeof(int8_t));
|
|
|
|
const int32_t nValues = static_cast<int32_t>(_fullData.size());
|
|
if (nValues == 0) {
|
|
LERROR("Error writing cache: No values were loaded");
|
|
return false;
|
|
}
|
|
fileStream.write(reinterpret_cast<const char*>(&nValues), sizeof(int32_t));
|
|
|
|
const int32_t nValuesPerAstronomicalObject = static_cast<int32_t>(
|
|
_nValuesPerAstronomicalObject
|
|
);
|
|
fileStream.write(reinterpret_cast<const char*>(
|
|
&nValuesPerAstronomicalObject),
|
|
sizeof(int32_t)
|
|
);
|
|
|
|
const size_t nBytes = nValues * sizeof(_fullData[0]);
|
|
fileStream.write(reinterpret_cast<const char*>(&_fullData[0]), nBytes);
|
|
|
|
bool success = fileStream.good();
|
|
return success;
|
|
}
|
|
else {
|
|
LERROR(fmt::format("Error opening file '{}' for save cache file", file));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void RenderablePlanesCloud::createPlanes() {
|
|
if (_dataIsDirty && _hasSpeckFile) {
|
|
LDEBUG("Creating planes...");
|
|
float maxSize = 0.f;
|
|
for (size_t p = 0; p < _fullData.size(); p += _nValuesPerAstronomicalObject) {
|
|
const glm::vec4 transformedPos = glm::vec4(
|
|
_transformationMatrix *
|
|
glm::dvec4(_fullData[p + 0], _fullData[p + 1], _fullData[p + 2], 1.0)
|
|
);
|
|
|
|
// Plane vectors u and v
|
|
glm::vec4 u = glm::vec4(
|
|
_transformationMatrix *
|
|
glm::dvec4(
|
|
_fullData[p + _planeStartingIndexPos + 0],
|
|
_fullData[p + _planeStartingIndexPos + 1],
|
|
_fullData[p + _planeStartingIndexPos + 2],
|
|
1.f
|
|
)
|
|
);
|
|
u /= 2.f;
|
|
u.w = 0.f;
|
|
|
|
glm::vec4 v = glm::vec4(
|
|
_transformationMatrix *
|
|
glm::dvec4(
|
|
_fullData[p + _planeStartingIndexPos + 3],
|
|
_fullData[p + _planeStartingIndexPos + 4],
|
|
_fullData[p + _planeStartingIndexPos + 5],
|
|
1.f
|
|
)
|
|
);
|
|
v /= 2.f;
|
|
v.w = 0.f;
|
|
|
|
if (!_luminosityVar.empty()) {
|
|
float lumS = _fullData[p + _variableDataPositionMap[_luminosityVar]] *
|
|
_sluminosity;
|
|
u *= lumS;
|
|
v *= lumS;
|
|
}
|
|
|
|
u *= _scaleFactor;
|
|
v *= _scaleFactor;
|
|
|
|
glm::vec4 vertex0 = transformedPos - u - v; // same as 3
|
|
glm::vec4 vertex1 = transformedPos + u + v; // same as 5
|
|
glm::vec4 vertex2 = transformedPos - u + v;
|
|
glm::vec4 vertex4 = transformedPos + u - v;
|
|
|
|
float scale = 0.f;
|
|
switch (_unit) {
|
|
case Meter:
|
|
scale = 1.f;
|
|
break;
|
|
case Kilometer:
|
|
scale = 1e3f;
|
|
break;
|
|
case Parsec:
|
|
scale = static_cast<float>(PARSEC);
|
|
break;
|
|
case Kiloparsec:
|
|
scale = static_cast<float>(1e3 * PARSEC);
|
|
break;
|
|
case Megaparsec:
|
|
scale = static_cast<float>(1e6 * PARSEC);
|
|
break;
|
|
case Gigaparsec:
|
|
scale = static_cast<float>(1e9 * PARSEC);
|
|
break;
|
|
case GigalightYears:
|
|
scale = static_cast<float>(306391534.73091 * PARSEC);
|
|
break;
|
|
}
|
|
|
|
for (int i = 0; i < 3; ++i) {
|
|
maxSize = std::max(maxSize, vertex0[i]);
|
|
maxSize = std::max(maxSize, vertex1[i]);
|
|
maxSize = std::max(maxSize, vertex2[i]);
|
|
maxSize = std::max(maxSize, vertex4[i]);
|
|
}
|
|
|
|
vertex0 *= scale;
|
|
vertex1 *= scale;
|
|
vertex2 *= scale;
|
|
vertex4 *= scale;
|
|
|
|
GLfloat vertexData[] = {
|
|
// x y z w s t
|
|
vertex0.x, vertex0.y, vertex0.z, 1.f, 0.f, 0.f,
|
|
vertex1.x, vertex1.y, vertex1.z, 1.f, 1.f, 1.f,
|
|
vertex2.x, vertex2.y, vertex2.z, 1.f, 0.f, 1.f,
|
|
vertex0.x, vertex0.y, vertex0.z, 1.f, 0.f, 0.f,
|
|
vertex4.x, vertex4.y, vertex4.z, 1.f, 1.f, 0.f,
|
|
vertex1.x, vertex1.y, vertex1.z, 1.f, 1.f, 1.f,
|
|
};
|
|
|
|
int textureIndex = static_cast<int>(_fullData[p + _textureVariableIndex]);
|
|
std::unordered_map<int, PlaneAggregate>::iterator found =
|
|
_planesMap.find(textureIndex);
|
|
if (found != _planesMap.end()) {
|
|
for (int i = 0; i < PLANES_VERTEX_DATA_SIZE; ++i) {
|
|
found->second.planesCoordinates.push_back(vertexData[i]);
|
|
}
|
|
found->second.numberOfPlanes++;
|
|
}
|
|
else {
|
|
PlaneAggregate pA;
|
|
pA.textureIndex = textureIndex;
|
|
glGenVertexArrays(1, &pA.vao);
|
|
glGenBuffers(1, &pA.vbo);
|
|
pA.numberOfPlanes = 1;
|
|
for (int i = 0; i < PLANES_VERTEX_DATA_SIZE; ++i) {
|
|
pA.planesCoordinates.push_back(vertexData[i]);
|
|
}
|
|
_planesMap.insert(std::pair<int, PlaneAggregate>(textureIndex, pA));
|
|
}
|
|
}
|
|
|
|
// Send data to GPU
|
|
for (const std::pair<const int, PlaneAggregate>& pAMapItem : _planesMap) {
|
|
glBindVertexArray(pAMapItem.second.vao);
|
|
glBindBuffer(GL_ARRAY_BUFFER, pAMapItem.second.vbo);
|
|
glBufferData(
|
|
GL_ARRAY_BUFFER,
|
|
sizeof(GLfloat) * PLANES_VERTEX_DATA_SIZE *
|
|
pAMapItem.second.numberOfPlanes,
|
|
pAMapItem.second.planesCoordinates.data(),
|
|
GL_STATIC_DRAW
|
|
);
|
|
// in_position
|
|
glEnableVertexAttribArray(0);
|
|
glVertexAttribPointer(
|
|
0,
|
|
4,
|
|
GL_FLOAT,
|
|
GL_FALSE,
|
|
sizeof(GLfloat) * 6,
|
|
nullptr
|
|
);
|
|
|
|
// texture coords
|
|
glEnableVertexAttribArray(1);
|
|
glVertexAttribPointer(
|
|
1,
|
|
2,
|
|
GL_FLOAT,
|
|
GL_FALSE,
|
|
sizeof(GLfloat) * 6,
|
|
reinterpret_cast<GLvoid*>(sizeof(GLfloat) * 4)
|
|
);
|
|
|
|
glBindVertexArray(0);
|
|
}
|
|
|
|
_dataIsDirty = false;
|
|
|
|
_fadeInDistance.setMaxValue(glm::vec2(10.f * maxSize));
|
|
}
|
|
|
|
if (_hasLabel && _labelDataIsDirty) {
|
|
_labelDataIsDirty = false;
|
|
}
|
|
}
|
|
|
|
} // namespace openspace
|