230 lines
5.8 KiB
C++
230 lines
5.8 KiB
C++
#pragma once
|
|
#ifndef _NB_TEXTURES
|
|
#define _NB_TEXTURES
|
|
|
|
#include <NBGraphics/Buffers.hpp>
|
|
#include <NBGraphics/Image.hpp>
|
|
#include <NBGraphics/OGLObjects.hpp>
|
|
|
|
/*! @file Textures.hpp */
|
|
|
|
namespace nb {
|
|
|
|
class TextureBuffer : public virtual Buffer {
|
|
public:
|
|
TextureBuffer() : Buffer(GL_TEXTURE_BUFFER) {}
|
|
|
|
};
|
|
|
|
/*!
|
|
@brief An OpenGL object that may be rendered to within a Framebuffer.
|
|
*/
|
|
class RenderTarget : public OpenGLObject {
|
|
protected:
|
|
using Base = OpenGLObject;
|
|
using Base::_id;
|
|
RenderTarget(GLenum target) : Target(target) {}
|
|
RenderTarget(RenderTarget&& rhs)
|
|
: Target(rhs.Target), Base(std::move(rhs)) {}
|
|
|
|
public:
|
|
using Base::id;
|
|
const GLenum Target;
|
|
};
|
|
|
|
/*!
|
|
@brief An OpenGL Target object
|
|
*/
|
|
class Texture : public RenderTarget {
|
|
protected:
|
|
using Base = RenderTarget;
|
|
using Base::_id;
|
|
Texture(GLenum);
|
|
virtual GLuint declare() override {
|
|
if (!_id) {
|
|
OPENGL_CALL(glGenTextures(1, &_id));
|
|
}
|
|
bind();
|
|
return _id;
|
|
}
|
|
virtual void remove() override {
|
|
if (_id) {
|
|
bind();
|
|
OPENGL_CALL(glDeleteTextures(0, &_id));
|
|
}
|
|
}
|
|
|
|
public:
|
|
using Base::id;
|
|
using Base::Target;
|
|
|
|
virtual void bind() const override {
|
|
if (_id) {
|
|
OPENGL_CALL(glBindTexture(Target, _id));
|
|
} else {
|
|
THROW(OpenGLObjectError(
|
|
OpenGLObjectError::Codes::INVALID_OBJECT,
|
|
"w/ Texture"
|
|
));
|
|
}
|
|
}
|
|
virtual void unbind() const override {
|
|
OPENGL_CALL(glBindTexture(Target, 0));
|
|
}
|
|
|
|
template <typename T>
|
|
void parameter(GLenum param_, const T& val_);
|
|
void parameter(GLenum param_, const float& val_) {
|
|
declare();
|
|
OPENGL_CALL(
|
|
glTexParameterf(Target, param_, val_)
|
|
);
|
|
}
|
|
void parameter(GLenum param_, const int& val_) {
|
|
declare();
|
|
OPENGL_CALL(
|
|
glTexParameteri(Target, param_, val_)
|
|
);
|
|
}
|
|
void parameter(GLenum param_, const std::vector<float>& val_) {
|
|
declare();
|
|
OPENGL_CALL(
|
|
glTexParameterfv(Target, param_, val_.data())
|
|
);
|
|
}
|
|
void parameter(GLenum param_, const std::vector<int>& val_) {
|
|
declare();
|
|
OPENGL_CALL(
|
|
glTexParameteriv(Target, param_, val_.data())
|
|
);
|
|
}
|
|
void parameter(GLenum param_, const std::vector<unsigned int>& val_) {
|
|
declare();
|
|
OPENGL_CALL(
|
|
glTexParameterIuiv(Target, param_, val_.data())
|
|
);
|
|
}
|
|
void generateMipmaps() const {
|
|
bind();
|
|
OPENGL_CALL(
|
|
glGenerateMipmap(Target)
|
|
);
|
|
}
|
|
|
|
};
|
|
|
|
template<typename T>
|
|
struct OGLPixelFormat;
|
|
|
|
template<typename T, typename... Channels>
|
|
struct OGLPixelFormat<Pixel<T, Channels...>>;
|
|
|
|
template<>
|
|
struct OGLPixelFormat<Pixel<uint8_t, Red, Green, Blue>> {
|
|
static constexpr GLenum glBase = GL_RGB;
|
|
static constexpr GLenum glFormat = GL_RGB8UI;
|
|
static constexpr GLenum glData = GL_UNSIGNED_BYTE;
|
|
};
|
|
|
|
template<>
|
|
struct OGLPixelFormat<Pixel<uint8_t, Red, Green, Blue, Alpha>> {
|
|
static constexpr GLenum glBase = GL_RGBA;
|
|
static constexpr GLenum glFormat = GL_RGBA8UI;
|
|
static constexpr GLenum glData = GL_UNSIGNED_BYTE;
|
|
};
|
|
|
|
template<>
|
|
struct OGLPixelFormat<Pixel<float, Red, Green>> {
|
|
static constexpr GLenum glBase = GL_RG;
|
|
static constexpr GLenum glFormat = GL_RG32F;
|
|
static constexpr GLenum glData = GL_FLOAT;
|
|
};
|
|
|
|
template<typename T>
|
|
class Texture2D;
|
|
|
|
template<typename T, typename... Channels>
|
|
class Texture2D<Pixel<T, Channels...>> : public Texture {
|
|
protected:
|
|
using Texture::Texture;
|
|
using PixelType = Pixel<T, Channels...>;
|
|
|
|
public:
|
|
using Texture::generateMipmaps;
|
|
Texture2D() : Texture(GL_TEXTURE_2D) {}
|
|
Texture2D(Texture2D&& cpy) {
|
|
*this = std::move(cpy);
|
|
}
|
|
Texture2D& operator=(Texture2D&& rhs) {
|
|
return Texture::operator=(std::move(rhs));
|
|
}
|
|
void setLayer(const Image<PixelType>& img, unsigned int layer) {
|
|
using Format = OGLPixelFormat<PixelType>;
|
|
declare();
|
|
auto data = img.data();
|
|
OPENGL_CALL(glTexImage2D(
|
|
Target,
|
|
layer,
|
|
Format::glFormat,
|
|
img.width,
|
|
img.height,
|
|
0,
|
|
Format::glBase,
|
|
Format::glData,
|
|
data ? data : nullptr
|
|
));
|
|
}
|
|
void setTexture(const Image<PixelType>& img, bool generateMipmap=true) {
|
|
setLayer(img, 0);
|
|
if (generateMipmap) { generateMipmaps(); }
|
|
}
|
|
|
|
};
|
|
|
|
template<typename T>
|
|
class Texture1D;
|
|
|
|
template<typename T, typename... Channels>
|
|
class Texture1D<Pixel<T, Channels...>> : public Texture {
|
|
protected:
|
|
using Texture::Texture;
|
|
using PixelType = Pixel<T, Channels...>;
|
|
|
|
public:
|
|
using Texture::generateMipmaps;
|
|
Texture1D() : Texture(GL_TEXTURE_1D) {}
|
|
Texture1D(Texture1D&& cpy) {
|
|
*this = std::move(cpy);
|
|
}
|
|
Texture1D& operator=(Texture1D&& rhs) {
|
|
return Texture::operator=(std::move(rhs));
|
|
}
|
|
void setLayer(const Image<PixelType>& tex, unsigned int layer) {
|
|
if (tex.height != 1) {
|
|
THROW(Error<>(
|
|
Error<>::VALUE_ERROR,
|
|
"Image must be of height 1"
|
|
));
|
|
}
|
|
using Format = OGLPixelFormat<PixelType>;
|
|
declare();
|
|
auto data = tex.data();
|
|
OPENGL_CALL(glTexImage1D(
|
|
Target,
|
|
layer,
|
|
Format::glFormat,
|
|
tex.width,
|
|
0,
|
|
Format::glBase,
|
|
Format::glData,
|
|
data ? data : nullptr
|
|
));
|
|
}
|
|
void setTexture(const Image<PixelType>& tex, bool generateMipmap=true) {
|
|
setLayer(tex, 0);
|
|
if (generateMipmap) { generateMipmaps(); }
|
|
}
|
|
};
|
|
|
|
} // namespace nb
|
|
#endif // _NB_TEXTURES
|