Refactor textures: add generic template, remove copypaste
This commit is contained in:
parent
daeba8674a
commit
db0f7915cf
3 changed files with 241 additions and 717 deletions
|
|
@ -422,7 +422,7 @@ struct grass_app
|
||||||
|
|
||||||
std::size_t slice_resolution = 256;
|
std::size_t slice_resolution = 256;
|
||||||
|
|
||||||
grass_slice_z_texture.load<gfx::color_rgba>(slice_resolution, slice_resolution, density_level_count);
|
grass_slice_z_texture.load<gfx::color_rgba>({slice_resolution, slice_resolution, density_level_count});
|
||||||
grass_slice_renderbuffer.storage(gl::DEPTH24_STENCIL8, slice_resolution, slice_resolution);
|
grass_slice_renderbuffer.storage(gl::DEPTH24_STENCIL8, slice_resolution, slice_resolution);
|
||||||
for (int d = 0; d < density_level_count; ++d)
|
for (int d = 0; d < density_level_count; ++d)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
#include <psemek/gfx/pixmap.hpp>
|
#include <psemek/gfx/pixmap.hpp>
|
||||||
#include <psemek/geom/vector.hpp>
|
#include <psemek/geom/vector.hpp>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
namespace psemek::gfx
|
namespace psemek::gfx
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -82,64 +84,52 @@ namespace psemek::gfx
|
||||||
static constexpr GLenum type = gl::FLOAT;
|
static constexpr GLenum type = gl::FLOAT;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct texture_1d
|
template <std::size_t D, GLenum Target>
|
||||||
|
struct basic_texture
|
||||||
{
|
{
|
||||||
texture_1d();
|
static_assert(D >= 1 && D <= 3);
|
||||||
texture_1d(texture_1d const &) = delete;
|
|
||||||
texture_1d(texture_1d &&);
|
|
||||||
|
|
||||||
texture_1d & operator = (texture_1d const &) = delete;
|
basic_texture();
|
||||||
texture_1d & operator = (texture_1d &&);
|
basic_texture(basic_texture &&);
|
||||||
|
basic_texture & operator = (basic_texture &&);
|
||||||
|
~basic_texture();
|
||||||
|
|
||||||
~texture_1d();
|
basic_texture(basic_texture const &) = delete;
|
||||||
|
basic_texture & operator = (basic_texture const &) = delete;
|
||||||
|
|
||||||
static texture_1d null();
|
static basic_texture null();
|
||||||
|
|
||||||
GLuint id() const { return id_; }
|
GLuint id() const { return id_; }
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
void bind() const;
|
void bind() const;
|
||||||
|
|
||||||
explicit operator bool () const { return id_ != 0; }
|
explicit operator bool() const { return id() != 0; }
|
||||||
|
|
||||||
int width() const { return width_; }
|
geom::vector<std::size_t, D> size() const { return size_; }
|
||||||
|
|
||||||
geom::vector<int, 1> size() const { return {width_}; }
|
std::size_t width() const;
|
||||||
|
std::size_t height() const;
|
||||||
|
std::size_t depth() const;
|
||||||
|
|
||||||
void load(GLint internal_format, std::size_t width, GLenum format, GLenum type, const void * data);
|
void load(GLint internal_format, geom::vector<std::size_t, D> const & size, GLenum format, GLenum type, const void * data);
|
||||||
|
|
||||||
template <typename Pixel>
|
template <typename Pixel>
|
||||||
void load(std::size_t width, Pixel const * data = nullptr)
|
void load(geom::vector<std::size_t, D> const & size, Pixel const * data = nullptr);
|
||||||
{
|
|
||||||
using traits = pixel_traits<Pixel>;
|
|
||||||
load(traits::internal_format, width, traits::format, traits::type, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Pixel>
|
template <typename Pixel>
|
||||||
void load(util::array<Pixel, 1> const & p)
|
void load(util::array<Pixel, D> const & p);
|
||||||
{
|
|
||||||
load(p.width(), p.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
void pixels(GLenum format, GLenum type, void * data) const;
|
void pixels(GLenum format, GLenum type, void * data) const;
|
||||||
|
|
||||||
template <typename Pixmap>
|
template <typename Pixmap>
|
||||||
Pixmap pixels() const
|
Pixmap pixels() const;
|
||||||
{
|
|
||||||
using traits = pixel_traits<typename Pixmap::pixel_type>;
|
|
||||||
Pixmap p({width_});
|
|
||||||
pixels(traits::format, traits::type, p.data());
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
static texture_1d from_data(GLint internal_format, std::size_t width, GLenum format, GLenum type, const void * data);
|
static basic_texture from_data(GLint internal_format, geom::vector<std::size_t, D> const & size, GLenum format, GLenum type, const void * data);
|
||||||
|
|
||||||
template <typename Pixmap>
|
template <typename Pixmap>
|
||||||
static texture_1d from_pixmap(Pixmap const & p)
|
static basic_texture from_pixmap(Pixmap const & p);
|
||||||
{
|
|
||||||
texture_1d t;
|
|
||||||
t.load(p);
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
void generate_mipmap();
|
void generate_mipmap();
|
||||||
void nearest_filter();
|
void nearest_filter();
|
||||||
|
|
@ -151,241 +141,236 @@ namespace psemek::gfx
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GLuint id_;
|
GLuint id_;
|
||||||
int width_ = 0;
|
geom::vector<std::size_t, D> size_;
|
||||||
|
|
||||||
texture_1d(GLuint id);
|
explicit basic_texture(std::nullptr_t);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct texture_2d
|
using texture_1d = basic_texture<1, gl::TEXTURE_1D>;
|
||||||
|
using texture_1d_array = basic_texture<2, gl::TEXTURE_1D_ARRAY>;
|
||||||
|
using texture_2d = basic_texture<2, gl::TEXTURE_2D>;
|
||||||
|
using texture_2d_array = basic_texture<3, gl::TEXTURE_2D_ARRAY>;
|
||||||
|
using texture_3d = basic_texture<3, gl::TEXTURE_3D>;
|
||||||
|
|
||||||
|
namespace detail
|
||||||
{
|
{
|
||||||
texture_2d();
|
std::optional<float> max_anisotropy();
|
||||||
texture_2d(texture_2d const &) = delete;
|
}
|
||||||
texture_2d(texture_2d &&);
|
|
||||||
|
|
||||||
texture_2d & operator = (texture_2d const &) = delete;
|
template <std::size_t D, GLenum Target>
|
||||||
texture_2d & operator = (texture_2d &&);
|
basic_texture<D, Target>::basic_texture()
|
||||||
|
{
|
||||||
|
gl::GenTextures(1, &id_);
|
||||||
|
}
|
||||||
|
|
||||||
~texture_2d();
|
template <std::size_t D, GLenum Target>
|
||||||
|
basic_texture<D, Target>::basic_texture(basic_texture && other)
|
||||||
|
: id_{other.id_}
|
||||||
|
{
|
||||||
|
other.id_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
static texture_2d null();
|
template <std::size_t D, GLenum Target>
|
||||||
|
basic_texture<D, Target> & basic_texture<D, Target>::operator = (basic_texture && other)
|
||||||
|
{
|
||||||
|
if (this == &other) return *this;
|
||||||
|
|
||||||
GLuint id() const { return id_; }
|
reset();
|
||||||
|
std::swap(id_, other.id_);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
void bind() const;
|
template <std::size_t D, GLenum Target>
|
||||||
|
basic_texture<D, Target>::~basic_texture()
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
explicit operator bool () const { return id_ != 0; }
|
template <std::size_t D, GLenum Target>
|
||||||
|
basic_texture<D, Target> basic_texture<D, Target>::null()
|
||||||
|
{
|
||||||
|
return basic_texture(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
int width() const { return width_; }
|
template <std::size_t D, GLenum Target>
|
||||||
int height() const { return height_; }
|
void basic_texture<D, Target>::reset()
|
||||||
|
{
|
||||||
|
if (id_ != 0)
|
||||||
|
gl::DeleteTextures(1, &id_);
|
||||||
|
id_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
geom::vector<int, 2> size() const { return {width_, height_}; }
|
template <std::size_t D, GLenum Target>
|
||||||
|
void basic_texture<D, Target>::bind() const
|
||||||
|
{
|
||||||
|
gl::BindTexture(Target, id());
|
||||||
|
}
|
||||||
|
|
||||||
void load(GLint internal_format, std::size_t width, std::size_t height, GLenum format, GLenum type, const void * data);
|
template <std::size_t D, GLenum Target>
|
||||||
|
std::size_t basic_texture<D, Target>::width() const
|
||||||
|
{
|
||||||
|
return size_[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::size_t D, GLenum Target>
|
||||||
|
std::size_t basic_texture<D, Target>::height() const
|
||||||
|
{
|
||||||
|
if constexpr (D >= 2)
|
||||||
|
{
|
||||||
|
return size_[1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::size_t D, GLenum Target>
|
||||||
|
std::size_t basic_texture<D, Target>::depth() const
|
||||||
|
{
|
||||||
|
if constexpr (D >= 3)
|
||||||
|
{
|
||||||
|
return size_[2];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::size_t D, GLenum Target>
|
||||||
|
void basic_texture<D, Target>::load(GLint internal_format, geom::vector<std::size_t, D> const & size, GLenum format, GLenum type, const void * data)
|
||||||
|
{
|
||||||
|
bind();
|
||||||
|
|
||||||
|
if constexpr (D == 1)
|
||||||
|
{
|
||||||
|
gl::TexImage1D(Target, 0, internal_format, size[0], 0, format, type, data);
|
||||||
|
}
|
||||||
|
else if (D == 2)
|
||||||
|
{
|
||||||
|
gl::TexImage2D(Target, 0, internal_format, size[0], size[1], 0, format, type, data);
|
||||||
|
}
|
||||||
|
else if (D == 3)
|
||||||
|
{
|
||||||
|
gl::TexImage3D(Target, 0, internal_format, size[0], size[1], size[2], 0, format, type, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_ = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::size_t D, GLenum Target>
|
||||||
template <typename Pixel>
|
template <typename Pixel>
|
||||||
void load(std::size_t width, std::size_t height, Pixel const * data = nullptr)
|
void basic_texture<D, Target>::load(geom::vector<std::size_t, D> const & size, Pixel const * data)
|
||||||
{
|
{
|
||||||
using traits = pixel_traits<Pixel>;
|
using traits = pixel_traits<Pixel>;
|
||||||
load(traits::internal_format, width, height, traits::format, traits::type, data);
|
load(traits::internal_format, size, traits::format, traits::type, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <std::size_t D, GLenum Target>
|
||||||
template <typename Pixel>
|
template <typename Pixel>
|
||||||
void load(basic_pixmap<Pixel> const & p)
|
void basic_texture<D, Target>::load(util::array<Pixel, D> const & p)
|
||||||
{
|
{
|
||||||
load(p.width(), p.height(), p.data());
|
geom::vector<std::size_t, D> size;
|
||||||
|
for (std::size_t i = 0; i < D; ++i) size[i] = p.dim(i);
|
||||||
|
load(size, p.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
void pixels(GLenum format, GLenum type, void * data) const;
|
template <std::size_t D, GLenum Target>
|
||||||
|
void basic_texture<D, Target>::pixels(GLenum format, GLenum type, void * data) const
|
||||||
|
{
|
||||||
|
bind();
|
||||||
|
gl::GetTexImage(Target, 0, format, type, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::size_t D, GLenum Target>
|
||||||
template <typename Pixmap>
|
template <typename Pixmap>
|
||||||
Pixmap pixels() const
|
Pixmap basic_texture<D, Target>::pixels() const
|
||||||
{
|
{
|
||||||
using traits = pixel_traits<typename Pixmap::pixel_type>;
|
using traits = pixel_traits<typename Pixmap::pixel_type>;
|
||||||
Pixmap p({width_, height_});
|
|
||||||
|
std::array<std::size_t, D> size;
|
||||||
|
for (std::size_t i = 0; i < D; ++i) size[i] = size_[i];
|
||||||
|
|
||||||
|
Pixmap p(size);
|
||||||
pixels(traits::format, traits::type, p.data());
|
pixels(traits::format, traits::type, p.data());
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
static texture_2d from_data(GLint internal_format, std::size_t width, std::size_t height, GLenum format, GLenum type, const void * data);
|
template <std::size_t D, GLenum Target>
|
||||||
|
basic_texture<D, Target> basic_texture<D, Target>::from_data(GLint internal_format, geom::vector<std::size_t, D> const & size, GLenum format, GLenum type, const void * data)
|
||||||
|
{
|
||||||
|
basic_texture result;
|
||||||
|
result.load(internal_format, size, format, type, data);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::size_t D, GLenum Target>
|
||||||
template <typename Pixmap>
|
template <typename Pixmap>
|
||||||
static texture_2d from_pixmap(Pixmap const & p)
|
basic_texture<D, Target> basic_texture<D, Target>::from_pixmap(Pixmap const & p)
|
||||||
{
|
{
|
||||||
texture_2d t;
|
basic_texture result;
|
||||||
t.load(p);
|
result.load(p);
|
||||||
return t;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_mipmap();
|
template <std::size_t D, GLenum Target>
|
||||||
void nearest_filter();
|
void basic_texture<D, Target>::generate_mipmap()
|
||||||
void linear_filter();
|
|
||||||
void anisotropy();
|
|
||||||
|
|
||||||
void repeat();
|
|
||||||
void clamp();
|
|
||||||
|
|
||||||
private:
|
|
||||||
GLuint id_;
|
|
||||||
int width_ = 0;
|
|
||||||
int height_ = 0;
|
|
||||||
|
|
||||||
texture_2d(GLuint id);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct texture_3d
|
|
||||||
{
|
{
|
||||||
texture_3d();
|
bind();
|
||||||
texture_3d(texture_3d const &) = delete;
|
gl::GenerateMipmap(Target);
|
||||||
texture_3d(texture_3d &&);
|
|
||||||
|
|
||||||
texture_3d & operator = (texture_3d const &) = delete;
|
|
||||||
texture_3d & operator = (texture_3d &&);
|
|
||||||
|
|
||||||
~texture_3d();
|
|
||||||
|
|
||||||
static texture_3d null();
|
|
||||||
|
|
||||||
GLuint id() const { return id_; }
|
|
||||||
|
|
||||||
void bind() const;
|
|
||||||
|
|
||||||
explicit operator bool () const { return id_ != 0; }
|
|
||||||
|
|
||||||
int width() const { return width_; }
|
|
||||||
int height() const { return height_; }
|
|
||||||
int depth() const { return depth_; }
|
|
||||||
|
|
||||||
geom::vector<int, 3> size() const { return {width_, height_, depth_}; }
|
|
||||||
|
|
||||||
void load(GLint internal_format, std::size_t width, std::size_t height, std::size_t depth, GLenum format, GLenum type, const void * data);
|
|
||||||
|
|
||||||
template <typename Pixel>
|
|
||||||
void load(std::size_t width, std::size_t height, std::size_t depth, Pixel const * data = nullptr)
|
|
||||||
{
|
|
||||||
using traits = pixel_traits<Pixel>;
|
|
||||||
load(traits::internal_format, width, height, depth, traits::format, traits::type, data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Pixel>
|
template <std::size_t D, GLenum Target>
|
||||||
void load(util::array<Pixel, 3> const & p)
|
void basic_texture<D, Target>::nearest_filter()
|
||||||
{
|
{
|
||||||
load(p.width(), p.height(), p.depth(), p.data());
|
bind();
|
||||||
|
gl::TexParameteri(Target, gl::TEXTURE_MIN_FILTER, gl::NEAREST);
|
||||||
|
gl::TexParameteri(Target, gl::TEXTURE_MAG_FILTER, gl::NEAREST);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pixels(GLenum format, GLenum type, void * data) const;
|
template <std::size_t D, GLenum Target>
|
||||||
|
void basic_texture<D, Target>::linear_filter()
|
||||||
template <typename Pixmap>
|
|
||||||
Pixmap pixels() const
|
|
||||||
{
|
{
|
||||||
using traits = pixel_traits<typename Pixmap::pixel_type>;
|
bind();
|
||||||
Pixmap p({width_, height_, depth_});
|
gl::TexParameteri(Target, gl::TEXTURE_MIN_FILTER, gl::LINEAR_MIPMAP_LINEAR);
|
||||||
pixels(traits::format, traits::type, p.data());
|
gl::TexParameteri(Target, gl::TEXTURE_MAG_FILTER, gl::LINEAR);
|
||||||
return p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static texture_3d from_data(GLint internal_format, std::size_t width, std::size_t height, std::size_t depth, GLenum format, GLenum type, const void * data);
|
template <std::size_t D, GLenum Target>
|
||||||
|
void basic_texture<D, Target>::anisotropy()
|
||||||
template <typename Pixmap>
|
|
||||||
static texture_3d from_pixmap(Pixmap const & p)
|
|
||||||
{
|
{
|
||||||
texture_3d t;
|
auto level = detail::max_anisotropy();
|
||||||
t.load(p);
|
if (level)
|
||||||
return t;
|
{
|
||||||
|
bind();
|
||||||
|
gl::TexParameterf(Target, gl::TEXTURE_MAX_ANISOTROPY_EXT, *level);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_mipmap();
|
template <std::size_t D, GLenum Target>
|
||||||
void nearest_filter();
|
void basic_texture<D, Target>::repeat()
|
||||||
void linear_filter();
|
|
||||||
void anisotropy();
|
|
||||||
|
|
||||||
void repeat();
|
|
||||||
void clamp();
|
|
||||||
|
|
||||||
private:
|
|
||||||
GLuint id_;
|
|
||||||
int width_ = 0;
|
|
||||||
int height_ = 0;
|
|
||||||
int depth_ = 0;
|
|
||||||
|
|
||||||
texture_3d(GLuint id);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct texture_2d_array
|
|
||||||
{
|
{
|
||||||
texture_2d_array();
|
bind();
|
||||||
texture_2d_array(texture_2d_array const &) = delete;
|
|
||||||
texture_2d_array(texture_2d_array &&);
|
|
||||||
|
|
||||||
texture_2d_array & operator = (texture_2d_array const &) = delete;
|
if constexpr (D >= 1) gl::TexParameteri(Target, gl::TEXTURE_WRAP_S, gl::REPEAT);
|
||||||
texture_2d_array & operator = (texture_2d_array &&);
|
if constexpr (D >= 2) gl::TexParameteri(Target, gl::TEXTURE_WRAP_T, gl::REPEAT);
|
||||||
|
if constexpr (D >= 3) gl::TexParameteri(Target, gl::TEXTURE_WRAP_R, gl::REPEAT);
|
||||||
~texture_2d_array();
|
|
||||||
|
|
||||||
static texture_2d_array null();
|
|
||||||
|
|
||||||
GLuint id() const { return id_; }
|
|
||||||
|
|
||||||
void bind() const;
|
|
||||||
|
|
||||||
explicit operator bool () const { return id_ != 0; }
|
|
||||||
|
|
||||||
int width() const { return width_; }
|
|
||||||
int height() const { return height_; }
|
|
||||||
int depth() const { return depth_; }
|
|
||||||
|
|
||||||
geom::vector<int, 3> size() const { return {width_, height_, depth_}; }
|
|
||||||
|
|
||||||
void load(GLint internal_format, std::size_t width, std::size_t height, std::size_t depth, GLenum format, GLenum type, const void * data);
|
|
||||||
|
|
||||||
template <typename Pixel>
|
|
||||||
void load(std::size_t width, std::size_t height, std::size_t depth, Pixel const * data = nullptr)
|
|
||||||
{
|
|
||||||
using traits = pixel_traits<Pixel>;
|
|
||||||
load(traits::internal_format, width, height, depth, traits::format, traits::type, data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Pixel>
|
template <std::size_t D, GLenum Target>
|
||||||
void load(util::array<Pixel, 3> const & p)
|
void basic_texture<D, Target>::clamp()
|
||||||
{
|
{
|
||||||
load(p.width(), p.height(), p.depth(), p.data());
|
bind();
|
||||||
|
|
||||||
|
if constexpr (D >= 1) gl::TexParameteri(Target, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE);
|
||||||
|
if constexpr (D >= 2) gl::TexParameteri(Target, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE);
|
||||||
|
if constexpr (D >= 3) gl::TexParameteri(Target, gl::TEXTURE_WRAP_R, gl::CLAMP_TO_EDGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pixels(GLenum format, GLenum type, void * data) const;
|
template <std::size_t D, GLenum Target>
|
||||||
|
basic_texture<D, Target>::basic_texture(std::nullptr_t)
|
||||||
template <typename Pixmap>
|
: id_{0}
|
||||||
Pixmap pixels() const
|
{}
|
||||||
{
|
|
||||||
using traits = pixel_traits<typename Pixmap::pixel_type>;
|
|
||||||
Pixmap p({width_, height_, depth_});
|
|
||||||
pixels(traits::format, traits::type, p.data());
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
static texture_2d_array from_data(GLint internal_format, std::size_t width, std::size_t height, std::size_t depth, GLenum format, GLenum type, const void * data);
|
|
||||||
|
|
||||||
template <typename Pixmap>
|
|
||||||
static texture_2d_array from_pixmap(Pixmap const & p)
|
|
||||||
{
|
|
||||||
texture_2d_array t;
|
|
||||||
t.load(p);
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
void generate_mipmap();
|
|
||||||
void nearest_filter();
|
|
||||||
void linear_filter();
|
|
||||||
void anisotropy();
|
|
||||||
|
|
||||||
void repeat();
|
|
||||||
void clamp();
|
|
||||||
|
|
||||||
private:
|
|
||||||
GLuint id_;
|
|
||||||
int width_ = 0;
|
|
||||||
int height_ = 0;
|
|
||||||
int depth_ = 0;
|
|
||||||
|
|
||||||
texture_2d_array(GLuint id);
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,484 +1,23 @@
|
||||||
#include <psemek/gfx/texture.hpp>
|
#include <psemek/gfx/texture.hpp>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
namespace psemek::gfx
|
namespace psemek::gfx::detail
|
||||||
{
|
{
|
||||||
|
|
||||||
static std::optional<float> max_anisotropy_level;
|
static std::optional<float> get_max_anisotropy()
|
||||||
|
|
||||||
texture_1d::texture_1d()
|
|
||||||
{
|
{
|
||||||
gl::GenTextures(1, &id_);
|
if (!gl::exts::var_EXT_texture_filter_anisotropic) return std::nullopt;
|
||||||
|
|
||||||
|
float level;
|
||||||
|
gl::GetFloatv(gl::MAX_TEXTURE_MAX_ANISOTROPY_EXT, &level);
|
||||||
|
return level;
|
||||||
}
|
}
|
||||||
|
|
||||||
texture_1d::texture_1d(GLuint id)
|
std::optional<float> max_anisotropy()
|
||||||
: id_(id)
|
|
||||||
{}
|
|
||||||
|
|
||||||
texture_1d texture_1d::null()
|
|
||||||
{
|
{
|
||||||
return texture_1d(0);
|
static std::optional<float> level = get_max_anisotropy();
|
||||||
}
|
|
||||||
|
|
||||||
void texture_1d::bind() const
|
return level;
|
||||||
{
|
|
||||||
gl::BindTexture(gl::TEXTURE_1D, id_);
|
|
||||||
}
|
|
||||||
|
|
||||||
texture_1d::texture_1d(texture_1d && other)
|
|
||||||
: id_(other.id_)
|
|
||||||
, width_(other.width_)
|
|
||||||
{
|
|
||||||
other.id_ = 0;
|
|
||||||
other.width_ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
texture_1d & texture_1d::operator = (texture_1d && other)
|
|
||||||
{
|
|
||||||
if (this == &other) return *this;
|
|
||||||
|
|
||||||
gl::DeleteTextures(1, &id_);
|
|
||||||
id_ = other.id_;
|
|
||||||
width_ = other.width_;
|
|
||||||
other.id_ = 0;
|
|
||||||
other.width_ = 0;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
texture_1d::~texture_1d()
|
|
||||||
{
|
|
||||||
gl::DeleteTextures(1, &id_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_1d::load(GLint internal_format, std::size_t width, GLenum format, GLenum type, const void * data)
|
|
||||||
{
|
|
||||||
bind();
|
|
||||||
gl::TexImage1D(gl::TEXTURE_1D, 0, internal_format, width, 0, format, type, data);
|
|
||||||
|
|
||||||
width_ = width;
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_1d::pixels(GLenum format, GLenum type, void * data) const
|
|
||||||
{
|
|
||||||
bind();
|
|
||||||
gl::GetTexImage(gl::TEXTURE_1D, 0, format, type, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
texture_1d texture_1d::from_data(GLint internal_format, std::size_t width, GLenum format, GLenum type, const void * data)
|
|
||||||
{
|
|
||||||
texture_1d tex;
|
|
||||||
tex.load(internal_format, width, format, type, data);
|
|
||||||
return tex;
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_1d::generate_mipmap()
|
|
||||||
{
|
|
||||||
bind();
|
|
||||||
gl::GenerateMipmap(gl::TEXTURE_1D);
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_1d::nearest_filter()
|
|
||||||
{
|
|
||||||
bind();
|
|
||||||
gl::TexParameteri(gl::TEXTURE_1D, gl::TEXTURE_MAG_FILTER, gl::NEAREST);
|
|
||||||
gl::TexParameteri(gl::TEXTURE_1D, gl::TEXTURE_MIN_FILTER, gl::LINEAR_MIPMAP_LINEAR);
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_1d::linear_filter()
|
|
||||||
{
|
|
||||||
bind();
|
|
||||||
gl::TexParameteri(gl::TEXTURE_1D, gl::TEXTURE_MAG_FILTER, gl::LINEAR);
|
|
||||||
gl::TexParameteri(gl::TEXTURE_1D, gl::TEXTURE_MIN_FILTER, gl::LINEAR_MIPMAP_LINEAR);
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_1d::anisotropy()
|
|
||||||
{
|
|
||||||
if (!gl::exts::var_EXT_texture_filter_anisotropic) return;
|
|
||||||
|
|
||||||
if (!max_anisotropy_level)
|
|
||||||
{
|
|
||||||
max_anisotropy_level = 0;
|
|
||||||
gl::GetFloatv(gl::MAX_TEXTURE_MAX_ANISOTROPY_EXT, &(*max_anisotropy_level));
|
|
||||||
}
|
|
||||||
gl::TexParameterf(gl::TEXTURE_1D, gl::TEXTURE_MAX_ANISOTROPY_EXT, *max_anisotropy_level);
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_1d::repeat()
|
|
||||||
{
|
|
||||||
bind();
|
|
||||||
gl::TexParameteri(gl::TEXTURE_1D, gl::TEXTURE_WRAP_S, gl::REPEAT);
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_1d::clamp()
|
|
||||||
{
|
|
||||||
bind();
|
|
||||||
gl::TexParameteri(gl::TEXTURE_1D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
texture_2d::texture_2d()
|
|
||||||
{
|
|
||||||
gl::GenTextures(1, &id_);
|
|
||||||
}
|
|
||||||
|
|
||||||
texture_2d::texture_2d(GLuint id)
|
|
||||||
: id_(id)
|
|
||||||
{}
|
|
||||||
|
|
||||||
texture_2d texture_2d::null()
|
|
||||||
{
|
|
||||||
return texture_2d(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_2d::bind() const
|
|
||||||
{
|
|
||||||
gl::BindTexture(gl::TEXTURE_2D, id_);
|
|
||||||
}
|
|
||||||
|
|
||||||
texture_2d::texture_2d(texture_2d && other)
|
|
||||||
: id_(other.id_)
|
|
||||||
, width_(other.width_)
|
|
||||||
, height_(other.height_)
|
|
||||||
{
|
|
||||||
other.id_ = 0;
|
|
||||||
other.width_ = 0;
|
|
||||||
other.height_ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
texture_2d & texture_2d::operator = (texture_2d && other)
|
|
||||||
{
|
|
||||||
if (this == &other) return *this;
|
|
||||||
|
|
||||||
gl::DeleteTextures(1, &id_);
|
|
||||||
id_ = other.id_;
|
|
||||||
width_ = other.width_;
|
|
||||||
height_ = other.height_;
|
|
||||||
other.id_ = 0;
|
|
||||||
other.width_ = 0;
|
|
||||||
other.height_ = 0;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
texture_2d::~texture_2d()
|
|
||||||
{
|
|
||||||
gl::DeleteTextures(1, &id_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_2d::load(GLint internal_format, std::size_t width, std::size_t height, GLenum format, GLenum type, const void * data)
|
|
||||||
{
|
|
||||||
bind();
|
|
||||||
gl::TexImage2D(gl::TEXTURE_2D, 0, internal_format, width, height, 0, format, type, data);
|
|
||||||
|
|
||||||
width_ = width;
|
|
||||||
height_ = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_2d::pixels(GLenum format, GLenum type, void * data) const
|
|
||||||
{
|
|
||||||
bind();
|
|
||||||
gl::GetTexImage(gl::TEXTURE_2D, 0, format, type, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
texture_2d texture_2d::from_data(GLint internal_format, std::size_t width, std::size_t height, GLenum format, GLenum type, const void * data)
|
|
||||||
{
|
|
||||||
texture_2d tex;
|
|
||||||
tex.load(internal_format, width, height, format, type, data);
|
|
||||||
return tex;
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_2d::generate_mipmap()
|
|
||||||
{
|
|
||||||
bind();
|
|
||||||
gl::GenerateMipmap(gl::TEXTURE_2D);
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_2d::nearest_filter()
|
|
||||||
{
|
|
||||||
bind();
|
|
||||||
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST);
|
|
||||||
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR_MIPMAP_LINEAR);
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_2d::linear_filter()
|
|
||||||
{
|
|
||||||
bind();
|
|
||||||
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR);
|
|
||||||
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR_MIPMAP_LINEAR);
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_2d::anisotropy()
|
|
||||||
{
|
|
||||||
if (!gl::exts::var_EXT_texture_filter_anisotropic) return;
|
|
||||||
|
|
||||||
if (!max_anisotropy_level)
|
|
||||||
{
|
|
||||||
max_anisotropy_level = 0;
|
|
||||||
gl::GetFloatv(gl::MAX_TEXTURE_MAX_ANISOTROPY_EXT, &(*max_anisotropy_level));
|
|
||||||
}
|
|
||||||
gl::TexParameterf(gl::TEXTURE_2D, gl::TEXTURE_MAX_ANISOTROPY_EXT, *max_anisotropy_level);
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_2d::repeat()
|
|
||||||
{
|
|
||||||
bind();
|
|
||||||
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::REPEAT);
|
|
||||||
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::REPEAT);
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_2d::clamp()
|
|
||||||
{
|
|
||||||
bind();
|
|
||||||
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE);
|
|
||||||
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
texture_3d::texture_3d()
|
|
||||||
{
|
|
||||||
gl::GenTextures(1, &id_);
|
|
||||||
}
|
|
||||||
|
|
||||||
texture_3d::texture_3d(GLuint id)
|
|
||||||
: id_(id)
|
|
||||||
{}
|
|
||||||
|
|
||||||
texture_3d texture_3d::null()
|
|
||||||
{
|
|
||||||
return texture_3d(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_3d::bind() const
|
|
||||||
{
|
|
||||||
gl::BindTexture(gl::TEXTURE_3D, id_);
|
|
||||||
}
|
|
||||||
|
|
||||||
texture_3d::texture_3d(texture_3d && other)
|
|
||||||
: id_(other.id_)
|
|
||||||
, width_(other.width_)
|
|
||||||
, height_(other.height_)
|
|
||||||
, depth_(other.depth_)
|
|
||||||
{
|
|
||||||
other.id_ = 0;
|
|
||||||
other.width_ = 0;
|
|
||||||
other.height_ = 0;
|
|
||||||
other.depth_ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
texture_3d & texture_3d::operator = (texture_3d && other)
|
|
||||||
{
|
|
||||||
if (this == &other) return *this;
|
|
||||||
|
|
||||||
gl::DeleteTextures(1, &id_);
|
|
||||||
id_ = other.id_;
|
|
||||||
width_ = other.width_;
|
|
||||||
height_ = other.height_;
|
|
||||||
depth_ = other.depth_;
|
|
||||||
other.id_ = 0;
|
|
||||||
other.width_ = 0;
|
|
||||||
other.height_ = 0;
|
|
||||||
other.depth_ = 0;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
texture_3d::~texture_3d()
|
|
||||||
{
|
|
||||||
gl::DeleteTextures(1, &id_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_3d::load(GLint internal_format, std::size_t width, std::size_t height, std::size_t depth, GLenum format, GLenum type, const void * data)
|
|
||||||
{
|
|
||||||
bind();
|
|
||||||
gl::TexImage3D(gl::TEXTURE_3D, 0, internal_format, width, height, depth, 0, format, type, data);
|
|
||||||
|
|
||||||
width_ = width;
|
|
||||||
height_ = height;
|
|
||||||
depth_ = depth;
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_3d::pixels(GLenum format, GLenum type, void * data) const
|
|
||||||
{
|
|
||||||
bind();
|
|
||||||
gl::GetTexImage(gl::TEXTURE_3D, 0, format, type, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
texture_3d texture_3d::from_data(GLint internal_format, std::size_t width, std::size_t height, std::size_t depth, GLenum format, GLenum type, const void * data)
|
|
||||||
{
|
|
||||||
texture_3d tex;
|
|
||||||
tex.load(internal_format, width, height, depth, format, type, data);
|
|
||||||
return tex;
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_3d::generate_mipmap()
|
|
||||||
{
|
|
||||||
bind();
|
|
||||||
gl::GenerateMipmap(gl::TEXTURE_3D);
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_3d::nearest_filter()
|
|
||||||
{
|
|
||||||
bind();
|
|
||||||
gl::TexParameteri(gl::TEXTURE_3D, gl::TEXTURE_MAG_FILTER, gl::NEAREST);
|
|
||||||
gl::TexParameteri(gl::TEXTURE_3D, gl::TEXTURE_MIN_FILTER, gl::LINEAR_MIPMAP_LINEAR);
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_3d::linear_filter()
|
|
||||||
{
|
|
||||||
bind();
|
|
||||||
gl::TexParameteri(gl::TEXTURE_3D, gl::TEXTURE_MAG_FILTER, gl::LINEAR);
|
|
||||||
gl::TexParameteri(gl::TEXTURE_3D, gl::TEXTURE_MIN_FILTER, gl::LINEAR_MIPMAP_LINEAR);
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_3d::anisotropy()
|
|
||||||
{
|
|
||||||
if (!gl::exts::var_EXT_texture_filter_anisotropic) return;
|
|
||||||
|
|
||||||
if (!max_anisotropy_level)
|
|
||||||
{
|
|
||||||
max_anisotropy_level = 0;
|
|
||||||
gl::GetFloatv(gl::MAX_TEXTURE_MAX_ANISOTROPY_EXT, &(*max_anisotropy_level));
|
|
||||||
}
|
|
||||||
gl::TexParameterf(gl::TEXTURE_3D, gl::TEXTURE_MAX_ANISOTROPY_EXT, *max_anisotropy_level);
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_3d::repeat()
|
|
||||||
{
|
|
||||||
bind();
|
|
||||||
gl::TexParameteri(gl::TEXTURE_3D, gl::TEXTURE_WRAP_S, gl::REPEAT);
|
|
||||||
gl::TexParameteri(gl::TEXTURE_3D, gl::TEXTURE_WRAP_T, gl::REPEAT);
|
|
||||||
gl::TexParameteri(gl::TEXTURE_3D, gl::TEXTURE_WRAP_R, gl::REPEAT);
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_3d::clamp()
|
|
||||||
{
|
|
||||||
bind();
|
|
||||||
gl::TexParameteri(gl::TEXTURE_3D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE);
|
|
||||||
gl::TexParameteri(gl::TEXTURE_3D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE);
|
|
||||||
gl::TexParameteri(gl::TEXTURE_3D, gl::TEXTURE_WRAP_R, gl::CLAMP_TO_EDGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
texture_2d_array::texture_2d_array()
|
|
||||||
{
|
|
||||||
gl::GenTextures(1, &id_);
|
|
||||||
}
|
|
||||||
|
|
||||||
texture_2d_array::texture_2d_array(GLuint id)
|
|
||||||
: id_(id)
|
|
||||||
{}
|
|
||||||
|
|
||||||
texture_2d_array texture_2d_array::null()
|
|
||||||
{
|
|
||||||
return texture_2d_array(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_2d_array::bind() const
|
|
||||||
{
|
|
||||||
gl::BindTexture(gl::TEXTURE_2D_ARRAY, id_);
|
|
||||||
}
|
|
||||||
|
|
||||||
texture_2d_array::texture_2d_array(texture_2d_array && other)
|
|
||||||
: id_(other.id_)
|
|
||||||
, width_(other.width_)
|
|
||||||
, height_(other.height_)
|
|
||||||
, depth_(other.depth_)
|
|
||||||
{
|
|
||||||
other.id_ = 0;
|
|
||||||
other.width_ = 0;
|
|
||||||
other.height_ = 0;
|
|
||||||
other.depth_ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
texture_2d_array & texture_2d_array::operator = (texture_2d_array && other)
|
|
||||||
{
|
|
||||||
if (this == &other) return *this;
|
|
||||||
|
|
||||||
gl::DeleteTextures(1, &id_);
|
|
||||||
id_ = other.id_;
|
|
||||||
width_ = other.width_;
|
|
||||||
height_ = other.height_;
|
|
||||||
depth_ = other.depth_;
|
|
||||||
other.id_ = 0;
|
|
||||||
other.width_ = 0;
|
|
||||||
other.height_ = 0;
|
|
||||||
other.depth_ = 0;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
texture_2d_array::~texture_2d_array()
|
|
||||||
{
|
|
||||||
gl::DeleteTextures(1, &id_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_2d_array::load(GLint internal_format, std::size_t width, std::size_t height, std::size_t depth, GLenum format, GLenum type, const void * data)
|
|
||||||
{
|
|
||||||
bind();
|
|
||||||
gl::TexImage3D(gl::TEXTURE_2D_ARRAY, 0, internal_format, width, height, depth, 0, format, type, data);
|
|
||||||
|
|
||||||
width_ = width;
|
|
||||||
height_ = height;
|
|
||||||
depth_ = depth;
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_2d_array::pixels(GLenum format, GLenum type, void * data) const
|
|
||||||
{
|
|
||||||
bind();
|
|
||||||
gl::GetTexImage(gl::TEXTURE_2D_ARRAY, 0, format, type, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
texture_2d_array texture_2d_array::from_data(GLint internal_format, std::size_t width, std::size_t height, std::size_t depth, GLenum format, GLenum type, const void * data)
|
|
||||||
{
|
|
||||||
texture_2d_array tex;
|
|
||||||
tex.load(internal_format, width, height, depth, format, type, data);
|
|
||||||
return tex;
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_2d_array::generate_mipmap()
|
|
||||||
{
|
|
||||||
bind();
|
|
||||||
gl::GenerateMipmap(gl::TEXTURE_2D_ARRAY);
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_2d_array::nearest_filter()
|
|
||||||
{
|
|
||||||
bind();
|
|
||||||
gl::TexParameteri(gl::TEXTURE_2D_ARRAY, gl::TEXTURE_MAG_FILTER, gl::NEAREST);
|
|
||||||
gl::TexParameteri(gl::TEXTURE_2D_ARRAY, gl::TEXTURE_MIN_FILTER, gl::LINEAR_MIPMAP_LINEAR);
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_2d_array::linear_filter()
|
|
||||||
{
|
|
||||||
bind();
|
|
||||||
gl::TexParameteri(gl::TEXTURE_2D_ARRAY, gl::TEXTURE_MAG_FILTER, gl::LINEAR);
|
|
||||||
gl::TexParameteri(gl::TEXTURE_2D_ARRAY, gl::TEXTURE_MIN_FILTER, gl::LINEAR_MIPMAP_LINEAR);
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_2d_array::anisotropy()
|
|
||||||
{
|
|
||||||
if (!gl::exts::var_EXT_texture_filter_anisotropic) return;
|
|
||||||
|
|
||||||
if (!max_anisotropy_level)
|
|
||||||
{
|
|
||||||
max_anisotropy_level = 0;
|
|
||||||
gl::GetFloatv(gl::MAX_TEXTURE_MAX_ANISOTROPY_EXT, &(*max_anisotropy_level));
|
|
||||||
}
|
|
||||||
gl::TexParameterf(gl::TEXTURE_2D_ARRAY, gl::TEXTURE_MAX_ANISOTROPY_EXT, *max_anisotropy_level);
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_2d_array::repeat()
|
|
||||||
{
|
|
||||||
bind();
|
|
||||||
gl::TexParameteri(gl::TEXTURE_2D_ARRAY, gl::TEXTURE_WRAP_S, gl::REPEAT);
|
|
||||||
gl::TexParameteri(gl::TEXTURE_2D_ARRAY, gl::TEXTURE_WRAP_T, gl::REPEAT);
|
|
||||||
gl::TexParameteri(gl::TEXTURE_2D_ARRAY, gl::TEXTURE_WRAP_R, gl::REPEAT);
|
|
||||||
}
|
|
||||||
|
|
||||||
void texture_2d_array::clamp()
|
|
||||||
{
|
|
||||||
bind();
|
|
||||||
gl::TexParameteri(gl::TEXTURE_2D_ARRAY, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE);
|
|
||||||
gl::TexParameteri(gl::TEXTURE_2D_ARRAY, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE);
|
|
||||||
gl::TexParameteri(gl::TEXTURE_2D_ARRAY, gl::TEXTURE_WRAP_R, gl::CLAMP_TO_EDGE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue