#pragma once #ifndef _NB_IMAGE #define _NB_IMAGE #include #include namespace nb { template struct Color {}; struct Red : Color {}; struct Green : Color {}; struct Blue : Color {}; struct Alpha : Color {}; struct Depth; struct Stencil; template struct PixelChannel; template struct PixelChannel { using type=T; T value; T& r=value; }; template struct PixelChannel { using type=T; T value; T& g=value; }; template struct PixelChannel { using type=T; T value; T& b=value; }; template struct PixelChannel { using type=T; T value; T& a=value; }; template struct PixelChannel { using type=T; T value; T& z=value; }; template<> struct PixelChannel { using type=uint8_t; uint8_t value; uint8_t& u=value; }; template struct Pixel : public PixelChannel... { Pixel() = default; Pixel& operator=(const Pixel& rhs) { (( [&](const typename PixelChannel::type& val){ this->PixelChannel::value = val; }(rhs.PixelChannel::value) ), ...); return *this; } Pixel(const Pixel& cpy) : Pixel(cpy.PixelChannel::value...) {} Pixel(typename PixelChannel::type... vals) : PixelChannel{vals}... {} }; template struct PixelReference; template struct PixelReference> : public Pixel { using PixelType = Pixel; using Base = Pixel; using Base::Base; PixelReference(PixelType& pixel) : Base(pixel.PixelChannel::value...) {} operator PixelType() { return PixelType(this->PixelChannel::value...); } PixelReference& operator=(const PixelType& pixel) { (( [&](const typename PixelChannel::type& val){ this->PixelChannel::value = val; }(pixel.PixelChannel::value) ), ...); return *this; } }; template using RGBA = Pixel; template using RGB = Pixel; class ImageError : public Error { protected: using Base = Error; using Base::Base; public: enum Codes : unsigned int { UNDEFINED, OUT_OF_BOUNDS }; static const std::string type; static const ErrorCodeMap ErrorMessages; }; template class Image; template class Image> { protected: using Codes = ImageError::Codes; T* _data; Image(unsigned int x, unsigned int y) : width(x), height(y), _data(nullptr) {} public: using PixelType = Pixel; static constexpr size_t NumberChannels = sizeof...(Channels); const unsigned int width; const unsigned int height; Image(unsigned int x, unsigned int y, const T* data) : Image(x, y) { size_t data_size = width*height*NumberChannels; _data = new T[data_size]; std::memcpy(_data, data, data_size*sizeof(T)); } Image(const Image&) = delete; Image& operator=(const Image&) = delete; Image& operator=(Image&&) = delete; Image(Image&& mv) : width(mv.width), height(mv.height), _data(mv._data) { mv._data = nullptr; } ~Image() { if (_data) { delete[] _data; } } const T* data() const { return _data; } Image&& copy() const { return Image(width, height, _data); } PixelReference at(unsigned int x, unsigned int y) { if (!(x= ("; note += std::to_string(width)+", "+std::to_string(height); note += ")"; THROW(ImageError( Codes::OUT_OF_BOUNDS, note )); } auto coord = y*height+x; return PixelReference( _data[coord*NumberChannels+Find::value-1]... ); } }; template class ImageReference; template class ImageReference> : public Image> { protected: using Base = Image>; using Base::_data; public: using Base::width; using Base::height; using Base::copy; ImageReference(unsigned int x, unsigned int y, T* data) : Base(x, y) { _data = data; } ~ImageReference() noexcept { Base::_data = nullptr; } }; } // namespace nb #endif // _NB_IMAGE