From 2911168e5b605a1a43c2f3f1b046f7fa066b04a3 Mon Sep 17 00:00:00 2001 From: Emil Axelsson Date: Wed, 18 May 2016 11:56:06 +0200 Subject: [PATCH] volume conversion tools and really basic data converter app --- apps/DataConverter/CMakeLists.txt | 45 ++++++++ apps/DataConverter/conversiontask.h | 17 +++ apps/DataConverter/main.cpp | 77 ++++++++++++++ apps/DataConverter/milkywayconversiontask.cpp | 50 +++++++++ apps/DataConverter/milkywayconversiontask.h | 41 +++++++ ext/ghoul | 2 +- modules/volume/CMakeLists.txt | 18 +++- modules/volume/linearlrucache.h | 91 ++++++++++++++++ modules/volume/lrucache.h | 91 ++++++++++++++++ modules/volume/rawvolume.h | 54 ++++++++++ modules/volume/rawvolume.inl | 100 ++++++++++++++++++ modules/volume/rawvolumereader.h | 57 ++++++++++ modules/volume/rawvolumereader.inl | 73 +++++++++++++ modules/volume/rawvolumewriter.h | 33 ++++++ modules/volume/rawvolumewriter.inl | 80 ++++++++++++++ modules/volume/textureslicevolumereader.h | 35 ++++++ modules/volume/textureslicevolumereader.inl | 63 +++++++++++ modules/volume/volumemodule.cpp | 2 - modules/volume/volumesampler.h | 20 ++++ modules/volume/volumesampler.inl | 57 ++++++++++ modules/volume/volumeutils.cpp | 31 ++++++ modules/volume/volumeutils.h | 39 +++++++ 22 files changed, 1069 insertions(+), 7 deletions(-) create mode 100644 apps/DataConverter/CMakeLists.txt create mode 100644 apps/DataConverter/conversiontask.h create mode 100644 apps/DataConverter/main.cpp create mode 100644 apps/DataConverter/milkywayconversiontask.cpp create mode 100644 apps/DataConverter/milkywayconversiontask.h create mode 100644 modules/volume/linearlrucache.h create mode 100644 modules/volume/lrucache.h create mode 100644 modules/volume/rawvolume.h create mode 100644 modules/volume/rawvolume.inl create mode 100644 modules/volume/rawvolumereader.h create mode 100644 modules/volume/rawvolumereader.inl create mode 100644 modules/volume/rawvolumewriter.h create mode 100644 modules/volume/rawvolumewriter.inl create mode 100644 modules/volume/textureslicevolumereader.h create mode 100644 modules/volume/textureslicevolumereader.inl create mode 100644 modules/volume/volumesampler.h create mode 100644 modules/volume/volumesampler.inl create mode 100644 modules/volume/volumeutils.cpp create mode 100644 modules/volume/volumeutils.h diff --git a/apps/DataConverter/CMakeLists.txt b/apps/DataConverter/CMakeLists.txt new file mode 100644 index 0000000000..54ebfe6ac3 --- /dev/null +++ b/apps/DataConverter/CMakeLists.txt @@ -0,0 +1,45 @@ +######################################################################################### +# # +# 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. # +######################################################################################### + +set(APPLICATION_NAME DataConverter) +set(APPLICATION_LINK_TO_OPENSPACE ON) + +include (${GHOUL_BASE_DIR}/support/cmake/handle_external_library.cmake) + +set(application_path ${OPENSPACE_APPS_DIR}/DataConverter) + +set(SOURCE_FILES + ${application_path}/main.cpp + ${application_path}/milkywayconversiontask.cpp +) +set(HEADER_FILES + ${application_path}/conversiontask.h + ${application_path}/milkywayconversiontask.h +) + +add_executable(${APPLICATION_NAME} MACOSX_BUNDLE + ${SOURCE_FILES} + ${HEADER_FILES} +) + diff --git a/apps/DataConverter/conversiontask.h b/apps/DataConverter/conversiontask.h new file mode 100644 index 0000000000..4719803e40 --- /dev/null +++ b/apps/DataConverter/conversiontask.h @@ -0,0 +1,17 @@ +#ifndef __CONVERSIONTASK_H__ +#define __CONVERSIONTASK_H__ + +#include + +namespace openspace { +namespace dataconverter { + +class ConversionTask { +public: + virtual void perform(const std::function& onProgress) = 0; +}; + +} +} + +#endif diff --git a/apps/DataConverter/main.cpp b/apps/DataConverter/main.cpp new file mode 100644 index 0000000000..9f4cdb418d --- /dev/null +++ b/apps/DataConverter/main.cpp @@ -0,0 +1,77 @@ +/***************************************************************************************** + * * + * 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 + +int main(int argc, char** argv) { + using namespace openspace; + using namespace dataconverter; + + ghoul::initialize(); + + #ifdef GHOUL_USE_DEVIL + ghoul::io::TextureReader::ref().addReader(std::make_shared()); + #endif // GHOUL_USE_DEVIL + #ifdef GHOUL_USE_FREEIMAGE + ghoul::io::TextureReader::ref().addReader(std::make_shared()); + #endif // GHOUL_USE_FREEIMAGE + + openspace::ProgressBar pb(100); + std::function onProgress = [&](float progress) { + pb.print(progress * 100); + }; + + // TODO: Make the converter configurable using either + // config files (json, lua dictionaries), + // lua scripts, + // or at the very least: a command line interface. + + MilkyWayConversionTask mwConversionTask( + "F:/milky-way/cam2_main.", + ".exr", + 1385, + 512, + "F:/milky-way/mw_512_512_64.rawvolume", + glm::vec3(512, 512, 64)); + + mwConversionTask.perform(onProgress); + + std::cout << "Done." << std::endl; + + std::cin.get(); + return 0; +}; diff --git a/apps/DataConverter/milkywayconversiontask.cpp b/apps/DataConverter/milkywayconversiontask.cpp new file mode 100644 index 0000000000..6537070b8e --- /dev/null +++ b/apps/DataConverter/milkywayconversiontask.cpp @@ -0,0 +1,50 @@ +#include +#include +#include +#include + +namespace openspace { +namespace dataconverter { + +MilkyWayConversionTask::MilkyWayConversionTask( + const std::string& inFilenamePrefix, + const std::string& inFilenameSuffix, + size_t inFirstIndex, + size_t inNSlices, + const std::string& outFilename, + const glm::ivec3& outDimensions) + : _inFilenamePrefix(inFilenamePrefix) + , _inFilenameSuffix(inFilenameSuffix) + , _inFirstIndex(inFirstIndex) + , _inNSlices(inNSlices) + , _outFilename(outFilename) + , _outDimensions(outDimensions) {} + + +void MilkyWayConversionTask::perform(const std::function& onProgress) { + std::vector filenames; + for (int i = 0; i < _inNSlices; i++) { + filenames.push_back(_inFilenamePrefix + std::to_string(i + _inFirstIndex) + _inFilenameSuffix); + } + + TextureSliceVolumeReader> sliceReader(filenames, _inNSlices, 10); + sliceReader.initialize(); + + RawVolumeWriter> rawWriter(_outFilename); + rawWriter.setDimensions(_outDimensions); + + glm::vec3 resolutionRatio = + static_cast(sliceReader.dimensions()) / static_cast(rawWriter.dimensions()); + + VolumeSampler>> sampler(sliceReader, resolutionRatio); + std::function(glm::ivec3)> sampleFunction = [&](glm::ivec3 outCoord) { + glm::vec3 inCoord = ((glm::vec3(outCoord) + glm::vec3(0.5)) * resolutionRatio) - glm::vec3(0.5); + glm::tvec4 value = sampler.sample(inCoord); + return value; + }; + + rawWriter.write(sampleFunction, onProgress); +} + +} +} diff --git a/apps/DataConverter/milkywayconversiontask.h b/apps/DataConverter/milkywayconversiontask.h new file mode 100644 index 0000000000..3927debd90 --- /dev/null +++ b/apps/DataConverter/milkywayconversiontask.h @@ -0,0 +1,41 @@ +#ifndef __MILKYWAYCONVERSIONTASK_H__ +#define __MILKYWAYCONVERSIONTASK_H__ + +#include +#include +#include +#include +#include +#include + + +namespace openspace { +namespace dataconverter { + +/** + * Converts a set of exr image slices to a raw volume + * with floating point RGBA data (32 bit per channel). + */ +class MilkyWayConversionTask : public ConversionTask { +public: + MilkyWayConversionTask(const std::string& inFilenamePrefix, + const std::string& inFilenameSuffix, + size_t inFirstIndex, + size_t inNSlices, + const std::string& outFilename, + const glm::ivec3& outDimensions); + + void perform(const std::function& onProgress) override; +private: + std::string _inFilenamePrefix; + std::string _inFilenameSuffix; + size_t _inFirstIndex; + size_t _inNSlices; + std::string _outFilename; + glm::ivec3 _outDimensions; +}; + +} +} + +#endif diff --git a/ext/ghoul b/ext/ghoul index 6bbf25bc7c..3ef4b9e9e4 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 6bbf25bc7cb8e5ef83a40effa112243fa3f91530 +Subproject commit 3ef4b9e9e40910a2f7860a39d6b6f1f62c9c448f diff --git a/modules/volume/CMakeLists.txt b/modules/volume/CMakeLists.txt index 7ecbad3840..b6538d01b5 100644 --- a/modules/volume/CMakeLists.txt +++ b/modules/volume/CMakeLists.txt @@ -25,14 +25,24 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake) set(HEADER_FILES -# ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablevolume.h -# ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablevolumegl.h + ${CMAKE_CURRENT_SOURCE_DIR}/rawvolume.h + ${CMAKE_CURRENT_SOURCE_DIR}/rawvolumereader.h + ${CMAKE_CURRENT_SOURCE_DIR}/rawvolumewriter.h + ${CMAKE_CURRENT_SOURCE_DIR}/textureslicevolumereader.h + ${CMAKE_CURRENT_SOURCE_DIR}/lrucache.h + ${CMAKE_CURRENT_SOURCE_DIR}/linearlrucache.h + ${CMAKE_CURRENT_SOURCE_DIR}/volumesampler.h + ${CMAKE_CURRENT_SOURCE_DIR}/volumeutils.h ) source_group("Header Files" FILES ${HEADER_FILES}) set(SOURCE_FILES -# ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablevolume.cpp -# ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablevolumegl.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rawvolume.inl + ${CMAKE_CURRENT_SOURCE_DIR}/rawvolumereader.inl + ${CMAKE_CURRENT_SOURCE_DIR}/rawvolumewriter.inl + ${CMAKE_CURRENT_SOURCE_DIR}/textureslicevolumereader.inl + ${CMAKE_CURRENT_SOURCE_DIR}/volumesampler.inl + ${CMAKE_CURRENT_SOURCE_DIR}/volumeutils.cpp ) source_group("Source Files" FILES ${SOURCE_FILES}) diff --git a/modules/volume/linearlrucache.h b/modules/volume/linearlrucache.h new file mode 100644 index 0000000000..437afa99e4 --- /dev/null +++ b/modules/volume/linearlrucache.h @@ -0,0 +1,91 @@ +/***************************************************************************************** + * * + * 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. * + ****************************************************************************************/ + +#ifndef __LRUCACHE_H__ +#define __LRUCACHE_H__ + +#include +#include +#include + +namespace openspace { + +template +class LinearLruCache { +public: + LinearLruCache(size_t capacity, size_t nIndices) + : _tracker() + , _cache(nIndices, std::make_pair(nullptr, _tracker.end())) + , _capacity(capacity) {}; + + bool has(size_t key) { + return _cache[key].first != nullptr; + }; + void set(size_t key, ValueType value) { + auto prev = _cache[key]; + if (prev.first != nullptr) { + prev.first = value; + std::list::iterator trackerIter = prev.second; + _tracker.splice(_tracker.end(), + _tracker, + trackerIter); + } + else { + insert(key, value); + } + }; + ValueType& use(size_t key) { + auto pair = _cache[key]; + std::list::iterator trackerIter = pair.second; + _tracker.splice(_tracker.end(), + _tracker, + trackerIter); + return pair.first; + }; + ValueType& get(size_t key) { + return _cache[key].first; + }; + void evict() { + _cache[_tracker.front()] = make_pair(nullptr, _tracker.end()); + _tracker.pop_front(); + }; + size_t capacity() { + return _capacity; + }; +private: + void insert(size_t key, const ValueType& value) { + if (_tracker.size() == _capacity) { + evict(); + } + auto iter = _tracker.insert(_tracker.end(), key); + _cache[key] = std::make_pair(value, iter); + }; + std::list _tracker; + std::vector::iterator>> _cache; + size_t _capacity; +}; + +} + +#endif diff --git a/modules/volume/lrucache.h b/modules/volume/lrucache.h new file mode 100644 index 0000000000..c8a3fee41e --- /dev/null +++ b/modules/volume/lrucache.h @@ -0,0 +1,91 @@ +/***************************************************************************************** + * * + * 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. * + ****************************************************************************************/ + +#ifndef __LRUCACHE_H__ +#define __LRUCACHE_H__ + +#include +#include +#include + +namespace openspace { + +template class ContainerType> +class LruCache { + typedef KeyType K; +public: + LruCache(size_t capacity) { + _capacity = capacity; + }; + bool has(const KeyType& key) { + return (_cache.find(key) != _cache.end()); + }; + void set(const KeyType& key, ValueType value) { + auto prev = _cache.find(key); + if (prev != _cache.end()) { + prev->second.first = value; + std::list::iterator trackerIter = prev->second.second; + _tracker.splice(_tracker.end(), + _tracker, + trackerIter); + } + else { + insert(key, value); + } + }; + ValueType& use(const KeyType& key) { + auto iter = _cache.find(key); + std::list::iterator trackerIter = iter->second.second; + _tracker.splice(_tracker.end(), + _tracker, + trackerIter); + return iter->second.first; + }; + ValueType& get(const KeyType& key) { + auto iter = _cache.find(key); + return iter->second.first; + }; + void evict() { + _cache.erase(_cache.find(_tracker.front())); + _tracker.pop_front(); + }; + size_t capacity() { + return _capacity; + }; +private: + void insert(const KeyType& key, const ValueType& value) { + if (_cache.size() == _capacity) { + evict(); + } + auto iter = _tracker.insert(_tracker.end(), key); + _cache[key] = std::make_pair(value, iter); + }; + ContainerType::iterator>> _cache; + std::list _tracker; + size_t _capacity; +}; + +} + +#endif diff --git a/modules/volume/rawvolume.h b/modules/volume/rawvolume.h new file mode 100644 index 0000000000..df5e3b9037 --- /dev/null +++ b/modules/volume/rawvolume.h @@ -0,0 +1,54 @@ +/***************************************************************************************** + * * + * 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. * + ****************************************************************************************/ + +#ifndef __RAWVOLUME_H__ +#define __RAWVOLUME_H__ + +namespace openspace { + +template +class RawVolume { +public: + typedef Voxel VoxelType; + RawVolume(const glm::ivec3& dimensions); + glm::ivec3 dimensions() const; + void setDimensions(const glm::ivec3& dimensions); + VoxelType get(const glm::ivec3& coordinates) const; + VoxelType get(const size_t index) const; + void set(const glm::ivec3& coordinates, const VoxelType& value); + void set(size_t index, const VoxelType& value); + void forEachVoxel(const std::function& fn); + VoxelType* data(); +private: + size_t coordsToIndex(const glm::ivec3& cartesian) const; + glm::ivec3 indexToCoords(size_t linear) const; + glm::ivec3 _dimensions; + std::vector _data; +}; + +} + +#include "rawvolume.inl" + +#endif // __RAWVOLUME_H__ diff --git a/modules/volume/rawvolume.inl b/modules/volume/rawvolume.inl new file mode 100644 index 0000000000..5f8edbc50a --- /dev/null +++ b/modules/volume/rawvolume.inl @@ -0,0 +1,100 @@ +/***************************************************************************************** + * * + * 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 + +namespace openspace { + +template +RawVolume::RawVolume(const glm::ivec3& dimensions) + : _dimensions(dimensions) + , _data(static_cast(dimensions.x) * + static_cast(dimensions.y) * + static_cast(dimensions.z)) {} + +template +glm::ivec3 RawVolume::dimensions() const { + return _dimensions; +} + +template +void RawVolume::setDimensions(const glm::ivec3& dimensions) { + _dimensions = dimensions; + _data.resize(static_cast(dimensions.x) * + static_cast(dimensions.y) * + static_cast(dimensions.z)); +} + +template +VoxelType RawVolume::get(const glm::ivec3& coordinates) const { + return get(coordsToIndex(coordinates, dimensions())); +} + +template +VoxelType RawVolume::get(size_t index) const { + return _data[index]; +} + +template +void RawVolume::set(const glm::ivec3& coordinates, const VoxelType& value) { + return set(coordsToIndex(coordinates, dimensions()), value); +} + +template +void RawVolume::set(size_t index, const VoxelType& value) { + _data[index] = value; +} + +template +void RawVolume::forEachVoxel( + const std::function& fn) +{ + + glm::ivec3 dims = dimensions(); + size_t nVals = static_cast(dims.x) * + static_cast(dims.y) * + static_cast(dims.z); + + for (size_t i = 0; i < nVals; i++) { + glm::ivec3 coords = indexToCoords(i); + fn(coords, _data[i]); + } +} + +template +size_t RawVolume::coordsToIndex(const glm::ivec3& cartesian) const { + return volumeutils::coordsToIndex(cartesian, dimensions()); +} + +template +glm::ivec3 RawVolume::indexToCoords(size_t linear) const { + return volumeutils::indexToCoords(linear, dimensions()); +} + +template +VoxelType* RawVolume::data() { + return _data.data(); +} + +} diff --git a/modules/volume/rawvolumereader.h b/modules/volume/rawvolumereader.h new file mode 100644 index 0000000000..a92b09a43a --- /dev/null +++ b/modules/volume/rawvolumereader.h @@ -0,0 +1,57 @@ +/***************************************************************************************** + * * + * 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. * + ****************************************************************************************/ + +#ifndef __RAWVOLUMEREADER_H__ +#define __RAWVOLUMEREADER_H__ + +#include +#include +#include + +namespace openspace { + +template +class RawVolumeReader { +public: + typedef Voxel VoxelType; + RawVolumeReader(const std::string& path, const glm::ivec3& dimensions); + glm::ivec3 dimensions() const; + std::string path() const; + void setPath(const std::string& path); + void setDimensions(const glm::ivec3& dimensions); + //VoxelType get(const glm::ivec3& coordinates) const; // TODO: Implement this + //VoxelType get(const size_t index) const; // TODO: Implement this + std::unique_ptr> read(); +private: + size_t coordsToIndex(const glm::ivec3& cartesian) const; + glm::ivec3 indexToCoords(size_t linear) const; + glm::ivec3 _dimensions; + std::string _path; +}; + +} + +#include "rawvolumereader.inl" + +#endif // __RAWVOLUMEREADER_H__ diff --git a/modules/volume/rawvolumereader.inl b/modules/volume/rawvolumereader.inl new file mode 100644 index 0000000000..fe16c09789 --- /dev/null +++ b/modules/volume/rawvolumereader.inl @@ -0,0 +1,73 @@ +#include + +namespace openspace { + +template +RawVolumeReader::RawVolumeReader(const std::string& path, + const glm::ivec3& dimensions) + : _path(path) + , _dimensions(dimensions) {} + +template +glm::ivec3 RawVolumeReader::dimensions() const { + return _dimensions; +} + +template +void RawVolumeReader::setDimensions(const glm::ivec3& dimensions) { + _dimensions = dimensions; +} + +template +std::string RawVolumeReader::path() const { + return _path; +} + +template +void RawVolumeReader::setPath(const std::string& path) { + _path = path; +} + + +/* +TODO: Implement these methods for random access in raw volume file +template +VoxelType RawVolumeReader::get(const glm::ivec3& coordinates) const { + return get(coordsToIndex(coordinates, dimensions())); +} + +template +VoxelType RawVolumeReader::get(size_t index) const { + // TODO: read from specific position. + return VoxelType(); +}*/ + +template +size_t RawVolumeReader::coordsToIndex(const glm::ivec3& cartesian) const { + return volumeutils::coordsToIndex(cartesian, dimensions()); +} + +template +glm::ivec3 RawVolumeReader::indexToCoords(size_t linear) const { + return volumeutils::indexToCoords(linear, dimensions()); +} + + +template +std::unique_ptr> RawVolumeReader::read() { + glm::ivec3 dims = dimensions(); + std::unique_ptr> volume = + std::make_unique>(dims); + + std::ifstream file(_path, std::ios::binary); + char *buffer = reinterpret_cast(volume->data()); + size_t length = static_cast(dims.x) * + static_cast(dims.y) * + static_cast(dims.z) * + sizeof(VoxelType); + + file.read(buffer, length); + return volume; +} + +} diff --git a/modules/volume/rawvolumewriter.h b/modules/volume/rawvolumewriter.h new file mode 100644 index 0000000000..07735fb3d6 --- /dev/null +++ b/modules/volume/rawvolumewriter.h @@ -0,0 +1,33 @@ +#ifndef __RAWVOLUMEWRITER_H__ +#define __RAWVOLUMEWRITER_H__ + +#include +#include +#include + +namespace openspace { + +template +class RawVolumeWriter { +public: + RawVolumeWriter(std::string path, size_t bufferSize = 1024); + void setPath(const std::string& path); + glm::ivec3 dimensions() const; + void setDimensions(const glm::ivec3& dimensions); + void write(const std::function& fn, + const std::function& onProgress = [&](float t) {}); + void write(const RawVolume& volume); + + size_t coordsToIndex(const glm::ivec3& coords) const; + glm::ivec3 indexToCoords(size_t linear) const; +private: + glm::ivec3 _dimensions; + std::string _path; + size_t _bufferSize; +}; + +} + +#include "rawvolumewriter.inl"; + +#endif diff --git a/modules/volume/rawvolumewriter.inl b/modules/volume/rawvolumewriter.inl new file mode 100644 index 0000000000..b1274f28a7 --- /dev/null +++ b/modules/volume/rawvolumewriter.inl @@ -0,0 +1,80 @@ +#include +#include + +namespace openspace { + +template + RawVolumeWriter::RawVolumeWriter(std::string path, size_t bufferSize) + : _path(path) + , _bufferSize(bufferSize) {} + +template +size_t RawVolumeWriter::coordsToIndex(const glm::ivec3& cartesian) const { + return volumeutils::coordsToIndex(cartesian, dimensions()); +} + +template +glm::ivec3 RawVolumeWriter::indexToCoords(size_t linear) const { + return volumeutils::indexToCoords(linear, dimensions()); +} + +template + void RawVolumeWriter::setDimensions(const glm::ivec3& dimensions) { + _dimensions = dimensions; +} + +template + glm::ivec3 RawVolumeWriter::dimensions() const { + return _dimensions; +} + + +template +void RawVolumeWriter::write(const std::function& fn, + const std::function& onProgress) +{ + glm::ivec3 dims = dimensions(); + + size_t size = static_cast(dims.x) * + static_cast(dims.y) * + static_cast(dims.z); + + std::vector buffer(_bufferSize); + std::ofstream file(_path, std::ios::binary); + + int nChunks = size / _bufferSize; + if (size % _bufferSize > 0) { + nChunks++; + } + + size_t i = 0; + for (int c = 0; c < nChunks; c++) { + size_t bufferPos = 0; + size_t bufferSize = std::min(_bufferSize, size - i); + for (bufferPos = 0; bufferPos < bufferSize; bufferPos++, i++) { + buffer[bufferPos] = fn(indexToCoords(i)); + } + file.write(reinterpret_cast(buffer.data()), bufferSize * sizeof(VoxelType)); + onProgress(static_cast(c + 1) / nChunks); + } + file.close(); +} + +template +void RawVolumeWriter::write(const RawVolume& volume) { + glm::ivec3 dims = dimensions(); + ghoul_assert(dims == volume.dims()); + + const char* buffer = reinterpret_cast(volume.data()); + size_t length = static_cast(dims.x) * + static_cast(dims.y) * + static_cast(dims.z) * + sizeof(VoxelType); + + std::ofstream file(_path, std::ios::binary); + file.write(buffer, length); + file.close(); +} + + +} diff --git a/modules/volume/textureslicevolumereader.h b/modules/volume/textureslicevolumereader.h new file mode 100644 index 0000000000..106db066ff --- /dev/null +++ b/modules/volume/textureslicevolumereader.h @@ -0,0 +1,35 @@ +#ifndef __TEXTURESLICEVOLUMEREADER_H__ +#define __TEXTURESLICEVOLUMEREADER_H__ + +#include +#include +#include +#include +#include +#include + +namespace openspace { + +template +class TextureSliceVolumeReader { +public: + typedef Voxel VoxelType; + TextureSliceVolumeReader(std::vector paths, size_t sliceCacheMaxItems, size_t sliceCacheSize); + VoxelType get(const glm::ivec3& coordinates) const; + virtual glm::ivec3 dimensions() const; + void setPaths(const std::vector paths); + void setCacheSize(size_t size); + void initialize(); +private: + ghoul::opengl::Texture& getSlice(int sliceIndex) const; + std::vector _paths; + mutable LinearLruCache> _cache; + glm::ivec2 _sliceDimensions; + bool _initialized; +}; + +} + +#include "textureslicevolumereader.inl" + +#endif // __TEXTURESLICEVOLUME_H__ diff --git a/modules/volume/textureslicevolumereader.inl b/modules/volume/textureslicevolumereader.inl new file mode 100644 index 0000000000..c85679923e --- /dev/null +++ b/modules/volume/textureslicevolumereader.inl @@ -0,0 +1,63 @@ +#include + +namespace openspace { + +template +VoxelType TextureSliceVolumeReader::get(const glm::ivec3& coordinates) const { + ghoul::opengl::Texture& slice = getSlice(coordinates.z); + return slice.texel(coordinates.xy()); +} + +template +glm::ivec3 TextureSliceVolumeReader::dimensions() const { + return glm::ivec3(_sliceDimensions, _paths.size()); +} + +template +TextureSliceVolumeReader::TextureSliceVolumeReader(std::vector paths, + size_t sliceCacheNIndices, + size_t sliceCacheCapacity) + : _initialized(false) + , _paths(paths) + , _cache(sliceCacheCapacity, sliceCacheNIndices) {} + +template +void TextureSliceVolumeReader::initialize() { + ghoul_assert(_paths.size() > 0, "No paths to read slices from."); + + std::shared_ptr firstSlice = + ghoul::io::TextureReader::ref().loadTexture(_paths[0]); + + _sliceDimensions = firstSlice->dimensions().xy(); + _initialized = true; + _cache.set(0, firstSlice); +} + +template +void TextureSliceVolumeReader::setPaths(const std::vector paths) { + _paths = paths; +} + +template +void TextureSliceVolumeReader::setCacheSize(size_t sliceCacheSize) { + _cache.resize(sliceCacheSize); +} + +template +ghoul::opengl::Texture& TextureSliceVolumeReader::getSlice(int sliceIndex) const { + ghoul_assert(_initialized, "Volume is not initialized"); + ghoul_assert(sliceIndex >= 0 && sliceIndex < _paths.size(), + "Slice index " + std::to_string(sliceIndex) + "is outside the range."); + + if (!_cache.has(sliceIndex)) { + std::shared_ptr texture = + ghoul::io::TextureReader::ref().loadTexture(_paths[sliceIndex]); + + glm::ivec2 dims = texture->dimensions().xy(); + ghoul_assert(dims == _sliceDimensions, "Slice dimensions do not agree."); + _cache.set(sliceIndex, std::move(texture)); + } + return *_cache.get(sliceIndex).get(); +} + +} diff --git a/modules/volume/volumemodule.cpp b/modules/volume/volumemodule.cpp index 04d446c4a3..42a04bdcde 100644 --- a/modules/volume/volumemodule.cpp +++ b/modules/volume/volumemodule.cpp @@ -40,8 +40,6 @@ VolumeModule::VolumeModule() void VolumeModule::internalInitialize() { auto fRenderable = FactoryManager::ref().factory(); ghoul_assert(fRenderable, "No renderable factory existed"); - - //fRenderable->registerClass("RenderableVolumeGL"); } } // namespace openspace diff --git a/modules/volume/volumesampler.h b/modules/volume/volumesampler.h new file mode 100644 index 0000000000..1f394385c6 --- /dev/null +++ b/modules/volume/volumesampler.h @@ -0,0 +1,20 @@ +#ifndef __VOLUMESAMPLER_H__ +#define __VOLUMESAMPLER_H__ + +namespace openspace { + +template +class VolumeSampler { +public: + VolumeSampler(const VolumeType& volume, const glm::vec3& filterSize); + typename VolumeType::VoxelType sample(const glm::vec3& position) const; +private: + glm::ivec3 _filterSize; + const VolumeType* _volume; +}; + +} + +#include "volumesampler.inl" + +#endif diff --git a/modules/volume/volumesampler.inl b/modules/volume/volumesampler.inl new file mode 100644 index 0000000000..c54e77b14a --- /dev/null +++ b/modules/volume/volumesampler.inl @@ -0,0 +1,57 @@ +namespace openspace { + +template +VolumeSampler::VolumeSampler(const VolumeType& volume, const glm::vec3& filterSize) { + // Only accept filter sizes of size 1, 3, 5, 7... + // Round down to closest odd number. + _filterSize = static_cast((filterSize - glm::vec3(1.0)) * glm::vec3(0.5)) * + glm::ivec3(2) + glm::ivec3(1); + + _volume = &volume; +} + +template +typename VolumeType::VoxelType VolumeSampler::sample(const glm::vec3& position) const { + glm::ivec3 flooredPos = static_cast(glm::floor(position)); + glm::vec3 t = glm::fract(position); + + // t is now in interval [0, 1[ (never 1) + glm::ivec3 minCoords = flooredPos - _filterSize / 2; // min coord to sample from + glm::ivec3 maxCoords = minCoords + _filterSize; // max coords to sample from, including interpolation. + glm::ivec3 clampCeiling = _volume->dimensions() - glm::ivec3(1); + + VolumeType::VoxelType value; + for (int z = minCoords.z; z <= maxCoords.z; z++) { + for (int y = minCoords.y; y <= maxCoords.y; y++) { + for (int x = minCoords.x; x <= maxCoords.x; x++) { + glm::ivec3 sampleCoords = glm::ivec3(x, y, z); + float filterCoefficient = 1.0; + + if (x == minCoords.x) { + filterCoefficient *= (1.0 - t.x); + } else if (x == maxCoords.x) { + filterCoefficient *= t.x; + } + if (y == minCoords.y) { + filterCoefficient *= (1.0 - t.y); + } else if (y == maxCoords.y) { + filterCoefficient *= t.y; + } + if (z == minCoords.z) { + filterCoefficient *= (1.0 - t.z); + } else if (z == maxCoords.z) { + filterCoefficient *= t.z; + } + + glm::ivec3 clampedCoords = glm::clamp(sampleCoords, glm::ivec3(0), clampCeiling); + value += filterCoefficient * _volume->get(clampedCoords); + + } + } + } + + value /= static_cast(_filterSize.x * _filterSize.y * _filterSize.z); + return value; +} + +} diff --git a/modules/volume/volumeutils.cpp b/modules/volume/volumeutils.cpp new file mode 100644 index 0000000000..42eddf10c5 --- /dev/null +++ b/modules/volume/volumeutils.cpp @@ -0,0 +1,31 @@ +#include "volumeutils.h" + +namespace openspace { +namespace volumeutils { + +size_t coordsToIndex(const glm::vec3& coords, const glm::ivec3& dims) { + size_t w = dims.x; + size_t h = dims.y; + size_t d = dims.z; + + size_t x = coords.x; + size_t y = coords.y; + size_t z = coords.z; + + return coords.z * (h * w) + coords.y * w + coords.x; +} + +glm::vec3 indexToCoords(size_t index, const glm::ivec3& dims) { + size_t w = dims.x; + size_t h = dims.y; + size_t d = dims.z; + + size_t x = index % w; + size_t y = (index / w) % h; + size_t z = index / w / h; + + return glm::ivec3(x, y, z); +} + +} +} diff --git a/modules/volume/volumeutils.h b/modules/volume/volumeutils.h new file mode 100644 index 0000000000..bcb16b4d23 --- /dev/null +++ b/modules/volume/volumeutils.h @@ -0,0 +1,39 @@ +/***************************************************************************************** + * * + * 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. * + ****************************************************************************************/ + +#ifndef __VOLUMEUTILS_H__ +#define __VOLUMEUTILS_H__ + +#include + +namespace openspace { +namespace volumeutils { + +size_t coordsToIndex(const glm::vec3& coords, const glm::ivec3& dimensions); +glm::vec3 indexToCoords(size_t index, const glm::ivec3& dimensions); + +} +} + +#endif // __VOLUMEUTILS__