image: templatise on component count

This commit is contained in:
Danny Robson 2015-10-20 16:53:32 +11:00
parent 03efa074ab
commit 003685ce2b
12 changed files with 102 additions and 92 deletions

122
image.cpp
View File

@ -22,21 +22,26 @@ using util::image::buffer;
//-----------------------------------------------------------------------------
template <typename T>
util::image::buffer<T>::buffer (util::extentu<2> _size):
template <size_t C, typename T>
buffer<C,T>::buffer (util::extentu<2> _size):
m_size (_size),
m_stride (1, _size.w),
m_data (std::make_unique<T[]> (_size.area ()))
{ ; }
m_stride (C, _size.w),
m_data (std::make_unique<T[]> (_size.area () * C))
{
std::partial_sum (m_stride.begin (),
m_stride.end (),
m_stride.begin (),
std::multiplies<T> ());
}
//-----------------------------------------------------------------------------
template <typename T>
template <size_t C, typename T>
template <typename U>
util::image::buffer<U>
util::image::buffer<T>::alloc (void) const
buffer<C,U>
buffer<C,T>::alloc (void) const
{
return buffer<U> (m_size);
return buffer<C,U> (m_size);
}
@ -50,45 +55,46 @@ rescale (T v)
//-----------------------------------------------------------------------------
template <typename T>
template <size_t C, typename T>
template <typename U>
util::image::buffer<U>
util::image::buffer<T>::clone (void) const
util::image::buffer<C,U>
util::image::buffer<C,T>::clone (void) const
{
auto out = alloc<U> ();
std::transform (begin (), end (), out.begin (), renormalise<T,U>);
auto func = renormalise<T,U>;
std::transform (begin (), end (), out.begin (), func);
return out;
}
///////////////////////////////////////////////////////////////////////////////
template <typename T>
template <size_t C, typename T>
const T&
buffer<T>::operator[] (point<2,size_t> p) const
buffer<C,T>::operator[] (point<2,size_t> p) const
{
CHECK (util::all (p < size ()));
CHECK (util::all (p < extent ()));
return begin ()[offset (p)];
}
//-----------------------------------------------------------------------------
template <typename T>
template <size_t C, typename T>
T&
buffer<T>::operator[] (point<2,size_t> p)
buffer<C,T>::operator[] (point<2,size_t> p)
{
CHECK (util::all (p < size ()));
CHECK (util::all (p < extent ()));
return begin ()[offset (p)];
}
//-----------------------------------------------------------------------------
template <typename T>
template <size_t C, typename T>
const T&
buffer<T>::operator[] (size_t idx) const
buffer<C,T>::operator[] (size_t idx) const
{
CHECK_LT (idx, size ());
@ -97,9 +103,9 @@ buffer<T>::operator[] (size_t idx) const
//-----------------------------------------------------------------------------
template <typename T>
template <size_t C, typename T>
T&
buffer<T>::operator[] (size_t idx)
buffer<C,T>::operator[] (size_t idx)
{
CHECK_LT (idx, size ());
@ -108,97 +114,101 @@ buffer<T>::operator[] (size_t idx)
///////////////////////////////////////////////////////////////////////////////
template <typename T>
template <size_t C, typename T>
T*
buffer<T>::data (void)
buffer<C,T>::data (void)
{
return begin ();
}
//-----------------------------------------------------------------------------
template <typename T>
template <size_t C, typename T>
T*
buffer<T>::begin (void)
buffer<C,T>::begin (void)
{
return m_data.get ();
}
//-----------------------------------------------------------------------------
template <typename T>
template <size_t C, typename T>
T*
buffer<T>::end (void)
buffer<C,T>::end (void)
{
return begin () + m_size.back () * m_stride.back ();
}
//-----------------------------------------------------------------------------
template <typename T>
template <size_t C, typename T>
const T*
buffer<T>::begin (void) const
buffer<C,T>::begin (void) const
{
return cbegin ();
}
//-----------------------------------------------------------------------------
template <typename T>
template <size_t C, typename T>
const T*
buffer<T>::end (void) const
buffer<C,T>::end (void) const
{
return cend ();
}
//-----------------------------------------------------------------------------
template <typename T>
template <size_t C, typename T>
const T*
buffer<T>::data (void) const
buffer<C,T>::data (void) const
{
return begin ();
}
//-----------------------------------------------------------------------------
template <typename T>
template <size_t C, typename T>
const T*
buffer<T>::cbegin (void) const
buffer<C,T>::cbegin (void) const
{
return m_data.get ();
}
//-----------------------------------------------------------------------------
template <typename T>
template <size_t C, typename T>
const T*
buffer<T>::cend (void) const
buffer<C,T>::cend (void) const
{
return cbegin () + m_size.back () * m_stride.back ();
}
///////////////////////////////////////////////////////////////////////////////
template struct util::image::buffer<char>;
template struct util::image::buffer<uint8_t>;
template struct util::image::buffer<uint16_t>;
template struct util::image::buffer<uint32_t>;
template struct util::image::buffer< int32_t>;
template struct util::image::buffer<float>;
template struct util::image::buffer<double>;
template util::image::buffer<char> util::image::buffer<char>::alloc (void) const;
#define INSTANTIATE_C_T_U(C,T,U) \
template util::image::buffer<C,U> util::image::buffer<C,T>::alloc (void) const; \
template util::image::buffer<C,U> util::image::buffer<C,T>::clone (void) const; \
template util::image::buffer<C,U> util::image::buffer<C,T>::cast (void) const;
template util::image::buffer<uint8_t> util::image::buffer<uint8_t>::alloc (void) const;
template util::image::buffer<uint8_t> util::image::buffer<uint8_t>::clone (void) const;
template util::image::buffer<uint8_t> util::image::buffer<float>::clone (void) const;
template util::image::buffer<uint8_t> util::image::buffer<double>::clone (void) const;
#define INSTANTIATE_C_T(C,T) \
template struct util::image::buffer<C,T>; \
INSTANTIATE_C_T_U(C,T,uint8_t) \
INSTANTIATE_C_T_U(C,T,uint16_t) \
INSTANTIATE_C_T_U(C,T,uint32_t) \
INSTANTIATE_C_T_U(C,T,float) \
INSTANTIATE_C_T_U(C,T,double)
template util::image::buffer<float> util::image::buffer<float>::alloc (void) const;
template util::image::buffer<uint32_t> util::image::buffer<float>::alloc (void) const;
template util::image::buffer< int32_t> util::image::buffer<float>::alloc (void) const;
template util::image::buffer<float> util::image::buffer<float>::clone (void) const;
#define INSTANTIATE_C(C) \
INSTANTIATE_C_T(C,uint8_t) \
INSTANTIATE_C_T(C,uint16_t) \
INSTANTIATE_C_T(C,uint32_t) \
INSTANTIATE_C_T(C,float) \
INSTANTIATE_C_T(C,double)
template util::image::buffer<uint32_t> util::image::buffer<uint32_t>::alloc (void) const;
INSTANTIATE_C(1)
INSTANTIATE_C(2)
INSTANTIATE_C(3)
INSTANTIATE_C(4)

View File

@ -26,7 +26,7 @@
namespace util { namespace image {
template <typename T>
template <size_t C, typename T>
struct buffer {
typedef T value_type;
@ -34,18 +34,18 @@ namespace util { namespace image {
buffer (util::extentu<2>);
buffer (util::extentu<2>, std::unique_ptr<T[]> &&data);
buffer (const buffer<T>&) = delete;
buffer (buffer<T> &&) = default;
buffer& operator= (const buffer<T>&) = default;
buffer& operator= (buffer<T>&&) = default;
buffer (const buffer&) = delete;
buffer (buffer &&) = default;
buffer& operator= (const buffer&) = default;
buffer& operator= (buffer&&) = default;
//---------------------------------------------------------------------
/// allocate and return a buffer of the same dimensions. contents are undefined.
template <typename U = T> buffer<U> alloc (void) const;
template <typename U = T> buffer<C,U> alloc (void) const;
/// allocate and return a buffer with the same contents
template <typename U = T> buffer<U> clone (void) const;
template <typename U> buffer<U> cast (void) const { return clone<U> (); }
template <typename U = T> buffer<C,U> clone (void) const;
template <typename U> buffer<C,U> cast (void) const { return clone<U> (); }
//---------------------------------------------------------------------
constexpr extent2u extent (void) const;

View File

@ -21,45 +21,45 @@
namespace util { namespace image {
//-------------------------------------------------------------------------
template <typename T>
template <size_t C, typename T>
constexpr extent2u
buffer<T>::extent (void) const
buffer<C,T>::extent (void) const
{
return m_size;
}
//-------------------------------------------------------------------------
template <typename T>
template <size_t C, typename T>
constexpr vector2u
buffer<T>::stride (void) const
buffer<C,T>::stride (void) const
{
return m_stride;
}
//-------------------------------------------------------------------------
template <typename T>
template <size_t C, typename T>
constexpr size_t
buffer<T>::offset (point<2,size_t> p) const
buffer<C,T>::offset (point<2,size_t> p) const
{
return dot (stride (), p);
}
//-------------------------------------------------------------------------
template <typename T>
template <size_t C, typename T>
constexpr size_t
buffer<T>::size (void) const
buffer<C,T>::size (void) const
{
return extent ().back () * stride ().back ();
}
//-------------------------------------------------------------------------
template <typename T>
template <size_t C, typename T>
constexpr bool
buffer<T>::is_packed (void) const
buffer<C,T>::is_packed (void) const
{
return stride ().back () == extent ().back ();
}

View File

@ -25,7 +25,7 @@
// HACK: This does not support the full header structure with any robustness.
// In particular it will abort when it sees a comment. If you want better
// support use waif, or port its implementation.
util::image::buffer<uint8_t>
util::image::buffer<1,uint8_t>
util::pgm::read (const boost::filesystem::path &path)
{
util::mapped_file raw (path);
@ -48,7 +48,7 @@ util::pgm::read (const boost::filesystem::path &path)
if (expected != remain)
throw std::runtime_error ("expected data size mismatch");
util::image::buffer<uint8_t> out ({width, height});
util::image::buffer<1,uint8_t> out ({width, height});
CHECK (out.is_packed ());
std::copy (raw.begin () + cooked.tellg () - 1, raw.end (), out.begin ());
@ -85,7 +85,7 @@ write_netpbm (const uint8_t *restrict pixels,
//-----------------------------------------------------------------------------
void
util::pgm::write (const util::image::buffer<uint8_t> &src,
util::pgm::write (const util::image::buffer<1,uint8_t> &src,
std::ostream &dst)
{
write (src.begin (), src.extent ().w, src.extent ().h, src.stride ().y, dst);
@ -94,7 +94,7 @@ util::pgm::write (const util::image::buffer<uint8_t> &src,
//-----------------------------------------------------------------------------
void
util::pgm::write (const util::image::buffer<uint8_t> &src,
util::pgm::write (const util::image::buffer<1,uint8_t> &src,
const boost::filesystem::path &path)
{
std::ofstream dst (path.string ());

View File

@ -27,11 +27,11 @@
namespace util {
// Portable GrayMap: single component greyscale.
struct pgm {
static image::buffer<uint8_t> read (const boost::filesystem::path&);
static image::buffer<1,uint8_t> read (const boost::filesystem::path&);
static void write (const image::buffer<uint8_t> &src,
static void write (const image::buffer<1,uint8_t> &src,
const boost::filesystem::path &dst);
static void write (const image::buffer<uint8_t> &src,
static void write (const image::buffer<1,uint8_t> &src,
std::ostream &dst);
static void write (const uint8_t *restrict pixels,

View File

@ -26,7 +26,7 @@
//-----------------------------------------------------------------------------
template <typename T>
void
util::noise::fill (image::buffer<T> &pixels,
util::noise::fill (image::buffer<1,T> &pixels,
const util::noise::fractal<T> &gen)
{
size_t h = pixels.h, s = pixels.s, w = pixels.w;
@ -37,8 +37,8 @@ util::noise::fill (image::buffer<T> &pixels,
data[y * s + x] = gen ({T(x), T(y)});
}
template void util::noise::fill (image::buffer<float>&, const util::noise::fractal<float>&);
template void util::noise::fill (image::buffer<double>&, const util::noise::fractal<double>&);
template void util::noise::fill (image::buffer<1,float>&, const util::noise::fractal<float>&);
template void util::noise::fill (image::buffer<1,double>&, const util::noise::fractal<double>&);
//-----------------------------------------------------------------------------

View File

@ -24,7 +24,7 @@
namespace util { namespace noise {
template <typename T, typename G>
void fill (image::buffer<T>&, const G&);
void fill (image::buffer<1,T>&, const G&);
} }
#include "noise.ipp"

View File

@ -23,7 +23,7 @@ namespace util { namespace noise {
//-------------------------------------------------------------------------
template <typename T, typename G>
void
fill (image::buffer<T> &pixels, const G& gen)
fill (image::buffer<1,T> &pixels, const G& gen)
{
size_t h = pixels.h, s = pixels.s, w = pixels.w;
T *data = pixels.data ();

View File

@ -25,7 +25,7 @@
// assumes corner points have been assigned their weights
template <typename T>
static void
fill (util::image::buffer<T> &img,
fill (util::image::buffer<1,T> &img,
uint64_t seed,
util::region2u target,
float scale,
@ -99,7 +99,7 @@ fill (util::image::buffer<T> &img,
///////////////////////////////////////////////////////////////////////////////
template <typename T>
void
util::noise::midpoint (image::buffer<T> &img, uint64_t seed, float persistence, float sides)
util::noise::midpoint (image::buffer<1,T> &img, uint64_t seed, float persistence, float sides)
{
auto ext = img.extent ();
@ -118,4 +118,4 @@ util::noise::midpoint (image::buffer<T> &img, uint64_t seed, float persistence,
//-----------------------------------------------------------------------------
template void util::noise::midpoint (image::buffer<float>&, uint64_t, float, float);
template void util::noise::midpoint (image::buffer<1,float>&, uint64_t, float, float);

View File

@ -22,7 +22,7 @@
namespace util { namespace noise {
template <typename T>
void
midpoint (image::buffer<T>&, uint64_t seed, float persistence = 0.65f, float sides = 0.25f);
midpoint (image::buffer<1,T>&, uint64_t seed, float persistence = 0.65f, float sides = 0.25f);
} }
#endif

View File

@ -10,7 +10,7 @@ main (void)
constexpr size_t W = 64;
constexpr size_t H = 128;
util::image::buffer<uint16_t> img ({W, H});
util::image::buffer<1,uint16_t> img ({W, H});
if (!img.is_packed ())
tap.skip ("linear position probe requires packed image allocation");

View File

@ -346,7 +346,7 @@ main (int argc, char **argv)
for (auto &p: t.perturb)
p.frequency (scale / res.w);
util::image::buffer<float> img (res);
util::image::buffer<1,float> img (res);
// XXX: offset slightly to avoid origin artefacts in some basis functions
const auto OFFSET = util::vector2f {