Back to Image-based texture with mip-map resampling
#ifndef PASTELGFX_MIPIMAGE_TEXTURE_HPP
#define PASTELGFX_MIPIMAGE_TEXTURE_HPP
#include "pastel/gfx/texture/mipimage_texture.h"
#include "pastel/gfx/texture/linearimage_texture.h"
#include "pastel/gfx/mipmap/mipmap.h"
#include "pastel/sys/view/arrayview.h"
#include "pastel/sys/view/repeatedconstview.h"
#include "pastel/sys/view/view_tools.h"
namespace Pastel
{
template <typename Type, integer N>
MipImage_Texture<Type, N>::MipImage_Texture()
: mipMap_(0)
, extender_()
{
}
template <typename Type, integer N>
MipImage_Texture<Type, N>::MipImage_Texture(
const MipMap<Type, N>& mipMap,
const ArrayExtender_& extender)
: mipMap_(&mipMap)
, extender_(extender)
{
}
template <typename Type, integer N>
Type MipImage_Texture<Type, N>::operator()(
const Vector<real, N>& uv,
const Matrix<real>& m) const
{
if (!mipMap_ || mipMap_->empty())
{
return Type();
}
integer n = m.height();
const Array<Type, N>& mostDetailedImage =
mipMap_->mostDetailed();
// Compute detail level.
// This is done by finding the tangent
// vector with the greatest length and using
// that as a isotropic sampling frequency.
// The one of greatest length is used to ensure
// we get rid of aliasing.
real d = 0;
for (integer i = 0;i < n;++i)
{
const real dotMi = dot(m.cColumn(i) * Vector<real, N>(mostDetailedImage.extent()));
if (dotMi > d)
{
d = dotMi;
}
}
real invLn2 = inverse(constantLn2<real>());
const real level = 0.5 * std::log(d) * invLn2;
// Handle the case where no filtering needs to be done.
if (level <= 0)
{
return sampleLinear(
evaluate(uv * Vector<real, N>(mostDetailedImage.extent())),
mostDetailedImage, extender_);
}
// Handle the case where the image is smaller than
// a single pixel.
if (level >= mipMap_->levels() - 1)
{
return mipMap_->coarsest()(0);
}
// Gather samples from the 2 neighboring mipmaps.
// First sample from the more detailed image.
integer detailLevel = std::floor(level);
const Array<Type, N>& detailImage =
(*mipMap_)(detailLevel);
Type detailSample =
sampleLinear(
evaluate(uv * Vector<real, N>(detailImage.extent())),
detailImage, extender_);
// Then sample from the less detailed image.
integer coarseLevel = detailLevel + 1;
const Array<Type, N>& coarseImage =
(*mipMap_)(coarseLevel);
Type coarseSample =
sampleLinear(
evaluate(uv * Vector<real, N>(coarseImage.extent())),
coarseImage, extender_);
// Linearly interpolate these samples by the
// fractional detail level.
real tDetail = level - detailLevel;
return linear(detailSample, coarseSample, tDetail);
}
}
#endif