Files
NBEngine/engine/NBGraphics/include/NBGraphics/Textures.hpp
T
2026-08-20 08:14:29 -05:00

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