694871da |
#include <gltexture.hpp>
#include <algorithm>
#include <ostream>
#include <utility>
#include <globject.hpp>
// NOLINTNEXTLINE
#define STR_EXCEPTION GLObject<>::Exception
#include <str.hpp>
/// Special member functions
GLTexture::GLTexture(
// NOLINTNEXTLINE
std::string object_label,
GLenum target,
GLenum binding,
GLenum internal_format,
GLenum wrap,
GLenum min_filter,
GLenum mag_filter
)
:
GLObject(STR_JOIN(" ", it, it, {
str_target_(target),
str_internal_format_(internal_format),
std::move(object_label)
})),
target_ {target},
binding_ {binding},
min_filter_{min_filter},
unit_ {0}
{
// check_internal_format_(internal_format);
unit(true);
if (wrap)
{
glTexParameteri(target_, GL_TEXTURE_WRAP_S, (GLint)wrap);
glTexParameteri(target_, GL_TEXTURE_WRAP_T, (GLint)wrap);
glTexParameteri(target_, GL_TEXTURE_WRAP_R, (GLint)wrap);
}
if (min_filter)
glTexParameteri(target_, GL_TEXTURE_MIN_FILTER, (GLint)min_filter);
if (mag_filter)
glTexParameteri(target_, GL_TEXTURE_MAG_FILTER, (GLint)mag_filter);
if (min_filter_mipmap_())
if (!supported({3, 0}, "GL_ARB_framebuffer_object"))
glTexParameteri(target_, GL_GENERATE_MIPMAP, GL_TRUE);
if (target_ == GL_TEXTURE_2D)
// NOLINTNEXTLINE
if (supported({4, 6}, "GL_ARB_texture_filter_anisotropic"))
// TODO(rcrnstn): Remove the `_EXT` suffix when the headers are
// updated.
glTexParameterf(target_, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy_);
}
/// Core
GLOBJECT_THREAD(GLTexture::anisotropy_, {1.0F})
GLint GLTexture::unit(bool force_active) const
try
{
auto static const unit_count = (GLuint)integer(
GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
);
auto static units = std::vector<GLuint>(unit_count);
auto static textures = std::vector<GLuint>(unit_count);
auto static targets = std::vector<GLenum>(unit_count);
auto static unit_next = GLuint{1};
auto static unit_active = GLuint{0};
if (!unit_ || textures[unit_] != object())
{
if (unit_next < unit_count)
units.back() = unit_ = unit_next++;
else
unit_ = units.back();
std::rotate(units.begin(), units.end() - 1, units.end());
}
if (force_active || unit_active != unit_)
{
glActiveTexture(GL_TEXTURE0 + unit_);
unit_active = unit_;
}
if (textures[unit_] != object())
{
GLOBJECT_DEBUG_IF(1)
check_unit_active_();
GLOBJECT_DEBUG_IF(1)
{
glBindTexture(targets[unit_], 0);
targets[unit_] = target_;
}
glBindTexture(target_, object());
textures[unit_] = object();
}
GLOBJECT_DEBUG_IF(1)
check_unit_texture_();
return (GLint)unit_;
}
catch (...)
{
fail_action_("allocate texture unit for");
}
bool GLTexture::min_filter_mipmap_() const
{
switch (min_filter_)
{
case GL_NEAREST_MIPMAP_NEAREST:
case GL_NEAREST_MIPMAP_LINEAR:
case GL_LINEAR_MIPMAP_NEAREST:
case GL_LINEAR_MIPMAP_LINEAR:
return true;
default:
return false;
}
}
/// Path
GLOBJECT_THREAD(GLTexture::prefix_, {"assets/textures"})
/// Check
void GLTexture::check_unit_active_() const
{
auto unit_active = (GLuint)integer(GL_ACTIVE_TEXTURE) - GL_TEXTURE0;
if (unit_active != unit_)
STR_THROW(
"Expected active unit " << unit_ << ", " <<
"got " << unit_active << "."
);
}
void GLTexture::check_unit_texture_() const
{
auto unit_texture = (GLuint)integer(binding_);
if (unit_texture != object())
STR_THROW(
"Expected unit " << unit_ << " " <<
"to be bound to " << debug_name() << ", " <<
"got " << unit_texture << "."
);
}
void GLTexture::check_data_size_(std::size_t data_size) const
{
if (data_size != data_size_())
STR_THROW(
"Expected data size " << data_size_() << ", " <<
"got " << data_size << "."
);
}
/// String
std::string GLTexture::str_target_(GLenum target)
{
switch (target)
{
STR_CASE(GL_TEXTURE_1D)
STR_CASE(GL_TEXTURE_2D)
STR_CASE(GL_TEXTURE_3D)
STR_CASE(GL_TEXTURE_1D_ARRAY)
STR_CASE(GL_TEXTURE_2D_ARRAY)
STR_CASE(GL_TEXTURE_RECTANGLE)
STR_CASE(GL_TEXTURE_CUBE_MAP)
STR_CASE(GL_TEXTURE_CUBE_MAP_ARRAY)
STR_CASE(GL_TEXTURE_BUFFER)
STR_CASE(GL_TEXTURE_2D_MULTISAMPLE)
STR_CASE(GL_TEXTURE_2D_MULTISAMPLE_ARRAY)
default:
return str_enum_(target);
}
}
|