169 lines
5.9 KiB
C++
169 lines
5.9 KiB
C++
#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<typename U, typename V>
|
|
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<U, V> pair) : mFirst(pair.first), mSecond(pair.second) {}
|
|
template<typename UC, typename VC>
|
|
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<MaterialPair>& values)
|
|
{
|
|
std::vector<U> firsts(values.size());
|
|
std::vector<V> 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<MaterialPair>& values, const std::vector<float>& weights)
|
|
{
|
|
std::vector<U> firsts(values.size());
|
|
std::vector<V> 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<unsigned8> Serialize() const {
|
|
std::vector<unsigned8> firstSerialized = GetFirst().Serialize();
|
|
std::vector<unsigned8> secondSerialized = GetSecond().Serialize();
|
|
firstSerialized.insert(firstSerialized.end(), secondSerialized.begin(), secondSerialized.end());
|
|
return firstSerialized;
|
|
};
|
|
|
|
void Deserialize(const std::vector<unsigned8>& value)
|
|
{
|
|
mFirst.Deserialize(std::vector<unsigned8>(value.begin(), value.begin() + sizeof(mFirst)));
|
|
mSecond.Deserialize(std::vector<unsigned8>(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<typename U, typename V>
|
|
struct NearestFinder<MaterialPair<U, V>>
|
|
{
|
|
MaterialPair<U, V> operator()(const MaterialPair<U, V>& source, const std::vector<MaterialPair<U, V>>& values)
|
|
{
|
|
std::vector<float> 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<typename U, typename V>
|
|
struct ParallelNearestFinder<MaterialPair<U, V>>
|
|
{
|
|
MaterialPair<U, V> operator()(const MaterialPair<U, V>& source, const std::vector<MaterialPair<U, V>>& values)
|
|
{
|
|
std::vector<float> 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<typename U, typename V>
|
|
struct hash<MaterialPair<U, V>> {
|
|
size_t operator()(const MaterialPair<U, V> &value) const {
|
|
#ifdef ENVIRONMENT64
|
|
size_t cHash = std::hash<U>()(value.GetFirst());
|
|
size_t nHash = std::hash<V>()(value.GetSecond());
|
|
return cHash | BitHelper::CircularShiftLeft<size_t>(nHash, V::BITS);
|
|
#else
|
|
return (unsigned32)value;
|
|
#endif
|
|
}
|
|
};
|
|
}
|
|
|
|
template<typename U, typename UCompare, typename V, typename VCompare>
|
|
struct MaterialPairCompare
|
|
{
|
|
bool operator()(const MaterialPair<U, V>& a, const MaterialPair<U, V>& b) const
|
|
{
|
|
if (a.GetFirst() != b.GetFirst()) return UCompare()(a.GetFirst(), b.GetFirst());
|
|
return VCompare()(a.GetSecond(), b.GetSecond());
|
|
}
|
|
};
|
|
|
|
template<typename U, typename V>
|
|
struct Serializer<MaterialPair<U, V>>
|
|
{
|
|
static void Serialize(const MaterialPair<U, V>& value, std::ostream& out)
|
|
{
|
|
Serializer<U>::Serialize(value.GetFirst(), out);
|
|
Serializer<V>::Serialize(value.GetSecond(), out);
|
|
}
|
|
|
|
static void Deserialize(MaterialPair<U, V>& value, std::istream& in)
|
|
{
|
|
U first; Serializer<U>::Deserialize(first, in); value.SetFirst(first);
|
|
V second; Serializer<V>::Deserialize(second, in); value.SetSecond(second);
|
|
}
|
|
}; |