#pragma once #include "UniqueIndexTree.h" #include "../Material/SignedIntMaterial.h" #include "MaterialTree.h" #include "../Material/MaterialLibrary.h" #include "../../inc/tbb/parallel_for.h" #include "IMaterialTexture.h" #include template, unsigned8 channelsPerPixel = 3> class UniqueIndexShiftTree : public UniqueIndexTree, public IMaterialTexture { private: MaterialLibrary* mMaterialLibrary; std::vector mMaterialTexture; unsigned16 mMaterialTextureSize; MaterialLibraryPointer mMaxTextureIndex; void ClearMaterialLibrary() { if (mMaterialLibrary != NULL) { delete mMaterialLibrary; mMaterialLibrary = NULL; } } inline void WriteMaterialTexture(std::ostream& file) { assert(mMaterialLibrary != NULL); mMaterialLibrary->Serialize(file); } inline void ReadMaterialTexture(std::istream& file) { if (mMaterialLibrary == NULL) mMaterialLibrary = new MaterialLibrary(); mMaterialLibrary->Deserialize(file); GetMaterialTexture(); } void BuildMaterialLibrary(const std::vector& materials) { ClearMaterialLibrary(); mMaterialLibrary = new MaterialLibrary(); for (T m : materials) mMaterialLibrary->AddMaterial(m); mMaterialLibrary->Finalize(); } bool CheckMaterialLibrary(const std::vector& materials) { for (T m : materials) if (!mMaterialLibrary->Contains(m)) return false; return true; } public: UniqueIndexShiftTree(unsigned8 maxLevel, CompressedTexture* nodeMaterialsTexture, unsigned32 collapsedMaterialLevels) : UniqueIndexTree(maxLevel, nodeMaterialsTexture, collapsedMaterialLevels), mMaterialLibrary(NULL), mMaterialTexture(std::vector()), mMaterialTextureSize(0), mMaxTextureIndex(MaterialLibraryPointer(0)) {} UniqueIndexShiftTree(unsigned8 maxLevel, CompressedTexture* nodeMaterialsTexture) : UniqueIndexShiftTree(maxLevel, nodeMaterialsTexture, 0) {} ~UniqueIndexShiftTree() override { ClearMaterialLibrary(); } void AppendPostProcess(glm::uvec3 coordinates, unsigned8 level, Tree* tree) override { UniqueIndexShiftTree* typedTree = (UniqueIndexShiftTree*)tree; // If the material libraries are equal, appending should work correctly assert(*typedTree->GetMaterialLibrary() == *mMaterialLibrary); UniqueIndexTree::AppendPostProcess(coordinates, level, typedTree, std::unordered_map()); } // Prepare the tree for a certain set of materials. This should be done before calling "BaseOn" or otherwise adding nodes to the tree. void PrepareForMaterials(const std::vector& materials) { assert(GetNodeCount() == 1); BuildMaterialLibrary(materials); } template void BaseOn(MaterialTree* tree) { // First we build a new material tree that contains the differences in the materials compared to the parents for each node (kind of watch hsc is) // To do this, we need an octree (as the same color doesn't mean it will have the same difference to it's parent) tree->ToOctree(); std::vector uniqueMaterials = tree->GetUniqueMaterials(); // Create the actual material library if (mMaterialLibrary == NULL) BuildMaterialLibrary(uniqueMaterials); else assert(CheckMaterialLibrary(uniqueMaterials)); // Now we calculate the shift for each node in the tree std::vector intMaterialPointer(tree->GetNodeCount()); tbb::parallel_for((unsigned32)0, tree->GetNodeCount(), [&](unsigned32 i) { auto node = tree->GetTypedNode(i); MaterialLibraryPointer matPointer = mMaterialLibrary->GetTextureIndex(tree->GetMaterial(node)); intMaterialPointer[i] = (matPointer.y * mMaterialLibrary->GetTextureSize()) + matPointer.x; }); std::vector shiftMaterials(tree->GetNodeCount()); shiftMaterials[0] = intMaterialPointer[0]; tbb::parallel_for((unsigned32)0, tree->GetNodeCount(), [&](unsigned32 i) //for (size_t i = 0; i < tree->GetNodeCount(); i++) { Node* node = tree->GetNode(i); int curIntIndex = intMaterialPointer[i]; unsigned32* children = node->GetChildren(); unsigned8 childCount = node->GetChildCount(); for (ChildIndex c = 0; c < childCount; c++) { int childIntIndex = intMaterialPointer[children[c]]; shiftMaterials[children[c]] = SignedIntMaterial(childIntIndex - curIntIndex); } }); std::vector shiftsCopy(shiftMaterials.size()); for (size_t i = 0; i < shiftMaterials.size(); i++) shiftsCopy[i] = shiftMaterials[i]; CollectionHelper::PrintStats(shiftsCopy); for (size_t i = 0; i < shiftsCopy.size(); i++) shiftsCopy[i] = abs(shiftsCopy[i]); CollectionHelper::PrintStats(shiftsCopy); UniqueIndexTree::BaseOn(tree, shiftMaterials); } std::vector GetUniqueMaterials() const { return mMaterialLibrary->GetMaterials(); } MaterialLibrary* GetMaterialLibrary() const { return mMaterialLibrary; } // Returns the texture containing all materials once std::vector GetMaterialTexture() override { if (!mMaterialTexture.empty()) return mMaterialTexture; assert(mMaterialLibrary->IsFinalized()); mMaterialTextureSize = mMaterialLibrary->GetTextureSize(); mMaterialTexture = mMaterialLibrary->GetTexture(); mMaxTextureIndex = mMaterialLibrary->GetMaxTextureIndex(); return mMaterialTexture; } unsigned GetMaterialTextureSize() override { GetMaterialTexture(); return mMaterialTextureSize; } unsigned8 GetMaterialTextureChannelsPerPixel() override { return channelsPerPixel; } protected: void WriteAdditionalUniqueIndexTreeProperties(std::ostream& file) override { WriteMaterialTexture(file); } void ReadAdditionalUniqueIndexTreeProperties(std::istream& file) override { ReadMaterialTexture(file); } void WriteAdditionalPoolProperties(std::ostream& file) override { WriteMaterialTexture(file); UniqueIndexTree::WriteAdditionalPoolProperties(file); } void ReadAdditionalPoolProperties(std::istream& file) override { ReadMaterialTexture(file); UniqueIndexTree::ReadAdditionalPoolProperties(file); } void PrintDebugInfo() const override { std::vector shifts = GetNodeValues(); std::vector shiftValues(shifts.size()); for (size_t i = 0; i < shifts.size(); i++) shiftValues[i] = (int)shifts[i]; CollectionHelper::PrintStats(shiftValues); } };