mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-01 17:20:09 -06:00
1092 lines
44 KiB
C++
1092 lines
44 KiB
C++
/*****************************************************************************************
|
||
* *
|
||
* OpenSpace *
|
||
* *
|
||
* Copyright (c) 2014-2021 *
|
||
* *
|
||
* 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/space/rendering/renderablefluxnodes.h>
|
||
|
||
#include <openspace/engine/globals.h>
|
||
#include <openspace/engine/windowdelegate.h>
|
||
#include <openspace/interaction/navigationhandler.h>
|
||
#include <openspace/interaction/orbitalnavigator.h>
|
||
#include <openspace/rendering/renderengine.h>
|
||
#include <openspace/scene/scene.h>
|
||
#include <openspace/util/timemanager.h>
|
||
#include <openspace/util/updatestructures.h>
|
||
#include <ghoul/filesystem/filesystem.h>
|
||
#include <ghoul/logging/logmanager.h>
|
||
// Test debugging tools more then logmanager
|
||
#include <ghoul/logging/consolelog.h>
|
||
#include <ghoul/logging/visualstudiooutputlog.h>
|
||
#include <ghoul/filesystem/cachemanager.h>
|
||
|
||
#include <ghoul/opengl/programobject.h>
|
||
#include <ghoul/opengl/textureunit.h>
|
||
#include <functional>
|
||
#include <fstream>
|
||
#include <thread>
|
||
#include <openspace/query/query.h>
|
||
#include <sys/stat.h>
|
||
#include <optional>
|
||
|
||
namespace {
|
||
// log category
|
||
constexpr const char* _loggerCat = "renderableFluxNodes";
|
||
|
||
// GL variables for shaders, probably needed some of them atleast
|
||
constexpr const GLuint VaPosition = 0; // MUST CORRESPOND TO THE SHADER PROGRAM
|
||
constexpr const GLuint VaColor = 1; // MUST CORRESPOND TO THE SHADER PROGRAM
|
||
constexpr const GLuint VaFiltering = 2; // MUST CORRESPOND TO THE SHADER PROGRAM
|
||
|
||
constexpr int8_t CurrentCacheVersion = 2;
|
||
|
||
//streamColor, nodeSize, nodeSizeLargerFlux, thresholdFlux,
|
||
constexpr const std::array<const char*, 27> UniformNames = {
|
||
"streamColor", "nodeSize", "nodeSizeLargerFlux", "thresholdFlux", "colorMode",
|
||
"filterLower", "filterUpper", "scalingMode", "colorTableRange", "domainLimZ",
|
||
"nodeSkip", "nodeSkipDefault", "nodeSkipEarth", "nodeSkipMethod",
|
||
"nodeSkipFluxThreshold", "nodeSkipRadiusThreshold", "fluxColorAlpha",
|
||
"fluxColorAlphaIlluminance", "earthPos", "distanceThreshold",
|
||
"enhanceMethod", "flowColor", "usingParticles",
|
||
"usingInterestingStreams","particleSize", "particleSpacing", "particleSpeed"
|
||
};
|
||
constexpr const std::array<const char*, 14> UniformNames2 = {
|
||
"time", "flowColoring", "maxNodeDistanceSize", "usingCameraPerspective",
|
||
"drawCircles", "drawHollow", "useGaussian", "usingRadiusPerspective",
|
||
"perspectiveDistanceFactor", "maxNodeSize", "minNodeSize", "usingPulse",
|
||
"usingGaussianPulse", "pulsatingAlways"
|
||
};
|
||
|
||
// --------------------------------- Property Info -------------------------------- //
|
||
constexpr openspace::properties::Property::PropertyInfo GoesEnergyBinsInfo = {
|
||
"GoesEnergy",
|
||
"Goes Energy",
|
||
"Select which energy bin you want to show. Emin01 is values > 10 Mev,"
|
||
"Default is Emin03 where values > 100 Mev."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo ColorModeInfo = {
|
||
"colorMode",
|
||
"Color Mode",
|
||
"Color lines uniformly or using color tables based on specific values on nodes,"
|
||
"for examples flux values."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo ColorTablePathInfo = {
|
||
"colorTablePath",
|
||
"Path to Color Table",
|
||
"Color Table/Transfer Function to use for 'By Flux Value' coloring."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo StreamColorInfo = {
|
||
"color",
|
||
"Color",
|
||
"Color of particles."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo NodeSizeInfo = {
|
||
"nodeSize",
|
||
"Size of nodes",
|
||
"Change the size of the nodes"
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo NodeSizeLargerFluxInfo = {
|
||
"nodeSizeLargerFlux",
|
||
"Size of nodes for larger flux",
|
||
"Change the size of the nodes when flux is larger than flux threshold value"
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo LineWidthInfo = {
|
||
"lineWidth",
|
||
"Line Width",
|
||
"This value specifies the line width of the field lines if the "
|
||
"selected render method includes lines."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo ThresholdFluxInfo = {
|
||
"thresholdFlux",
|
||
"Threshold flux value",
|
||
"This value specifies the threshold that will be changed with the flux value."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo FilteringInfo = {
|
||
"filterLower",
|
||
"Filtering Lower Value in AU",
|
||
"Use filtering to show nodes within a given range."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo FilteringUpperInfo = {
|
||
"filterUpper",
|
||
"Filtering Upper Value in AU",
|
||
"Use filtering to show nodes within a given range."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo AmountofNodesInfo = {
|
||
"amountOfNodes",
|
||
"Every nth node to render in",
|
||
"Show only every nth node"
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo DefaultNodeSkipInfo = {
|
||
"nodeSkip",
|
||
"Every nth node to render default",
|
||
"Show only every nth node outside of skippingmethod"
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo EarthNodeSkipInfo = {
|
||
"nodeSkipEarth",
|
||
"Every nth node to render close to Earth",
|
||
"Show only every nth node outside of skippingmethod"
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo ScalingmethodInfo = {
|
||
"scalingFlux",
|
||
"Scale the flux value with color table",
|
||
"Use scaling to color nodes with a given method."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo NodeskipMethodInfo = {
|
||
"skippingNodes",
|
||
"How to select nodes to skip",
|
||
"Methods to select nodes to skip."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo colorTableRangeInfo = {
|
||
"colorTableRange",
|
||
"Color Table Range",
|
||
"Valid range for the color table. [Min, Max]"
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo DomainZInfo = {
|
||
"zLimit",
|
||
"Z-limits",
|
||
"Valid range along the Z-axis. [Min, Max]"
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo FluxColorAlphaInfo = {
|
||
"fluxColorAlpha",
|
||
"Flux Color Alpha",
|
||
"The value of alpha for the flux color mode."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo
|
||
FluxColorAlphaIlluminanceInfo = {
|
||
"fluxColorAlphaIlluminance",
|
||
"Flux Color Alpha for illuminance",
|
||
"The value of alpha for the flux color mode."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo FluxNodeskipThresholdInfo = {
|
||
"skippingNodesByFlux",
|
||
"Skipping Nodes By Flux",
|
||
"Select nodes to skip depending on flux value."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo
|
||
RadiusNodeSkipThresholdInfo = {
|
||
"skippingNodesByRadius",
|
||
"Skipping Nodes By Radius",
|
||
"Select nodes to skip depending on Radius."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo EnhanceMethodInfo = {
|
||
"enhanceMethod",
|
||
"Enhance Method",
|
||
"Deciding what method to use for nodes close to earth"
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo DistanceplanetInfo = {
|
||
"distanceplanet",
|
||
"Distance Planet",
|
||
"Deciding what planet to check distance to."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo DistanceThresholdInfo = {
|
||
"distancePlanetThreshold",
|
||
"Threshold for distance between planet",
|
||
"Enhance the size of nodes dependent on distance to planet."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo MisalignedIndexInfo = {
|
||
"misalignedIndex",
|
||
"Index to shift sequence number",
|
||
"The misalignement number for sequence for fluxnodes vs Fieldlines"
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo FlowColorInfo = {
|
||
"flowcolor",
|
||
"Color of Flow",
|
||
"Color of Flow."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo FlowEnabledInfo = {
|
||
"flowEnabled",
|
||
"Flow Direction",
|
||
"Toggles the rendering of moving particles along the lines. Can, for example, "
|
||
"illustrate magnetic flow."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo InterestingStreamsInfo = {
|
||
"interestingStreamsEnabled",
|
||
"Interesting Streams Enabled",
|
||
"Toggles the rendering of selected streams."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo FlowParticleSizeInfo = {
|
||
"particleSize",
|
||
"Particle Size",
|
||
"Size of the particles."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo FlowParticleSpacingInfo = {
|
||
"particleSpacing",
|
||
"Particle Spacing",
|
||
"Spacing inbetween particles."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo FlowSpeedInfo = {
|
||
"speed",
|
||
"Speed",
|
||
"Speed of the flow."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo UseFlowColorInfo = {
|
||
"coloring",
|
||
"Color either by Flowcolor or Flow colortable",
|
||
"If set to true the flow will be colored by Flowcolor."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo TempInfo1 = {
|
||
"temp1",
|
||
"temp",
|
||
"Temp"
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo MaxNodeDistanceSizeInfo = {
|
||
"maxNodeDistanceSize",
|
||
"Max Node Distance Size",
|
||
"The maximum size of the nodes at a certin distance."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo NodeDistanceThresholdInfo = {
|
||
"nodeDistanceThreshold",
|
||
"Node Distance Threshold",
|
||
"Threshold for where to interpolate between the max and min node distance."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo
|
||
CameraPerspectiveEnabledInfo = {
|
||
"cameraPerspectiveEnabled",
|
||
"Use Camera perspective",
|
||
"Camera perspective changes the size of the nodes dependent on "
|
||
"distance from camera."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo DrawingCirclesInfo = {
|
||
"renderingcircles",
|
||
"Render as circles",
|
||
"Using fragment shader to draw nodes as circles instead of squares."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo DrawingHollowInfo = {
|
||
"renderingHollowCircles",
|
||
"Render as hollow circles",
|
||
"Using fragment shader to draw nodes as hollow circles."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo GaussiandAlphaFilterInfo = {
|
||
"renderingGaussianAlphaFilter",
|
||
"Alpha by Gaussian",
|
||
"Using fragment shader to draw nodes with Gaussian filter for alpha value."
|
||
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo
|
||
RadiusPerspectiveEnabledInfo = {
|
||
"radiusPerspectiveEnabled",
|
||
"Include radius with cameraperspective",
|
||
"If false, then nodes closer to the sun will not be larger "
|
||
"regardless of distance to camera."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo
|
||
PerspectiveDistanceFactorInfo = {
|
||
"perspectiveDistanceFactor",
|
||
"Perspective Distance factor",
|
||
"This value decides how far away the camera must be to start "
|
||
"impacting the node size."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo MinNodeSizeInfo = {
|
||
"minNodeSize",
|
||
"Minimum node size",
|
||
"The minimum node size."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo MaxNodeSizeInfo = {
|
||
"maxNodeSize",
|
||
"Maximum node size",
|
||
"The minimum node size."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo AlwaysPulseInfo = {
|
||
"alwaysPulsate",
|
||
"Pulsate regardless of camera position",
|
||
"Always have nodes close to earth pulsate regardless of position."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo pulseEnabledInfo = {
|
||
"pulseEnabled",
|
||
"Nodes close to Earth pulsate",
|
||
"Toggles the pulse for nodes close to Earth."
|
||
};
|
||
constexpr openspace::properties::Property::PropertyInfo gaussianPulseEnabledInfo = {
|
||
"gaussianPulseEnabled",
|
||
"Nodes close to Earth pulsate with alpha by gaussian",
|
||
"Toggles the pulse with alpha by gaussian for nodes close to Earth."
|
||
};
|
||
|
||
float stringToFloat(const std::string input, const float backupValue = 0.f) {
|
||
float tmp;
|
||
try {
|
||
tmp = std::stof(input);
|
||
}
|
||
catch (const std::invalid_argument& ia) {
|
||
LWARNING(fmt::format(
|
||
"Invalid argument: {}. '{}' is NOT a valid number", ia.what(), input
|
||
));
|
||
return backupValue;
|
||
}
|
||
return tmp;
|
||
}
|
||
|
||
struct [[codegen::Dictionary(RenderableFluxNodes)]] Parameters {
|
||
// path to source folder with the 3 binary files in it
|
||
std::string binarySourceFolder;
|
||
// [[codegen::verbatim(ColorTablePathInfo.description)]]
|
||
std::optional<std::vector<std::string>> colorTablePaths;
|
||
// [[codegen::verbatim(LineWidthInfo.description)]]
|
||
//float lineWidth;
|
||
// [[codegen::verbatim(GoesEnergyBinsInfo.description)]]
|
||
std::optional<int> energyBin;
|
||
};
|
||
#include "renderablefluxnodes_codegen.cpp"
|
||
|
||
// Changed everything from dvec3 to vec3
|
||
glm::vec3 sphericalToCartesianCoord(glm::vec3 position) {
|
||
glm::vec3 cartesianPosition = glm::vec3();
|
||
|
||
// ρsinφcosθ
|
||
cartesianPosition.x = position.x * sin(position.z) * cos(position.y);
|
||
// ρsinφsinθ
|
||
cartesianPosition.y = position.x * sin(position.z) * sin(position.y);
|
||
// ρcosφ
|
||
cartesianPosition.z = position.x * cos(position.z);
|
||
|
||
return cartesianPosition;
|
||
}
|
||
} //namespace
|
||
|
||
namespace openspace {
|
||
|
||
documentation::Documentation RenderableFluxNodes::Documentation() {
|
||
return codegen::doc<Parameters>("space_renderable_flux_nodes");
|
||
}
|
||
|
||
using namespace properties;
|
||
RenderableFluxNodes::RenderableFluxNodes(const ghoul::Dictionary& dictionary)
|
||
|
||
: Renderable(dictionary)
|
||
, _pGoesEnergyBins(GoesEnergyBinsInfo, OptionProperty::DisplayType::Radio)
|
||
, _pColorGroup({ "Color" })
|
||
, _pColorMode(ColorModeInfo, OptionProperty::DisplayType::Radio)
|
||
, _pScalingmethod(ScalingmethodInfo, OptionProperty::DisplayType::Radio)
|
||
, _pNodeskipMethod(NodeskipMethodInfo, OptionProperty::DisplayType::Radio)
|
||
, _pEnhancemethod(EnhanceMethodInfo, OptionProperty::DisplayType::Dropdown)
|
||
, _pColorTablePath(ColorTablePathInfo)
|
||
, _pStreamColor(StreamColorInfo,
|
||
glm::vec4(0.96f, 0.88f, 0.8f, 1.f),
|
||
glm::vec4(0.f),
|
||
glm::vec4(1.f))
|
||
, _pStreamGroup({ "Streams" })
|
||
, _pNodesamountGroup({ "NodeGroup" })
|
||
, _pNodeSize(NodeSizeInfo, 2.f, 1.f, 10.f)
|
||
, _pNodeSizeLargerFlux(NodeSizeLargerFluxInfo, 2.f, 1.f, 10.f)
|
||
, _pLineWidth(LineWidthInfo, 4.f, 1.f, 20.f)
|
||
, _pColorTableRange(colorTableRangeInfo)
|
||
, _pDomainZ(DomainZInfo)
|
||
, _pFluxColorAlpha(FluxColorAlphaInfo, 0.f, 0.f, 1.f)
|
||
, _pFluxColorAlphaIlluminance(FluxColorAlphaIlluminanceInfo, 1.f, 0.f, 1.f)
|
||
, _pThresholdFlux(ThresholdFluxInfo, -1.5f, -50.f, 10.f)
|
||
, _pFilteringLower(FilteringInfo, 0.f, 0.f, 5.f)
|
||
, _pFilteringUpper(FilteringUpperInfo, 5.f, 0.f, 5.f)
|
||
, _pAmountofNodes(AmountofNodesInfo, 1, 1, 100)
|
||
, _pDefaultNodeSkip(DefaultNodeSkipInfo, 1, 1, 100)
|
||
, _pEarthNodeSkip(EarthNodeSkipInfo, 1, 1, 100)
|
||
, _pFluxNodeskipThreshold(FluxNodeskipThresholdInfo, 0, -20, 10)
|
||
, _pRadiusNodeSkipThreshold(RadiusNodeSkipThresholdInfo, 0.f, 0.f, 5.f)
|
||
, _pEarthdistGroup({ "Earthfocus" })
|
||
, _pDistanceThreshold(DistanceThresholdInfo, 0.0f, 0.0f, 1.0f)
|
||
, _pMisalignedIndex(MisalignedIndexInfo, 0, -5, 20)
|
||
, _pFlowColor(
|
||
FlowColorInfo,
|
||
glm::vec4(0.96f, 0.88f, 0.8f, 0.5f),
|
||
glm::vec4(0.f),
|
||
glm::vec4(1.f)
|
||
)
|
||
, _pFlowEnabled(FlowEnabledInfo, false)
|
||
, _pInterestingStreamsEnabled(InterestingStreamsInfo, false)
|
||
, _pFlowGroup({ "Flow" })
|
||
, _pFlowParticleSize(FlowParticleSizeInfo, 5, 0, 500)
|
||
, _pFlowParticleSpacing(FlowParticleSpacingInfo, 60, 0, 500)
|
||
, _pFlowSpeed(FlowSpeedInfo, 20, 0, 1000)
|
||
, _pUseFlowColor(UseFlowColorInfo, false)
|
||
, _scaleFactor(TempInfo1, 150.f, 1.f, 500.f)
|
||
, _pMaxNodeDistanceSize(MaxNodeDistanceSizeInfo, 1.f, 1.f, 10.f)
|
||
, _pNodeDistanceThreshold(NodeDistanceThresholdInfo, 0.f, 0.f, 40.f)
|
||
, _pCameraPerspectiveEnabled(CameraPerspectiveEnabledInfo, false)
|
||
, _pDrawingCircles(DrawingCirclesInfo, false)
|
||
, _pCameraPerspectiveGroup({" CameraPerspective"})
|
||
, _pDrawingHollow(DrawingHollowInfo, false)
|
||
, _pGaussianAlphaFilter(GaussiandAlphaFilterInfo, false)
|
||
, _pRadiusPerspectiveEnabled(RadiusPerspectiveEnabledInfo, true)
|
||
, _pPerspectiveDistanceFactor(PerspectiveDistanceFactorInfo, 2.67f, 1.f, 20.f)
|
||
, _pMaxNodeSize(MaxNodeSizeInfo, 30.f, 1.f, 200.f)
|
||
, _pMinNodeSize(MinNodeSizeInfo, 2.f, 1.f, 10.f)
|
||
, _pPulseEnabled(pulseEnabledInfo, false)
|
||
, _pGaussianPulseEnabled(gaussianPulseEnabledInfo, false)
|
||
, _pPulseAlways(AlwaysPulseInfo, false)
|
||
|
||
{
|
||
|
||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||
|
||
|
||
if (p.colorTablePaths.has_value()) {
|
||
_colorTablePaths = p.colorTablePaths.value_or(_colorTablePaths);
|
||
_transferFunction = std::make_unique<TransferFunction>(_colorTablePaths[0]);
|
||
_transferFunctionCMR =
|
||
std::make_unique<TransferFunction>(absPath(_colorTablePaths[1]).string());
|
||
_transferFunctionEarth =
|
||
std::make_unique<TransferFunction>(absPath(_colorTablePaths[2]).string());
|
||
_transferFunctionFlow =
|
||
std::make_unique<TransferFunction>(absPath(_colorTablePaths[3]).string());
|
||
}
|
||
_pColorTablePath = _colorTablePaths[0];
|
||
|
||
_binarySourceFolderPath = p.binarySourceFolder;
|
||
if (std::filesystem::is_directory(_binarySourceFolderPath)) {
|
||
// Extract all file paths from the provided folder
|
||
_binarySourceFiles.clear();
|
||
namespace fs = std::filesystem;
|
||
for (const fs::directory_entry& e : fs::directory_iterator(
|
||
_binarySourceFolderPath)) {
|
||
if (e.is_regular_file()) {
|
||
_binarySourceFiles.push_back(e.path().string());
|
||
}
|
||
}
|
||
std::sort(_binarySourceFiles.begin(), _binarySourceFiles.end());
|
||
|
||
// Ensure that there are available and valid source files left
|
||
if (_binarySourceFiles.empty()) {
|
||
LERROR(fmt::format(
|
||
"{} contains no files", _binarySourceFolderPath
|
||
));
|
||
}
|
||
}
|
||
else {
|
||
LERROR(fmt::format(
|
||
"Source folder {} is not a valid directory",
|
||
_binarySourceFolderPath
|
||
));
|
||
}
|
||
|
||
// --------------------- Add Options to OptionProperties --------------------- //
|
||
_pGoesEnergyBins.addOption(static_cast<int>(GoesEnergyBins::Emin01), "Emin01");
|
||
_pGoesEnergyBins.addOption(static_cast<int>(GoesEnergyBins::Emin03), "Emin03");
|
||
_pColorMode.addOption(static_cast<int>(ColorMethod::ByFluxValue), "By Flux Value");
|
||
_pColorMode.addOption(static_cast<int>(ColorMethod::Uniform), "Uniform");
|
||
|
||
_pScalingmethod.addOption(static_cast<int>(ScalingMethod::Flux), "Flux");
|
||
_pScalingmethod.addOption(static_cast<int>(ScalingMethod::RFlux), "Radius * Flux");
|
||
_pScalingmethod.addOption(static_cast<int>(ScalingMethod::R2Flux), "Radius^2 * Flux");
|
||
_pScalingmethod.addOption(
|
||
static_cast<int>(ScalingMethod::log10RFlux), "log10(r) * Flux");
|
||
_pScalingmethod.addOption(static_cast<int>(ScalingMethod::lnRFlux), "ln(r) * Flux");
|
||
|
||
_pNodeskipMethod.addOption(static_cast<int>(NodeSkipMethod::Uniform), "Uniform");
|
||
_pNodeskipMethod.addOption(static_cast<int>(NodeSkipMethod::Flux), "Flux");
|
||
_pNodeskipMethod.addOption(static_cast<int>(NodeSkipMethod::Radius), "Radius");
|
||
_pNodeskipMethod.addOption(
|
||
static_cast<int>(NodeSkipMethod::Streamnumber), "Streamnumber");
|
||
|
||
_pEnhancemethod.addOption(
|
||
static_cast<int>(EnhanceMethod::Sizescaling), "SizeScaling");
|
||
_pEnhancemethod.addOption(
|
||
static_cast<int>(EnhanceMethod::Colortables), "ColorTables");
|
||
_pEnhancemethod.addOption(
|
||
static_cast<int>(EnhanceMethod::Sizeandcolor), "Sizescaling and colortables");
|
||
_pEnhancemethod.addOption(
|
||
static_cast<int>(EnhanceMethod::Illuminance), "Illuminance");
|
||
|
||
if (p.energyBin.has_value()) {
|
||
_pGoesEnergyBins.setValue(p.energyBin.value());
|
||
}
|
||
else { // default int 1 == Emin03 == MeV>100
|
||
LWARNING("Assuming default value 1, meaning Emin03");
|
||
_pGoesEnergyBins.setValue(1);
|
||
}
|
||
}
|
||
|
||
void RenderableFluxNodes::initialize() {
|
||
setModelDependentConstants();
|
||
|
||
populateStartTimes();
|
||
|
||
loadNodeData(_pGoesEnergyBins.option().value);
|
||
|
||
computeSequenceEndTime();
|
||
}
|
||
|
||
void RenderableFluxNodes::initializeGL() {
|
||
|
||
// Setup shader program
|
||
_shaderProgram = global::renderEngine->buildRenderProgram(
|
||
"Fluxnodes",
|
||
absPath("${MODULE_SPACE}/shaders/fluxnodes_vs.glsl"),
|
||
absPath("${MODULE_SPACE}/shaders/fluxnodes_fs.glsl")
|
||
);
|
||
|
||
_uniformCache.streamColor = _shaderProgram->uniformLocation("streamColor");
|
||
_uniformCache.nodeSize = _shaderProgram->uniformLocation("nodeSize");
|
||
_uniformCache.nodeSizeLargerFlux =
|
||
_shaderProgram->uniformLocation("nodeSizeLargerFlux");
|
||
_uniformCache.thresholdFlux = _shaderProgram->uniformLocation("thresholdFlux");
|
||
|
||
ghoul::opengl::updateUniformLocations(*_shaderProgram, _uniformCache, UniformNames);
|
||
ghoul::opengl::updateUniformLocations(*_shaderProgram, _uniformCache2, UniformNames2);
|
||
|
||
glGenVertexArrays(1, &_vertexArrayObject);
|
||
glGenBuffers(1, &_vertexPositionBuffer);
|
||
glGenBuffers(1, &_vertexColorBuffer);
|
||
glGenBuffers(1, &_vertexFilteringBuffer);
|
||
|
||
// Needed for alpha transparency
|
||
setRenderBin(Renderable::RenderBin::PreDeferredTransparent);
|
||
setupProperties();
|
||
}
|
||
|
||
void RenderableFluxNodes::definePropertyCallbackFunctions() {
|
||
// Add Property Callback Functions
|
||
|
||
_pColorTablePath.onChange([this] {
|
||
_transferFunction->setPath(_pColorTablePath);
|
||
_colorTablePaths[0] = _pColorTablePath;
|
||
});
|
||
|
||
_pGoesEnergyBins.onChange([this] {
|
||
loadNodeData(_pGoesEnergyBins.option().value);
|
||
});
|
||
}
|
||
|
||
void RenderableFluxNodes::setModelDependentConstants() {
|
||
// Just used as a default value.
|
||
float limit = 8.f;
|
||
_pColorTableRange.setMinValue(glm::vec2(-limit));
|
||
_pColorTableRange.setMaxValue(glm::vec2(limit));
|
||
_pColorTableRange = glm::vec2(-2, 4);
|
||
|
||
float limitZMin = -2.5f;
|
||
float limitZMax = 2.5f;
|
||
|
||
_pDomainZ.setMinValue(glm::vec2(limitZMin));
|
||
_pDomainZ.setMaxValue(glm::vec2(limitZMax));
|
||
_pDomainZ = glm::vec2(limitZMin, limitZMax);
|
||
}
|
||
|
||
void RenderableFluxNodes::loadNodeData(const int& energybinOption) {
|
||
constexpr const float AuToMeter = 149597870700.f; // Astronomical Units
|
||
|
||
LDEBUG("Loading in binary files directly from sync folder");
|
||
|
||
std::string energybin;
|
||
switch (energybinOption) {
|
||
case 0:
|
||
energybin = "_emin01";
|
||
break;
|
||
case 1:
|
||
energybin = "_emin03";
|
||
break;
|
||
}
|
||
|
||
std::string _file = _binarySourceFolderPath + "\\positions" + energybin;
|
||
std::string _file2 = _binarySourceFolderPath + "\\fluxes" + energybin;
|
||
std::string _file3 = _binarySourceFolderPath + "\\radiuses" + energybin;
|
||
|
||
std::ifstream fileStream(_file, std::ifstream::binary);
|
||
std::ifstream fileStream2(_file2, std::ifstream::binary);
|
||
std::ifstream fileStream3(_file3, std::ifstream::binary);
|
||
|
||
if (!fileStream.good()) {
|
||
LERROR(fmt::format("Could not read file '{}'", _file));
|
||
return;
|
||
}
|
||
|
||
uint32_t nNodesPerTimestep = 0;
|
||
fileStream.read(reinterpret_cast<char*>(&nNodesPerTimestep), sizeof(uint32_t));
|
||
|
||
uint32_t nTimeSteps = 0;
|
||
fileStream.read(reinterpret_cast<char*>(&nTimeSteps), sizeof(uint32_t));
|
||
_nStates = nTimeSteps;
|
||
|
||
if (_nStates != _startTimes.size()) {
|
||
LERROR("number of states, _nStates, and number of start times, _startTimes, "
|
||
"dont match");
|
||
return;
|
||
}
|
||
|
||
_statesColor.clear();
|
||
_statesPos.clear();
|
||
_statesRadius.clear();
|
||
|
||
for (unsigned int i = 0; i < _nStates; ++i) {
|
||
_vertexPositions.resize(nNodesPerTimestep);
|
||
fileStream.read(reinterpret_cast<char*>(
|
||
_vertexPositions.data()),
|
||
nNodesPerTimestep * sizeof(glm::vec3));
|
||
|
||
_statesPos.push_back(_vertexPositions);
|
||
_vertexPositions.clear();
|
||
}
|
||
for (unsigned int i = 0; i < _nStates; ++i) {
|
||
_vertexColor.resize(nNodesPerTimestep);
|
||
fileStream2.read(reinterpret_cast<char*>(
|
||
_vertexColor.data()),
|
||
nNodesPerTimestep * sizeof(float));
|
||
|
||
_statesColor.push_back(_vertexColor);
|
||
_vertexColor.clear();
|
||
}
|
||
for (unsigned int i = 0; i < _nStates; ++i) {
|
||
_vertexRadius.resize(nNodesPerTimestep);
|
||
fileStream3.read(reinterpret_cast<char*>(
|
||
_vertexRadius.data()),
|
||
nNodesPerTimestep * sizeof(float));
|
||
|
||
_statesRadius.push_back(_vertexRadius);
|
||
_vertexRadius.clear();
|
||
}
|
||
}
|
||
|
||
void RenderableFluxNodes::setupProperties() {
|
||
|
||
// -------------- Add non-grouped properties (enablers and buttons) -------------- //
|
||
addProperty(_pGoesEnergyBins);
|
||
addProperty(_pLineWidth);
|
||
addProperty(_pMisalignedIndex);
|
||
addProperty(_scaleFactor);
|
||
|
||
// ----------------------------- Add Property Groups ----------------------------- //
|
||
addPropertySubOwner(_pColorGroup);
|
||
addPropertySubOwner(_pStreamGroup);
|
||
addPropertySubOwner(_pNodesamountGroup);
|
||
addPropertySubOwner(_pEarthdistGroup);
|
||
addPropertySubOwner(_pCameraPerspectiveGroup);
|
||
_pEarthdistGroup.addPropertySubOwner(_pFlowGroup);
|
||
|
||
// ------------------------- Add Properties to the groups ------------------------ //
|
||
_pColorGroup.addProperty(_pColorMode);
|
||
_pColorGroup.addProperty(_pScalingmethod);
|
||
_pColorGroup.addProperty(_pColorTableRange);
|
||
_pColorGroup.addProperty(_pColorTablePath);
|
||
_pColorGroup.addProperty(_pStreamColor);
|
||
_pColorGroup.addProperty(_pFluxColorAlpha);
|
||
_pColorGroup.addProperty(_pFluxColorAlphaIlluminance);
|
||
|
||
_pStreamGroup.addProperty(_pThresholdFlux);
|
||
_pStreamGroup.addProperty(_pFilteringLower);
|
||
_pStreamGroup.addProperty(_pFilteringUpper);
|
||
_pStreamGroup.addProperty(_pDomainZ);
|
||
|
||
_pNodesamountGroup.addProperty(_pNodeskipMethod);
|
||
_pNodesamountGroup.addProperty(_pAmountofNodes);
|
||
_pNodesamountGroup.addProperty(_pDefaultNodeSkip);
|
||
_pNodesamountGroup.addProperty(_pEarthNodeSkip);
|
||
_pNodesamountGroup.addProperty(_pNodeSize);
|
||
_pNodesamountGroup.addProperty(_pNodeSizeLargerFlux);
|
||
_pNodesamountGroup.addProperty(_pFluxNodeskipThreshold);
|
||
_pNodesamountGroup.addProperty(_pRadiusNodeSkipThreshold);
|
||
_pNodesamountGroup.addProperty(_pMaxNodeDistanceSize);
|
||
_pNodesamountGroup.addProperty(_pNodeDistanceThreshold);
|
||
|
||
_pEarthdistGroup.addProperty(_pDistanceThreshold);
|
||
_pEarthdistGroup.addProperty(_pEnhancemethod);
|
||
_pEarthdistGroup.addProperty(_pInterestingStreamsEnabled);
|
||
|
||
_pFlowGroup.addProperty(_pFlowEnabled);
|
||
_pFlowGroup.addProperty(_pFlowColor);
|
||
_pFlowGroup.addProperty(_pFlowParticleSize);
|
||
_pFlowGroup.addProperty(_pFlowParticleSpacing);
|
||
_pFlowGroup.addProperty(_pFlowSpeed);
|
||
_pFlowGroup.addProperty(_pUseFlowColor);
|
||
|
||
_pCameraPerspectiveGroup.addProperty(_pCameraPerspectiveEnabled);
|
||
_pCameraPerspectiveGroup.addProperty(_pPerspectiveDistanceFactor);
|
||
_pCameraPerspectiveGroup.addProperty(_pDrawingCircles);
|
||
_pCameraPerspectiveGroup.addProperty(_pDrawingHollow);
|
||
_pCameraPerspectiveGroup.addProperty(_pGaussianAlphaFilter);
|
||
_pCameraPerspectiveGroup.addProperty(_pRadiusPerspectiveEnabled);
|
||
_pCameraPerspectiveGroup.addProperty(_pMaxNodeSize);
|
||
_pCameraPerspectiveGroup.addProperty(_pMinNodeSize);
|
||
_pCameraPerspectiveGroup.addProperty(_pPulseEnabled);
|
||
_pCameraPerspectiveGroup.addProperty(_pGaussianPulseEnabled);
|
||
_pCameraPerspectiveGroup.addProperty(_pPulseAlways);
|
||
|
||
definePropertyCallbackFunctions();
|
||
}
|
||
|
||
void RenderableFluxNodes::deinitializeGL() {
|
||
glDeleteVertexArrays(1, &_vertexArrayObject);
|
||
_vertexArrayObject = 0;
|
||
|
||
glDeleteBuffers(1, &_vertexPositionBuffer);
|
||
_vertexPositionBuffer = 0;
|
||
|
||
glDeleteBuffers(1, &_vertexColorBuffer);
|
||
_vertexColorBuffer = 0;
|
||
|
||
glDeleteBuffers(1, &_vertexFilteringBuffer);
|
||
_vertexFilteringBuffer = 0;
|
||
|
||
if (_shaderProgram) {
|
||
global::renderEngine->removeRenderProgram(_shaderProgram.get());
|
||
_shaderProgram = nullptr;
|
||
}
|
||
}
|
||
|
||
bool RenderableFluxNodes::isReady() const {
|
||
return _shaderProgram != nullptr;
|
||
}
|
||
|
||
void RenderableFluxNodes::populateStartTimes() {
|
||
|
||
// number of characters in UTC ISO8601 format (without additional Z)
|
||
// 'YYYY-MM-DDTHH-MM-SS-XXX'
|
||
constexpr const int timeFormatSize = 23;
|
||
|
||
std::string timeFile = "";
|
||
std::string fileType = "";
|
||
for (const std::string& filePath : _binarySourceFiles) {
|
||
timeFile = filePath;
|
||
|
||
if (filePath.substr(filePath.find_last_of(".") + 1) == "csv" ) {
|
||
fileType = "csv";
|
||
break;
|
||
}
|
||
|
||
else if (filePath.substr(filePath.find_last_of(".") + 1) == "dat") {
|
||
fileType = "dat";
|
||
break;
|
||
}
|
||
|
||
else if (filePath.substr(filePath.find_last_of(".") + 1) == "txt") {
|
||
fileType = "txt";
|
||
break;
|
||
}
|
||
//if no file extention but word "time" in file name
|
||
else if (filePath.find("time") != std::string::npos &&
|
||
filePath.find(".") == std::string::npos) {
|
||
break;
|
||
}
|
||
else {
|
||
LERROR(fmt::format("Error in file type or nameing of file '{}'.",
|
||
" Time meta file supports csv, dat, txt or without file extention",
|
||
" (but then have to include 'time' in filename)", filePath
|
||
));
|
||
timeFile = "";
|
||
}
|
||
}
|
||
|
||
if (timeFile.empty()) {
|
||
LERROR("Could not find a metadata file with time steps,"
|
||
" such as a csv, dat, txt or no file extention with 'time' in filename");
|
||
}
|
||
// time filestream
|
||
std::ifstream tfs(timeFile);
|
||
if (!tfs.is_open()) throw std::runtime_error("Could not open file");
|
||
|
||
std::string line;
|
||
std::getline(tfs, line); //gets only first line
|
||
std::stringstream s;
|
||
s << line;
|
||
|
||
int nColumns = 0;
|
||
std::string columnName;
|
||
//loops through the names/columns in first line/header
|
||
while (s >> columnName) ++nColumns;
|
||
|
||
while (std::getline(tfs, line)) { //for each line of data
|
||
std::istringstream iss(line);
|
||
for (int i = 0; i < nColumns; ++i) { //for each column in line
|
||
std::string columnValue;
|
||
iss >> columnValue;
|
||
if (i == nColumns - 1) { // last column
|
||
if (columnValue.length() == 23) {
|
||
// Ensure the separators are correct
|
||
columnValue.replace(4, 1, "-");
|
||
columnValue.replace(7, 1, "-");
|
||
columnValue.replace(13, 1, ":");
|
||
columnValue.replace(16, 1, ":");
|
||
columnValue.replace(19, 1, ".");
|
||
const double triggerTime = Time::convertTime(columnValue);
|
||
LDEBUG("timestring " + columnValue);
|
||
_startTimes.push_back(triggerTime);
|
||
}
|
||
else {
|
||
LERROR(fmt::format("Error in file formating. Last column in ",
|
||
"file '{}' is not on UTC ISO8601 format", timeFile
|
||
));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void RenderableFluxNodes::updateActiveTriggerTimeIndex(double currentTime) {
|
||
auto iter = std::upper_bound(_startTimes.begin(), _startTimes.end(), currentTime);
|
||
if (iter != _startTimes.end()) {
|
||
if (iter != _startTimes.begin()) {
|
||
_activeTriggerTimeIndex = static_cast<int>(
|
||
std::distance(_startTimes.begin(), iter)
|
||
) - 1;
|
||
}
|
||
else {
|
||
_activeTriggerTimeIndex = 0;
|
||
}
|
||
}
|
||
else {
|
||
_activeTriggerTimeIndex = static_cast<int>(_nStates) - 1;
|
||
}
|
||
}
|
||
void RenderableFluxNodes::render(const RenderData& data, RendererTasks&) {
|
||
if (_activeTriggerTimeIndex != -1) {
|
||
_shaderProgram->activate();
|
||
|
||
// Calculate Model View MatrixProjection
|
||
const glm::dmat4 rotMat = glm::dmat4(data.modelTransform.rotation);
|
||
const glm::dmat4 modelMat =
|
||
glm::translate(glm::dmat4(1.0), data.modelTransform.translation) *
|
||
rotMat *
|
||
glm::dmat4(glm::scale(glm::dmat4(1), glm::dvec3(data.modelTransform.scale)));
|
||
const glm::dmat4 modelViewMat = data.camera.combinedViewMatrix() * modelMat;
|
||
|
||
//not in use atm.
|
||
_shaderProgram->setUniform("modelViewProjection",
|
||
data.camera.sgctInternal.projectionMatrix() * glm::mat4(modelViewMat));
|
||
|
||
SceneGraphNode* earthNode = sceneGraphNode("Earth");
|
||
glm::vec3 earthPos = earthNode->worldPosition() * data.modelTransform.rotation;
|
||
|
||
_shaderProgram->setUniform(_uniformCache.streamColor, _pStreamColor);
|
||
_shaderProgram->setUniform(_uniformCache.nodeSize, _pNodeSize);
|
||
_shaderProgram->setUniform(_uniformCache.nodeSizeLargerFlux,
|
||
_pNodeSizeLargerFlux);
|
||
_shaderProgram->setUniform(_uniformCache.thresholdFlux, _pThresholdFlux);
|
||
_shaderProgram->setUniform(_uniformCache.colorMode, _pColorMode);
|
||
_shaderProgram->setUniform(_uniformCache.filterLower, _pFilteringLower);
|
||
_shaderProgram->setUniform(_uniformCache.filterUpper, _pFilteringUpper);
|
||
_shaderProgram->setUniform(_uniformCache.scalingMode, _pScalingmethod);
|
||
_shaderProgram->setUniform(_uniformCache.colorTableRange,
|
||
_pColorTableRange.value());
|
||
_shaderProgram->setUniform(_uniformCache.domainLimZ, _pDomainZ.value());
|
||
_shaderProgram->setUniform(_uniformCache.nodeSkip, _pAmountofNodes);
|
||
_shaderProgram->setUniform(_uniformCache.nodeSkipDefault, _pDefaultNodeSkip);
|
||
_shaderProgram->setUniform(_uniformCache.nodeSkipEarth, _pEarthNodeSkip);
|
||
_shaderProgram->setUniform(_uniformCache.nodeSkipMethod, _pNodeskipMethod);
|
||
_shaderProgram->setUniform(_uniformCache.nodeSkipFluxThreshold,
|
||
_pFluxNodeskipThreshold);
|
||
_shaderProgram->setUniform(_uniformCache.nodeSkipRadiusThreshold,
|
||
_pRadiusNodeSkipThreshold);
|
||
_shaderProgram->setUniform(_uniformCache.fluxColorAlpha, _pFluxColorAlpha);
|
||
_shaderProgram->setUniform(_uniformCache.fluxColorAlphaIlluminance,
|
||
_pFluxColorAlphaIlluminance);
|
||
_shaderProgram->setUniform(_uniformCache.earthPos, earthPos);
|
||
_shaderProgram->setUniform(_uniformCache.distanceThreshold, _pDistanceThreshold);
|
||
_shaderProgram->setUniform(_uniformCache.enhanceMethod, _pEnhancemethod);
|
||
_shaderProgram->setUniform(_uniformCache.flowColor, _pFlowColor);
|
||
_shaderProgram->setUniform(_uniformCache.usingParticles, _pFlowEnabled);
|
||
_shaderProgram->setUniform(_uniformCache.usingInterestingStreams,
|
||
_pInterestingStreamsEnabled);
|
||
_shaderProgram->setUniform(_uniformCache.particleSize, _pFlowParticleSize);
|
||
_shaderProgram->setUniform(_uniformCache.particleSpacing, _pFlowParticleSpacing);
|
||
_shaderProgram->setUniform(_uniformCache.particleSpeed, _pFlowSpeed);
|
||
_shaderProgram->setUniform(_uniformCache2.time,
|
||
global::windowDelegate->applicationTime() * -1);
|
||
_shaderProgram->setUniform(_uniformCache2.flowColoring, _pUseFlowColor);
|
||
_shaderProgram->setUniform(_uniformCache2.maxNodeDistanceSize,
|
||
_pMaxNodeDistanceSize);
|
||
_shaderProgram->setUniform(_uniformCache2.usingCameraPerspective,
|
||
_pCameraPerspectiveEnabled);
|
||
_shaderProgram->setUniform(_uniformCache2.drawCircles, _pDrawingCircles);
|
||
_shaderProgram->setUniform(_uniformCache2.drawHollow, _pDrawingHollow);
|
||
_shaderProgram->setUniform(_uniformCache2.useGaussian, _pGaussianAlphaFilter);
|
||
_shaderProgram->setUniform(_uniformCache2.usingRadiusPerspective,
|
||
_pRadiusPerspectiveEnabled);
|
||
_shaderProgram->setUniform(_uniformCache2.perspectiveDistanceFactor,
|
||
_pPerspectiveDistanceFactor);
|
||
_shaderProgram->setUniform(_uniformCache2.maxNodeSize, _pMaxNodeSize);
|
||
_shaderProgram->setUniform(_uniformCache2.minNodeSize, _pMinNodeSize);
|
||
_shaderProgram->setUniform(_uniformCache2.usingPulse, _pPulseEnabled);
|
||
_shaderProgram->setUniform(_uniformCache2.usingGaussianPulse,
|
||
_pGaussianPulseEnabled);
|
||
_shaderProgram->setUniform(_uniformCache2.pulsatingAlways, _pPulseAlways);
|
||
|
||
glm::vec3 cameraPos = data.camera.positionVec3() * data.modelTransform.rotation;
|
||
|
||
_shaderProgram->setUniform("cameraPos", cameraPos);
|
||
|
||
if (_pColorMode == static_cast<int>(ColorMethod::ByFluxValue)) {
|
||
ghoul::opengl::TextureUnit textureUnit;
|
||
textureUnit.activate();
|
||
_transferFunction->bind(); // Calls update internally
|
||
_shaderProgram->setUniform("colorTable", textureUnit);
|
||
|
||
ghoul::opengl::TextureUnit textureUnitCMR;
|
||
textureUnitCMR.activate();
|
||
_transferFunctionCMR->bind(); // Calls update internally
|
||
_shaderProgram->setUniform("colorTableCMR", textureUnitCMR);
|
||
|
||
ghoul::opengl::TextureUnit textureUnitEarth;
|
||
textureUnitEarth.activate();
|
||
_transferFunctionEarth->bind(); // Calls update internally
|
||
_shaderProgram->setUniform("colorTableEarth", textureUnitEarth);
|
||
|
||
ghoul::opengl::TextureUnit textureUnitFlow;
|
||
textureUnitFlow.activate();
|
||
_transferFunctionFlow->bind(); // Calls update internally
|
||
_shaderProgram->setUniform("colorTableFlow", textureUnitFlow);
|
||
|
||
}
|
||
|
||
glBindVertexArray(_vertexArrayObject);
|
||
|
||
glDrawArrays(
|
||
GL_POINTS,
|
||
0,
|
||
static_cast<GLsizei>(_vertexPositions.size())
|
||
);
|
||
|
||
glBindVertexArray(0);
|
||
_shaderProgram->deactivate();
|
||
}
|
||
}
|
||
inline void unbindGL() {
|
||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||
glBindVertexArray(0);
|
||
}
|
||
|
||
void RenderableFluxNodes::computeSequenceEndTime() {
|
||
if (_nStates > 1) {
|
||
const double lastTriggerTime = _startTimes[_nStates - 1];
|
||
const double sequenceDuration = lastTriggerTime - _startTimes[0];
|
||
const double averageStateDuration = sequenceDuration /
|
||
(static_cast<double>(_nStates) - 1.0);
|
||
_sequenceEndTime = lastTriggerTime + averageStateDuration;
|
||
}
|
||
else if (_nStates == 1) {
|
||
// If there's just one state it should never disappear!
|
||
_sequenceEndTime = DBL_MAX;
|
||
}
|
||
else {
|
||
LWARNING("Start up or error?");
|
||
}
|
||
}
|
||
|
||
void RenderableFluxNodes::update(const UpdateData& data) {
|
||
if (!this->_enabled) return;
|
||
if (_shaderProgram->isDirty()) {
|
||
_shaderProgram->rebuildFromFile();
|
||
}
|
||
bool needsUpdate = true;
|
||
//Everything below is for updating depending on time
|
||
const double currentTime = data.time.j2000Seconds();
|
||
const bool isInInterval = (currentTime >= _startTimes[0]) &&
|
||
(currentTime < _sequenceEndTime);
|
||
//const bool isInInterval = true;
|
||
if (isInInterval) {
|
||
const size_t nextIdx = _activeTriggerTimeIndex + 1;
|
||
if (
|
||
// true => Previous frame was not within the sequence interval
|
||
//_activeTriggerTimeIndex < 0 ||
|
||
// true => We stepped back to a time represented by another state
|
||
currentTime < _startTimes[_activeTriggerTimeIndex] ||
|
||
// true => We stepped forward to a time represented by another state
|
||
(nextIdx < _nStates && currentTime >= _startTimes[nextIdx]))
|
||
{
|
||
updateActiveTriggerTimeIndex(currentTime);
|
||
|
||
needsUpdate = true;
|
||
|
||
} // else {we're still in same state as previous frame (no changes needed)}
|
||
}
|
||
else {
|
||
_activeTriggerTimeIndex = -1;
|
||
needsUpdate = false;
|
||
}
|
||
|
||
if (needsUpdate) {
|
||
|
||
if(!_statesPos[_activeTriggerTimeIndex].empty()) {
|
||
//if (_activeTriggerTimeIndex > _pMisalignedIndex) {
|
||
// _activeTriggerTimeIndex += -_pMisalignedIndex;
|
||
//}
|
||
_vertexPositions = _statesPos[_activeTriggerTimeIndex];//TODO urgent.
|
||
_vertexColor = _statesColor[_activeTriggerTimeIndex]; //access violation
|
||
_vertexRadius = _statesRadius[_activeTriggerTimeIndex];
|
||
needsUpdate = false;
|
||
updatePositionBuffer();
|
||
updateVertexColorBuffer();
|
||
updateVertexFilteringBuffer();
|
||
}
|
||
}
|
||
|
||
if (_shaderProgram->isDirty()) {
|
||
_shaderProgram->rebuildFromFile();
|
||
ghoul::opengl::updateUniformLocations(*_shaderProgram, _uniformCache,
|
||
UniformNames);
|
||
ghoul::opengl::updateUniformLocations(*_shaderProgram, _uniformCache2,
|
||
UniformNames2);
|
||
}
|
||
}
|
||
|
||
void RenderableFluxNodes::updatePositionBuffer() {
|
||
glBindVertexArray(_vertexArrayObject);
|
||
glBindBuffer(GL_ARRAY_BUFFER, _vertexPositionBuffer);
|
||
|
||
const std::vector<glm::vec3>& vertPos = _vertexPositions;
|
||
|
||
glBufferData(
|
||
GL_ARRAY_BUFFER,
|
||
vertPos.size() * sizeof(glm::vec3),
|
||
vertPos.data(),
|
||
GL_STATIC_DRAW
|
||
);
|
||
|
||
glEnableVertexAttribArray(VaPosition);
|
||
glEnable(GL_PROGRAM_POINT_SIZE);
|
||
glVertexAttribPointer(VaPosition, 3, GL_FLOAT, GL_FALSE, 0, 0);
|
||
|
||
unbindGL();
|
||
}
|
||
void RenderableFluxNodes::updateVertexColorBuffer() {
|
||
glBindVertexArray(_vertexArrayObject);
|
||
glBindBuffer(GL_ARRAY_BUFFER, _vertexColorBuffer);
|
||
|
||
const std::vector<float>& vertColor = _vertexColor;
|
||
|
||
glBufferData(
|
||
GL_ARRAY_BUFFER,
|
||
vertColor.size() * sizeof(float),
|
||
vertColor.data(),
|
||
GL_STATIC_DRAW
|
||
);
|
||
|
||
glEnableVertexAttribArray(VaColor);
|
||
glVertexAttribPointer(VaColor, 1, GL_FLOAT, GL_FALSE, 0, 0);
|
||
|
||
unbindGL();
|
||
}
|
||
void RenderableFluxNodes::updateVertexFilteringBuffer() {
|
||
glBindVertexArray(_vertexArrayObject);
|
||
glBindBuffer(GL_ARRAY_BUFFER, _vertexFilteringBuffer);
|
||
|
||
const std::vector<float>& vertexRadius = _vertexRadius;
|
||
|
||
glBufferData(
|
||
GL_ARRAY_BUFFER,
|
||
vertexRadius.size() * sizeof(float),
|
||
vertexRadius.data(),
|
||
GL_STATIC_DRAW
|
||
);
|
||
|
||
glEnableVertexAttribArray(VaFiltering);
|
||
glVertexAttribPointer(VaFiltering, 1, GL_FLOAT, GL_FALSE, 0, 0);
|
||
|
||
unbindGL();
|
||
}
|
||
} // namespace openspace
|