Back to Image-based texture using rip-map resampling
#ifndef PASTELGFX_RIPIMAGE_TEXTURE_HPP
#define PASTELGFX_RIPIMAGE_TEXTURE_HPP
#include "pastel/gfx/texture/ripimage_texture.h"
#include "pastel/gfx/texture/linearimage_texture.h"
#include "pastel/gfx/ripmap/ripmap.h"
#include "pastel/sys/vector/vector_tools.h"
namespace Pastel
{
template <typename Type, integer N>
RipImage_Texture<Type, N>::RipImage_Texture()
: ripMap_(0)
, extender_()
{
}
template <typename Type, integer N>
RipImage_Texture<Type, N>::RipImage_Texture(
const RipMap<Type, N>& ripMap,
const ArrayExtender_& extender)
: ripMap_(&ripMap)
, extender_(extender)
{
}
template <typename Type, integer N>
Type RipImage_Texture<Type, N>::operator()(
const Vector<real, N>& uv,
const Matrix<real>& m) const
{
if (!ripMap_ || ripMap_->empty())
{
return Type();
}
integer n = uv.size();
const Array<Type, N>& mostDetailedImage =
ripMap_->mostDetailed();
Vector<real, N> radius =
max(abs(m)) * Vector<real, N>(mostDetailedImage.extent());
if (allLessEqual(radius, 1))
{
// Magnification: just do linear interpolation.
return sampleLinear(
evaluate(uv * Vector<real, N>(mostDetailedImage.extent())),
mostDetailedImage, extender_);
}
real invLn2 = inverse(constantLn2<real>());
const Vector<real, N> level(max(evaluate(log(radius) * invLn2), 0));
if (allLessEqual(level, 0))
{
return sampleLinear(
evaluate(uv * Vector<real, N>(mostDetailedImage.extent())),
mostDetailedImage, extender_);
}
if (anyGreaterEqual(level, Vector<real, N>(ripMap_->levels() - 1)))
{
// Return the coarsest ripmap pixel.
return ripMap_->coarsest()(0);
}
// Gather samples from all of the neighboring
// 2^n ripmaps.
Vector<integer, N> p(floor(level));
Vector<real, N> tDetail = level - Vector<real, N>(p);
integer samples = (integer)1 << n;
Tuple<Type, ModifyN<N, 1 << N>::Result> valueSet(ofDimension(samples));
Tuple<bool, N> s(ofDimension(n), false);
for (integer i = 0;i < samples;++i)
{
const Array<Type, N>& image = (*ripMap_)(p);
valueSet[i] = sampleLinear(
evaluate(uv * Vector<real, N>(image.extent())),
image, extender_);
integer axis = 0;
while(axis < n)
{
if (s[axis])
{
s[axis] = false;
--p[axis];
}
else
{
s[axis] = true;
++p[axis];
break;
}
++axis;
}
}
// Linearly interpolate between those samples.
return linear(tDetail,
range(valueSet.begin(), valueSet.end()));
}
}
#endif