Refactor: restructure & clean up

This commit is contained in:
Oskar Carlbaum
2017-10-05 01:35:14 +02:00
parent d9268593ce
commit b1d1a7cf02
3 changed files with 145 additions and 118 deletions

View File

@@ -34,6 +34,10 @@
namespace {
std::string _loggerCat = "RenderableFieldlinesSequence";
const GLuint _VA_POSITION = 0; // MUST CORRESPOND TO THE SHADER PROGRAM
const GLuint _VA_COLOR = 1; // MUST CORRESPOND TO THE SHADER PROGRAM
const GLuint _VA_MASKING = 2; // MUST CORRESPOND TO THE SHADER PROGRAM
} // namespace
namespace openspace {
@@ -58,13 +62,13 @@ void RenderableFieldlinesSequence::deinitialize() {
}
// Stall main thread until thread that's loading states is done!
while (/*!_newStateIsReady &&*/ _isLoadingStateFromDisk) {
while (_isLoadingStateFromDisk) {
LWARNING("TRYING TO DESTROY CLASS WHEN A THREAD USING IT IS STILL ACTIVE");
}
}
bool RenderableFieldlinesSequence::isReady() const {
return _sourceFileType != INVALID;
return _isReady;
}
void RenderableFieldlinesSequence::render(const RenderData& data, RendererTasks&) {
@@ -197,7 +201,7 @@ void RenderableFieldlinesSequence::update(const UpdateData& data) {
if (_needsUpdate || _newStateIsReady) {
if (_loadingStatesDynamically) {
_states[0] = std::move(_newState);
_states[0] = std::move(*_newState);
}
updateVertexPositionBuffer();
@@ -245,14 +249,12 @@ void RenderableFieldlinesSequence::updateActiveTriggerTimeIndex(const double CUR
}
}
// Reading state from disk. Thread safe!
// Reading state from disk. Must be thread safe!
void RenderableFieldlinesSequence::readNewState(const std::string& FILEPATH) {
FieldlinesState newState;
bool isSuccessful = newState.loadStateFromOsfls(FILEPATH);
_newState = std::move(newState);
_newStateIsReady = true;
_newState = std::make_unique<FieldlinesState>();
if (_newState->loadStateFromOsfls(FILEPATH)) {
_newStateIsReady = true;
}
_isLoadingStateFromDisk = false;
}

View File

@@ -39,14 +39,15 @@
#include <atomic>
namespace openspace {
namespace {
enum class SourceFileType;
}
class ghoul::Dictionary;
namespace openspace {
class RenderableFieldlinesSequence : public Renderable {
public:
RenderableFieldlinesSequence(const ghoul::Dictionary& dictionary);
// ~RenderableFieldlinesSequence();
void initialize() override;
void deinitialize() override;
@@ -56,59 +57,51 @@ public:
void render(const RenderData& data, RendererTasks& rendererTask) override;
void update(const UpdateData& data) override;
private:
enum ColorMethod : int {
// ------------------------------------- ENUMS -------------------------------------//
enum ColorMethod : int { // Used to determine if lines should be colored UNIFORMLY or by an extraQuantity
UNIFORM = 0,
BY_QUANTITY
};
enum SourceFileType : int {
CDF = 0,
JSON,
OSFLS,
INVALID
};
// ------------------------------------ STRINGS ------------------------------------//
std::string _name; // Name of the Node!
std::string _name;
// ------------------------------------- FLAGS -------------------------------------//
std::atomic<bool> _isLoadingStateFromDisk { false}; // Used for 'runtime-states'. True when loading a new state from disk on another thread.
bool _isReady = false; // If initialization proved successful
bool _loadingStatesDynamically = false; // False => states are stored in RAM (using 'in-RAM-states'), True => states are loaded from disk during runtime (using 'runtime-states')
bool _mustLoadNewStateFromDisk = false; // Used for 'runtime-states': True if new 'runtime-state' must be loaded from disk. False => the previous frame's state should still be shown
bool _needsUpdate = false; // Used for 'in-RAM-states' : True if new 'in-RAM-state' must be loaded. False => the previous frame's state should still be shown
std::atomic<bool> _newStateIsReady { false}; // Used for 'runtime-states'. True when finished loading a new state from disk on another thread.
bool _shouldUpdateColorBuffer = false; // True when new state is loaded or user change which quantity to color the lines by
bool _shouldUpdateMaskingBuffer = false; // True when new state is loaded or user change which quantity used for masking out line segments
int _activeStateIndex = -1;
int _activeTriggerTimeIndex = -1;
bool _loadingStatesDynamically = false; // False => loading osfls files into RAM in initializing step
bool _mustLoadNewStateFromDisk = false;
bool _needsUpdate = false; // If still in same state as previous frame == false
bool _shouldUpdateColorBuffer = false;
bool _shouldUpdateMaskingBuffer = false;
FieldlinesState _newState;
size_t _nStates = 0;
float _scalingFactor = 1.f;
double _sequenceEndTime;
SourceFileType _sourceFileType;
// --------------------------------- NUMERICALS ----------------------------------- //
int _activeStateIndex = -1; // Active index of _states. If(==-1)=>no state available for current time. Always the same as _activeTriggerTimeIndex if(_loadingStatesDynamically==true), else always = 0
int _activeTriggerTimeIndex = -1; // Active index of _startTimes
size_t _nStates = 0; // Number of states in the sequence
float _scalingFactor = 1.f; // In setup it is used to scale JSON coordinates. During runtime it is used to scale domain limits.
double _sequenceEndTime; // Estimated end of sequence.
GLuint _vertexArrayObject = 0; // OpenGL Vertex Array Object
GLuint _vertexColorBuffer = 0; // OpenGL Vertex Buffer Object containing the extraQuantity values used for coloring the lines
GLuint _vertexMaskingBuffer = 0; // OpenGL Vertex Buffer Object containing the extraQuantity values used for masking out segments of the lines
GLuint _vertexPositionBuffer = 0; // OpenGL Vertex Buffer Object containing the vertex positions
std::atomic<bool> _isLoadingStateFromDisk{false};
std::atomic<bool> _newStateIsReady{false};
std::unique_ptr<ghoul::Dictionary> _dictionary;
std::shared_ptr<TransferFunction> _transferFunction; // Transfer funtion (tf)
// ----------------------------------- POINTERS ------------------------------------//
std::unique_ptr<ghoul::Dictionary> _dictionary; // The Lua-Modfile-Dictionary used during initialization
std::unique_ptr<FieldlinesState> _newState; // Used for 'runtime-states' when switching out current state to a new state
std::unique_ptr<ghoul::opengl::ProgramObject> _shaderProgram;
std::shared_ptr<TransferFunction> _transferFunction; // Transfer function used to color lines when _pColorMethod is set to BY_QUANTITY
std::vector<std::string> _colorTablePaths {"${OPENSPACE_DATA}/colortables/kroyw.txt"}; // Default in case user doesn't specify otherwise
std::vector<std::string> _sourceFiles; // Stored in RAM if files are loaded at runtime, else emptied after initialization
std::vector<double> _startTimes;
std::vector<FieldlinesState> _states;
std::vector<glm::vec2> _colorTableRanges; // Values represents min & max values represented in the color table
std::vector<glm::vec2> _maskingRanges; // Values represents min & max values for valid masking range
// ------------------------------------ VECTORS ----------------------------------- //
std::vector<std::string> _colorTablePaths; // Paths to color tables. One for each 'extraQuantity'
std::vector<glm::vec2> _colorTableRanges; // Values represents min & max values represented in the color table
std::vector<glm::vec2> _maskingRanges; // Values represents min & max limits for valid masking range
std::vector<std::string> _sourceFiles; // Stores the provided source file paths if using 'runtime-states', else emptied after initialization
std::vector<double> _startTimes; // Contains the _triggerTimes for all FieldlineStates in the sequence
std::vector<FieldlinesState> _states; // Stores the FieldlineStates
GLuint _vertexArrayObject = 0;
GLuint _vertexPositionBuffer = 0;
GLuint _vertexColorBuffer = 0;
GLuint _vertexMaskingBuffer = 0;
// THESE MUST CORRESPOND TO THE SHADER PROGRAM
// TODO: THIS CAN BE DETERMINED BY ASKING THE SHADER PROGRAM TOO
const GLuint _VA_POSITION = 0;
const GLuint _VA_COLOR = 1;
const GLuint _VA_MASKING = 2;
// ----------------------------- Properties -----------------------------
// ---------------------------------- Properties ---------------------------------- //
properties::PropertyOwner _pColorGroup; // Group to hold the color properties
properties::OptionProperty _pColorMethod; // Uniform/transfer function/topology?
properties::OptionProperty _pColorQuantity; // Index of the extra quantity to color lines by
@@ -142,22 +135,24 @@ private:
properties::TriggerProperty _pFocusOnOriginBtn; // Button which sets camera focus to parent node of the renderable
properties::TriggerProperty _pJumpToStartBtn; // Button which executes a time jump to start of sequence
// --------------------- FUNCTIONS USED DURING INITIALIZATION --------------------- //
void computeSequenceEndTime();
bool extractInfoFromDictionary(const ghoul::Dictionary& dictionary);
void definePropertyCallbackFunctions();
bool extractJsonInfoFromDictionary(fls::Model& model);
bool extractMandatoryInfoFromDictionary(SourceFileType& sourceFileType);
void extractOptionalInfoFromDictionary(std::string& outputFolderPath);
void extractOsflsInfoFromDictionary();
void extractTriggerTimesFromFileNames();
void readNewState(const std::string& FILEPATH);
void setModelDependentConstants();
void setupProperties();
// ------------------------- FUNCTIONS USED DURING RUNTIME ------------------------ //
inline bool isWithinSequenceInterval(const double CURRENT_TIME) const;
void readNewState(const std::string& FILEPATH);
void updateActiveTriggerTimeIndex(const double CURRENT_TIME);
void updateVertexPositionBuffer();
void updateVertexColorBuffer();
void updateVertexMaskingBuffer();
void definePropertyCallbackFunctions();
void setupProperties();
void setModelDependentConstants();
};
} // namespace openspace

View File

@@ -128,6 +128,13 @@ namespace {
"timeJumpToStart", "Jump to Start Of Sequence", "Performs a time jump to the start of the sequence."
};
enum class SourceFileType : int {
CDF = 0,
JSON,
OSFLS,
INVALID
};
float stringToFloat(const std::string INPUT, const float BACKUP_VALUE = 0.f) {
float tmp;
try {
@@ -143,8 +150,8 @@ namespace {
namespace openspace {
RenderableFieldlinesSequence::RenderableFieldlinesSequence(const ghoul::Dictionary& dictionary)
: Renderable(dictionary),
RenderableFieldlinesSequence::RenderableFieldlinesSequence(const ghoul::Dictionary& DICTIONARY)
: Renderable(DICTIONARY),
_pColorGroup({ "Color" }),
_pColorMethod(ColorMethodInfo, properties::OptionProperty::DisplayType::Radio),
_pColorQuantity(ColorQuantityInfo, properties::OptionProperty::DisplayType::Dropdown),
@@ -176,29 +183,37 @@ RenderableFieldlinesSequence::RenderableFieldlinesSequence(const ghoul::Dictiona
_pFocusOnOriginBtn(OriginButtonInfo),
_pJumpToStartBtn(TimeJumpButtonInfo) {
_dictionary = std::make_unique<ghoul::Dictionary>(dictionary);
// Set the default color table, just in case user defined paths are corrupt!
_transferFunction = std::make_shared<TransferFunction>(absPath(_colorTablePaths[0]));
_dictionary = std::make_unique<ghoul::Dictionary>(DICTIONARY);
}
void RenderableFieldlinesSequence::initialize() {
LINFO("RenderableFieldlinesSequence::initialize()");
if (!extractInfoFromDictionary(*_dictionary)) {
_sourceFileType = SourceFileType::INVALID;
// EXTRACT MANDATORY INFORMATION FROM DICTIONARY
SourceFileType sourceFileType = SourceFileType::INVALID;
if (!extractMandatoryInfoFromDictionary(sourceFileType)) {
return;
}
// dictionary is no longer necessary as everything is extracted
_dictionary.reset();
// Set the default color table, just in case the (optional) user defined paths are corrupt!
_colorTablePaths.push_back("${OPENSPACE_DATA}/colortables/kroyw.txt");
_transferFunction = std::make_shared<TransferFunction>(absPath(_colorTablePaths[0]));
switch (_sourceFileType) {
case CDF:
// EXTRACT OPTIONAL INFORMATION FROM DICTIONARY
std::string outputFolderPath;
extractOptionalInfoFromDictionary(outputFolderPath);
const bool SHOULD_SAVE_STATES = !outputFolderPath.empty();
// EXTRACT SOURCE FILE TYPE SPECIFIC INFOMRATION FROM DICTIONARY & GET STATES FROM SOURCE
switch (sourceFileType) {
case SourceFileType::CDF:
LERROR("CDF NOT YET IMPLEMENTED!"); return;
break;
case JSON:
case SourceFileType::JSON:
LERROR("JSON NOT YET IMPLEMENTED!"); return;
break;
case OSFLS:
case SourceFileType::OSFLS:
extractOsflsInfoFromDictionary();
if (_loadingStatesDynamically) {
extractTriggerTimesFromFileNames();
FieldlinesState newState;
@@ -209,7 +224,7 @@ void RenderableFieldlinesSequence::initialize() {
_activeStateIndex = 0;
} else {
LERROR("The provided .osfls files seem to be corrupt!");
_sourceFileType = SourceFileType::INVALID;
sourceFileType = SourceFileType::INVALID;
}
} else {
// Load states into RAM!
@@ -228,6 +243,9 @@ void RenderableFieldlinesSequence::initialize() {
return;
}
// dictionary is no longer needed as everything is extracted
_dictionary.reset();
// At this point there's at least one state loaded into memory!
// No need to store source paths in memory if they are already in RAM!
if (!_loadingStatesDynamically) {
@@ -248,7 +266,7 @@ void RenderableFieldlinesSequence::initialize() {
if (!_shaderProgram) {
LERROR("Shader program failed initialization!");
_sourceFileType = SourceFileType::INVALID;
sourceFileType = SourceFileType::INVALID;
}
//------------------ Initialize OpenGL VBOs and VAOs-------------------------------//
@@ -259,42 +277,44 @@ void RenderableFieldlinesSequence::initialize() {
// Needed for additive blending
setRenderBin(Renderable::RenderBin::Overlay);
_isReady = true;
}
bool RenderableFieldlinesSequence::extractInfoFromDictionary(
const ghoul::Dictionary& dictionary) {
/*
* Returns false if it fails to extract mandatory information!
*/
bool RenderableFieldlinesSequence::extractMandatoryInfoFromDictionary(
SourceFileType& sourceFileType) {
std::string name;
dictionary.getValue(SceneGraphNode::KeyName, name);
_name = name;
name += ": ";
_dictionary->getValue(SceneGraphNode::KeyName, _name);
// ------------------- EXTRACT MANDATORY VALUES FROM DICTIONARY ------------------- //
std::string inputFileTypeString;
if (!dictionary.getValue(KEY_INPUT_FILE_TYPE, inputFileTypeString)) {
LERROR(name << "The field " << std::string(KEY_INPUT_FILE_TYPE) << " is missing!");
if (!_dictionary->getValue(KEY_INPUT_FILE_TYPE, inputFileTypeString)) {
LERROR(_name << ": The field " << std::string(KEY_INPUT_FILE_TYPE) << " is missing!");
return false;
} else {
std::transform(inputFileTypeString.begin(), inputFileTypeString.end(),
inputFileTypeString.begin(), ::tolower);
// Verify that the input type is correct
if (inputFileTypeString == VALUE_INPUT_FILE_TYPE_CDF) {
_sourceFileType = CDF;
sourceFileType = SourceFileType::CDF;
} else if (inputFileTypeString == VALUE_INPUT_FILE_TYPE_JSON) {
_sourceFileType = JSON;
sourceFileType = SourceFileType::JSON;
} else if (inputFileTypeString == VALUE_INPUT_FILE_TYPE_OSFLS) {
_sourceFileType = OSFLS;
sourceFileType = SourceFileType::OSFLS;
} else {
LERROR(name << inputFileTypeString << " is not a recognised "
LERROR(_name << ": " << inputFileTypeString << " is not a recognised "
<< KEY_INPUT_FILE_TYPE);
_sourceFileType = INVALID;
sourceFileType = SourceFileType::INVALID;
return false;
}
}
std::string sourceFolderPath;
if (!dictionary.getValue(KEY_SOURCE_FOLDER, sourceFolderPath)) {
LERROR(name << "The field " << std::string(KEY_SOURCE_FOLDER) << " is missing!");
if (!_dictionary->getValue(KEY_SOURCE_FOLDER, sourceFolderPath)) {
LERROR(_name << ": The field " << std::string(KEY_SOURCE_FOLDER) << " is missing!");
return false;
}
@@ -315,19 +335,25 @@ bool RenderableFieldlinesSequence::extractInfoFromDictionary(
}), _sourceFiles.end());
// Ensure that there are available and valid source files left
if (_sourceFiles.empty()) {
LERROR(name << sourceFolderPath << " contains no ." << inputFileTypeString
LERROR(_name << ": " << sourceFolderPath << " contains no ." << inputFileTypeString
<< " files!");
return false;
}
} else {
LERROR(name << "FieldlinesSequence" << sourceFolderPath
LERROR(_name << ": FieldlinesSequence" << sourceFolderPath
<< " is not a valid directory!");
return false;
}
return true;
}
void RenderableFieldlinesSequence::extractOptionalInfoFromDictionary(
std::string& outputFolderPath) {
// ------------------- EXTRACT OPTIONAL VALUES FROM DICTIONARY ------------------- //
ghoul::Dictionary colorTablesPathsDictionary;
if (dictionary.getValue(KEY_COLOR_TABLE_PATHS, colorTablesPathsDictionary)) {
if (_dictionary->getValue(KEY_COLOR_TABLE_PATHS, colorTablesPathsDictionary)) {
const size_t N_PROVIDED_PATHS = colorTablesPathsDictionary.size();
if (N_PROVIDED_PATHS > 0) {
// Clear the default! It is already specified in the transferFunction
@@ -340,7 +366,7 @@ bool RenderableFieldlinesSequence::extractInfoFromDictionary(
}
ghoul::Dictionary colorTablesRangesDictionary;
if (dictionary.getValue(KEY_COLOR_TABLE_RANGES, colorTablesRangesDictionary)) {
if (_dictionary->getValue(KEY_COLOR_TABLE_RANGES, colorTablesRangesDictionary)) {
const size_t N_PROVIDED_RANGES = colorTablesRangesDictionary.size();
for (size_t i = 1; i <= N_PROVIDED_RANGES; ++i) {
_colorTableRanges.push_back(
@@ -350,30 +376,35 @@ bool RenderableFieldlinesSequence::extractInfoFromDictionary(
_colorTableRanges.push_back(glm::vec2(0, 1));
}
// Extract info specific to each inputType
switch (_sourceFileType) {
case CDF:
LERROR(name << "CDF NOT YET IMPLEMENTED!");
break;
case JSON:
LERROR(name << "JSON NOT YET IMPLEMENTED!");
break;
case OSFLS: {
bool shouldLoadInRealtime = false;
if (dictionary.getValue(KEY_OSLFS_LOAD_AT_RUNTIME, shouldLoadInRealtime)) {
_loadingStatesDynamically = shouldLoadInRealtime;
} else {
LWARNING(name << KEY_OSLFS_LOAD_AT_RUNTIME <<
" isn't specified! States from OSFLS files will be stored in RAM!");
}
} break;
default:
break;
ghoul::Dictionary maskingRangesDictionary;
if (_dictionary->getValue(KEY_MASKING_RANGES, maskingRangesDictionary)) {
const size_t N_PROVIDED_RANGES = maskingRangesDictionary.size();
for (size_t i = 1; i <= N_PROVIDED_RANGES; ++i) {
_maskingRanges.push_back(
maskingRangesDictionary.value<glm::vec2>(std::to_string(i)));
}
} else {
_maskingRanges.push_back(glm::vec2(-100000, 100000)); // Just some default values!
}
}
/*
* Returns false if it fails to extract mandatory information!
*/
bool RenderableFieldlinesSequence::extractJsonInfoFromDictionary(fls::Model& model) {
return true;
}
void RenderableFieldlinesSequence::extractOsflsInfoFromDictionary() {
bool shouldLoadInRealtime = false;
if (_dictionary->getValue(KEY_OSLFS_LOAD_AT_RUNTIME, shouldLoadInRealtime)) {
_loadingStatesDynamically = shouldLoadInRealtime;
} else {
LWARNING(_name << ": " << KEY_OSLFS_LOAD_AT_RUNTIME <<
" isn't specified! States will be stored in RAM!");
}
}
void RenderableFieldlinesSequence::setupProperties() {
// -------------- Add non-grouped properties (enablers and buttons) -------------- //
addProperty(_pColorABlendEnabled);
@@ -441,7 +472,6 @@ void RenderableFieldlinesSequence::setupProperties() {
_pMaskingQuantity = 0;
_pMaskingMin = std::to_string(_maskingRanges[_pMaskingQuantity].x);
_pMaskingMax = std::to_string(_maskingRanges[_pMaskingQuantity].y);
}
void RenderableFieldlinesSequence::definePropertyCallbackFunctions() {