|
|
@ -20,6 +20,8 @@ |
|
|
|
#include <engine/gl/texture.hpp>
|
|
|
|
#include <engine/gl/texture-1d.hpp>
|
|
|
|
#include <engine/gl/texture-2d.hpp>
|
|
|
|
#include <engine/gl/texture-3d.hpp>
|
|
|
|
#include <engine/gl/texture-cube.hpp>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <engine/gl/color-space.hpp>
|
|
|
|
#include <engine/gl/pixel-format.hpp>
|
|
|
@ -123,145 +125,161 @@ static constexpr GLenum mag_filter_lut[] = |
|
|
|
GL_LINEAR |
|
|
|
}; |
|
|
|
|
|
|
|
texture::texture(std::uint16_t width, std::uint16_t height, std::uint16_t depth, gl::pixel_type type, gl::pixel_format format, gl::color_space color_space, const std::byte* data): |
|
|
|
gl_texture_target((depth) ? GL_TEXTURE_3D : (height) ? GL_TEXTURE_2D : GL_TEXTURE_1D), |
|
|
|
gl_texture_id(0), |
|
|
|
dimensions({0, 0, 0}), |
|
|
|
wrapping({texture_wrapping::repeat, texture_wrapping::repeat, texture_wrapping::repeat}), |
|
|
|
filters({texture_min_filter::linear_mipmap_linear, texture_mag_filter::linear}), |
|
|
|
max_anisotropy(0.0f) |
|
|
|
texture::texture(std::uint16_t width, std::uint16_t height, std::uint16_t depth, bool cube, gl::pixel_type type, gl::pixel_format format, gl::color_space color_space, const std::byte* data) |
|
|
|
{ |
|
|
|
glGenTextures(1, &gl_texture_id); |
|
|
|
m_gl_texture_target = static_cast<unsigned int>(cube ? GL_TEXTURE_CUBE_MAP : (depth) ? GL_TEXTURE_3D : (height) ? GL_TEXTURE_2D : GL_TEXTURE_1D); |
|
|
|
|
|
|
|
glGenTextures(1, &m_gl_texture_id); |
|
|
|
resize(width, height, depth, type, format, color_space, data); |
|
|
|
set_wrapping(wrapping[0], wrapping[1], wrapping[2]); |
|
|
|
set_filters(std::get<0>(filters), std::get<1>(filters)); |
|
|
|
set_max_anisotropy(max_anisotropy); |
|
|
|
set_wrapping(m_wrapping[0], m_wrapping[1], m_wrapping[2]); |
|
|
|
set_filters(std::get<0>(m_filters), std::get<1>(m_filters)); |
|
|
|
set_max_anisotropy(m_max_anisotropy); |
|
|
|
} |
|
|
|
|
|
|
|
texture::texture(std::uint16_t width, std::uint16_t height, gl::pixel_type type, gl::pixel_format format, gl::color_space color_space, const std::byte* data): |
|
|
|
texture(width, height, 0, type, format, color_space, data) |
|
|
|
texture::texture(std::uint16_t width, std::uint16_t height, bool cube, gl::pixel_type type, gl::pixel_format format, gl::color_space color_space, const std::byte* data): |
|
|
|
texture(width, height, 0, cube, type, format, color_space, data) |
|
|
|
{} |
|
|
|
|
|
|
|
texture::texture(std::uint16_t width, gl::pixel_type type, gl::pixel_format format, gl::color_space color_space, const std::byte* data): |
|
|
|
texture(width, 0, 0, type, format, color_space, data) |
|
|
|
texture::texture(std::uint16_t width, bool cube, gl::pixel_type type, gl::pixel_format format, gl::color_space color_space, const std::byte* data): |
|
|
|
texture(width, 0, 0, cube, type, format, color_space, data) |
|
|
|
{} |
|
|
|
|
|
|
|
texture::~texture() |
|
|
|
{ |
|
|
|
glDeleteTextures(1, &gl_texture_id); |
|
|
|
glDeleteTextures(1, &m_gl_texture_id); |
|
|
|
} |
|
|
|
|
|
|
|
void texture::set_filters(texture_min_filter min_filter, texture_mag_filter mag_filter) |
|
|
|
{ |
|
|
|
filters = {min_filter, mag_filter}; |
|
|
|
m_filters = {min_filter, mag_filter}; |
|
|
|
|
|
|
|
GLenum gl_min_filter = min_filter_lut[static_cast<std::size_t>(min_filter)]; |
|
|
|
GLenum gl_mag_filter = mag_filter_lut[static_cast<std::size_t>(mag_filter)]; |
|
|
|
GLenum gl_min_filter = min_filter_lut[std::to_underlying(min_filter)]; |
|
|
|
GLenum gl_mag_filter = mag_filter_lut[std::to_underlying(mag_filter)]; |
|
|
|
|
|
|
|
glBindTexture(gl_texture_target, gl_texture_id); |
|
|
|
glTexParameteri(gl_texture_target, GL_TEXTURE_MIN_FILTER, gl_min_filter); |
|
|
|
glTexParameteri(gl_texture_target, GL_TEXTURE_MAG_FILTER, gl_mag_filter); |
|
|
|
glBindTexture(m_gl_texture_target, m_gl_texture_id); |
|
|
|
glTexParameteri(m_gl_texture_target, GL_TEXTURE_MIN_FILTER, gl_min_filter); |
|
|
|
glTexParameteri(m_gl_texture_target, GL_TEXTURE_MAG_FILTER, gl_mag_filter); |
|
|
|
} |
|
|
|
|
|
|
|
void texture::set_max_anisotropy(float anisotropy) |
|
|
|
{ |
|
|
|
max_anisotropy = std::max<float>(0.0f, std::min<float>(1.0f, anisotropy)); |
|
|
|
m_max_anisotropy = std::max<float>(0.0f, std::min<float>(1.0f, anisotropy)); |
|
|
|
|
|
|
|
// Get the maximum supported anisotropy value
|
|
|
|
float gl_max_texture_max_anisotropy; |
|
|
|
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gl_max_texture_max_anisotropy); |
|
|
|
|
|
|
|
// Lerp between 1.0 and GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
|
|
|
|
float gl_max_anisotropy = 1.0f + max_anisotropy * (gl_max_texture_max_anisotropy - 1.0f); |
|
|
|
float gl_max_anisotropy = 1.0f + m_max_anisotropy * (gl_max_texture_max_anisotropy - 1.0f); |
|
|
|
|
|
|
|
glBindTexture(gl_texture_target, gl_texture_id); |
|
|
|
glTexParameterf(gl_texture_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_max_anisotropy); |
|
|
|
glBindTexture(m_gl_texture_target, m_gl_texture_id); |
|
|
|
glTexParameterf(m_gl_texture_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_max_anisotropy); |
|
|
|
} |
|
|
|
|
|
|
|
void texture::set_wrapping(gl::texture_wrapping wrap_s, gl::texture_wrapping wrap_t, gl::texture_wrapping wrap_r) |
|
|
|
{ |
|
|
|
wrapping = {wrap_s, wrap_t, wrap_r}; |
|
|
|
m_wrapping = {wrap_s, wrap_t, wrap_r}; |
|
|
|
|
|
|
|
GLenum gl_wrap_s = wrapping_lut[static_cast<std::size_t>(wrap_s)]; |
|
|
|
GLenum gl_wrap_t = wrapping_lut[static_cast<std::size_t>(wrap_t)]; |
|
|
|
GLenum gl_wrap_r = wrapping_lut[static_cast<std::size_t>(wrap_r)]; |
|
|
|
GLenum gl_wrap_s = wrapping_lut[std::to_underlying(wrap_s)]; |
|
|
|
GLenum gl_wrap_t = wrapping_lut[std::to_underlying(wrap_t)]; |
|
|
|
GLenum gl_wrap_r = wrapping_lut[std::to_underlying(wrap_r)]; |
|
|
|
|
|
|
|
glBindTexture(gl_texture_target, gl_texture_id); |
|
|
|
glTexParameteri(gl_texture_target, GL_TEXTURE_WRAP_S, gl_wrap_s); |
|
|
|
glTexParameteri(gl_texture_target, GL_TEXTURE_WRAP_T, gl_wrap_t); |
|
|
|
glTexParameteri(gl_texture_target, GL_TEXTURE_WRAP_R, gl_wrap_r); |
|
|
|
glBindTexture(m_gl_texture_target, m_gl_texture_id); |
|
|
|
glTexParameteri(m_gl_texture_target, GL_TEXTURE_WRAP_S, gl_wrap_s); |
|
|
|
glTexParameteri(m_gl_texture_target, GL_TEXTURE_WRAP_T, gl_wrap_t); |
|
|
|
glTexParameteri(m_gl_texture_target, GL_TEXTURE_WRAP_R, gl_wrap_r); |
|
|
|
} |
|
|
|
|
|
|
|
void texture::set_wrapping(gl::texture_wrapping wrap_s, gl::texture_wrapping wrap_t) |
|
|
|
{ |
|
|
|
std::get<0>(wrapping) = wrap_s; |
|
|
|
std::get<1>(wrapping) = wrap_t; |
|
|
|
std::get<0>(m_wrapping) = wrap_s; |
|
|
|
std::get<1>(m_wrapping) = wrap_t; |
|
|
|
|
|
|
|
GLenum gl_wrap_s = wrapping_lut[static_cast<std::size_t>(wrap_s)]; |
|
|
|
GLenum gl_wrap_t = wrapping_lut[static_cast<std::size_t>(wrap_t)]; |
|
|
|
GLenum gl_wrap_s = wrapping_lut[std::to_underlying(wrap_s)]; |
|
|
|
GLenum gl_wrap_t = wrapping_lut[std::to_underlying(wrap_t)]; |
|
|
|
|
|
|
|
glBindTexture(gl_texture_target, gl_texture_id); |
|
|
|
glTexParameteri(gl_texture_target, GL_TEXTURE_WRAP_S, gl_wrap_s); |
|
|
|
glTexParameteri(gl_texture_target, GL_TEXTURE_WRAP_T, gl_wrap_t); |
|
|
|
glBindTexture(m_gl_texture_target, m_gl_texture_id); |
|
|
|
glTexParameteri(m_gl_texture_target, GL_TEXTURE_WRAP_S, gl_wrap_s); |
|
|
|
glTexParameteri(m_gl_texture_target, GL_TEXTURE_WRAP_T, gl_wrap_t); |
|
|
|
} |
|
|
|
|
|
|
|
void texture::set_wrapping(gl::texture_wrapping wrap_s) |
|
|
|
{ |
|
|
|
std::get<0>(wrapping) = wrap_s; |
|
|
|
std::get<0>(m_wrapping) = wrap_s; |
|
|
|
|
|
|
|
GLenum gl_wrap_s = wrapping_lut[static_cast<std::size_t>(wrap_s)]; |
|
|
|
GLenum gl_wrap_s = wrapping_lut[std::to_underlying(wrap_s)]; |
|
|
|
|
|
|
|
glBindTexture(gl_texture_target, gl_texture_id); |
|
|
|
glTexParameteri(gl_texture_target, GL_TEXTURE_WRAP_S, gl_wrap_s); |
|
|
|
glBindTexture(m_gl_texture_target, m_gl_texture_id); |
|
|
|
glTexParameteri(m_gl_texture_target, GL_TEXTURE_WRAP_S, gl_wrap_s); |
|
|
|
} |
|
|
|
|
|
|
|
void texture::resize(std::uint16_t width, std::uint16_t height, std::uint16_t depth, gl::pixel_type type, gl::pixel_format format, gl::color_space color_space, const std::byte* data) |
|
|
|
{ |
|
|
|
dimensions = {width, height, depth}; |
|
|
|
pixel_type = type; |
|
|
|
pixel_format = format; |
|
|
|
this->color_space = color_space; |
|
|
|
m_dimensions = {width, height, depth}; |
|
|
|
m_pixel_type = type; |
|
|
|
m_pixel_format = format; |
|
|
|
m_color_space = color_space; |
|
|
|
|
|
|
|
GLenum gl_internal_format; |
|
|
|
if (color_space == gl::color_space::srgb) |
|
|
|
if (m_color_space == gl::color_space::srgb) |
|
|
|
{ |
|
|
|
gl_internal_format = srgb_internal_format_lut[static_cast<std::size_t>(format)][static_cast<std::size_t>(type)]; |
|
|
|
gl_internal_format = srgb_internal_format_lut[std::to_underlying(format)][std::to_underlying(type)]; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
gl_internal_format = linear_internal_format_lut[static_cast<std::size_t>(format)][static_cast<std::size_t>(type)]; |
|
|
|
gl_internal_format = linear_internal_format_lut[std::to_underlying(format)][std::to_underlying(type)]; |
|
|
|
} |
|
|
|
|
|
|
|
GLenum gl_format = pixel_format_lut[static_cast<std::size_t>(format)]; |
|
|
|
const GLint* gl_swizzle_mask = swizzle_mask_lut[static_cast<std::size_t>(format)]; |
|
|
|
GLenum gl_format = pixel_format_lut[std::to_underlying(format)]; |
|
|
|
const GLint* gl_swizzle_mask = swizzle_mask_lut[std::to_underlying(format)]; |
|
|
|
|
|
|
|
GLenum gl_type = pixel_type_lut[static_cast<std::size_t>(type)]; |
|
|
|
GLenum gl_type = pixel_type_lut[std::to_underlying(type)]; |
|
|
|
|
|
|
|
// Special cases for depth + stencil pixel formats
|
|
|
|
if (gl_internal_format == GL_DEPTH24_STENCIL8) |
|
|
|
{ |
|
|
|
gl_type = GL_UNSIGNED_INT_24_8; |
|
|
|
} |
|
|
|
else if (gl_internal_format == GL_DEPTH32F_STENCIL8) |
|
|
|
{ |
|
|
|
gl_type = GL_FLOAT_32_UNSIGNED_INT_24_8_REV; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
glPixelStorei(GL_PACK_ALIGNMENT, 1); |
|
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); |
|
|
|
|
|
|
|
glBindTexture(gl_texture_target, gl_texture_id); |
|
|
|
if (depth) |
|
|
|
glTexImage3D(gl_texture_target, 0, gl_internal_format, width, height, depth, 0, gl_format, gl_type, data); |
|
|
|
else if (height) |
|
|
|
glTexImage2D(gl_texture_target, 0, gl_internal_format, width, height, 0, gl_format, gl_type, data); |
|
|
|
else if (width) |
|
|
|
glTexImage1D(gl_texture_target, 0, gl_internal_format, width, 0, gl_format, gl_type, data); |
|
|
|
glBindTexture(m_gl_texture_target, m_gl_texture_id); |
|
|
|
|
|
|
|
glGenerateMipmap(gl_texture_target); |
|
|
|
glTexParameteriv(gl_texture_target, GL_TEXTURE_SWIZZLE_RGBA, gl_swizzle_mask); |
|
|
|
switch (m_gl_texture_target) |
|
|
|
{ |
|
|
|
case GL_TEXTURE_1D: |
|
|
|
glTexImage1D(m_gl_texture_target, 0, gl_internal_format, width, 0, gl_format, gl_type, data); |
|
|
|
break; |
|
|
|
|
|
|
|
case GL_TEXTURE_2D: |
|
|
|
glTexImage2D(m_gl_texture_target, 0, gl_internal_format, width, height, 0, gl_format, gl_type, data); |
|
|
|
break; |
|
|
|
|
|
|
|
case GL_TEXTURE_3D: |
|
|
|
glTexImage3D(m_gl_texture_target, 0, gl_internal_format, width, height, depth, 0, gl_format, gl_type, data); |
|
|
|
break; |
|
|
|
|
|
|
|
case GL_TEXTURE_CUBE_MAP: |
|
|
|
update_cube_faces(gl_internal_format, gl_format, gl_type, data); |
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
glGenerateMipmap(m_gl_texture_target); |
|
|
|
glTexParameteriv(m_gl_texture_target, GL_TEXTURE_SWIZZLE_RGBA, gl_swizzle_mask); |
|
|
|
|
|
|
|
/// @TODO: remove this
|
|
|
|
if (format == pixel_format::d) |
|
|
|
{ |
|
|
|
glTexParameteri(gl_texture_target, GL_TEXTURE_COMPARE_FUNC, GL_LESS); |
|
|
|
glTexParameteri(gl_texture_target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); |
|
|
|
glTexParameteri(m_gl_texture_target, GL_TEXTURE_COMPARE_FUNC, GL_LESS); |
|
|
|
glTexParameteri(m_gl_texture_target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -275,6 +293,184 @@ void texture::resize(std::uint16_t width, gl::pixel_type type, gl::pixel_format |
|
|
|
resize(width, 0, 0, type, format, color_space, data); |
|
|
|
} |
|
|
|
|
|
|
|
void texture::update_cube_faces(unsigned int gl_internal_format, unsigned int gl_format, unsigned int gl_type, const std::byte* data) |
|
|
|
{ |
|
|
|
const auto width = get_width(); |
|
|
|
const auto height = get_height(); |
|
|
|
const auto layout = texture_cube::infer_cube_map_layout(width, height); |
|
|
|
const auto face_size = texture_cube::infer_cube_map_face_size(layout, width, height); |
|
|
|
|
|
|
|
std::size_t channel_count = 0; |
|
|
|
switch (m_pixel_format) |
|
|
|
{ |
|
|
|
case pixel_format::d: |
|
|
|
case pixel_format::r: |
|
|
|
channel_count = 1; |
|
|
|
break; |
|
|
|
|
|
|
|
case pixel_format::ds: |
|
|
|
case pixel_format::rg: |
|
|
|
channel_count = 2; |
|
|
|
break; |
|
|
|
|
|
|
|
case pixel_format::rgb: |
|
|
|
case pixel_format::bgr: |
|
|
|
channel_count = 3; |
|
|
|
break; |
|
|
|
|
|
|
|
case pixel_format::rgba: |
|
|
|
case pixel_format::bgra: |
|
|
|
channel_count = 4; |
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
std::size_t channel_size = 0; |
|
|
|
switch (m_pixel_type) |
|
|
|
{ |
|
|
|
case pixel_type::int_8: |
|
|
|
case pixel_type::uint_8: |
|
|
|
channel_size = 1; |
|
|
|
break; |
|
|
|
|
|
|
|
case pixel_type::int_16: |
|
|
|
case pixel_type::uint_16: |
|
|
|
case pixel_type::float_16: |
|
|
|
channel_size = 2; |
|
|
|
break; |
|
|
|
|
|
|
|
case pixel_type::int_32: |
|
|
|
case pixel_type::uint_32: |
|
|
|
case pixel_type::float_32: |
|
|
|
channel_size = 4; |
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
const std::size_t pixel_stride = channel_count * channel_size; |
|
|
|
const std::size_t row_stride = static_cast<std::size_t>(face_size) * pixel_stride; |
|
|
|
const std::size_t face_stride = static_cast<std::size_t>(face_size) * row_stride; |
|
|
|
|
|
|
|
constexpr std::uint16_t vcross_offsets[6][2] = |
|
|
|
{ |
|
|
|
{2, 2}, {0, 2}, |
|
|
|
{1, 3}, {1, 1}, |
|
|
|
{1, 0}, {1, 2} |
|
|
|
}; |
|
|
|
constexpr std::uint16_t hcross_offsets[6][2] = |
|
|
|
{ |
|
|
|
{2, 1}, {0, 1}, |
|
|
|
{1, 2}, {1, 0}, |
|
|
|
{3, 1}, {1, 1} |
|
|
|
}; |
|
|
|
|
|
|
|
std::vector<std::byte> face_buffer(face_stride); |
|
|
|
|
|
|
|
switch (layout) |
|
|
|
{ |
|
|
|
case cube_map_layout::column: |
|
|
|
for (std::uint16_t i = 0; i < 6; ++i) |
|
|
|
{ |
|
|
|
const std::byte* face_data = data + face_stride * (5 - i); |
|
|
|
|
|
|
|
for (std::uint16_t y = 0; y < face_size; ++y) |
|
|
|
{ |
|
|
|
for (std::uint16_t x = 0; x < face_size; ++x) |
|
|
|
{ |
|
|
|
if (i < 2 || i > 3) |
|
|
|
{ |
|
|
|
std::memcpy(face_buffer.data() + y * row_stride + x * pixel_stride, face_data + (face_size - y - 1) * row_stride + (face_size - x - 1) * pixel_stride, pixel_stride); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
std::memcpy(face_buffer.data() + y * row_stride + x * pixel_stride, face_data + y * row_stride + x * pixel_stride, pixel_stride); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, gl_internal_format, face_size, face_size, 0, gl_format, gl_type, face_buffer.data()); |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case cube_map_layout::row: |
|
|
|
for (std::uint16_t i = 0; i < 6; ++i) |
|
|
|
{ |
|
|
|
for (std::uint16_t y = 0; y < face_size; ++y) |
|
|
|
{ |
|
|
|
for (std::uint16_t x = 0; x < face_size; ++x) |
|
|
|
{ |
|
|
|
if (i < 2 || i > 3) |
|
|
|
{ |
|
|
|
std::memcpy(face_buffer.data() + y * row_stride + x * pixel_stride, data + row_stride * (face_size - y - 1) * 6 + row_stride * i + (face_size - x - 1) * pixel_stride, pixel_stride); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
std::memcpy(face_buffer.data() + y * row_stride + x * pixel_stride, data + row_stride * y * 6 + row_stride * i + x * pixel_stride, pixel_stride); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, gl_internal_format, face_size, face_size, 0, gl_format, gl_type, face_buffer.data()); |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case cube_map_layout::vertical_cross: |
|
|
|
for (std::uint16_t i = 0; i < 6; ++i) |
|
|
|
{ |
|
|
|
const std::byte* face_data = data + vcross_offsets[i][1] * row_stride * face_size * 3 + vcross_offsets[i][0] * row_stride; |
|
|
|
|
|
|
|
for (std::uint16_t y = 0; y < face_size; ++y) |
|
|
|
{ |
|
|
|
for (std::uint16_t x = 0; x < face_size; ++x) |
|
|
|
{ |
|
|
|
if (i < 2 || i > 3) |
|
|
|
{ |
|
|
|
std::memcpy(face_buffer.data() + y * row_stride + x * pixel_stride, face_data + (face_size - y - 1) * row_stride * 3 + (face_size - x - 1) * pixel_stride, pixel_stride); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
std::memcpy(face_buffer.data() + y * row_stride + x * pixel_stride, face_data + y * row_stride * 3 + x * pixel_stride, pixel_stride); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, gl_internal_format, face_size, face_size, 0, gl_format, gl_type, face_buffer.data()); |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case cube_map_layout::horizontal_cross: |
|
|
|
for (std::uint16_t i = 0; i < 6; ++i) |
|
|
|
{ |
|
|
|
const std::byte* face_data = data + hcross_offsets[i][1] * row_stride * face_size * 4 + hcross_offsets[i][0] * row_stride; |
|
|
|
|
|
|
|
for (std::uint16_t y = 0; y < face_size; ++y) |
|
|
|
{ |
|
|
|
for (std::uint16_t x = 0; x < face_size; ++x) |
|
|
|
{ |
|
|
|
if (i < 2 || i > 3) |
|
|
|
{ |
|
|
|
std::memcpy(face_buffer.data() + y * row_stride + x * pixel_stride, face_data + (face_size - y - 1) * row_stride * 4 + (face_size - x - 1) * pixel_stride, pixel_stride); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
std::memcpy(face_buffer.data() + y * row_stride + x * pixel_stride, face_data + y * row_stride * 4 + x * pixel_stride, pixel_stride); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, gl_internal_format, face_size, face_size, 0, gl_format, gl_type, face_buffer.data()); |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
throw std::runtime_error("Unsupported cube map layout"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} // namespace gl
|
|
|
|
|
|
|
|
template <> |
|
|
@ -286,7 +482,9 @@ std::unique_ptr resource_loader::load(::resource |
|
|
|
// Read image filename
|
|
|
|
std::string image_filename; |
|
|
|
if (auto element = json_data->find("image"); element != json_data->end()) |
|
|
|
{ |
|
|
|
image_filename = element.value().get<std::string>(); |
|
|
|
} |
|
|
|
|
|
|
|
// Load image
|
|
|
|
auto image = resource_manager.load<::image>(image_filename); |
|
|
@ -297,9 +495,13 @@ std::unique_ptr resource_loader::load(::resource |
|
|
|
{ |
|
|
|
std::string value = element.value().get<std::string>(); |
|
|
|
if (value == "linear") |
|
|
|
{ |
|
|
|
color_space = gl::color_space::linear; |
|
|
|
} |
|
|
|
else if (value == "srgb") |
|
|
|
{ |
|
|
|
color_space = gl::color_space::srgb; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Read extension mode
|
|
|
@ -308,13 +510,21 @@ std::unique_ptr resource_loader::load(::resource |
|
|
|
{ |
|
|
|
std::string value = element.value().get<std::string>(); |
|
|
|
if (value == "clip") |
|
|
|
{ |
|
|
|
wrapping = gl::texture_wrapping::clip; |
|
|
|
} |
|
|
|
else if (value == "extend") |
|
|
|
{ |
|
|
|
wrapping = gl::texture_wrapping::extend; |
|
|
|
} |
|
|
|
else if (value == "repeat") |
|
|
|
{ |
|
|
|
wrapping = gl::texture_wrapping::repeat; |
|
|
|
} |
|
|
|
else if (value == "mirrored_repeat") |
|
|
|
{ |
|
|
|
wrapping = gl::texture_wrapping::mirrored_repeat; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Read interpolation mode
|
|
|
@ -338,7 +548,9 @@ std::unique_ptr resource_loader::load(::resource |
|
|
|
// Read max anisotropy
|
|
|
|
float max_anisotropy = 0.0f; |
|
|
|
if (auto element = json_data->find("max_anisotropy"); element != json_data->end()) |
|
|
|
{ |
|
|
|
max_anisotropy = element.value().get<float>(); |
|
|
|
} |
|
|
|
|
|
|
|
// Determine pixel type
|
|
|
|
gl::pixel_type type = (image->component_size() == sizeof(float)) ? gl::pixel_type::float_32 : gl::pixel_type::uint_8; |
|
|
@ -384,7 +596,9 @@ std::unique_ptr resource_loader::load(::resource |
|
|
|
// Read image filename
|
|
|
|
std::string image_filename; |
|
|
|
if (auto element = json_data->find("image"); element != json_data->end()) |
|
|
|
{ |
|
|
|
image_filename = element.value().get<std::string>(); |
|
|
|
} |
|
|
|
|
|
|
|
// Load image
|
|
|
|
auto image = resource_manager.load<::image>(image_filename); |
|
|
@ -395,9 +609,13 @@ std::unique_ptr resource_loader::load(::resource |
|
|
|
{ |
|
|
|
std::string value = element.value().get<std::string>(); |
|
|
|
if (value == "linear") |
|
|
|
{ |
|
|
|
color_space = gl::color_space::linear; |
|
|
|
} |
|
|
|
else if (value == "srgb") |
|
|
|
{ |
|
|
|
color_space = gl::color_space::srgb; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Read extension mode
|
|
|
@ -406,13 +624,21 @@ std::unique_ptr resource_loader::load(::resource |
|
|
|
{ |
|
|
|
std::string value = element.value().get<std::string>(); |
|
|
|
if (value == "clip") |
|
|
|
{ |
|
|
|
wrapping = gl::texture_wrapping::clip; |
|
|
|
} |
|
|
|
else if (value == "extend") |
|
|
|
{ |
|
|
|
wrapping = gl::texture_wrapping::extend; |
|
|
|
} |
|
|
|
else if (value == "repeat") |
|
|
|
{ |
|
|
|
wrapping = gl::texture_wrapping::repeat; |
|
|
|
} |
|
|
|
else if (value == "mirrored_repeat") |
|
|
|
{ |
|
|
|
wrapping = gl::texture_wrapping::mirrored_repeat; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Read interpolation mode
|
|
|
@ -436,7 +662,9 @@ std::unique_ptr resource_loader::load(::resource |
|
|
|
// Read max anisotropy
|
|
|
|
float max_anisotropy = 0.0f; |
|
|
|
if (auto element = json_data->find("max_anisotropy"); element != json_data->end()) |
|
|
|
{ |
|
|
|
max_anisotropy = element.value().get<float>(); |
|
|
|
} |
|
|
|
|
|
|
|
// Determine pixel type
|
|
|
|
gl::pixel_type type = (image->component_size() == sizeof(float)) ? gl::pixel_type::float_32 : gl::pixel_type::uint_8; |
|
|
@ -472,3 +700,123 @@ std::unique_ptr resource_loader::load(::resource |
|
|
|
|
|
|
|
return texture; |
|
|
|
} |
|
|
|
|
|
|
|
template <> |
|
|
|
std::unique_ptr<gl::texture_3d> resource_loader<gl::texture_3d>::load(::resource_manager& resource_manager, deserialize_context& ctx) |
|
|
|
{ |
|
|
|
throw std::runtime_error("3D texture loading not yet supported"); |
|
|
|
} |
|
|
|
|
|
|
|
template <> |
|
|
|
std::unique_ptr<gl::texture_cube> resource_loader<gl::texture_cube>::load(::resource_manager& resource_manager, deserialize_context& ctx) |
|
|
|
{ |
|
|
|
// Load JSON data
|
|
|
|
auto json_data = resource_loader<nlohmann::json>::load(resource_manager, ctx); |
|
|
|
|
|
|
|
// Read image filename
|
|
|
|
std::string image_filename; |
|
|
|
if (auto element = json_data->find("image"); element != json_data->end()) |
|
|
|
{ |
|
|
|
image_filename = element.value().get<std::string>(); |
|
|
|
} |
|
|
|
|
|
|
|
// Load image
|
|
|
|
auto image = resource_manager.load<::image>(image_filename); |
|
|
|
|
|
|
|
// Read color space
|
|
|
|
gl::color_space color_space = gl::color_space::linear; |
|
|
|
if (auto element = json_data->find("color_space"); element != json_data->end()) |
|
|
|
{ |
|
|
|
std::string value = element.value().get<std::string>(); |
|
|
|
if (value == "linear") |
|
|
|
{ |
|
|
|
color_space = gl::color_space::linear; |
|
|
|
} |
|
|
|
else if (value == "srgb") |
|
|
|
{ |
|
|
|
color_space = gl::color_space::srgb; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Read extension mode
|
|
|
|
gl::texture_wrapping wrapping = gl::texture_wrapping::repeat; |
|
|
|
if (auto element = json_data->find("extension"); element != json_data->end()) |
|
|
|
{ |
|
|
|
std::string value = element.value().get<std::string>(); |
|
|
|
if (value == "clip") |
|
|
|
{ |
|
|
|
wrapping = gl::texture_wrapping::clip; |
|
|
|
} |
|
|
|
else if (value == "extend") |
|
|
|
{ |
|
|
|
wrapping = gl::texture_wrapping::extend; |
|
|
|
} |
|
|
|
else if (value == "repeat") |
|
|
|
{ |
|
|
|
wrapping = gl::texture_wrapping::repeat; |
|
|
|
} |
|
|
|
else if (value == "mirrored_repeat") |
|
|
|
{ |
|
|
|
wrapping = gl::texture_wrapping::mirrored_repeat; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Read interpolation mode
|
|
|
|
gl::texture_min_filter min_filter = gl::texture_min_filter::linear_mipmap_linear; |
|
|
|
gl::texture_mag_filter mag_filter = gl::texture_mag_filter::linear; |
|
|
|
if (auto element = json_data->find("interpolation"); element != json_data->end()) |
|
|
|
{ |
|
|
|
std::string value = element.value().get<std::string>(); |
|
|
|
if (value == "linear") |
|
|
|
{ |
|
|
|
min_filter = gl::texture_min_filter::linear_mipmap_linear; |
|
|
|
mag_filter = gl::texture_mag_filter::linear; |
|
|
|
} |
|
|
|
else if (value == "closest") |
|
|
|
{ |
|
|
|
min_filter = gl::texture_min_filter::nearest_mipmap_nearest; |
|
|
|
mag_filter = gl::texture_mag_filter::nearest; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Read max anisotropy
|
|
|
|
float max_anisotropy = 0.0f; |
|
|
|
if (auto element = json_data->find("max_anisotropy"); element != json_data->end()) |
|
|
|
{ |
|
|
|
max_anisotropy = element.value().get<float>(); |
|
|
|
} |
|
|
|
|
|
|
|
// Determine pixel type
|
|
|
|
gl::pixel_type type = (image->component_size() == sizeof(float)) ? gl::pixel_type::float_32 : gl::pixel_type::uint_8; |
|
|
|
|
|
|
|
// Determine pixel format
|
|
|
|
gl::pixel_format format; |
|
|
|
if (image->channel_count() == 1) |
|
|
|
{ |
|
|
|
format = gl::pixel_format::r; |
|
|
|
} |
|
|
|
else if (image->channel_count() == 2) |
|
|
|
{ |
|
|
|
format = gl::pixel_format::rg; |
|
|
|
} |
|
|
|
else if (image->channel_count() == 3) |
|
|
|
{ |
|
|
|
format = gl::pixel_format::rgb; |
|
|
|
} |
|
|
|
else if (image->channel_count() == 4) |
|
|
|
{ |
|
|
|
format = gl::pixel_format::rgba; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
throw std::runtime_error(std::format("Texture image has unsupported number of channels ({})", image->channel_count())); |
|
|
|
} |
|
|
|
|
|
|
|
// Create texture
|
|
|
|
auto texture = std::make_unique<gl::texture_cube>(image->width(), image->height(), type, format, color_space, image->data()); |
|
|
|
texture->set_wrapping(wrapping, wrapping, wrapping); |
|
|
|
texture->set_filters(min_filter, mag_filter); |
|
|
|
texture->set_max_anisotropy(max_anisotropy); |
|
|
|
|
|
|
|
return texture; |
|
|
|
} |