Files
CDAG/Research/core/Util/TransferFunction.h

72 lines
1.7 KiB
C++

#pragma once
#include "../Defines.h"
#include <vector>
#include <algorithm>
#include "../MathHelper.h"
template<typename T>
class TransferFunction
{
public:
struct Node
{
unsigned32 value;
float opacity;
T material;
Node(unsigned32 value, float opacity, T mat) : value(value), opacity(opacity), material(mat) {}
Node(unsigned32 value) : value(value), opacity(0), material(T()) {}
};
struct NodeCompare { bool operator()(const Node& a, const Node& b) { return a.value < b.value; } };
TransferFunction()
{
}
~TransferFunction() { mFunction.clear(); }
void AddNode(unsigned32 value, float opacity, T mat)
{
Node node(value, opacity, mat);
auto pos = LowerBound(node);
if (pos != mFunction.end() && pos->value == value)
mFunction[pos - mFunction.begin()] = node;
else
mFunction.insert(pos, node);
}
template<typename Interpolator>
void Evaluate(unsigned32 value, float& outOpacity, T& outMat, Interpolator interpolator) const
{
Node node(value);
// Set default values
outOpacity = 1.f;
outMat = T();
// Find the current node
auto pos = LowerBound(node);
if (pos == mFunction.end()) return;
Node after = *pos;
if (pos == mFunction.begin())
{
outOpacity = after.opacity;
outMat = after.material;
return;
}
pos--;
Node before = *pos;
float t = float(value - before.value) / float(after.value - before.value);
outMat = interpolator(before.material, after.material, t);
outOpacity = MathHelper::lerp(t, before.opacity, after.opacity);
}
private:
typename std::vector<Node>::const_iterator LowerBound(const Node& node) const
{
return std::lower_bound(mFunction.begin(), mFunction.end(), node, NodeCompare());
}
std::vector<Node> mFunction;
};