// /***************************************************************************************** // * * // * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { using json = nlohmann::json; const std::string _loggerCat = "KameleonPlane"; } namespace openspace { KameleonPlane::KameleonPlane(const ghoul::Dictionary& dictionary) :CygnetPlane(dictionary) ,_useLog("useLog","Use Logarithm", false) ,_useHistogram("useHistogram", "Use Histogram", 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") { std::string name; dictionary.getValue("Name", name); setName(name); registerProperties(); addProperty(_useLog); addProperty(_useHistogram); addProperty(_normValues); addProperty(_backgroundValues); addProperty(_transferFunctionsFile); addProperty(_dataOptions); addProperty(_fieldlines); if(_data->groupName.empty()){ OsEng.gui()._iswa.registerProperty(&_useLog); OsEng.gui()._iswa.registerProperty(&_useHistogram); OsEng.gui()._iswa.registerProperty(&_normValues); OsEng.gui()._iswa.registerProperty(&_backgroundValues); OsEng.gui()._iswa.registerProperty(&_transferFunctionsFile); OsEng.gui()._iswa.registerProperty(&_dataOptions); OsEng.gui()._iswa.registerProperty(&_fieldlines); } setTransferFunctions(_transferFunctionsFile.value()); _dataProcessor = std::make_shared( _useLog.value(), _useHistogram.value(), _normValues ); _dataOptions.onChange([this](){updateTexture();}); _normValues.onChange([this](){ _dataProcessor->normValues(_normValues.value()); loadTexture(); }); _useLog.onChange([this](){ _dataProcessor->useLog(_useLog.value()); loadTexture(); }); _useHistogram.onChange([this](){ _dataProcessor->useHistogram(_useHistogram.value()); loadTexture(); }); _transferFunctionsFile.onChange([this](){ setTransferFunctions(_transferFunctionsFile.value()); }); _type = IswaManager::CygnetType::Data; dictionary.getValue("kwPath", _kwPath); std::string fieldlineIndexFile; dictionary.getValue("fieldlineSeedsIndexFile", fieldlineIndexFile); readFieldlinePaths(absPath(fieldlineIndexFile)); _dataOptions.onChange([this](){updateTexture();}); _fieldlines.onChange([this](){ updateFieldlineSeeds();} ); std::string axis; dictionary.getValue("axisCut", axis); _dimensions = glm::size3_t(150); if(axis == "x"){ _data->scale.x = 0; _dimensions.x = 1; _dimensions.z = (int) _dimensions.y * (_data->scale.y/_data->scale.z); _textureDimensions = glm::size3_t(_dimensions.y, _dimensions.z, 1); }else if(axis == "y"){ _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); }else{ _data->scale.z = 0; _dimensions.z = 1; _dimensions.y = (int) _dimensions.x * (_data->scale.x/_data->scale.y); _textureDimensions = glm::size3_t(_dimensions.x, _dimensions.y, 1); } std::cout << "Dimensions: " << _dimensions.x << " " << _dimensions.y << " " << _dimensions.z << std::endl; } KameleonPlane::~KameleonPlane(){ _kw = nullptr; } // bool KameleonPlane::initialize(){ // _textures.push_back(nullptr); // std::cout << "initialize kameleonplane" << std::endl; // // std::string kwPath; // // dictionary.getValue("KW", _kw); // createPlane(); // if (_shader == nullptr) { // // DatePlane Program // RenderEngine& renderEngine = OsEng.renderEngine(); // _shader = renderEngine.buildRenderProgram("PlaneProgram", // "${MODULE_ISWA}/shaders/dataplane_vs.glsl", // "${MODULE_ISWA}/shaders/dataplane_fs.glsl" // ); // if (!_shader) // return false; // } // loadTexture();P // return isReady(); // } // bool KameleonPlane::deinitialize(){ // unregisterProperties(); // destroyPlane(); // destroyShader(); // _kw = nullptr; // _memorybuffer = ""; // return true; // } bool KameleonPlane::loadTexture() { ghoul::opengl::Texture::FilterMode filtermode = ghoul::opengl::Texture::FilterMode::Linear; ghoul::opengl::Texture::WrappingMode wrappingmode = ghoul::opengl::Texture::WrappingMode::ClampToEdge; std::vector data = _dataProcessor->processKameleonData(_dataSlices, _dimensions, _dataOptions); if(data.empty()) return false; _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, _textureDimensions, 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 KameleonPlane::updateTexture(){ if(!_kw){ _kw = std::make_shared(absPath(_kwPath)); } if(!_dataOptions.options().size()){ fillOptions(); } std::vector selectedOptions = _dataOptions.value(); auto options = _dataOptions.options(); float zSlice = 0.5f; for(int option : selectedOptions){ if(!_dataSlices[option]){ std::cout << options[option].description << std::endl; _dataSlices[option] = _kw->getUniformSliceValues(options[option].description, _dimensions, zSlice); } } loadTexture(); return true; } bool KameleonPlane::readyToRender(){ return (_textures[0] != nullptr && !_transferFunctions.empty()); } void KameleonPlane::setUniformAndTextures(){ std::vector selectedOptions = _dataOptions.value(); int activeTextures = selectedOptions.size(); int activeTransferfunctions = _transferFunctions.size(); 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(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++; } } } _shader->setUniform("numTextures", activeTextures); _shader->setUniform("numTransferFunctions", activeTransferfunctions); _shader->setUniform("backgroundValues", _backgroundValues.value()); } bool KameleonPlane::createShader(){ if (_shader == nullptr) { // DatePlane Program RenderEngine& renderEngine = OsEng.renderEngine(); _shader = renderEngine.buildRenderProgram("DataPlaneProgram", "${MODULE_ISWA}/shaders/dataplane_vs.glsl", "${MODULE_ISWA}/shaders/dataplane_fs.glsl" ); if (!_shader) return false; } } void KameleonPlane::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); } } } if(!tfs.empty()){ _transferFunctions.clear(); _transferFunctions = tfs; } } void KameleonPlane::fillOptions(){ std::vector options = _kw->getVariables(); int numOptions = 0; for(std::string option : options){ if(option.size() < 4 && option != "x" && option != "y" && option != "z"){ _dataOptions.addOption({numOptions, option}); _dataSlices.push_back(nullptr); _textures.push_back(nullptr); numOptions++; } } _dataOptions.setValue(std::vector(1,0)); if(!_data->groupName.empty()) IswaManager::ref().registerOptionsToGroup(_data->groupName, _dataOptions.options()); } void KameleonPlane::updateFieldlineSeeds(){ std::vector selectedOptions = _fieldlines.value(); // SeedPath == map > for (auto& seedPath: _fieldlineState) { // if this option was turned off if( std::find(selectedOptions.begin(), selectedOptions.end(), seedPath.first)==selectedOptions.end() && std::get<2>(seedPath.second)){ LDEBUG("Removed fieldlines: " + std::get<0>(seedPath.second)); OsEng.scriptEngine().queueScript("openspace.removeSceneGraphNode('" + std::get<0>(seedPath.second) + "')"); std::get<2>(seedPath.second) = false; // if this option was turned on } else if( std::find(selectedOptions.begin(), selectedOptions.end(), seedPath.first)!=selectedOptions.end() && !std::get<2>(seedPath.second)) { LDEBUG("Created fieldlines: " + std::get<0>(seedPath.second)); IswaManager::ref().createFieldline(std::get<0>(seedPath.second), _kwPath, std::get<1>(seedPath.second)); std::get<2>(seedPath.second) = true; } } } void KameleonPlane::readFieldlinePaths(std::string indexFile){ LINFO("Reading seed points paths from file '" << indexFile << "'"); // Read the index file from disk std::ifstream seedFile(indexFile); if (!seedFile.good()) LERROR("Could not open seed points file '" << indexFile << "'"); else { std::string line; std::string fileContent; while (std::getline(seedFile, line)) { fileContent += line; } //Parse and add each fieldline as an selection json fieldlines = json::parse(fileContent); int i = 0; for (json::iterator it = fieldlines.begin(); it != fieldlines.end(); ++it) { _fieldlines.addOption({i, it.key()}); _fieldlineState[i] = std::make_tuple(it.key(), it.value(), false); i++; } // _fieldlines.setValue(std::vector(1,0)); } } }// namespace openspace