From d84d48d15b28d5a6391c9ba7fea5a375a9a978c2 Mon Sep 17 00:00:00 2001 From: Jonas Strandstedt Date: Thu, 24 Apr 2014 10:32:01 -0400 Subject: [PATCH] Added working CDF data loading - RenderableVolume can now load .raw and .cdf data to ghoul Texture - KameleonWrapper included for easy interaction with Kameleon - openspace-data updated with support for BATSRUS model - CMakeLists.txt updated with settings to Kamelon library - ext/kameleon not included due to Kameleon is currently being ported to git. Waiting to add it as submodule to avoid duplication of files. --- CMakeLists.txt | 9 ++ .../openspace/rendering/renderablevolume.h | 1 + .../rendering/renderablevolumeexpert.h | 4 +- include/openspace/util/kameleonwrapper.h | 57 +++++++++ openspace-data | 2 +- src/rendering/renderablevolume.cpp | 71 ++++++++++- src/rendering/renderablevolumeexpert.cpp | 20 +-- src/util/kameleonwrapper.cpp | 114 ++++++++++++++++++ 8 files changed, 261 insertions(+), 17 deletions(-) create mode 100644 include/openspace/util/kameleonwrapper.h create mode 100644 src/util/kameleonwrapper.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 235e5f746f..a533495cd9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -92,6 +92,15 @@ if(OPENCL_FOUND) set(GHOUL_DEPENDENCIES ${GHOUL_DEPENDENCIES} ${OPENCL_LIBRARIES}) endif(OPENCL_FOUND) +# Kameleon +option(KAMELEON_LIBRARY_ONLY "Build with Kameleon as library only" ON) +option(BUILD_SHARED_LIBS "Build Shared Libraries" ON) +set(KAMELEON_ROOT_DIR ${OPENSPACE_EXT_DIR}/kameleon) +set(KAMELEON_INCLUDES ${KAMELEON_ROOT_DIR}/src) +add_subdirectory(${KAMELEON_ROOT_DIR}) +include_directories(${KAMELEON_INCLUDES}) +set(DEPENDENT_LIBS ${DEPENDENT_LIBS} ccmc) + if (APPLE) include_directories(/Developer/Headers/FlatCarbon) find_library(CARBON_LIBRARY Carbon) diff --git a/include/openspace/rendering/renderablevolume.h b/include/openspace/rendering/renderablevolume.h index 5898a2938e..00bc8c680b 100644 --- a/include/openspace/rendering/renderablevolume.h +++ b/include/openspace/rendering/renderablevolume.h @@ -44,6 +44,7 @@ public: protected: std::string findPath(const std::string& path); + ghoul::opengl::Texture* loadVolume(const std::string& filepath, const ghoul::Dictionary& hintsDictionary); ghoul::RawVolumeReader::ReadHints readHints(const ghoul::Dictionary& dictionary); ghoul::opengl::Texture* loadTransferFunction(const std::string& filepath); diff --git a/include/openspace/rendering/renderablevolumeexpert.h b/include/openspace/rendering/renderablevolumeexpert.h index 3583d7df12..1b274f293a 100644 --- a/include/openspace/rendering/renderablevolumeexpert.h +++ b/include/openspace/rendering/renderablevolumeexpert.h @@ -37,7 +37,6 @@ #include #include #include -#include #include #ifdef __APPLE__ @@ -75,7 +74,7 @@ private: // Volumes std::vector _volumePaths; - std::vector _volumeHints; + std::vector _volumeHints; // Textures ghoul::opengl::Texture* _output; @@ -105,7 +104,6 @@ private: std::mutex* _textureLock; ghoul::opengl::ProgramObject *_quadProgram; - sgct_utils::SGCTBox* _boundingBox; GLuint _screenQuad; VolumeRaycasterBox* _colorBoxRenderer; diff --git a/include/openspace/util/kameleonwrapper.h b/include/openspace/util/kameleonwrapper.h new file mode 100644 index 0000000000..467373ac25 --- /dev/null +++ b/include/openspace/util/kameleonwrapper.h @@ -0,0 +1,57 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * 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. * + ****************************************************************************************/ + +#ifndef KAMELEONWRAPPER_H_ +#define KAMELEONWRAPPER_H_ + +#include +#include + +namespace ccmc { + class Model; + class Interpolator; +} + +namespace openspace { + +class KameleonWrapper { +public: + + enum class Model { + ENLIL, // Heliosphere + BATSRUS // Magnetosphere + }; + + KameleonWrapper(const std::string& filename, Model model); + ~KameleonWrapper(); + float* getUniformSampledValues(const std::string& var, glm::size3_t outDimensions); + +private: + ccmc::Model* _model; + ccmc::Interpolator* _interpolator; +}; + +} // namespace openspace + +#endif // KAMELEONWRAPPER_H_ diff --git a/openspace-data b/openspace-data index 700afc3b72..23fa37b495 160000 --- a/openspace-data +++ b/openspace-data @@ -1 +1 @@ -Subproject commit 700afc3b72a29a2f2faff3aa8d121cd94c35d975 +Subproject commit 23fa37b495961c714cc361c0f9e5f37326b6d64f diff --git a/src/rendering/renderablevolume.cpp b/src/rendering/renderablevolume.cpp index 1a08515c53..7ecccbaaf1 100644 --- a/src/rendering/renderablevolume.cpp +++ b/src/rendering/renderablevolume.cpp @@ -29,6 +29,8 @@ #include #include +#include + #include #include @@ -41,10 +43,11 @@ namespace { std::string _loggerCat = "RenderableVolume"; - bool hasEnding (std::string const &fullString, std::string const &ending) + bool hasExtension (std::string const &filepath, std::string const &extension) { - if (fullString.length() >= ending.length()) { - return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending)); + std::string ending = "." + extension; + if (filepath.length() > ending.length()) { + return (0 == filepath.compare (filepath.length() - ending.length(), ending.length(), ending)); } else { return false; } @@ -96,6 +99,66 @@ std::string RenderableVolume::findPath(const std::string& path) { return ""; } +ghoul::opengl::Texture* RenderableVolume::loadVolume(const std::string& filepath, const ghoul::Dictionary& hintsDictionary) { + if( ! FileSys.fileExists(filepath)) { + LWARNING("Could not load volume, could not find '" << filepath << "'"); + return nullptr; + } + + if(hasExtension(filepath, "raw")) { + ghoul::RawVolumeReader::ReadHints hints = readHints(hintsDictionary); + ghoul::RawVolumeReader rawReader(hints); + return rawReader.read(filepath); + } else if(hasExtension(filepath, "cdf")) { + + std::string modelString; + if (hintsDictionary.hasKey("Model") && hintsDictionary.getValue("Model", modelString)) { + KameleonWrapper::Model model; + if (modelString == "BATSRUS") { + model = KameleonWrapper::Model::BATSRUS; + } else if (modelString == "ENLIL") { + model = KameleonWrapper::Model::ENLIL; + } else { + LWARNING("Hints does not specify a valid 'Model'"); + return nullptr; + } + + std::string variableString; + if (hintsDictionary.hasKey("Variable") && hintsDictionary.getValue("Variable", variableString)) { + glm::size3_t dimensions(1,1,1); + double tempValue; + if (hintsDictionary.hasKey("Dimensions.1") && hintsDictionary.getValue("Dimensions.1", tempValue)) { + int intVal = static_cast(tempValue); + if(intVal > 0) + dimensions[0] = intVal; + } + if (hintsDictionary.hasKey("Dimensions.2") && hintsDictionary.getValue("Dimensions.2", tempValue)) { + int intVal = static_cast(tempValue); + if(intVal > 0) + dimensions[1] = intVal; + } + if (hintsDictionary.hasKey("Dimensions.3") && hintsDictionary.getValue("Dimensions.3", tempValue)) { + int intVal = static_cast(tempValue); + if(intVal > 0) + dimensions[2] = intVal; + } + + KameleonWrapper kw(filepath, model); + float* data = kw.getUniformSampledValues(variableString, dimensions); + return new ghoul::opengl::Texture(data, dimensions, ghoul::opengl::Texture::Format::Red, GL_RED, GL_FLOAT); + } else { + LWARNING("Hints does not specify a 'Variable'"); + } + + + } + LWARNING("Hints does not specify a 'Model'"); + } else { + LWARNING("No valid file extension."); + } + return nullptr; +} + ghoul::RawVolumeReader::ReadHints RenderableVolume::readHints(const ghoul::Dictionary& dictionary) { ghoul::RawVolumeReader::ReadHints hints; hints._dimensions = glm::ivec3(1, 1, 1); @@ -165,7 +228,7 @@ ghoul::opengl::Texture* RenderableVolume::loadTransferFunction(const std::string } // check if not a txt based texture - if ( ! hasEnding(filepath, ".txt")) { + if ( ! hasExtension(filepath, "txt")) { return ghoul::opengl::loadTexture(f); } diff --git a/src/rendering/renderablevolumeexpert.cpp b/src/rendering/renderablevolumeexpert.cpp index fa7d1048f6..32e1555d0e 100644 --- a/src/rendering/renderablevolumeexpert.cpp +++ b/src/rendering/renderablevolumeexpert.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include @@ -85,10 +86,9 @@ RenderableVolumeExpert::RenderableVolumeExpert(const ghoul::Dictionary& dictiona ghoul::Dictionary hintsDictionary; if(volume.hasKey("Hints")) volume.getValue("Hints", hintsDictionary); - ghoul::RawVolumeReader::ReadHints hints = readHints(hintsDictionary); _volumePaths.push_back(file); - _volumeHints.push_back(hints); + _volumeHints.push_back(hintsDictionary); } } } @@ -204,13 +204,15 @@ bool RenderableVolumeExpert::initialize() { } for (int i = 0; i < _volumePaths.size(); ++i) { - ghoul::RawVolumeReader rawReader(_volumeHints.at(i)); - ghoul::opengl::Texture* volume = rawReader.read(_volumePaths.at(i)); - volume->uploadTexture(); - cl_mem volumeTexture = _context.createTextureFromGLTexture(CL_MEM_READ_ONLY, *volume); - - _volumes.push_back(volume); - _clVolumes.push_back(volumeTexture); + + ghoul::opengl::Texture* volume = loadVolume(_volumePaths.at(i), _volumeHints.at(i)); + if(volume) { + volume->uploadTexture(); + cl_mem volumeTexture = _context.createTextureFromGLTexture(CL_MEM_READ_ONLY, *volume); + + _volumes.push_back(volume); + _clVolumes.push_back(volumeTexture); + } } // ------ SETUP GEOMETRY ---------------- diff --git a/src/util/kameleonwrapper.cpp b/src/util/kameleonwrapper.cpp new file mode 100644 index 0000000000..c7526be5e3 --- /dev/null +++ b/src/util/kameleonwrapper.cpp @@ -0,0 +1,114 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * 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 + +namespace openspace { + +std::string _loggerCat = "KameleonWrapper"; + +KameleonWrapper::KameleonWrapper(const std::string& filename, Model model) { + switch (model) { + case Model::BATSRUS: + _model = new ccmc::BATSRUS(); + if(!_model) LERROR("BATSRUS:Failed to create model instance"); + if (_model->open(filename) != ccmc::FileReader::OK) + LERROR("BATSRUS:Failed to open "+filename); + _interpolator = _model->createNewInterpolator(); + if (!_interpolator) LERROR("BATSRUS:Failed to create interpolator"); + break; + case Model::ENLIL: + _model = new ccmc::ENLIL(); + if(!_model) LERROR("Failed to create model instance"); + if (_model->open(filename) != ccmc::FileReader::OK) + LERROR("Failed to open "+filename); + _interpolator = _model->createNewInterpolator(); + if (!_interpolator) LERROR("Failed to create interpolator"); + break; + default: + LERROR("Only the BATSRUS model is supported for now. Sorry."); + } +} + +KameleonWrapper::~KameleonWrapper() { + delete _model; + delete _interpolator; +} + +float* KameleonWrapper::getUniformSampledValues(const std::string& var, glm::size3_t outDimensions) { + assert(_model && _interpolator); + assert(outDimensions.x > 0 && outDimensions.y > 0 && outDimensions.z > 0); + LDEBUG("getUniformSampledValues"); + + int size = outDimensions.x*outDimensions.y*outDimensions.z; + float* data = new float[size]; + + // TODO Check which coordinate system the model use. Currently assumes {x,y,z} + float xMin = _model->getVariableAttribute("x", "actual_min").getAttributeFloat(); + float xMax = _model->getVariableAttribute("x", "actual_max").getAttributeFloat(); + float yMin = _model->getVariableAttribute("y", "actual_min").getAttributeFloat(); + float yMax = _model->getVariableAttribute("y", "actual_max").getAttributeFloat(); + float zMin = _model->getVariableAttribute("z", "actual_min").getAttributeFloat(); + float zMax = _model->getVariableAttribute("z", "actual_max").getAttributeFloat(); + float varMin = _model->getVariableAttribute(var, "actual_min").getAttributeFloat(); + float varMax = _model->getVariableAttribute(var, "actual_max").getAttributeFloat(); + + float stepX = (xMax-xMin)/((float)outDimensions.x-1.0); + float stepY = (yMax-yMin)/((float)outDimensions.y-1.0); + float stepZ = (zMax-zMin)/((float)outDimensions.z-1.0); + + // Temporary hack to keep data proportions correct, will give a lot of empty + // voxels in y and z. TODO Add spacing/voxel dimensions + float step = std::max(stepX, stepY); + step = std::max(step, stepZ); + + for (int x = 0; x < outDimensions.x; ++x) { + unsigned int progress = (unsigned int)(((float)x/(float)outDimensions.x)*100.f); + if (progress % 10 == 0) { + std::cout << "Getting data from kameleon: "<< progress << "% \r" << std::flush; + } + for (int y = 0; y < outDimensions.y; ++y) { + for (int z = 0; z < outDimensions.z; ++z) { + + float xPos = xMin + step*x; + float yPos = yMin + step*y; + float zPos = zMin + step*z; + int index = x + y*outDimensions.x + z*outDimensions.x*outDimensions.y; + // get interpolated data value for (xPos, yPos, zPos) and scale to [0,1] + data[index] = (_interpolator->interpolate(var, xPos, yPos, zPos)-varMin)/(varMax-varMin); + } + } + } + + return data; +} + +} // namespace openspace +