#include "OctreeLoader.h" #include "TreeTypeParser.h" #include "SettingsParser.h" #include "../../scene/Material/Color.h" #include "../../scene/Material/SmallNormal.h" #include "../../scene/Material/ColorAndNormal.h" #include "../../scene/Material/ColorAndNormalAndValue.h" #include "../../scene/Material/ColorAndOpacity.h" #include "../../scene/Octree/BaseTree.h" #include "../../scene/Octree/Tree.h" #include "../../scene/Octree/MaterialTree.h" #include "../../scene/Octree/MultiRootTree.h" #include "../../scene/Octree/ColorChannelMultiRootTree.h" #include "../../scene/Octree/MultiRootBitsTree.h" #include "../../scene/Octree/MaterialLibraryTree.h" #include "../../scene/Octree/HierarchicalShiftingColoredTree.h" #include "../../scene/Octree/HierarchicalColorsOnlyTree.h" #include "../../scene/Octree/MaterialLibraryUniqueIndexTree.h" #include "../../scene/Octree/UniqueIndexShiftTree.h" #include "../../scene/Octree/MaterialLibraryMultiRootTree.h" #include "../../scene/Octree/IMaterialTexture.h" #include "../../scene/Octree/IBlockTexture.h" #include "../../scene/PoolBuilder/StandardPoolBuilder.h" #include "CompressedTextureFactory.h" #include "PoolBuilderFactory.h" #include "../../scene/Material/MaterialLibraryPointer.h" #include "../../scene/Material/SignedIntMaterial.h" #include "ColorQuantizerFactory.h" #include "../../PropertyLoader.h" #include "../Util/Stopwatch.h" #include "../StringHelper.h" #include "../MathHelper.h" bool OctreeLoader::VerifyCache() { bool useCache = SettingsParser::GetUseCacheFromSettings(); if (!useCache) return false; bool verbose = SettingsParser::GetVerboseFromSettings(); if (verbose) printf("Verifying cache... "); Stopwatch watch; watch.Reset(); auto octreeType = SettingsParser::GetTreeTypeFromSettings(); unsigned8 maxLevel = SettingsParser::GetMaxLevelFromSettings(); std::string filename = SettingsParser::GetFilenameFromSettings(); bool cacheValid = VerifyCache(octreeType, maxLevel, filename); if (verbose) printf("Cache is %s, confirmed in %d ms\n", cacheValid ? "valid" : "invalid", (int)(watch.GetTime() * 1000)); return cacheValid; } bool OctreeLoader::VerifyCache(std::string treeType, unsigned8 maxLevel, std::string filename) { std::string outputFile = GetFullFilename(treeType, maxLevel, filename); auto tree = CreateTree(treeType, maxLevel); bool cacheValid = tree->VerifyTree(outputFile.c_str()); delete tree; return cacheValid; } BaseTree* OctreeLoader::ReadCache() { bool verbose = SettingsParser::GetVerboseFromSettings(); if (verbose) printf("Reading cache... "); Stopwatch watch; watch.Reset(); auto octreeType = SettingsParser::GetTreeTypeFromSettings(); unsigned8 maxLevel = SettingsParser::GetMaxLevelFromSettings(); std::string filename = SettingsParser::GetFilenameFromSettings(); auto tree = ReadCache(octreeType, maxLevel, filename); if (verbose) printf("Read tree with %llu nodes succesfully in %u ms\n", (unsigned64)tree->GetNodeCount(), (unsigned)(watch.GetTime() * 1000)); return tree; } BaseTree* OctreeLoader::ReadCache(std::string treeType, unsigned8 maxLevel, std::string filename, bool verbose) { Stopwatch watch; watch.Reset(); std::string outputFile = GetFullFilename(treeType, maxLevel, filename); if (verbose) printf("Reading file %s.oct.", outputFile.c_str()); auto tree = CreateTree(treeType, maxLevel); bool readSuccessful = tree->ReadTree(outputFile.c_str()); if (!readSuccessful) { delete tree; if (verbose) printf("Reading .oct file failed.\n"); return NULL; } if (verbose) printf("Read .oct file in %u ms.\n", (unsigned)(watch.GetTime() * 1000)); if (verbose) tree->PrintDebugInfo(); return tree; } void OctreeLoader::DeleteCache(std::string treeType, unsigned8 maxLevel, std::string filename) { try { std::remove(Tree<>::GetOctreeFileName(GetFullFilename(treeType, maxLevel, filename).c_str()).c_str()); } catch (...) { printf("Deleting cache file %s failed", GetFullFilename(treeType.c_str(), maxLevel, filename).c_str()); } } bool OctreeLoader::WriteCache(BaseTree* tree, std::string treeType, std::string filename, bool verbose) { std::string outputFile = GetFullFilename(treeType, tree->GetMaxLevel(), filename); // Write the final tree to a file Stopwatch watch; watch.Reset(); if (verbose) printf("Writing DAG to \"%s\"... ", outputFile.c_str()); bool res = tree->WriteTree(outputFile.c_str()); if (verbose) printf("Writing took %d ms\n", (int)(watch.GetTime() * 1000)); return res; } bool OctreeLoader::VerifyPool() { bool useCache = SettingsParser::GetUsePoolCacheFromSettings(); if (!useCache) return false; std::string filename = SettingsParser::GetFilenameFromSettings(); unsigned8 maxLevel = SettingsParser::GetMaxLevelFromSettings(); std::string treeType = SettingsParser::GetTreeTypeFromSettings(); return VerifyPool(treeType, maxLevel, filename); } bool OctreeLoader::VerifyPool(std::string treeType, unsigned8 maxLevel, std::string filename) { auto fullFileName = GetFullFilename(treeType, maxLevel, filename); StandardPoolBuilder builder; return builder.VerifyCachedPool(fullFileName, maxLevel); } bool OctreeLoader::BuildNodePool(BaseTree* tree, std::string poolType, std::string poolFullFilename, std::vector& outPool, unsigned& outPoolSize, bool verbose) { Stopwatch watch; if (verbose) printf("Building node pool (%s)...", PoolBuilderFactory::GetReadableName(poolType).c_str()); BasePoolBuilder* builder = PoolBuilderFactory::Create(poolType); watch.Reset(); builder->BuildPool(tree, outPool); outPoolSize = (unsigned32)MathHelper::DivideRoundUp(outPool.size(), TEXTURESIZE * TEXTURESIZE); // Try and write the nodepool builder->WritePool(poolFullFilename, outPool); delete builder; tree->WriteAdditionalPool(poolFullFilename.c_str()); //if (outPoolSize < 16) outPoolSize = 16; outPool.resize(TEXTURESIZE * TEXTURESIZE * outPoolSize); if (verbose) printf("Nodepool of size %u generated in %u ms.\n", outPoolSize, (unsigned)(watch.GetTime() * 1000)); return true; } bool OctreeLoader::ReadNodePool(BaseTree* tree, std::string poolType, std::string poolFileName, std::vector& outPool, unsigned& outPoolSize, bool verbose) { Stopwatch watch; watch.Reset(); BasePoolBuilder* builder = PoolBuilderFactory::Create(poolType); if (verbose) printf("Reading node pool (%s) directly... ", PoolBuilderFactory::GetReadableName(poolType).c_str()); bool success = builder->ReadPool(poolFileName, outPool); if (success) { // if reading succeeded, return the outPoolSize = (unsigned32)MathHelper::DivideRoundUp(outPool.size(), TEXTURESIZE * TEXTURESIZE); //if (outPoolSize < 16) outPoolSize = 16; outPool.resize(TEXTURESIZE * TEXTURESIZE * outPoolSize); tree->ReadAdditionalPool(poolFileName.c_str()); if (verbose) printf("Reading node pool succeeded in %u ms.\n", (unsigned)(watch.GetTime() * 1000)); } else if (verbose) printf("Reading directly failed.\n"); delete builder; return success; } bool OctreeLoader::HasMaterialTexture(BaseTree* tree) { // If the tree can be cast to an IMaterialTexture interface, it has a material texture return dynamic_cast(tree) != NULL; } bool OctreeLoader::GetMaterialTexture(BaseTree* tree, std::string treeType, std::vector& outMaterialTexture, unsigned& outMaterialTextureSize) { if (HasMaterialTexture(tree)) { auto materialTextureTree = dynamic_cast(tree); outMaterialTexture = materialTextureTree->GetMaterialTexture(); outMaterialTextureSize = materialTextureTree->GetMaterialTextureSize(); return true; } return false; } bool OctreeLoader::HasBlockTexture(BaseTree* tree) { return dynamic_cast(tree) != NULL; } bool OctreeLoader::GetBlockPointerPool(BaseTree* tree, std::string treeType, std::vector& outBlockPointerPool) { if (HasBlockTexture(tree)) { auto uTree = dynamic_cast(tree); outBlockPointerPool = uTree->GetBlockPointerPool(); return true; } return false; } bool OctreeLoader::GetBlockPool(BaseTree* tree, std::string treeType, std::vector& outBlockPool) { if (HasBlockTexture(tree)) { auto uTree = dynamic_cast(tree); outBlockPool = uTree->GetBlockPool(); return true; } return false; } bool OctreeLoader::HasAdditionalProperties(BaseTree* tree) { return dynamic_cast(tree) != NULL; } bool OctreeLoader::GetAdditionalProperties(BaseTree* tree, std::string treeType, std::string poolType, std::map& outAdditionalProperties) { if (HasAdditionalProperties(tree)) { auto uTree = dynamic_cast(tree); outAdditionalProperties = uTree->GetAdditionalProperties(); } // Some types have specific additional properties: auto descr = TreeTypeParser::GetTreeTypeDescriptor(treeType); std::string material = "MT_NONE"; if (descr.material == "c") material = "MT_COLOR"; else if (descr.material == "n") material = "MT_NORMAL"; else if (descr.material == "cn") material = "MT_COLORNORMAL"; else if (descr.material == "cnr") material = "MT_COLORNORMALREFLECTIVITY"; else if (descr.material == "co") material = "MT_COLOROPACITY"; outAdditionalProperties.insert(std::make_pair("Material", material)); if (descr.material == "n" || descr.material == "cn" || descr.material == "cnr") outAdditionalProperties.insert(std::make_pair("NormalSize", std::to_string(SmallNormal::BITS))); std::string globalTypeString; switch (descr.globalType) { case MULTIROOT: globalTypeString = "TT_MULTIROOT"; break; case HIERARCHICAL: globalTypeString = (descr.additionalTypeInfo == "s") ? "TT_HIERARCHICALSHIFT" : "TT_HIERARCHICAL"; break; case ONLYMATERIAL: globalTypeString = "TT_ONLYMATERIAL"; break; case UNIQUEINDEX: globalTypeString = (descr.additionalTypeInfo != "" && descr.additionalTypeInfo[0] == 's') ? "TT_UNIQUEINDEXSHIFT" : "TT_UNIQUEINDEX"; break; case RANDOM: globalTypeString = "TT_RANDOM"; break; case BITTREES: globalTypeString = "TT_BITTREES"; break; case STANDARD: default: globalTypeString = "TT_STANDARD"; break; } outAdditionalProperties.insert(std::pair("TreeType", globalTypeString)); std::string poolTypeString; PoolBuilderType poolTypeEnum = PoolBuilderFactory::GetType(poolType); switch (poolTypeEnum) { case ORIGINAL: poolTypeString = "PT_ORIGINAL"; break; case STANDARDPOOL: poolTypeString = "PT_STANDARD"; break; case ADAPTIVEDIRECT1: poolTypeString = "PT_ADAPTIVEDIRECT1"; break; case ADAPTIVELOOKUP1: poolTypeString = "PT_ADAPTIVELOOKUP1"; break; case ADAPTIVEDIRECT2: poolTypeString = "PT_ADAPTIVEDIRECT2"; break; case ADAPTIVELOOKUP2: poolTypeString = "PT_ADAPTIVELOOKUP2"; break; case VIRTUALNODES: poolTypeString = "PT_VIRTUALNODES"; break; } outAdditionalProperties.insert(std::make_pair("PoolType", poolTypeString)); if (descr.globalType == UNIQUEINDEX) { std::string compressionType = ""; CompressionType cType = CompressedTextureFactory::GetCompressionType(descr.textureCompressor); if (cType == BASIC) compressionType = "BASIC_PACK"; else if (cType == TIGHT) compressionType = "TIGHT_PACK"; else if (cType == BLOCK) compressionType = "BLOCK_PACK"; else if (cType == TIGHTBLOCK) compressionType = "TIGHTBLOCK_PACK"; else if (cType == PALETTEBLOCK) compressionType = "PALETTE_PACK"; else if (cType == DAGBASED) compressionType = "DAGBASED_PACK"; else if (cType == MULTIROOTBASED) compressionType = "MULTIROOTBASED_PACK"; outAdditionalProperties.insert(std::pair("TextureCompression", compressionType)); } if (descr.globalType == MULTIROOT) { outAdditionalProperties.insert(std::pair("BitsPerTree", std::to_string(TreeTypeParser::GetBitsPerTree(descr)))); outAdditionalProperties.insert(std::pair("BitsPerChannel", std::to_string(TreeTypeParser::GetBitsPerChannel(descr)))); } return true; } bool OctreeLoader::GetPool( std::vector& outPool, unsigned& outPoolSize, std::vector& outMaterialTexture, unsigned& outMaterialTextureSize, std::vector& outMaterialPool, unsigned& outMaterialPoolSize, std::vector& outBlockPointerPool, std::vector& outBlockPool, std::map& outAdditionalProperties) { return GetPool(SettingsParser::GetTreeTypeFromSettings(), SettingsParser::GetPoolTypeFromSettings(), SettingsParser::GetMaxLevelFromSettings(), SettingsParser::GetFilenameFromSettings(), SettingsParser::GetUsePoolCacheFromSettings(), outPool, outPoolSize, outMaterialTexture, outMaterialTextureSize, outMaterialPool, outMaterialPoolSize, outBlockPointerPool, outBlockPool, outAdditionalProperties, SettingsParser::GetVerboseFromSettings()); } bool OctreeLoader::GetPool(std::string treeType, std::string poolType, unsigned8 maxLevel, std::string filename, bool usePoolCache, std::vector& outPool, unsigned& outPoolSize, std::vector& outMaterialTexture, unsigned& outMaterialTextureSize, std::vector& outMaterialPool, unsigned& outMaterialPoolSize, std::vector& outBlockPointerPool, std::vector& outBlockPool, std::map& outAdditionalProperties, bool verbose) { unsigned globalType = TreeTypeParser::GetGlobalType(treeType); bool succes = false; switch (globalType) { case HIERARCHICAL: case BITTREES: succes = OctreeLoader::GetHierarchicalPool(treeType, poolType, maxLevel, filename, usePoolCache, outPool, outPoolSize, outMaterialTexture, outMaterialTextureSize, outAdditionalProperties, verbose); break; case ONLYMATERIAL: succes = OctreeLoader::GetOnlyMaterialPool(treeType, poolType, maxLevel, filename, usePoolCache, outPool, outPoolSize, outMaterialPool, outMaterialPoolSize, outMaterialTexture, outMaterialTextureSize, outAdditionalProperties, verbose); break; case UNIQUEINDEX: succes = OctreeLoader::GetUniqueIndexPool(treeType, poolType, maxLevel, filename, usePoolCache, outPool, outPoolSize, outMaterialTexture, outMaterialTextureSize, outBlockPointerPool, outBlockPool, outAdditionalProperties, verbose); break; default: succes = OctreeLoader::GetStandardPool(treeType, poolType, maxLevel, filename, usePoolCache, outPool, outPoolSize, outAdditionalProperties, verbose); break; } return succes; } bool OctreeLoader::GetStandardPool(std::vector& outPool, unsigned& outPoolSize, std::map& outAdditionalProperties) { return GetStandardPool( SettingsParser::GetTreeTypeFromSettings(), SettingsParser::GetPoolTypeFromSettings(), SettingsParser::GetMaxLevelFromSettings(), SettingsParser::GetFilenameFromSettings(), SettingsParser::GetUsePoolCacheFromSettings(), outPool, outPoolSize, outAdditionalProperties, SettingsParser::GetVerboseFromSettings()); } bool OctreeLoader::GetStandardPool(std::string treeType, std::string poolType, unsigned8 maxLevel, std::string filename, bool usePoolCache, std::vector& outPool, unsigned& outPoolSize, std::map& outAdditionalProperties, bool verbose) { unsigned globalType = TreeTypeParser::GetGlobalType(treeType); // Standard, Colored and Multiroot all use the same type of pool if (globalType != STANDARD && globalType != MULTIROOT && globalType != RANDOM) return false; std::string poolFilename = GetFullFilename(treeType, maxLevel, filename); if (usePoolCache) { // Try and read the pool cache // Create a root of the correct type to try and read the pool BaseTree* tree = CreateTree(treeType, maxLevel); bool readSucces = ReadNodePool(tree, poolType, poolFilename, outPool, outPoolSize, verbose); if (readSucces) readSucces &= GetAdditionalProperties(tree, treeType, poolType, outAdditionalProperties); if (readSucces && verbose) PrintGPUMemoryRequirements(outPool.size(), 0, 0, 0); delete tree; if (readSucces) return true; } // If cache shouldn't be used or loading failed, load the tree file and build the pool from it BaseTree* tree = ReadCache(treeType, maxLevel, filename, verbose); if (tree == NULL) return false; bool succes = BuildNodePool(tree, poolType, poolFilename, outPool, outPoolSize, verbose); if (succes) succes &= GetAdditionalProperties(tree, treeType, poolType, outAdditionalProperties); if (verbose && succes) PrintGPUMemoryRequirements(treeType, poolType, maxLevel, tree); delete tree; return succes; } bool OctreeLoader::GetHierarchicalPool(std::vector& outPool, unsigned& outPoolSize, std::vector& outMaterialTexture, unsigned& outMaterialTextureSize, std::map& outAdditionalProperties) { return GetHierarchicalPool( SettingsParser::GetTreeTypeFromSettings(), SettingsParser::GetPoolTypeFromSettings(), SettingsParser::GetMaxLevelFromSettings(), SettingsParser::GetFilenameFromSettings(), SettingsParser::GetUsePoolCacheFromSettings(), outPool, outPoolSize, outMaterialTexture, outMaterialTextureSize, outAdditionalProperties, SettingsParser::GetVerboseFromSettings()); } bool OctreeLoader::GetHierarchicalPool(std::string treeType, std::string poolType, unsigned8 maxLevel, std::string filename, bool usePoolCache, std::vector& outPool, unsigned& outPoolSize, std::vector& outMaterialTexture, unsigned& outMaterialTextureSize, std::map& outAdditionalProperties, bool verbose) { unsigned globalType = TreeTypeParser::GetGlobalType(treeType); if (globalType != HIERARCHICAL && globalType != BITTREES) return false; std::string poolFilename = GetFullFilename(treeType, maxLevel, filename); if (usePoolCache) { // Try and read the pool cache // Create a root of the correct type to try and read the pool BaseTree* tree = CreateTree(treeType, maxLevel); bool readSucces = ReadNodePool(tree, poolType, poolFilename, outPool, outPoolSize, verbose); if (readSucces) readSucces &= GetMaterialTexture(tree, treeType, outMaterialTexture, outMaterialTextureSize); if (readSucces) readSucces &= GetAdditionalProperties(tree, treeType, poolType, outAdditionalProperties); if (readSucces && verbose) PrintGPUMemoryRequirements(outPool.size(), outMaterialTexture.size(), 0, 0); delete tree; if (readSucces) return true; } // If cache shouldn't be used or loading failed, load the tree file and build the pool from it BaseTree* tree = ReadCache(treeType, maxLevel, filename, verbose); if (tree == NULL) return false; bool succes = BuildNodePool(tree, poolType, poolFilename, outPool, outPoolSize, verbose); succes &= GetMaterialTexture(tree, treeType, outMaterialTexture, outMaterialTextureSize); if (succes) succes &= GetAdditionalProperties(tree, treeType, poolType, outAdditionalProperties); if (verbose) PrintGPUMemoryRequirements(treeType, poolType, maxLevel, tree); delete tree; return succes; } bool OctreeLoader::GetOnlyMaterialPool( std::vector& outGeometryPool, unsigned& outGeometryPoolSize, std::vector& outMaterialPool, unsigned& outMaterialPoolSize, std::vector& outMaterialTexture, unsigned& outMaterialTextureSize, std::map& outAdditionalProperties) { return GetOnlyMaterialPool( SettingsParser::GetTreeTypeFromSettings(), SettingsParser::GetPoolTypeFromSettings(), SettingsParser::GetMaxLevelFromSettings(), SettingsParser::GetFilenameFromSettings(), SettingsParser::GetUsePoolCacheFromSettings(), outGeometryPool, outGeometryPoolSize, outMaterialPool, outMaterialPoolSize, outMaterialTexture, outMaterialTextureSize, outAdditionalProperties, SettingsParser::GetVerboseFromSettings()); } bool OctreeLoader::GetOnlyMaterialPool(std::string treeType, std::string poolType, unsigned8 maxLevel, std::string filename, bool usePoolCache, std::vector& outGeometryPool, unsigned& outGeometryPoolSize, std::vector& outMaterialPool, unsigned& outMaterialPoolSize, std::vector& outMaterialTexture, unsigned& outMaterialTextureSize, std::map& outAdditionalProperties, bool verbose) { unsigned globalType = TreeTypeParser::GetGlobalType(treeType); if (globalType != ONLYMATERIAL) return false; std::string poolFilename = GetFullFilename(treeType, maxLevel, filename); bool geometryReadSucces = false; bool materialReadSucces = false; if (usePoolCache) { // Try and read the pool cache for both the // Create a root of the correct type to try and read the pool BaseTree* geometryTree = CreateTree("s", maxLevel); geometryReadSucces = ReadNodePool(geometryTree, poolType, GetFullFilename("s", maxLevel, filename), outGeometryPool, outGeometryPoolSize); delete geometryTree; BaseTree* materialTree = CreateTree(treeType, maxLevel); materialReadSucces &= ReadNodePool(materialTree, poolType, poolFilename, outMaterialPool, outMaterialPoolSize, verbose); if (materialReadSucces) materialReadSucces &= GetMaterialTexture(materialTree, treeType, outMaterialTexture, outMaterialTextureSize); if (materialReadSucces) materialReadSucces &= GetAdditionalProperties(materialTree, treeType, poolType, outAdditionalProperties); delete materialTree; if (geometryReadSucces && materialReadSucces) return true; } // If cache shouldn't be used or loading failed, load the tree file and build the pool from it if (!geometryReadSucces) { BaseTree* geometryTree = ReadCache("s", maxLevel, filename, verbose); if (geometryTree == NULL) return false; geometryReadSucces = BuildNodePool(geometryTree, poolType, poolFilename, outGeometryPool, outGeometryPoolSize, verbose); delete geometryTree; } if (!materialReadSucces) { BaseTree* materialTree = ReadCache(treeType, maxLevel, filename, verbose); if (materialTree == NULL) return false; materialReadSucces = BuildNodePool(materialTree, poolType, poolFilename, outMaterialPool, outMaterialPoolSize, verbose); materialReadSucces &= GetMaterialTexture(materialTree, treeType, outMaterialTexture, outMaterialTextureSize); if (materialReadSucces) materialReadSucces &= GetAdditionalProperties(materialTree, treeType, poolType, outAdditionalProperties); delete materialTree; } return materialReadSucces && geometryReadSucces; } bool OctreeLoader::GetUniqueIndexPool( std::vector& outPool, unsigned& outPoolSize, std::vector& outMaterialTexture, unsigned& outMaterialTextureSize, std::vector& outBlockPointerPool, std::vector& outBlockPool, std::map& outAdditionalProperties) { return GetUniqueIndexPool( SettingsParser::GetTreeTypeFromSettings(), SettingsParser::GetPoolTypeFromSettings(), SettingsParser::GetMaxLevelFromSettings(), SettingsParser::GetFilenameFromSettings(), SettingsParser::GetUsePoolCacheFromSettings(), outPool, outPoolSize, outMaterialTexture, outMaterialTextureSize, outBlockPointerPool, outBlockPool, outAdditionalProperties, SettingsParser::GetVerboseFromSettings()); } bool OctreeLoader::GetUniqueIndexPool(std::string treeType, std::string poolType, unsigned8 maxLevel, std::string filename, bool usePoolCache, std::vector& outPool, unsigned& outPoolSize, std::vector& outMaterialTexture, unsigned& outMaterialTextureSize, std::vector& outBlockPointerPool, std::vector& outBlockPool, std::map& outAdditionalProperties, bool verbose) { unsigned globalType = TreeTypeParser::GetGlobalType(treeType); if (globalType != UNIQUEINDEX) return false; std::string poolFilename = GetFullFilename(treeType, maxLevel, filename); if (usePoolCache) { // Try and read the pool cache // Create a root of the correct type to try and read the pool BaseTree* tree = CreateTree(treeType, maxLevel); bool readSucces = ReadNodePool(tree, poolType, poolFilename, outPool, outPoolSize, verbose); if (readSucces) readSucces &= GetMaterialTexture(tree, treeType, outMaterialTexture, outMaterialTextureSize); if (readSucces) readSucces &= GetBlockPointerPool(tree, treeType, outBlockPointerPool); if (readSucces) readSucces &= GetBlockPool(tree, treeType, outBlockPool); if (readSucces) readSucces &= GetAdditionalProperties(tree, treeType, poolType, outAdditionalProperties); if (readSucces && verbose) PrintGPUMemoryRequirements(outPool.size(), outMaterialTexture.size(), outBlockPool.size(), outBlockPointerPool.size()); delete tree; if (readSucces) return true; } // If cache shouldn't be used or loading failed, load the tree file and build the pool from it BaseTree* tree = ReadCache(treeType, maxLevel, filename, verbose); if (tree == NULL) return false; bool succes = BuildNodePool(tree, poolType, poolFilename, outPool, outPoolSize, verbose); if (succes) succes &= GetMaterialTexture(tree, treeType, outMaterialTexture, outMaterialTextureSize); if (succes) succes &= GetBlockPointerPool(tree, treeType, outBlockPointerPool); if (succes) succes &= GetBlockPool(tree, treeType, outBlockPool); if (succes) succes &= GetAdditionalProperties(tree, treeType, poolType, outAdditionalProperties); if (verbose) PrintGPUMemoryRequirements(treeType, poolType, maxLevel, tree); delete tree; return succes; } size_t OctreeLoader::GetGPUMemoryRequirements() { return OctreeLoader::GetGPUMemoryRequirements(SettingsParser::GetTreeTypeFromSettings(), SettingsParser::GetPoolTypeFromSettings(), SettingsParser::GetMaxLevelFromSettings(), SettingsParser::GetFilenameFromSettings()); } size_t OctreeLoader::GetGPUMemoryRequirements(std::string treeType, std::string poolType, unsigned8 maxLevel, std::string filename) { BaseTree* tree = OctreeLoader::ReadCache(treeType, maxLevel, filename); return GetGPUMemoryRequirements(treeType, poolType, tree); } size_t OctreeLoader::GetGPUMemoryRequirements(std::string treeType, std::string poolType, BaseTree* tree) { // Every tree has the nodepool. BasePoolBuilder* builder = PoolBuilderFactory::Create(poolType); size_t treePoolSize = builder->GetPoolSize(tree); delete builder; size_t res = treePoolSize; if (HasMaterialTexture(tree)) { auto materialTree = dynamic_cast(tree); size_t materialTextureSize = materialTree->GetMaterialTextureSize(); res += materialTextureSize * materialTextureSize * materialTree->GetMaterialTextureChannelsPerPixel(); // 2D texture with the given channels per pixel } if (HasBlockTexture(tree)) { auto blockTextureTree = dynamic_cast(tree); size_t blockPointerPoolMemoryRequirements = blockTextureTree->GetBlockPointerPoolSize(); size_t blockPoolMemoryRequirements = blockTextureTree->GetBlockPoolSize(); size_t blockTextureMemoryRequirements = blockPointerPoolMemoryRequirements + blockPoolMemoryRequirements; res += blockTextureMemoryRequirements; printf("Block texture required %.2f MB. (main: %.2f MB, additional: %.2f MB)\n", (double)blockTextureMemoryRequirements / (1024.0 * 1024.0), (double)blockPoolMemoryRequirements / (1024.0 * 1024.0), (double)blockPointerPoolMemoryRequirements / (1024.0 * 1024.0)); } return res; } size_t OctreeLoader::GetMainTreeGPUMemoryRequirements() { std::string treeType = SettingsParser::GetTreeTypeFromSettings(); BaseTree* tree = OctreeLoader::ReadCache(treeType, SettingsParser::GetMaxLevelFromSettings(), SettingsParser::GetFilenameFromSettings()); size_t res = GetGPUMemoryRequirements(treeType, SettingsParser::GetPoolTypeFromSettings(), tree); return res; } size_t OctreeLoader::GetMainTreeGPUMemoryRequirements(std::string treeType, std::string poolType, BaseTree* tree) { BasePoolBuilder* builder = PoolBuilderFactory::Create(poolType); size_t treePoolSize = builder->GetPoolSize(tree); delete builder; return TEXTURESIZE * TEXTURESIZE * MathHelper::DivideRoundUp(treePoolSize, TEXTURESIZE * TEXTURESIZE); } void OctreeLoader::PrintGPUMemoryRequirements(std::string treeType, std::string poolType, unsigned8 maxLevel, BaseTree* tree) { size_t memoryRequirements = GetGPUMemoryRequirements(treeType, poolType, tree); printf("Tree requires %11zu bytes (%8.2f MB).\n", memoryRequirements, (double)memoryRequirements / 1048576.0); } void OctreeLoader::PrintGPUMemoryRequirements(size_t poolSize, size_t materialTextureSize, size_t blockPoolSize, size_t blockPointerPoolSize) { size_t memoryRequirements = poolSize + materialTextureSize + blockPoolSize + blockPointerPoolSize; printf("Tree requires %11zu bytes (%8.2f MB).\n", memoryRequirements, (double)memoryRequirements / 1048576.0); } std::string OctreeLoader::GetFullFilename() { PropertyLoader::Create(); auto propertyLoader = PropertyLoader::Instance(); std::string filename = propertyLoader->GetProperty("dag_file"); unsigned8 maxLevel = (unsigned8)std::stoi(propertyLoader->GetProperty("shader_max_level")); std::string treeType = propertyLoader->GetProperty("octree_type"); return GetFullFilename(treeType, maxLevel, filename); } std::string OctreeLoader::GetFullFilename(std::string treeType, unsigned8 maxLevel, std::string filename) { // Hack: make sure filenames are consistent for soem special tree types if (treeType == "m") treeType = "m8"; // Convert compression method to normalized compression method TreeTypeDescriptor descr = TreeTypeParser::GetTreeTypeDescriptor(treeType); if (descr.quantizer != "") { StringHelper::Replace(treeType, descr.quantizer, ColorQuantizerFactory::GetNormalizedType(descr.quantizer)); } if (descr.globalType == UNIQUEINDEX && descr.additionalTypeInfo != "") { unsigned8 lod = TreeTypeParser::GetLevelsWithoutMaterials(descr); if (lod != 0) StringHelper::Replace(treeType, descr.additionalTypeInfo, std::to_string(lod) + "lod"); } return filename + "_" + std::to_string(maxLevel) + "_" + treeType; } BaseTree* OctreeLoader::CreateTree(std::string type, unsigned8 maxLevel) { BaseTree* tree = NULL; TreeTypeDescriptor descr = TreeTypeParser::GetTreeTypeDescriptor(type); switch (descr.globalType) { case HIERARCHICAL: { if (descr.material == "c") { if (descr.additionalTypeInfo == "s") tree = new HierarchicalShiftingColoredTree(maxLevel); else tree = new MaterialLibraryTree(maxLevel); } else if (descr.material == "n") tree = new MaterialLibraryTree(maxLevel); else if (descr.material == "cn") tree = new MaterialLibraryTree(maxLevel); else if (descr.material == "cnr") tree = new MaterialLibraryTree(maxLevel); else if (descr.material == "co") tree = new MaterialLibraryTree(maxLevel); break; } case ONLYMATERIAL: { tree = new HierarchicalColorsOnlyTree(maxLevel); break; } case UNIQUEINDEX: { unsigned8 levelsWithoutMaterials = TreeTypeParser::GetLevelsWithoutMaterials(descr); if (descr.additionalTypeInfo != "" && descr.additionalTypeInfo[0] == 's') { assert(descr.material != "n"); auto texture = CompressedTextureFactory::GetCompressedTexture(descr.textureCompressor); tree = new UniqueIndexShiftTree(maxLevel, texture, levelsWithoutMaterials); } else { auto texture = CompressedTextureFactory::GetCompressedTexture(descr.textureCompressor); if (descr.material == "c") tree = new MaterialLibraryUniqueIndexTree(maxLevel, texture, levelsWithoutMaterials); else if (descr.material == "n") tree = new MaterialLibraryUniqueIndexTree(maxLevel, texture, levelsWithoutMaterials); else if (descr.material == "cn") tree = new MaterialLibraryUniqueIndexTree(maxLevel, texture, levelsWithoutMaterials); else if (descr.material == "cnr") tree = new MaterialLibraryUniqueIndexTree(maxLevel, texture, levelsWithoutMaterials); else if (descr.material == "co") tree = new MaterialLibraryUniqueIndexTree(maxLevel, texture, levelsWithoutMaterials); else delete texture; } break; } case MULTIROOT: { std::vector additionalTypes(8); additionalTypes[0] = "1"; additionalTypes[1] = "2"; additionalTypes[2] = "3"; additionalTypes[3] = "4"; additionalTypes[4] = "5"; additionalTypes[5] = "6"; additionalTypes[6] = "7"; additionalTypes[7] = "8"; if (descr.additionalTypeInfo == "cc") { tree = new LeafMaterialMultiRootTree(maxLevel, 3); } else if (CollectionHelper::Contains(additionalTypes, descr.additionalTypeInfo)) { unsigned8 bitsPerChannel = TreeTypeParser::GetBitsPerChannel(descr); tree = new MultiRootTree<>(maxLevel, 3 * bitsPerChannel); } else { unsigned8 bitsPerChannel = TreeTypeParser::GetBitsPerChannel(descr); unsigned8 bitsPerTree = TreeTypeParser::GetBitsPerTree(descr); unsigned8 treesPerChannel = bitsPerChannel / bitsPerTree + (bitsPerChannel % bitsPerTree == 0 ? 0 : 1); switch (bitsPerTree) { case 1: tree = new LeafMaterialMultiRootTree>(maxLevel, 3 * treesPerChannel); break; case 2: tree = new LeafMaterialMultiRootTree>(maxLevel, 3 * treesPerChannel); break; case 3: tree = new LeafMaterialMultiRootTree>(maxLevel, 3 * treesPerChannel); break; case 4: tree = new LeafMaterialMultiRootTree>(maxLevel, 3 * treesPerChannel); break; case 5: tree = new LeafMaterialMultiRootTree>(maxLevel, 3 * treesPerChannel); break; case 6: tree = new LeafMaterialMultiRootTree>(maxLevel, 3 * treesPerChannel); break; case 7: tree = new LeafMaterialMultiRootTree>(maxLevel, 3 * treesPerChannel); break; case 8: tree = new LeafMaterialMultiRootTree>(maxLevel, 3 * treesPerChannel); break; } } break; } case RANDOM: { tree = new MaterialTree, HashComparer>>(maxLevel); break; } case BITTREES: { if (descr.additionalTypeInfo == "l") tree = new MaterialLibraryMultiRoot(maxLevel); break; } default: { tree = new Tree<>(maxLevel); break; } } return tree; }