diff --git a/data/scene/default.scene b/data/scene/default.scene index 596aa846a6..3baee3cb63 100644 --- a/data/scene/default.scene +++ b/data/scene/default.scene @@ -30,7 +30,7 @@ function postInitialization() openspace.printInfo("Done setting default values") - openspace.iswa.addCygnet(-4,"Data","Ion"); + --openspace.iswa.addCygnet(-4,"Data","Ion"); --openspace.iswa.addCygnet(-1,"Data"); --openspace.iswa.addCygnet(-2,"Data"); diff --git a/modules/iswa/CMakeLists.txt b/modules/iswa/CMakeLists.txt index 49ae882ecf..c8041bd735 100644 --- a/modules/iswa/CMakeLists.txt +++ b/modules/iswa/CMakeLists.txt @@ -42,6 +42,7 @@ set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/rendering/iswadatagroup.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/iswakameleongroup.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/texturecygnet.h + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/datacygnet.h ) source_group("Header Files" FILES ${HEADER_FILES}) @@ -63,6 +64,7 @@ set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/rendering/iswadatagroup.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/iswakameleongroup.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/texturecygnet.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/datacygnet.cpp ) source_group("Source Files" FILES ${SOURCE_FILES}) diff --git a/modules/iswa/rendering/cygnetplane.cpp b/modules/iswa/rendering/cygnetplane.cpp index add4407c54..2f4d3eb934 100644 --- a/modules/iswa/rendering/cygnetplane.cpp +++ b/modules/iswa/rendering/cygnetplane.cpp @@ -1,20 +1,26 @@ -// * 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. * -// ****************************************************************************************/ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * 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 #include diff --git a/modules/iswa/rendering/cygnetsphere.cpp b/modules/iswa/rendering/cygnetsphere.cpp index 7a2df6d29c..05b811862f 100644 --- a/modules/iswa/rendering/cygnetsphere.cpp +++ b/modules/iswa/rendering/cygnetsphere.cpp @@ -1,20 +1,26 @@ -// * 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. * -// ****************************************************************************************/ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * 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 @@ -46,12 +52,12 @@ bool CygnetSphere::createGeometry(){ int segments = 100; _sphere = std::make_shared(radius, segments); _sphere->initialize(); - return true; + return true; } bool CygnetSphere::destroyGeometry(){ _sphere = nullptr; - return true; + return true; } void CygnetSphere::renderGeometry() const { diff --git a/modules/iswa/rendering/datacygnet.cpp b/modules/iswa/rendering/datacygnet.cpp index c943966da1..11c0e8efb6 100644 --- a/modules/iswa/rendering/datacygnet.cpp +++ b/modules/iswa/rendering/datacygnet.cpp @@ -24,6 +24,12 @@ #include +#include +#include +#include +#include +#include + namespace { const std::string _loggerCat = "DataCygnet"; } @@ -32,8 +38,198 @@ namespace openspace{ DataCygnet::DataCygnet(const ghoul::Dictionary& dictionary) :IswaCygnet(dictionary) -{} + ,_dataProcessor(nullptr) + ,_dataOptions("dataOptions", "Data Options") +{ + addProperty(_dataOptions); + registerProperties(); +} DataCygnet::~DataCygnet(){} +bool DataCygnet::loadTexture(){ + // if The future is done then get the new dataFile + if(_futureObject.valid() && DownloadManager::futureReady(_futureObject)){ + DownloadManager::MemoryFile dataFile = _futureObject.get(); + + if(dataFile.corrupted) + return false; + + _dataBuffer = ""; + _dataBuffer.append(dataFile.buffer, dataFile.size); + delete[] dataFile.buffer; + } + + // if the buffer in the datafile is empty, do not proceed + if(_dataBuffer.empty()) + return false; + + if(!_dataOptions.options().size()){ // load options for value selection + fillOptions(); + _dataProcessor->addDataValues(_dataBuffer, _dataOptions); + + // if this datacygnet has added new values then reload texture + // for the whole group, including this datacygnet, and return after. + if(_group){ + _group->updateGroup(); + return true; + } + } + + std::vector data = _dataProcessor->processData(_dataBuffer, _dataOptions); + + if(data.empty()) + return false; + + bool texturesReady = false; + std::vector selectedOptions = _dataOptions.value(); + + for(int option: selectedOptions){ + float* values = data[option]; + if(!values) continue; + + if(!_textures[option]){ + std::unique_ptr texture = std::make_unique( + values, + _dataProcessor->dimensions(), + ghoul::opengl::Texture::Format::Red, + GL_RED, + GL_FLOAT, + ghoul::opengl::Texture::FilterMode::Linear, + ghoul::opengl::Texture::WrappingMode::ClampToEdge + ); + + if(texture){ + texture->uploadTexture(); + texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear); + _textures[option] = std::move(texture); + } + }else{ + _textures[option]->setPixelData(values); + _textures[option]->uploadTexture(); + } + texturesReady = true; + } + return texturesReady; +} + +bool DataCygnet::updateTexture(){ + if(_futureObject.valid()) + return false; + + std::future future = IswaManager::ref().fetchDataCygnet(_data->id); + + if(future.valid()){ + _futureObject = std::move(future); + return true; + } + + return false; +} + +bool DataCygnet::readyToRender() const{ + return (!_textures.empty()); +} + +/** + * Set both transfer function textures and data textures in same function so that they bind to + * the right texture units. If separate in to two functions a list of ghoul::TextureUnit + * needs to be passed as an argument to both. + */ +void DataCygnet::setTextureUniforms(){ + std::vector selectedOptions = _dataOptions.value(); + int activeTextures = std::min((int)selectedOptions.size(), MAX_TEXTURES); + int activeTransferfunctions = std::min((int)_transferFunctions.size(), MAX_TEXTURES); + + // Set Textures + ghoul::opengl::TextureUnit txUnits[MAX_TEXTURES]; + int j = 0; + for(int option : selectedOptions){ + if(_textures[option]){ + txUnits[j].activate(); + _textures[option]->bind(); + _shader->setUniform( + "textures[" + std::to_string(j) + "]", + txUnits[j] + ); + + j++; + if(j >= MAX_TEXTURES) break; + } + } + + //Set Transfer Functions + if(activeTextures > 0){ + if(selectedOptions.back()>=activeTransferfunctions) + activeTransferfunctions = 1; + } + + ghoul::opengl::TextureUnit tfUnits[MAX_TEXTURES]; + j = 0; + + if((activeTransferfunctions == 1)){ + tfUnits[0].activate(); + _transferFunctions[0]->bind(); + _shader->setUniform( + "transferFunctions[0]", + tfUnits[0] + ); + }else{ + for(int option : selectedOptions){ + + if(_transferFunctions[option]){ + tfUnits[j].activate(); + _transferFunctions[option]->bind(); + _shader->setUniform( + "transferFunctions[" + std::to_string(j) + "]", + tfUnits[j] + ); + + j++; + if(j >= MAX_TEXTURES) break; + } + } + } + + _shader->setUniform("numTransferFunctions", activeTransferfunctions); + _shader->setUniform("numTextures", activeTextures); +} + + +void DataCygnet::readTransferFunctions(std::string tfPath){ + std::string line; + std::ifstream tfFile(absPath(tfPath)); + + std::vector> tfs; + + if(tfFile.is_open()){ + while(getline(tfFile, line)){ + std::shared_ptr tf = std::make_shared(absPath(line)); + if(tf){ + tfs.push_back(tf); + } + } + + tfFile.close(); + } + + if(!tfs.empty()){ + _transferFunctions.clear(); + _transferFunctions = tfs; + } +} + +void DataCygnet::fillOptions(){ + std::vector options = _dataProcessor->readMetadata(_dataBuffer); + + for(int i=0; i(1,0)); + if(_group) + std::dynamic_pointer_cast(_group)->registerOptions(_dataOptions.options()); +} + + } //namespace openspace \ No newline at end of file diff --git a/modules/iswa/rendering/datacygnet.h b/modules/iswa/rendering/datacygnet.h index beeab0ecf3..0766025817 100644 --- a/modules/iswa/rendering/datacygnet.h +++ b/modules/iswa/rendering/datacygnet.h @@ -26,14 +26,58 @@ #define __DATACYGNET_H__ #include +#include +#include + +namespace { + const int MAX_TEXTURES = 6; +} namespace openspace{ +/** + * This class abstracts away the the loading of data and creation of + * textures for all data cygnets. It specifies the interface that needs to + * be implemented for all concrete subclasses + */ class DataCygnet : public IswaCygnet { public: DataCygnet(const ghoul::Dictionary& dictionary); ~DataCygnet(); protected: + + bool loadTexture() override; + bool updateTexture() override; + bool readyToRender() const override; + + /** + * loads the transferfunctions specified in tfPath into + * _transferFunctions list. + * + * @param tfPath Path to transfer function file + */ + void readTransferFunctions(std::string tfPath); + + /** + * This function binds and sets all textures that should go to the + * shader program, this includes both the data and transferfunctions. + */ + void setTextureUniforms(); + + // Subclass interface. Must be protected, called from base class + virtual bool createGeometry() = 0; + virtual bool destroyGeometry() = 0; + virtual void renderGeometry() const = 0; + // This function can call parent setTextureUniforms() + virtual void setUniforms() = 0; + + properties::SelectionProperty _dataOptions; + std::shared_ptr _dataProcessor; + +private: + void fillOptions(); + + std::string _dataBuffer; }; } //namespace openspace diff --git a/modules/iswa/rendering/dataplane.cpp b/modules/iswa/rendering/dataplane.cpp index b5be763e09..83abdcd7a4 100644 --- a/modules/iswa/rendering/dataplane.cpp +++ b/modules/iswa/rendering/dataplane.cpp @@ -22,43 +22,23 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ #include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include namespace { const std::string _loggerCat = "DataPlane"; - const int MAX_TEXTURES = 6; } namespace openspace { DataPlane::DataPlane(const ghoul::Dictionary& dictionary) - :CygnetPlane(dictionary) + :DataCygnet(dictionary) ,_useLog("useLog","Use Logarithm", false) - ,_useHistogram("useHistogram", "Use Histogram", true) - ,_autoFilter("autoFilter", "Auto Filter", true) + ,_useHistogram("useHistogram", "Auto Contrast", false) + ,_autoFilter("autoFilter", "Auto Filter", false) ,_normValues("normValues", "Normalize Values", glm::vec2(1.0,1.0), glm::vec2(0), glm::vec2(5.0)) ,_backgroundValues("backgroundValues", "Background Values", glm::vec2(0.0), glm::vec2(0), glm::vec2(1.0)) ,_transferFunctionsFile("transferfunctions", "Transfer Functions", "${SCENE}/iswa/tfs/hot.tf") - ,_dataOptions("dataOptions", "Data Options") - ,_dataProcessor(nullptr) { - std::string name; - dictionary.getValue("Name", name); - setName(name); - - registerProperties(); addProperty(_useLog); addProperty(_useHistogram); @@ -66,7 +46,6 @@ DataPlane::DataPlane(const ghoul::Dictionary& dictionary) addProperty(_normValues); addProperty(_backgroundValues); addProperty(_transferFunctionsFile); - addProperty(_dataOptions); _programName = "DataPlaneProgram"; _vsPath = "${MODULE_ISWA}/shaders/dataplane_vs.glsl"; @@ -82,60 +61,7 @@ bool DataPlane::initialize(){ if(_group){ _dataProcessor = _group->dataProcessor(); - auto groupEvent = _group->groupEvent(); - - groupEvent->subscribe(name(), "useLogChanged", [&](const ghoul::Dictionary& dict){ - LDEBUG(name() + " Event useLogChanged"); - _useLog.setValue(dict.value("useLog")); - }); - - groupEvent->subscribe(name(), "normValuesChanged", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event normValuesChanged"); - std::shared_ptr values; - bool success = dict.getValue("normValues", values); - if(success){ - _normValues.setValue(*values); - } - }); - - groupEvent->subscribe(name(), "useHistogramChanged", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event useHistogramChanged"); - _useHistogram.setValue(dict.value("useHistogram")); - }); - - groupEvent->subscribe(name(), "dataOptionsChanged", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event dataOptionsChanged"); - std::shared_ptr > values; - bool success = dict.getValue("dataOptions", values); - if(success){ - _dataOptions.setValue(*values); - } - }); - - groupEvent->subscribe(name(), "transferFunctionsChanged", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event transferFunctionsChanged"); - _transferFunctionsFile.setValue(dict.value("transferFunctions")); - }); - - groupEvent->subscribe(name(), "backgroundValuesChanged", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event backgroundValuesChanged"); - std::shared_ptr values; - bool success = dict.getValue("backgroundValues", values); - if(success){ - _backgroundValues.setValue(*values); - } - }); - - groupEvent->subscribe(name(), "autoFilterChanged", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event autoFilterChanged"); - _autoFilter.setValue(dict.value("autoFilter")); - }); - - groupEvent->subscribe(name(), "updateGroup", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event updateGroup"); - loadTexture(); - }); - + subscribeToGroup(); }else{ OsEng.gui()._iswa.registerProperty(&_useLog); OsEng.gui()._iswa.registerProperty(&_useHistogram); @@ -145,9 +71,21 @@ bool DataPlane::initialize(){ OsEng.gui()._iswa.registerProperty(&_transferFunctionsFile); OsEng.gui()._iswa.registerProperty(&_dataOptions); _dataProcessor = std::make_shared(); + + //If autofiler is on, background values property should be hidden + _autoFilter.onChange([this](){ + // If autofiler is selected, use _dataProcessor to set backgroundValues + // and unregister backgroundvalues property. + if(_autoFilter.value()){ + _backgroundValues.setValue(_dataProcessor->filterValues()); + // else if autofilter is turned off, register backgroundValues + } else { + OsEng.gui()._iswa.registerProperty(&_backgroundValues, &_autoFilter); + } + }); } - setTransferFunctions(_transferFunctionsFile.value()); + readTransferFunctions(_transferFunctionsFile.value()); _normValues.onChange([this](){ _dataProcessor->normValues(_normValues.value()); @@ -162,6 +100,8 @@ bool DataPlane::initialize(){ _useHistogram.onChange([this](){ _dataProcessor->useHistogram(_useHistogram.value()); loadTexture(); + if(_autoFilter.value()) + _backgroundValues.setValue(_dataProcessor->filterValues()); }); _dataOptions.onChange([this](){ @@ -171,194 +111,124 @@ bool DataPlane::initialize(){ }); _transferFunctionsFile.onChange([this](){ - setTransferFunctions(_transferFunctionsFile.value()); + readTransferFunctions(_transferFunctionsFile.value()); }); + _autoFilter.setValue(true); + return true; } -bool DataPlane::loadTexture() { - // if The future is done then get the new dataFile - if(_futureObject.valid() && DownloadManager::futureReady(_futureObject)){ - DownloadManager::MemoryFile dataFile = _futureObject.get(); - - if(dataFile.corrupted) - return false; - - _dataBuffer = ""; - _dataBuffer.append(dataFile.buffer, dataFile.size); - delete[] dataFile.buffer; - } - - // if the buffer in the datafile is empty, do not proceed - if(_dataBuffer.empty()) - return false; - - if(!_dataOptions.options().size()){ // load options for value selection - fillOptions(); - _dataProcessor->addDataValues(_dataBuffer, _dataOptions); - - if(_group) - _group->updateGroup(); - } - - std::vector data = _dataProcessor->processData(_dataBuffer, _dataOptions); - - if(data.empty()) - return false; - - if(_autoFilter.value()) - _backgroundValues.setValue(_dataProcessor->filterValues()); +bool DataPlane::createGeometry() { + glGenVertexArrays(1, &_quad); // generate array + glGenBuffers(1, &_vertexPositionBuffer); // generate buffer - bool texturesReady = false; - std::vector selectedOptions = _dataOptions.value(); + // ============================ + // GEOMETRY (quad) + // ============================ + // GLfloat x,y, z; + float s = _data->spatialScale.x; + const GLfloat x = s*_data->scale.x/2.0; + const GLfloat y = s*_data->scale.y/2.0; + const GLfloat z = s*_data->scale.z/2.0; + const GLfloat w = _data->spatialScale.w; - for(int option: selectedOptions){ - float* values = data[option]; - if(!values) continue; + const GLfloat vertex_data[] = { // square of two triangles (sigh) + // x y z w s t + -x, -y, -z, w, 0, 1, + x, y, z, w, 1, 0, + -x, ((x>0)?y:-y), z, w, 0, 0, + -x, -y, -z, w, 0, 1, + x, ((x>0)?-y:y), -z, w, 1, 1, + x, y, z, w, 1, 0, + }; - if(!_textures[option]){ - std::unique_ptr texture = std::make_unique( - values, - _dataProcessor->dimensions(), - ghoul::opengl::Texture::Format::Red, - GL_RED, - GL_FLOAT, - ghoul::opengl::Texture::FilterMode::Linear, - ghoul::opengl::Texture::WrappingMode::ClampToEdge - ); - - if(texture){ - texture->uploadTexture(); - texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear); - _textures[option] = std::move(texture); - } - }else{ - _textures[option]->setPixelData(values); - _textures[option]->uploadTexture(); - } - texturesReady = true; - } - - return texturesReady; + glBindVertexArray(_quad); // bind array + glBindBuffer(GL_ARRAY_BUFFER, _vertexPositionBuffer); // bind buffer + glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, reinterpret_cast(0)); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, reinterpret_cast(sizeof(GLfloat) * 4)); + return true; } -bool DataPlane::updateTexture(){ - if(_futureObject.valid()) - return false; +bool DataPlane::destroyGeometry(){ + glDeleteVertexArrays(1, &_quad); + _quad = 0; - std::future future = IswaManager::ref().fetchDataCygnet(_data->id); + glDeleteBuffers(1, &_vertexPositionBuffer); + _vertexPositionBuffer = 0; - if(future.valid()){ - _futureObject = std::move(future); - return true; - } - - return false; + return true; } -bool DataPlane::readyToRender() const { - return (!_textures.empty()); +void DataPlane::renderGeometry() const { + glBindVertexArray(_quad); + glDrawArrays(GL_TRIANGLES, 0, 6); } -void DataPlane::setUniformAndTextures(){ - std::vector selectedOptions = _dataOptions.value(); - int activeTextures = std::min((int)selectedOptions.size(), MAX_TEXTURES); - int activeTransferfunctions = std::min((int)_transferFunctions.size(), MAX_TEXTURES); - - ghoul::opengl::TextureUnit txUnits[6]; - int j = 0; - for(int option : selectedOptions){ - if(_textures[option]){ - txUnits[j].activate(); - _textures[option]->bind(); - _shader->setUniform( - "textures[" + std::to_string(j) + "]", - txUnits[j] - ); - - j++; - if(j >= MAX_TEXTURES) break; - } - } - - if(activeTextures > 0){ - if(selectedOptions.back()>=activeTransferfunctions) - activeTransferfunctions = 1; - } - - ghoul::opengl::TextureUnit tfUnits[6]; - j = 0; - - if((activeTransferfunctions == 1)){ - tfUnits[0].activate(); - _transferFunctions[0]->bind(); - _shader->setUniform( - "transferFunctions[0]", - tfUnits[0] - ); - }else{ - for(int option : selectedOptions){ - // std::cout << option << std::endl; - // if(option >= activeTransferfunctions){ - // // LWARNING("No transfer function for this value."); - // break; - // } - - if(_transferFunctions[option]){ - tfUnits[j].activate(); - _transferFunctions[option]->bind(); - _shader->setUniform( - "transferFunctions[" + std::to_string(j) + "]", - tfUnits[j] - ); - - j++; - if(j >= MAX_TEXTURES) break; - } - } - } - - _shader->setUniform("numTextures", activeTextures); - _shader->setUniform("numTransferFunctions", activeTransferfunctions); +void DataPlane::setUniforms(){ + // set both data texture and transfer function texture + setTextureUniforms(); _shader->setUniform("backgroundValues", _backgroundValues.value()); _shader->setUniform("transparency", _alpha.value()); } -void DataPlane::setTransferFunctions(std::string tfPath){ - std::string line; - std::ifstream tfFile(absPath(tfPath)); +void DataPlane::subscribeToGroup(){ + auto groupEvent = _group->groupEvent(); + groupEvent->subscribe(name(), "useLogChanged", [&](const ghoul::Dictionary& dict){ + LDEBUG(name() + " Event useLogChanged"); + _useLog.setValue(dict.value("useLog")); + }); - std::vector> tfs; - - if(tfFile.is_open()){ - while(getline(tfFile, line)){ - std::shared_ptr tf = std::make_shared(absPath(line)); - if(tf){ - tfs.push_back(tf); - } + groupEvent->subscribe(name(), "normValuesChanged", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event normValuesChanged"); + std::shared_ptr values; + bool success = dict.getValue("normValues", values); + if(success){ + _normValues.setValue(*values); } + }); - tfFile.close(); - } + groupEvent->subscribe(name(), "useHistogramChanged", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event useHistogramChanged"); + _useHistogram.setValue(dict.value("useHistogram")); + }); - - if(!tfs.empty()){ - _transferFunctions.clear(); - _transferFunctions = tfs; - } -} + groupEvent->subscribe(name(), "dataOptionsChanged", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event dataOptionsChanged"); + std::shared_ptr > values; + bool success = dict.getValue("dataOptions", values); + if(success){ + _dataOptions.setValue(*values); + } + }); -void DataPlane::fillOptions(){ - std::vector options = _dataProcessor->readMetadata(_dataBuffer); - for(int i=0; i(1,0)); - if(_group) - std::dynamic_pointer_cast (_group)->registerOptions(_dataOptions.options()); + groupEvent->subscribe(name(), "transferFunctionsChanged", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event transferFunctionsChanged"); + _transferFunctionsFile.setValue(dict.value("transferFunctions")); + }); + + groupEvent->subscribe(name(), "backgroundValuesChanged", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event backgroundValuesChanged"); + std::shared_ptr values; + bool success = dict.getValue("backgroundValues", values); + if(success){ + _backgroundValues.setValue(*values); + } + }); + + groupEvent->subscribe(name(), "autoFilterChanged", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event autoFilterChanged"); + _autoFilter.setValue(dict.value("autoFilter")); + }); + + groupEvent->subscribe(name(), "updateGroup", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event updateGroup"); + loadTexture(); + }); } }// namespace openspace \ No newline at end of file diff --git a/modules/iswa/rendering/dataplane.h b/modules/iswa/rendering/dataplane.h index ac79c47464..e06e6433e4 100644 --- a/modules/iswa/rendering/dataplane.h +++ b/modules/iswa/rendering/dataplane.h @@ -25,49 +25,49 @@ #ifndef __DATAPLANE_H__ #define __DATAPLANE_H__ -#include -#include +#include #include #include -#include namespace openspace{ -class IswaBaseGroup; - -class DataPlane : public CygnetPlane { +/** + * DataPlane is a concrete IswaCygnet with data files as its input source. + * The class handles creation, destruction and rendering of a plane geometry. + * It also specifies what uniforms to use and what GUI properties it needs. + */ +class DataPlane : public DataCygnet { friend class IswaBaseGroup; - public: +public: DataPlane(const ghoul::Dictionary& dictionary); ~DataPlane(); bool initialize() override; - private: - virtual bool loadTexture() override; - virtual bool updateTexture() override; +protected: - virtual bool readyToRender() const override; - virtual void setUniformAndTextures() override; + /** + * Creates a plane geometry + */ + bool createGeometry() override; + bool destroyGeometry() override; + void renderGeometry() const override; + void setUniforms() override; - void setTransferFunctions(std::string tfPath); - void fillOptions(); +private: + + void subscribeToGroup(); - properties::SelectionProperty _dataOptions; properties::StringProperty _transferFunctionsFile; properties::Vec2Property _backgroundValues; - properties::Vec2Property _normValues; - properties::BoolProperty _useLog; properties::BoolProperty _useHistogram; properties::BoolProperty _autoFilter; - std::string _dataBuffer; + GLuint _quad; + GLuint _vertexPositionBuffer; +}; - std::shared_ptr _dataProcessor; - - }; - - } // namespace openspace +} // namespace openspace #endif //__DATAPLANE_H__ \ No newline at end of file diff --git a/modules/iswa/rendering/datasphere.cpp b/modules/iswa/rendering/datasphere.cpp index c455be04f1..2059caf590 100644 --- a/modules/iswa/rendering/datasphere.cpp +++ b/modules/iswa/rendering/datasphere.cpp @@ -23,36 +23,28 @@ ****************************************************************************************/ #include -#include -#include -#include -#include -#include +#include #include - namespace { const std::string _loggerCat = "DataSphere"; - const int MAX_TEXTURES = 6; } namespace openspace { DataSphere::DataSphere(const ghoul::Dictionary& dictionary) - :CygnetSphere(dictionary) + :DataCygnet(dictionary) ,_useLog("useLog","Use Logarithm", false) - ,_useHistogram("useHistogram", "Use Histogram", true) - ,_autoFilter("autoFilter", "Auto Filter", true) + ,_useHistogram("useHistogram", "Auto Contrast", false) + ,_autoFilter("autoFilter", "Auto Filter", false) ,_normValues("normValues", "Normalize Values", glm::vec2(1.0,1.0), glm::vec2(0), glm::vec2(5.0)) ,_backgroundValues("backgroundValues", "Background Values", glm::vec2(0.0), glm::vec2(0), glm::vec2(1.0)) ,_transferFunctionsFile("transferfunctions", "Transfer Functions", "${SCENE}/iswa/tfs/hot.tf") - ,_dataOptions("dataOptions", "Data Options") + ,_sphere(nullptr) { - std::string name; - dictionary.getValue("Name", name); - setName(name); - - registerProperties(); + float radius; + dictionary.getValue("Radius", radius); + _radius = radius; addProperty(_useLog); addProperty(_useHistogram); @@ -60,7 +52,6 @@ DataSphere::DataSphere(const ghoul::Dictionary& dictionary) addProperty(_normValues); addProperty(_backgroundValues); addProperty(_transferFunctionsFile); - addProperty(_dataOptions); _programName = "DataSphereProgram"; _vsPath = "${MODULE_ISWA}/shaders/datasphere_vs.glsl"; @@ -74,72 +65,31 @@ bool DataSphere::initialize(){ if(_group){ _dataProcessor = _group->dataProcessor(); - auto groupEvent = _group->groupEvent(); - - groupEvent->subscribe(name(), "useLogChanged", [&](const ghoul::Dictionary& dict){ - LDEBUG(name() + " Event useLogChanged"); - _useLog.setValue(dict.value("useLog")); - }); - - groupEvent->subscribe(name(), "normValuesChanged", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event normValuesChanged"); - std::shared_ptr values; - bool success = dict.getValue("normValues", values); - if(success){ - _normValues.setValue(*values); - } - }); - - groupEvent->subscribe(name(), "useHistogramChanged", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event useHistogramChanged"); - _useHistogram.setValue(dict.value("useHistogram")); - }); - - groupEvent->subscribe(name(), "dataOptionsChanged", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event dataOptionsChanged"); - std::shared_ptr > values; - bool success = dict.getValue("dataOptions", values); - if(success){ - _dataOptions.setValue(*values); - } - }); - - groupEvent->subscribe(name(), "transferFunctionsChanged", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event transferFunctionsChanged"); - _transferFunctionsFile.setValue(dict.value("transferFunctions")); - }); - - groupEvent->subscribe(name(), "backgroundValuesChanged", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event backgroundValuesChanged"); - std::shared_ptr values; - bool success = dict.getValue("backgroundValues", values); - if(success){ - _backgroundValues.setValue(*values); - } - }); - - groupEvent->subscribe(name(), "autoFilterChanged", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event autoFilterChanged"); - _autoFilter.setValue(dict.value("autoFilter")); - }); - - groupEvent->subscribe(name(), "updateGroup", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event updateGroup"); - loadTexture(); - }); - + subscribeToGroup(); }else{ OsEng.gui()._iswa.registerProperty(&_useLog); OsEng.gui()._iswa.registerProperty(&_useHistogram); OsEng.gui()._iswa.registerProperty(&_autoFilter); - OsEng.gui()._iswa.registerProperty(&_normValues); OsEng.gui()._iswa.registerProperty(&_backgroundValues); + OsEng.gui()._iswa.registerProperty(&_normValues); OsEng.gui()._iswa.registerProperty(&_transferFunctionsFile); OsEng.gui()._iswa.registerProperty(&_dataOptions); + _dataProcessor = std::make_shared(); + //If autofiler is on, background values property should be hidden + _autoFilter.onChange([this](){ + // If autofiler is selected, use _dataProcessor to set backgroundValues + // and unregister backgroundvalues property. + if(_autoFilter.value()){ + _backgroundValues.setValue(_dataProcessor->filterValues()); + // else if autofilter is turned off, register backgroundValues + } else { + OsEng.gui()._iswa.registerProperty(&_backgroundValues, &_autoFilter); + } + }); } - setTransferFunctions(_transferFunctionsFile.value()); + readTransferFunctions(_transferFunctionsFile.value()); _normValues.onChange([this](){ _dataProcessor->normValues(_normValues.value()); @@ -152,8 +102,10 @@ bool DataSphere::initialize(){ }); _useHistogram.onChange([this](){ - _dataProcessor->useHistogram(_useHistogram.value()); + _dataProcessor->useHistogram(_useHistogram.value()); loadTexture(); + if(_autoFilter.value()) + _backgroundValues.setValue(_dataProcessor->filterValues()); }); _dataOptions.onChange([this](){ @@ -163,219 +115,94 @@ bool DataSphere::initialize(){ }); _transferFunctionsFile.onChange([this](){ - setTransferFunctions(_transferFunctionsFile.value()); + readTransferFunctions(_transferFunctionsFile.value()); }); + _useHistogram.setValue(true); + _autoFilter.setValue(true); + return true; } -bool DataSphere::loadTexture(){ - - // if The future is done then get the new dataFile - if(_futureObject.valid() && DownloadManager::futureReady(_futureObject)){ - DownloadManager::MemoryFile dataFile = _futureObject.get(); - - if(dataFile.corrupted) - return false; - - _dataBuffer = ""; - _dataBuffer.append(dataFile.buffer, dataFile.size); - delete[] dataFile.buffer; - } - - // if the buffer in the datafile is empty, do not proceed - if(_dataBuffer.empty()) - return false; - - if(!_dataOptions.options().size()){ // load options for value selection - fillOptions(); - _dataProcessor->addDataValues(_dataBuffer, _dataOptions); - - if(_group) - _group->updateGroup(); - } - - std::vector data = _dataProcessor->processData(_dataBuffer, _dataOptions); - - if(data.empty()) - return false; - - if(_autoFilter.value()) - _backgroundValues.setValue(_dataProcessor->filterValues()); - - bool texturesReady = false; - std::vector selectedOptions = _dataOptions.value(); - - for(int option: selectedOptions){ - float* values = data[option]; - if(!values) continue; - - if(!_textures[option]){ - std::unique_ptr texture = std::make_unique( - values, - _dataProcessor->dimensions(), - ghoul::opengl::Texture::Format::Red, - GL_RED, - GL_FLOAT, - ghoul::opengl::Texture::FilterMode::Linear, - ghoul::opengl::Texture::WrappingMode::ClampToEdge - ); - - if(texture){ - texture->uploadTexture(); - texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear); - _textures[option] = std::move(texture); - } - }else{ - _textures[option]->setPixelData(values); - _textures[option]->uploadTexture(); - } - texturesReady = true; - } - - // _dataBuffer = ""; - return texturesReady; +bool DataSphere::createGeometry(){ + PowerScaledScalar radius = PowerScaledScalar(6.371f*_radius, 6.0); + int segments = 100; + _sphere = std::make_shared(radius, segments); + _sphere->initialize(); + return true; } -bool DataSphere::updateTexture(){ - - if(_futureObject.valid()) - return false; - - std::future future = IswaManager::ref().fetchDataCygnet(_data->id); - - if(future.valid()){ - _futureObject = std::move(future); - return true; - } - - return false; +bool DataSphere::destroyGeometry(){ + _sphere = nullptr; + return true; } - -bool DataSphere::readyToRender() const { - return (!_textures.empty()); - - bool ready = isReady(); - ready &= (!_textures.empty() && _textures[0]); - ready &= (_sphere != nullptr); - return ready; +void DataSphere::renderGeometry() const { + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + _sphere->render(); } - -void DataSphere::setUniformAndTextures(){ - std::vector selectedOptions = _dataOptions.value(); - int activeTextures = std::min((int)selectedOptions.size(), MAX_TEXTURES); - int activeTransferfunctions = std::min((int)_transferFunctions.size(), MAX_TEXTURES); - - ghoul::opengl::TextureUnit txUnits[10]; - int j = 0; - for(int option : selectedOptions){ - if(_textures[option]){ - txUnits[j].activate(); - _textures[option]->bind(); - _shader->setUniform( - "textures[" + std::to_string(j) + "]", - txUnits[j] - ); - - j++; - if(j >= MAX_TEXTURES) break; - - } - } - - if(activeTextures > 0){ - if(selectedOptions.back()>=activeTransferfunctions) - activeTransferfunctions = 1; - } - - ghoul::opengl::TextureUnit tfUnits[10]; - j = 0; - - if((activeTransferfunctions == 1)){ - tfUnits[0].activate(); - _transferFunctions[0]->bind(); - _shader->setUniform( - "transferFunctions[0]", - tfUnits[0] - ); - }else{ - for(int option : selectedOptions){ - // std::cout << option << std::endl; - // if(option >= activeTransferfunctions){ - // // LWARNING("No transfer function for this value."); - // break; - // } - - if(_transferFunctions[option]){ - tfUnits[j].activate(); - _transferFunctions[option]->bind(); - _shader->setUniform( - "transferFunctions[" + std::to_string(j) + "]", - tfUnits[j] - ); - - j++; - if(j >= MAX_TEXTURES) break; - } - } - } - - _shader->setUniform("numTextures", activeTextures); - _shader->setUniform("numTransferFunctions", activeTransferfunctions); +void DataSphere::setUniforms(){ + // set both data texture and transfer function texture + setTextureUniforms(); _shader->setUniform("backgroundValues", _backgroundValues.value()); _shader->setUniform("transparency", _alpha.value()); } +void DataSphere::subscribeToGroup(){ + auto groupEvent = _group->groupEvent(); + groupEvent->subscribe(name(), "useLogChanged", [&](const ghoul::Dictionary& dict){ + LDEBUG(name() + " Event useLogChanged"); + _useLog.setValue(dict.value("useLog")); + }); -// bool DataSphere::createShader(){ -// if (_shader == nullptr) { -// // Plane Program -// RenderEngine& renderEngine = OsEng.renderEngine(); -// _shader = renderEngine.buildRenderProgram( -// "DataSphereProgram", -// "${MODULE_ISWA}/shaders/datasphere_vs.glsl", -// "${MODULE_ISWA}/shaders/datasphere_fs.glsl"); -// if (!_shader) -// return false; -// } -// return true; -// } - -void DataSphere::setTransferFunctions(std::string tfPath){ - std::string line; - std::ifstream tfFile(absPath(tfPath)); - - std::vector> tfs; - - if(tfFile.is_open()){ - while(getline(tfFile, line)){ - std::shared_ptr tf = std::make_shared(absPath(line)); - if(tf){ - tfs.push_back(tf); - } + groupEvent->subscribe(name(), "normValuesChanged", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event normValuesChanged"); + std::shared_ptr values; + bool success = dict.getValue("normValues", values); + if(success){ + _normValues.setValue(*values); } - tfFile.close(); - } + }); + groupEvent->subscribe(name(), "useHistogramChanged", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event useHistogramChanged"); + _useHistogram.setValue(dict.value("useHistogram")); + }); - if(!tfs.empty()){ - _transferFunctions.clear(); - _transferFunctions = tfs; - } -} + groupEvent->subscribe(name(), "dataOptionsChanged", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event dataOptionsChanged"); + std::shared_ptr > values; + bool success = dict.getValue("dataOptions", values); + if(success){ + _dataOptions.setValue(*values); + } + }); -void DataSphere::fillOptions(){ - std::vector options = _dataProcessor->readMetadata(_dataBuffer); - for(int i=0; i(1,0)); - if(_group) - std::dynamic_pointer_cast(_group)->registerOptions(_dataOptions.options()); - // IswaManager::ref().registerOptionsToGroup(_data->groupName, _dataOptions.options()); + groupEvent->subscribe(name(), "transferFunctionsChanged", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event transferFunctionsChanged"); + _transferFunctionsFile.setValue(dict.value("transferFunctions")); + }); + + groupEvent->subscribe(name(), "backgroundValuesChanged", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event backgroundValuesChanged"); + std::shared_ptr values; + bool success = dict.getValue("backgroundValues", values); + if(success){ + _backgroundValues.setValue(*values); + } + }); + + groupEvent->subscribe(name(), "autoFilterChanged", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event autoFilterChanged"); + _autoFilter.setValue(dict.value("autoFilter")); + }); + + groupEvent->subscribe(name(), "updateGroup", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event updateGroup"); + loadTexture(); + }); } } //namespace openspace \ No newline at end of file diff --git a/modules/iswa/rendering/datasphere.h b/modules/iswa/rendering/datasphere.h index 8026fd3088..7ea036fc42 100644 --- a/modules/iswa/rendering/datasphere.h +++ b/modules/iswa/rendering/datasphere.h @@ -25,45 +25,47 @@ #ifndef __DATASPHERE_H__ #define __DATASPHERE_H__ -#include +#include #include #include -#include - namespace openspace{ class PowerScaledSphere; -class DataSphere : public CygnetSphere { -friend class IswaBaseGroup; + +/** + * DataSphere is a concrete IswaCygnet with data files as its input source. + * The class handles creation, destruction and rendering of a sphere geometry. + * It also specifies what uniforms to use and what GUI properties it needs. + */ +class DataSphere : public DataCygnet { public: DataSphere(const ghoul::Dictionary& dictionary); ~DataSphere(); bool initialize() override; +protected: + + /** + * Creates a sphere geometry + */ + bool createGeometry() override; + bool destroyGeometry() override; + void renderGeometry() const override; + void setUniforms() override; private: - virtual bool loadTexture() override; - virtual bool updateTexture() override; - virtual bool readyToRender() const override; - virtual void setUniformAndTextures() override; + void subscribeToGroup(); - void setTransferFunctions(std::string tfPath); - void fillOptions(); - - properties::SelectionProperty _dataOptions; properties::StringProperty _transferFunctionsFile; properties::Vec2Property _backgroundValues; - properties::Vec2Property _normValues; - properties::BoolProperty _useLog; properties::BoolProperty _useHistogram; properties::BoolProperty _autoFilter; - - std::string _dataBuffer; - std::shared_ptr _dataProcessor; + std::shared_ptr _sphere; + float _radius; }; diff --git a/modules/iswa/rendering/iswacygnet.cpp b/modules/iswa/rendering/iswacygnet.cpp index a12a8aa30a..b2a9893d2b 100644 --- a/modules/iswa/rendering/iswacygnet.cpp +++ b/modules/iswa/rendering/iswacygnet.cpp @@ -24,8 +24,6 @@ #include #include #include -#include -#include #include #include #include @@ -45,6 +43,10 @@ IswaCygnet::IswaCygnet(const ghoul::Dictionary& dictionary) ,_group(nullptr) ,_textureDirty(false) { + std::string name; + dictionary.getValue("Name", name); + setName(name); + _data = std::make_shared(); // dict.getValue can only set strings in _data directly @@ -86,26 +88,11 @@ IswaCygnet::IswaCygnet(const ghoul::Dictionary& dictionary) _data->scale = scale; _data->offset = offset; - // std::cout << std::to_string(min) << std::endl; - // std::cout << std::to_string(max) << std::endl; - // std::cout << std::to_string(_data->scale) << std::endl; - // std::cout << std::to_string(_data->offset) << std::endl; - addProperty(_alpha); addProperty(_delete); - // if(dictionary.hasValue("Group")){ dictionary.getValue("Group", _data->groupName); - // } - // _data->groupId = groupId; - // std::cout << _data->id << std::endl; - // std::cout << _data->frame << std::endl; - // std::cout << std::to_string(_data->offset) << std::endl; - // std::cout << std::to_string(_data->scale) << std::endl; - // std::cout << std::to_string(_data->max) << std::endl; - // std::cout << std::to_string(_data->min) << std::endl; - // std::cout << std::to_string(_data->spatialScale) << std::endl; - // OsEng.gui()._iswa.registerProperty(&_enabled); + } IswaCygnet::~IswaCygnet(){} @@ -135,8 +122,6 @@ bool IswaCygnet::initialize(){ bool IswaCygnet::deinitialize(){ if(!_data->groupName.empty()) _group->groupEvent()->unsubscribe(name()); - // IswaManager::ref().unregisterFromGroup(_data->groupName, this); - unregisterProperties(); destroyGeometry(); @@ -178,7 +163,7 @@ void IswaCygnet::render(const RenderData& data){ setPscUniforms(*_shader.get(), data.camera, position); - setUniformAndTextures(); + setUniforms(); renderGeometry(); glEnable(GL_CULL_FACE); @@ -245,7 +230,6 @@ void IswaCygnet::initializeTime(){ bool IswaCygnet::createShader(){ if (_shader == nullptr) { - // Plane Program RenderEngine& renderEngine = OsEng.renderEngine(); _shader = renderEngine.buildRenderProgram(_programName, _vsPath, @@ -257,10 +241,9 @@ bool IswaCygnet::createShader(){ } void IswaCygnet::initializeGroup(){ - // _groupEvent = IswaManager::ref().groupEvent(_data->groupName, _type); _group = IswaManager::ref().iswaGroup(_data->groupName); - //Subscribe to enable propert and delete + //Subscribe to enable and delete property auto groupEvent = _group->groupEvent(); groupEvent->subscribe(name(), "enabledChanged", [&](const ghoul::Dictionary& dict){ LDEBUG(name() + " Event enabledChanged"); diff --git a/modules/iswa/rendering/iswacygnet.h b/modules/iswa/rendering/iswacygnet.h index 7323797019..20989f249a 100644 --- a/modules/iswa/rendering/iswacygnet.h +++ b/modules/iswa/rendering/iswacygnet.h @@ -30,20 +30,16 @@ #include #include -#include -#include +#include #include +#include +#include +#include +#include #include #include #include -#include -#include -#include -#include -#include #include -#include -#include #include #include @@ -92,7 +88,6 @@ protected: void unregisterProperties(); void initializeTime(); void initializeGroup(); - bool destroyShader(); bool createShader(); virtual bool createGeometry() = 0; @@ -102,7 +97,7 @@ protected: virtual bool loadTexture() = 0; virtual bool updateTexture() = 0; virtual bool readyToRender() const = 0; - virtual void setUniformAndTextures() = 0; + virtual void setUniforms() = 0; properties::FloatProperty _alpha; properties::TriggerProperty _delete; @@ -126,12 +121,15 @@ protected: std::shared_ptr _group; - // IswaManager::CygnetType _type; bool _textureDirty; std::string _vsPath; std::string _fsPath; std::string _programName; + +private: + bool destroyShader(); + }; }//namespace openspace diff --git a/modules/iswa/rendering/iswagroup.cpp b/modules/iswa/rendering/iswagroup.cpp index 62cb4d8706..44fe7c20a9 100644 --- a/modules/iswa/rendering/iswagroup.cpp +++ b/modules/iswa/rendering/iswagroup.cpp @@ -57,6 +57,8 @@ IswaBaseGroup::IswaBaseGroup(std::string name, std::string type) _groupEvent = std::make_shared >(); registerProperties(); + + _autoFilter.setValue(true); } IswaBaseGroup::~IswaBaseGroup(){} @@ -98,7 +100,6 @@ void IswaBaseGroup::registerProperties(){ _groupEvent->publish("alphaChanged", ghoul::Dictionary({{"alpha", _alpha.value()}})); }); - OsEng.gui()._iswa.registerProperty(&_delete); _delete.onChange([this]{ clearGroup(); diff --git a/modules/iswa/rendering/kameleonplane.cpp b/modules/iswa/rendering/kameleonplane.cpp index 94a58331bd..c8cd787119 100644 --- a/modules/iswa/rendering/kameleonplane.cpp +++ b/modules/iswa/rendering/kameleonplane.cpp @@ -51,19 +51,16 @@ namespace openspace { KameleonPlane::KameleonPlane(const ghoul::Dictionary& dictionary) :CygnetPlane(dictionary) ,_useLog("useLog","Use Logarithm", false) - ,_useHistogram("useHistogram", "Use Histogram", false) + ,_useHistogram("useHistogram", "Auto Contrast", false) ,_autoFilter("autoFilter", "Auto Filter", true) ,_normValues("normValues", "Normalize Values", glm::vec2(1.0,1.0), glm::vec2(0), glm::vec2(5.0)) ,_backgroundValues("backgroundValues", "Background Values", glm::vec2(0.0), glm::vec2(0), glm::vec2(1.0)) ,_transferFunctionsFile("transferfunctions", "Transfer Functions", "${SCENE}/iswa/tfs/hot.tf") ,_dataOptions("dataOptions", "Data Options") ,_fieldlines("fieldlineSeedsIndexFile", "Fieldline Seedpoints") - ,_resolution("resolution", "Resolutionx100", 3, 1, 5) + ,_resolution("resolution", "Resolutionx100", 1, 1, 5) ,_slice("slice", "Slice", 0.0, 0.0, 1.0) { - std::string name; - dictionary.getValue("Name", name); - setName(name); registerProperties(); @@ -247,20 +244,20 @@ bool KameleonPlane::initialize(){ _dimensions.z = (int) _dimensions.y * (_data->scale.y/_data->scale.z); _textureDimensions = glm::size3_t(_dimensions.y, _dimensions.z, 1); - _data->offset.x = _data->gridMin.x+_slice.value()*_scale; + // _data->offset.x = _data->gridMin.x+0.5*_slice.value()*_scale; }else if(_data->scale.y == 0){ _dimensions.y = 1; _dimensions.z = (int) _dimensions.x * (_data->scale.x/_data->scale.z); _textureDimensions = glm::size3_t(_dimensions.x, _dimensions.z, 1); - _data->offset.y = _data->gridMin.y+_slice.value()*_scale; + // _data->offset.y = _data->gridMin.y+0.5*_slice.value()*_scale; }else{ _dimensions.z = 1; _dimensions.y = (int) _dimensions.x * (_data->scale.x/_data->scale.y); _textureDimensions = glm::size3_t(_dimensions.x, _dimensions.y, 1); - _data->offset.z = _data->gridMin.z+_slice.value()*_scale; + // _data->offset.z = _data->gridMin.z+0.5*_slice.value()*_scale; } fillOptions(); @@ -273,7 +270,7 @@ bool KameleonPlane::initialize(){ } bool KameleonPlane::loadTexture() { - std::vector data = std::dynamic_pointer_cast (_dataProcessor)->processData(_kwPath, _dataOptions, _slice); + std::vector data = std::dynamic_pointer_cast (_dataProcessor)->processData(_kwPath, _dataOptions, _slice, _dimensions); if(data.empty()) return false; @@ -324,14 +321,6 @@ bool KameleonPlane::updateTexture(){ _data->offset.z = _data->gridMin.z+_slice.value()*_scale; } - // for(int i=0; i<_dataSlices.size(); ++i){ - // float* slice = _dataSlices[i]; - // if(slice){ - // _dataSlices[i] = nullptr; - // delete slice; - // } - // } - _textureDirty = true; return true; @@ -342,7 +331,7 @@ bool KameleonPlane::readyToRender() const { return (!_textures.empty() && !_transferFunctions.empty()); } -void KameleonPlane::setUniformAndTextures(){ +void KameleonPlane::setUniforms(){ std::vector selectedOptions = _dataOptions.value(); int activeTextures = std::min((int)selectedOptions.size(), MAX_TEXTURES); int activeTransferfunctions = std::min((int)_transferFunctions.size(), MAX_TEXTURES); diff --git a/modules/iswa/rendering/kameleonplane.h b/modules/iswa/rendering/kameleonplane.h index 3a1c7fc545..b1bf47ddd3 100644 --- a/modules/iswa/rendering/kameleonplane.h +++ b/modules/iswa/rendering/kameleonplane.h @@ -47,7 +47,7 @@ virtual bool updateTexture() override; virtual bool readyToRender() const override; - virtual void setUniformAndTextures() override; + virtual void setUniforms() override; /** * Given a path to the json index of seedpoints file, this diff --git a/modules/iswa/rendering/texturecygnet.cpp b/modules/iswa/rendering/texturecygnet.cpp index 2212f26f93..649c94fa72 100644 --- a/modules/iswa/rendering/texturecygnet.cpp +++ b/modules/iswa/rendering/texturecygnet.cpp @@ -34,7 +34,9 @@ namespace openspace{ TextureCygnet::TextureCygnet(const ghoul::Dictionary& dictionary) :IswaCygnet(dictionary) -{} +{ + registerProperties(); +} TextureCygnet::~TextureCygnet(){} diff --git a/modules/iswa/rendering/texturecygnet.h b/modules/iswa/rendering/texturecygnet.h index d4837fe2a2..bd0e2ca7c5 100644 --- a/modules/iswa/rendering/texturecygnet.h +++ b/modules/iswa/rendering/texturecygnet.h @@ -30,7 +30,7 @@ namespace openspace{ /** - * This class exist tp abstract away the loading of images + * This class exist to abstract away the loading of images * from iSWA and updating of the textures for child geometries. * The class specifies the minimum interface that child classes * needs to implement. @@ -47,7 +47,8 @@ protected: bool readyToRender() const override; // Interface for concrete subclasses - virtual void setUniformAndTextures() = 0; + //virtual void setUniformAndTextures() = 0; + virtual void setUniforms() = 0; virtual bool createGeometry() = 0; virtual bool destroyGeometry() = 0; virtual void renderGeometry() const = 0; diff --git a/modules/iswa/rendering/textureplane.cpp b/modules/iswa/rendering/textureplane.cpp index 07e7b9bbc0..777dac2c1a 100644 --- a/modules/iswa/rendering/textureplane.cpp +++ b/modules/iswa/rendering/textureplane.cpp @@ -36,11 +36,6 @@ TexturePlane::TexturePlane(const ghoul::Dictionary& dictionary) ,_quad(0) ,_vertexPositionBuffer(0) { - std::string name; - dictionary.getValue("Name", name); - setName(name); - registerProperties(); - _programName = "PlaneProgram"; _vsPath = "${MODULE_ISWA}/shaders/cygnetplane_vs.glsl"; _fsPath = "${MODULE_ISWA}/shaders/cygnetplane_fs.glsl"; @@ -48,7 +43,7 @@ TexturePlane::TexturePlane(const ghoul::Dictionary& dictionary) TexturePlane::~TexturePlane(){} -void TexturePlane::setUniformAndTextures(){ +void TexturePlane::setUniforms(){ ghoul::opengl::TextureUnit unit; unit.activate(); diff --git a/modules/iswa/rendering/textureplane.h b/modules/iswa/rendering/textureplane.h index 62a2a571d1..4803ec0176 100644 --- a/modules/iswa/rendering/textureplane.h +++ b/modules/iswa/rendering/textureplane.h @@ -30,9 +30,9 @@ namespace openspace{ /** - * TexturePlane is a "concrete" IswaCygnet. It handles the creation, - * destruction and rendering of a plane geometry. It also specifies - * which shaders to use and the uniforms that it needs. + * TexturePlane is a "concrete" IswaCygnet with texture as its input source. + * It handles the creation, destruction and rendering of a plane geometry. + * It also specifies which shaders to use and the uniforms that it needs. */ class TexturePlane : public TextureCygnet{ public: @@ -41,7 +41,7 @@ public: private: bool createGeometry() override; - void setUniformAndTextures() override; + void setUniforms() override; bool destroyGeometry() override; void renderGeometry() const override; diff --git a/modules/iswa/shaders/dataplane_fs.glsl b/modules/iswa/shaders/dataplane_fs.glsl index c17b190d06..c470fd14d3 100644 --- a/modules/iswa/shaders/dataplane_fs.glsl +++ b/modules/iswa/shaders/dataplane_fs.glsl @@ -35,7 +35,6 @@ uniform bool averageValues; uniform vec2 backgroundValues; uniform float transparency; - // uniform float background; in vec2 vs_st; @@ -63,6 +62,7 @@ Fragment getFragment() { vec4 color = texture(transferFunctions[0], vec2(v,0)); if((v<(x+y)) && v>(x-y)) color = mix(transparent, color, clamp(1,0,abs(v-x))); + diffuse = color; }else{ for(int i=0; i DataProcessorKameleon::processData(std::string path, properties::SelectionProperty& dataOptions, float slice){ +std::vector DataProcessorKameleon::processData(std::string path, properties::SelectionProperty& dataOptions, float slice, glm::size3_t& dimensions){ _slice = slice; + _dimensions = dimensions; return processData(path, dataOptions); } diff --git a/modules/iswa/util/dataprocessorkameleon.h b/modules/iswa/util/dataprocessorkameleon.h index 7d8e90c14e..f22a1f31d3 100644 --- a/modules/iswa/util/dataprocessorkameleon.h +++ b/modules/iswa/util/dataprocessorkameleon.h @@ -37,7 +37,7 @@ public: virtual std::vector readMetadata(std::string path) override; virtual void addDataValues(std::string data, properties::SelectionProperty& dataOptions) override; virtual std::vector processData(std::string path, properties::SelectionProperty& dataOptions) override; - virtual std::vector processData(std::string path, properties::SelectionProperty& dataOptions, float slize); + virtual std::vector processData(std::string path, properties::SelectionProperty& dataOptions, float slice, glm::size3_t& dimensions); void dimensions(glm::size3_t dimensions){_dimensions = dimensions;} private: diff --git a/modules/iswa/util/iswamanager.cpp b/modules/iswa/util/iswamanager.cpp index f4ec466e44..3efcdd5011 100644 --- a/modules/iswa/util/iswamanager.cpp +++ b/modules/iswa/util/iswamanager.cpp @@ -39,6 +39,7 @@ #include #include +#include #include #include #include diff --git a/modules/iswa/util/iswamanager.h b/modules/iswa/util/iswamanager.h index b7cc4c2a99..b3ca5a7ef0 100644 --- a/modules/iswa/util/iswamanager.h +++ b/modules/iswa/util/iswamanager.h @@ -93,15 +93,10 @@ public: std::future fetchDataCygnet(int id); std::string iswaUrl(int id, std::string type = "image"); - std::shared_ptr > groupEvent(std::string name, CygnetType type); - // std::shared_ptr getIswaBaseGroup(std::string groupName, CygnetType type); - // void unregisterFromGroup(std::string name, IswaCygnet* cygnet); - // void registerOptionsToGroup(std::string name, const std::vector& options); std::shared_ptr iswaGroup(std::string name); std::map>& cygnetInformation(); std::map>& groups(); - // std::vector& cdfInformation(); std::map>& cdfInformation(); static scripting::ScriptEngine::LuaLibrary luaLibrary(); @@ -123,7 +118,6 @@ private: void createKameleonPlane(CdfInfo info, std::string cut); void fillCygnetInfo(std::string jsonString); - void registerGroup(std::string groupName, std::string type); std::map _month; @@ -135,7 +129,6 @@ private: std::map> _groups; std::map> _cygnetInformation; - // std::vector _cdfInformation; std::map> _cdfInformation; ghoul::Event<> _iswaEvent;