216 lines
5.0 KiB
C++
216 lines
5.0 KiB
C++
#pragma once
|
|
#ifndef _NB_IMAGE
|
|
#define _NB_IMAGE
|
|
|
|
#include <cstring>
|
|
|
|
#include <NBCore/Errors.hpp>
|
|
|
|
namespace nb {
|
|
|
|
template<typename T>
|
|
struct Color {};
|
|
|
|
struct Red : Color<Red> {};
|
|
struct Green : Color<Green> {};
|
|
struct Blue : Color<Blue> {};
|
|
struct Alpha : Color<Alpha> {};
|
|
|
|
struct Depth;
|
|
struct Stencil;
|
|
|
|
template<typename... T>
|
|
struct PixelChannel;
|
|
|
|
template<typename T>
|
|
struct PixelChannel<T, Red> {
|
|
using type=T;
|
|
T value;
|
|
T& r=value;
|
|
};
|
|
template<typename T>
|
|
struct PixelChannel<T, Green> {
|
|
using type=T;
|
|
T value;
|
|
T& g=value;
|
|
};
|
|
template<typename T>
|
|
struct PixelChannel<T, Blue> {
|
|
using type=T;
|
|
T value;
|
|
T& b=value;
|
|
};
|
|
template<typename T>
|
|
struct PixelChannel<T, Alpha> {
|
|
using type=T;
|
|
T value;
|
|
T& a=value;
|
|
};
|
|
|
|
template<typename T>
|
|
struct PixelChannel<T, Depth> {
|
|
using type=T;
|
|
T value;
|
|
T& z=value;
|
|
};
|
|
|
|
template<>
|
|
struct PixelChannel<uint8_t, Stencil> {
|
|
using type=uint8_t;
|
|
uint8_t value;
|
|
uint8_t& u=value;
|
|
};
|
|
|
|
template<typename T, typename... Channels>
|
|
struct Pixel : public PixelChannel<T, Channels>... {
|
|
Pixel() = default;
|
|
Pixel& operator=(const Pixel& rhs) {
|
|
((
|
|
[&](const typename PixelChannel<T, Channels>::type& val){
|
|
this->PixelChannel<T, Channels>::value = val;
|
|
}(rhs.PixelChannel<T, Channels>::value)
|
|
), ...);
|
|
return *this;
|
|
}
|
|
|
|
|
|
Pixel(const Pixel& cpy)
|
|
: Pixel(cpy.PixelChannel<T, Channels>::value...) {}
|
|
|
|
Pixel(typename PixelChannel<T, Channels>::type... vals)
|
|
: PixelChannel<T, Channels>{vals}... {}
|
|
};
|
|
|
|
template<typename Ref>
|
|
struct PixelReference;
|
|
|
|
template<typename T, typename... Channels>
|
|
struct PixelReference<Pixel<T, Channels...>>
|
|
: public Pixel<T&, Channels...> {
|
|
using PixelType = Pixel<T, Channels...>;
|
|
using Base = Pixel<T&, Channels...>;
|
|
using Base::Base;
|
|
|
|
PixelReference(PixelType& pixel)
|
|
: Base(pixel.PixelChannel<T, Channels>::value...) {}
|
|
|
|
operator PixelType() {
|
|
return PixelType(this->PixelChannel<T&, Channels>::value...);
|
|
}
|
|
|
|
PixelReference& operator=(const PixelType& pixel) {
|
|
((
|
|
[&](const typename PixelChannel<T, Channels>::type& val){
|
|
this->PixelChannel<T&, Channels>::value = val;
|
|
}(pixel.PixelChannel<T, Channels>::value)
|
|
), ...);
|
|
return *this;
|
|
}
|
|
|
|
};
|
|
|
|
template <typename T>
|
|
using RGBA = Pixel<T, Red, Green, Blue, Alpha>;
|
|
|
|
template <typename T>
|
|
using RGB = Pixel<T, Red, Green, Blue>;
|
|
|
|
class ImageError : public Error<ImageError> {
|
|
protected:
|
|
using Base = Error<ImageError>;
|
|
using Base::Base;
|
|
|
|
public:
|
|
enum Codes : unsigned int {
|
|
UNDEFINED, OUT_OF_BOUNDS
|
|
};
|
|
static const std::string type;
|
|
static const ErrorCodeMap ErrorMessages;
|
|
|
|
};
|
|
|
|
template<typename T>
|
|
class Image;
|
|
|
|
template<typename T, typename... Channels>
|
|
class Image<Pixel<T, Channels...>> {
|
|
protected:
|
|
using Codes = ImageError::Codes;
|
|
T* _data;
|
|
Image(unsigned int x, unsigned int y)
|
|
: width(x), height(y), _data(nullptr) {}
|
|
|
|
public:
|
|
using PixelType = Pixel<T, Channels...>;
|
|
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<PixelType> at(unsigned int x, unsigned int y) {
|
|
if (!(x<width) || !(y<height)) {
|
|
std::string note = "w/ ("+std::to_string(x);
|
|
note += ", "+std::to_string(y) + ") >= (";
|
|
note += std::to_string(width)+", "+std::to_string(height);
|
|
note += ")";
|
|
THROW(ImageError(
|
|
Codes::OUT_OF_BOUNDS,
|
|
note
|
|
));
|
|
}
|
|
auto coord = y*height+x;
|
|
return PixelReference<PixelType>(
|
|
_data[coord*NumberChannels+Find<Channels, Channels...>::value-1]...
|
|
);
|
|
}
|
|
|
|
};
|
|
|
|
template<typename... T>
|
|
class ImageReference;
|
|
|
|
template<typename T, typename... Channels>
|
|
class ImageReference<Pixel<T, Channels...>> : public Image<Pixel<T, Channels...>> {
|
|
protected:
|
|
using Base = Image<Pixel<T, Channels...>>;
|
|
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
|