170 lines
4.5 KiB
C++
170 lines
4.5 KiB
C++
#pragma once
|
|
|
|
#include "../../core/BitHelper.h"
|
|
#include "../../core/Defines.h"
|
|
#include <cmath>
|
|
|
|
template <unsigned N>
|
|
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<size_t>(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<unsigned32>(0, 11)) << 10) | (((unsigned32)material.z) & BitHelper::GetLSMask<unsigned32>(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<BitsMaterial>& values)
|
|
{
|
|
size_t sum = 0;
|
|
for (auto value : values) sum += value.GetValue();
|
|
sum /= values.size();
|
|
return BitsMaterial(sum);
|
|
}
|
|
|
|
static BitsMaterial WeightedAverage(const std::vector<BitsMaterial>& values, std::vector<float> 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<unsigned8>(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<unsigned8> Serialize() const {
|
|
std::vector<unsigned8> res(BYTECOUNT);
|
|
for (size_t i = 0; i < BYTECOUNT; i++) res[i] = mValue[i];
|
|
return res;
|
|
}
|
|
|
|
void Deserialize(std::vector<unsigned8> 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<N>& other) const {
|
|
for (unsigned i = 0; i < BYTECOUNT; i++)
|
|
if (mValue[i] != other.mValue[i]) return false;
|
|
return true;
|
|
}
|
|
|
|
bool operator<(const BitsMaterial<N>& 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<unsigned N> struct hash <BitsMaterial<N>>
|
|
{
|
|
size_t operator()(BitsMaterial<N> 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<unsigned N>
|
|
struct BitsMaterialComparer
|
|
{
|
|
bool operator()(const BitsMaterial<N>& a, const BitsMaterial<N>& b)
|
|
{
|
|
return a.GetValue() < b.GetValue();
|
|
}
|
|
}; |