From 966a9b43474cc872aadd989c7b41df90694ee253 Mon Sep 17 00:00:00 2001 From: aniisaaden Date: Thu, 9 Jul 2020 09:03:14 +0200 Subject: [PATCH] Compiling module made --- modules/softwareintegration/CMakeLists.txt | 39 +- .../rendering/gaiaoptions.h | 54 - .../rendering/octreeculler.cpp | 82 - .../rendering/octreeculler.h | 76 - .../rendering/octreemanager.cpp | 1399 --------- .../rendering/octreemanager.h | 387 --- .../rendering/renderablegaiastars.cpp | 2522 ----------------- .../rendering/renderablegaiastars.h | 216 -- .../shaders/gaia_billboard_fs.glsl | 114 - .../shaders/gaia_billboard_ge.glsl | 132 - .../shaders/gaia_billboard_nofbo_fs.glsl | 123 - .../shaders/gaia_point_fs.glsl | 98 - .../shaders/gaia_point_ge.glsl | 76 - .../shaders/gaia_ssbo_vs.glsl | 187 -- .../gaia_tonemapping_billboard_fs.glsl | 53 - .../shaders/gaia_tonemapping_point_fs.glsl | 179 -- .../shaders/gaia_tonemapping_vs.glsl | 34 - .../shaders/gaia_vbo_vs.glsl | 120 - .../softwareintegrationmodule.cpp | 19 +- .../softwareintegrationmodule.h | 1 - .../tasks/constructoctreetask.cpp | 816 ------ .../tasks/constructoctreetask.h | 143 - .../softwareintegration/tasks/readfilejob.cpp | 264 -- .../softwareintegration/tasks/readfilejob.h | 71 - .../tasks/readfitstask.cpp | 392 --- .../softwareintegration/tasks/readfitstask.h | 82 - .../tasks/readspecktask.cpp | 122 - .../softwareintegration/tasks/readspecktask.h | 52 - openspace.cfg | 2 +- 29 files changed, 12 insertions(+), 7843 deletions(-) delete mode 100644 modules/softwareintegration/rendering/gaiaoptions.h delete mode 100644 modules/softwareintegration/rendering/octreeculler.cpp delete mode 100644 modules/softwareintegration/rendering/octreeculler.h delete mode 100644 modules/softwareintegration/rendering/octreemanager.cpp delete mode 100644 modules/softwareintegration/rendering/octreemanager.h delete mode 100644 modules/softwareintegration/rendering/renderablegaiastars.cpp delete mode 100644 modules/softwareintegration/rendering/renderablegaiastars.h delete mode 100644 modules/softwareintegration/shaders/gaia_billboard_fs.glsl delete mode 100644 modules/softwareintegration/shaders/gaia_billboard_ge.glsl delete mode 100644 modules/softwareintegration/shaders/gaia_billboard_nofbo_fs.glsl delete mode 100644 modules/softwareintegration/shaders/gaia_point_fs.glsl delete mode 100644 modules/softwareintegration/shaders/gaia_point_ge.glsl delete mode 100644 modules/softwareintegration/shaders/gaia_ssbo_vs.glsl delete mode 100644 modules/softwareintegration/shaders/gaia_tonemapping_billboard_fs.glsl delete mode 100644 modules/softwareintegration/shaders/gaia_tonemapping_point_fs.glsl delete mode 100644 modules/softwareintegration/shaders/gaia_tonemapping_vs.glsl delete mode 100644 modules/softwareintegration/shaders/gaia_vbo_vs.glsl delete mode 100644 modules/softwareintegration/tasks/constructoctreetask.cpp delete mode 100644 modules/softwareintegration/tasks/constructoctreetask.h delete mode 100644 modules/softwareintegration/tasks/readfilejob.cpp delete mode 100644 modules/softwareintegration/tasks/readfilejob.h delete mode 100644 modules/softwareintegration/tasks/readfitstask.cpp delete mode 100644 modules/softwareintegration/tasks/readfitstask.h delete mode 100644 modules/softwareintegration/tasks/readspecktask.cpp delete mode 100644 modules/softwareintegration/tasks/readspecktask.h diff --git a/modules/softwareintegration/CMakeLists.txt b/modules/softwareintegration/CMakeLists.txt index 782b9ced23..9cc5c6cd0f 100644 --- a/modules/softwareintegration/CMakeLists.txt +++ b/modules/softwareintegration/CMakeLists.txt @@ -25,47 +25,18 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake) set(HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/gaiamodule.h - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablegaiastars.h - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/octreemanager.h - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/octreeculler.h - ${CMAKE_CURRENT_SOURCE_DIR}/tasks/readfilejob.h - ${CMAKE_CURRENT_SOURCE_DIR}/tasks/readfitstask.h - ${CMAKE_CURRENT_SOURCE_DIR}/tasks/readspecktask.h - ${CMAKE_CURRENT_SOURCE_DIR}/tasks/constructoctreetask.h - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gaiaoptions.h + ${CMAKE_CURRENT_SOURCE_DIR}/softwareintegrationmodule.h ) source_group("Header Files" FILES ${HEADER_FILES}) set(SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/gaiamodule.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablegaiastars.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/octreemanager.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/octreeculler.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/tasks/readfilejob.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/tasks/readfitstask.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/tasks/readspecktask.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/tasks/constructoctreetask.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/softwareintegrationmodule.cpp ) source_group("Source Files" FILES ${SOURCE_FILES}) -set(SHADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/gaia_vbo_vs.glsl - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/gaia_ssbo_vs.glsl - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/gaia_billboard_nofbo_fs.glsl - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/gaia_billboard_fs.glsl - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/gaia_billboard_ge.glsl - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/gaia_point_fs.glsl - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/gaia_point_ge.glsl - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/gaia_tonemapping_vs.glsl - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/gaia_tonemapping_point_fs.glsl - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/gaia_tonemapping_billboard_fs.glsl -) -source_group("Shader Files" FILES ${SHADER_FILES}) - create_new_module( - "Gaia" - gaia + "SoftwareIntegration" + softwareintegration STATIC - ${HEADER_FILES} ${SOURCE_FILES} ${SHADER_FILES} + ${HEADER_FILES} ${SOURCE_FILES} ) diff --git a/modules/softwareintegration/rendering/gaiaoptions.h b/modules/softwareintegration/rendering/gaiaoptions.h deleted file mode 100644 index b1740b7cb5..0000000000 --- a/modules/softwareintegration/rendering/gaiaoptions.h +++ /dev/null @@ -1,54 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2020 * - * * - * 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 __OPENSPACE_MODULE_GAIA___GAIAOPTIONS___H__ -#define __OPENSPACE_MODULE_GAIA___GAIAOPTIONS___H__ - -namespace openspace::gaia { - -enum RenderOption { - Static = 0, - Color = 1, - Motion = 2 -}; - -enum FileReaderOption { - Fits = 0, - Speck = 1, - BinaryRaw = 2, - BinaryOctree = 3, - StreamOctree = 4 -}; - -enum ShaderOption { - Point_SSBO = 0, - Point_VBO = 1, - Billboard_SSBO = 2, - Billboard_VBO = 3, - Billboard_SSBO_noFBO = 4 -}; - -} // namespace openspace::gaiamission - -#endif // __OPENSPACE_MODULE_GAIA___GAIAOPTIONS___H__ diff --git a/modules/softwareintegration/rendering/octreeculler.cpp b/modules/softwareintegration/rendering/octreeculler.cpp deleted file mode 100644 index 0ffef8d717..0000000000 --- a/modules/softwareintegration/rendering/octreeculler.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2020 * - * * - * 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 - -namespace openspace { - -namespace { - bool intersects(const globebrowsing::AABB3& bb, const globebrowsing::AABB3& o) { - return (bb.min.x <= o.max.x) && (o.min.x <= bb.max.x) - && (bb.min.y <= o.max.y) && (o.min.y <= bb.max.y) - && (bb.min.z <= o.max.z) && (o.min.z <= bb.max.z); - } - - void expand(globebrowsing::AABB3& bb, const glm::vec3& p) { - bb.min = glm::min(bb.min, p); - bb.max = glm::max(bb.max, p); - } -} // namespace - -OctreeCuller::OctreeCuller(globebrowsing::AABB3 viewFrustum) - : _viewFrustum(std::move(viewFrustum)) -{} - -bool OctreeCuller::isVisible(const std::vector& corners, - const glm::dmat4& mvp) -{ - createNodeBounds(corners, mvp); - return intersects(_viewFrustum, _nodeBounds); -} - -glm::vec2 OctreeCuller::getNodeSizeInPixels(const std::vector& corners, - const glm::dmat4& mvp, - const glm::vec2& screenSize) -{ - - createNodeBounds(corners, mvp); - - // Screen space is mapped to [-1, 1] so divide by 2 and multiply with screen size. - glm::vec3 size = (_nodeBounds.max - _nodeBounds.min) / 2.f; - size = glm::abs(size); - return glm::vec2(size.x * screenSize.x, size.y * screenSize.y); -} - -void OctreeCuller::createNodeBounds(const std::vector& corners, - const glm::dmat4& mvp) -{ - // Create a bounding box in clipping space from node boundaries. - _nodeBounds = globebrowsing::AABB3(); - - for (size_t i = 0; i < 8; ++i) { - glm::dvec4 cornerClippingSpace = mvp * corners[i]; - glm::dvec4 ndc = (1.f / glm::abs(cornerClippingSpace.w)) * cornerClippingSpace; - expand(_nodeBounds, glm::dvec3(ndc)); - } -} - -} // namespace openspace diff --git a/modules/softwareintegration/rendering/octreeculler.h b/modules/softwareintegration/rendering/octreeculler.h deleted file mode 100644 index c8a2e2362f..0000000000 --- a/modules/softwareintegration/rendering/octreeculler.h +++ /dev/null @@ -1,76 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2020 * - * * - * 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 __OPENSPACE_MODULE_GAIA___OCTREECULLER___H__ -#define __OPENSPACE_MODULE_GAIA___OCTREECULLER___H__ - -#include -#include - -// TODO: Move /geometry/* to libOpenSpace so as not to depend on globebrowsing. - -namespace openspace { - -/** - * Culls all octree nodes that are completely outside the view frustum. - * - * The frustum culling uses a 2D axis aligned bounding box for the OctreeNode in - * screen space. - */ - -class OctreeCuller { -public: - - /** - * \param viewFrustum is the view space in normalized device coordinates space. - * Hence it is an axis aligned bounding box and not a real frustum. - */ - OctreeCuller(globebrowsing::AABB3 viewFrustum); - - ~OctreeCuller() = default; - - /** - * \return true if any part of the node is visible in the current view. - */ - bool isVisible(const std::vector& corners, const glm::dmat4& mvp); - - /** - * \return the size [in pixels] of the node in clipping space. - */ - glm::vec2 getNodeSizeInPixels(const std::vector& corners, - const glm::dmat4& mvp, const glm::vec2& screenSize); - -private: - /** - * Creates an axis-aligned bounding box containing all \p corners in clipping space. - */ - void createNodeBounds(const std::vector& corners, const glm::dmat4& mvp); - - const globebrowsing::AABB3 _viewFrustum; - globebrowsing::AABB3 _nodeBounds; -}; - -} // namespace openspace - -#endif // __OPENSPACE_MODULE_GAIA___OCTREECULLER___H__ diff --git a/modules/softwareintegration/rendering/octreemanager.cpp b/modules/softwareintegration/rendering/octreemanager.cpp deleted file mode 100644 index 5b56c62816..0000000000 --- a/modules/softwareintegration/rendering/octreemanager.cpp +++ /dev/null @@ -1,1399 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2020 * - * * - * 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 - -namespace { - constexpr const char* _loggerCat = "OctreeManager"; -} // namespace - -namespace openspace { - -void OctreeManager::initOctree(long long cpuRamBudget, int maxDist, int maxStarsPerNode) { - if (_root) { - LDEBUG("Clear existing Octree"); - clearAllData(); - } - - LDEBUG("Initializing new Octree"); - _root = std::make_shared(); - _root->octreePositionIndex = 8; - - // Initialize the culler. The NDC.z of the comparing corners are always -1 or 1. - globebrowsing::AABB3 box; - box.min = glm::vec3(-1.f, -1.f, 0.f); - box.max = glm::vec3(1.f, 1.f, 100.f); - _culler = std::make_unique(box); - _removedKeysInPrevCall = std::set(); - _leastRecentlyFetchedNodes = std::queue(); - - // Reset default values when rebuilding the Octree during runtime. - _numInnerNodes = 0; - _numLeafNodes = 0; - _totalDepth = 0; - _valuesPerStar = POS_SIZE + COL_SIZE + VEL_SIZE; - _maxCpuRamBudget = cpuRamBudget; - _cpuRamBudget = cpuRamBudget; - _parentNodeOfCamera = 8; - - if (maxDist > 0) { - MAX_DIST = static_cast(maxDist); - } - if (maxStarsPerNode > 0) { - MAX_STARS_PER_NODE = static_cast(maxStarsPerNode); - } - - for (size_t i = 0; i < 8; ++i) { - _numLeafNodes++; - _root->Children[i] = std::make_shared(); - _root->Children[i]->posData = std::vector(); - _root->Children[i]->colData = std::vector(); - _root->Children[i]->velData = std::vector(); - _root->Children[i]->magOrder = std::vector>(); - _root->Children[i]->isLeaf = true; - _root->Children[i]->isLoaded = false; - _root->Children[i]->hasLoadedDescendant = false; - _root->Children[i]->bufferIndex = DEFAULT_INDEX; - _root->Children[i]->octreePositionIndex = 80 + i; - _root->Children[i]->numStars = 0; - _root->Children[i]->halfDimension = MAX_DIST / 2.f; - _root->Children[i]->originX = (i % 2 == 0) ? - _root->Children[i]->halfDimension : - -_root->Children[i]->halfDimension; - _root->Children[i]->originY = (i % 4 < 2) ? - _root->Children[i]->halfDimension : - -_root->Children[i]->halfDimension; - _root->Children[i]->originZ = (i < 4) ? - _root->Children[i]->halfDimension : - -_root->Children[i]->halfDimension; - } -} - -void OctreeManager::initBufferIndexStack(long long maxNodes, bool useVBO, - bool datasetFitInMemory) -{ - // Clear stack if we've used it before. - _biggestChunkIndexInUse = 0; - _freeSpotsInBuffer = std::stack(); - _rebuildBuffer = true; - _useVBO = useVBO; - _datasetFitInMemory = datasetFitInMemory; - - // Build stack back-to-front. - for (long long idx = maxNodes - 1; idx >= 0; --idx) { - _freeSpotsInBuffer.push(static_cast(idx)); - } - _maxStackSize = _freeSpotsInBuffer.size(); - LINFO("StackSize: " + std::to_string(maxNodes)); -} - -void OctreeManager::insert(const std::vector& starValues) { - size_t index = getChildIndex(starValues[0], starValues[1], starValues[2]); - - insertInNode(*_root->Children[index], starValues); -} - -void OctreeManager::sliceLodData(size_t branchIndex) { - if (branchIndex != 8) { - sliceNodeLodCache(*_root->Children[branchIndex]); - } - else { - for (int i = 0; i < 7; ++i) { - sliceNodeLodCache(*_root->Children[i]); - } - } -} - -void OctreeManager::printStarsPerNode() const { - auto accumulatedString = std::string(); - - for (int i = 0; i < 8; ++i) { - std::string prefix = "{" + std::to_string(i); - accumulatedString += printStarsPerNode(*_root->Children[i], prefix); - } - LINFO(fmt::format("Number of stars per node: \n{}", accumulatedString)); - LINFO(fmt::format("Number of leaf nodes: {}", std::to_string(_numLeafNodes))); - LINFO(fmt::format("Number of inner nodes: {}", std::to_string(_numInnerNodes))); - LINFO(fmt::format("Depth of tree: {}", std::to_string(_totalDepth))); -} - -void OctreeManager::fetchSurroundingNodes(const glm::dvec3& cameraPos, - size_t chunkSizeInBytes, - const glm::ivec2& additionalNodes) -{ - - // If entire dataset fits in RAM then load the entire dataset asynchronously now. - // Nodes will be rendered when they've been made available. - if (_datasetFitInMemory) { - // Only traverse Octree once! - if (_parentNodeOfCamera == 8) { - // Fetch first layer of children - fetchChildrenNodes(*_root, 0); - - for (int i = 0; i < 8; ++i) { - // Check so branch doesn't have a single layer. - if (_root->Children[i]->isLeaf) { - continue; - } - - // Use multithreading to load files and detach thread from main execution - // so it can execute independently. Thread will be destroyed when - // finished! - std::thread([this, n = _root->Children[i]]() { - fetchChildrenNodes(*n, -1); - }).detach(); - } - _parentNodeOfCamera = 0; - } - return; - } - - // Get leaf node in which the camera resides. - glm::vec3 fCameraPos = static_cast( - cameraPos / (1000.0 * distanceconstants::Parsec) - ); - size_t idx = getChildIndex(fCameraPos.x, fCameraPos.y, fCameraPos.z); - std::shared_ptr node = _root->Children[idx]; - - while (!node->isLeaf) { - idx = getChildIndex( - fCameraPos.x, - fCameraPos.y, - fCameraPos.z, - node->originX, - node->originY, - node->originZ - ); - node = node->Children[idx]; - } - unsigned long long leafId = node->octreePositionIndex; - unsigned long long firstParentId = leafId / 10; - - // Return early if camera resides in the same first parent as before! - // Otherwise camera has moved and may need to load more nodes! - if (_parentNodeOfCamera == firstParentId) { - return; - } - _parentNodeOfCamera = firstParentId; - - // Each parent level may be root, make sure to propagate it in that case! - unsigned long long secondParentId = (firstParentId == 8) ? 8 : leafId / 100; - unsigned long long thirdParentId = (secondParentId == 8) ? 8 : leafId / 1000; - unsigned long long fourthParentId = (thirdParentId == 8) ? 8 : leafId / 10000; - unsigned long long fifthParentId = (fourthParentId == 8) ? 8 : leafId / 100000; - - // Get the number of levels to fetch from user input. - int additionalLevelsToFetch = additionalNodes.y; - - // Get more descendants when closer to root. - if (_parentNodeOfCamera < 80000) { - additionalLevelsToFetch++; - } - - // Get the 3^3 closest parents and load all their (eventual) children. - for (int x = -1; x <= 1; x += 1) { - for (int y = -2; y <= 2; y += 2) { - for (int z = -4; z <= 4; z += 4) { - // Fetch all stars the 216 closest leaf nodes. - findAndFetchNeighborNode( - firstParentId, - x, - y, - z, - additionalLevelsToFetch - ); - // Fetch LOD stars from 208 parents one and two layer(s) up. - if (x != 0 || y != 0 || z != 0) { - if (additionalNodes.x > 0) { - findAndFetchNeighborNode( - secondParentId, - x, - y, - z, - additionalLevelsToFetch - ); - } - if (additionalNodes.x > 1) { - findAndFetchNeighborNode( - thirdParentId, - x, - y, - z, - additionalLevelsToFetch - ); - } - if (additionalNodes.x > 2) { - findAndFetchNeighborNode( - fourthParentId, - x, - y, - z, - additionalLevelsToFetch - ); - } - if (additionalNodes.x > 3) { - findAndFetchNeighborNode( - fifthParentId, - x, - y, - z, - additionalLevelsToFetch - ); - } - } - } - } - } - - // Check if we should remove any nodes from RAM. - long long tenthOfRamBudget = _maxCpuRamBudget / 10; - if (_cpuRamBudget < tenthOfRamBudget) { - long long bytesToTenthOfRam = tenthOfRamBudget - _cpuRamBudget; - size_t nNodesToRemove = static_cast(bytesToTenthOfRam / chunkSizeInBytes); - std::vector nodesToRemove; - while (nNodesToRemove > 0) { - // Dequeue nodes that were least recently fetched by findAndFetchNeighborNode. - nodesToRemove.push_back(_leastRecentlyFetchedNodes.front()); - _leastRecentlyFetchedNodes.pop(); - nNodesToRemove--; - } - // Use asynchronous removal. - if (!nodesToRemove.empty()) { - std::thread(&OctreeManager::removeNodesFromRam, this, nodesToRemove).detach(); - } - } -} - -void OctreeManager::findAndFetchNeighborNode(unsigned long long firstParentId, int x, - int y, int z, int additionalLevelsToFetch) -{ - unsigned long long parentId = firstParentId; - auto indexStack = std::stack(); - - // Fetch first layer children if we're already at root. - if (parentId == 8) { - fetchChildrenNodes(*_root, 0); - return; - } - - //----------------- Change first index -------------------// - int nodeIndex = parentId % 10; - - int dx = (nodeIndex % 2 == 0) ? 1 : -1; - int dy = (nodeIndex % 4 < 2) ? 2 : -2; - int dz = (nodeIndex < 4) ? 4 : -4; - - // Determine if we need to switch any side (find a higher common parent). - bool needToSwitchX = (x == dx); - bool needToSwitchY = (y == dy); - bool needToSwitchZ = (z == dz); - - if (!needToSwitchX) { - x = -x; - } - if (!needToSwitchY) { - y = -y; - } - if (!needToSwitchZ) { - z = -z; - } - - // Update node index and store it at the back of our stack. - nodeIndex += x + y + z; - indexStack.push(nodeIndex); - parentId /= 10; - - //--------- Change all indices until we find a common parent --------------// - while (parentId != 8 && (needToSwitchX || needToSwitchY || needToSwitchZ) ) { - nodeIndex = parentId % 10; - - dx = (nodeIndex % 2 == 0) ? 1 : -1; - dy = (nodeIndex % 4 < 2) ? 2 : -2; - dz = (nodeIndex < 4) ? 4 : -4; - - if (needToSwitchX) { - if (x != dx) { - needToSwitchX = false; - } - nodeIndex += dx; - } - if (needToSwitchY) { - if (y != dy) { - needToSwitchY = false; - } - nodeIndex += dy; - } - if (needToSwitchZ) { - if (z != dz) { - needToSwitchZ = false; - } - nodeIndex += dz; - } - - indexStack.push(nodeIndex); - parentId /= 10; - } - - // Take care of edge cases. If we got to the root but still need to switch to a - // common parent then no neighbor exists in that direction. - if (needToSwitchX || needToSwitchY || needToSwitchZ) { - return; - } - - // Continue to root if we didn't reach it. - while (parentId != 8) { - nodeIndex = parentId % 10; - indexStack.push(nodeIndex); - parentId /= 10; - } - - // Traverse to that parent node (as long as such a child exists!). - std::shared_ptr node = _root; - while (!indexStack.empty() && !node->Children[indexStack.top()]->isLeaf) { - node = node->Children[indexStack.top()]; - node->hasLoadedDescendant = true; - indexStack.pop(); - } - - // Fetch all children nodes from found parent. Use multithreading to load files - // asynchronously! Detach thread from main execution so it can execute independently. - // Thread will then be destroyed when it has finished! - std::thread([this, node, additionalLevelsToFetch]() { - fetchChildrenNodes(*node, additionalLevelsToFetch); - }).detach(); -} - -std::map> OctreeManager::traverseData(const glm::dmat4& mvp, - const glm::vec2& screenSize, - int& deltaStars, - gaia::RenderOption option, - float lodPixelThreshold) -{ - auto renderData = std::map>(); - bool innerRebuild = false; - _minTotalPixelsLod = lodPixelThreshold; - - // Reclaim indices from previous render call. - for (auto removedKey = _removedKeysInPrevCall.rbegin(); - removedKey != _removedKeysInPrevCall.rend(); ++removedKey) { - - // Uses a reverse loop to try to decrease the biggest chunk. - if (*removedKey == _biggestChunkIndexInUse - 1) { - _biggestChunkIndexInUse = *removedKey; - LDEBUG(fmt::format( - "Decreased size to: {} Free Spots in VBO: {}", - _biggestChunkIndexInUse, _freeSpotsInBuffer.size() - )); - } - _freeSpotsInBuffer.push(*removedKey); - } - // Clear cache of removed keys before next render call. - if (!_removedKeysInPrevCall.empty()) { - _removedKeysInPrevCall.clear(); - } - - // Rebuild VBO from scratch if we're not using most of it but have a high max index. - if ((_biggestChunkIndexInUse > _maxStackSize * 4 / 5) && - (_freeSpotsInBuffer.size() > _maxStackSize * 5 / 6)) - { - LDEBUG(fmt::format( - "Rebuilding VBO. Biggest Chunk: {} 4/5: {} FreeSpotsInVBO: {} 5/6: {}", - _biggestChunkIndexInUse, _maxStackSize * 4 / 5, _freeSpotsInBuffer.size(), - _maxStackSize * 5 / 6 - )); - initBufferIndexStack(_maxStackSize, _useVBO, _datasetFitInMemory); - innerRebuild = true; - } - - // Check if entire tree is too small to see, and if so remove it. - std::vector corners(8); - float fMaxDist = static_cast(MAX_DIST); - for (int i = 0; i < 8; ++i) { - float x = (i % 2 == 0) ? fMaxDist : -fMaxDist; - float y = (i % 4 < 2) ? fMaxDist : -fMaxDist; - float z = (i < 4) ? fMaxDist : -fMaxDist; - glm::dvec3 pos = glm::dvec3(x, y, z) * 1000.0 * distanceconstants::Parsec; - corners[i] = glm::dvec4(pos, 1.0); - } - if (!_culler->isVisible(corners, mvp)) { - return renderData; - } - glm::vec2 nodeSize = _culler->getNodeSizeInPixels(corners, mvp, screenSize); - float totalPixels = nodeSize.x * nodeSize.y; - if (totalPixels < _minTotalPixelsLod * 2) { - // Remove LOD from first layer of children. - for (int i = 0; i < 8; ++i) { - std::map> tmpData = removeNodeFromCache( - *_root->Children[i], - deltaStars - ); - renderData.insert(tmpData.begin(), tmpData.end()); - } - return renderData; - } - - for (size_t i = 0; i < 8; ++i) { - if (i < _traversedBranchesInRenderCall) { - continue; - } - - std::map> tmpData = checkNodeIntersection( - *_root->Children[i], - mvp, - screenSize, - deltaStars, - option - ); - - // Avoid freezing when switching render mode for large datasets by only fetching - // one branch at a time when rebuilding buffer. - if (_rebuildBuffer) { - //renderData = std::move(tmpData); - _traversedBranchesInRenderCall++; - //break; - } - - // Observe that if there exists identical keys in renderData then those values in - // tmpData will be ignored! Thus we store the removed keys until next render call! - renderData.insert(tmpData.begin(), tmpData.end()); - } - - if (_rebuildBuffer) { - if (_useVBO) { - // We need to overwrite bigger indices that had data before! No need for SSBO. - std::map> idxToRemove; - for (int idx : _removedKeysInPrevCall) { - idxToRemove[idx] = std::vector(); - } - - // This will only insert indices that doesn't already exist in map - // (i.e. > biggestIdx). - renderData.insert(idxToRemove.begin(), idxToRemove.end()); - } - if (innerRebuild) { - deltaStars = 0; - } - - // Clear potential removed keys for both VBO and SSBO! - _removedKeysInPrevCall.clear(); - - LDEBUG(fmt::format( - "After rebuilding branch {} - Biggest chunk: {} Free spots in buffer: {}", - _traversedBranchesInRenderCall, _biggestChunkIndexInUse, - _freeSpotsInBuffer.size() - )); - - // End rebuild when all branches has been fetched. - if (_traversedBranchesInRenderCall == 8) { - _rebuildBuffer = false; - _traversedBranchesInRenderCall = 0; - } - } - return renderData; -} - -std::vector OctreeManager::getAllData(gaia::RenderOption option) { - std::vector fullData; - - for (size_t i = 0; i < 8; ++i) { - std::vector tmpData = getNodeData(*_root->Children[i], option); - fullData.insert(fullData.end(), tmpData.begin(), tmpData.end()); - } - return fullData; -} - -void OctreeManager::clearAllData(int branchIndex) { - // Don't clear everything if not needed. - if (branchIndex != -1) { - clearNodeData(*_root->Children[branchIndex]); - } - else { - for (size_t i = 0; i < 8; ++i) { - clearNodeData(*_root->Children[i]); - } - } -} - -void OctreeManager::writeToFile(std::ofstream& outFileStream, bool writeData) { - outFileStream.write(reinterpret_cast(&_valuesPerStar), sizeof(int32_t)); - outFileStream.write( - reinterpret_cast(&MAX_STARS_PER_NODE), - sizeof(int32_t) - ); - outFileStream.write(reinterpret_cast(&MAX_DIST), sizeof(int32_t)); - - // Use pre-traversal (Morton code / Z-order). - for (size_t i = 0; i < 8; ++i) { - writeNodeToFile(outFileStream, *_root->Children[i], writeData); - } -} - -void OctreeManager::writeNodeToFile(std::ofstream& outFileStream, const OctreeNode& node, - bool writeData) -{ - // Write node structure. - bool isLeaf = node.isLeaf; - int32_t numStars = static_cast(node.numStars); - outFileStream.write(reinterpret_cast(&isLeaf), sizeof(bool)); - outFileStream.write(reinterpret_cast(&numStars), sizeof(int32_t)); - - // Write node data if specified - if (writeData) { - std::vector nodeData = node.posData; - nodeData.insert(nodeData.end(), node.colData.begin(), node.colData.end()); - nodeData.insert(nodeData.end(), node.velData.begin(), node.velData.end()); - int32_t nDataSize = static_cast(nodeData.size()); - size_t nBytes = nDataSize * sizeof(nodeData[0]); - - outFileStream.write(reinterpret_cast(&nDataSize), sizeof(int32_t)); - if (nDataSize > 0) { - outFileStream.write(reinterpret_cast(nodeData.data()), nBytes); - } - } - - // Write children to file (in Morton order) if we're in an inner node. - if (!node.isLeaf) { - for (size_t i = 0; i < 8; ++i) { - writeNodeToFile(outFileStream, *node.Children[i], writeData); - } - } -} - -int OctreeManager::readFromFile(std::ifstream& inFileStream, bool readData, - const std::string& folderPath) -{ - int nStarsRead = 0; - int oldMaxdist = static_cast(MAX_DIST); - - // If we're not reading data then we need to stream from files later on. - _streamOctree = !readData; - if (_streamOctree) { - _streamFolderPath = folderPath; - } - - _valuesPerStar = 0; - inFileStream.read(reinterpret_cast(&_valuesPerStar), sizeof(int32_t)); - inFileStream.read(reinterpret_cast(&MAX_STARS_PER_NODE), sizeof(int32_t)); - inFileStream.read(reinterpret_cast(&MAX_DIST), sizeof(int32_t)); - - LDEBUG(fmt::format( - "Max stars per node in read Octree: {} - Radius of root layer: {}", - MAX_STARS_PER_NODE, MAX_DIST - )); - - // Octree Manager root halfDistance must be updated before any nodes are created! - if (MAX_DIST != oldMaxdist) { - for (size_t i = 0; i < 8; ++i) { - _root->Children[i]->halfDimension = MAX_DIST / 2.f; - _root->Children[i]->originX = (i % 2 == 0) ? - _root->Children[i]->halfDimension : - -_root->Children[i]->halfDimension; - _root->Children[i]->originY = (i % 4 < 2) ? - _root->Children[i]->halfDimension : - -_root->Children[i]->halfDimension; - _root->Children[i]->originZ = (i < 4) ? - _root->Children[i]->halfDimension : - -_root->Children[i]->halfDimension; - } - } - - if (_valuesPerStar != (POS_SIZE + COL_SIZE + VEL_SIZE)) { - LERROR("Read file doesn't have the same structure of render parameters!"); - } - - // Use the same technique to construct octree from file. - for (size_t i = 0; i < 8; ++i) { - nStarsRead += readNodeFromFile(inFileStream, *_root->Children[i], readData); - } - return nStarsRead; -} - -int OctreeManager::readNodeFromFile(std::ifstream& inFileStream, OctreeNode& node, - bool readData) -{ - // Read node structure. - bool isLeaf; - int32_t numStars = 0; - - inFileStream.read(reinterpret_cast(&isLeaf), sizeof(bool)); - inFileStream.read(reinterpret_cast(&numStars), sizeof(int32_t)); - - node.isLeaf = isLeaf; - node.numStars = numStars; - - // Read node data if specified. - if (readData) { - int32_t nDataSize = 0; - inFileStream.read(reinterpret_cast(&nDataSize), sizeof(int32_t)); - - if (nDataSize > 0) { - std::vector fetchedData(nDataSize, 0.0f); - size_t nBytes = nDataSize * sizeof(fetchedData[0]); - - inFileStream.read(reinterpret_cast(&fetchedData[0]), nBytes); - - int starsInNode = static_cast(nDataSize / _valuesPerStar); - auto posEnd = fetchedData.begin() + (starsInNode * POS_SIZE); - auto colEnd = posEnd + (starsInNode * COL_SIZE); - auto velEnd = colEnd + (starsInNode * VEL_SIZE); - node.posData = std::vector(fetchedData.begin(), posEnd); - node.colData = std::vector(posEnd, colEnd); - node.velData = std::vector(colEnd, velEnd); - } - } - - // Create children if we're in an inner node and read from the corresponding nodes. - if (!node.isLeaf) { - numStars = 0; - createNodeChildren(node); - for (size_t i = 0; i < 8; ++i) { - numStars += readNodeFromFile(inFileStream, *node.Children[i], readData); - } - } - - // Return the number of stars in the entire branch, no need to check children. - return numStars; -} - -void OctreeManager::writeToMultipleFiles(const std::string& outFolderPath, - size_t branchIndex) -{ - // Write entire branch to disc, with one file per node. - std::string outFilePrefix = outFolderPath + std::to_string(branchIndex); - // More threads doesn't make it much faster, disk speed still the limiter. - writeNodeToMultipleFiles(outFilePrefix, *_root->Children[branchIndex], false); - - // Clear all data in branch. - LINFO(fmt::format("Clear all data from branch {} in octree", branchIndex)); - clearNodeData(*_root->Children[branchIndex]); -} - -void OctreeManager::writeNodeToMultipleFiles(const std::string& outFilePrefix, - OctreeNode& node, bool threadWrites) -{ - // Prepare node data, save nothing else. - std::vector nodeData = node.posData; - nodeData.insert(nodeData.end(), node.colData.begin(), node.colData.end()); - nodeData.insert(nodeData.end(), node.velData.begin(), node.velData.end()); - int32_t nDataSize = static_cast(nodeData.size()); - size_t nBytes = nDataSize * sizeof(nodeData[0]); - - // Only open output stream if we have any values to write. - if (nDataSize > 0) { - // Use Morton code to name file (placement in Octree). - std::string outPath = outFilePrefix + BINARY_SUFFIX; - std::ofstream outFileStream(outPath, std::ofstream::binary); - if (outFileStream.good()) { - // LINFO("Write " + std::to_string(nDataSize) + " values to " + outPath); - outFileStream.write( - reinterpret_cast(&nDataSize), - sizeof(int32_t) - ); - outFileStream.write(reinterpret_cast(nodeData.data()), nBytes); - - outFileStream.close(); - } - else { - LERROR(fmt::format("Error opening file: {} as output data file.", outPath)); - } - } - - // Recursively write children to file (in Morton order) if we're in an inner node. - if (!node.isLeaf) { - std::vector writeThreads(8); - for (size_t i = 0; i < 8; ++i) { - std::string newOutFilePrefix = outFilePrefix + std::to_string(i); - if (threadWrites) { - // Divide writing to new threads to speed up the process. - std::thread t( - [this, newOutFilePrefix, n = node.Children[i]]() { - writeNodeToMultipleFiles(newOutFilePrefix, *n, false); - } - ); - writeThreads[i] = std::move(t); - } - else { - writeNodeToMultipleFiles(newOutFilePrefix, *node.Children[i], false); - } - } - if (threadWrites) { - // Make sure all threads are done. - for (int thread = 0; thread < 8; ++thread) { - writeThreads[thread].join(); - } - } - } -} - -void OctreeManager::fetchChildrenNodes(OctreeNode& parentNode, - int additionalLevelsToFetch) -{ - // Lock node to make sure nobody else are trying to load the same children. - std::lock_guard lock(parentNode.loadingLock); - - for (int i = 0; i < 8; ++i) { - // Fetch node data if we're streaming and it doesn't exist in RAM yet. - // (As long as there is any RAM budget left and node actually has any data!) - if (!parentNode.Children[i]->isLoaded && - (parentNode.Children[i]->numStars > 0) && - _cpuRamBudget > static_cast(parentNode.Children[i]->numStars - * (POS_SIZE + COL_SIZE + VEL_SIZE) * 4)) - { - fetchNodeDataFromFile(*parentNode.Children[i]); - } - - // Fetch all Children's Children if recursive is set to true! - if (additionalLevelsToFetch != 0 && !parentNode.Children[i]->isLeaf) { - fetchChildrenNodes(*parentNode.Children[i], --additionalLevelsToFetch); - } - } -} - -void OctreeManager::fetchNodeDataFromFile(OctreeNode& node) { - // Remove root ID ("8") from index before loading file. - std::string posId = std::to_string(node.octreePositionIndex); - posId.erase(posId.begin()); - - std::string inFilePath = _streamFolderPath + posId + BINARY_SUFFIX; - std::ifstream inFileStream(inFilePath, std::ifstream::binary); - // LINFO("Fetch node data file: " + inFilePath); - - if (inFileStream.good()) { - // Read node data. - int32_t nDataSize = 0; - - // Octree knows if we have any data in this node = it exists. - // Otherwise don't call this function! - inFileStream.read(reinterpret_cast(&nDataSize), sizeof(int32_t)); - - std::vector readData(nDataSize, 0.f); - int nBytes = nDataSize * sizeof(readData[0]); - if (nDataSize > 0) { - inFileStream.read(reinterpret_cast(&readData[0]), nBytes); - } - - int starsInNode = static_cast(nDataSize / _valuesPerStar); - auto posEnd = readData.begin() + (starsInNode * POS_SIZE); - auto colEnd = posEnd + (starsInNode * COL_SIZE); - auto velEnd = colEnd + (starsInNode * VEL_SIZE); - node.posData = std::vector(readData.begin(), posEnd); - node.colData = std::vector(posEnd, colEnd); - node.velData = std::vector(colEnd, velEnd); - - // Keep track of nodes that are loaded and update CPU RAM budget. - node.isLoaded = true; - if (!_datasetFitInMemory) { - std::lock_guard g(_leastRecentlyFetchedNodesMutex); - _leastRecentlyFetchedNodes.push(node.octreePositionIndex); - } - _cpuRamBudget -= nBytes; - } - else { - LERROR("Error opening node data file: " + inFilePath); - } -} - -void OctreeManager::removeNodesFromRam( - const std::vector& nodesToRemove) -{ - // LINFO("Removed " + std::to_string(nodesToRemove.size()) + " nodes from RAM."); - - for (unsigned long long nodePosIndex : nodesToRemove) { - std::stack indexStack; - while (nodePosIndex != 8) { - int nodeIndex = nodePosIndex % 10; - indexStack.push(nodeIndex); - nodePosIndex /= 10; - } - - // Traverse to node and remove it. - std::shared_ptr node = _root; - std::vector> ancestors; - while (!indexStack.empty()) { - ancestors.push_back(node); - node = node->Children[indexStack.top()]; - indexStack.pop(); - } - removeNode(*node); - - propagateUnloadedNodes(ancestors); - } -} - -void OctreeManager::removeNode(OctreeNode& node) { - // Lock node to make sure nobody else is trying to access it while removing. - std::lock_guard lock(node.loadingLock); - - int nBytes = static_cast( - node.numStars * _valuesPerStar * sizeof(node.posData[0]) - ); - // Keep track of which nodes that are loaded and update CPU RAM budget. - node.isLoaded = false; - _cpuRamBudget += nBytes; - - // Clear data - node.posData.clear(); - node.posData.shrink_to_fit(); - node.colData.clear(); - node.colData.shrink_to_fit(); - node.velData.clear(); - node.velData.shrink_to_fit(); -} - -void OctreeManager::propagateUnloadedNodes( - std::vector> ancestorNodes) -{ - std::shared_ptr parentNode = ancestorNodes.back(); - while (parentNode->octreePositionIndex != 8) { - // Check if any children of inner node is still loaded, or has loaded descendants. - if (parentNode->Children[0]->isLoaded || parentNode->Children[1]->isLoaded || - parentNode->Children[2]->isLoaded || parentNode->Children[3]->isLoaded || - parentNode->Children[4]->isLoaded || parentNode->Children[5]->isLoaded || - parentNode->Children[6]->isLoaded || parentNode->Children[7]->isLoaded || - parentNode->Children[0]->hasLoadedDescendant || - parentNode->Children[1]->hasLoadedDescendant || - parentNode->Children[2]->hasLoadedDescendant || - parentNode->Children[3]->hasLoadedDescendant || - parentNode->Children[4]->hasLoadedDescendant || - parentNode->Children[5]->hasLoadedDescendant || - parentNode->Children[6]->hasLoadedDescendant || - parentNode->Children[7]->hasLoadedDescendant) - { - return; - } - // Else all children has been unloaded and we can update parent flag. - parentNode->hasLoadedDescendant = false; - // LINFO("Removed ancestor: " + std::to_string(parentNode->octreePositionIndex)); - - // Propagate change upwards. - ancestorNodes.pop_back(); - parentNode = ancestorNodes.back(); - } -} - -size_t OctreeManager::numLeafNodes() const { - return _numLeafNodes; -} - -size_t OctreeManager::numInnerNodes() const { - return _numInnerNodes; -} - -size_t OctreeManager::totalNodes() const { - return _numLeafNodes + _numInnerNodes; -} - -size_t OctreeManager::totalDepth() const { - return _totalDepth; -} - -size_t OctreeManager::maxDist() const { - return MAX_DIST; -} - -size_t OctreeManager::maxStarsPerNode() const { - return MAX_STARS_PER_NODE; -} - -size_t OctreeManager::biggestChunkIndexInUse() const { - return _biggestChunkIndexInUse; -} - -size_t OctreeManager::numFreeSpotsInBuffer() const { - return _freeSpotsInBuffer.size(); -} - -long long OctreeManager::cpuRamBudget() const { - return _cpuRamBudget; -} - -bool OctreeManager::isRebuildOngoing() const { - return _rebuildBuffer; -} - -size_t OctreeManager::getChildIndex(float posX, float posY, float posZ, float origX, - float origY, float origZ) -{ - size_t index = 0; - if (posX < origX) { - index += 1; - } - if (posY < origY) { - index += 2; - } - if (posZ < origZ) { - index += 4; - } - return index; -} - -bool OctreeManager::insertInNode(OctreeNode& node, const std::vector& starValues, - int depth) -{ - if (node.isLeaf && node.numStars < MAX_STARS_PER_NODE) { - // Node is a leaf and it's not yet full -> insert star. - storeStarData(node, starValues); - - if (depth > _totalDepth) { - _totalDepth = depth; - } - return true; - } - else if (node.isLeaf) { - // Too many stars in leaf node, subdivide into 8 new nodes. - // Create children and clean up parent. - createNodeChildren(node); - - // Distribute stars from parent node into children. - for (size_t n = 0; n < MAX_STARS_PER_NODE; ++n) { - // Position data. - auto posBegin = node.posData.begin() + n * POS_SIZE; - auto posEnd = posBegin + POS_SIZE; - std::vector tmpValues(posBegin, posEnd); - // Color data. - auto colBegin = node.colData.begin() + n * COL_SIZE; - auto colEnd = colBegin + COL_SIZE; - tmpValues.insert(tmpValues.end(), colBegin, colEnd); - // Velocity data. - auto velBegin = node.velData.begin() + n * VEL_SIZE; - auto velEnd = velBegin + VEL_SIZE; - tmpValues.insert(tmpValues.end(), velBegin, velEnd); - - // Find out which child that will inherit the data and store it. - size_t index = getChildIndex( - tmpValues[0], - tmpValues[1], - tmpValues[2], - node.originX, - node.originY, - node.originZ - ); - insertInNode(*node.Children[index], tmpValues, depth); - } - - // Sort magnitudes in inner node. - // (The last value will be used as comparison for what to store in LOD cache.) - std::sort(node.magOrder.begin(), node.magOrder.end()); - } - - // Node is an inner node, keep recursion going. - // This will also take care of the new star when a subdivision has taken place. - size_t index = getChildIndex( - starValues[0], - starValues[1], - starValues[2], - node.originX, - node.originY, - node.originZ - ); - - // Determine if new star should be kept in our LOD cache. - // Keeps track of the brightest nodes in children. - if (starValues[POS_SIZE] < node.magOrder[MAX_STARS_PER_NODE - 1].first) { - storeStarData(node, starValues); - } - - return insertInNode(*node.Children[index], starValues, ++depth); -} - -void OctreeManager::sliceNodeLodCache(OctreeNode& node) { - // Slice stored LOD data in inner nodes. - if (!node.isLeaf) { - // Sort by magnitude. Inverse relation (i.e. a lower magnitude means a brighter - // star!) - std::sort(node.magOrder.begin(), node.magOrder.end()); - node.magOrder.resize(MAX_STARS_PER_NODE); - - std::vector tmpPos; - std::vector tmpCol; - std::vector tmpVel; - // Ordered map contain the MAX_STARS_PER_NODE brightest stars in all children! - for (auto const &[absMag, placement] : node.magOrder) { - auto posBegin = node.posData.begin() + placement * POS_SIZE; - auto colBegin = node.colData.begin() + placement * COL_SIZE; - auto velBegin = node.velData.begin() + placement * VEL_SIZE; - tmpPos.insert(tmpPos.end(), posBegin, posBegin + POS_SIZE); - tmpCol.insert(tmpCol.end(), colBegin, colBegin + COL_SIZE); - tmpVel.insert(tmpVel.end(), velBegin, velBegin + VEL_SIZE); - } - node.posData = std::move(tmpPos); - node.colData = std::move(tmpCol); - node.velData = std::move(tmpVel); - node.numStars = node.magOrder.size(); // = MAX_STARS_PER_NODE - - for (int i = 0; i < 8; ++i) { - sliceNodeLodCache(*node.Children[i]); - } - } -} - -void OctreeManager::storeStarData(OctreeNode& node, const std::vector& starValues) -{ - // Insert star data at the back of vectors and store a vector with pairs consisting of - // star magnitude and insert index for later sorting and slicing of LOD cache. - float mag = starValues[POS_SIZE]; - node.magOrder.insert(node.magOrder.end(), std::make_pair(mag, node.numStars)); - node.numStars++; - - // If LOD is growing too large then sort it and resize to [chunk size] to avoid too - // much RAM usage and increase threshold for adding new stars. - if (node.magOrder.size() > MAX_STARS_PER_NODE * 2) { - std::sort(node.magOrder.begin(), node.magOrder.end()); - node.magOrder.resize(MAX_STARS_PER_NODE); - } - - auto posEnd = starValues.begin() + POS_SIZE; - auto colEnd = posEnd + COL_SIZE; - node.posData.insert(node.posData.end(), starValues.begin(), posEnd); - node.colData.insert(node.colData.end(), posEnd, colEnd); - node.velData.insert(node.velData.end(), colEnd, starValues.end()); -} - -std::string OctreeManager::printStarsPerNode(const OctreeNode& node, - const std::string& prefix) const -{ - - // Print both inner and leaf nodes. - auto str = prefix + "} : " + std::to_string(node.numStars); - - if (node.isLeaf) { - return str + " - [Leaf] \n"; - } - else { - str += fmt::format("LOD: {} - [Parent]\n", node.posData.size() / POS_SIZE); - for (int i = 0; i < 8; ++i) { - auto pref = prefix + "->" + std::to_string(i); - str += printStarsPerNode(*node.Children[i], pref); - } - return str; - } -} - -std::map> OctreeManager::checkNodeIntersection(OctreeNode& node, - const glm::dmat4& mvp, - const glm::vec2& screenSize, - int& deltaStars, - gaia::RenderOption option) -{ - std::map> fetchedData; - //int depth = static_cast(log2( MAX_DIST / node->halfDimension )); - - // Calculate the corners of the node. - std::vector corners(8); - for (int i = 0; i < 8; ++i) { - const float x = (i % 2 == 0) ? - node.originX + node.halfDimension : - node.originX - node.halfDimension; - const float y = (i % 4 < 2) ? - node.originY + node.halfDimension : - node.originY - node.halfDimension; - const float z = (i < 4) ? - node.originZ + node.halfDimension : - node.originZ - node.halfDimension; - glm::dvec3 pos = glm::dvec3(x, y, z) * 1000.0 * distanceconstants::Parsec; - corners[i] = glm::dvec4(pos, 1.0); - } - - // Check if node is visible from camera. If not then return early. - if (!(_culler->isVisible(corners, mvp))) { - // Check if this node or any of its children existed in cache previously. - // If so, then remove them from cache and add those indices to stack. - fetchedData = removeNodeFromCache(node, deltaStars); - return fetchedData; - } - - // Remove node if it has been unloaded while still in view. - // (While streaming big datasets.) - if (node.bufferIndex != DEFAULT_INDEX && !node.isLoaded && _streamOctree && - !_datasetFitInMemory) - { - fetchedData = removeNodeFromCache(node, deltaStars); - return fetchedData; - } - - // Take care of inner nodes. - if (!(node.isLeaf)) { - glm::vec2 nodeSize = _culler->getNodeSizeInPixels(corners, mvp, screenSize); - float totalPixels = nodeSize.x * nodeSize.y; - - // Check if we should return any LOD cache data. If we're streaming a big dataset - // from files and inner node is visible and loaded, then it should be rendered - // (as long as it doesn't have loaded children because then we should traverse to - // lowest loaded level and render it instead)! - if ((totalPixels < _minTotalPixelsLod) || (_streamOctree && - !_datasetFitInMemory && node.isLoaded && !node.hasLoadedDescendant)) - { - // Get correct insert index from stack if node didn't exist already. Otherwise - // we will overwrite the old data. Key merging is not a problem here. - if ((node.bufferIndex == DEFAULT_INDEX) || _rebuildBuffer) { - // Return empty if we couldn't claim a buffer stream index. - if (!updateBufferIndex(node)) { - return fetchedData; - } - - // We're in an inner node, remove indices from potential children in cache - for (int i = 0; i < 8; ++i) { - std::map> tmpData = removeNodeFromCache( - *node.Children[i], - deltaStars - ); - fetchedData.insert(tmpData.begin(), tmpData.end()); - } - - // Insert data and adjust stars added in this frame. - fetchedData[node.bufferIndex] = constructInsertData( - node, - option, - deltaStars - ); - } - return fetchedData; - } - } - // Return node data if node is a leaf. - else { - // If node already is in cache then skip it, otherwise store it. - if ((node.bufferIndex == DEFAULT_INDEX) || _rebuildBuffer) { - // Return empty if we couldn't claim a buffer stream index. - if (!updateBufferIndex(node)) { - return fetchedData; - } - - // Insert data and adjust stars added in this frame. - fetchedData[node.bufferIndex] = constructInsertData( - node, - option, - deltaStars - ); - } - return fetchedData; - } - - // We're in a big, visible inner node -> remove it from cache if it existed. - // But not its children -> set recursive check to false. - fetchedData = removeNodeFromCache(node, deltaStars, false); - - // Recursively check if children should be rendered. - for (size_t i = 0; i < 8; ++i) { - // Observe that if there exists identical keys in fetchedData then those values in - // tmpData will be ignored! Thus we store the removed keys until next render call! - std::map> tmpData = checkNodeIntersection( - *node.Children[i], - mvp, - screenSize, - deltaStars, - option - ); - fetchedData.insert(tmpData.begin(), tmpData.end()); - } - return fetchedData; -} - -std::map> OctreeManager::removeNodeFromCache(OctreeNode& node, - int& deltaStars, - bool recursive) -{ - std::map> keysToRemove; - - // If we're in rebuilding mode then there is no need to remove any nodes. - //if (_rebuildBuffer) return keysToRemove; - - // Check if this node was rendered == had a specified index. - if (node.bufferIndex != DEFAULT_INDEX) { - - // Reclaim that index. We need to wait until next render call to use it again! - _removedKeysInPrevCall.insert(node.bufferIndex); - - // Insert dummy node at offset index that should be removed from render. - keysToRemove[node.bufferIndex] = std::vector(); - - // Reset index and adjust stars removed this frame. - node.bufferIndex = DEFAULT_INDEX; - deltaStars -= static_cast(node.numStars); - } - - // Check children recursively if we're in an inner node. - if (!(node.isLeaf) && recursive) { - for (int i = 0; i < 8; ++i) { - std::map> tmpData = removeNodeFromCache( - *node.Children[i], - deltaStars - ); - keysToRemove.insert(tmpData.begin(), tmpData.end()); - } - } - return keysToRemove; -} - -std::vector OctreeManager::getNodeData(const OctreeNode& node, - gaia::RenderOption option) -{ - // Return node data if node is a leaf. - if (node.isLeaf) { - int dStars = 0; - return constructInsertData(node, option, dStars); - } - - // If we're not in a leaf, get data from all children recursively. - auto nodeData = std::vector(); - for (size_t i = 0; i < 8; ++i) { - std::vector tmpData = getNodeData(*node.Children[i], option); - nodeData.insert(nodeData.end(), tmpData.begin(), tmpData.end()); - } - return nodeData; -} - -void OctreeManager::clearNodeData(OctreeNode& node) { - // Clear data and its allocated memory. - node.posData.clear(); - node.posData.shrink_to_fit(); - node.colData.clear(); - node.colData.shrink_to_fit(); - node.velData.clear(); - node.velData.shrink_to_fit(); - - // Clear magnitudes as well! - //std::vector>().swap(node->magOrder); - node.magOrder.clear(); - - if (!node.isLeaf) { - // Remove data from all children recursively. - for (size_t i = 0; i < 8; ++i) { - clearNodeData(*node.Children[i]); - } - } -} - -void OctreeManager::createNodeChildren(OctreeNode& node) { - for (size_t i = 0; i < 8; ++i) { - _numLeafNodes++; - node.Children[i] = std::make_shared(); - node.Children[i]->isLeaf = true; - node.Children[i]->isLoaded = false; - node.Children[i]->hasLoadedDescendant = false; - node.Children[i]->bufferIndex = DEFAULT_INDEX; - node.Children[i]->octreePositionIndex = (node.octreePositionIndex * 10) + i; - node.Children[i]->numStars = 0; - node.Children[i]->posData = std::vector(); - node.Children[i]->colData = std::vector(); - node.Children[i]->velData = std::vector(); - node.Children[i]->magOrder = std::vector>(); - node.Children[i]->halfDimension = node.halfDimension / 2.f; - - // Calculate new origin. - node.Children[i]->originX = node.originX; - node.Children[i]->originX += (i % 2 == 0) ? - node.Children[i]->halfDimension : - -node.Children[i]->halfDimension; - node.Children[i]->originY = node.originY; - node.Children[i]->originY += (i % 4 < 2) ? - node.Children[i]->halfDimension : - -node.Children[i]->halfDimension; - node.Children[i]->originZ = node.originZ; - node.Children[i]->originZ += (i < 4) ? - node.Children[i]->halfDimension : - -node.Children[i]->halfDimension; - } - - // Clean up parent. - node.isLeaf = false; - _numLeafNodes--; - _numInnerNodes++; -} - -bool OctreeManager::updateBufferIndex(OctreeNode& node) { - if (node.bufferIndex != DEFAULT_INDEX) { - // If we're rebuilding Buffer Index Cache then store indices to overwrite later. - _removedKeysInPrevCall.insert(node.bufferIndex); - } - - // Make sure node isn't loading/unloading as we're checking isLoaded flag. - std::lock_guard lock(node.loadingLock); - - // Return false if there are no more spots in our buffer, or if we're streaming and - // node isn't loaded yet, or if node doesn't have any stars. - if (_freeSpotsInBuffer.empty() || (_streamOctree && !node.isLoaded) || - node.numStars == 0) - { - return false; - } - - // Get correct insert index from stack. - node.bufferIndex = _freeSpotsInBuffer.top(); - _freeSpotsInBuffer.pop(); - - // Keep track of how many chunks are in use (ceiling). - if (_freeSpotsInBuffer.empty()) { - _biggestChunkIndexInUse++; - } - else if (_freeSpotsInBuffer.top() > _biggestChunkIndexInUse) { - _biggestChunkIndexInUse = _freeSpotsInBuffer.top(); - } - return true; -} - -std::vector OctreeManager::constructInsertData(const OctreeNode& node, - gaia::RenderOption option, - int& deltaStars) -{ - // Return early if node doesn't contain any stars! - if (node.numStars == 0) { - return std::vector(); - } - - // Fill chunk by appending zeroes to data so we overwrite possible earlier values. - // And more importantly so our attribute pointers knows where to read! - auto insertData = std::vector(node.posData.begin(), node.posData.end()); - if (_useVBO) { - insertData.resize(POS_SIZE * MAX_STARS_PER_NODE, 0.f); - } - if (option != gaia::RenderOption::Static) { - insertData.insert(insertData.end(), node.colData.begin(), node.colData.end()); - if (_useVBO) { - insertData.resize((POS_SIZE + COL_SIZE) * MAX_STARS_PER_NODE, 0.f); - } - if (option == gaia::RenderOption::Motion) { - insertData.insert(insertData.end(), node.velData.begin(), node.velData.end()); - if (_useVBO) { - insertData.resize( - (POS_SIZE + COL_SIZE + VEL_SIZE) * MAX_STARS_PER_NODE, 0.f - ); - } - } - } - - // Update deltaStars. - deltaStars += static_cast(node.numStars); - return insertData; -} - -} // namespace openspace diff --git a/modules/softwareintegration/rendering/octreemanager.h b/modules/softwareintegration/rendering/octreemanager.h deleted file mode 100644 index 031e9e3630..0000000000 --- a/modules/softwareintegration/rendering/octreemanager.h +++ /dev/null @@ -1,387 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2020 * - * * - * 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 __OPENSPACE_MODULE_GAIA___OCTREEMANAGER___H__ -#define __OPENSPACE_MODULE_GAIA___OCTREEMANAGER___H__ - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace openspace { - -class OctreeCuller; - -class OctreeManager { -public: - struct OctreeNode { - std::shared_ptr Children[8]; - std::vector posData; - std::vector colData; - std::vector velData; - std::vector> magOrder; - float originX; - float originY; - float originZ; - float halfDimension; - size_t numStars; - bool isLeaf; - bool isLoaded; - bool hasLoadedDescendant; - std::mutex loadingLock; - int bufferIndex; - unsigned long long octreePositionIndex; - }; - - OctreeManager() = default; - ~OctreeManager() = default; - - /** - * Initializes a one layer Octree with root and 8 children that covers all stars. - * - * \param maxDist together with \param maxstarsPerNode (if defined) determines the - * depth of the tree as well as how many nodes will be created. - */ - void initOctree(long long cpuRamBudget = 0, int maxDist = 0, int maxStarsPerNode = 0); - - /** - * Initializes a stack of size \param maxNodes that keeps track of all free spot in - * buffer stream. Can be used to trigger a rebuild of buffer(s). - * - * \param useVBO defines if VBO or SSBO is used as buffer(s) - * \param datasetFitInMemory defines if streaming of nodes during runtime is used - */ - void initBufferIndexStack(long long maxNodes, bool useVBO, bool datasetFitInMemory); - - /** - * Inserts star values in correct position in Octree. Makes use of a recursive - * traversal strategy. Internally calls insertInNode() - */ - void insert(const std::vector& starValues); - - /** - * Slices LOD data so only the MAX_STARS_PER_NODE brightest stars are stored in inner - * nodes. If \p branchIndex is defined then only that branch will be sliced. - * Calls sliceNodeLodCache() internally. - */ - void sliceLodData(size_t branchIndex = 8); - - /** - * Prints the whole tree structure, including number of stars per node, number of - * nodes, tree depth and if node is a leaf. - * Calls printStarsPerNode(node, prefix) internally. - */ - void printStarsPerNode() const; - - /** - * Used while streaming nodes from files. Checks if any nodes need to be loaded or - * unloaded. If entire dataset fits in RAM then the whole dataset will be loaded - * asynchronously. Otherwise only nodes close to the camera will be fetched. - * When RAM stars to fill up least-recently used nodes will start to unload. - * Calls findAndFetchNeighborNode() and - * removeNodesFromRam() internally. - */ - void fetchSurroundingNodes(const glm::dvec3& cameraPos, size_t chunkSizeInBytes, - const glm::ivec2& additionalNodes); - - /** - * Builds render data structure by traversing the Octree and checking for intersection - * with view frustum. Every vector in map contains data for one node. - * The corresponding integer key is the index where chunk should be inserted into - * streaming buffer. Calls checkNodeIntersection() for every branch. - * \pdeltaStars keeps track of how many stars that were added/removed this render - * call. - */ - std::map> traverseData(const glm::dmat4& mvp, - const glm::vec2& screenSize, int& deltaStars, gaia::RenderOption option, - float lodPixelThreshold); - - /** - * Builds full render data structure by traversing all leaves in the Octree. - */ - std::vector getAllData(gaia::RenderOption option); - - /** - * Removes all data from Octree, or only from a specific branch if specified. - * \param branchIndex defined which branch to clear if defined. - */ - void clearAllData(int branchIndex = -1); - - /** - * Write entire Octree structure to a binary file. \param writeData defines if data - * should be included or if only structure should be written to the file. - * Calls writeNodeToFile() which recursively writes all nodes. - */ - void writeToFile(std::ofstream& outFileStream, bool writeData); - - /** - * Read a constructed Octree from a file. \returns the total number of (distinct) - * stars read. - * - * \param readData defines if full data or only structure should be read. - * Calls readNodeFromFile() which recursively reads all nodes. - */ - int readFromFile(std::ifstream& inFileStream, bool readData, - const std::string& folderPath = std::string()); - - /** - * Write specified part of Octree to multiple files, including all data. - * \param branchIndex defines which branch to write. - * Clears specified branch after writing is done. - * Calls writeNodeToMultipleFiles() for the specified branch. - */ - void writeToMultipleFiles(const std::string& outFolderPath, size_t branchIndex); - - /** - * Getters. - */ - size_t numLeafNodes() const; - size_t numInnerNodes() const; - size_t totalNodes() const; - size_t totalDepth() const; - size_t maxDist() const; - size_t maxStarsPerNode() const; - size_t biggestChunkIndexInUse() const; - size_t numFreeSpotsInBuffer() const; - bool isRebuildOngoing() const; - - /** - * \returns current CPU RAM budget in bytes. - */ - long long cpuRamBudget() const; - -private: - const size_t POS_SIZE = 3; - const size_t COL_SIZE = 2; - const size_t VEL_SIZE = 3; - - // MAX_DIST [kPc] - Determines the depth of Octree together with MAX_STARS_PER_NODE. - // A smaller distance is better (i.e. a smaller total depth) and a smaller MAX_STARS - // is also better (i.e. finer borders and fewer nodes/less data needs to be uploaded - // to the GPU), but MAX_STARS still needs to be big enough to be able to swallow all - // stars that falls outside of top border nodes, otherwise it causes a stack overflow - // when building Octree. However, fewer total nodes (i.e. bigger Stars/Node) reduces - // traversing time which is preferable, especially with big datasets - // DR1_TGAS [2M] - A MAX_DIST of 5 kPc works fine with down to 1 kSPN. - // DR1_full [1.2B] - A MAX_DIST of 10 kPc works fine with most SPN. - // DR2_rv [7.2M] - A MAX_DIST of 15 kPc works fine with down to 10 kSPN. - // DR2_subset [42.9M] - A MAX_DIST of 100 kPc works fine with 20 kSPN. - // DR2_full [1.7B] - A MAX_DIST of 250 kPc works fine with 150 kSPN. - size_t MAX_DIST = 2; // [kPc] - size_t MAX_STARS_PER_NODE = 2000; - - const int DEFAULT_INDEX = -1; - const std::string BINARY_SUFFIX = ".bin"; - - /** - * \returns the correct index of child node. Maps [1,1,1] to 0 and [-1,-1,-1] to 7. - */ - size_t getChildIndex(float posX, float posY, float posZ, float origX = 0.f, - float origY = 0.f, float origZ = 0.f); - - /** - * Private help function for insert(). Inserts star into node if leaf and - * numStars < MAX_STARS_PER_NODE. If a leaf goes above the threshold it is subdivided - * into 8 new nodes. - * If node is an inner node, then star is stores in LOD cache if it is among the - * brightest stars in all children. - */ - bool insertInNode(OctreeNode& node, const std::vector& starValues, - int depth = 1); - - /** - * Slices LOD cache data in node to the MAX_STARS_PER_NODE brightest stars. This needs - * to be called after the last star has been inserted into Octree but before it is - * saved to file(s). Slices all descendants recursively. - */ - void sliceNodeLodCache(OctreeNode& node); - - /** - * Private help function for insertInNode(). Stores star data in node and - * keeps track of the brightest stars all children. - */ - void storeStarData(OctreeNode& node, const std::vector& starValues); - - /** - * Private help function for printStarsPerNode(). \returns an accumulated - * string containing all descendant nodes. - */ - std::string printStarsPerNode(const OctreeNode& node, - const std::string& prefix) const; - - /** - * Private help function for traverseData(). Recursively checks which - * nodes intersect with the view frustum (interpreted as an AABB) and decides if data - * should be optimized away or not. Keeps track of which nodes that are visible and - * loaded (if streaming). \param deltaStars keeps track of how many stars that were - * added/removed this render call. - */ - std::map> checkNodeIntersection(OctreeNode& node, - const glm::dmat4& mvp, const glm::vec2& screenSize, int& deltaStars, - gaia::RenderOption option); - - /** - * Checks if specified node existed in cache, and removes it if that's the case. - * If node is an inner node then all children will be checked recursively as well as - * long as \param recursive is not set to false. \param deltaStars keeps track of how - * many stars that were removed. - */ - std::map> removeNodeFromCache(OctreeNode& node, - int& deltaStars, bool recursive = true); - - /** - * Get data in node and its descendants regardless if they are visible or not. - */ - std::vector getNodeData(const OctreeNode& node, gaia::RenderOption option); - - /** - * Clear data from node and its descendants and shrink vectors to deallocate memory. - */ - void clearNodeData(OctreeNode& node); - - /** - * Contruct default children nodes for specified node. - */ - void createNodeChildren(OctreeNode& node); - - /** - * Checks if node should be inserted into stream or not. \returns true if it should, - * (i.e. it doesn't already exists, there is room for it in the buffer and node data - * is loaded if streaming). \returns false otherwise. - */ - bool updateBufferIndex(OctreeNode& node); - - /** - * Node should be inserted into stream. This function \returns the data to be - * inserted. If VBOs are used then the chunks will be appended by zeros, otherwise - * only the star data corresponding to RenderOption \param option will be inserted. - * - * \param deltaStars keeps track of how many stars that were added. - */ - std::vector constructInsertData(const OctreeNode& node, - gaia::RenderOption option, int& deltaStars); - - /** - * Write a node to outFileStream. \param writeData defines if data should be included - * or if only structure should be written. - */ - void writeNodeToFile(std::ofstream& outFileStream, const OctreeNode& node, - bool writeData); - - /** - * Read a node from file and its potential children. \param readData defines if full - * data or only structure should be read. - * \returns accumulated sum of all read stars in node and its descendants. - */ - int readNodeFromFile(std::ifstream& inFileStream, OctreeNode& node, bool readData); - - /** - * Write node data to a file. \param outFilePrefix specifies the accumulated path - * and name of the file. If \param threadWrites is set to true then one new thread - * will be created for each child to write its descendents. - */ - void writeNodeToMultipleFiles(const std::string& outFilePrefix, OctreeNode& node, - bool threadWrites); - - /** - * Finds the neighboring node on the same level (or a higher level if there is no - * corresponding level) in the specified direction. Also fetches data from found node - * if it's not already loaded. \param additionalLevelsToFetch determines if any - * descendants of the found node should be fetched as well (if they exists). - */ - void findAndFetchNeighborNode(unsigned long long firstParentId, int x, int y, int z, - int additionalLevelsToFetch); - - /** - * Fetches data from all children of \param parentNode, as long as it's not already - * fetched, it exists and it can fit in RAM. - * \param additionalLevelsToFetch determines how many levels of descendants to fetch. - * If it is set to 0 no additional level will be fetched. - * If it is set to a negative value then all descendants will be fetched recursively. - * Calls fetchNodeDataFromFile() for every child that passes the tests. - */ - void fetchChildrenNodes(OctreeNode& parentNode, int additionalLevelsToFetch); - - /** - * Fetches data for specified node from file. - * OBS! Only call if node file exists (i.e. node has any data, node->numStars > 0) - * and is not already loaded. - */ - void fetchNodeDataFromFile(OctreeNode& node); - - /** - * Loops though all nodes in \param nodesToRemove and clears them from RAM. - * Also checks if any ancestor should change the hasLoadedDescendant flag - * by calling propagateUnloadedNodes() with all ancestors. - */ - void removeNodesFromRam(const std::vector& nodesToRemove); - - /** - * Removes data in specified node from main memory and updates RAM budget and flags - * accordingly. - */ - void removeNode(OctreeNode& node); - - /** - * Loops through \param ancestorNodes backwards and checks if parent node has any - * loaded descendants left. If not, then flag hasLoadedDescendant will be - * set to false for that parent node and next parent in line will be checked. - */ - void propagateUnloadedNodes(std::vector> ancestorNodes); - - std::shared_ptr _root; - std::unique_ptr _culler; - std::stack _freeSpotsInBuffer; - std::set _removedKeysInPrevCall; - std::queue _leastRecentlyFetchedNodes; - std::mutex _leastRecentlyFetchedNodesMutex; - - size_t _totalDepth = 0; - size_t _numLeafNodes = 0; - size_t _numInnerNodes = 0; - size_t _biggestChunkIndexInUse = 0; - size_t _valuesPerStar = 0; - float _minTotalPixelsLod = 0.f; - - size_t _maxStackSize = 0; - bool _rebuildBuffer = false; - bool _useVBO = false; - bool _streamOctree = false; - bool _datasetFitInMemory = false; - long long _cpuRamBudget = 0; - long long _maxCpuRamBudget = 0; - unsigned long long _parentNodeOfCamera = 8; - std::string _streamFolderPath; - size_t _traversedBranchesInRenderCall = 0; - -}; // class OctreeManager - -} // namespace openspace - -#endif // __OPENSPACE_MODULE_GAIA___OCTREEMANAGER___H__ diff --git a/modules/softwareintegration/rendering/renderablegaiastars.cpp b/modules/softwareintegration/rendering/renderablegaiastars.cpp deleted file mode 100644 index a67a1d17c2..0000000000 --- a/modules/softwareintegration/rendering/renderablegaiastars.cpp +++ /dev/null @@ -1,2522 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2020 * - * * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include - -namespace { - constexpr const char* _loggerCat = "RenderableGaiaStars"; - - constexpr size_t PositionSize = 3; - constexpr size_t ColorSize = 2; - constexpr size_t VelocitySize = 3; - - constexpr openspace::properties::Property::PropertyInfo FilePathInfo = { - "File", - "File Path", - "The path to the file with data for the stars to be rendered." - }; - - constexpr openspace::properties::Property::PropertyInfo FileReaderOptionInfo = { - "FileReaderOption", - "File Reader Option", - "This value tells the renderable what format the input data file has. " - "'Fits' will read a FITS file, construct an Octree from it and render full " - "data. 'Speck' will read a SPECK file, construct an Octree from it and render " - "full data. 'BinaryRaw' will read a preprocessed binary file with ordered star " - "data, construct an Octree and render it. 'BinaryOctree' will read a constructed " - "Octree from binary file and render full data. 'StreamOctree' will read an index " - "file with full Octree structure and then stream nodes during runtime. (This " - "option is suited for bigger datasets.)" - }; - - constexpr openspace::properties::Property::PropertyInfo RenderOptionInfo = { - "RenderOption", - "Render Option", - "This value determines which predefined columns to use in rendering. If " - "'Static' only the position of the stars is used. 'Color' uses position + color " - "parameters and 'Motion' uses pos, color as well as velocity for the stars." - }; - - constexpr openspace::properties::Property::PropertyInfo ShaderOptionInfo = { - "ShaderOption", - "Shader Option", - "This value determines which shaders to use while rendering. If 'Point_*' is " - "chosen then gl_Points will be rendered and then spread out with a bloom " - "filter. If 'Billboard_*' is chosen then the geometry shaders will generate " - "screen-faced billboards for all stars. For '*_SSBO' the data will be stored in " - "Shader Storage Buffer Objects while '*_VBO' uses Vertex Buffer Objects for the " - "streaming. OBS! SSBO won't work on APPLE!" - }; - - constexpr openspace::properties::Property::PropertyInfo PsfTextureInfo = { - "Texture", - "Point Spread Function Texture", - "The path to the texture that should be used as a point spread function for the " - "stars." - }; - - constexpr openspace::properties::Property::PropertyInfo LuminosityMultiplierInfo = { - "LuminosityMultiplier", - "Luminosity Multiplier", - "Factor by which to multiply the luminosity with. [Works in Color and Motion " - "modes]" - }; - - constexpr openspace::properties::Property::PropertyInfo MagnitudeBoostInfo = { - "MagnitudeBoost", - "Magnitude Boost", - "Sets what percent of the star magnitude that will be used as boost to star " - "size. [Works only with billboards in Color and Motion modes]" - }; - - constexpr openspace::properties::Property::PropertyInfo CutOffThresholdInfo = { - "CutOffThreshold", - "Cut Off Threshold", - "Set threshold for when to cut off star rendering. " - "Stars closer than this threshold are given full opacity. " - "Farther away, stars dim proportionally to the 4-logarithm of their distance." - }; - - constexpr openspace::properties::Property::PropertyInfo SharpnessInfo = { - "Sharpness", - "Sharpness", - "Adjust star sharpness. [Works only with billboards]" - }; - - constexpr openspace::properties::Property::PropertyInfo BillboardSizeInfo = { - "BillboardSize", - "Billboard Size", - "Set the billboard size of all stars. [Works only with billboards]" - }; - - constexpr openspace::properties::Property::PropertyInfo CloseUpBoostDistInfo = { - "CloseUpBoostDist", - "Close-Up Boost Distance [pc]", - "Set the distance where stars starts to increase in size. Unit is Parsec." - "[Works only with billboards]" - }; - - constexpr openspace::properties::Property::PropertyInfo TmPointFilterSizeInfo = { - "FilterSize", - "Filter Size [px]", - "Set the filter size in pixels used in tonemapping for point splatting rendering." - "[Works only with points]" - }; - - constexpr openspace::properties::Property::PropertyInfo TmPointSigmaInfo = { - "Sigma", - "Normal Distribution Sigma", - "Set the normal distribution sigma used in tonemapping for point splatting " - "rendering. [Works only with points]" - }; - - constexpr openspace::properties::Property::PropertyInfo AdditionalNodesInfo = { - "AdditionalNodes", - "Additional Nodes", - "Determines how many additional nodes around the camera that will be fetched " - "from disk. The first value determines how many additional layers of parents " - "that will be fetched. The second value determines how many layers of descendant " - "that will be fetched from the found parents." - }; - - constexpr openspace::properties::Property::PropertyInfo TmPointPxThresholdInfo = { - "PixelWeightThreshold", - "Pixel Weight Threshold", - "Set the threshold for how big the elliptic weight of a pixel has to be to " - "contribute to the final elliptic shape. A smaller value gives a more visually " - "pleasing result while a bigger value will speed up the rendering on skewed " - "frustums (aka Domes)." - }; - - constexpr openspace::properties::Property::PropertyInfo ColorTextureInfo = { - "ColorMap", - "Color Texture", - "The path to the texture that is used to convert from the magnitude of the star " - "to its color. The texture is used as a one dimensional lookup function." - }; - - constexpr openspace::properties::Property::PropertyInfo FirstRowInfo = { - "FirstRow", - "First Row to Read", - "Defines the first row that will be read from the specified FITS file." - "No need to define if data already has been processed." - "[Works only with FileReaderOption::Fits]" - }; - - constexpr openspace::properties::Property::PropertyInfo LastRowInfo = { - "LastRow", - "Last Row to Read", - "Defines the last row that will be read from the specified FITS file." - "Has to be equal to or greater than FirstRow. No need to define if " - "data already has been processed." - "[Works only with FileReaderOption::Fits]" - }; - - constexpr openspace::properties::Property::PropertyInfo ColumnNamesInfo = { - "ColumnNames", - "Column Names", - "A list of strings with the names of all the columns that are to be " - "read from the specified FITS file. No need to define if data already " - "has been processed." - "[Works only with FileReaderOption::Fits]" - }; - - constexpr openspace::properties::Property::PropertyInfo NumRenderedStarsInfo = { - "NumRenderedStars", - "Rendered Stars", - "The number of rendered stars in the current frame." - }; - - constexpr openspace::properties::Property::PropertyInfo CpuRamBudgetInfo = { - "CpuRamBudget", - "CPU RAM Budget", - "Current remaining budget (bytes) on the CPU RAM for loading more node data " - "files." - }; - - constexpr openspace::properties::Property::PropertyInfo GpuStreamBudgetInfo = { - "GpuStreamBudget", - "GPU Stream Budget", - "Current remaining memory budget [in number of chunks] on the GPU for streaming " - "additional stars." - }; - - constexpr openspace::properties::Property::PropertyInfo LodPixelThresholdInfo = { - "LodPixelThreshold", - "LOD Pixel Threshold", - "The number of total pixels a nodes AABB can have in clipping space before its " - "parent is fetched as LOD cache." - }; - - constexpr openspace::properties::Property::PropertyInfo MaxGpuMemoryPercentInfo = { - "MaxGpuMemoryPercent", - "Max GPU Memory", - "Sets the max percent of existing GPU memory budget that the streaming will use." - }; - - constexpr openspace::properties::Property::PropertyInfo MaxCpuMemoryPercentInfo = { - "MaxCpuMemoryPercent", - "Max CPU Memory", - "Sets the max percent of existing CPU memory budget that the streaming of files " - "will use." - }; - - constexpr openspace::properties::Property::PropertyInfo FilterPosXInfo = { - "FilterPosX", - "PosX Threshold", - "If defined then only stars with Position X values between [min, max] " - "will be rendered (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). Measured in kiloParsec." - }; - - constexpr openspace::properties::Property::PropertyInfo FilterPosYInfo = { - "FilterPosY", - "PosY Threshold", - "If defined then only stars with Position Y values between [min, max] " - "will be rendered (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). Measured in kiloParsec." - }; - - constexpr openspace::properties::Property::PropertyInfo FilterPosZInfo = { - "FilterPosZ", - "PosZ Threshold", - "If defined then only stars with Position Z values between [min, max] " - "will be rendered (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). Measured in kiloParsec." - }; - - constexpr openspace::properties::Property::PropertyInfo FilterGMagInfo = { - "FilterGMag", - "GMag Threshold", - "If defined then only stars with G mean magnitude values between [min, max] " - "will be rendered (if min is set to 20.0 it is read as -Inf, " - "if max is set to 20.0 it is read as +Inf). If min = max then all values " - "equal min|max will be filtered away." - }; - - constexpr openspace::properties::Property::PropertyInfo FilterBpRpInfo = { - "FilterBpRp", - "Bp-Rp Threshold", - "If defined then only stars with Bp-Rp color values between [min, max] " - "will be rendered (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). If min = max then all values " - "equal min|max will be filtered away." - }; - - constexpr openspace::properties::Property::PropertyInfo FilterDistInfo = { - "FilterDist", - "Dist Threshold", - "If defined then only stars with Distances values between [min, max] " - "will be rendered (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). Measured in kParsec." - }; - - constexpr openspace::properties::Property::PropertyInfo ReportGlErrorsInfo = { - "ReportGlErrors", - "Report GL Errors", - "If set to true, any OpenGL errors will be reported if encountered" - }; -} // namespace - -namespace openspace { - -documentation::Documentation RenderableGaiaStars::Documentation() { - using namespace documentation; - return { - "RenderableGaiaStars", - "gaiamission_renderablegaiastars", - { - { - "Type", - new StringEqualVerifier("RenderableGaiaStars"), - Optional::No - }, - { - FilePathInfo.identifier, - new StringVerifier, - Optional::No, - FilePathInfo.description - }, - { - FileReaderOptionInfo.identifier, - new StringInListVerifier({ - "Fits", "Speck", "BinaryRaw", "BinaryOctree", "StreamOctree" - }), - Optional::No, - FileReaderOptionInfo.description - }, - { - RenderOptionInfo.identifier, - new StringInListVerifier({ - "Static", "Color", "Motion" - }), - Optional::Yes, - RenderOptionInfo.description - }, - { - ShaderOptionInfo.identifier, - new StringInListVerifier({ - "Point_SSBO", "Point_VBO", "Billboard_SSBO", "Billboard_VBO", - "Billboard_SSBO_noFBO" - }), - Optional::Yes, - ShaderOptionInfo.description - }, - { - PsfTextureInfo.identifier, - new StringVerifier, - Optional::No, - PsfTextureInfo.description - }, - { - ColorTextureInfo.identifier, - new StringVerifier, - Optional::No, - ColorTextureInfo.description - }, - { - LuminosityMultiplierInfo.identifier, - new DoubleVerifier, - Optional::Yes, - LuminosityMultiplierInfo.description - }, - { - MagnitudeBoostInfo.identifier, - new DoubleVerifier, - Optional::Yes, - MagnitudeBoostInfo.description - }, - { - CutOffThresholdInfo.identifier, - new DoubleVerifier, - Optional::Yes, - CutOffThresholdInfo.description - }, - { - SharpnessInfo.identifier, - new DoubleVerifier, - Optional::Yes, - SharpnessInfo.description - }, - { - BillboardSizeInfo.identifier, - new DoubleVerifier, - Optional::Yes, - BillboardSizeInfo.description - }, - { - CloseUpBoostDistInfo.identifier, - new DoubleVerifier, - Optional::Yes, - CloseUpBoostDistInfo.description - }, - { - TmPointFilterSizeInfo.identifier, - new IntVerifier, - Optional::Yes, - TmPointFilterSizeInfo.description - }, - { - TmPointSigmaInfo.identifier, - new DoubleVerifier, - Optional::Yes, - TmPointSigmaInfo.description - }, - { - AdditionalNodesInfo.identifier, - new Vector2Verifier, - Optional::Yes, - AdditionalNodesInfo.description - }, - { - TmPointPxThresholdInfo.identifier, - new DoubleVerifier, - Optional::Yes, - TmPointPxThresholdInfo.description - }, - { - FirstRowInfo.identifier, - new IntVerifier, - Optional::Yes, - FirstRowInfo.description - }, - { - LastRowInfo.identifier, - new IntVerifier, - Optional::Yes, - LastRowInfo.description - }, - { - ColumnNamesInfo.identifier, - new StringListVerifier, - Optional::Yes, - ColumnNamesInfo.description - }, - { - LodPixelThresholdInfo.identifier, - new DoubleVerifier, - Optional::Yes, - LodPixelThresholdInfo.description - }, - { - MaxGpuMemoryPercentInfo.identifier, - new DoubleVerifier, - Optional::Yes, - MaxGpuMemoryPercentInfo.description - }, - { - MaxCpuMemoryPercentInfo.identifier, - new DoubleVerifier, - Optional::Yes, - MaxCpuMemoryPercentInfo.description - }, - { - FilterPosXInfo.identifier, - new Vector2Verifier, - Optional::Yes, - FilterPosXInfo.description - }, - { - FilterPosYInfo.identifier, - new Vector2Verifier, - Optional::Yes, - FilterPosYInfo.description - }, - { - FilterPosZInfo.identifier, - new Vector2Verifier, - Optional::Yes, - FilterPosZInfo.description - }, - { - FilterGMagInfo.identifier, - new Vector2Verifier, - Optional::Yes, - FilterGMagInfo.description - }, - { - FilterBpRpInfo.identifier, - new Vector2Verifier, - Optional::Yes, - FilterBpRpInfo.description - }, - { - FilterDistInfo.identifier, - new Vector2Verifier, - Optional::Yes, - FilterDistInfo.description - }, - { - ReportGlErrorsInfo.identifier, - new BoolVerifier, - Optional::Yes, - ReportGlErrorsInfo.description - } - } - }; -} - -RenderableGaiaStars::RenderableGaiaStars(const ghoul::Dictionary& dictionary) - : Renderable(dictionary) - , _filePath(FilePathInfo) - , _fileReaderOption( - FileReaderOptionInfo, - properties::OptionProperty::DisplayType::Dropdown - ) - , _renderOption(RenderOptionInfo, properties::OptionProperty::DisplayType::Dropdown) - , _shaderOption(ShaderOptionInfo, properties::OptionProperty::DisplayType::Dropdown) - , _pointSpreadFunctionTexturePath(PsfTextureInfo) - , _colorTexturePath(ColorTextureInfo) - , _luminosityMultiplier(LuminosityMultiplierInfo, 35.f, 1.f, 1000.f) - , _magnitudeBoost(MagnitudeBoostInfo, 25.f, 0.f, 100.f) - , _cutOffThreshold(CutOffThresholdInfo, 38.f, 0.f, 50.f) - , _sharpness(SharpnessInfo, 1.45f, 0.f, 5.f) - , _billboardSize(BillboardSizeInfo, 10.f, 1.f, 100.f) - , _closeUpBoostDist(CloseUpBoostDistInfo, 300.f, 1.f, 1000.f) - , _tmPointFilterSize(TmPointFilterSizeInfo, 7, 1, 19) - , _tmPointSigma(TmPointSigmaInfo, 0.7f, 0.1f, 3.f) - , _additionalNodes(AdditionalNodesInfo, glm::ivec2(1), glm::ivec2(0), glm::ivec2(4)) - , _tmPointPixelWeightThreshold(TmPointPxThresholdInfo, 0.001f, 0.000001f, 0.01f) - , _lodPixelThreshold(LodPixelThresholdInfo, 250.f, 0.f, 5000.f) - , _maxGpuMemoryPercent(MaxGpuMemoryPercentInfo, 0.45f, 0.f, 1.f) - , _maxCpuMemoryPercent(MaxCpuMemoryPercentInfo, 0.5f, 0.f, 1.f) - , _posXThreshold(FilterPosXInfo, glm::vec2(0.f), glm::vec2(-10.f), glm::vec2(10.f)) - , _posYThreshold(FilterPosYInfo, glm::vec2(0.f), glm::vec2(-10.f), glm::vec2(10.f)) - , _posZThreshold(FilterPosZInfo, glm::vec2(0.f), glm::vec2(-10.f), glm::vec2(10.f)) - , _gMagThreshold(FilterGMagInfo, glm::vec2(20.f), glm::vec2(-10.f), glm::vec2(30.f)) - , _bpRpThreshold(FilterBpRpInfo, glm::vec2(0.f), glm::vec2(-10.f), glm::vec2(30.f)) - , _distThreshold(FilterDistInfo, glm::vec2(0.f), glm::vec2(0.f), glm::vec2(100.f)) - , _firstRow(FirstRowInfo, 0, 0, 2539913) // DR1-max: 2539913 - , _lastRow(LastRowInfo, 0, 0, 2539913) - , _columnNamesList(ColumnNamesInfo) - , _nRenderedStars(NumRenderedStarsInfo, 0, 0, 2000000000) // 2 Billion stars - , _cpuRamBudgetProperty(CpuRamBudgetInfo, 0.f, 0.f, 1.f) - , _gpuStreamBudgetProperty(GpuStreamBudgetInfo, 0.f, 0.f, 1.f) - , _reportGlErrors(ReportGlErrorsInfo, false) - , _accumulatedIndices(1, 0) -{ - using File = ghoul::filesystem::File; - - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "RenderableGaiaStars" - ); - - _filePath = absPath(dictionary.value(FilePathInfo.identifier)); - _dataFile = std::make_unique(_filePath); - _dataFile->setCallback([&](const File&) { _dataIsDirty = true; }); - - _filePath.onChange([&]() { _dataIsDirty = true; }); - addProperty(_filePath); - - _fileReaderOption.addOptions({ - { gaia::FileReaderOption::Fits, "Fits" }, - { gaia::FileReaderOption::Speck, "Speck" }, - { gaia::FileReaderOption::BinaryRaw, "BinaryRaw" }, - { gaia::FileReaderOption::BinaryOctree, "BinaryOctree" }, - { gaia::FileReaderOption::StreamOctree, "StreamOctree" } - }); - if (dictionary.hasKey(FileReaderOptionInfo.identifier)) { - const std::string fileReaderOption = dictionary.value( - FileReaderOptionInfo.identifier - ); - if (fileReaderOption == "Fits") { - _fileReaderOption = gaia::FileReaderOption::Fits; - } - else if (fileReaderOption == "Speck") { - _fileReaderOption = gaia::FileReaderOption::Speck; - } - else if (fileReaderOption == "BinaryRaw") { - _fileReaderOption = gaia::FileReaderOption::BinaryRaw; - } - else if (fileReaderOption == "BinaryOctree") { - _fileReaderOption = gaia::FileReaderOption::BinaryOctree; - } - else { - _fileReaderOption = gaia::FileReaderOption::StreamOctree; - } - } - - _renderOption.addOptions({ - { gaia::RenderOption::Static, "Static" }, - { gaia::RenderOption::Color, "Color" }, - { gaia::RenderOption::Motion, "Motion" } - }); - if (dictionary.hasKey(RenderOptionInfo.identifier)) { - const std::string renderOption = dictionary.value( - RenderOptionInfo.identifier - ); - if (renderOption == "Static") { - _renderOption = gaia::RenderOption::Static; - } - else if (renderOption == "Color") { - _renderOption = gaia::RenderOption::Color; - } - else { - _renderOption = gaia::RenderOption::Motion; - } - } - _renderOption.onChange([&]() { _buffersAreDirty = true; }); - addProperty(_renderOption); - -#ifndef __APPLE__ - _shaderOption.addOptions({ - { gaia::ShaderOption::Point_SSBO, "Point_SSBO" }, - { gaia::ShaderOption::Point_VBO, "Point_VBO" }, - { gaia::ShaderOption::Billboard_SSBO, "Billboard_SSBO" }, - { gaia::ShaderOption::Billboard_VBO, "Billboard_VBO" }, - { gaia::ShaderOption::Billboard_SSBO_noFBO, "Billboard_SSBO_noFBO" } - }); -#else // __APPLE__ - _shaderOption.addOptions({ - { gaia::ShaderOption::Point_VBO, "Point_VBO" }, - { gaia::ShaderOption::Billboard_VBO, "Billboard_VBO" }, - }); -#endif // __APPLE__ - - if (dictionary.hasKey(ShaderOptionInfo.identifier)) { - // Default shader option: - _shaderOption = gaia::ShaderOption::Billboard_VBO; - - const std::string shaderOption = dictionary.value( - ShaderOptionInfo.identifier - ); - -#ifndef __APPLE__ - if (shaderOption == "Point_SSBO") { - _shaderOption = gaia::ShaderOption::Point_SSBO; - } - else if (shaderOption == "Billboard_SSBO") { - _shaderOption = gaia::ShaderOption::Billboard_SSBO; - } - else if (shaderOption == "Billboard_SSBO_noFBO") { - _shaderOption = gaia::ShaderOption::Billboard_SSBO_noFBO; - } -#endif // __APPLE__ - - if (shaderOption == "Point_VBO") { - _shaderOption = gaia::ShaderOption::Point_VBO; - } - else if (shaderOption == "Billboard_VBO") { - _shaderOption = gaia::ShaderOption::Billboard_VBO; - } - } - _shaderOption.onChange([&]() { - _buffersAreDirty = true; - _shadersAreDirty = true; - }); - addProperty(_shaderOption); - - _pointSpreadFunctionTexturePath = absPath(dictionary.value( - PsfTextureInfo.identifier - )); - _pointSpreadFunctionFile = std::make_unique(_pointSpreadFunctionTexturePath); - - _pointSpreadFunctionTexturePath.onChange( - [&](){ _pointSpreadFunctionTextureIsDirty = true; } - ); - _pointSpreadFunctionFile->setCallback( - [&](const File&) { _pointSpreadFunctionTextureIsDirty = true; } - ); - - _colorTexturePath = absPath(dictionary.value( - ColorTextureInfo.identifier - )); - _colorTextureFile = std::make_unique(_colorTexturePath); - _colorTexturePath.onChange([&]() { _colorTextureIsDirty = true; }); - _colorTextureFile->setCallback([&](const File&) { _colorTextureIsDirty = true; }); - - if (dictionary.hasKey(LuminosityMultiplierInfo.identifier)) { - _luminosityMultiplier = static_cast( - dictionary.value(LuminosityMultiplierInfo.identifier) - ); - } - - if (dictionary.hasKey(MagnitudeBoostInfo.identifier)) { - _magnitudeBoost = static_cast( - dictionary.value(MagnitudeBoostInfo.identifier) - ); - } - - if (dictionary.hasKey(CutOffThresholdInfo.identifier)) { - _cutOffThreshold = static_cast( - dictionary.value(CutOffThresholdInfo.identifier) - ); - } - - if (dictionary.hasKey(SharpnessInfo.identifier)) { - _sharpness = static_cast( - dictionary.value(SharpnessInfo.identifier) - ); - } - - if (dictionary.hasKey(BillboardSizeInfo.identifier)) { - _billboardSize = static_cast( - dictionary.value(BillboardSizeInfo.identifier) - ); - } - - if (dictionary.hasKey(CloseUpBoostDistInfo.identifier)) { - _closeUpBoostDist = static_cast( - dictionary.value(CloseUpBoostDistInfo.identifier) - ); - } - - if (dictionary.hasKey(TmPointFilterSizeInfo.identifier)) { - _tmPointFilterSize = static_cast( - dictionary.value(TmPointFilterSizeInfo.identifier) - ); - } - - if (dictionary.hasKey(TmPointSigmaInfo.identifier)) { - _tmPointSigma = static_cast( - dictionary.value(TmPointSigmaInfo.identifier) - ); - } - if (dictionary.hasKey(TmPointPxThresholdInfo.identifier)) { - _tmPointPixelWeightThreshold = static_cast( - dictionary.value(TmPointPxThresholdInfo.identifier) - ); - } - - if (dictionary.hasKey(AdditionalNodesInfo.identifier)) { - _additionalNodes = static_cast( - dictionary.value(AdditionalNodesInfo.identifier) - ); - } - - if (dictionary.hasKey(LodPixelThresholdInfo.identifier)) { - _lodPixelThreshold = static_cast( - dictionary.value(LodPixelThresholdInfo.identifier) - ); - } - - if (dictionary.hasKey(MaxGpuMemoryPercentInfo.identifier)) { - _maxGpuMemoryPercent = static_cast( - dictionary.value(MaxGpuMemoryPercentInfo.identifier) - ); - } - _maxGpuMemoryPercent.onChange([&]() { - if (_ssboData != 0) { - glDeleteBuffers(1, &_ssboData); - glGenBuffers(1, &_ssboData); - LDEBUG(fmt::format( - "Re-generating Data Shader Storage Buffer Object id '{}'", _ssboData - )); - } - - // Find out our new budget. Use dedicated video memory instead of current - // available to always be consistant with previous call(s). - GLint nDedicatedVidMemoryInKB = 0; - glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &nDedicatedVidMemoryInKB); - float dedicatedVidMem = static_cast( - static_cast(nDedicatedVidMemoryInKB) * 1024 - ); - - // TODO: Need to fix what happens if we can't query! For now use 2 GB by default. - _gpuMemoryBudgetInBytes = dedicatedVidMem > 0 ? - static_cast(dedicatedVidMem * _maxGpuMemoryPercent) : - 2147483648; - _buffersAreDirty = true; - _maxStreamingBudgetInBytes = 0; - }); - - if (dictionary.hasKey(MaxCpuMemoryPercentInfo.identifier)) { - _maxCpuMemoryPercent = static_cast( - dictionary.value(MaxCpuMemoryPercentInfo.identifier) - ); - } - - if (dictionary.hasKey(FilterPosXInfo.identifier)) { - _posXThreshold = dictionary.value(FilterPosXInfo.identifier); - } - addProperty(_posXThreshold); - - if (dictionary.hasKey(FilterPosYInfo.identifier)) { - _posXThreshold = dictionary.value(FilterPosYInfo.identifier); - } - addProperty(_posYThreshold); - - if (dictionary.hasKey(FilterPosZInfo.identifier)) { - _posZThreshold = dictionary.value(FilterPosZInfo.identifier); - } - addProperty(_posZThreshold); - - if (dictionary.hasKey(FilterGMagInfo.identifier)) { - _gMagThreshold = dictionary.value(FilterGMagInfo.identifier); - } - addProperty(_gMagThreshold); - - if (dictionary.hasKey(FilterBpRpInfo.identifier)) { - _bpRpThreshold = dictionary.value(FilterBpRpInfo.identifier); - } - addProperty(_bpRpThreshold); - - if (dictionary.hasKey(FilterDistInfo.identifier)) { - _distThreshold = dictionary.value(FilterDistInfo.identifier); - } - addProperty(_distThreshold); - - // Only add properties correlated to fits files if we're reading from a fits file. - if (_fileReaderOption == gaia::FileReaderOption::Fits) { - if (dictionary.hasKey(FirstRowInfo.identifier)) { - _firstRow = static_cast( - dictionary.value(FirstRowInfo.identifier) - ); - } - _firstRow.onChange([&]() { _dataIsDirty = true; }); - addProperty(_firstRow); - - if (dictionary.hasKey(LastRowInfo.identifier)) { - _lastRow = static_cast(dictionary.value(LastRowInfo.identifier)); - } - _lastRow.onChange([&]() { _dataIsDirty = true; }); - addProperty(_lastRow); - - if (dictionary.hasKey(ColumnNamesInfo.identifier)) { - ghoul::Dictionary tmpDict = dictionary.value( - ColumnNamesInfo.identifier - ); - - // Ugly fix for ASCII sorting when there are more columns read than 10. - std::set intKeys; - for (const std::string& key : tmpDict.keys()) { - intKeys.insert(std::stoi(key)); - } - - for (int key : intKeys) { - _columnNames.push_back(tmpDict.value(std::to_string(key))); - } - - // Copy values to the StringListproperty to be shown in the Property list. - _columnNamesList = _columnNames; - // OBS - This is not used atm! - } - - if (_firstRow > _lastRow) { - throw ghoul::RuntimeError("User defined FirstRow is bigger than LastRow."); - } - } - - if (dictionary.hasKey(ReportGlErrorsInfo.identifier)) { - _reportGlErrors = dictionary.value(ReportGlErrorsInfo.identifier); - } - addProperty(_reportGlErrors); - - // Add a read-only property for the number of rendered stars per frame. - _nRenderedStars.setReadOnly(true); - addProperty(_nRenderedStars); - - // Add CPU RAM Budget Property and GPU Stream Budget Property to menu. - _cpuRamBudgetProperty.setReadOnly(true); - addProperty(_cpuRamBudgetProperty); - _gpuStreamBudgetProperty.setReadOnly(true); - addProperty(_gpuStreamBudgetProperty); -} - -bool RenderableGaiaStars::isReady() const { - return _program && _programTM; -} - -void RenderableGaiaStars::initializeGL() { - //using IgnoreError = ghoul::opengl::ProgramObject::IgnoreError; - //_program->setIgnoreUniformLocationError(IgnoreError::Yes); - - // Add common properties to menu. - addProperty(_colorTexturePath); - addProperty(_luminosityMultiplier); - addProperty(_cutOffThreshold); - addProperty(_lodPixelThreshold); - addProperty(_maxGpuMemoryPercent); - - // Construct shader program depending on user-defined shader option. - const int option = _shaderOption; - switch (option) { - case gaia::ShaderOption::Point_SSBO: { - _program = ghoul::opengl::ProgramObject::Build( - "GaiaStar", - absPath("${MODULE_GAIA}/shaders/gaia_ssbo_vs.glsl"), - absPath("${MODULE_GAIA}/shaders/gaia_point_fs.glsl"), - absPath("${MODULE_GAIA}/shaders/gaia_point_ge.glsl") - ); - _uniformCache.maxStarsPerNode = _program->uniformLocation("maxStarsPerNode"); - _uniformCache.valuesPerStar = _program->uniformLocation("valuesPerStar"); - _uniformCache.nChunksToRender = _program->uniformLocation("nChunksToRender"); - - _programTM = global::renderEngine.buildRenderProgram( - "ToneMapping", - absPath("${MODULE_GAIA}/shaders/gaia_tonemapping_vs.glsl"), - absPath("${MODULE_GAIA}/shaders/gaia_tonemapping_point_fs.glsl") - ); - _uniformCacheTM.screenSize = _programTM->uniformLocation("screenSize"); - _uniformCacheTM.filterSize = _programTM->uniformLocation("filterSize"); - _uniformCacheTM.sigma = _programTM->uniformLocation("sigma"); - _uniformCacheTM.projection = _programTM->uniformLocation("projection"); - _uniformCacheTM.pixelWeightThreshold = - _programTM->uniformLocation("pixelWeightThreshold"); - - addProperty(_tmPointFilterSize); - addProperty(_tmPointSigma); - addProperty(_tmPointPixelWeightThreshold); - break; - } - case gaia::ShaderOption::Point_VBO: { - _program = ghoul::opengl::ProgramObject::Build( - "GaiaStar", - absPath("${MODULE_GAIA}/shaders/gaia_vbo_vs.glsl"), - absPath("${MODULE_GAIA}/shaders/gaia_point_fs.glsl"), - absPath("${MODULE_GAIA}/shaders/gaia_point_ge.glsl") - ); - - _programTM = global::renderEngine.buildRenderProgram("ToneMapping", - absPath("${MODULE_GAIA}/shaders/gaia_tonemapping_vs.glsl"), - absPath("${MODULE_GAIA}/shaders/gaia_tonemapping_point_fs.glsl") - ); - _uniformCacheTM.screenSize = _programTM->uniformLocation("screenSize"); - _uniformCacheTM.filterSize = _programTM->uniformLocation("filterSize"); - _uniformCacheTM.sigma = _programTM->uniformLocation("sigma"); - _uniformCacheTM.projection = _programTM->uniformLocation("projection"); - _uniformCacheTM.pixelWeightThreshold = - _programTM->uniformLocation("pixelWeightThreshold"); - - addProperty(_tmPointFilterSize); - addProperty(_tmPointSigma); - addProperty(_tmPointPixelWeightThreshold); - break; - } - case gaia::ShaderOption::Billboard_SSBO: { - _program = ghoul::opengl::ProgramObject::Build( - "GaiaStar", - absPath("${MODULE_GAIA}/shaders/gaia_ssbo_vs.glsl"), - absPath("${MODULE_GAIA}/shaders/gaia_billboard_fs.glsl"), - absPath("${MODULE_GAIA}/shaders/gaia_billboard_ge.glsl") - ); - _uniformCache.cameraPos = _program->uniformLocation("cameraPos"); - _uniformCache.cameraLookUp = _program->uniformLocation("cameraLookUp"); - _uniformCache.magnitudeBoost = _program->uniformLocation("magnitudeBoost"); - _uniformCache.sharpness = _program->uniformLocation("sharpness"); - _uniformCache.billboardSize = _program->uniformLocation("billboardSize"); - _uniformCache.closeUpBoostDist = _program->uniformLocation( - "closeUpBoostDist" - ); - _uniformCache.psfTexture = _program->uniformLocation("psfTexture"); - - _uniformCache.maxStarsPerNode = _program->uniformLocation("maxStarsPerNode"); - _uniformCache.valuesPerStar = _program->uniformLocation("valuesPerStar"); - _uniformCache.nChunksToRender = _program->uniformLocation("nChunksToRender"); - - _programTM = global::renderEngine.buildRenderProgram( - "ToneMapping", - absPath("${MODULE_GAIA}/shaders/gaia_tonemapping_vs.glsl"), - absPath("${MODULE_GAIA}/shaders/gaia_tonemapping_billboard_fs.glsl") - ); - - addProperty(_magnitudeBoost); - addProperty(_sharpness); - addProperty(_billboardSize); - addProperty(_closeUpBoostDist); - //addProperty(_pointSpreadFunctionTexturePath); - break; - } - case gaia::ShaderOption::Billboard_SSBO_noFBO: { - _program = global::renderEngine.buildRenderProgram("GaiaStar", - absPath("${MODULE_GAIA}/shaders/gaia_ssbo_vs.glsl"), - absPath("${MODULE_GAIA}/shaders/gaia_billboard_nofbo_fs.glsl"), - absPath("${MODULE_GAIA}/shaders/gaia_billboard_ge.glsl") - ); - _uniformCache.cameraPos = _program->uniformLocation("cameraPos"); - _uniformCache.cameraLookUp = _program->uniformLocation("cameraLookUp"); - _uniformCache.magnitudeBoost = _program->uniformLocation("magnitudeBoost"); - _uniformCache.sharpness = _program->uniformLocation("sharpness"); - _uniformCache.billboardSize = _program->uniformLocation("billboardSize"); - _uniformCache.closeUpBoostDist = _program->uniformLocation( - "closeUpBoostDist" - ); - _uniformCache.psfTexture = _program->uniformLocation("psfTexture"); - - _uniformCache.maxStarsPerNode = _program->uniformLocation("maxStarsPerNode"); - _uniformCache.valuesPerStar = _program->uniformLocation("valuesPerStar"); - _uniformCache.nChunksToRender = _program->uniformLocation("nChunksToRender"); - - addProperty(_magnitudeBoost); - addProperty(_sharpness); - addProperty(_billboardSize); - addProperty(_closeUpBoostDist); - break; - } - case gaia::ShaderOption::Billboard_VBO: { - _program = ghoul::opengl::ProgramObject::Build( - "GaiaStar", - absPath("${MODULE_GAIA}/shaders/gaia_vbo_vs.glsl"), - absPath("${MODULE_GAIA}/shaders/gaia_billboard_fs.glsl"), - absPath("${MODULE_GAIA}/shaders/gaia_billboard_ge.glsl") - ); - _uniformCache.cameraPos = _program->uniformLocation("cameraPos"); - _uniformCache.cameraLookUp = _program->uniformLocation("cameraLookUp"); - _uniformCache.magnitudeBoost = _program->uniformLocation("magnitudeBoost"); - _uniformCache.sharpness = _program->uniformLocation("sharpness"); - _uniformCache.billboardSize = _program->uniformLocation("billboardSize"); - _uniformCache.closeUpBoostDist = _program->uniformLocation( - "closeUpBoostDist" - ); - _uniformCache.psfTexture = _program->uniformLocation("psfTexture"); - - _programTM = global::renderEngine.buildRenderProgram("ToneMapping", - absPath("${MODULE_GAIA}/shaders/gaia_tonemapping_vs.glsl"), - absPath("${MODULE_GAIA}/shaders/gaia_tonemapping_billboard_fs.glsl") - ); - - addProperty(_magnitudeBoost); - addProperty(_sharpness); - addProperty(_billboardSize); - addProperty(_closeUpBoostDist); - //addProperty(_pointSpreadFunctionTexturePath); - break; - } - } - - // Common uniforms for all shaders: - _uniformCache.model = _program->uniformLocation("model"); - _uniformCache.view = _program->uniformLocation("view"); - _uniformCache.projection = _program->uniformLocation("projection"); - _uniformCache.time = _program->uniformLocation("time"); - _uniformCache.renderOption = _program->uniformLocation("renderOption"); - _uniformCache.viewScaling = _program->uniformLocation("viewScaling"); - _uniformCache.cutOffThreshold = _program->uniformLocation("cutOffThreshold"); - _uniformCache.luminosityMultiplier = _program->uniformLocation( - "luminosityMultiplier" - ); - _uniformCache.colorTexture = _program->uniformLocation("colorTexture"); - - _uniformFilterCache.posXThreshold = _program->uniformLocation("posXThreshold"); - _uniformFilterCache.posYThreshold = _program->uniformLocation("posYThreshold"); - _uniformFilterCache.posZThreshold = _program->uniformLocation("posZThreshold"); - _uniformFilterCache.gMagThreshold = _program->uniformLocation("gMagThreshold"); - _uniformFilterCache.bpRpThreshold = _program->uniformLocation("bpRpThreshold"); - _uniformFilterCache.distThreshold = _program->uniformLocation("distThreshold"); - - _uniformCacheTM.renderedTexture = _programTM->uniformLocation("renderedTexture"); - - - // Find out how much GPU memory this computer has (Nvidia cards). - GLint nDedicatedVidMemoryInKB = 0; - glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &nDedicatedVidMemoryInKB); - GLint nTotalMemoryInKB = 0; - glGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, &nTotalMemoryInKB); - GLint nCurrentAvailMemoryInKB = 0; - glGetIntegerv( - GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, - &nCurrentAvailMemoryInKB - ); - - LDEBUG(fmt::format( - "nDedicatedVidMemoryKB: {} - nTotalMemoryKB: {} - nCurrentAvailMemoryKB: {}", - nDedicatedVidMemoryInKB, nTotalMemoryInKB, nCurrentAvailMemoryInKB - )); - - // Set ceiling for video memory to use in streaming. - float dedicatedVidMem = static_cast( - static_cast(nDedicatedVidMemoryInKB) * 1024 - ); - // TODO: Need to fix what happens if we can't query! For now use 2 GB by default. - _gpuMemoryBudgetInBytes = dedicatedVidMem > 0 ? - static_cast(dedicatedVidMem * _maxGpuMemoryPercent) : - 2147483648; - - // Set ceiling for how much of the installed CPU RAM to use for streaming - long long installedRam = static_cast(CpuCap.installedMainMemory()) * - 1024 * 1024; - // TODO: What to do if we can't query? As for now we use 4 GB by default. - _cpuRamBudgetInBytes = installedRam > 0 ? - static_cast(static_cast(installedRam) * _maxCpuMemoryPercent) : - 4294967296; - _cpuRamBudgetProperty.setMaxValue(static_cast(_cpuRamBudgetInBytes)); - - LDEBUG(fmt::format( - "GPU Memory Budget (bytes): {} - CPU RAM Budget (bytes): {}", - _gpuMemoryBudgetInBytes, _cpuRamBudgetInBytes - )); -} - -void RenderableGaiaStars::deinitializeGL() { - if (_vboPos != 0) { - glDeleteBuffers(1, &_vboPos); - _vboPos = 0; - } - if (_vboCol != 0) { - glDeleteBuffers(1, &_vboCol); - _vboCol = 0; - } - if (_vboVel != 0) { - glDeleteBuffers(1, &_vboVel); - _vboVel = 0; - } - if (_ssboIdx != 0) { - glDeleteBuffers(1, &_ssboIdx); - _ssboIdx = 0; - glDeleteBuffers(1, &_ssboData); - _ssboData = 0; - } - if (_vao != 0) { - glDeleteVertexArrays(1, &_vao); - _vao = 0; - } - if (_vaoEmpty != 0) { - glDeleteVertexArrays(1, &_vaoEmpty); - _vaoEmpty = 0; - } - - glDeleteBuffers(1, &_vboQuad); - _vboQuad = 0; - glDeleteVertexArrays(1, &_vaoQuad); - _vaoQuad = 0; - glDeleteFramebuffers(1, &_fbo); - _fbo = 0; - - _dataFile = nullptr; - _pointSpreadFunctionTexture = nullptr; - _colorTexture = nullptr; - _fboTexture = nullptr; - - if (_program) { - global::renderEngine.removeRenderProgram(_program.get()); - _program = nullptr; - } - if (_programTM) { - global::renderEngine.removeRenderProgram(_programTM.get()); - _programTM = nullptr; - } -} - -void RenderableGaiaStars::render(const RenderData& data, RendererTasks&) { - checkGlErrors("Before render"); - - // Save current FBO. - GLint defaultFbo; - glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFbo); - - glm::dmat4 model = glm::translate(glm::dmat4(1.0), data.modelTransform.translation) * - glm::dmat4(data.modelTransform.rotation) * - glm::dmat4(glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale))); - - float viewScaling = data.camera.scaling(); - glm::dmat4 view = data.camera.combinedViewMatrix(); - glm::dmat4 projection = data.camera.projectionMatrix(); - - glm::dmat4 modelViewProjMat = projection * view * model; - glm::vec2 screenSize = glm::vec2(global::renderEngine.renderingResolution()); - - // Wait until camera has stabilized before we traverse the Octree/stream from files. - const double rotationDiff = abs(length(_previousCameraRotation) - - length(data.camera.rotationQuaternion())); - if (_firstDrawCalls && rotationDiff > 1e-10) { - _previousCameraRotation = data.camera.rotationQuaternion(); - return; - } - else { - _firstDrawCalls = false; - } - - // Update which nodes that are stored in memory as the camera moves around - // (if streaming) - if (_fileReaderOption == gaia::FileReaderOption::StreamOctree) { - glm::dvec3 cameraPos = data.camera.positionVec3(); - size_t chunkSizeBytes = _chunkSize * sizeof(GLfloat); - _octreeManager.fetchSurroundingNodes(cameraPos, chunkSizeBytes, _additionalNodes); - - // Update CPU Budget property. - _cpuRamBudgetProperty = static_cast(_octreeManager.cpuRamBudget()); - } - - // Traverse Octree and build a map with new nodes to render, uses mvp matrix to decide - const int renderOption = _renderOption; - int deltaStars = 0; - std::map> updateData = _octreeManager.traverseData( - modelViewProjMat, - screenSize, - deltaStars, - gaia::RenderOption(renderOption), - _lodPixelThreshold - ); - - // Update number of rendered stars. - _nStarsToRender += deltaStars; - _nRenderedStars = _nStarsToRender; - - // Update GPU Stream Budget property. - _gpuStreamBudgetProperty = static_cast(_octreeManager.numFreeSpotsInBuffer()); - - int nChunksToRender = static_cast(_octreeManager.biggestChunkIndexInUse()); - int maxStarsPerNode = static_cast(_octreeManager.maxStarsPerNode()); - int valuesPerStar = static_cast(_nRenderValuesPerStar); - - // Switch rendering technique depending on user-defined shader option. - const int shaderOption = _shaderOption; - if (shaderOption == gaia::ShaderOption::Billboard_SSBO || - shaderOption == gaia::ShaderOption::Point_SSBO || - shaderOption == gaia::ShaderOption::Billboard_SSBO_noFBO) - { -#ifndef __APPLE__ - //------------------------ RENDER WITH SSBO --------------------------- - // Update SSBO Index array with accumulated stars in all chunks. - glBindBuffer(GL_SHADER_STORAGE_BUFFER, _ssboIdx); - int lastValue = _accumulatedIndices.back(); - _accumulatedIndices.resize(nChunksToRender + 1, lastValue); - - // Update vector with accumulated indices. - for (const auto& [offset, subData] : updateData) { - int newValue = static_cast(subData.size() / _nRenderValuesPerStar) + - _accumulatedIndices[offset]; - int changeInValue = newValue - _accumulatedIndices[offset + 1]; - _accumulatedIndices[offset + 1] = newValue; - // Propagate change. - for (int i = offset + 1; i < nChunksToRender; ++i) { - _accumulatedIndices[i + 1] += changeInValue; - } - } - - // Fix number of stars rendered if it doesn't correspond to our buffers. - if (_accumulatedIndices.back() != _nStarsToRender) { - _nStarsToRender = _accumulatedIndices.back(); - _nRenderedStars = _nStarsToRender; - } - - size_t indexBufferSize = _accumulatedIndices.size() * sizeof(GLint); - - // Update SSBO Index (stars per chunk). - glBufferData( - GL_SHADER_STORAGE_BUFFER, - indexBufferSize, - _accumulatedIndices.data(), - GL_STREAM_DRAW - ); - - // Use orphaning strategy for data SSBO. - glBindBuffer(GL_SHADER_STORAGE_BUFFER, _ssboData); - - glBufferData( - GL_SHADER_STORAGE_BUFFER, - _maxStreamingBudgetInBytes, - nullptr, - GL_STREAM_DRAW - ); - - // Update SSBO with one insert per chunk/node. - // The key in map holds the offset index. - for (const auto &[offset, subData] : updateData) { - // We don't need to fill chunk with zeros for SSBOs! - // Just check if we have any values to update. - if (!subData.empty()) { - glBufferSubData( - GL_SHADER_STORAGE_BUFFER, - offset * _chunkSize * sizeof(GLfloat), - subData.size() * sizeof(GLfloat), - subData.data() - ); - } - } - - glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); -#endif // !__APPLE__ - } - else { - //---------------------- RENDER WITH VBO ----------------------------- - // Update VBOs with new nodes. - // This will overwrite old data that's not visible anymore as well. - glBindVertexArray(_vao); - - // Always update Position VBO. - glBindBuffer(GL_ARRAY_BUFFER, _vboPos); - float posMemoryShare = static_cast(PositionSize) / _nRenderValuesPerStar; - size_t posChunkSize = maxStarsPerNode * PositionSize; - long long posStreamingBudget = static_cast( - _maxStreamingBudgetInBytes * posMemoryShare - ); - - // Use buffer orphaning to update a subset of total data. - glBufferData( - GL_ARRAY_BUFFER, - posStreamingBudget, - nullptr, - GL_STREAM_DRAW - ); - - // Update buffer with one insert per chunk/node. - //The key in map holds the offset index. - for (const auto& [offset, subData] : updateData) { - // Fill chunk by appending zeroes so we overwrite possible earlier values. - // Only required when removing nodes because chunks are filled up in octree - // fetch on add. - std::vector vectorData(subData.begin(), subData.end()); - vectorData.resize(posChunkSize, 0.f); - glBufferSubData( - GL_ARRAY_BUFFER, - offset * posChunkSize * sizeof(GLfloat), - posChunkSize * sizeof(GLfloat), - vectorData.data() - ); - } - - // Update Color VBO if render option is 'Color' or 'Motion'. - if (renderOption != gaia::RenderOption::Static) { - glBindBuffer(GL_ARRAY_BUFFER, _vboCol); - float colMemoryShare = static_cast(ColorSize) / _nRenderValuesPerStar; - size_t colChunkSize = maxStarsPerNode * ColorSize; - long long colStreamingBudget = static_cast( - _maxStreamingBudgetInBytes * colMemoryShare - ); - - // Use buffer orphaning to update a subset of total data. - glBufferData( - GL_ARRAY_BUFFER, - colStreamingBudget, - nullptr, - GL_STREAM_DRAW - ); - - // Update buffer with one insert per chunk/node. - //The key in map holds the offset index. - for (const auto& [offset, subData] : updateData) { - // Fill chunk by appending zeroes so we overwrite possible earlier values. - std::vector vectorData(subData.begin(), subData.end()); - vectorData.resize(posChunkSize + colChunkSize, 0.f); - glBufferSubData( - GL_ARRAY_BUFFER, - offset * colChunkSize * sizeof(GLfloat), - colChunkSize * sizeof(GLfloat), - vectorData.data() + posChunkSize - ); - } - - // Update Velocity VBO if specified. - if (renderOption == gaia::RenderOption::Motion) { - glBindBuffer(GL_ARRAY_BUFFER, _vboVel); - float velMemoryShare = static_cast(VelocitySize) / - _nRenderValuesPerStar; - size_t velChunkSize = maxStarsPerNode * VelocitySize; - long long velStreamingBudget = static_cast( - _maxStreamingBudgetInBytes * velMemoryShare - ); - - // Use buffer orphaning to update a subset of total data. - glBufferData( - GL_ARRAY_BUFFER, - velStreamingBudget, - nullptr, - GL_STREAM_DRAW - ); - - // Update buffer with one insert per chunk/node. - //The key in map holds the offset index. - for (const auto& [offset, subData] : updateData) { - // Fill chunk by appending zeroes. - std::vector vectorData(subData.begin(), subData.end()); - vectorData.resize(_chunkSize, 0.f); - glBufferSubData( - GL_ARRAY_BUFFER, - offset * velChunkSize * sizeof(GLfloat), - velChunkSize * sizeof(GLfloat), - vectorData.data() + posChunkSize + colChunkSize - ); - } - } - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); - } - - checkGlErrors("After buffer updates"); - - // Activate shader program and send uniforms. - glBlendFunc(GL_SRC_ALPHA, GL_ONE); - glDepthMask(false); - _program->activate(); - - _program->setUniform(_uniformCache.model, model); - _program->setUniform(_uniformCache.view, view); - _program->setUniform(_uniformCache.projection, projection); - _program->setUniform( - _uniformCache.time, - static_cast(data.time.j2000Seconds()) - ); - _program->setUniform(_uniformCache.renderOption, _renderOption); - _program->setUniform(_uniformCache.viewScaling, viewScaling); - _program->setUniform(_uniformCache.cutOffThreshold, _cutOffThreshold); - _program->setUniform(_uniformCache.luminosityMultiplier, _luminosityMultiplier); - - // Send filterValues. - _program->setUniform(_uniformFilterCache.posXThreshold, _posXThreshold); - _program->setUniform(_uniformFilterCache.posYThreshold, _posYThreshold); - _program->setUniform(_uniformFilterCache.posZThreshold, _posZThreshold); - _program->setUniform(_uniformFilterCache.gMagThreshold, _gMagThreshold); - _program->setUniform(_uniformFilterCache.bpRpThreshold, _bpRpThreshold); - _program->setUniform(_uniformFilterCache.distThreshold, _distThreshold); - - ghoul::opengl::TextureUnit colorUnit; - if (_colorTexture) { - colorUnit.activate(); - _colorTexture->bind(); - _program->setUniform(_uniformCache.colorTexture, colorUnit); - } - - // Specify how many stars we will render. Will be overwritten if rendering billboards - GLsizei nShaderCalls = _nStarsToRender; - - ghoul::opengl::TextureUnit psfUnit; - switch (shaderOption) { - case gaia::ShaderOption::Point_SSBO: { - _program->setUniform(_uniformCache.maxStarsPerNode, maxStarsPerNode); - _program->setUniform(_uniformCache.valuesPerStar, valuesPerStar); - _program->setUniform(_uniformCache.nChunksToRender, nChunksToRender); - break; - } - case gaia::ShaderOption::Point_VBO: { - // Specify how many potential stars we have to render. - nShaderCalls = maxStarsPerNode * nChunksToRender; - break; - } - case gaia::ShaderOption::Billboard_SSBO: - case gaia::ShaderOption::Billboard_SSBO_noFBO: { - _program->setUniform( - _uniformCache.cameraPos, - data.camera.positionVec3() - ); - _program->setUniform( - _uniformCache.cameraLookUp, - data.camera.lookUpVectorWorldSpace() - ); - _program->setUniform(_uniformCache.maxStarsPerNode, maxStarsPerNode); - _program->setUniform(_uniformCache.valuesPerStar, valuesPerStar); - _program->setUniform(_uniformCache.nChunksToRender, nChunksToRender); - - _program->setUniform(_uniformCache.closeUpBoostDist, - _closeUpBoostDist * static_cast(distanceconstants::Parsec) - ); - _program->setUniform(_uniformCache.billboardSize, _billboardSize); - _program->setUniform(_uniformCache.magnitudeBoost, _magnitudeBoost); - _program->setUniform(_uniformCache.sharpness, _sharpness); - - psfUnit.activate(); - _pointSpreadFunctionTexture->bind(); - _program->setUniform(_uniformCache.psfTexture, psfUnit); - break; - } - case gaia::ShaderOption::Billboard_VBO: { - _program->setUniform( - _uniformCache.cameraPos, - data.camera.positionVec3() - ); - _program->setUniform( - _uniformCache.cameraLookUp, - data.camera.lookUpVectorWorldSpace() - ); - _program->setUniform(_uniformCache.closeUpBoostDist, - _closeUpBoostDist * static_cast(distanceconstants::Parsec) - ); - _program->setUniform(_uniformCache.billboardSize, _billboardSize); - _program->setUniform(_uniformCache.magnitudeBoost, _magnitudeBoost); - _program->setUniform(_uniformCache.sharpness, _sharpness); - - psfUnit.activate(); - _pointSpreadFunctionTexture->bind(); - _program->setUniform(_uniformCache.psfTexture, psfUnit); - - // Specify how many potential stars we have to render. - nShaderCalls = maxStarsPerNode * nChunksToRender; - break; - } - } - - if (shaderOption != gaia::ShaderOption::Billboard_SSBO_noFBO) { - // Render to FBO. - glBindFramebuffer(GL_FRAMEBUFFER, _fbo); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } - - //glEnable(GL_PROGRAM_POINT_SIZE); - // A non-zero named vao MUST ALWAYS be bound! - if (_useVBO) { - glBindVertexArray(_vao); - } - else { - glBindVertexArray(_vaoEmpty); - } - - glDrawArrays(GL_POINTS, 0, nShaderCalls); - glBindVertexArray(0); - //glDisable(GL_PROGRAM_POINT_SIZE); - _program->deactivate(); - - if (shaderOption != gaia::ShaderOption::Billboard_SSBO_noFBO) { - // Use ToneMapping shaders and render to default FBO again! - _programTM->activate(); - - glBindFramebuffer(GL_FRAMEBUFFER, defaultFbo); - - ghoul::opengl::TextureUnit fboTexUnit; - if (_fboTexture) { - fboTexUnit.activate(); - _fboTexture->bind(); - _programTM->setUniform(_uniformCacheTM.renderedTexture, fboTexUnit); - } - - if (shaderOption == gaia::ShaderOption::Point_SSBO || - shaderOption == gaia::ShaderOption::Point_VBO) - { - _programTM->setUniform(_uniformCacheTM.screenSize, screenSize); - _programTM->setUniform(_uniformCacheTM.filterSize, _tmPointFilterSize); - _programTM->setUniform(_uniformCacheTM.sigma, _tmPointSigma); - _programTM->setUniform(_uniformCacheTM.projection, projection); - _programTM->setUniform( - _uniformCacheTM.pixelWeightThreshold, - _tmPointPixelWeightThreshold - ); - } - - glBindVertexArray(_vaoQuad); - glDrawArrays(GL_TRIANGLES, 0, 6); // 2 triangles - glBindVertexArray(0); - - _programTM->deactivate(); - } - - glDepthMask(true); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - checkGlErrors("After render"); -} - -void RenderableGaiaStars::checkGlErrors(const std::string& identifier) const { - if (_reportGlErrors) { - GLenum error = glGetError(); - if (error != GL_NO_ERROR) { - switch (error) { - case GL_INVALID_ENUM: - LINFO(identifier + " - GL_INVALID_ENUM"); - break; - case GL_INVALID_VALUE: - LINFO(identifier + " - GL_INVALID_VALUE"); - break; - case GL_INVALID_OPERATION: - LINFO(identifier + " - GL_INVALID_OPERATION"); - break; - case GL_INVALID_FRAMEBUFFER_OPERATION: - LINFO(identifier + " - GL_INVALID_FRAMEBUFFER_OPERATION"); - break; - case GL_OUT_OF_MEMORY: - LINFO(identifier + " - GL_OUT_OF_MEMORY"); - break; - default: - LINFO(identifier + " - Unknown error"); - break; - } - } - } -} - -void RenderableGaiaStars::update(const UpdateData&) { - const int shaderOption = _shaderOption; - const int renderOption = _renderOption; - - // Don't update anything if we are in the middle of a rebuild. - if (_octreeManager.isRebuildOngoing()) { - return; - } - - if (_dataIsDirty) { - LDEBUG("Regenerating data"); - // Reload data file. This may reconstruct the Octree as well. - bool success = readDataFile(); - if (!success) { - throw ghoul::RuntimeError("Error loading Gaia Star data"); - } - _dataIsDirty = false; - // Make sure we regenerate buffers if data has reloaded! - _buffersAreDirty = true; - } - - if (_program->isDirty() || _shadersAreDirty) { - switch (shaderOption) { - case gaia::ShaderOption::Point_SSBO: { -#ifndef __APPLE__ - std::unique_ptr program = - ghoul::opengl::ProgramObject::Build( - "GaiaStar", - absPath("${MODULE_GAIA}/shaders/gaia_ssbo_vs.glsl"), - absPath("${MODULE_GAIA}/shaders/gaia_point_fs.glsl"), - absPath("${MODULE_GAIA}/shaders/gaia_point_ge.glsl") - ); - if (_program) { - global::renderEngine.removeRenderProgram(_program.get()); - } - _program = std::move(program); - - _uniformCache.maxStarsPerNode = _program->uniformLocation( - "maxStarsPerNode" - ); - _uniformCache.valuesPerStar = _program->uniformLocation( - "valuesPerStar" - ); - _uniformCache.nChunksToRender = _program->uniformLocation( - "nChunksToRender" - ); - - // If rebuild was triggered by switching ShaderOption then ssboBinding may - // not have been initialized yet. Binding will happen in later in - // buffersAredirty. - if (!_shadersAreDirty) { - _program->setSsboBinding( - "ssbo_idx_data", - _ssboIdxBinding->bindingNumber() - ); - _program->setSsboBinding( - "ssbo_comb_data", - _ssboDataBinding->bindingNumber() - ); - } - if (hasProperty(&_magnitudeBoost)) { - removeProperty(_magnitudeBoost); - } - if (hasProperty(&_sharpness)) { - removeProperty(_sharpness); - } - if (hasProperty(&_billboardSize)) { - removeProperty(_billboardSize); - } - if (hasProperty(&_closeUpBoostDist)) { - removeProperty(_closeUpBoostDist); - } - if (hasProperty(&_pointSpreadFunctionTexturePath)) { - removeProperty(_pointSpreadFunctionTexturePath); - } - if (!hasProperty(&_tmPointFilterSize)) { - addProperty(_tmPointFilterSize); - } - if (!hasProperty(&_tmPointSigma)) { - addProperty(_tmPointSigma); - } - if (!hasProperty(&_tmPointPixelWeightThreshold)) { - addProperty(_tmPointPixelWeightThreshold); - } - #endif // !__APPLE__ - break; - } - case gaia::ShaderOption::Point_VBO: { - std::unique_ptr program = - ghoul::opengl::ProgramObject::Build( - "GaiaStar", - absPath("${MODULE_GAIA}/shaders/gaia_vbo_vs.glsl"), - absPath("${MODULE_GAIA}/shaders/gaia_point_fs.glsl"), - absPath("${MODULE_GAIA}/shaders/gaia_point_ge.glsl") - ); - if (_program) { - global::renderEngine.removeRenderProgram(_program.get()); - } - _program = std::move(program); - - if (hasProperty(&_magnitudeBoost)) { - removeProperty(_magnitudeBoost); - } - if (hasProperty(&_sharpness)) { - removeProperty(_sharpness); - } - if (hasProperty(&_billboardSize)) { - removeProperty(_billboardSize); - } - if (hasProperty(&_closeUpBoostDist)) { - removeProperty(_closeUpBoostDist); - } - if (hasProperty(&_pointSpreadFunctionTexturePath)) { - removeProperty(_pointSpreadFunctionTexturePath); - } - if (!hasProperty(&_tmPointFilterSize)) { - addProperty(_tmPointFilterSize); - } - if (!hasProperty(&_tmPointSigma)) { - addProperty(_tmPointSigma); - } - if (!hasProperty(&_tmPointPixelWeightThreshold)) { - addProperty(_tmPointPixelWeightThreshold); - } - break; - } - case gaia::ShaderOption::Billboard_SSBO: - case gaia::ShaderOption::Billboard_SSBO_noFBO: { - #ifndef __APPLE__ - std::unique_ptr program; - if (shaderOption == gaia::ShaderOption::Billboard_SSBO) { - program = ghoul::opengl::ProgramObject::Build( - "GaiaStar", - absPath("${MODULE_GAIA}/shaders/gaia_ssbo_vs.glsl"), - absPath("${MODULE_GAIA}/shaders/gaia_billboard_fs.glsl"), - absPath("${MODULE_GAIA}/shaders/gaia_billboard_ge.glsl") - ); - } - else { - program = global::renderEngine.buildRenderProgram("GaiaStar", - absPath("${MODULE_GAIA}/shaders/gaia_ssbo_vs.glsl"), - absPath("${MODULE_GAIA}/shaders/gaia_billboard_nofbo_fs.glsl"), - absPath("${MODULE_GAIA}/shaders/gaia_billboard_ge.glsl") - ); - } - - if (_program) { - global::renderEngine.removeRenderProgram(_program.get()); - } - _program = std::move(program); - - _uniformCache.cameraPos = _program->uniformLocation("cameraPos"); - _uniformCache.cameraLookUp = _program->uniformLocation("cameraLookUp"); - _uniformCache.magnitudeBoost = _program->uniformLocation( - "magnitudeBoost" - ); - _uniformCache.sharpness = _program->uniformLocation("sharpness"); - _uniformCache.billboardSize = _program->uniformLocation("billboardSize"); - _uniformCache.closeUpBoostDist = _program->uniformLocation( - "closeUpBoostDist" - ); - _uniformCache.psfTexture = _program->uniformLocation("psfTexture"); - - _uniformCache.maxStarsPerNode = _program->uniformLocation( - "maxStarsPerNode" - ); - _uniformCache.valuesPerStar = _program->uniformLocation("valuesPerStar"); - _uniformCache.nChunksToRender = _program->uniformLocation( - "nChunksToRender" - ); - - // If rebuild was triggered by switching ShaderOption then ssboBinding - // may not have been initialized yet. Binding will happen in later in - // buffersAredirty. - if (!_shadersAreDirty) { - _program->setSsboBinding( - "ssbo_idx_data", - _ssboIdxBinding->bindingNumber() - ); - _program->setSsboBinding( - "ssbo_comb_data", - _ssboDataBinding->bindingNumber() - ); - } - - if (!hasProperty(&_magnitudeBoost)) { - addProperty(_magnitudeBoost); - } - if (!hasProperty(&_sharpness)) { - addProperty(_sharpness); - } - if (!hasProperty(&_billboardSize)) { - addProperty(_billboardSize); - } - if (!hasProperty(&_closeUpBoostDist)) { - addProperty(_closeUpBoostDist); - } - if (!hasProperty(&_pointSpreadFunctionTexturePath)) { - addProperty(_pointSpreadFunctionTexturePath); - } - if (hasProperty(&_tmPointFilterSize)) { - removeProperty(_tmPointFilterSize); - } - if (hasProperty(&_tmPointSigma)) { - removeProperty(_tmPointSigma); - } - if (hasProperty(&_tmPointPixelWeightThreshold)) { - removeProperty(_tmPointPixelWeightThreshold); - } - #endif // !__APPLE__ - break; - } - case gaia::ShaderOption::Billboard_VBO: { - std::unique_ptr program = - ghoul::opengl::ProgramObject::Build( - "GaiaStar", - absPath("${MODULE_GAIA}/shaders/gaia_vbo_vs.glsl"), - absPath("${MODULE_GAIA}/shaders/gaia_billboard_fs.glsl"), - absPath("${MODULE_GAIA}/shaders/gaia_billboard_ge.glsl") - ); - if (_program) { - global::renderEngine.removeRenderProgram(_program.get()); - } - _program = std::move(program); - - _uniformCache.cameraPos = _program->uniformLocation("cameraPos"); - _uniformCache.cameraLookUp = _program->uniformLocation("cameraLookUp"); - _uniformCache.magnitudeBoost = _program->uniformLocation( - "magnitudeBoost" - ); - _uniformCache.sharpness = _program->uniformLocation("sharpness"); - _uniformCache.billboardSize = _program->uniformLocation("billboardSize"); - _uniformCache.closeUpBoostDist = _program->uniformLocation( - "closeUpBoostDist" - ); - _uniformCache.psfTexture = _program->uniformLocation("psfTexture"); - - if (!hasProperty(&_magnitudeBoost)) { - addProperty(_magnitudeBoost); - } - if (!hasProperty(&_sharpness)) { - addProperty(_sharpness); - } - if (!hasProperty(&_billboardSize)) { - addProperty(_billboardSize); - } - if (!hasProperty(&_closeUpBoostDist)) { - addProperty(_closeUpBoostDist); - } - if (!hasProperty(&_pointSpreadFunctionTexturePath)) { - addProperty(_pointSpreadFunctionTexturePath); - } - if (hasProperty(&_tmPointFilterSize)) { - removeProperty(_tmPointFilterSize); - } - if (hasProperty(&_tmPointSigma)) { - removeProperty(_tmPointSigma); - } - if (hasProperty(&_tmPointPixelWeightThreshold)) { - removeProperty(_tmPointPixelWeightThreshold); - } - break; - } - } - - // Common uniforms for all shaders: - _uniformCache.model = _program->uniformLocation("model"); - _uniformCache.view = _program->uniformLocation("view"); - _uniformCache.projection = _program->uniformLocation("projection"); - _uniformCache.time = _program->uniformLocation("time"); - _uniformCache.renderOption = _program->uniformLocation("renderOption"); - _uniformCache.viewScaling = _program->uniformLocation("viewScaling"); - _uniformCache.cutOffThreshold = _program->uniformLocation("cutOffThreshold"); - _uniformCache.luminosityMultiplier = _program->uniformLocation( - "luminosityMultiplier" - ); - _uniformCache.colorTexture = _program->uniformLocation("colorTexture"); - // Filter uniforms: - _uniformFilterCache.posXThreshold = _program->uniformLocation("posXThreshold"); - _uniformFilterCache.posYThreshold = _program->uniformLocation("posYThreshold"); - _uniformFilterCache.posZThreshold = _program->uniformLocation("posZThreshold"); - _uniformFilterCache.gMagThreshold = _program->uniformLocation("gMagThreshold"); - _uniformFilterCache.bpRpThreshold = _program->uniformLocation("bpRpThreshold"); - _uniformFilterCache.distThreshold = _program->uniformLocation("distThreshold"); - } - - if (_programTM->isDirty() || _shadersAreDirty) { - switch (shaderOption) { - case gaia::ShaderOption::Point_SSBO: - case gaia::ShaderOption::Point_VBO: { - std::unique_ptr programTM = - global::renderEngine.buildRenderProgram( - "ToneMapping", - absPath("${MODULE_GAIA}/shaders/gaia_tonemapping_vs.glsl"), - absPath("${MODULE_GAIA}/shaders/gaia_tonemapping_point_fs.glsl") - ); - if (_programTM) { - global::renderEngine.removeRenderProgram(_programTM.get()); - } - _programTM = std::move(programTM); - - _uniformCacheTM.screenSize = _programTM->uniformLocation("screenSize"); - _uniformCacheTM.filterSize = _programTM->uniformLocation("filterSize"); - _uniformCacheTM.sigma = _programTM->uniformLocation("sigma"); - _uniformCacheTM.projection = _programTM->uniformLocation("projection"); - _uniformCacheTM.pixelWeightThreshold = _programTM->uniformLocation( - "pixelWeightThreshold" - ); - break; - } - case gaia::ShaderOption::Billboard_SSBO: - case gaia::ShaderOption::Billboard_VBO: { - std::string vs = absPath( - "${MODULE_GAIA}/shaders/gaia_tonemapping_vs.glsl" - ); - std::string fs = absPath( - "${MODULE_GAIA}/shaders/gaia_tonemapping_billboard_fs.glsl" - ); - std::unique_ptr programTM = - global::renderEngine.buildRenderProgram("ToneMapping", vs, fs); - if (_programTM) { - global::renderEngine.removeRenderProgram(_programTM.get()); - } - _programTM = std::move(programTM); - break; - } - } - // Common uniforms: - _uniformCacheTM.renderedTexture = _programTM->uniformLocation("renderedTexture"); - - _shadersAreDirty = false; - } - - if (_buffersAreDirty) { - LDEBUG("Regenerating buffers"); - - // Set values per star slice depending on render option. - if (renderOption == gaia::RenderOption::Static) { - _nRenderValuesPerStar = PositionSize; - } - else if (renderOption == gaia::RenderOption::Color) { - _nRenderValuesPerStar = PositionSize + ColorSize; - } - else { // (renderOption == gaia::RenderOption::Motion) - _nRenderValuesPerStar = PositionSize + ColorSize + VelocitySize; - } - - // Calculate memory budgets. - _chunkSize = _octreeManager.maxStarsPerNode() * _nRenderValuesPerStar; - long long totalChunkSizeInBytes = _octreeManager.totalNodes() * - _chunkSize * sizeof(GLfloat); - _maxStreamingBudgetInBytes = std::min( - totalChunkSizeInBytes, - _gpuMemoryBudgetInBytes - ); - long long maxNodesInStream = _maxStreamingBudgetInBytes / - (_chunkSize * sizeof(GLfloat)); - - _gpuStreamBudgetProperty.setMaxValue(static_cast(maxNodesInStream)); - bool datasetFitInMemory = - static_cast(_totalDatasetSizeInBytes) < (_cpuRamBudgetInBytes * 0.9f); - - if (!datasetFitInMemory && !hasProperty(&_additionalNodes)) { - addProperty(_additionalNodes); - } - else if (hasProperty(&_additionalNodes)) { - removeProperty(_additionalNodes); - } - - LDEBUG(fmt::format( - "Chunk size: {} - Max streaming budget (bytes): {} - Max nodes in stream: {}", - _chunkSize, _maxStreamingBudgetInBytes, maxNodesInStream - )); - - // ------------------ RENDER WITH SSBO ----------------------- - if (shaderOption == gaia::ShaderOption::Billboard_SSBO || - shaderOption == gaia::ShaderOption::Point_SSBO || - shaderOption == gaia::ShaderOption::Billboard_SSBO_noFBO) - { -#ifndef __APPLE__ - _useVBO = false; - - // Trigger a rebuild of buffer data from octree. - // With SSBO we won't fill the chunks. - _octreeManager.initBufferIndexStack( - maxNodesInStream, - _useVBO, - datasetFitInMemory - ); - _nStarsToRender = 0; - - // Generate SSBO Buffers and bind them. - if (_vaoEmpty == 0) { - glGenVertexArrays(1, &_vaoEmpty); - LDEBUG(fmt::format("Generating Empty Vertex Array id '{}'", _vaoEmpty)); - } - if (_ssboIdx == 0) { - glGenBuffers(1, &_ssboIdx); - LDEBUG(fmt::format( - "Generating Index Shader Storage Buffer Object id '{}'", _ssboIdx - )); - } - if (_ssboData == 0) { - glGenBuffers(1, &_ssboData); - LDEBUG(fmt::format( - "Generating Data Shader Storage Buffer Object id '{}'", _ssboData - )); - } - - // Bind SSBO blocks to our shader positions. - // Number of stars per chunk (a.k.a. Index). - glBindBuffer(GL_SHADER_STORAGE_BUFFER, _ssboIdx); - - _ssboIdxBinding = std::make_unique - >(); - glBindBufferBase( - GL_SHADER_STORAGE_BUFFER, - _ssboIdxBinding->bindingNumber(), - _ssboIdx - ); - _program->setSsboBinding("ssbo_idx_data", _ssboIdxBinding->bindingNumber()); - - // Combined SSBO with all data. - glBindBuffer(GL_SHADER_STORAGE_BUFFER, _ssboData); - - _ssboDataBinding = std::make_unique - >(); - glBindBufferBase( - GL_SHADER_STORAGE_BUFFER, - _ssboDataBinding->bindingNumber(), - _ssboData - ); - _program->setSsboBinding("ssbo_comb_data", _ssboDataBinding->bindingNumber()); - - glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); - - // Deallocate VBO Buffers if any existed. - if (_vboPos != 0) { - glBindBuffer(GL_ARRAY_BUFFER, _vboPos); - glBufferData( - GL_ARRAY_BUFFER, - 0, - nullptr, - GL_STREAM_DRAW - ); - } - if (_vboCol != 0) { - glBindBuffer(GL_ARRAY_BUFFER, _vboCol); - glBufferData( - GL_ARRAY_BUFFER, - 0, - nullptr, - GL_STREAM_DRAW - ); - } - if (_vboVel != 0) { - glBindBuffer(GL_ARRAY_BUFFER, _vboVel); - glBufferData( - GL_ARRAY_BUFFER, - 0, - nullptr, - GL_STREAM_DRAW - ); - } - glBindBuffer(GL_ARRAY_BUFFER, 0); -#endif // !__APPLE__ - } - else { // ------------------ RENDER WITH VBO ----------------------- - _useVBO = true; - - // Trigger a rebuild of buffer data from octree. - // With VBO we will fill the chunks. - _octreeManager.initBufferIndexStack( - maxNodesInStream, - _useVBO, - datasetFitInMemory - ); - _nStarsToRender = 0; - - // Generate VAO and VBOs - if (_vao == 0) { - glGenVertexArrays(1, &_vao); - LDEBUG(fmt::format("Generating Vertex Array id '{}'", _vao)); - } - if (_vboPos == 0) { - glGenBuffers(1, &_vboPos); - LDEBUG(fmt::format( - "Generating Position Vertex Buffer Object id '{}'", _vboPos - )); - } - if (_vboCol == 0) { - glGenBuffers(1, &_vboCol); - LDEBUG(fmt::format( - "Generating Color Vertex Buffer Object id '{}'", _vboCol - )); - } - if (_vboVel == 0) { - glGenBuffers(1, &_vboVel); - LDEBUG(fmt::format( - "Generating Velocity Vertex Buffer Object id '{}'", _vboVel - )); - } - - // Bind our different VBOs to our vertex array layout. - glBindVertexArray(_vao); - - switch (renderOption) { - case gaia::RenderOption::Static: { - glBindBuffer(GL_ARRAY_BUFFER, _vboPos); - GLint positionAttrib = _program->attributeLocation("in_position"); - glEnableVertexAttribArray(positionAttrib); - - glVertexAttribPointer( - positionAttrib, - PositionSize, - GL_FLOAT, - GL_FALSE, - 0, - nullptr - ); - - break; - } - case gaia::RenderOption::Color: { - glBindBuffer(GL_ARRAY_BUFFER, _vboPos); - GLint positionAttrib = _program->attributeLocation("in_position"); - glEnableVertexAttribArray(positionAttrib); - - glVertexAttribPointer( - positionAttrib, - PositionSize, - GL_FLOAT, - GL_FALSE, - 0, - nullptr - ); - - glBindBuffer(GL_ARRAY_BUFFER, _vboCol); - GLint brightnessAttrib = _program->attributeLocation("in_brightness"); - glEnableVertexAttribArray(brightnessAttrib); - - glVertexAttribPointer( - brightnessAttrib, - ColorSize, - GL_FLOAT, - GL_FALSE, - 0, - nullptr - ); - break; - } - case gaia::RenderOption::Motion: { - glBindBuffer(GL_ARRAY_BUFFER, _vboPos); - GLint positionAttrib = _program->attributeLocation("in_position"); - glEnableVertexAttribArray(positionAttrib); - - glVertexAttribPointer( - positionAttrib, - PositionSize, - GL_FLOAT, - GL_FALSE, - 0, - nullptr - ); - - glBindBuffer(GL_ARRAY_BUFFER, _vboCol); - GLint brightnessAttrib = _program->attributeLocation("in_brightness"); - glEnableVertexAttribArray(brightnessAttrib); - - glVertexAttribPointer( - brightnessAttrib, - ColorSize, - GL_FLOAT, - GL_FALSE, - 0, - nullptr - ); - - glBindBuffer(GL_ARRAY_BUFFER, _vboVel); - GLint velocityAttrib = _program->attributeLocation("in_velocity"); - glEnableVertexAttribArray(velocityAttrib); - - glVertexAttribPointer( - velocityAttrib, - VelocitySize, - GL_FLOAT, - GL_FALSE, - 0, - nullptr - ); - break; - } - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); - -#ifndef __APPLE__ - // Deallocate SSBO buffers if they existed. - if (_ssboIdx != 0) { - glBindBuffer(GL_SHADER_STORAGE_BUFFER, _ssboIdx); - glBufferData( - GL_SHADER_STORAGE_BUFFER, - 0, - nullptr, - GL_STREAM_DRAW - ); - } - if (_ssboData != 0) { - glBindBuffer(GL_SHADER_STORAGE_BUFFER, _ssboData); - glBufferData( - GL_SHADER_STORAGE_BUFFER, - 0, - nullptr, - GL_STREAM_DRAW - ); - } - glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); -#endif //!__APPLE__ - } - - // Generate VAO and VBO for Quad. - if (_vaoQuad == 0) { - glGenVertexArrays(1, &_vaoQuad); - LDEBUG(fmt::format("Generating Quad Vertex Array id '{}'", _vaoQuad)); - } - if (_vboQuad == 0) { - glGenBuffers(1, &_vboQuad); - LDEBUG(fmt::format("Generating Quad Vertex Buffer Object id '{}'", _vboQuad)); - } - - // Bind VBO and VAO for Quad rendering. - glBindVertexArray(_vaoQuad); - glBindBuffer(GL_ARRAY_BUFFER, _vboQuad); - - // Quad for fullscreen. - static const GLfloat vbo_quad_data[] = { - -1.0f, -1.0f, 0.0f, - 1.0f, -1.0f, 0.0f, - -1.0f, 1.0f, 0.0f, - -1.0f, 1.0f, 0.0f, - 1.0f, -1.0f, 0.0f, - 1.0f, 1.0f, 0.0f, - }; - - glBufferData( - GL_ARRAY_BUFFER, - sizeof(vbo_quad_data), - vbo_quad_data, - GL_STATIC_DRAW - ); - - GLint tmPositionAttrib = _programTM->attributeLocation("in_position"); - glEnableVertexAttribArray(tmPositionAttrib); - glVertexAttribPointer( - tmPositionAttrib, - 3, - GL_FLOAT, - GL_FALSE, - 0, - nullptr - ); - - glEnableVertexAttribArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); - - // Generate Framebuffer Object and Texture. - if (_fbo == 0) { - glGenFramebuffers(1, &_fbo); - LDEBUG(fmt::format("Generating Framebuffer Object id '{}'", _fbo)); - } - if (!_fboTexture) { - // Generate a new texture and attach it to our FBO. - glm::vec2 screenSize = glm::vec2(global::renderEngine.renderingResolution()); - _fboTexture = std::make_unique( - glm::uvec3(screenSize, 1), - ghoul::opengl::Texture::Format::RGBA, - GL_RGBA32F, - GL_FLOAT - ); - _fboTexture->uploadTexture(); - LDEBUG("Generating Framebuffer Texture!"); - } - // Bind render texture to FBO. - glBindFramebuffer(GL_FRAMEBUFFER, _fbo); - glBindTexture(GL_TEXTURE_2D, *_fboTexture); - glFramebufferTexture( - GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - *_fboTexture, - 0 - ); - GLenum textureBuffers[1] = { GL_COLOR_ATTACHMENT0 }; - glDrawBuffers(1, textureBuffers); - - // Check that our framebuffer is ok. - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - LERROR("Error when generating GaiaStar Framebuffer."); - } - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - _buffersAreDirty = false; - } - - if (_pointSpreadFunctionTextureIsDirty) { - LDEBUG("Reloading Point Spread Function texture"); - _pointSpreadFunctionTexture = nullptr; - if (!_pointSpreadFunctionTexturePath.value().empty()) { - _pointSpreadFunctionTexture = ghoul::io::TextureReader::ref().loadTexture( - absPath(_pointSpreadFunctionTexturePath) - ); - - if (_pointSpreadFunctionTexture) { - LDEBUG(fmt::format( - "Loaded texture from '{}'", absPath(_pointSpreadFunctionTexturePath) - )); - _pointSpreadFunctionTexture->uploadTexture(); - } - _pointSpreadFunctionTexture->setFilter( - ghoul::opengl::Texture::FilterMode::AnisotropicMipMap - ); - - _pointSpreadFunctionFile = std::make_unique( - _pointSpreadFunctionTexturePath - ); - _pointSpreadFunctionFile->setCallback( - [&](const ghoul::filesystem::File&) { - _pointSpreadFunctionTextureIsDirty = true; - } - ); - } - _pointSpreadFunctionTextureIsDirty = false; - } - - if (_colorTextureIsDirty) { - LDEBUG("Reloading Color Texture"); - _colorTexture = nullptr; - if (!_colorTexturePath.value().empty()) { - _colorTexture = ghoul::io::TextureReader::ref().loadTexture( - absPath(_colorTexturePath) - ); - if (_colorTexture) { - LDEBUG(fmt::format( - "Loaded texture from '{}'", absPath(_colorTexturePath) - )); - _colorTexture->uploadTexture(); - } - - _colorTextureFile = std::make_unique( - _colorTexturePath - ); - _colorTextureFile->setCallback( - [&](const ghoul::filesystem::File&) { _colorTextureIsDirty = true; } - ); - } - _colorTextureIsDirty = false; - } - - if (global::windowDelegate.windowHasResized()) { - // Update FBO texture resolution if we haven't already. - glm::vec2 screenSize = glm::vec2(global::renderEngine.renderingResolution()); - const bool hasChanged = glm::any( - glm::notEqual(_fboTexture->dimensions(), glm::uvec3(screenSize, 1)) - ); - - if (hasChanged) { - _fboTexture = std::make_unique( - glm::uvec3(screenSize, 1), - ghoul::opengl::Texture::Format::RGBA, - GL_RGBA32F, - GL_FLOAT - ); - _fboTexture->uploadTexture(); - LDEBUG("Re-Generating Gaia Framebuffer Texture!"); - - glBindFramebuffer(GL_FRAMEBUFFER, _fbo); - glBindTexture(GL_TEXTURE_2D, *_fboTexture); - glFramebufferTexture( - GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - *_fboTexture, - 0 - ); - GLenum textureBuffers[1] = { GL_COLOR_ATTACHMENT0 }; - glDrawBuffers(1, textureBuffers); - - // Check that our framebuffer is ok. - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - LERROR("Error when re-generating GaiaStar Framebuffer."); - } - glBindFramebuffer(GL_FRAMEBUFFER, 0); - } - } -} - -bool RenderableGaiaStars::readDataFile() { - const int fileReaderOption = _fileReaderOption; - int nReadStars = 0; - - _octreeManager.initOctree(_cpuRamBudgetInBytes); - - LINFO("Loading data file: " + _filePath.value()); - - switch (fileReaderOption) { - case gaia::FileReaderOption::Fits: - // Read raw fits file and construct Octree. - nReadStars = readFitsFile(_filePath); - break; - case gaia::FileReaderOption::Speck: - // Read raw speck file and construct Octree. - nReadStars = readSpeckFile(_filePath); - break; - case gaia::FileReaderOption::BinaryRaw: - // Stars are stored in an ordered binary file. - nReadStars = readBinaryRawFile(_filePath); - break; - case gaia::FileReaderOption::BinaryOctree: - // Octree already constructed and stored as a binary file. - nReadStars = readBinaryOctreeFile(_filePath); - break; - case gaia::FileReaderOption::StreamOctree: - // Read Octree structure from file, without data. - nReadStars = readBinaryOctreeStructureFile(_filePath); - break; - default: - LERROR("Wrong FileReaderOption - no data file loaded!"); - break; - } - - //_octreeManager->printStarsPerNode(); - _nRenderedStars.setMaxValue(nReadStars); - LINFO("Dataset contains a total of " + std::to_string(nReadStars) + " stars."); - _totalDatasetSizeInBytes = nReadStars * (PositionSize + ColorSize + VelocitySize) * 4; - - return nReadStars > 0; -} - -int RenderableGaiaStars::readFitsFile(const std::string& filePath) { - int nReadValuesPerStar = 0; - - FitsFileReader fitsFileReader(false); - std::vector fullData = fitsFileReader.readFitsFile( - filePath, - nReadValuesPerStar, - _firstRow, - _lastRow, - _columnNames - ); - - // Insert stars into octree. - for (size_t i = 0; i < fullData.size(); i += nReadValuesPerStar) { - auto first = fullData.begin() + i; - auto last = fullData.begin() + i + nReadValuesPerStar; - std::vector starValues(first, last); - - _octreeManager.insert(starValues); - } - _octreeManager.sliceLodData(); - return static_cast(fullData.size() / nReadValuesPerStar); -} - -int RenderableGaiaStars::readSpeckFile(const std::string& filePath) { - int nReadValuesPerStar = 0; - - FitsFileReader fileReader(false); - std::vector fullData = fileReader.readSpeckFile(filePath, nReadValuesPerStar); - - // Insert stars into octree. - for (size_t i = 0; i < fullData.size(); i += nReadValuesPerStar) { - auto first = fullData.begin() + i; - auto last = fullData.begin() + i + nReadValuesPerStar; - std::vector starValues(first, last); - - _octreeManager.insert(starValues); - } - _octreeManager.sliceLodData(); - return static_cast(fullData.size() / nReadValuesPerStar); -} - -int RenderableGaiaStars::readBinaryRawFile(const std::string& filePath) { - std::vector fullData; - int nReadStars = 0; - - std::ifstream fileStream(filePath, std::ifstream::binary); - if (fileStream.good()) { - int32_t nValues = 0; - int32_t nReadValuesPerStar = 0; - int renderValues = 8; - fileStream.read(reinterpret_cast(&nValues), sizeof(int32_t)); - fileStream.read(reinterpret_cast(&nReadValuesPerStar), sizeof(int32_t)); - - fullData.resize(nValues); - fileStream.read( - reinterpret_cast(fullData.data()), - nValues * sizeof(fullData[0]) - ); - - // Insert stars into octree. - for (size_t i = 0; i < fullData.size(); i += nReadValuesPerStar) { - auto first = fullData.begin() + i; - auto last = fullData.begin() + i + renderValues; - std::vector starValues(first, last); - - _octreeManager.insert(starValues); - } - _octreeManager.sliceLodData(); - - nReadStars = nValues / nReadValuesPerStar; - fileStream.close(); - } - else { - LERROR(fmt::format( - "Error opening file '{}' for loading raw binary file!", filePath - )); - return nReadStars; - } - return nReadStars; -} - -int RenderableGaiaStars::readBinaryOctreeFile(const std::string& filePath) { - int nReadStars = 0; - - std::ifstream fileStream(filePath, std::ifstream::binary); - if (fileStream.good()) { - nReadStars = _octreeManager.readFromFile(fileStream, true); - - fileStream.close(); - } - else { - LERROR(fmt::format( - "Error opening file '{}' for loading binary Octree file!", filePath - )); - return nReadStars; - } - return nReadStars; -} - -int RenderableGaiaStars::readBinaryOctreeStructureFile(const std::string& folderPath) { - int nReadStars = 0; - std::string indexFile = folderPath + "index.bin"; - - std::ifstream fileStream(indexFile, std::ifstream::binary); - if (fileStream.good()) { - nReadStars = _octreeManager.readFromFile(fileStream, false, folderPath); - - fileStream.close(); - } - else { - LERROR(fmt::format( - "Error opening file '{}' for loading binary Octree file!", indexFile - )); - return nReadStars; - } - return nReadStars; -} - -} // namespace openspace diff --git a/modules/softwareintegration/rendering/renderablegaiastars.h b/modules/softwareintegration/rendering/renderablegaiastars.h deleted file mode 100644 index dfde5abc04..0000000000 --- a/modules/softwareintegration/rendering/renderablegaiastars.h +++ /dev/null @@ -1,216 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2020 * - * * - * 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 __OPENSPACE_MODULE_GAIA___RENDERABLEGAIASTARS___H__ -#define __OPENSPACE_MODULE_GAIA___RENDERABLEGAIASTARS___H__ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ghoul::filesystem { class File; } -namespace ghoul::opengl { - class ProgramObject; - class Texture; -} // namespace ghoul::opengl - -namespace openspace { - -namespace documentation { struct Documentation; } - -class RenderableGaiaStars : public Renderable { -public: - explicit RenderableGaiaStars(const ghoul::Dictionary& dictionary); - virtual ~RenderableGaiaStars() = default; - - void initializeGL() override; - void deinitializeGL() override; - - bool isReady() const override; - - void render(const RenderData& data, RendererTasks& rendererTask) override; - void update(const UpdateData& data) override; - - static documentation::Documentation Documentation(); - -private: - /** - * Reads data file in format defined by FileReaderOption. - * - * \return true if data was successfully read. - */ - bool readDataFile(); - - /** - * Reads a FITS file by using FitsFileReader.readFitsFile() and constructs an octree. - * - * \return the number of stars read. - */ - int readFitsFile(const std::string& filePath); - - /** - * Read a SPECK file by using FitsFileReader.readSpeckFile() and constructs an octree. - * - * \return the number of stars read. - */ - int readSpeckFile(const std::string& filePath); - - /** - * Reads a preprocessed binary file and constructs an octree. - * - * \return the number of stars read. - */ - int readBinaryRawFile(const std::string& filePath); - - /** - * Reads a pre-constructed octree, with all data, from a binary file. - * - * \return the number of stars read. - */ - int readBinaryOctreeFile(const std::string& filePath); - - /** - * Reads the structure of a pre-constructed octree from a binary file, without any - * data. - * - * \return the number of stars read. - */ - int readBinaryOctreeStructureFile(const std::string& folderPath); - - /** - * Checks for any OpenGL errors and reports these to the log if _reportGlErrors is - * set to true. - */ - void checkGlErrors(const std::string& identifier) const; - - properties::StringProperty _filePath; - std::unique_ptr _dataFile; - bool _dataIsDirty = true; - bool _buffersAreDirty = true; - bool _shadersAreDirty = false; - - properties::StringProperty _pointSpreadFunctionTexturePath; - std::unique_ptr _pointSpreadFunctionTexture; - std::unique_ptr _pointSpreadFunctionFile; - bool _pointSpreadFunctionTextureIsDirty = true; - - properties::StringProperty _colorTexturePath; - std::unique_ptr _colorTexture; - std::unique_ptr _colorTextureFile; - bool _colorTextureIsDirty = true; - - properties::FloatProperty _luminosityMultiplier; - properties::FloatProperty _magnitudeBoost; - properties::FloatProperty _cutOffThreshold; - properties::FloatProperty _sharpness; - properties::FloatProperty _billboardSize; - properties::FloatProperty _closeUpBoostDist; - properties::IntProperty _tmPointFilterSize; - properties::FloatProperty _tmPointSigma; - properties::IVec2Property _additionalNodes; - properties::FloatProperty _tmPointPixelWeightThreshold; - properties::FloatProperty _lodPixelThreshold; - - properties::Vec2Property _posXThreshold; - properties::Vec2Property _posYThreshold; - properties::Vec2Property _posZThreshold; - properties::Vec2Property _gMagThreshold; - properties::Vec2Property _bpRpThreshold; - properties::Vec2Property _distThreshold; - - properties::IntProperty _firstRow; - properties::IntProperty _lastRow; - properties::StringListProperty _columnNamesList; - std::vector _columnNames; - properties::OptionProperty _fileReaderOption; - properties::OptionProperty _renderOption; - properties::OptionProperty _shaderOption; - properties::IntProperty _nRenderedStars; - // LongLongProperty doesn't show up in menu, use FloatProperty instead. - properties::FloatProperty _cpuRamBudgetProperty; - properties::FloatProperty _gpuStreamBudgetProperty; - properties::FloatProperty _maxGpuMemoryPercent; - properties::FloatProperty _maxCpuMemoryPercent; - - properties::BoolProperty _reportGlErrors; - - std::unique_ptr _program; - UniformCache(model, view, cameraPos, cameraLookUp, viewScaling, projection, - renderOption, luminosityMultiplier, magnitudeBoost, cutOffThreshold, - sharpness, billboardSize, closeUpBoostDist, screenSize, psfTexture, - time, colorTexture, nChunksToRender, valuesPerStar, maxStarsPerNode) - _uniformCache; - - UniformCache(posXThreshold, posYThreshold, posZThreshold, gMagThreshold, - bpRpThreshold, distThreshold) _uniformFilterCache; - - std::unique_ptr _programTM; - UniformCache(renderedTexture, screenSize, filterSize, sigma, pixelWeightThreshold, - projection) _uniformCacheTM; - std::unique_ptr _fboTexture; - - OctreeManager _octreeManager; - std::unique_ptr> _ssboIdxBinding; - std::unique_ptr> _ssboDataBinding; - - std::vector _accumulatedIndices; - size_t _nRenderValuesPerStar = 0; - int _nStarsToRender = 0; - bool _firstDrawCalls = true; - glm::dquat _previousCameraRotation = glm::dquat(1.0, 0.0, 0.0, 0.0); - bool _useVBO = false; - long long _cpuRamBudgetInBytes = 0; - long long _totalDatasetSizeInBytes = 0; - long long _gpuMemoryBudgetInBytes = 0; - long long _maxStreamingBudgetInBytes = 0; - size_t _chunkSize = 0; - - GLuint _vao = 0; - GLuint _vaoEmpty = 0; - GLuint _vboPos = 0; - GLuint _vboCol = 0; - GLuint _vboVel = 0; - GLuint _ssboIdx = 0; - GLuint _ssboData = 0; - GLuint _vaoQuad = 0; - GLuint _vboQuad = 0; - GLuint _fbo = 0; -}; - -} // namespace openspace - -#endif // __OPENSPACE_MODULE_GAIA___RENDERABLEGAIASTARS___H__ diff --git a/modules/softwareintegration/shaders/gaia_billboard_fs.glsl b/modules/softwareintegration/shaders/gaia_billboard_fs.glsl deleted file mode 100644 index d9b9ebbbd5..0000000000 --- a/modules/softwareintegration/shaders/gaia_billboard_fs.glsl +++ /dev/null @@ -1,114 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2020 * - * * - * 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. * - ****************************************************************************************/ - -#version __CONTEXT__ - -#include "floatoperations.glsl" - -layout (location = 0) out vec4 outColor; - -// Keep in sync with gaiaoptions.h:RenderOption enum -const int RENDEROPTION_STATIC = 0; -const int RENDEROPTION_COLOR = 1; -const int RENDEROPTION_MOTION = 2; -const float ONE_PARSEC = 3.08567758e16; // 1 Parsec -const float FLT_MAX = 3.402823466e38; // Max float constant in GLSL -const float LUM_LOWER_CAP = 0.01; - -in vec2 ge_brightness; -in vec4 ge_gPosition; -in vec2 texCoord; -in float ge_starDistFromSun; -in float ge_cameraDistFromSun; -in float ge_observedDist; - -uniform sampler2D psfTexture; -uniform sampler1D colorTexture; -uniform float luminosityMultiplier; -uniform float sharpness; -uniform int renderOption; - -vec3 color2rgb(float color) { - // BV is [-0.4, 2.0] - float st = (color + 0.4) / (2.0 + 0.4); - - // Bp-Rp[-2.0, 6.5], Bp-G[-2.1, 5.0], G-Rp[-1.0, 3.0] - //float st = (color + 1.0) / (5.0 + 1.0); - - return texture(colorTexture, st).rgb; -} - -void main() { - - // Assume all stars has equal luminosity as the Sun when no magnitude is loaded. - float luminosity = 0.05; - vec3 color = vec3(luminosity); - float ratioMultiplier = 0.05; - - vec4 textureColor = texture(psfTexture, texCoord); - textureColor.a = pow(textureColor.a, sharpness); - if (textureColor.a < 0.001) { - discard; - } - - // Calculate the color and luminosity if we have the magnitude and B-V color. - if ( renderOption != RENDEROPTION_STATIC ) { - color = color2rgb(ge_brightness.y); - ratioMultiplier = 0.5; - - // Absolute magnitude is brightness a star would have at 10 pc away. - float absoluteMagnitude = ge_brightness.x; - - // From formula: MagSun - MagStar = 2.5*log(LumStar / LumSun), it gives that: - // LumStar = 10^(1.89 - 0.4*Magstar) , if LumSun = 1 and MagSun = 4.72 - luminosity = pow(10.0, 1.89 - 0.4 * absoluteMagnitude); - - // If luminosity is really really small then set it to a static low number. - if (luminosity < LUM_LOWER_CAP) { - luminosity = LUM_LOWER_CAP; - } - } - - // Luminosity decrease by {squared} distance [measured in Pc]. - float observedDistance = ge_observedDist / ONE_PARSEC; - luminosity /= pow(observedDistance, 2.0); - - // Multiply our color with the luminosity as well as a user-controlled property. - color *= luminosity * pow(luminosityMultiplier, 3.0); - - // Decrease contributing brightness for stars in central cluster. - if ( ge_cameraDistFromSun > ge_starDistFromSun ) { - float ratio = ge_starDistFromSun / ge_cameraDistFromSun; - //color *= ratio * ratioMultiplier; - } - - // Use truncating tonemapping here so we don't overexposure individual stars. - //color = 1.0 - 1.0 * exp(-5.0 * color.rgb); - float maxVal = max(max(color.r, color.g), color.b); - if (maxVal > 1.0) { - color /= maxVal; - } - - outColor = vec4(color, textureColor.a); -} diff --git a/modules/softwareintegration/shaders/gaia_billboard_ge.glsl b/modules/softwareintegration/shaders/gaia_billboard_ge.glsl deleted file mode 100644 index 3296ae1fa2..0000000000 --- a/modules/softwareintegration/shaders/gaia_billboard_ge.glsl +++ /dev/null @@ -1,132 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2020 * - * * - * 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. * - ****************************************************************************************/ - -#version __CONTEXT__ - -#include "floatoperations.glsl" - -// Keep in sync with gaiaoptions.h:RenderOption enum -const int RENDEROPTION_STATIC = 0; -const int RENDEROPTION_COLOR = 1; -const int RENDEROPTION_MOTION = 2; -const float EPS = 1e-5; - -layout(points) in; -in vec2 vs_brightness[]; -in vec4 vs_gPosition[]; -in float vs_starDistFromSun[]; -in float vs_cameraDistFromSun[]; - -layout(triangle_strip, max_vertices = 4) out; -out vec2 ge_brightness; -out vec4 ge_gPosition; -out vec2 texCoord; -out float ge_starDistFromSun; -out float ge_cameraDistFromSun; -out float ge_observedDist; - -uniform dmat4 view; -uniform dmat4 projection; - -uniform dvec3 cameraPos; -uniform dvec3 cameraLookUp; -uniform float viewScaling; -uniform float cutOffThreshold; -uniform float closeUpBoostDist; -uniform float billboardSize; -uniform int renderOption; -uniform float magnitudeBoost; - -const vec2 corners[4] = vec2[4]( - vec2(0.0, 1.0), - vec2(0.0, 0.0), - vec2(1.0, 1.0), - vec2(1.0, 0.0) -); - - -void main() { - - ge_brightness = vs_brightness[0]; - ge_starDistFromSun = vs_starDistFromSun[0]; - ge_cameraDistFromSun = vs_cameraDistFromSun[0]; - - vec4 viewPosition = vec4(view * vs_gPosition[0]); - - // Make closer stars look a bit bigger. - ge_observedDist = safeLength(viewPosition / viewScaling); - float closeUpBoost = closeUpBoostDist / ge_observedDist; - float initStarSize = billboardSize; - - // Use magnitude for size boost as well. - if ( renderOption != RENDEROPTION_STATIC ) { - // DR1 magnitudes are [4, 20], but could be [-15, 20] according to this chart: - // https://qph.fs.quoracdn.net/main-qimg-317a18e3b228efc7d7f67a1632a55961 - // Negative magnitude => Giants - // Big positive magnitude => Dwarfs - float absoluteMagnitude = vs_brightness[0].x; - float normalizedMagnitude = (absoluteMagnitude - 20) / -1; // (-15 - 20); - - // TODO: A linear scale is prabably not the best! - initStarSize += normalizedMagnitude * (magnitudeBoost / 50); - } - - vec4 position = gl_in[0].gl_Position; - vec2 starSize = vec2(initStarSize + closeUpBoost) * position.w / 1000.0; - - float distThreshold = cutOffThreshold - log(ge_observedDist) / log(4.0); - - // Discard geometry if star has no position (but wasn't a nullArray). - // Or if observed distance is above threshold set by cutOffThreshold. - // By discarding in gs instead of fs we save computations for when nothing is visible. - if (length(position) < EPS || distThreshold <= 0) { - return; - } - - vec4 centerWorldPos = vs_gPosition[0]; - - dvec3 cameraNormal = normalize(cameraPos - dvec3(centerWorldPos.xyz)); - dvec3 newRight = normalize(cross(cameraLookUp, cameraNormal)); - dvec3 newUp = cross(cameraNormal, newRight); - vec4 wCameraRight = vec4(newRight, 0.0); - vec4 wCameraUp = vec4(newUp, 0.0); - - float multiplier = float(length(cameraPos)); - starSize *= float(multiplier/1E1); - - for (int i = 0; i < 4; i++) { - // Always turn the billboard towards the camera (needed for warped screen). - vec4 cornerPoint = centerWorldPos - + wCameraRight * starSize.x * (corners[i].x - 0.5) - + wCameraUp * starSize.y * (corners[i].y - 0.5); - gl_Position = vec4(projection * view * cornerPoint); - gl_Position.z = 0.0; - texCoord = corners[i]; - ge_gPosition = viewPosition; - - EmitVertex(); - } - - EndPrimitive(); -} diff --git a/modules/softwareintegration/shaders/gaia_billboard_nofbo_fs.glsl b/modules/softwareintegration/shaders/gaia_billboard_nofbo_fs.glsl deleted file mode 100644 index 2e67386300..0000000000 --- a/modules/softwareintegration/shaders/gaia_billboard_nofbo_fs.glsl +++ /dev/null @@ -1,123 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2020 * - * * - * 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 "fragment.glsl" -#include "floatoperations.glsl" - -// Keep in sync with gaiaoptions.h:RenderOption enum -const int RENDEROPTION_STATIC = 0; -const int RENDEROPTION_COLOR = 1; -const int RENDEROPTION_MOTION = 2; -const float ONE_PARSEC = 3.08567758e16; // 1 Parsec -const float DEFAULT_DEPTH = 3.08567758e19; // 1000 Pc -const float LUM_LOWER_CAP = 0.01; - -in vec2 ge_brightness; -in vec4 ge_gPosition; -in vec2 texCoord; -in float ge_starDistFromSun; -in float ge_cameraDistFromSun; -in float ge_observedDist; - -uniform sampler2D psfTexture; -uniform sampler1D colorTexture; -uniform float luminosityMultiplier; -uniform float sharpness; -uniform int renderOption; - -vec3 color2rgb(float color) { - // BV is [-0.4, 2.0] - float st = (color + 0.4) / (2.0 + 0.4); - - // Bp-Rp[-2.0, 6.5], Bp-G[-2.1, 5.0], G-Rp[-1.0, 3.0] - //float st = (color + 1.0) / (5.0 + 1.0); - - return texture(colorTexture, st).rgb; -} - -Fragment getFragment() { - - // Assume all stars has equal luminosity as the Sun when no magnitude is loaded. - float luminosity = 1.0; - vec3 color = vec3(luminosity); - float ratioMultiplier = 0.03; - - vec4 textureColor = texture(psfTexture, texCoord); - textureColor.a = pow(textureColor.a, sharpness); - if (textureColor.a < 0.001) { - discard; - } - - // Calculate the color and luminosity if we have the magnitude and B-V color. - if ( renderOption != RENDEROPTION_STATIC ) { - color = color2rgb(ge_brightness.y); - ratioMultiplier = 0.5; - - // Absolute magnitude is brightness a star would have at 10 pc away. - float absoluteMagnitude = ge_brightness.x; - - // From formula: MagSun - MagStar = 2.5*log(LumStar / LumSun), it gives that: - // LumStar = 10^(1.89 - 0.4*Magstar) , if LumSun = 1 and MagSun = 4.72 - luminosity = pow(10.0, 1.89 - 0.4 * absoluteMagnitude); - - // If luminosity is really really small then set it to a static low number. - if (luminosity < LUM_LOWER_CAP) { - luminosity = LUM_LOWER_CAP; - } - } - - // Luminosity decrease by {squared} distance [measured in Pc]. - float observedDistance = ge_observedDist / ONE_PARSEC; - luminosity /= pow(observedDistance, 2.0); - - // Multiply our color with the luminosity as well as a user-controlled property. - color *= luminosity * pow(luminosityMultiplier, 3.0); - - // Decrease contributing brightness for stars in central cluster. - if ( ge_cameraDistFromSun > ge_starDistFromSun ) { - float ratio = ge_starDistFromSun / ge_cameraDistFromSun; - //color *= ratio * ratioMultiplier; - } - - // Use truncating tonemapping here so we don't overexposure individual stars. - //color = 1.0 - 1.0 * exp(-5.0 * color.rgb); - float maxVal = max(max(color.r, color.g), color.b); - if (maxVal > 1.0) { - color /= maxVal; - } - - if (length(color) < 0.01) { - discard; - } - - Fragment frag; - frag.color = vec4(color, textureColor.a);; - // Place stars at back to begin with. - frag.depth = DEFAULT_DEPTH; - frag.gNormal = vec4(0.0, 0.0, 0.0, 1.0); - frag.blend = BLEND_MODE_NORMAL; - - return frag; -} - diff --git a/modules/softwareintegration/shaders/gaia_point_fs.glsl b/modules/softwareintegration/shaders/gaia_point_fs.glsl deleted file mode 100644 index 22fa3fafb9..0000000000 --- a/modules/softwareintegration/shaders/gaia_point_fs.glsl +++ /dev/null @@ -1,98 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2020 * - * * - * 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. * - ****************************************************************************************/ - -#version __CONTEXT__ - -#include "floatoperations.glsl" - -layout (location = 0) out vec4 outColor; - -// Keep in sync with gaiaoptions.h:RenderOption enum -const int RENDEROPTION_STATIC = 0; -const int RENDEROPTION_COLOR = 1; -const int RENDEROPTION_MOTION = 2; -const float ONE_PARSEC = 3.08567758e16; // 1 Parsec -const float LUM_LOWER_CAP = 0.01; - -in vec2 ge_brightness; -in vec4 ge_gPosition; -in float ge_starDistFromSun; -in float ge_cameraDistFromSun; -in float ge_observedDist; - -uniform sampler1D colorTexture; -uniform float luminosityMultiplier; -uniform int renderOption; -uniform float viewScaling; - -vec3 color2rgb(float color) { - // BV is [-0.4, 2.0] - float st = (color + 0.4) / (2.0 + 0.4); - - // Bp-Rp[-2.0, 6.5], Bp-G[-2.1, 5.0], G-Rp[-1.0, 3.0] - //float st = (color + 1.0) / (5.0 + 1.0); - - return texture(colorTexture, st).rgb; -} - -void main() { - - // Assume all stars has equal luminosity as the Sun when no magnitude is loaded. - float luminosity = 0.05; - vec3 color = vec3(luminosity); - float ratioMultiplier = 1.0; - - // Calculate the color and luminosity if we have the magnitude and B-V color. - if ( renderOption != RENDEROPTION_STATIC ) { - color = color2rgb(ge_brightness.y); - ratioMultiplier = 0.01; - - // Absolute magnitude is brightness a star would have at 10 pc away. - float absoluteMagnitude = ge_brightness.x; - - // From formula: MagSun - MagStar = 2.5*log(LumStar / LumSun), it gives that: - // LumStar = 10^(1.89 - 0.4*Magstar) , if LumSun = 1 and MagSun = 4.72 - luminosity = pow(10.0, 1.89 - 0.4 * absoluteMagnitude); - - // If luminosity is really really small then set it to a static low number. - if (luminosity < LUM_LOWER_CAP) { - luminosity = LUM_LOWER_CAP; - } - } - - // Luminosity decrease by {squared} distance [measured in Pc]. - float observedDistance = ge_observedDist / ONE_PARSEC; - luminosity /= pow(observedDistance, 2.0); - - // Multiply our color with the luminosity as well as a user-controlled property. - color *= luminosity * pow(luminosityMultiplier, 3.0); - - // Decrease contributing brightness for stars in central cluster. - if ( ge_cameraDistFromSun > ge_starDistFromSun ) { - float ratio = ge_starDistFromSun / ge_cameraDistFromSun; - //color *= ratio * ratioMultiplier; - } - - outColor = vec4(color, 1.0f); -} diff --git a/modules/softwareintegration/shaders/gaia_point_ge.glsl b/modules/softwareintegration/shaders/gaia_point_ge.glsl deleted file mode 100644 index b36e18f5bb..0000000000 --- a/modules/softwareintegration/shaders/gaia_point_ge.glsl +++ /dev/null @@ -1,76 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2020 * - * * - * 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. * - ****************************************************************************************/ - -#version __CONTEXT__ - -#include "floatoperations.glsl" - -const float EPS = 1e-5; - -layout(points) in; -in vec2 vs_brightness[]; -in vec4 vs_gPosition[]; -in float vs_starDistFromSun[]; -in float vs_cameraDistFromSun[]; - -layout(points, max_vertices = 1) out; -out vec2 ge_brightness; -out vec4 ge_gPosition; -out float ge_starDistFromSun; -out float ge_cameraDistFromSun; -out float ge_observedDist; - -uniform dmat4 view; -uniform float viewScaling; -uniform float cutOffThreshold; - -void main() { - - ge_brightness = vs_brightness[0]; - ge_starDistFromSun = vs_starDistFromSun[0]; - ge_cameraDistFromSun = vs_cameraDistFromSun[0]; - - vec4 viewPosition = vec4(view * vs_gPosition[0]); - - ge_observedDist = safeLength(viewPosition / viewScaling); - float distThreshold = cutOffThreshold - log(ge_observedDist) / log(4.0); - - vec4 position = gl_in[0].gl_Position; - - // Discard geometry if star has no position (but wasn't a nullArray). - // Or if observed distance is above threshold set by cutOffThreshold. - // By discarding in gs instead of fs we save computations for when nothing is visible. - if (length(position) < EPS || distThreshold <= 0) { - return; - } - - //gl_PointSize = 1.0; - gl_Position = position; - gl_Position.z = 0.0; - ge_gPosition = viewPosition; - - EmitVertex(); - - EndPrimitive(); -} diff --git a/modules/softwareintegration/shaders/gaia_ssbo_vs.glsl b/modules/softwareintegration/shaders/gaia_ssbo_vs.glsl deleted file mode 100644 index ecd6f1b064..0000000000 --- a/modules/softwareintegration/shaders/gaia_ssbo_vs.glsl +++ /dev/null @@ -1,187 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2020 * - * * - * 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. * - ****************************************************************************************/ - -#version __CONTEXT__ - -#include "floatoperations.glsl" - -// Keep in sync with gaiaoptions.h:RenderOption enum -const int RENDEROPTION_STATIC = 0; -const int RENDEROPTION_COLOR = 1; -const int RENDEROPTION_MOTION = 2; -const float EPS = 1e-5; -const float Parsec = 3.0856776e16; - -layout (std430) buffer ssbo_idx_data { - int starsPerChunk[]; -}; - -layout (std430) buffer ssbo_comb_data { - float allData[]; -}; - -in int gl_VertexID; - -out vec2 vs_brightness; -out vec4 vs_gPosition; -out float vs_starDistFromSun; -out float vs_cameraDistFromSun; - -uniform dmat4 model; -uniform dmat4 view; -uniform dmat4 projection; -uniform float time; -uniform int renderOption; - -uniform int maxStarsPerNode; -uniform int valuesPerStar; -uniform int nChunksToRender; - -uniform vec2 posXThreshold; -uniform vec2 posYThreshold; -uniform vec2 posZThreshold; -uniform vec2 gMagThreshold; -uniform vec2 bpRpThreshold; -uniform vec2 distThreshold; - -// Use binary search to find the chunk containing our star ID. -int findChunkId(int left, int right, int id) { - - while ( left <= right ) { - int middle = (left + right) / 2; - int firstStarInChunk = starsPerChunk[middle]; - if (left == right || (firstStarInChunk <= id && id < starsPerChunk[middle+1])) { - return middle; - } - else if (id < firstStarInChunk) { - // Go smaller - right = middle - 1; - } - else { - // Go bigger - left = middle + 1; - } - } - return -1; -} - -void main() { - // Fetch our data. - int chunkId = findChunkId(0, nChunksToRender - 1, gl_VertexID); - // Fail safe - this should never happen! - if (chunkId == -1) { - vs_gPosition = vec4(0.0); - gl_Position = vec4(0.0); - return; - } - int placeInChunk = gl_VertexID - starsPerChunk[chunkId]; - int firstStarInChunk = valuesPerStar * maxStarsPerNode * chunkId; // Chunk offset - int nStarsInChunk = starsPerChunk[chunkId + 1] - starsPerChunk[chunkId]; // Stars in current chunk. - // Remove possible duplicates. - if (nStarsInChunk <= 0) { - vs_gPosition = vec4(0.0); - gl_Position = vec4(0.0); - return; - } - - int startOfPos = firstStarInChunk + placeInChunk * 3; - vec3 in_position = vec3(allData[startOfPos], allData[startOfPos + 1], allData[startOfPos + 2]); - vec2 in_brightness = vec2(0.0); - vec3 in_velocity = vec3(0.0); - - // Check if we should filter this star by position. - if ( (abs(posXThreshold.x) > EPS && in_position.x < posXThreshold.x) || - (abs(posXThreshold.y) > EPS && in_position.x > posXThreshold.y) || - (abs(posYThreshold.x) > EPS && in_position.y < posYThreshold.x) || - (abs(posYThreshold.y) > EPS && in_position.y > posYThreshold.y) || - (abs(posZThreshold.x) > EPS && in_position.z < posZThreshold.x) || - (abs(posZThreshold.y) > EPS && in_position.z > posZThreshold.y) || - (abs(distThreshold.x - distThreshold.y) < EPS - && abs(length(in_position) - distThreshold.y) < EPS) ) { - // Discard star in geometry shader. - vs_gPosition = vec4(0.0); - gl_Position = vec4(0.0); - return; - } - - - if ( renderOption != RENDEROPTION_STATIC ) { - int startOfCol = firstStarInChunk + nStarsInChunk * 3 + placeInChunk * 2; - in_brightness = vec2(allData[startOfCol], allData[startOfCol + 1]); - - // Check if we should filter this star by magnitude or color. - if ( (abs(gMagThreshold.x - gMagThreshold.y) < EPS && abs(gMagThreshold.x - in_brightness.x) < EPS) || - (abs(gMagThreshold.x - 20.0f) > EPS && in_brightness.x < gMagThreshold.x) || - (abs(gMagThreshold.y - 20.0f) > EPS && in_brightness.x > gMagThreshold.y) || - (abs(bpRpThreshold.x - bpRpThreshold.y) < EPS && abs(bpRpThreshold.x - in_brightness.y) < EPS) || - (abs(bpRpThreshold.x) > EPS && in_brightness.y < bpRpThreshold.x) || - (abs(bpRpThreshold.y) > EPS && in_brightness.y > bpRpThreshold.y) ) { - // Discard star in geometry shader. - vs_gPosition = vec4(0.0); - gl_Position = vec4(0.0); - return; - } - - if ( renderOption == RENDEROPTION_MOTION ) { - int startOfVel = firstStarInChunk + nStarsInChunk * 5 + placeInChunk * 3; - in_velocity = vec3(allData[startOfVel], allData[startOfVel + 1], allData[startOfVel + 2]); - } - } - vs_brightness = in_brightness; - - // Convert kiloParsec to meter. - vec4 objectPosition = vec4(in_position * 1000 * Parsec, 1.0); - - // Add velocity [m/s] if we've read any. - objectPosition.xyz += time * in_velocity; - - // Thres moving stars by their new position. - float distPosition = length(objectPosition.xyz / (1000.0 * Parsec) ); - if ( (abs(distThreshold.x - distThreshold.y) > EPS && - ((abs(distThreshold.x) > EPS && distPosition < distThreshold.x) || - (abs(distThreshold.y) > EPS && distPosition > distThreshold.y))) ) { - // Discard star in geometry shader. - vs_gPosition = vec4(0.0); - gl_Position = vec4(0.0); - return; - } - - // Apply camera transforms. - dvec4 viewPosition = view * model * objectPosition; - vec4 sunPosition = vec4(view * model * dvec4(0.0f, 0.0f, 0.0f, 1.0f)); - - vs_starDistFromSun = safeLength(objectPosition); - vs_cameraDistFromSun = safeLength(sunPosition); - - // Remove stars without position, happens when VBO chunk is stuffed with zeros. - // Has to be done in Geometry shader because Vertices cannot be discarded here. - if ( length(in_position) > EPS ){ - vs_gPosition = vec4(model * objectPosition); - gl_Position = vec4(projection * viewPosition); - } - else { - vs_gPosition = vec4(0.0); - gl_Position = vec4(0.0); - } -} diff --git a/modules/softwareintegration/shaders/gaia_tonemapping_billboard_fs.glsl b/modules/softwareintegration/shaders/gaia_tonemapping_billboard_fs.glsl deleted file mode 100644 index 3cf794162f..0000000000 --- a/modules/softwareintegration/shaders/gaia_tonemapping_billboard_fs.glsl +++ /dev/null @@ -1,53 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2020 * - * * - * 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 "fragment.glsl" - -in vec2 uv; - -uniform sampler2D renderedTexture; - -const float DEFAULT_DEPTH = 3.08567758e19; // 1000 Pc - - -Fragment getFragment() { - - vec4 color = vec4(0.0); - - // BILLBOARDS - // Sample color. Tonemapping done in first shader pass. - vec4 textureColor = texture( renderedTexture, uv ); - - // Use the following to check for any intensity at all. - //color = (length(intensity.rgb) > 0.001) ? vec4(1.0) : vec4(0.0); - - Fragment frag; - frag.color = textureColor; - // Place stars at back to begin with. - frag.depth = DEFAULT_DEPTH; - frag.gNormal = vec4(0.0, 0.0, 0.0, 1.0); - frag.blend = BLEND_MODE_NORMAL; - - return frag; -} diff --git a/modules/softwareintegration/shaders/gaia_tonemapping_point_fs.glsl b/modules/softwareintegration/shaders/gaia_tonemapping_point_fs.glsl deleted file mode 100644 index f2da517b0b..0000000000 --- a/modules/softwareintegration/shaders/gaia_tonemapping_point_fs.glsl +++ /dev/null @@ -1,179 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2020 * - * * - * 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 "fragment.glsl" - -in vec2 uv; - -uniform sampler2D renderedTexture; -uniform dmat4 projection; -uniform vec2 screenSize; -uniform int filterSize; -uniform float sigma; -uniform float pixelWeightThreshold; - -const float M_PI = 3.141592653589793238462; -const float DEFAULT_DEPTH = 3.08567758e19; // 1000 Pc - -Fragment getFragment() { - - vec4 color = vec4(0.0); - - // GL_POINTS - - // Use frustum params to be able to compensate for a skewed frustum (in a dome). - float near = float(projection[3][2] / (projection[2][2] - 1.0)); - float left = float(near * (projection[2][0] - 1.0) / projection[0][0]); - float right = float(near * (projection[2][0] + 1.0) / projection[0][0]); - float top = float(near * (projection[2][1] + 1.0) / projection[1][1]); - float bottom = float(near * (projection[2][1] - 1.0) / projection[1][1]); - - float xFactor = float(projection[0][0]); - float yFactor = float(projection[1][1]); - - float planeAspect = yFactor / xFactor; // Equals: (right - left) / (top - bottom) - float screenAspect = screenSize.x / screenSize.y; - float fullAspect = planeAspect / screenAspect; - - // Find screenPos in skewed frustum. uv is [0, 1] - vec2 screenPos = uv * vec2(right - left, top - bottom) + vec2(left, bottom); - - // Find our elliptic scale factors by trigonometric approximation. - float beta = atan(length(screenPos) / near); - vec2 sigmaScaleFactor = vec2( 1.0 / cos(beta), 1.0 / pow(cos(beta), 2.0)); - - float defaultScreen = 1200.0; - float scaling = screenSize.y / defaultScreen * yFactor; - - // Scale filter size depending on screen pos. - vec2 filterScaleFactor = vec2( - pow(screenPos.x / near, 2.0) * fullAspect, - pow(screenPos.y / near, 2.0) - ); - - // Use to ignore scaling. - //filterScaleFactor = vec2(0.0); - //scaling = 1.0; - //sigmaScaleFactor = vec2(1.0); - - // Use the following to find the origo in a skewed frustum. - //Fragment origoFrag; - //vec2 screenOrigo = vec2(-left, -bottom) / vec2(right - left, top - bottom); - //if (abs(screenOrigo.x - uv.x) > 0.0005 && abs(screenOrigo.y - uv.y) > 0.0005) { - // origoFrag.color = vec4(0.0); - //} - //else { - // origoFrag.color = vec4(1.0); - //} - //return origoFrag; - - // Uncomment to compare to original filterSize (assumes origo in center of screen). - //screenPos = (uv - 0.5) * 2.0; // [-1, 1] - //filterScaleFactor = vec2( - // pow(screenPos.x, 2.0), - // pow(screenPos.y, 2.0) - //); - - // Make use of the following flag this to toggle betweeen circular and elliptic distribution. - bool useCircleDist = false; - - // Apply scaling on bloom filter. - vec2 newFilterSize = vec2(filterSize) * (1.0 + length(filterScaleFactor)) * scaling; - - // Calculate params for a rotated Elliptic Gaussian distribution. - float sigmaMajor; - float sigmaMinor; - float a; - float b; - float c; - if (!useCircleDist) { - float alpha = atan(screenPos.y, screenPos.x); - // Apply scaling on sigma. - sigmaMajor = sigma * sigmaScaleFactor.y * scaling; - sigmaMinor = sigma * sigmaScaleFactor.x * scaling; - - a = pow(cos(alpha), 2.0) / (2 * pow(sigmaMajor, 2.0)) - + pow(sin(alpha), 2.0) / (2 * pow(sigmaMinor, 2.0)) ; - b = sin(2 * alpha) / (4 * pow(sigmaMajor, 2.0)) - - sin(2 * alpha) / (4 * pow(sigmaMinor, 2.0)) ; - c = pow(sin(alpha), 2.0) / (2 * pow(sigmaMajor, 2.0)) - + pow(cos(alpha), 2.0) / (2 * pow(sigmaMinor, 2.0)) ; - } - - // Get a [newFilterSize x newFilterSize] filter around our pixel. UV is [0, 1] - vec3 intensity = vec3(0.0); - vec2 pixelSize = 1.0 / screenSize; - ivec2 halfFilterSize = ivec2((newFilterSize - 1.0) / 2.0); - for (int y = -halfFilterSize.y; y <= halfFilterSize.y; y += 1) { - for (int x = -halfFilterSize.x; x <= halfFilterSize.x; x += 1) { - vec2 sPoint = uv + (pixelSize * ivec2(x, y)); - - // Calculate the contribution of this pixel (elliptic gaussian distribution). - float pixelWeight = exp(-( - a * pow(x * fullAspect, 2.0) - + 2 * b * x * y * fullAspect - + c * pow(y, 2.0) - )); - - // Only sample inside FBO texture and if the pixel will contribute to final color. - if (all(greaterThan(sPoint, vec2(0.0))) && all(lessThan(sPoint, vec2(1.0))) - && pixelWeight > pixelWeightThreshold) { - vec4 sIntensity = texture( renderedTexture, sPoint ); - - // Use normal distribution function for halo/bloom effect. - if (useCircleDist) { - float circleDist = sqrt(pow(x / (1 + length(filterScaleFactor)), 2.0) - + pow(y / (1 + length(filterScaleFactor)), 2.0)); - intensity += sIntensity.rgb * (1.0 / (sigma * sqrt(2.0 * M_PI))) * - exp(-(pow(circleDist, 2.0) / (2.0 * pow(sigma, 2.0)))) / filterSize; - } - else { - // Divide contribution by area of ellipse. - intensity += sIntensity.rgb * pixelWeight * fullAspect; - } - } - } - } - // Tonemap intensity to color! - //intensity = 1.0 - 1.0 * exp(-25.0 * intensity); - intensity = pow(intensity, vec3(0.8)); - - if (length(intensity) < 0.01) { - discard; - } - - color = vec4(intensity, 1.0f); - - // Use the following to check for any intensity at all. - //color = (length(intensity.rgb) > 0.001) ? vec4(1.0) : vec4(0.0); - - Fragment frag; - frag.color = color; - // Place stars at back to begin with. - frag.depth = DEFAULT_DEPTH; - frag.gNormal = vec4(0.0, 0.0, 0.0, 1.0); - frag.blend = BLEND_MODE_NORMAL; - - return frag; -} \ No newline at end of file diff --git a/modules/softwareintegration/shaders/gaia_tonemapping_vs.glsl b/modules/softwareintegration/shaders/gaia_tonemapping_vs.glsl deleted file mode 100644 index 2f9122836d..0000000000 --- a/modules/softwareintegration/shaders/gaia_tonemapping_vs.glsl +++ /dev/null @@ -1,34 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2020 * - * * - * 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. * - ****************************************************************************************/ - -#version __CONTEXT__ - -in vec3 in_position; - -out vec2 uv; - -void main() { - uv = (in_position.xy + 1.0) / 2.0; - gl_Position = vec4(in_position, 1.0); -} diff --git a/modules/softwareintegration/shaders/gaia_vbo_vs.glsl b/modules/softwareintegration/shaders/gaia_vbo_vs.glsl deleted file mode 100644 index f5a635c3d2..0000000000 --- a/modules/softwareintegration/shaders/gaia_vbo_vs.glsl +++ /dev/null @@ -1,120 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2020 * - * * - * 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. * - ****************************************************************************************/ - -#version __CONTEXT__ - -#include "floatoperations.glsl" - -// Keep in sync with gaiaoptions.h:RenderOption enum -const int RENDEROPTION_STATIC = 0; -const int RENDEROPTION_COLOR = 1; -const int RENDEROPTION_MOTION = 2; -const float EPS = 1e-5; -const float Parsec = 3.0856776e16; - -in vec3 in_position; -in vec2 in_brightness; -in vec3 in_velocity; - -out vec2 vs_brightness; -out vec4 vs_gPosition; -out float vs_starDistFromSun; -out float vs_cameraDistFromSun; - -uniform dmat4 model; -uniform dmat4 view; -uniform dmat4 projection; -uniform float time; -uniform int renderOption; - -uniform vec2 posXThreshold; -uniform vec2 posYThreshold; -uniform vec2 posZThreshold; -uniform vec2 gMagThreshold; -uniform vec2 bpRpThreshold; -uniform vec2 distThreshold; - -void main() { - vs_brightness = in_brightness; - - // Check if we should filter this star by position. Thres depending on original values. - if ( (abs(posXThreshold.x) > EPS && in_position.x < posXThreshold.x) || - (abs(posXThreshold.y) > EPS && in_position.x > posXThreshold.y) || - (abs(posYThreshold.x) > EPS && in_position.y < posYThreshold.x) || - (abs(posYThreshold.y) > EPS && in_position.y > posYThreshold.y) || - (abs(posZThreshold.x) > EPS && in_position.z < posZThreshold.x) || - (abs(posZThreshold.y) > EPS && in_position.z > posZThreshold.y) || - (abs(distThreshold.x - distThreshold.y) < EPS - && abs(length(in_position) - distThreshold.y) < EPS) || - ( renderOption != RENDEROPTION_STATIC && ( - (abs(gMagThreshold.x - gMagThreshold.y) < EPS && abs(gMagThreshold.x - in_brightness.x) < EPS) || - (abs(gMagThreshold.x - 20.0f) > EPS && in_brightness.x < gMagThreshold.x) || - (abs(gMagThreshold.y - 20.0f) > EPS && in_brightness.x > gMagThreshold.y) || - (abs(bpRpThreshold.x - bpRpThreshold.y) < EPS && abs(bpRpThreshold.x - in_brightness.y) < EPS) || - (abs(bpRpThreshold.x) > EPS && in_brightness.y < bpRpThreshold.x) || - (abs(bpRpThreshold.y) > EPS && in_brightness.y > bpRpThreshold.y))) ) { - // Discard star in geometry shader. - vs_gPosition = vec4(0.0); - gl_Position = vec4(0.0); - return; - } - - // Convert kiloParsec to meter. - vec4 objectPosition = vec4(in_position * 1000 * Parsec, 1.0); - - // Add velocity if we've read any. - if ( renderOption == RENDEROPTION_MOTION ) { - // Velocity is already in [m/s]. - objectPosition.xyz += time * in_velocity; - } - - // Thres moving stars by their new position. - float distPosition = length(objectPosition.xyz / (1000.0 * Parsec) ); - if ( (abs(distThreshold.x - distThreshold.y) > EPS && - ((abs(distThreshold.x) > EPS && distPosition< distThreshold.x) || - (abs(distThreshold.y) > EPS && distPosition > distThreshold.y))) ) { - // Discard star in geometry shader. - vs_gPosition = vec4(0.0); - gl_Position = vec4(0.0); - return; - } - - // Apply camera transforms. - dvec4 viewPosition = view * model * objectPosition; - vec4 sunPosition = vec4(view * model * vec4(0.0f, 0.0f, 0.0f, 1.0f)); - - vs_starDistFromSun = safeLength(objectPosition); - vs_cameraDistFromSun = safeLength(sunPosition); - - // Remove stars without position, happens when VBO chunk is stuffed with zeros. - // Has to be done in Geometry shader because Vertices cannot be discarded here. - if ( length(in_position) > EPS ){ - vs_gPosition = vec4(model * objectPosition); - gl_Position = vec4(projection * viewPosition); - } - else { - vs_gPosition = vec4(0.0); - gl_Position = vec4(0.0); - } -} diff --git a/modules/softwareintegration/softwareintegrationmodule.cpp b/modules/softwareintegration/softwareintegrationmodule.cpp index 8d729a3db2..5fe2ad8fad 100644 --- a/modules/softwareintegration/softwareintegrationmodule.cpp +++ b/modules/softwareintegration/softwareintegrationmodule.cpp @@ -24,10 +24,6 @@ #include -#include -//#include -#include -#include #include #include #include @@ -44,19 +40,16 @@ void SoftwareIntegrationModule::internalInitialize(const ghoul::Dictionary&) { ghoul_assert(fRenderable, "No renderable factory existed"); //fRenderable->registerClass("RenderableGaiaStars"); - auto fTask = FactoryManager::ref().factory(); - ghoul_assert(fRenderable, "No task factory existed"); - fTask->registerClass("ReadFitsTask"); - fTask->registerClass("ReadSpeckTask"); - fTask->registerClass("ConstructOctreeTask"); + //auto fTask = FactoryManager::ref().factory(); + //ghoul_assert(fRenderable, "No task factory existed"); + //fTask->registerClass("ReadFitsTask"); + //fTask->registerClass("ReadSpeckTask"); + //fTask->registerClass("ConstructOctreeTask"); } std::vector SoftwareIntegrationModule::documentations() const { return { - //RenderableGaiaStars::Documentation(), - ReadFitsTask::Documentation(), - ReadSpeckTask::Documentation(), - ConstructOctreeTask::Documentation(), + }; } diff --git a/modules/softwareintegration/softwareintegrationmodule.h b/modules/softwareintegration/softwareintegrationmodule.h index f3f79d5342..59526426ee 100644 --- a/modules/softwareintegration/softwareintegrationmodule.h +++ b/modules/softwareintegration/softwareintegrationmodule.h @@ -26,7 +26,6 @@ #define __OPENSPACE_MODULE_SOFTWAREINTEGRATION___SOFTWAREINTEGRATIONMODULE___H__ #include - #include namespace openspace { diff --git a/modules/softwareintegration/tasks/constructoctreetask.cpp b/modules/softwareintegration/tasks/constructoctreetask.cpp deleted file mode 100644 index 725d86963c..0000000000 --- a/modules/softwareintegration/tasks/constructoctreetask.cpp +++ /dev/null @@ -1,816 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2020 * - * * - * 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 - -namespace { - constexpr const char* KeyInFileOrFolderPath = "InFileOrFolderPath"; - constexpr const char* KeyOutFileOrFolderPath = "OutFileOrFolderPath"; - constexpr const char* KeyMaxDist = "MaxDist"; - constexpr const char* KeyMaxStarsPerNode = "MaxStarsPerNode"; - constexpr const char* KeySingleFileInput = "SingleFileInput"; - - constexpr const char* KeyFilterPosX = "FilterPosX"; - constexpr const char* KeyFilterPosY = "FilterPosY"; - constexpr const char* KeyFilterPosZ = "FilterPosZ"; - constexpr const char* KeyFilterGMag = "FilterGMag"; - constexpr const char* KeyFilterBpRp = "FilterBpRp"; - constexpr const char* KeyFilterVelX = "FilterVelX"; - constexpr const char* KeyFilterVelY = "FilterVelY"; - constexpr const char* KeyFilterVelZ = "FilterVelZ"; - constexpr const char* KeyFilterBpMag = "FilterBpMag"; - constexpr const char* KeyFilterRpMag = "FilterRpMag"; - constexpr const char* KeyFilterBpG = "FilterBpG"; - constexpr const char* KeyFilterGRp = "FilterGRp"; - constexpr const char* KeyFilterRa = "FilterRa"; - constexpr const char* KeyFilterRaError = "FilterRaError"; - constexpr const char* KeyFilterDec = "FilterDec"; - constexpr const char* KeyFilterDecError = "FilterDecError"; - constexpr const char* KeyFilterParallax = "FilterParallax"; - constexpr const char* KeyFilterParallaxError = "FilterParallaxError"; - constexpr const char* KeyFilterPmra = "FilterPmra"; - constexpr const char* KeyFilterPmraError = "FilterPmraError"; - constexpr const char* KeyFilterPmdec = "FilterPmdec"; - constexpr const char* KeyFilterPmdecError = "FilterPmdecError"; - constexpr const char* KeyFilterRv = "FilterRv"; - constexpr const char* KeyFilterRvError = "FilterRvError"; - - constexpr const char* _loggerCat = "ConstructOctreeTask"; -} // namespace - -namespace openspace { - -ConstructOctreeTask::ConstructOctreeTask(const ghoul::Dictionary& dictionary) { - openspace::documentation::testSpecificationAndThrow( - documentation(), - dictionary, - "ConstructOctreeTask" - ); - - _inFileOrFolderPath = absPath(dictionary.value(KeyInFileOrFolderPath)); - _outFileOrFolderPath = absPath(dictionary.value(KeyOutFileOrFolderPath)); - - if (dictionary.hasKey(KeyMaxDist)) { - _maxDist = static_cast(dictionary.value(KeyMaxDist)); - } - - if (dictionary.hasKey(KeyMaxStarsPerNode)) { - _maxStarsPerNode = static_cast(dictionary.value(KeyMaxStarsPerNode)); - } - - if (dictionary.hasKey(KeySingleFileInput)) { - _singleFileInput = dictionary.value(KeySingleFileInput); - } - - _octreeManager = std::make_shared(); - _indexOctreeManager = std::make_shared(); - - // Check for filter params. - if (dictionary.hasKey(KeyFilterPosX)) { - _posX = dictionary.value(KeyFilterPosX); - _filterPosX = true; - } - if (dictionary.hasKey(KeyFilterPosY)) { - _posY = dictionary.value(KeyFilterPosY); - _filterPosY = true; - } - if (dictionary.hasKey(KeyFilterPosZ)) { - _posZ = dictionary.value(KeyFilterPosZ); - _filterPosZ = true; - } - if (dictionary.hasKey(KeyFilterGMag)) { - _gMag = dictionary.value(KeyFilterGMag); - _filterGMag = true; - } - if (dictionary.hasKey(KeyFilterBpRp)) { - _bpRp = dictionary.value(KeyFilterBpRp); - _filterBpRp = true; - } - if (dictionary.hasKey(KeyFilterVelX)) { - _velX = dictionary.value(KeyFilterVelX); - _filterVelX = true; - } - if (dictionary.hasKey(KeyFilterVelY)) { - _velY = dictionary.value(KeyFilterVelY); - _filterVelY = true; - } - if (dictionary.hasKey(KeyFilterVelZ)) { - _velZ = dictionary.value(KeyFilterVelZ); - _filterVelZ = true; - } - if (dictionary.hasKey(KeyFilterBpMag)) { - _bpMag = dictionary.value(KeyFilterBpMag); - _filterBpMag = true; - } - if (dictionary.hasKey(KeyFilterRpMag)) { - _rpMag = dictionary.value(KeyFilterRpMag); - _filterRpMag = true; - } - if (dictionary.hasKey(KeyFilterBpG)) { - _bpG = dictionary.value(KeyFilterBpG); - _filterBpG = true; - } - if (dictionary.hasKey(KeyFilterGRp)) { - _gRp = dictionary.value(KeyFilterGRp); - _filterGRp = true; - } - if (dictionary.hasKey(KeyFilterRa)) { - _ra = dictionary.value(KeyFilterRa); - _filterRa = true; - } - if (dictionary.hasKey(KeyFilterRaError)) { - _raError = dictionary.value(KeyFilterRaError); - _filterRaError = true; - } - if (dictionary.hasKey(KeyFilterDec)) { - _dec = dictionary.value(KeyFilterDec); - _filterDec = true; - } - if (dictionary.hasKey(KeyFilterDecError)) { - _decError = dictionary.value(KeyFilterDecError); - _filterDecError = true; - } - if (dictionary.hasKey(KeyFilterParallax)) { - _parallax = dictionary.value(KeyFilterParallax); - _filterParallax = true; - } - if (dictionary.hasKey(KeyFilterParallaxError)) { - _parallaxError = dictionary.value(KeyFilterParallaxError); - _filterParallaxError = true; - } - if (dictionary.hasKey(KeyFilterPmra)) { - _pmra = dictionary.value(KeyFilterPmra); - _filterPmra = true; - } - if (dictionary.hasKey(KeyFilterPmraError)) { - _pmraError = dictionary.value(KeyFilterPmraError); - _filterPmraError = true; - } - if (dictionary.hasKey(KeyFilterPmdec)) { - _pmdec = dictionary.value(KeyFilterPmdec); - _filterPmdec = true; - } - if (dictionary.hasKey(KeyFilterPmdecError)) { - _pmdecError = dictionary.value(KeyFilterPmdecError); - _filterPmdecError = true; - } - if (dictionary.hasKey(KeyFilterRv)) { - _rv = dictionary.value(KeyFilterRv); - _filterRv = true; - } - if (dictionary.hasKey(KeyFilterRvError)) { - _rvError = dictionary.value(KeyFilterRvError); - _filterRvError = true; - } -} - -std::string ConstructOctreeTask::description() { - return "Read bin file (or files in folder): " + _inFileOrFolderPath + "\n " - "and write octree data file (or files) into: " + _outFileOrFolderPath + "\n"; -} - -void ConstructOctreeTask::perform(const Task::ProgressCallback& onProgress) { - onProgress(0.0f); - - if (_singleFileInput) { - constructOctreeFromSingleFile(onProgress); - } - else { - constructOctreeFromFolder(onProgress); - } - - onProgress(1.0f); -} - -void ConstructOctreeTask::constructOctreeFromSingleFile( - const Task::ProgressCallback& progressCallback) -{ - std::vector fullData; - int32_t nValues = 0; - int32_t nValuesPerStar = 0; - size_t nFilteredStars = 0; - int nTotalStars = 0; - - _octreeManager->initOctree(0, _maxDist, _maxStarsPerNode); - - LINFO("Reading data file: " + _inFileOrFolderPath); - - LINFO(fmt::format( - "MAX DIST: {} - MAX STARS PER NODE: {}", - _octreeManager->maxDist(), _octreeManager->maxStarsPerNode() - )); - - // Use to generate a synthetic dataset - /*for (float z = -1.0; z < 1.0; z += 0.05) { - for (float y = -1.0; y < 1.0; y += 0.05) { - for (float x = -1.0; x < 1.0; x += 0.05) { - float r = static_cast (rand()) / static_cast (RAND_MAX); - std::vector renderValues(8); - renderValues[0] = x; // + x * r; - renderValues[2] = z; // + y * r; - renderValues[1] = y; // + z * r; - renderValues[3] = 5.0; // + 10 * r; - renderValues[4] = 2.0; // + 10 * r; - renderValues[5] = r; - renderValues[6] = r; - renderValues[7] = r; - _octreeManager->insert(renderValues); - nTotalStars++; - nValues+=8; - } - } - } - - for (float phi = -180.0; phi < 180.0; phi += 10.0) { - for (float theta = -90.0; theta <= 90.0; theta += 10.0) { - float r = 1.0; - std::vector renderValues(8); - renderValues[0] = r * sin(glm::radians(theta)) * cos(glm::radians(phi)); - renderValues[2] = r * sin(glm::radians(theta)) * sin(glm::radians(phi)); - renderValues[1] = r * cos(glm::radians(theta)); - renderValues[3] = 5.0; - renderValues[4] = 2.0; - renderValues[5] = r; - renderValues[6] = r; - renderValues[7] = r; - _octreeManager->insert(renderValues); - nTotalStars++; - nValues += 8; - } - }*/ - - std::ifstream inFileStream(_inFileOrFolderPath, std::ifstream::binary); - if (inFileStream.good()) { - inFileStream.read(reinterpret_cast(&nValues), sizeof(int32_t)); - inFileStream.read(reinterpret_cast(&nValuesPerStar), sizeof(int32_t)); - - fullData.resize(nValues); - inFileStream.read( - reinterpret_cast(fullData.data()), - nValues * sizeof(fullData[0]) - ); - nTotalStars = nValues / nValuesPerStar; - - progressCallback(0.3f); - LINFO("Constructing Octree."); - - // Insert star into octree. We assume the data already is in correct order. - for (size_t i = 0; i < fullData.size(); i += nValuesPerStar) { - auto first = fullData.begin() + i; - auto last = fullData.begin() + i + nValuesPerStar; - std::vector filterValues(first, last); - std::vector renderValues(first, first + RENDER_VALUES); - - // Filter data by parameters. - if (checkAllFilters(filterValues)) { - nFilteredStars++; - continue; - } - - // If all filters passed then insert render values into Octree. - _octreeManager->insert(renderValues); - } - inFileStream.close(); - } - else { - LERROR(fmt::format( - "Error opening file '{}' for loading preprocessed file!", - _inFileOrFolderPath - )); - } - LINFO(fmt::format("{} of {} read stars were filtered", nFilteredStars, nTotalStars)); - - // Slice LOD data before writing to files. - _octreeManager->sliceLodData(); - - LINFO("Writing octree to: " + _outFileOrFolderPath); - std::ofstream outFileStream(_outFileOrFolderPath, std::ofstream::binary); - if (outFileStream.good()) { - if (nValues == 0) { - LERROR("Error writing file - No values were read from file."); - } - _octreeManager->writeToFile(outFileStream, true); - - outFileStream.close(); - } - else { - LERROR(fmt::format( - "Error opening file: {} as output data file.", _outFileOrFolderPath - )); - } -} - -void ConstructOctreeTask::constructOctreeFromFolder( - const Task::ProgressCallback& progressCallback) -{ - int32_t nStars = 0; - int32_t nValuesPerStar = 0; - size_t nFilteredStars = 0; - //float maxRadius = 0.0; - //int starsOutside10 = 0; - //int starsOutside25 = 0; - //int starsOutside50 = 0; - //int starsOutside75 = 0; - //int starsOutside100 = 0; - //int starsOutside200 = 0; - //int starsOutside300 = 0; - //int starsOutside400 = 0; - //int starsOutside500 = 0; - //int starsOutside750 = 0; - //int starsOutside1000 = 0; - //int starsOutside1500 = 0; - //int starsOutside2000 = 0; - //int starsOutside5000 = 0; - - ghoul::filesystem::Directory currentDir(_inFileOrFolderPath); - std::vector allInputFiles = currentDir.readFiles(); - std::vector filterValues; - auto writeThreads = std::vector(8); - - _indexOctreeManager->initOctree(0, _maxDist, _maxStarsPerNode); - - float processOneFile = 1.f / allInputFiles.size(); - - LINFO(fmt::format( - "MAX DIST: {} - MAX STARS PER NODE: {}", - _indexOctreeManager->maxDist(), _indexOctreeManager->maxStarsPerNode() - )); - - for (size_t idx = 0; idx < allInputFiles.size(); ++idx) { - std::string inFilePath = allInputFiles[idx]; - int nStarsInfile = 0; - - LINFO("Reading data file: " + inFilePath); - - std::ifstream inFileStream(inFilePath, std::ifstream::binary); - if (inFileStream.good()) { - inFileStream.read(reinterpret_cast(&nValuesPerStar), sizeof(int32_t)); - filterValues.resize(nValuesPerStar, 0.f); - - while (inFileStream.read( - reinterpret_cast(filterValues.data()), - nValuesPerStar * sizeof(filterValues[0]) - )) - { - // Filter data by parameters. - if (checkAllFilters(filterValues)) { - nFilteredStars++; - continue; - } - // Generate a 50/12,5 dataset (gMag <=13/>13). - //if ((filterStar(glm::vec2(20.0), filterValues[3], 20.f)) || - // (filterStar(glm::vec2(0.0), filterValues[16])) || - // (filterValues[3] > 13.0 && filterValues[17] > 0.125) || - // (filterValues[3] <= 13.0 && filterValues[17] > 0.5)) { - // nFilteredStars++; - // continue; - //} - - // If all filters passed then insert render values into Octree. - std::vector renderValues( - filterValues.begin(), - filterValues.begin() + RENDER_VALUES - ); - - _indexOctreeManager->insert(renderValues); - nStarsInfile++; - - //float maxVal = fmax(fmax(fabs(renderValues[0]), fabs(renderValues[1])), - // fabs(renderValues[2])); - //if (maxVal > maxRadius) maxRadius = maxVal; - //// Calculate how many stars are outside of different thresholds. - //if (maxVal > 10) starsOutside10++; - //if (maxVal > 25) starsOutside25++; - //if (maxVal > 50) starsOutside50++; - //if (maxVal > 75) starsOutside75++; - //if (maxVal > 100) starsOutside100++; - //if (maxVal > 200) starsOutside200++; - //if (maxVal > 300) starsOutside300++; - //if (maxVal > 400) starsOutside400++; - //if (maxVal > 500) starsOutside500++; - //if (maxVal > 750) starsOutside750++; - //if (maxVal > 1000) starsOutside1000++; - //if (maxVal > 1500) starsOutside1500++; - //if (maxVal > 2000) starsOutside2000++; - //if (maxVal > 5000) starsOutside5000++; - } - inFileStream.close(); - } - else { - LERROR(fmt::format( - "Error opening file '{}' for loading preprocessed file!", inFilePath - )); - } - - // Slice LOD data. - LINFO("Slicing LOD data!"); - _indexOctreeManager->sliceLodData(idx); - - progressCallback((idx + 1) * processOneFile); - nStars += nStarsInfile; - - LINFO(fmt::format("Writing {} stars to octree files!", nStarsInfile)); - LINFO(fmt::format( - "Number leaf nodes: {}\n Number inner nodes: {}\n Total depth of tree: {}", - _indexOctreeManager->numLeafNodes(), - _indexOctreeManager->numInnerNodes(), - _indexOctreeManager->totalDepth() - )); - - // Write to 8 separate files in a separate thread. Data will be cleared after it - // has been written. Store joinable thread for later sync. - std::thread t( - &OctreeManager::writeToMultipleFiles, - _indexOctreeManager, - _outFileOrFolderPath, - idx - ); - writeThreads[idx] = std::move(t); - } - - LINFO(fmt::format( - "A total of {} stars were read from files and distributed into {} total nodes", - nStars, _indexOctreeManager->totalNodes() - )); - LINFO(std::to_string(nFilteredStars) + " stars were filtered"); - - //LINFO("Max radius of dataset is: " + std::to_string(maxRadius) + - // "\n Number of stars outside of:" + - // " - 10kPc is " + std::to_string(starsOutside10) + "\n" + - // " - 25kPc is " + std::to_string(starsOutside25) + "\n" + - // " - 50kPc is " + std::to_string(starsOutside50) + "\n" + - // " - 75kPc is " + std::to_string(starsOutside75) + "\n" + - // " - 100kPc is " + std::to_string(starsOutside100) + "\n" + - // " - 200kPc is " + std::to_string(starsOutside200) + "\n" + - // " - 300kPc is " + std::to_string(starsOutside300) + "\n" + - // " - 400kPc is " + std::to_string(starsOutside400) + "\n" + - // " - 500kPc is " + std::to_string(starsOutside500) + "\n" + - // " - 750kPc is " + std::to_string(starsOutside750) + "\n" + - // " - 1000kPc is " + std::to_string(starsOutside1000) + "\n" + - // " - 1500kPc is " + std::to_string(starsOutside1500) + "\n" + - // " - 2000kPc is " + std::to_string(starsOutside2000) + "\n" + - // " - 5000kPc is " + std::to_string(starsOutside5000)); - - // Write index file of Octree structure. - std::string indexFileOutPath = _outFileOrFolderPath + "index.bin"; - std::ofstream outFileStream(indexFileOutPath, std::ofstream::binary); - if (outFileStream.good()) { - LINFO("Writing index file!"); - _indexOctreeManager->writeToFile(outFileStream, false); - - outFileStream.close(); - } - else { - LERROR(fmt::format( - "Error opening file: {} as index output file.", indexFileOutPath - )); - } - - // Make sure all threads are done. - for (int i = 0; i < 8; ++i) { - writeThreads[i].join(); - } -} - -bool ConstructOctreeTask::checkAllFilters(const std::vector& filterValues) { - // Return true if star is caught in any filter. - return (_filterPosX && filterStar(_posX, filterValues[0])) || - (_filterPosY && filterStar(_posY, filterValues[1])) || - (_filterPosZ && filterStar(_posZ, filterValues[2])) || - (_filterGMag && filterStar(_gMag, filterValues[3], 20.f)) || - (_filterBpRp && filterStar(_bpRp, filterValues[4])) || - (_filterVelX && filterStar(_velX, filterValues[5])) || - (_filterVelY && filterStar(_velY, filterValues[6])) || - (_filterVelZ && filterStar(_velZ, filterValues[7])) || - (_filterBpMag && filterStar(_bpMag, filterValues[8], 20.f)) || - (_filterRpMag && filterStar(_rpMag, filterValues[9], 20.f)) || - (_filterBpG && filterStar(_bpG, filterValues[10])) || - (_filterGRp && filterStar(_gRp, filterValues[11])) || - (_filterRa && filterStar(_ra, filterValues[12])) || - (_filterRaError && filterStar(_raError, filterValues[13])) || - (_filterDec && filterStar(_dec, filterValues[14])) || - (_filterDecError && filterStar(_decError, filterValues[15])) || - (_filterParallax && filterStar(_parallax, filterValues[16])) || - (_filterParallaxError && filterStar(_parallaxError, filterValues[17])) || - (_filterPmra && filterStar(_pmra, filterValues[18])) || - (_filterPmraError && filterStar(_pmraError, filterValues[19])) || - (_filterPmdec && filterStar(_pmdec, filterValues[20])) || - (_filterPmdecError && filterStar(_pmdecError, filterValues[21])) || - (_filterRv && filterStar(_rv, filterValues[22])) || - (_filterRvError && filterStar(_rvError, filterValues[23])); -} - -bool ConstructOctreeTask::filterStar(const glm::vec2& range, float filterValue, - float normValue) -{ - // Return true if star should be filtered away, i.e. if min = max = filterValue or - // if filterValue < min (when min != 0.0) or filterValue > max (when max != 0.0). - return (fabs(range.x - range.y) < FLT_EPSILON && - fabs(range.x - filterValue) < FLT_EPSILON) || - (fabs(range.x - normValue) > FLT_EPSILON && filterValue < range.x) || - (fabs(range.y - normValue) > FLT_EPSILON && filterValue > range.y); -} - -documentation::Documentation ConstructOctreeTask::Documentation() { - using namespace documentation; - return { - "ConstructOctreeTask", - "gaiamission_constructoctreefrombin", - { - { - "Type", - new StringEqualVerifier("ConstructOctreeTask"), - Optional::No - }, - { - KeyInFileOrFolderPath, - new StringVerifier, - Optional::No, - "If SingleFileInput is set to true then this specifies the path to a " - "single BIN file containing a full dataset. Otherwise this specifies the " - "path to a folder with multiple BIN files containing subsets of sorted " - "star data.", - }, - { - KeyOutFileOrFolderPath, - new StringVerifier, - Optional::No, - "If SingleFileInput is set to true then this specifies the output file " - "name (including full path). Otherwise this specifies the path to the " - "folder which to save all files.", - }, - { - KeyMaxDist, - new IntVerifier, - Optional::Yes, - "If set it determines what MAX_DIST to use when creating Octree." - }, - { - KeyMaxStarsPerNode, - new IntVerifier, - Optional::Yes, - "If set it determines what MAX_STAR_PER_NODE to use when creating Octree." - }, - { - KeySingleFileInput, - new BoolVerifier, - Optional::Yes, - "If true then task will read from a single file and output a single " - "binary file with the full Octree. If false then task will read all " - "files in specified folder and output multiple files for the Octree." - }, - { - KeyFilterPosX, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Position X values between [min, max] " - "will be inserted into Octree (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). If min = max then all values " - "equal min|max will be filtered away." - }, - { - KeyFilterPosY, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Position Y values between [min, max] " - "will be inserted into Octree (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). If min = max then all values " - "equal min|max will be filtered away." - }, - { - KeyFilterPosZ, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Position Z values between [min, max] " - "will be inserted into Octree (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). If min = max then all values " - "equal min|max will be filtered away." - }, - { - KeyFilterGMag, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with G mean magnitude values between " - "[min, max] will be inserted into Octree (if min is set to 20.0 it is " - "read as -Inf, if max is set to 20.0 it is read as +Inf). If min = max " - "then all values equal min|max will be filtered away. Default " - "GMag = 20.0 if no value existed." - }, - { - KeyFilterBpRp, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Bp-Rp color values between [min, max] " - "will be inserted into Octree (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). If min = max then all values " - "equal min|max will be filtered away." - }, - { - KeyFilterVelX, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Velocity X values between [min, max] " - "will be inserted into Octree (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). If min = max then all values " - "equal min|max will be filtered away." - }, - { - KeyFilterVelY, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Velocity Y values between [min, max] " - "will be inserted into Octree (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). If min = max then all values " - "equal min|max will be filtered away." - }, - { - KeyFilterVelZ, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Velocity Z values between [min, max] " - "will be inserted into Octree (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). If min = max then all values " - "equal min|max will be filtered away." - }, - { - KeyFilterBpMag, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Bp mean magnitude values between " - "[min, max] will be inserted into Octree (if min is set to 20.0 it is " - "read as -Inf, if max is set to 20.0 it is read as +Inf). If min = max " - "then all values equal min|max will be filtered away. Default " - "BpMag = 20.0 if no value existed." - }, - { - KeyFilterRpMag, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Rp mean magnitude values between " - "[min, max] will be inserted into Octree (if min is set to 20.0 it is " - "read as -Inf, if max is set to 20.0 it is read as +Inf). If min = max " - "then all values equal min|max will be filtered away. Default RpMag = " - "20.0 if no value existed." - }, - { - KeyFilterBpG, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Bp-G color values between [min, max] " - "will be inserted into Octree (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). If min = max then all values " - "equal min|max will be filtered away." - }, - { - KeyFilterGRp, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with G-Rp color values between [min, max] " - "will be inserted into Octree (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). If min = max then all values " - "equal min|max will be filtered away." - }, - { - KeyFilterRa, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with RA values between [min, max] " - "will be inserted into Octree (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). If min = max then all values " - "equal min|max will be filtered away." - }, - { - KeyFilterRaError, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with RA Error values between [min, max] " - "will be inserted into Octree (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). If min = max then all values " - "equal min|max will be filtered away." - }, - { - KeyFilterDec, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with DEC values between [min, max] " - "will be inserted into Octree (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). If min = max then all values " - "equal min|max will be filtered away." - }, - { - KeyFilterDecError, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with DEC Error values between [min, max] " - "will be inserted into Octree (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). If min = max then all values " - "equal min|max will be filtered away." - }, - { - KeyFilterParallax, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Parallax values between [min, max] " - "will be inserted into Octree (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). If min = max then all values " - "equal min|max will be filtered away." - }, - { - KeyFilterParallaxError, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Parallax Error values between " - "[min, max] will be inserted into Octree (if min is set to 0.0 it is " - "read as -Inf, if max is set to 0.0 it is read as +Inf). If min = max " - "then all values equal min|max will be filtered away." - }, - { - KeyFilterPmra, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Proper Motion RA values between " - "[min, max] will be inserted into Octree (if min is set to 0.0 it is " - "read as -Inf, if max is set to 0.0 it is read as +Inf). If min = max " - "then all values equal min|max will be filtered away." - }, - { - KeyFilterPmraError, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Proper Motion RA Error values between " - "[min, max] will be inserted into Octree (if min is set to 0.0 it is " - "read as -Inf, if max is set to 0.0 it is read as +Inf). If min = max " - "then all values equal min|max will be filtered away." - }, - { - KeyFilterPmdec, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Proper Motion DEC values between " - "[min, max] will be inserted into Octree (if min is set to 0.0 it is " - "read as -Inf, if max is set to 0.0 it is read as +Inf). If min = max " - "then all values equal min|max will be filtered away." - }, - { - KeyFilterPmdecError, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Proper Motion DEC Error values between " - "[min, max] will be inserted into Octree (if min is set to 0.0 it is " - "read as -Inf, if max is set to 0.0 it is read as +Inf). If min = max " - "then all values equal min|max will be filtered away." - }, - { - KeyFilterRv, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Radial Velocity values between " - "[min, max] will be inserted into Octree (if min is set to 0.0 it is " - "read as -Inf, if max is set to 0.0 it is read as +Inf). If min = max " - "then all values equal min|max will be filtered away." - }, - { - KeyFilterRvError, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Radial Velocity Error values between " - "[min, max] will be inserted into Octree (if min is set to 0.0 it is " - "read as -Inf, if max is set to 0.0 it is read as +Inf). If min = max " - "then all values equal min|max will be filtered away." - }, - } - }; -} - -} // namespace openspace diff --git a/modules/softwareintegration/tasks/constructoctreetask.h b/modules/softwareintegration/tasks/constructoctreetask.h deleted file mode 100644 index 824521e340..0000000000 --- a/modules/softwareintegration/tasks/constructoctreetask.h +++ /dev/null @@ -1,143 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2020 * - * * - * 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 __OPENSPACE_MODULE_GAIA___CONSTRUCTOCTREETASK___H__ -#define __OPENSPACE_MODULE_GAIA___CONSTRUCTOCTREETASK___H__ - -#include - -#include -#include - -namespace openspace { - -namespace documentation { struct Documentation; } - -class ConstructOctreeTask : public Task { -public: - ConstructOctreeTask(const ghoul::Dictionary& dictionary); - virtual ~ConstructOctreeTask() = default; - - std::string description() override; - void perform(const Task::ProgressCallback& onProgress) override; - static documentation::Documentation Documentation(); - -private: - const int RENDER_VALUES = 8; - - /** - * Reads a single binary file with preprocessed star data and insert the render values - * into an octree structure (if star data passed all defined filters). - * Stores the entire octree in one binary file. - */ - void constructOctreeFromSingleFile(const Task::ProgressCallback& progressCallback); - - /** - * Reads binary star data from 8 preprocessed files (one per branch) in specified - * folder, prepared by ReadFitsTask, and inserts star render data into an octree - * (if star data passed all defined filters). - * Stores octree structure in a binary index file and stores all render data - * separate files, one file per node in the octree. - */ - void constructOctreeFromFolder(const Task::ProgressCallback& progressCallback); - - /** - * Checks all defined filter ranges and \returns true if any of the corresponding - * filterValues are outside of the defined range. - * \returns false if value should be inserted into Octree. - * \param filterValues are all read filter values in binary file. - */ - bool checkAllFilters(const std::vector& filterValues); - - /** - * \returns true if star should be filtered away and false if all filters passed. - * \param range contains ]min, max[ and \param filterValue corresponding value in - * star. Star is filtered either if min = max = filterValue or if filterValue < min - * (when min != 0.0) or filterValue > max (when max != 0.0). - */ - bool filterStar(const glm::vec2& range, float filterValue, float normValue = 0.f); - - std::string _inFileOrFolderPath; - std::string _outFileOrFolderPath; - int _maxDist = 0; - int _maxStarsPerNode = 0; - bool _singleFileInput = false; - - std::shared_ptr _octreeManager; - std::shared_ptr _indexOctreeManager; - - // Filter params - glm::vec2 _posX = glm::vec2(0.f); - bool _filterPosX = false; - glm::vec2 _posY = glm::vec2(0.f); - bool _filterPosY = false; - glm::vec2 _posZ = glm::vec2(0.f); - bool _filterPosZ = false; - glm::vec2 _gMag = glm::vec2(0.f); - bool _filterGMag = false; - glm::vec2 _bpRp = glm::vec2(0.f); - bool _filterBpRp = false; - glm::vec2 _velX = glm::vec2(0.f); - bool _filterVelX = false; - glm::vec2 _velY = glm::vec2(0.f); - bool _filterVelY = false; - glm::vec2 _velZ = glm::vec2(0.f); - bool _filterVelZ = false; - glm::vec2 _bpMag = glm::vec2(0.f); - bool _filterBpMag = false; - glm::vec2 _rpMag = glm::vec2(0.f); - bool _filterRpMag = false; - glm::vec2 _bpG = glm::vec2(0.f); - bool _filterBpG = false; - glm::vec2 _gRp = glm::vec2(0.f); - bool _filterGRp = false; - glm::vec2 _ra = glm::vec2(0.f); - bool _filterRa = false; - glm::vec2 _raError = glm::vec2(0.f); - bool _filterRaError = false; - glm::vec2 _dec = glm::vec2(0.f); - bool _filterDec = false; - glm::vec2 _decError = glm::vec2(0.f); - bool _filterDecError = false; - glm::vec2 _parallax = glm::vec2(0.f); - bool _filterParallax = false; - glm::vec2 _parallaxError = glm::vec2(0.f); - bool _filterParallaxError = false; - glm::vec2 _pmra = glm::vec2(0.f); - bool _filterPmra = false; - glm::vec2 _pmraError = glm::vec2(0.f); - bool _filterPmraError = false; - glm::vec2 _pmdec = glm::vec2(0.f); - bool _filterPmdec = false; - glm::vec2 _pmdecError = glm::vec2(0.f); - bool _filterPmdecError = false; - glm::vec2 _rv = glm::vec2(0.f); - bool _filterRv = false; - glm::vec2 _rvError = glm::vec2(0.f); - bool _filterRvError = false; -}; - -} // namespace openspace - -#endif // __OPENSPACE_MODULE_GAIA___CONSTRUCTOCTREETASK___H__ diff --git a/modules/softwareintegration/tasks/readfilejob.cpp b/modules/softwareintegration/tasks/readfilejob.cpp deleted file mode 100644 index ac15d85d87..0000000000 --- a/modules/softwareintegration/tasks/readfilejob.cpp +++ /dev/null @@ -1,264 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2020 * - * * - * 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 - -namespace { - constexpr const char* _loggerCat = "ReadFileJob"; -} - -namespace openspace::gaia { - -ReadFileJob::ReadFileJob(std::string filePath, std::vector allColumns, - int firstRow, int lastRow, size_t nDefaultCols, - int nValuesPerStar, std::shared_ptr fitsReader) - : _inFilePath(std::move(filePath)) - , _allColumns(std::move(allColumns)) - , _firstRow(firstRow) - , _lastRow(lastRow) - , _nDefaultCols(nDefaultCols) - , _nValuesPerStar(nValuesPerStar) - , _fitsFileReader(std::move(fitsReader)) - , _octants(8) -{} - -void ReadFileJob::execute() { - // Read columns from FITS file. If rows aren't specified then full table will be read. - std::shared_ptr> table = _fitsFileReader->readTable( - _inFilePath, - _allColumns, - _firstRow, - _lastRow - ); - - if (!table) { - throw ghoul::RuntimeError( - fmt::format("Failed to open Fits file '{}'", _inFilePath - )); - } - - int nStars = table->readRows - _firstRow + 1; - - int nNullArr = 0; - size_t nColumnsRead = _allColumns.size(); - if (nColumnsRead != _nDefaultCols) { - LINFO("Additional columns will be read! Consider add column in code for " - "significant speedup!"); - } - - // Copy columns to local variables. - std::unordered_map>& tableContent = table->contents; - - // Default columns parameters. - //std::vector l_longitude = std::move(tableContent[_allColumns[0]]); - //std::vector b_latitude = std::move(tableContent[_allColumns[1]]); - std::vector ra = std::move(tableContent[_allColumns[0]]); - std::vector ra_err = std::move(tableContent[_allColumns[1]]); - std::vector dec = std::move(tableContent[_allColumns[2]]); - std::vector dec_err = std::move(tableContent[_allColumns[3]]); - std::vector parallax = std::move(tableContent[_allColumns[4]]); - std::vector parallax_err = std::move(tableContent[_allColumns[5]]); - std::vector pmra = std::move(tableContent[_allColumns[6]]); - std::vector pmra_err = std::move(tableContent[_allColumns[7]]); - std::vector pmdec = std::move(tableContent[_allColumns[8]]); - std::vector pmdec_err = std::move(tableContent[_allColumns[9]]); - std::vector meanMagG = std::move(tableContent[_allColumns[10]]); - std::vector meanMagBp = std::move(tableContent[_allColumns[11]]); - std::vector meanMagRp = std::move(tableContent[_allColumns[12]]); - std::vector bp_rp = std::move(tableContent[_allColumns[13]]); - std::vector bp_g = std::move(tableContent[_allColumns[14]]); - std::vector g_rp = std::move(tableContent[_allColumns[15]]); - std::vector radial_vel = std::move(tableContent[_allColumns[16]]); - std::vector radial_vel_err = std::move(tableContent[_allColumns[17]]); - - - // Construct data array. OBS: ORDERING IS IMPORTANT! This is where slicing happens. - for (int i = 0; i < nStars; ++i) { - std::vector values(_nValuesPerStar); - size_t idx = 0; - - // Default order for rendering: - // Position [X, Y, Z] - // Mean G-band Magnitude - // -- Mean Bp-band Magnitude - // -- Mean Rp-band Magnitude - // Bp-Rp Color - // -- Bp-G Color - // -- G-Rp Color - // Velocity [X, Y, Z] - - // Return early if star doesn't have a measured position. - if (std::isnan(ra[i]) || std::isnan(dec[i])) { - nNullArr++; - continue; - } - - // Store positions. Set to a default distance if parallax doesn't exist. - float radiusInKiloParsec = 9.0; - if (!std::isnan(parallax[i])) { - // Parallax is in milliArcseconds -> distance in kiloParsecs - // https://gea.esac.esa.int/archive/documentation/GDR2/Gaia_archive/ - // chap_datamodel/sec_dm_main_tables/ssec_dm_gaia_source.html - //LINFO("Parallax: " + std::to_string(parallax[i])); - radiusInKiloParsec = 1.f / parallax[i]; - } - /*// Convert to Galactic Coordinates from Galactic Lon & Lat. - // https://gea.esac.esa.int/archive/documentation/GDR2/Data_processing/ - // chap_cu3ast/sec_cu3ast_intro/ssec_cu3ast_intro_tansforms.html#SSS1 - values[idx++] = radiusInKiloParsec * cos(glm::radians(b_latitude[i])) * - cos(glm::radians(l_longitude[i])); // Pos X - values[idx++] = radiusInKiloParsec * cos(glm::radians(b_latitude[i])) * - sin(glm::radians(l_longitude[i])); // Pos Y - values[idx++] = radiusInKiloParsec * sin(glm::radians(b_latitude[i])); // Pos Z - */ - - // Convert ICRS Equatorial Ra and Dec to Galactic latitude and longitude. - glm::mat3 aPrimG = glm::mat3( - // Col 0 - glm::vec3(-0.0548755604162154, 0.4941094278755837, -0.8676661490190047), - // Col 1 - glm::vec3(-0.8734370902348850, -0.4448296299600112, -0.1980763734312015), - // Col 2 - glm::vec3(-0.4838350155487132, 0.7469822444972189, 0.4559837761750669) - ); - glm::vec3 rICRS = glm::vec3( - cos(glm::radians(ra[i])) * cos(glm::radians(dec[i])), - sin(glm::radians(ra[i])) * cos(glm::radians(dec[i])), - sin(glm::radians(dec[i])) - ); - glm::vec3 rGal = aPrimG * rICRS; - values[idx++] = radiusInKiloParsec * rGal.x; // Pos X - values[idx++] = radiusInKiloParsec * rGal.y; // Pos Y - values[idx++] = radiusInKiloParsec * rGal.z; // Pos Z - - /*if (abs(rGal.x - values[0]) > 1e-5 || abs(rGal.y - values[1]) > 1e-5 || - abs(rGal.z - values[2]) > 1e-5) { - LINFO("rGal: " + std::to_string(rGal) + - " - LB: [" + std::to_string(values[0]) + ", " + std::to_string(values[1]) + - ", " + std::to_string(values[2]) + "]"); - }*/ - - // Store magnitude render value. (Set default to high mag = low brightness) - values[idx++] = std::isnan(meanMagG[i]) ? 20.f : meanMagG[i]; // Mean G-band Mag - - // Store color render value. (Default value is bluish stars) - values[idx++] = std::isnan(bp_rp[i]) ? 0.f : bp_rp[i]; // Bp-Rp Color - - - // Store velocity. - if (std::isnan(pmra[i])) { - pmra[i] = 0.f; - } - if (std::isnan(pmdec[i])) { - pmdec[i] = 0.f; - } - - // Convert Proper Motion from ICRS [Ra,Dec] to Galactic Tanget Vector [l,b]. - glm::vec3 uICRS = glm::vec3( - -sin(glm::radians(ra[i])) * pmra[i] - - cos(glm::radians(ra[i])) * sin(glm::radians(dec[i])) * pmdec[i], - cos(glm::radians(ra[i])) * pmra[i] - - sin(glm::radians(ra[i])) * sin(glm::radians(dec[i])) * pmdec[i], - cos(glm::radians(dec[i])) * pmdec[i] - ); - glm::vec3 pmVecGal = aPrimG * uICRS; - - // Convert to Tangential vector [m/s] from Proper Motion vector [mas/yr] - float tanVelX = 1000.f * 4.74f * radiusInKiloParsec * pmVecGal.x; - float tanVelY = 1000.f * 4.74f * radiusInKiloParsec * pmVecGal.y; - float tanVelZ = 1000.f * 4.74f * radiusInKiloParsec * pmVecGal.z; - - // Calculate True Space Velocity [m/s] if we have the radial velocity - if (!std::isnan(radial_vel[i])) { - // Calculate Radial Velocity in the direction of the star. - // radial_vel is given in [km/s] -> convert to [m/s]. - float radVelX = 1000.f * radial_vel[i] * rGal.x; - float radVelY = 1000.f * radial_vel[i] * rGal.y; - float radVelZ = 1000.f * radial_vel[i] * rGal.z; - - // Use Pythagoras theorem for the final Space Velocity [m/s]. - values[idx++] = sqrt(pow(radVelX, 2) + pow(tanVelX, 2)); // Vel X [U] - values[idx++] = sqrt(pow(radVelY, 2) + pow(tanVelY, 2)); // Vel Y [V] - values[idx++] = sqrt(pow(radVelZ, 2) + pow(tanVelZ, 2)); // Vel Z [W] - } - // Otherwise use the vector [m/s] we got from proper motion. - else { - radial_vel[i] = 0.f; - values[idx++] = tanVelX; // Vel X [U] - values[idx++] = tanVelY; // Vel Y [V] - values[idx++] = tanVelZ; // Vel Z [W] - } - - // Store additional parameters to filter by. - values[idx++] = std::isnan(meanMagBp[i]) ? 20.f : meanMagBp[i]; - values[idx++] = std::isnan(meanMagRp[i]) ? 20.f : meanMagRp[i]; - values[idx++] = std::isnan(bp_g[i]) ? 0.f : bp_g[i]; - values[idx++] = std::isnan(g_rp[i]) ? 0.f : g_rp[i]; - values[idx++] = ra[i]; - values[idx++] = std::isnan(ra_err[i]) ? 0.f : ra_err[i]; - values[idx++] = dec[i]; - values[idx++] = std::isnan(dec_err[i]) ? 0.f : dec_err[i]; - values[idx++] = std::isnan(parallax[i]) ? 0.f : parallax[i]; - values[idx++] = std::isnan(parallax_err[i]) ? 0.f : parallax_err[i]; - values[idx++] = pmra[i]; - values[idx++] = std::isnan(pmra_err[i]) ? 0.f : pmra_err[i]; - values[idx++] = pmdec[i]; - values[idx++] = std::isnan(pmdec_err[i]) ? 0.f : pmdec_err[i]; - values[idx++] = radial_vel[i]; - values[idx++] = std::isnan(radial_vel_err[i]) ? 0.f : radial_vel_err[i]; - - // Read extra columns, if any. This will slow down the sorting tremendously! - for (size_t col = _nDefaultCols; col < nColumnsRead; ++col) { - std::vector vecData = std::move(tableContent[_allColumns[col]]); - values[idx++] = std::isnan(vecData[col]) ? 0.f : vecData[col]; - } - - size_t index = 0; - if (values[0] < 0.0) { - index += 1; - } - if (values[1] < 0.0) { - index += 2; - } - if (values[2] < 0.0) { - index += 4; - } - - _octants[index].insert(_octants[index].end(), values.begin(), values.end()); - } - - /*LINFO(std::to_string(nNullArr) + " out of " + - std::to_string(nStars) + " read stars were nullArrays.");*/ -} - -std::vector> ReadFileJob::product() { - return _octants; -} - -} // namespace openspace::gaiamission diff --git a/modules/softwareintegration/tasks/readfilejob.h b/modules/softwareintegration/tasks/readfilejob.h deleted file mode 100644 index 13f3cfc38b..0000000000 --- a/modules/softwareintegration/tasks/readfilejob.h +++ /dev/null @@ -1,71 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2020 * - * * - * 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 __OPENSPACE_MODULE_GAIA___READFILEJOB___H__ -#define __OPENSPACE_MODULE_GAIA___READFILEJOB___H__ - -#include - -#include - -namespace openspace::gaia { - -struct ReadFileJob : public Job>> { - /** - * Constructs a Job that will read a single FITS file in a concurrent thread and - * divide the star data into 8 octants depending on position. - * \param allColumns define which columns that will be read, it should correspond - * to the pre-defined order in the job. If additional columns are defined they will - * be read but slow down the process. - * Proper conversions of positions and velocities will take place and all values - * will be checked for NaNs. - * If \param firstRow is < 1 then reading will begin at first row in table. - * If \param lastRow < firstRow then entire table will be read. - * \param nValuesPerStar defines how many values that will be stored per star. - */ - ReadFileJob(std::string filePath, std::vector allColumns, int firstRow, - int lastRow, size_t nDefaultCols, int nValuesPerStar, - std::shared_ptr fitsReader); - - ~ReadFileJob() = default; - - void execute() override; - - std::vector> product() override; - -private: - std::string _inFilePath; - int _firstRow; - int _lastRow; - size_t _nDefaultCols; - int _nValuesPerStar; - std::vector _allColumns; - - std::shared_ptr _fitsFileReader; - std::vector> _octants; -}; - -} // namespace openspace::gaiamission - -#endif // __OPENSPACE_MODULE_GAIA___READFILEJOB___H__ diff --git a/modules/softwareintegration/tasks/readfitstask.cpp b/modules/softwareintegration/tasks/readfitstask.cpp deleted file mode 100644 index 5cbe1cf384..0000000000 --- a/modules/softwareintegration/tasks/readfitstask.cpp +++ /dev/null @@ -1,392 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2020 * - * * - * 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 - -namespace { - constexpr const char* KeyInFileOrFolderPath = "InFileOrFolderPath"; - constexpr const char* KeyOutFileOrFolderPath = "OutFileOrFolderPath"; - constexpr const char* KeySingleFileProcess = "SingleFileProcess"; - constexpr const char* KeyThreadsToUse = "ThreadsToUse"; - constexpr const char* KeyFirstRow = "FirstRow"; - constexpr const char* KeyLastRow = "LastRow"; - constexpr const char* KeyFilterColumnNames = "FilterColumnNames"; - - constexpr const char* _loggerCat = "ReadFitsTask"; -} // namespace - -namespace openspace { - -ReadFitsTask::ReadFitsTask(const ghoul::Dictionary& dictionary) { - openspace::documentation::testSpecificationAndThrow( - documentation(), - dictionary, - "ReadFitsTask" - ); - - _inFileOrFolderPath = absPath(dictionary.value(KeyInFileOrFolderPath)); - _outFileOrFolderPath = absPath(dictionary.value(KeyOutFileOrFolderPath)); - - if (dictionary.hasKey(KeySingleFileProcess)) { - _singleFileProcess = dictionary.value(KeySingleFileProcess); - } - - if (dictionary.hasKey(KeyThreadsToUse)) { - _threadsToUse = static_cast(dictionary.value(KeyThreadsToUse)); - if (_threadsToUse < 1) { - LINFO(fmt::format( - "User defined ThreadsToUse was: {}. Will be set to 1", _threadsToUse - )); - _threadsToUse = 1; - } - } - - if (dictionary.hasKey(KeyFirstRow)) { - _firstRow = static_cast(dictionary.value(KeyFirstRow)); - } - - if (dictionary.hasKey(KeyLastRow)) { - _lastRow = static_cast(dictionary.value(KeyLastRow)); - } - - - if (dictionary.hasKey(KeyFilterColumnNames)) { - ghoul::Dictionary d = dictionary.value(KeyFilterColumnNames); - - // Ugly fix for ASCII sorting when there are more columns read than 10. - std::set intKeys; - for (const std::string& key : d.keys()) { - intKeys.insert(std::stoi(key)); - } - - for (int key : intKeys) { - _filterColumnNames.push_back(d.value(std::to_string(key))); - } - } -} - -std::string ReadFitsTask::description() { - return fmt::format( - "Read the specified fits file (or all fits files in specified folder): {}\n and " - "write raw star data into: {}\nAll columns required for default rendering and " - "filtering parameters will always be read but user can define additional filter " - "columns to read.", _inFileOrFolderPath, _outFileOrFolderPath - ); -} - -void ReadFitsTask::perform(const Task::ProgressCallback& onProgress) { - onProgress(0.f); - - if (_singleFileProcess) { - readSingleFitsFile(onProgress); - } - else { - readAllFitsFilesFromFolder(onProgress); - } - - onProgress(1.f); -} - -void ReadFitsTask::readSingleFitsFile(const Task::ProgressCallback& progressCallback) { - int32_t nValuesPerStar = 0; - - FitsFileReader fileReader(false); - std::vector fullData = fileReader.readFitsFile( - _inFileOrFolderPath, - nValuesPerStar, - _firstRow, - _lastRow, - _filterColumnNames - ); - - progressCallback(0.8f); - - std::ofstream outFileStream(_outFileOrFolderPath, std::ofstream::binary); - if (outFileStream.good()) { - int32_t nValues = static_cast(fullData.size()); - LINFO(fmt::format("Writing {} values to file {}", nValues, _outFileOrFolderPath)); - LINFO("Number of values per star: " + std::to_string(nValuesPerStar)); - - if (nValues == 0) { - LERROR("Error writing file - No values were read from file."); - } - outFileStream.write( - reinterpret_cast(&nValues), - sizeof(int32_t) - ); - outFileStream.write( - reinterpret_cast(&nValuesPerStar), - sizeof(int32_t) - ); - - size_t nBytes = nValues * sizeof(fullData[0]); - outFileStream.write(reinterpret_cast(fullData.data()), nBytes); - - outFileStream.close(); - } - else { - LERROR(fmt::format( - "Error opening file: {} as output data file.", _outFileOrFolderPath - )); - } -} - -void ReadFitsTask::readAllFitsFilesFromFolder(const Task::ProgressCallback&) { - std::vector> octants(8); - std::vector isFirstWrite(8, true); - size_t finishedJobs = 0; - int totalStars = 0; - - _firstRow = std::max(_firstRow, 1); - - // Create Threadpool and JobManager. - LINFO("Threads in pool: " + std::to_string(_threadsToUse)); - ThreadPool threadPool(_threadsToUse); - ConcurrentJobManager>> jobManager(threadPool); - - // Get all files in specified folder. - ghoul::filesystem::Directory currentDir(_inFileOrFolderPath); - std::vector allInputFiles = currentDir.readFiles(); - size_t nInputFiles = allInputFiles.size(); - LINFO("Files to read: " + std::to_string(nInputFiles)); - - // Define what columns to read. - _allColumnNames.clear(); - // Read in the order of table in file. - std::vector defaultColumnNames = { - "ra", - "ra_error", - "dec", - "dec_error", - "parallax", - "parallax_error", - "pmra", - "pmra_error", - "pmdec", - "pmdec_error", - "phot_g_mean_mag", - "phot_bp_mean_mag", - "phot_rp_mean_mag", - "bp_rp", - "bp_g", - "g_rp", - "radial_velocity", - "radial_velocity_error", - }; - _allColumnNames.insert( - _allColumnNames.end(), - defaultColumnNames.begin(), - defaultColumnNames.end() - ); - // Append additional filter parameters to default rendering parameters. - _allColumnNames.insert( - _allColumnNames.end(), - _filterColumnNames.begin(), - _filterColumnNames.end() - ); - - std::string allNames = "Columns to read: \n"; - for (const std::string& colName : _allColumnNames) { - allNames += colName + "\n"; - } - LINFO(allNames); - - // Declare how many values to save for each star. - int32_t nValuesPerStar = 24; - size_t nDefaultColumns = defaultColumnNames.size(); - auto fitsFileReader = std::make_shared(false); - - // Divide all files into ReadFilejobs and then delegate them onto several threads! - while (!allInputFiles.empty()) { - std::string fileToRead = allInputFiles.back(); - allInputFiles.erase(allInputFiles.end() - 1); - - // Add reading of file to jobmanager, which will distribute it to our threadpool. - auto readFileJob = std::make_shared( - fileToRead, - _allColumnNames, - _firstRow, - _lastRow, - nDefaultColumns, - nValuesPerStar, - fitsFileReader - ); - jobManager.enqueueJob(readFileJob); - } - - LINFO("All files added to queue!"); - - // Check for finished jobs. - while (finishedJobs < nInputFiles) { - if (jobManager.numFinishedJobs() > 0) { - std::vector> newOctant = - jobManager.popFinishedJob()->product(); - - finishedJobs++; - - for (int i = 0; i < 8; ++i) { - // Add read values to global octant and check if it's time to write! - octants[i].insert( - octants[i].end(), - newOctant[i].begin(), - newOctant[i].end() - ); - if ((octants[i].size() > MAX_SIZE_BEFORE_WRITE) || - (finishedJobs == nInputFiles)) - { - // Write to file! - totalStars += writeOctantToFile( - octants[i], - i, - isFirstWrite, - nValuesPerStar - ); - - octants[i].clear(); - octants[i].shrink_to_fit(); - } - } - } - } - LINFO(fmt::format("A total of {} stars were written to binary files.", totalStars)); -} - -int ReadFitsTask::writeOctantToFile(const std::vector& octantData, int index, - std::vector& isFirstWrite, int nValuesPerStar) -{ - std::string outPath = fmt::format("{}octant_{}.bin", _outFileOrFolderPath, index); - std::ofstream fileStream(outPath, std::ofstream::binary | std::ofstream::app); - if (fileStream.good()) { - int32_t nValues = static_cast(octantData.size()); - LINFO("Write " + std::to_string(nValues) + " values to " + outPath); - - if (nValues == 0) { - LERROR("Error writing file - No values were read from file."); - } - // If this is the first write then write number of values per star! - if (isFirstWrite[index]) { - LINFO("First write for Octant_" + std::to_string(index)); - fileStream.write( - reinterpret_cast(&nValuesPerStar), - sizeof(int32_t) - ); - isFirstWrite[index] = false; - } - - size_t nBytes = nValues * sizeof(octantData[0]); - fileStream.write(reinterpret_cast(octantData.data()), nBytes); - - fileStream.close(); - - // Return number of stars written. - return nValues / nValuesPerStar; - } - else { - LERROR(fmt::format("Error opening file: {} as output data file.", outPath)); - return 0; - } -} - -documentation::Documentation ReadFitsTask::Documentation() { - using namespace documentation; - return { - "ReadFitsFile", - "gaiamission_fitsfiletorawdata", - { - { - "Type", - new StringEqualVerifier("ReadFitsTask"), - Optional::No - }, - { - KeyInFileOrFolderPath, - new StringVerifier, - Optional::No, - "If SingleFileProcess is set to true then this specifies the path to a " - "single FITS file that will be read. Otherwise it specifies the path to " - "a folder with multiple FITS files that are to be read.", - }, - { - KeyOutFileOrFolderPath, - new StringVerifier, - Optional::No, - "If SingleFileProcess is set to true then this specifies the name " - "(including entire path) to the output file. Otherwise it specifies the " - "path to the output folder which to export binary star data to.", - }, - { - KeySingleFileProcess, - new BoolVerifier, - Optional::Yes, - "If true then task will read from a single FITS file and output a single " - "binary file. If false then task will read all files in specified folder " - "and output multiple files sorted by location." - }, - { - KeyThreadsToUse, - new IntVerifier, - Optional::Yes, - "Defines how many threads to use when reading from multiple files." - }, - { - KeyFirstRow, - new IntVerifier, - Optional::Yes, - "Defines the first row that will be read from the specified FITS " - "file(s). If not defined then reading will start at first row.", - }, - { - KeyLastRow, - new IntVerifier, - Optional::Yes, - "Defines the last row that will be read from the specified FITS file(s). " - "If not defined (or less than FirstRow) then full file(s) will be read.", - }, - { - KeyFilterColumnNames, - new StringListVerifier, - Optional::Yes, - "A list of strings with the names of all the additional columns that are " - "to be read from the specified FITS file(s). These columns can be used " - "for filtering while constructing Octree later.", - }, - - } - }; -} - -} // namespace openspace diff --git a/modules/softwareintegration/tasks/readfitstask.h b/modules/softwareintegration/tasks/readfitstask.h deleted file mode 100644 index ba3981fa0b..0000000000 --- a/modules/softwareintegration/tasks/readfitstask.h +++ /dev/null @@ -1,82 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2020 * - * * - * 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 __OPENSPACE_MODULE_GAIA___READFITSTASK___H__ -#define __OPENSPACE_MODULE_GAIA___READFITSTASK___H__ - -#include -#include -#include -#include - -namespace openspace { - -namespace documentation { struct Documentation; } - -class ReadFitsTask : public Task { -public: - ReadFitsTask(const ghoul::Dictionary& dictionary); - virtual ~ReadFitsTask() = default; - - std::string description() override; - void perform(const Task::ProgressCallback& onProgress) override; - static documentation::Documentation Documentation(); - -private: - const size_t MAX_SIZE_BEFORE_WRITE = 48000000; // ~183MB -> 2M stars with 24 values - //const size_t MAX_SIZE_BEFORE_WRITE = 9000000; // ~34MB -> 0,5 stars with 18 values - - /** - * Reads a single FITS file and stores ordered star data in one binary file. - */ - void readSingleFitsFile(const Task::ProgressCallback& progressCallback); - - /** - * Reads all FITS files in a folder with multiple threads and stores ordered star - * data into 8 binary files. - */ - void readAllFitsFilesFromFolder(const Task::ProgressCallback& progressCallback); - - /** - * Writes \param data to octant [\param index] file. - * \param isFirstWrite defines if this is the first write to specified octant, if so - * the file is created, otherwise the accumulated data is appended to the end of the - * file. - */ - int writeOctantToFile(const std::vector& data, int index, - std::vector& isFirstWrite, int nValuesPerStar); - - std::string _inFileOrFolderPath; - std::string _outFileOrFolderPath; - bool _singleFileProcess = false; - size_t _threadsToUse = 1; - int _firstRow = 0; - int _lastRow = 0; - std::vector _allColumnNames; - std::vector _filterColumnNames; -}; - -} // namespace openspace - -#endif // __OPENSPACE_MODULE_GAIA___READFITSTASK___H__ diff --git a/modules/softwareintegration/tasks/readspecktask.cpp b/modules/softwareintegration/tasks/readspecktask.cpp deleted file mode 100644 index d30d39d058..0000000000 --- a/modules/softwareintegration/tasks/readspecktask.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2020 * - * * - * 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 - -namespace { - constexpr const char* KeyInFilePath = "InFilePath"; - constexpr const char* KeyOutFilePath = "OutFilePath"; - - constexpr const char* _loggerCat = "ReadSpeckTask"; -} // namespace - -namespace openspace { - -ReadSpeckTask::ReadSpeckTask(const ghoul::Dictionary& dictionary) { - openspace::documentation::testSpecificationAndThrow( - documentation(), - dictionary, - "ReadSpeckTask" - ); - - _inFilePath = absPath(dictionary.value(KeyInFilePath)); - _outFilePath = absPath(dictionary.value(KeyOutFilePath)); -} - -std::string ReadSpeckTask::description() { - return fmt::format( - "Read speck file {} and write raw star data into {}", _inFilePath, _outFilePath - ); -} - -void ReadSpeckTask::perform(const Task::ProgressCallback& onProgress) { - onProgress(0.f); - - int32_t nRenderValues = 0; - - FitsFileReader fileReader(false); - std::vector fullData = fileReader.readSpeckFile(_inFilePath, nRenderValues); - - onProgress(0.9f); - - std::ofstream fileStream(_outFilePath, std::ofstream::binary); - if (fileStream.good()) { - int32_t nValues = static_cast(fullData.size()); - LINFO("nValues: " + std::to_string(nValues)); - - if (nValues == 0) { - LERROR("Error writing file - No values were read from file."); - } - fileStream.write(reinterpret_cast(&nValues), sizeof(int32_t)); - fileStream.write(reinterpret_cast(&nRenderValues), sizeof(int32_t)); - - size_t nBytes = nValues * sizeof(fullData[0]); - fileStream.write(reinterpret_cast(fullData.data()), nBytes); - - fileStream.close(); - } - else { - LERROR(fmt::format("Error opening file: {} as output data file.", _outFilePath)); - } - - onProgress(1.f); -} - -documentation::Documentation ReadSpeckTask::Documentation() { - using namespace documentation; - return { - "ReadSpeckTask", - "gaiamission_speckfiletorawdata", - { - { - "Type", - new StringEqualVerifier("ReadSpeckTask"), - Optional::No - }, - { - KeyInFilePath, - new StringVerifier, - Optional::No, - "The path to the SPECK file that are to be read.", - }, - { - KeyOutFilePath, - new StringVerifier, - Optional::No, - "The path to the file to export raw VBO data to.", - }, - } - }; -} - -} // namespace openspace diff --git a/modules/softwareintegration/tasks/readspecktask.h b/modules/softwareintegration/tasks/readspecktask.h deleted file mode 100644 index e9c6517dfb..0000000000 --- a/modules/softwareintegration/tasks/readspecktask.h +++ /dev/null @@ -1,52 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2020 * - * * - * 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 __OPENSPACE_MODULE_GAIA___READSPECKTASK___H__ -#define __OPENSPACE_MODULE_GAIA___READSPECKTASK___H__ - -#include - -#include - -namespace openspace { - -namespace documentation { struct Documentation; } - -class ReadSpeckTask : public Task { -public: - ReadSpeckTask(const ghoul::Dictionary& dictionary); - virtual ~ReadSpeckTask() = default; - - std::string description() override; - void perform(const Task::ProgressCallback& onProgress) override; - static documentation::Documentation Documentation(); - -private: - std::string _inFilePath; - std::string _outFilePath; -}; - -} // namespace openspace - -#endif // __OPENSPACE_MODULE_GAIA___READSPECKTASK___H__ diff --git a/openspace.cfg b/openspace.cfg index ad59b8f18e..59b6f7a5eb 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -45,7 +45,7 @@ SGCTConfig = sgct.config.single{} -- Sets the scene that is to be loaded by OpenSpace. A scene file is a description -- of all entities that will be visible during an instance of OpenSpace -Asset = "default" + Asset = "default" -- Asset = "asteroids" -- Asset = "default_full" -- Asset = "newhorizons"