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> template <size_t C, typename T>
util::image::buffer<T>::buffer (util::extentu<2> _size): buffer<C,T>::buffer (util::extentu<2> _size):
m_size (_size), m_size (_size),
m_stride (1, _size.w), m_stride (C, _size.w),
m_data (std::make_unique<T[]> (_size.area ())) 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> template <typename U>
util::image::buffer<U> buffer<C,U>
util::image::buffer<T>::alloc (void) const 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> template <typename U>
util::image::buffer<U> util::image::buffer<C,U>
util::image::buffer<T>::clone (void) const util::image::buffer<C,T>::clone (void) const
{ {
auto out = alloc<U> (); 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; return out;
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
template <typename T> template <size_t C, typename T>
const 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)]; return begin ()[offset (p)];
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template <typename T> template <size_t C, typename T>
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)]; return begin ()[offset (p)];
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template <typename T> template <size_t C, typename T>
const T& const T&
buffer<T>::operator[] (size_t idx) const buffer<C,T>::operator[] (size_t idx) const
{ {
CHECK_LT (idx, size ()); 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& T&
buffer<T>::operator[] (size_t idx) buffer<C,T>::operator[] (size_t idx)
{ {
CHECK_LT (idx, size ()); CHECK_LT (idx, size ());
@ -108,97 +114,101 @@ buffer<T>::operator[] (size_t idx)
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
template <typename T> template <size_t C, typename T>
T* T*
buffer<T>::data (void) buffer<C,T>::data (void)
{ {
return begin (); return begin ();
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template <typename T> template <size_t C, typename T>
T* T*
buffer<T>::begin (void) buffer<C,T>::begin (void)
{ {
return m_data.get (); return m_data.get ();
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template <typename T> template <size_t C, typename T>
T* T*
buffer<T>::end (void) buffer<C,T>::end (void)
{ {
return begin () + m_size.back () * m_stride.back (); return begin () + m_size.back () * m_stride.back ();
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template <typename T> template <size_t C, typename T>
const T* const T*
buffer<T>::begin (void) const buffer<C,T>::begin (void) const
{ {
return cbegin (); return cbegin ();
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template <typename T> template <size_t C, typename T>
const T* const T*
buffer<T>::end (void) const buffer<C,T>::end (void) const
{ {
return cend (); return cend ();
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template <typename T> template <size_t C, typename T>
const T* const T*
buffer<T>::data (void) const buffer<C,T>::data (void) const
{ {
return begin (); return begin ();
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template <typename T> template <size_t C, typename T>
const T* const T*
buffer<T>::cbegin (void) const buffer<C,T>::cbegin (void) const
{ {
return m_data.get (); return m_data.get ();
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template <typename T> template <size_t C, typename T>
const T* const T*
buffer<T>::cend (void) const buffer<C,T>::cend (void) const
{ {
return cbegin () + m_size.back () * m_stride.back (); 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; #define INSTANTIATE_C_T(C,T) \
template util::image::buffer<uint8_t> util::image::buffer<uint8_t>::clone (void) const; template struct util::image::buffer<C,T>; \
template util::image::buffer<uint8_t> util::image::buffer<float>::clone (void) const; INSTANTIATE_C_T_U(C,T,uint8_t) \
template util::image::buffer<uint8_t> util::image::buffer<double>::clone (void) const; 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 { namespace util { namespace image {
template <typename T> template <size_t C, typename T>
struct buffer { struct buffer {
typedef T value_type; typedef T value_type;
@ -34,18 +34,18 @@ namespace util { namespace image {
buffer (util::extentu<2>); buffer (util::extentu<2>);
buffer (util::extentu<2>, std::unique_ptr<T[]> &&data); buffer (util::extentu<2>, std::unique_ptr<T[]> &&data);
buffer (const buffer<T>&) = delete; buffer (const buffer&) = delete;
buffer (buffer<T> &&) = default; buffer (buffer &&) = default;
buffer& operator= (const buffer<T>&) = default; buffer& operator= (const buffer&) = default;
buffer& operator= (buffer<T>&&) = default; buffer& operator= (buffer&&) = default;
//--------------------------------------------------------------------- //---------------------------------------------------------------------
/// allocate and return a buffer of the same dimensions. contents are undefined. /// 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 /// allocate and return a buffer with the same contents
template <typename U = T> buffer<U> clone (void) const; template <typename U = T> buffer<C,U> clone (void) const;
template <typename U> buffer<U> cast (void) const { return clone<U> (); } template <typename U> buffer<C,U> cast (void) const { return clone<U> (); }
//--------------------------------------------------------------------- //---------------------------------------------------------------------
constexpr extent2u extent (void) const; constexpr extent2u extent (void) const;

View File

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

View File

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

View File

@ -27,11 +27,11 @@
namespace util { namespace util {
// Portable GrayMap: single component greyscale. // Portable GrayMap: single component greyscale.
struct pgm { 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); 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); std::ostream &dst);
static void write (const uint8_t *restrict pixels, static void write (const uint8_t *restrict pixels,

View File

@ -26,7 +26,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template <typename T> template <typename T>
void void
util::noise::fill (image::buffer<T> &pixels, util::noise::fill (image::buffer<1,T> &pixels,
const util::noise::fractal<T> &gen) const util::noise::fractal<T> &gen)
{ {
size_t h = pixels.h, s = pixels.s, w = pixels.w; 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)}); 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<1,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,double>&, const util::noise::fractal<double>&);
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View File

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

View File

@ -23,7 +23,7 @@ namespace util { namespace noise {
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
template <typename T, typename G> template <typename T, typename G>
void 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; size_t h = pixels.h, s = pixels.s, w = pixels.w;
T *data = pixels.data (); T *data = pixels.data ();

View File

@ -25,7 +25,7 @@
// assumes corner points have been assigned their weights // assumes corner points have been assigned their weights
template <typename T> template <typename T>
static void static void
fill (util::image::buffer<T> &img, fill (util::image::buffer<1,T> &img,
uint64_t seed, uint64_t seed,
util::region2u target, util::region2u target,
float scale, float scale,
@ -99,7 +99,7 @@ fill (util::image::buffer<T> &img,
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
template <typename T> template <typename T>
void 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 (); 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 { namespace util { namespace noise {
template <typename T> template <typename T>
void 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 #endif

View File

@ -10,7 +10,7 @@ main (void)
constexpr size_t W = 64; constexpr size_t W = 64;
constexpr size_t H = 128; 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 ()) if (!img.is_packed ())
tap.skip ("linear position probe requires packed image allocation"); 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) for (auto &p: t.perturb)
p.frequency (scale / res.w); 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 // XXX: offset slightly to avoid origin artefacts in some basis functions
const auto OFFSET = util::vector2f { const auto OFFSET = util::vector2f {