Files
CDAG/Research/core/OctreeBuilder/OctreeLoader.cpp

782 lines
34 KiB
C++

#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<unsigned8>& outPool, unsigned& outPoolSize, bool verbose)
{
Stopwatch watch;
if (verbose) printf("Building node pool (%s)...", PoolBuilderFactory::GetReadableName(poolType).c_str());
BasePoolBuilder<BaseTree>* 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<unsigned8>& outPool, unsigned& outPoolSize, bool verbose)
{
Stopwatch watch;
watch.Reset();
BasePoolBuilder<BaseTree>* 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<IMaterialTexture*>(tree) != NULL;
}
bool OctreeLoader::GetMaterialTexture(BaseTree* tree, std::string treeType, std::vector<unsigned char>& outMaterialTexture, unsigned& outMaterialTextureSize)
{
if (HasMaterialTexture(tree))
{
auto materialTextureTree = dynamic_cast<IMaterialTexture*>(tree);
outMaterialTexture = materialTextureTree->GetMaterialTexture();
outMaterialTextureSize = materialTextureTree->GetMaterialTextureSize();
return true;
}
return false;
}
bool OctreeLoader::HasBlockTexture(BaseTree* tree)
{
return dynamic_cast<IBlockTexture*>(tree) != NULL;
}
bool OctreeLoader::GetBlockPointerPool(BaseTree* tree, std::string treeType, std::vector<unsigned8>& outBlockPointerPool)
{
if (HasBlockTexture(tree))
{
auto uTree = dynamic_cast<IBlockTexture*>(tree);
outBlockPointerPool = uTree->GetBlockPointerPool();
return true;
}
return false;
}
bool OctreeLoader::GetBlockPool(BaseTree* tree, std::string treeType, std::vector<unsigned8>& outBlockPool)
{
if (HasBlockTexture(tree))
{
auto uTree = dynamic_cast<IBlockTexture*>(tree);
outBlockPool = uTree->GetBlockPool();
return true;
}
return false;
}
bool OctreeLoader::HasAdditionalProperties(BaseTree* tree)
{
return dynamic_cast<IAdditionalProperties*>(tree) != NULL;
}
bool OctreeLoader::GetAdditionalProperties(BaseTree* tree, std::string treeType, std::string poolType, std::map<std::string, std::string>& outAdditionalProperties)
{
if (HasAdditionalProperties(tree))
{
auto uTree = dynamic_cast<IAdditionalProperties*>(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<std::string, std::string>("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<MaterialLibraryPointer>::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<std::string, std::string>("TextureCompression", compressionType));
}
if (descr.globalType == MULTIROOT)
{
outAdditionalProperties.insert(std::pair<std::string, std::string>("BitsPerTree", std::to_string(TreeTypeParser::GetBitsPerTree(descr))));
outAdditionalProperties.insert(std::pair<std::string, std::string>("BitsPerChannel", std::to_string(TreeTypeParser::GetBitsPerChannel(descr))));
}
return true;
}
bool OctreeLoader::GetPool(
std::vector<unsigned8>& outPool, unsigned& outPoolSize,
std::vector<unsigned8>& outMaterialTexture, unsigned& outMaterialTextureSize,
std::vector<unsigned8>& outMaterialPool, unsigned& outMaterialPoolSize,
std::vector<unsigned8>& outBlockPointerPool, std::vector<unsigned8>& outBlockPool,
std::map<std::string, std::string>& 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<unsigned8>& outPool, unsigned& outPoolSize,
std::vector<unsigned8>& outMaterialTexture, unsigned& outMaterialTextureSize,
std::vector<unsigned8>& outMaterialPool, unsigned& outMaterialPoolSize,
std::vector<unsigned8>& outBlockPointerPool, std::vector<unsigned8>& outBlockPool,
std::map<std::string, std::string>& 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<unsigned8>& outPool, unsigned& outPoolSize, std::map<std::string, std::string>& 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<unsigned8>& outPool, unsigned& outPoolSize, std::map<std::string, std::string>& 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<unsigned8>& outPool, unsigned& outPoolSize,
std::vector<unsigned char>& outMaterialTexture, unsigned& outMaterialTextureSize,
std::map<std::string, std::string>& 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<unsigned8>& outPool, unsigned& outPoolSize, std::vector<unsigned char>& outMaterialTexture, unsigned& outMaterialTextureSize,
std::map<std::string, std::string>& 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<unsigned8>& outGeometryPool, unsigned& outGeometryPoolSize,
std::vector<unsigned8>& outMaterialPool, unsigned& outMaterialPoolSize,
std::vector<unsigned char>& outMaterialTexture, unsigned& outMaterialTextureSize,
std::map<std::string, std::string>& 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<unsigned8>& outGeometryPool, unsigned& outGeometryPoolSize,
std::vector<unsigned8>& outMaterialPool, unsigned& outMaterialPoolSize,
std::vector<unsigned char>& outMaterialTexture, unsigned& outMaterialTextureSize,
std::map<std::string, std::string>& 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<unsigned8>& outPool, unsigned& outPoolSize,
std::vector<unsigned8>& outMaterialTexture, unsigned& outMaterialTextureSize,
std::vector<unsigned8>& outBlockPointerPool, std::vector<unsigned8>& outBlockPool,
std::map<std::string, std::string>& 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<unsigned8>& outPool, unsigned& outPoolSize,
std::vector<unsigned8>& outMaterialTexture, unsigned& outMaterialTextureSize,
std::vector<unsigned8>& outBlockPointerPool, std::vector<unsigned8>& outBlockPool,
std::map<std::string, std::string>& 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<BaseTree>* builder = PoolBuilderFactory::Create(poolType);
size_t treePoolSize = builder->GetPoolSize(tree);
delete builder;
size_t res = treePoolSize;
if (HasMaterialTexture(tree))
{
auto materialTree = dynamic_cast<IMaterialTexture*>(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<IBlockTexture*>(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<BaseTree>* 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<Color, ColorCompare>(maxLevel);
}
else if (descr.material == "n")
tree = new MaterialLibraryTree<SmallNormal, NormalCompare, SmallNormal::BYTES>(maxLevel);
else if (descr.material == "cn")
tree = new MaterialLibraryTree<ColorAndNormal, ColorAndNormalCompare, ColorAndNormal::CHANNELSPERPIXEL>(maxLevel);
else if (descr.material == "cnr")
tree = new MaterialLibraryTree<ColorAndNormalAndValue, ColorAndNormalAndValueCompare, ColorAndNormalAndValue::CHANNELSPERPIXEL>(maxLevel);
else if (descr.material == "co")
tree = new MaterialLibraryTree<ColorAndOpacity, ColorAndOpacityCompare, ColorAndOpacity::CHANNELSPERPIXEL>(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<SignedIntMaterial>::GetCompressedTexture(descr.textureCompressor);
tree = new UniqueIndexShiftTree<Color, ColorCompare>(maxLevel, texture, levelsWithoutMaterials);
}
else
{
auto texture = CompressedTextureFactory<MaterialLibraryPointer>::GetCompressedTexture(descr.textureCompressor);
if (descr.material == "c")
tree = new MaterialLibraryUniqueIndexTree<Color, ColorCompare>(maxLevel, texture, levelsWithoutMaterials);
else if (descr.material == "n")
tree = new MaterialLibraryUniqueIndexTree<SmallNormal, NormalCompare, SmallNormal::CHANNELSPERPIXEL>(maxLevel, texture, levelsWithoutMaterials);
else if (descr.material == "cn")
tree = new MaterialLibraryUniqueIndexTree<ColorAndNormal, ColorAndNormalCompare, ColorAndNormal::CHANNELSPERPIXEL>(maxLevel, texture, levelsWithoutMaterials);
else if (descr.material == "cnr")
tree = new MaterialLibraryUniqueIndexTree<ColorAndNormalAndValue, ColorAndNormalAndValueCompare, ColorAndNormalAndValue::CHANNELSPERPIXEL>(maxLevel, texture, levelsWithoutMaterials);
else if (descr.material == "co")
tree = new MaterialLibraryUniqueIndexTree<ColorAndOpacity, ColorAndOpacityCompare, ColorAndOpacity::CHANNELSPERPIXEL>(maxLevel, texture, levelsWithoutMaterials);
else
delete texture;
}
break;
}
case MULTIROOT:
{
std::vector<std::string> 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<ColorChannel>(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<BitsMaterial<1>>(maxLevel, 3 * treesPerChannel); break;
case 2: tree = new LeafMaterialMultiRootTree<BitsMaterial<2>>(maxLevel, 3 * treesPerChannel); break;
case 3: tree = new LeafMaterialMultiRootTree<BitsMaterial<3>>(maxLevel, 3 * treesPerChannel); break;
case 4: tree = new LeafMaterialMultiRootTree<BitsMaterial<4>>(maxLevel, 3 * treesPerChannel); break;
case 5: tree = new LeafMaterialMultiRootTree<BitsMaterial<5>>(maxLevel, 3 * treesPerChannel); break;
case 6: tree = new LeafMaterialMultiRootTree<BitsMaterial<6>>(maxLevel, 3 * treesPerChannel); break;
case 7: tree = new LeafMaterialMultiRootTree<BitsMaterial<7>>(maxLevel, 3 * treesPerChannel); break;
case 8: tree = new LeafMaterialMultiRootTree<BitsMaterial<8>>(maxLevel, 3 * treesPerChannel); break;
}
}
break;
}
case RANDOM:
{
tree = new MaterialTree<BitsMaterial<1>, HashComparer<BitsMaterial<1>>>(maxLevel); break;
}
case BITTREES:
{
if (descr.additionalTypeInfo == "l")
tree = new MaterialLibraryMultiRoot<Color, ColorCompare>(maxLevel);
break;
}
default:
{
tree = new Tree<>(maxLevel);
break;
}
}
return tree;
}