#pragma once #include "Color.h" #include "../../core/ColorHelper.h" #include "../../inc/glm/glm.hpp" #include "../../core/Hashers.h" #include "../../core/Comparers.h" #include "../../core/CollectionHelper.h" #include "../../core/Serializer.h" #include "../../core/BitHelper.h" template class MaterialPair { private: U mFirst; V mSecond; public: static const unsigned8 BITS = U::BITS + V::BITS; static const unsigned8 CHANNELSPERPIXEL = BITS % 32 == 0 ? 4 : 3; MaterialPair() : mFirst(U()), mSecond(V()) {} MaterialPair(U first, V second) : mFirst(first), mSecond(second) {} MaterialPair(std::pair pair) : mFirst(pair.first), mSecond(pair.second) {} template MaterialPair(UC first, VC second) : MaterialPair(U(first), V(second)) {} const U& GetFirst() const { return mFirst; } void SetFirst(U value) { mFirst = value; } const V& GetSecond() const { return mSecond; } void SetSecond(V value) { mSecond = value; } static MaterialPair Average(const std::vector& values) { std::vector firsts(values.size()); std::vector seconds(values.size()); for (size_t i = 0; i < values.size(); i++) { firsts[i] = values[i].GetFirst(); seconds[i] = values[i].GetSecond(); } return MaterialPair(U::Average(first), V::Average(seconds)); } static MaterialPair WeightedAverage(const std::vector& values, const std::vector& weights) { std::vector firsts(values.size()); std::vector seconds(values.size()); for (size_t i = 0; i < values.size(); i++) { firsts[i] = values[i].GetFirst(); seconds[i] = values[i].GetSecond(); } return MaterialPair(U::WeightedAverage(firsts, weights), V::WeightedAverage(seconds, weights)); } static float Distance(const MaterialPair& a, const MaterialPair& b) { return (U::Distance(a.GetFirst(), a.GetSecond()) + V::Distance(a.GetSecond(), b.GetSecond())) * 0.5f; } std::string GetTypeSuffix() const { return GetFirst().GetTypeSuffix() + GetSecond().GetTypeSuffix(); } std::vector Serialize() const { std::vector firstSerialized = GetFirst().Serialize(); std::vector secondSerialized = GetSecond().Serialize(); firstSerialized.insert(firstSerialized.end(), secondSerialized.begin(), secondSerialized.end()); return firstSerialized; }; void Deserialize(const std::vector& value) { mFirst.Deserialize(std::vector(value.begin(), value.begin() + sizeof(mFirst))); mSecond.Deserialize(std::vector(value.begin() + sizeof(mFirst), value.end())); } bool operator==(const MaterialPair& v) const { return v.mFirst == mFirst && v.mSecond == mSecond; } bool operator!=(const MaterialPair& n) const { return !(n == *this); } //// Assignment operator, used for easy access to different kinds of materials //ColorAndValue& operator=(const unsigned& source) //{ // mValue = source & 0x3FF; // glm::u8vec3 color; // color.r = (source >> (10 + 14 - 1)) & 0xFE; // color.g = (source >> (10 + 7 - 1)) & 0xFE; // color.b = (source >> (10 - 1)) & 0xFE; // mColor = Color(color); //} //operator unsigned() const //{ // // Value is stored in the 10 lowest siginificant bits // unsigned32 res = (unsigned32)mValue; // // Colors are stored in the 21 highest significant bits (7 bits per channel, doesn't fit otherwise...) // res |= ((unsigned32)mColor.GetR() & 0xFE) << (10 + 14 - 1); // res |= ((unsigned32)mColor.GetG() & 0xFE) << (10 + 7 - 1); // res |= ((unsigned32)mColor.GetB() & 0xFE) << (10 - 1); // return res; //} }; template struct NearestFinder> { MaterialPair operator()(const MaterialPair& source, const std::vector>& values) { std::vector distances(values.size()); // Distances are defined as the sum. for (size_t i = 0; i < values.size(); i++) distances[i] = U::Distance(source.GetFirst(), values[i].GetFirst()) + V::Distance(source.GetSecond(), values[i].GetSecond()); auto minIt = std::min_element(distances.begin(), distances.end()); size_t minIndex = std::distance(distances.begin(), minIt); return values[minIndex]; } }; template struct ParallelNearestFinder> { MaterialPair operator()(const MaterialPair& source, const std::vector>& values) { std::vector distances(values.size()); // Distances are defined as the sum. for (size_t i = 0; i < values.size(); i++) distances[i] = U::Distance(source.GetFirst(), values[i].GetFirst()) + V::Distance(source.GetSecond(), values[i].GetSecond()); auto minIt = std::min_element(distances.begin(), distances.end()); size_t minIndex = std::distance(distances.begin(), minIt); return values[minIndex]; } }; namespace std { template struct hash> { size_t operator()(const MaterialPair &value) const { #ifdef ENVIRONMENT64 size_t cHash = std::hash()(value.GetFirst()); size_t nHash = std::hash()(value.GetSecond()); return cHash | BitHelper::CircularShiftLeft(nHash, V::BITS); #else return (unsigned32)value; #endif } }; } template struct MaterialPairCompare { bool operator()(const MaterialPair& a, const MaterialPair& b) const { if (a.GetFirst() != b.GetFirst()) return UCompare()(a.GetFirst(), b.GetFirst()); return VCompare()(a.GetSecond(), b.GetSecond()); } }; template struct Serializer> { static void Serialize(const MaterialPair& value, std::ostream& out) { Serializer::Serialize(value.GetFirst(), out); Serializer::Serialize(value.GetSecond(), out); } static void Deserialize(MaterialPair& value, std::istream& in) { U first; Serializer::Deserialize(first, in); value.SetFirst(first); V second; Serializer::Deserialize(second, in); value.SetSecond(second); } };