#pragma once #include "../../core/BitHelper.h" #include "../../core/Defines.h" #include template class BitsMaterial { public: const static size_t BYTECOUNT = N / 8 + ((N % 8) == 0 ? 0 : 1); // Calculate the space needed to store the required number of bits const static unsigned8 BITS = N; private: unsigned8 mValue[BYTECOUNT]; static size_t GrabBits(size_t value, unsigned8 startBit, unsigned8 length) { return ((BitHelper::GetLSMask(startBit, startBit + length)) & value) >> startBit; } static size_t GrabBits(size_t value, unsigned8 startBit) { return GrabBits(value, startBit, N); } inline void Init(size_t value) { for (unsigned8 i = 0; i < BYTECOUNT; i++) mValue[BYTECOUNT - i - 1] = (unsigned8)GrabBits(value, i * 8, 8); } public: BitsMaterial() { mValue[0] = 0; } BitsMaterial(size_t value) { Init(value); } // Grab some bits from the number and store them in this material BitsMaterial(unsigned value, unsigned8 startBit) { Init(GrabBits(value, startBit)); } ~BitsMaterial() {} bool Empty() { return mValue == 0; } glm::u16vec3 GetProperties() const { unsigned32 value = (unsigned32)GetValue(); return glm::u16vec3(GrabBits(value, 21, 11), GrabBits(value, 10, 11), GrabBits(value, 0, 10)); } void SetProperties(glm::u16vec3 material) { unsigned32 value = (((unsigned32)material.x) << 21) | (((unsigned32)material.y & BitHelper::GetLSMask(0, 11)) << 10) | (((unsigned32)material.z) & BitHelper::GetLSMask(0, 10)); Init(value); } size_t GetValue() const { size_t value = 0; for (unsigned8 i = 0; i < BYTECOUNT; i++) value |= mValue[i] << ((BYTECOUNT - i - 1) >> 3); // Get the value, shift it to the correct position, and add it to the GetValue() result return value; } std::string GetTypeSuffix() const { return "b" + std::to_string(N); } static float Distance(BitsMaterial a, BitsMaterial b) { size_t maxValue = BitHelper::Exp2(N); return (float)std::abs((float)b.GetValue() - (float)a.GetValue()) / (float)maxValue; } static BitsMaterial Average(const std::vector& values) { size_t sum = 0; for (auto value : values) sum += value.GetValue(); sum /= values.size(); return BitsMaterial(sum); } static BitsMaterial WeightedAverage(const std::vector& values, std::vector weights) { float sum = 0; for (size_t i = 0; i < values.size(); i++) sum += (float)values[i].GetValue() * weights[i]; sum /= (float)CollectionHelper::Sum(weights); return BitsMaterial((size_t)sum); } void SetLS(size_t index, bool value) { size_t byte = index >> 8; unsigned8 mask = BitHelper::GetLSSingleBitMask(index & 0x07); // Clear the bit mValue[byte] &= ~mask; // Set the bit if (value) mValue[byte] |= mask; } bool GetLS(size_t index) { size_t byte = index >> 8; size_t bit = index % 8; return BitHelper::GetLS(mValue[byte], (unsigned8)bit); } void SetHS(size_t index, bool value) { SetLS(N - index - 1, value); } bool GetHS(size_t index) { return GetLS(N - index - 1); } std::vector Serialize() const { std::vector res(BYTECOUNT); for (size_t i = 0; i < BYTECOUNT; i++) res[i] = mValue[i]; return res; } void Deserialize(std::vector value) { assert(value.size() == BYTECOUNT); for (size_t i = 0; i < BYTECOUNT; i++) mValue[i] = value[i]; } void Serialize(std::ostream& stream) const { stream.write((char*)&mValue[0], BYTECOUNT); } void Deserialize(std::istream& stream) { stream.read((char*)&mValue[0], BYTECOUNT); } bool operator==(const BitsMaterial& other) const { for (unsigned i = 0; i < BYTECOUNT; i++) if (mValue[i] != other.mValue[i]) return false; return true; } bool operator<(const BitsMaterial& other) const { for (unsigned8 i = 0; i < BYTECOUNT; i++) if (mValue[i] != other.mValue[i]) return mValue[i] < other.mValue[i]; return false; // If they are equal, return false } operator unsigned() const { return (unsigned32)GetValue(); } }; namespace std { template struct hash > { size_t operator()(BitsMaterial const& value) const { // Check if a perfect hash is possible if (N < (sizeof(size_t) * 8)) { return value.GetValue(); } else { // TODO: make a hash for all bytes return value.GetValue(); } } }; } template struct BitsMaterialComparer { bool operator()(const BitsMaterial& a, const BitsMaterial& b) { return a.GetValue() < b.GetValue(); } };