Files
OpenSpace/modules/globebrowsing/src/globelabelscomponent.cpp
Alexander Bock 6dc738e54e Move functions about globe locations from the GlobeBrowsingModule into the core (#3613)
* Make GlobeRotation and GlobeTranslation work for non-globes and move them to the base module
* Move ellipsoid and geodetic classes into the core
* Allow more things to take scene graph nodes instead of RenderableGlobes
* Move goToGeo and related Lua functions into the core
* Move more functions from the pathnavigation namespace into the navigation namespace

---------

Co-authored-by: Emma Broman <emma.broman@liu.se>
2025-04-23 16:15:17 +02:00

693 lines
26 KiB
C++

/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2025 *
* *
* 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/globebrowsing/src/globelabelscomponent.h>
#include <modules/globebrowsing/globebrowsingmodule.h>
#include <modules/globebrowsing/src/renderableglobe.h>
#include <openspace/documentation/documentation.h>
#include <openspace/documentation/verifier.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/util/updatestructures.h>
#include <ghoul/filesystem/cachemanager.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/font/fontmanager.h>
#include <ghoul/font/fontrenderer.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/dictionary.h>
#include <ghoul/misc/profiling.h>
#include <ghoul/misc/stringhelper.h>
#include <ghoul/opengl/programobject.h>
#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <locale>
#include <optional>
namespace {
constexpr std::string_view _loggerCat = "GlobeLabels";
constexpr double LabelFadeOutLimitAltitudeMeters = 25000.0;
constexpr float MinOpacityValueConst = 0.009f;
enum LabelRenderingAlignmentType {
Horizontally = 0,
Circularly
};
constexpr int8_t CurrentCacheVersion = 1;
constexpr openspace::properties::Property::PropertyInfo EnabledInfo = {
"Enabled",
"Enabled",
"Enables and disables labels' rendering.",
openspace::properties::Property::Visibility::NoviceUser
};
constexpr openspace::properties::Property::PropertyInfo FontSizeInfo = {
"FontSize",
"Font Size",
"Font size for the rendering labels. This is different fromt text size.",
openspace::properties::Property::Visibility::User
};
constexpr openspace::properties::Property::PropertyInfo MinMaxSizeInfo = {
"MinMaxSize",
"Min/Max Text Size",
"Minimum and maximum label size, in pixels.",
openspace::properties::Property::Visibility::AdvancedUser
};
constexpr openspace::properties::Property::PropertyInfo SizeInfo = {
"LabelsSize",
"Labels Size",
"This value affects the size scale of the labels.",
openspace::properties::Property::Visibility::User
};
constexpr openspace::properties::Property::PropertyInfo HeightOffsetInfo = {
"HeightOffset",
"Height Offset",
"This value moves the label away from the globe surface by the specified "
"distance (in meters).",
openspace::properties::Property::Visibility::User
};
constexpr openspace::properties::Property::PropertyInfo ColorInfo = {
"Color",
"Color",
"The text color of the labels.",
openspace::properties::Property::Visibility::NoviceUser
};
constexpr openspace::properties::Property::PropertyInfo FadeDistancesInfo = {
"FadeDistances",
"Fade-In Distances",
"The distances above the globe's surface at which the labels start fading in or "
"out, given in meters. The final distances are also adjusted by the specified "
"height offset.",
openspace::properties::Property::Visibility::AdvancedUser
};
constexpr openspace::properties::Property::PropertyInfo FadeInEnabledInfo = {
"FadeInEnabled",
"Fade In Enabled",
"Sets whether the labels fade in when approaching the globe from a distance. If "
"false, no fading happens and the labels immediately has full opacity.",
openspace::properties::Property::Visibility::User
};
constexpr openspace::properties::Property::PropertyInfo FadeOutEnabledInfo = {
"FadeOutEnabled",
"Fade Out Enabled",
"Sets whether the labels fade out when approaching the surface of the globe. If "
"false, no fading happens and the labels stays in full opacity.",
openspace::properties::Property::Visibility::User
};
constexpr openspace::properties::Property::PropertyInfo DisableCullingInfo = {
"DisableCulling",
"Culling Disabled",
"Labels culling disabled.",
openspace::properties::Property::Visibility::Developer
};
constexpr openspace::properties::Property::PropertyInfo DistanceEPSInfo = {
"DistanceEPS",
"Culling Distance",
"Labels culling distance from globe's center.",
openspace::properties::Property::Visibility::Developer
};
constexpr openspace::properties::Property::PropertyInfo AlignmentOptionInfo = {
"AlignmentOption",
"Alignment Option",
"Labels are aligned horizontally or circularly related to the planet.",
openspace::properties::Property::Visibility::User
};
bool isLabelInFrustum(const glm::dmat4& MVMatrix, const glm::dvec3& position) {
// Frustum Planes
const glm::dvec3 col1(MVMatrix[0][0], MVMatrix[1][0], MVMatrix[2][0]);
const glm::dvec3 col2(MVMatrix[0][1], MVMatrix[1][1], MVMatrix[2][1]);
const glm::dvec3 col3(MVMatrix[0][2], MVMatrix[1][2], MVMatrix[2][2]);
const glm::dvec3 col4(MVMatrix[0][3], MVMatrix[1][3], MVMatrix[2][3]);
glm::dvec3 leftNormal = col4 + col1;
glm::dvec3 rightNormal = col4 - col1;
glm::dvec3 bottomNormal = col4 + col2;
glm::dvec3 topNormal = col4 - col2;
glm::dvec3 nearNormal = col3 + col4;
glm::dvec3 farNormal = col4 - col3;
// Plane Distances
double leftDistance = MVMatrix[3][3] + MVMatrix[3][0];
double rightDistance = MVMatrix[3][3] - MVMatrix[3][0];
double bottomDistance = MVMatrix[3][3] + MVMatrix[3][1];
double topDistance = MVMatrix[3][3] - MVMatrix[3][1];
double nearDistance = MVMatrix[3][3] + MVMatrix[3][2];
// double farDistance = MVMatrix[3][3] - MVMatrix[3][2];
// Normalize Planes
const double invMagLeft = 1.0 / glm::length(leftNormal);
leftNormal *= invMagLeft;
leftDistance *= invMagLeft;
const double invMagRight = 1.0 / glm::length(rightNormal);
rightNormal *= invMagRight;
rightDistance *= invMagRight;
const double invMagBottom = 1.0 / glm::length(bottomNormal);
bottomNormal *= invMagBottom;
bottomDistance *= invMagBottom;
const double invMagTop = 1.0 / glm::length(topNormal);
topNormal *= invMagTop;
topDistance *= invMagTop;
const double invMagNear = 1.0 / glm::length(nearNormal);
nearNormal *= invMagNear;
nearDistance *= invMagNear;
const double invMagFar = 1.0 / glm::length(farNormal);
farNormal *= invMagFar;
// farDistance *= invMagFar;
constexpr float Radius = 1.0;
const bool res = ((glm::dot(leftNormal, position) + leftDistance) < -Radius) ||
((glm::dot(rightNormal, position) + rightDistance) < -Radius) ||
((glm::dot(bottomNormal, position) + bottomDistance) < -Radius) ||
((glm::dot(topNormal, position) + topDistance) < -Radius) ||
((glm::dot(nearNormal, position) + nearDistance) < -Radius);
return !res;
}
struct [[codegen::Dictionary(GlobeLabelsComponent)]] Parameters {
// The path to the labels file
std::optional<std::filesystem::path> fileName;
// [[codegen::verbatim(EnabledInfo.description)]]
std::optional<bool> enabled;
// This value determines the opacity of the labels
std::optional<float> opacity [[codegen::inrange(0.f, 1.f)]];
// [[codegen::verbatim(FontSizeInfo.description)]]
std::optional<float> fontSize;
// [[codegen::verbatim(MinMaxSizeInfo.description)]]
std::optional<glm::ivec2> minMaxSize;
// [[codegen::verbatim(SizeInfo.description)]]
std::optional<float> size;
// [[codegen::verbatim(HeightOffsetInfo.description)]]
std::optional<float> heightOffset;
// [[codegen::verbatim(ColorInfo.description)]]
std::optional<glm::vec3> color [[codegen::color()]];
// [[codegen::verbatim(FadeDistancesInfo.description)]]
std::optional<glm::vec2> fadeDistances;
// [[codegen::verbatim(FadeInEnabledInfo.description)]]
std::optional<bool> fadeInEnabled;
// [[codegen::verbatim(FadeOutEnabledInfo.description)]]
std::optional<bool> fadeOutEnabled;
// [[codegen::verbatim(DisableCullingInfo.description)]]
std::optional<bool> disableCulling;
// [[codegen::verbatim(DistanceEPSInfo.description)]]
std::optional<float> distanceEPS;
enum class [[codegen::map(LabelRenderingAlignmentType)]] Alignment {
Horizontally,
Circularly
};
// [[codegen::verbatim(AlignmentOptionInfo.description)]]
std::optional<Alignment> alignmentOption;
};
#include "globelabelscomponent_codegen.cpp"
} // namespace
namespace openspace {
documentation::Documentation GlobeLabelsComponent::Documentation() {
return codegen::doc<Parameters>("globebrowsing_globelabelscomponent");
}
GlobeLabelsComponent::GlobeLabelsComponent()
: properties::PropertyOwner({ "Labels" })
, _enabled(EnabledInfo, false)
, _color(ColorInfo, glm::vec3(1.f, 1.f, 0.f), glm::vec3(0.f), glm::vec3(1.f))
, _fontSize(FontSizeInfo, 30.f, 1.f, 300.f)
, _size(SizeInfo, 2.5, 0, 30)
, _minMaxSize(MinMaxSizeInfo, glm::ivec2(1, 1000), glm::ivec2(1), glm::ivec2(1000))
, _heightOffset(HeightOffsetInfo, 100.f, 0.f, 10000.f)
, _fadeDistances(
FadeDistancesInfo,
glm::vec2(1e4f, 1e6f),
glm::vec2(1.f),
glm::vec2(1e8f)
)
, _fadeInEnabled(FadeInEnabledInfo, false)
, _fadeOutEnabled(FadeOutEnabledInfo, false)
, _disableCulling(DisableCullingInfo, false)
, _distanceEPS(DistanceEPSInfo, 100000.f, 1000.f, 10000000.f)
, _alignmentOption(AlignmentOptionInfo)
{
addProperty(_enabled);
addProperty(_color);
_color.setViewOption(properties::Property::ViewOptions::Color);
addProperty(Fadeable::_opacity);
addProperty(Fadeable::_fade);
addProperty(_fontSize);
addProperty(_size);
_minMaxSize.setViewOption(properties::Property::ViewOptions::MinMaxRange);
addProperty(_minMaxSize);
_fadeDistances.setViewOption(properties::Property::ViewOptions::MinMaxRange);
_fadeDistances.setExponent(3.f);
addProperty(_fadeDistances);
addProperty(_fadeInEnabled);
addProperty(_fadeOutEnabled);
addProperty(_heightOffset);
addProperty(_disableCulling);
addProperty(_distanceEPS);
_alignmentOption.addOption(Horizontally, "Horizontally");
_alignmentOption.addOption(Circularly, "Circularly");
_alignmentOption = Horizontally;
addProperty(_alignmentOption);
}
void GlobeLabelsComponent::initialize(const ghoul::Dictionary& dictionary,
globebrowsing::RenderableGlobe* globe)
{
ZoneScoped;
_globe = globe;
const Parameters p = codegen::bake<Parameters>(dictionary);
if (!p.fileName.has_value()) {
return;
}
const bool loadSuccess = loadLabelsData(*p.fileName);
if (!loadSuccess) {
return;
}
Fadeable::_opacity = p.opacity.value_or(Fadeable::_opacity);
_enabled = p.enabled.value_or(_enabled);
_fontSize = p.fontSize.value_or(_fontSize);
_fontSize.onChange([this]() { initializeFonts(); });
// @TODO (emmbr, 2021-05-31): Temporarily set as read only, to avoid errors from font
// rendering (avoid filling font atlas)
_fontSize.setReadOnly(true);
_size = p.size.value_or(_size);
_heightOffset = p.heightOffset.value_or(_heightOffset);
_color = p.color.value_or(_color);
_opacity = p.opacity.value_or(_opacity);
_fadeInEnabled = p.fadeInEnabled.value_or(_fadeInEnabled);
_fadeOutEnabled = p.fadeOutEnabled.value_or(_fadeOutEnabled);
_fadeDistances = p.fadeDistances.value_or(_fadeDistances);
_minMaxSize = p.minMaxSize.value_or(_minMaxSize);
_disableCulling = p.disableCulling.value_or(_disableCulling);
_distanceEPS = p.distanceEPS.value_or(_distanceEPS);
if (p.alignmentOption.has_value()) {
_alignmentOption = codegen::map<LabelRenderingAlignmentType>(*p.alignmentOption);
}
initializeFonts();
}
void GlobeLabelsComponent::initializeFonts() {
_font = openspace::global::fontManager->font(
"Mono",
static_cast<float>(_fontSize),
ghoul::fontrendering::FontManager::Outline::Yes,
ghoul::fontrendering::FontManager::LoadGlyphs::Yes
);
}
bool GlobeLabelsComponent::loadLabelsData(const std::filesystem::path& file) {
std::filesystem::path cachedFile = FileSys.cacheManager()->cachedFilename(
file,
"GlobeLabelsComponent|" + identifier()
);
const bool hasCachedFile = std::filesystem::is_regular_file(cachedFile);
if (hasCachedFile) {
LINFO(std::format(
"Cached file '{}' used for labels file '{}'", cachedFile, file
));
const bool hasCache = loadCachedFile(cachedFile);
if (hasCache) {
return true;
}
else {
FileSys.cacheManager()->removeCacheFile(file);
// Intentional fall-through to the 'else' to generate the cache
// file for the next run
}
}
else {
LINFO(std::format("Cache for labels file '{}' not found", file));
}
LINFO(std::format("Loading labels file '{}'", file));
const bool success = readLabelsFile(file);
if (success) {
saveCachedFile(cachedFile);
}
return success;
}
bool GlobeLabelsComponent::readLabelsFile(const std::filesystem::path& file) {
try {
std::fstream csvLabelFile(file);
if (!csvLabelFile.good()) {
LERROR(std::format("Failed to open labels file '{}'", file));
return false;
}
if (!csvLabelFile.is_open()) {
return false;
}
_labels.labelsArray.clear();
std::string sline;
while (!csvLabelFile.eof()) {
ghoul::getline(csvLabelFile, sline);
if (sline.size() <= 10) {
continue;
}
std::istringstream iss(sline);
std::string token;
ghoul::getline(iss, token, ',');
// First line is just the Header
if (token == "Feature_Name") {
continue;
}
LabelEntry lEntry;
// Non-ascii characters aren't displayed correctly by the text
// rendering (We don't have the non-ascii character in the texture
// atlas)
// Once this limitation is fixed, we can remove the next piece of code
// Removing non ASCII characters:
strncpy(lEntry.feature, token.c_str(), 255);
int tokenChar = 0;
while (tokenChar < 256) {
if (lEntry.feature[tokenChar] < 0 || lEntry.feature[tokenChar] == '\0') {
lEntry.feature[tokenChar] = '*';
}
else if (lEntry.feature[tokenChar] == '\"') {
lEntry.feature[tokenChar] = '=';
}
tokenChar++;
}
ghoul::getline(iss, token, ','); // Target is not used
ghoul::getline(iss, token, ','); // Diameter
lEntry.diameter = std::stof(token);
ghoul::getline(iss, token, ','); // Latitude
lEntry.latitude = std::stof(token);
ghoul::getline(iss, token, ','); // Longitude
lEntry.longitude = std::stof(token);
ghoul::getline(iss, token, ','); // Coord System
const std::string_view coordinateSystem = token;
const size_t found = coordinateSystem.find("West");
if (found != std::string::npos) {
lEntry.longitude = 360.f - lEntry.longitude;
}
// Clean white spaces
std::istringstream issFeature(lEntry.feature);
ghoul::getline(issFeature, token, '=');
if (token.empty()) {
ghoul::getline(issFeature, token, '=');
}
std::strncpy(lEntry.feature, token.c_str(), 255);
lEntry.geoPosition = cartesianCoordinatesFromGeo(
*static_cast<SceneGraphNode*>(_globe->owner()),
lEntry.latitude,
lEntry.longitude,
lEntry.diameter
);
_labels.labelsArray.push_back(lEntry);
}
return true;
}
catch (const std::fstream::failure& e) {
LERROR(std::format("Failed reading labels file '{}'", file));
LERROR(e.what());
return false;
}
}
bool GlobeLabelsComponent::loadCachedFile(const std::filesystem::path& file) {
std::ifstream fileStream(file, std::ifstream::binary);
if (!fileStream.good()) {
LERROR(std::format("Error opening file '{}' for loading cache file", file));
return false;
}
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();
if (std::filesystem::is_regular_file(file)) {
std::filesystem::remove(file);
}
return false;
}
int32_t nValues = 0;
fileStream.read(reinterpret_cast<char*>(&nValues), sizeof(int32_t));
_labels.labelsArray.resize(nValues);
fileStream.read(
reinterpret_cast<char*>(_labels.labelsArray.data()),
nValues * sizeof(LabelEntry)
);
return fileStream.good();
}
bool GlobeLabelsComponent::saveCachedFile(const std::filesystem::path& file) const {
std::ofstream fileStream = std::ofstream(file, std::ofstream::binary);
if (!fileStream.good()) {
LERROR(std::format("Error opening file '{}' for save cache file", file));
return false;
}
fileStream.write(reinterpret_cast<const char*>(&CurrentCacheVersion), sizeof(int8_t));
const int32_t nValues = static_cast<int32_t>(_labels.labelsArray.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 size_t nBytes = nValues * sizeof(LabelEntry);
fileStream.write(reinterpret_cast<const char*>(_labels.labelsArray.data()), nBytes);
return fileStream.good();
}
void GlobeLabelsComponent::draw(const RenderData& data) {
if (!_enabled) {
return;
}
// Calculate the MVP matrix
const glm::dmat4 viewTransform = glm::dmat4(data.camera.combinedViewMatrix());
const glm::dmat4 vp = glm::dmat4(data.camera.sgctInternal.projectionMatrix()) *
viewTransform;
const glm::dmat4 mvp = vp * _globe->modelTransform();
const glm::dvec3 globePosWorld =
glm::dvec3(_globe->modelTransform() * glm::vec4(0.f, 0.f, 0.f, 1.f));
const glm::dvec3 cameraToGlobeWorld = globePosWorld - data.camera.positionVec3();
const double distanceCameraGlobeWorld = glm::length(cameraToGlobeWorld);
float varyingOpacity = 1.f;
const glm::dvec3 globeRadii = _globe->ellipsoid().radii();
const double averageRadius = (globeRadii.x + globeRadii.y + globeRadii.z) / 3.0;
if (_fadeInEnabled) {
glm::dvec2 fadeRange = glm::dvec2(averageRadius + _heightOffset);
fadeRange.x += _fadeDistances.value().y;
const double a = 1.0 / (fadeRange.y - fadeRange.x);
const double b = -(fadeRange.x / (fadeRange.y - fadeRange.x));
const double funcValue = a * distanceCameraGlobeWorld + b;
varyingOpacity *= static_cast<float>(std::min(funcValue, 1.0));
if (varyingOpacity < MinOpacityValueConst) {
return;
}
}
if (_fadeOutEnabled) {
glm::dvec2 fadeRange = glm::dvec2(
averageRadius + _heightOffset + LabelFadeOutLimitAltitudeMeters
);
fadeRange.x += _fadeDistances.value().x;
const double a = 1.0 / (fadeRange.x - fadeRange.y);
const double b = -(fadeRange.y / (fadeRange.x - fadeRange.y));
const double funcValue = a * distanceCameraGlobeWorld + b;
varyingOpacity *= static_cast<float>(std::min(funcValue, 1.0));
if (varyingOpacity < MinOpacityValueConst) {
return;
}
}
renderLabels(data, mvp, static_cast<float>(distanceCameraGlobeWorld), varyingOpacity);
}
void GlobeLabelsComponent::renderLabels(const RenderData& data,
const glm::dmat4& modelViewProjectionMatrix,
float distToCamera, float fadeInVariable
) {
const glm::vec4 textColor = glm::vec4(glm::vec3(_color), opacity() * fadeInVariable);
const glm::dmat4 VP = glm::dmat4(data.camera.sgctInternal.projectionMatrix()) *
data.camera.combinedViewMatrix();
const glm::dmat4 invModelMatrix = glm::inverse(_globe->modelTransform());
const glm::dvec3 cameraViewDirectionObj = glm::dvec3(
invModelMatrix * glm::dvec4(data.camera.viewDirectionWorldSpace(), 0.0)
);
const glm::dvec3 cameraUpDirectionObj = glm::dvec3(
invModelMatrix * glm::dvec4(data.camera.lookUpVectorWorldSpace(), 0.0)
);
glm::dvec3 orthoRight = glm::normalize(
glm::cross(cameraViewDirectionObj, cameraUpDirectionObj)
);
if (orthoRight == glm::dvec3(0.0)) {
const glm::dvec3 otherVector = glm::dvec3(
cameraUpDirectionObj.y,
cameraUpDirectionObj.x,
cameraUpDirectionObj.z
);
orthoRight = glm::normalize(glm::cross(otherVector, cameraViewDirectionObj));
}
glm::dvec3 orthoUp = glm::normalize(glm::cross(orthoRight, cameraViewDirectionObj));
for (const LabelEntry& lEntry : _labels.labelsArray) {
glm::vec3 position = lEntry.geoPosition;
const glm::dvec3 locationPositionWorld =
glm::dvec3(_globe->modelTransform() * glm::dvec4(position, 1.0));
const double distanceCameraToLabelWorld =
glm::length(locationPositionWorld - data.camera.positionVec3());
if (_disableCulling ||
((distToCamera > (distanceCameraToLabelWorld + _distanceEPS)) &&
isLabelInFrustum(VP, locationPositionWorld)))
{
if (_alignmentOption == Circularly) {
const glm::dvec3 labelNormalObj = glm::dvec3(
invModelMatrix * glm::dvec4(data.camera.positionVec3(), 1.0)
) - glm::dvec3(position);
const glm::dvec3 labelUpDirectionObj = glm::dvec3(position);
orthoRight = glm::normalize(
glm::cross(labelUpDirectionObj, labelNormalObj)
);
if (orthoRight == glm::dvec3(0.0)) {
const glm::dvec3 otherVector = glm::dvec3(
labelUpDirectionObj.y,
labelUpDirectionObj.x,
labelUpDirectionObj.z
);
orthoRight = glm::normalize(glm::cross(otherVector, labelNormalObj));
}
orthoUp = glm::normalize(glm::cross(labelNormalObj, orthoRight));
}
// Move the position along the normal. Note that position is in model space
position += _heightOffset.value() * glm::normalize(position);
ghoul::fontrendering::FontRenderer::ProjectedLabelsInformation labelInfo;
labelInfo.orthoRight = orthoRight;
labelInfo.orthoUp = orthoUp;
labelInfo.minSize = _minMaxSize.value().x;
labelInfo.maxSize = _minMaxSize.value().y;
labelInfo.cameraPos = data.camera.positionVec3();
labelInfo.cameraLookUp = data.camera.lookUpVectorWorldSpace();
labelInfo.renderType = 0;
labelInfo.mvpMatrix = modelViewProjectionMatrix;
labelInfo.scale = powf(2.f, _size);
labelInfo.enableDepth = true;
labelInfo.enableFalseDepth = true;
labelInfo.disableTransmittance = true;
// Testing
const glm::dmat4 modelviewTransform = glm::dmat4(
data.camera.combinedViewMatrix()) * _globe->modelTransform();
labelInfo.modelViewMatrix = modelviewTransform;
labelInfo.projectionMatrix = glm::dmat4(
data.camera.sgctInternal.projectionMatrix()
);
ghoul::fontrendering::FontRenderer::defaultProjectionRenderer().render(
*_font,
position,
lEntry.feature,
textColor,
labelInfo
);
}
}
}
} // namespace openspace