Browse Source

Add support for cube map loading

master
C. J. Howard 11 months ago
parent
commit
a1f3b60e5b
21 changed files with 915 additions and 225 deletions
  1. +1
    -0
      CMakeLists.txt
  2. +51
    -0
      src/engine/gl/cube-map-layout.hpp
  3. +7
    -1
      src/engine/gl/framebuffer.cpp
  4. +16
    -16
      src/engine/gl/opengl/gl-shader-variables.cpp
  5. +1
    -4
      src/engine/gl/texture-1d.cpp
  6. +4
    -3
      src/engine/gl/texture-1d.hpp
  7. +1
    -4
      src/engine/gl/texture-2d.cpp
  8. +6
    -5
      src/engine/gl/texture-2d.hpp
  9. +1
    -4
      src/engine/gl/texture-3d.cpp
  10. +4
    -3
      src/engine/gl/texture-3d.hpp
  11. +79
    -8
      src/engine/gl/texture-cube.cpp
  12. +52
    -15
      src/engine/gl/texture-cube.hpp
  13. +45
    -0
      src/engine/gl/texture-type.hpp
  14. +415
    -67
      src/engine/gl/texture.cpp
  15. +75
    -89
      src/engine/gl/texture.hpp
  16. +64
    -1
      src/engine/render/material.cpp
  17. +4
    -1
      src/engine/scene/light-type.hpp
  18. +25
    -0
      src/engine/scene/sky-light.cpp
  19. +47
    -0
      src/engine/scene/sky-light.hpp
  20. +2
    -2
      src/game/states/main-menu-state.cpp
  21. +15
    -2
      src/game/states/nest-view-state.cpp

+ 1
- 0
CMakeLists.txt View File

@ -1,5 +1,6 @@
cmake_minimum_required(VERSION 3.25)
option(APPLICATION_NAME "Application name" "Antkeeper")
option(APPLICATION_VERSION "Application version string" "0.0.0")
option(APPLICATION_AUTHOR "Application author" "C. J. Howard")

+ 51
- 0
src/engine/gl/cube-map-layout.hpp View File

@ -0,0 +1,51 @@
/*
* Copyright (C) 2023 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_GL_CUBE_MAP_LAYOUT_HPP
#define ANTKEEPER_GL_CUBE_MAP_LAYOUT_HPP
#include <cstdint>
namespace gl {
/// Cube map layout types.
enum class cube_map_layout: std::uint8_t
{
/// Faces are stored consecutively in a vertical column.
column = 1,
/// Faces are stored consecutively in a horizontal row.
row,
/// Faces are stored in a vertical cross.
vertical_cross,
/// Faces are stored in a horizontal cross.
horizontal_cross,
/// Faces are stored in an equirectangular projection.
equirectangular,
/// Faces are stored in a spherical projection.
spherical
};
} // namespace gl
#endif // ANTKEEPER_GL_CUBE_MAP_LAYOUT_HPP

+ 7
- 1
src/engine/gl/framebuffer.cpp View File

@ -58,14 +58,20 @@ void framebuffer::attach(framebuffer_attachment_type attachment_type, texture_2d
glBindFramebuffer(GL_FRAMEBUFFER, gl_framebuffer_id);
GLenum gl_attachment = attachment_lut[static_cast<std::size_t>(attachment_type)];
glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attachment, GL_TEXTURE_2D, texture->gl_texture_id, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attachment, GL_TEXTURE_2D, texture->m_gl_texture_id, 0);
if (attachment_type == framebuffer_attachment_type::color)
{
color_attachment = texture;
}
else if (attachment_type == framebuffer_attachment_type::depth)
{
depth_attachment = texture;
}
else if (attachment_type == framebuffer_attachment_type::stencil)
{
stencil_attachment = texture;
}
if (!color_attachment)
{

+ 16
- 16
src/engine/gl/opengl/gl-shader-variables.cpp View File

@ -451,7 +451,7 @@ void gl_shader_texture_1d::update(const texture_1d& value) const noexcept
{
// Bind texture to texture unit
glActiveTexture(GL_TEXTURE0 + static_cast<GLenum>(gl_texture_unit_indices.front()));
glBindTexture(GL_TEXTURE_1D, value.gl_texture_id);
glBindTexture(GL_TEXTURE_1D, value.m_gl_texture_id);
// Pass texture unit index to shader
glUniform1i(gl_uniform_location, gl_texture_unit_indices.front());
@ -463,7 +463,7 @@ void gl_shader_texture_1d::update(const texture_1d& value, std::size_t index) co
// Bind texture to texture unit
glActiveTexture(GL_TEXTURE0 + static_cast<GLenum>(gl_texture_index));
glBindTexture(GL_TEXTURE_1D, value.gl_texture_id);
glBindTexture(GL_TEXTURE_1D, value.m_gl_texture_id);
// Pass texture unit index to shader
glUniform1i(gl_uniform_location + static_cast<GLint>(index), gl_texture_index);
@ -475,7 +475,7 @@ void gl_shader_texture_1d::update(std::span values, std
for (std::size_t i = 0; i < values.size(); ++i)
{
glActiveTexture(GL_TEXTURE0 + static_cast<GLenum>(gl_texture_unit_indices[index + i]));
glBindTexture(GL_TEXTURE_1D, values[i]->gl_texture_id);
glBindTexture(GL_TEXTURE_1D, values[i]->m_gl_texture_id);
}
// Pass texture unit indices to shader
@ -488,7 +488,7 @@ void gl_shader_texture_1d::update(std::span> v
for (std::size_t i = 0; i < values.size(); ++i)
{
glActiveTexture(GL_TEXTURE0 + static_cast<GLenum>(gl_texture_unit_indices[index + i]));
glBindTexture(GL_TEXTURE_1D, values[i]->gl_texture_id);
glBindTexture(GL_TEXTURE_1D, values[i]->m_gl_texture_id);
}
// Pass texture unit indices to shader
@ -507,7 +507,7 @@ void gl_shader_texture_2d::update(const texture_2d& value) const noexcept
{
// Bind texture to texture unit
glActiveTexture(GL_TEXTURE0 + static_cast<GLenum>(gl_texture_unit_indices.front()));
glBindTexture(GL_TEXTURE_2D, value.gl_texture_id);
glBindTexture(GL_TEXTURE_2D, value.m_gl_texture_id);
// Pass texture unit index to shader
glUniform1i(gl_uniform_location, gl_texture_unit_indices.front());
@ -519,7 +519,7 @@ void gl_shader_texture_2d::update(const texture_2d& value, std::size_t index) co
// Bind texture to texture unit
glActiveTexture(GL_TEXTURE0 + static_cast<GLenum>(gl_texture_index));
glBindTexture(GL_TEXTURE_2D, value.gl_texture_id);
glBindTexture(GL_TEXTURE_2D, value.m_gl_texture_id);
// Pass texture unit index to shader
glUniform1i(gl_uniform_location + static_cast<GLint>(index), gl_texture_index);
@ -531,7 +531,7 @@ void gl_shader_texture_2d::update(std::span values, std
for (std::size_t i = 0; i < values.size(); ++i)
{
glActiveTexture(GL_TEXTURE0 + static_cast<GLenum>(gl_texture_unit_indices[index + i]));
glBindTexture(GL_TEXTURE_2D, values[i]->gl_texture_id);
glBindTexture(GL_TEXTURE_2D, values[i]->m_gl_texture_id);
}
// Pass texture unit indices to shader
@ -544,7 +544,7 @@ void gl_shader_texture_2d::update(std::span> v
for (std::size_t i = 0; i < values.size(); ++i)
{
glActiveTexture(GL_TEXTURE0 + static_cast<GLenum>(gl_texture_unit_indices[index + i]));
glBindTexture(GL_TEXTURE_2D, values[i]->gl_texture_id);
glBindTexture(GL_TEXTURE_2D, values[i]->m_gl_texture_id);
}
// Pass texture unit indices to shader
@ -563,7 +563,7 @@ void gl_shader_texture_3d::update(const texture_3d& value) const noexcept
{
// Bind texture to texture unit
glActiveTexture(GL_TEXTURE0 + static_cast<GLenum>(gl_texture_unit_indices.front()));
glBindTexture(GL_TEXTURE_3D, value.gl_texture_id);
glBindTexture(GL_TEXTURE_3D, value.m_gl_texture_id);
// Pass texture unit index to shader
glUniform1i(gl_uniform_location, gl_texture_unit_indices.front());
@ -575,7 +575,7 @@ void gl_shader_texture_3d::update(const texture_3d& value, std::size_t index) co
// Bind texture to texture unit
glActiveTexture(GL_TEXTURE0 + static_cast<GLenum>(gl_texture_index));
glBindTexture(GL_TEXTURE_3D, value.gl_texture_id);
glBindTexture(GL_TEXTURE_3D, value.m_gl_texture_id);
// Pass texture unit index to shader
glUniform1i(gl_uniform_location + static_cast<GLint>(index), gl_texture_index);
@ -587,7 +587,7 @@ void gl_shader_texture_3d::update(std::span values, std
for (std::size_t i = 0; i < values.size(); ++i)
{
glActiveTexture(GL_TEXTURE0 + static_cast<GLenum>(gl_texture_unit_indices[index + i]));
glBindTexture(GL_TEXTURE_3D, values[i]->gl_texture_id);
glBindTexture(GL_TEXTURE_3D, values[i]->m_gl_texture_id);
}
// Pass texture unit indices to shader
@ -600,7 +600,7 @@ void gl_shader_texture_3d::update(std::span> v
for (std::size_t i = 0; i < values.size(); ++i)
{
glActiveTexture(GL_TEXTURE0 + static_cast<GLenum>(gl_texture_unit_indices[index + i]));
glBindTexture(GL_TEXTURE_3D, values[i]->gl_texture_id);
glBindTexture(GL_TEXTURE_3D, values[i]->m_gl_texture_id);
}
// Pass texture unit indices to shader
@ -619,7 +619,7 @@ void gl_shader_texture_cube::update(const texture_cube& value) const noexcept
{
// Bind texture to texture unit
glActiveTexture(GL_TEXTURE0 + static_cast<GLenum>(gl_texture_unit_indices.front()));
glBindTexture(GL_TEXTURE_CUBE_MAP, value.gl_texture_id);
glBindTexture(GL_TEXTURE_CUBE_MAP, value.m_gl_texture_id);
// Pass texture unit index to shader
glUniform1i(gl_uniform_location, gl_texture_unit_indices.front());
@ -631,7 +631,7 @@ void gl_shader_texture_cube::update(const texture_cube& value, std::size_t index
// Bind texture to texture unit
glActiveTexture(GL_TEXTURE0 + static_cast<GLenum>(gl_texture_index));
glBindTexture(GL_TEXTURE_CUBE_MAP, value.gl_texture_id);
glBindTexture(GL_TEXTURE_CUBE_MAP, value.m_gl_texture_id);
// Pass texture unit index to shader
glUniform1i(gl_uniform_location + static_cast<GLint>(index), gl_texture_index);
@ -643,7 +643,7 @@ void gl_shader_texture_cube::update(std::span values,
for (std::size_t i = 0; i < values.size(); ++i)
{
glActiveTexture(GL_TEXTURE0 + static_cast<GLenum>(gl_texture_unit_indices[index + i]));
glBindTexture(GL_TEXTURE_CUBE_MAP, values[i]->gl_texture_id);
glBindTexture(GL_TEXTURE_CUBE_MAP, values[i]->m_gl_texture_id);
}
// Pass texture unit indices to shader
@ -656,7 +656,7 @@ void gl_shader_texture_cube::update(std::span
for (std::size_t i = 0; i < values.size(); ++i)
{
glActiveTexture(GL_TEXTURE0 + static_cast<GLenum>(gl_texture_unit_indices[index + i]));
glBindTexture(GL_TEXTURE_CUBE_MAP, values[i]->gl_texture_id);
glBindTexture(GL_TEXTURE_CUBE_MAP, values[i]->m_gl_texture_id);
}
// Pass texture unit indices to shader

+ 1
- 4
src/engine/gl/texture-1d.cpp View File

@ -22,10 +22,7 @@
namespace gl {
texture_1d::texture_1d(std::uint16_t width, gl::pixel_type type, gl::pixel_format format, gl::color_space color_space, const std::byte* data):
texture(width, type, format, color_space, data)
{}
texture_1d::~texture_1d()
texture(width, false, type, format, color_space, data)
{}
void texture_1d::resize(std::uint16_t width, gl::pixel_type type, gl::pixel_format format, gl::color_space color_space, const std::byte* data)

+ 4
- 3
src/engine/gl/texture-1d.hpp View File

@ -30,11 +30,12 @@ namespace gl {
class texture_1d: public texture
{
public:
/// @copydoc texture::texture(std::uint16_t, gl::pixel_type, gl::pixel_format, gl::color_space, const std::byte*)
explicit texture_1d(std::uint16_t width, gl::pixel_type type = gl::pixel_type::uint_8, gl::pixel_format format = gl::pixel_format::rgba, gl::color_space color_space = gl::color_space::linear, const std::byte* data = nullptr);
/// Destructs a 1D texture.
virtual ~texture_1d();
[[nodiscard]] inline constexpr texture_type get_texture_type() const noexcept override
{
return texture_type::one_dimensional;
}
/// @copydoc texture::resize(std::uint16_t, gl::pixel_type, gl::pixel_format, gl::color_space, const std::byte*)
virtual void resize(std::uint16_t width, gl::pixel_type type, gl::pixel_format format, gl::color_space color_space, const std::byte* data);

+ 1
- 4
src/engine/gl/texture-2d.cpp View File

@ -22,10 +22,7 @@
namespace gl {
texture_2d::texture_2d(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, type, format, color_space, data)
{}
texture_2d::~texture_2d()
texture(width, height, false, type, format, color_space, data)
{}
void texture_2d::resize(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)

+ 6
- 5
src/engine/gl/texture-2d.hpp View File

@ -30,14 +30,15 @@ namespace gl {
class texture_2d: public texture
{
public:
/// @copydoc texture::texture(std::uint16_t, std::uint16_t, gl::pixel_type, gl::pixel_format, gl::color_space, const std::byte*)
texture_2d(std::uint16_t width, std::uint16_t height, gl::pixel_type type = gl::pixel_type::uint_8, gl::pixel_format format = gl::pixel_format::rgba, gl::color_space color_space = gl::color_space::linear, const std::byte* data = nullptr);
/// Destructs a 2D texture.
virtual ~texture_2d();
[[nodiscard]] inline constexpr texture_type get_texture_type() const noexcept override
{
return texture_type::two_dimensional;
}
/// @copydoc texture::resize(std::uint16_t, std::uint16_t, gl::pixel_type, gl::pixel_format, gl::color_space, const std::byte*)
virtual void resize(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);
void resize(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) override;
/**
* Resizes the texture.
@ -49,7 +50,7 @@ public:
void resize(std::uint16_t width, std::uint16_t height, const std::byte* data);
/// @copydoc texture::set_wrapping(gl::texture_wrapping, gl::texture_wrapping)
virtual void set_wrapping(gl::texture_wrapping wrap_s, texture_wrapping wrap_t);
void set_wrapping(gl::texture_wrapping wrap_s, texture_wrapping wrap_t) override;
};
} // namespace gl

+ 1
- 4
src/engine/gl/texture-3d.cpp View File

@ -22,10 +22,7 @@
namespace gl {
texture_3d::texture_3d(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):
texture(width, height, depth, type, format, color_space, data)
{}
texture_3d::~texture_3d()
texture(width, height, depth, false, type, format, color_space, data)
{}
void texture_3d::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)

+ 4
- 3
src/engine/gl/texture-3d.hpp View File

@ -30,11 +30,12 @@ namespace gl {
class texture_3d: public texture
{
public:
/// @copydoc texture::texture(std::uint16_t, std::uint16_t, std::uint16_t, gl::pixel_type, gl::pixel_format, gl::color_space, const std::byte*)
texture_3d(std::uint16_t width, std::uint16_t height, std::uint16_t depth, gl::pixel_type type = gl::pixel_type::uint_8, gl::pixel_format format = gl::pixel_format::rgba, gl::color_space color_space = gl::color_space::linear, const std::byte* data = nullptr);
/// Destructs a 3D texture.
virtual ~texture_3d();
[[nodiscard]] inline constexpr texture_type get_texture_type() const noexcept override
{
return texture_type::three_dimensional;
}
/// @copydoc texture::resize(std::uint16_t, std::uint16_t, std::uint16_t, gl::pixel_type, gl::pixel_format, gl::color_space, const std::byte*)
virtual void 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);

+ 79
- 8
src/engine/gl/texture-cube.cpp View File

@ -18,20 +18,91 @@
*/
#include <engine/gl/texture-cube.hpp>
#include <glad/glad.h>
namespace gl {
texture_cube::texture_cube():
gl_texture_id(0),
face_size(0)
cube_map_layout texture_cube::infer_cube_map_layout(std::uint16_t w, std::uint16_t h) noexcept
{
glGenTextures(1, &gl_texture_id);
if (h == w * 6)
{
return cube_map_layout::column;
}
else if (w == h * 6)
{
return cube_map_layout::row;
}
else if (w == (h / 4) * 3)
{
return cube_map_layout::vertical_cross;
}
else if (h == (w / 4) * 3)
{
return cube_map_layout::horizontal_cross;
}
else if (w == h * 2)
{
return cube_map_layout::equirectangular;
}
else if (w == h)
{
return cube_map_layout::spherical;
}
return {};
}
texture_cube::~texture_cube()
std::uint16_t texture_cube::infer_cube_map_face_size(cube_map_layout layout, std::uint16_t w, std::uint16_t h) noexcept
{
glDeleteTextures(1, &gl_texture_id);
switch (layout)
{
case cube_map_layout::column:
case cube_map_layout::spherical:
return w;
case cube_map_layout::row:
return h;
case cube_map_layout::vertical_cross:
return h / 4;
case cube_map_layout::horizontal_cross:
case cube_map_layout::equirectangular:
return w / 4;
default:
return 0;
}
}
} // namespace gl
texture_cube::texture_cube(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, true, type, format, color_space, data)
{
resized();
}
void texture_cube::resize(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::resize(width, height, type, format, color_space, data);
resized();
}
void texture_cube::resize(std::uint16_t width, std::uint16_t height, const std::byte* data)
{
texture::resize(width, height, get_pixel_type(), get_pixel_format(), get_color_space(), data);
resized();
}
void texture_cube::set_wrapping(gl::texture_wrapping wrap_s, texture_wrapping wrap_t, texture_wrapping wrap_r)
{
texture::set_wrapping(wrap_s, wrap_t, wrap_r);
}
void texture_cube::resized()
{
const auto w = get_width();
const auto h = get_height();
const auto layout = infer_cube_map_layout(w, h);
m_face_size = infer_cube_map_face_size(layout, w, h);
}
} // namespace gl

+ 52
- 15
src/engine/gl/texture-cube.hpp View File

@ -20,36 +20,73 @@
#ifndef ANTKEEPER_GL_TEXTURE_CUBE_HPP
#define ANTKEEPER_GL_TEXTURE_CUBE_HPP
#include <engine/gl/texture.hpp>
#include <engine/gl/cube-map-layout.hpp>
namespace gl {
/**
* A cube texture which can be uploaded to shaders via shader inputs.
*/
class texture_cube
class texture_cube: public texture
{
public:
/**
* Creates a cube texture.
* Infers the layout of a cube map from its aspect ratio.
*
* @param w Width of the cube map, in pixels.
* @param h Height of the cube map, in pixels.
*
* @return Inferred cube map layout.
*/
texture_cube();
[[nodiscard]] static cube_map_layout infer_cube_map_layout(std::uint16_t w, std::uint16_t h) noexcept;
/**
* Destroys a cube texture.
* Infers the edge length of a cube map face from its layout and resolution.
*
* @param layout Layout of the cube map.
* @param w Width of the cube map, in pixels.
* @param h Height of the cube map, in pixels.
*
* @return Edge length of the cube map faces, in pixels.
*/
~texture_cube();
/// Returns the linear size of a cube face, in pixels.
int get_face_size() const;
[[nodiscard]] static std::uint16_t infer_cube_map_face_size(cube_map_layout layout, std::uint16_t w, std::uint16_t h) noexcept;
/// Constructs a cube texture.
texture_cube(std::uint16_t width, std::uint16_t height, gl::pixel_type type = gl::pixel_type::uint_8, gl::pixel_format format = gl::pixel_format::rgba, gl::color_space color_space = gl::color_space::linear, const std::byte* data = nullptr);
[[nodiscard]] inline constexpr texture_type get_texture_type() const noexcept override
{
return texture_type::cube;
}
unsigned int gl_texture_id{0};
int face_size{0};
/// @copydoc texture::resize(std::uint16_t, std::uint16_t, gl::pixel_type, gl::pixel_format, gl::color_space, const std::byte*)
void resize(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) override;
/**
* Resizes the texture.
*
* @param width Texture width, in pixels.
* @param height Texture height, in pixels.
* @param data Pointer to pixel data.
*/
void resize(std::uint16_t width, std::uint16_t height, const std::byte* data);
/// @copydoc texture::set_wrapping(gl::texture_wrapping, gl::texture_wrapping, gl::texture_wrapping)
virtual void set_wrapping(gl::texture_wrapping wrap_s, texture_wrapping wrap_t, texture_wrapping wrap_r);
/// Returns the edge length of the cube texture faces, in pixels.
[[nodiscard]] inline std::uint16_t get_face_size() const noexcept
{
return m_face_size;
}
private:
void resized();
std::uint16_t m_face_size{};
};
inline int texture_cube::get_face_size() const
{
return face_size;
}
} // namespace gl
#endif // ANTKEEPER_GL_TEXTURE_CUBE_HPP

+ 45
- 0
src/engine/gl/texture-type.hpp View File

@ -0,0 +1,45 @@
/*
* Copyright (C) 2023 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_GL_TEXTURE_TYPE_HPP
#define ANTKEEPER_GL_TEXTURE_TYPE_HPP
#include <cstdint>
namespace gl {
/// Texture types.
enum class texture_type: std::uint8_t
{
/// 1D texture.
one_dimensional,
/// 2D texture.
two_dimensional,
/// 3D texture.
three_dimensional,
/// Cube texture.
cube,
};
} // namespace gl
#endif // ANTKEEPER_GL_TEXTURE_TYPE_HPP

+ 415
- 67
src/engine/gl/texture.cpp View File

@ -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;
}

+ 75
- 89
src/engine/gl/texture.hpp View File

@ -24,6 +24,7 @@
#include <engine/gl/pixel-format.hpp>
#include <engine/gl/pixel-type.hpp>
#include <engine/gl/texture-filter.hpp>
#include <engine/gl/texture-type.hpp>
#include <engine/gl/texture-wrapping.hpp>
#include <array>
#include <cstdint>
@ -44,29 +45,10 @@ class gl_shader_texture_cube;
class texture
{
public:
/**
* Constructs a texture.
*
* @param width Texture width, in pixels.
* @param height Texture height, in pixels. For 2D or 3D textures.
* @param depth Texture depth, in pixels. For 3D textures only.
* @param type Pixel component data type.
* @param format Pixel format.
* @param color_space Color space of the pixel data.
* @param data Pointer to pixel data.
*
* @warning If the sRGB color space is specified, pixel data will be stored internally as 8 bits per channel, and automatically converted to linear space before reading.
*/
/// @{
texture(std::uint16_t width, std::uint16_t height, std::uint16_t depth, gl::pixel_type type = gl::pixel_type::uint_8, gl::pixel_format format = gl::pixel_format::rgba, gl::color_space color_space = gl::color_space::linear, const std::byte* data = nullptr);
texture(std::uint16_t width, std::uint16_t height, gl::pixel_type type = gl::pixel_type::uint_8, gl::pixel_format format = gl::pixel_format::rgba, gl::color_space color_space = gl::color_space::linear, const std::byte* data = nullptr);
explicit texture(std::uint16_t width, gl::pixel_type type = gl::pixel_type::uint_8, gl::pixel_format format = gl::pixel_format::rgba, gl::color_space color_space = gl::color_space::linear, const std::byte* data = nullptr);
/// @}
/**
* Destructs a texture.
*/
virtual ~texture() = 0;
virtual ~texture();
/**
* Sets the texture filtering modes.
@ -83,37 +65,89 @@ public:
*/
void set_max_anisotropy(float anisotropy);
/// Returns the texture type.
[[nodiscard]] virtual constexpr texture_type get_texture_type() const noexcept = 0;
/// Returns the dimensions of the texture, in pixels.
const std::array<std::uint16_t, 3>& get_dimensions() const;
[[nodiscard]] inline const std::array<std::uint16_t, 3>& get_dimensions() const noexcept
{
return m_dimensions;
}
/// Returns the width of the texture, in pixels.
const std::uint16_t& get_width() const;
[[nodiscard]] inline std::uint16_t get_width() const noexcept
{
return m_dimensions[0];
}
/// Returns the height of the texture, in pixels.
const std::uint16_t& get_height() const;
[[nodiscard]] inline std::uint16_t get_height() const noexcept
{
return m_dimensions[1];
}
/// Returns the depth of the texture, in pixels.
const std::uint16_t& get_depth() const;
[[nodiscard]] inline std::uint16_t get_depth() const noexcept
{
return m_dimensions[2];
}
/// Returns the pixel type enumeration.
const pixel_type& get_pixel_type() const;
[[nodiscard]] inline pixel_type get_pixel_type() const noexcept
{
return m_pixel_type;
}
/// Returns the pixel format enumeration.
const pixel_format& get_pixel_format() const;
[[nodiscard]] inline pixel_format get_pixel_format() const noexcept
{
return m_pixel_format;
}
/// Returns the color space enumeration.
const color_space& get_color_space() const;
[[nodiscard]] inline color_space get_color_space() const noexcept
{
return m_color_space;
}
/// Returns the wrapping modes of the texture.
const std::array<texture_wrapping, 3>& get_wrapping() const;
[[nodiscard]] inline const std::array<texture_wrapping, 3>& get_wrapping() const noexcept
{
return m_wrapping;
}
/// Returns the filtering modes of the texture.
const std::tuple<texture_min_filter, texture_mag_filter>& get_filters() const;
[[nodiscard]] inline const std::tuple<texture_min_filter, texture_mag_filter>& get_filters() const noexcept
{
return m_filters;
}
/// Returns the maximum anisotropy.
float get_max_anisotropy() const;
[[nodiscard]] inline float get_max_anisotropy() const noexcept
{
return m_max_anisotropy;
}
protected:
/**
* Constructs a texture.
*
* @param width Texture width, in pixels.
* @param height Texture height, in pixels. For 2D or 3D textures.
* @param depth Texture depth, in pixels. For 3D textures only.
* @param type Pixel component data type.
* @param format Pixel format.
* @param color_space Color space of the pixel data.
* @param data Pointer to pixel data.
*
* @warning If the sRGB color space is specified, pixel data will be stored internally as 8 bits per channel, and automatically converted to linear space before reading.
*/
/// @{
texture(std::uint16_t width, std::uint16_t height, std::uint16_t depth, bool cube = false, gl::pixel_type type = gl::pixel_type::uint_8, gl::pixel_format format = gl::pixel_format::rgba, gl::color_space color_space = gl::color_space::linear, const std::byte* data = nullptr);
texture(std::uint16_t width, std::uint16_t height, bool cube = false, gl::pixel_type type = gl::pixel_type::uint_8, gl::pixel_format format = gl::pixel_format::rgba, gl::color_space color_space = gl::color_space::linear, const std::byte* data = nullptr);
explicit texture(std::uint16_t width, bool cube = false, gl::pixel_type type = gl::pixel_type::uint_8, gl::pixel_format format = gl::pixel_format::rgba, gl::color_space color_space = gl::color_space::linear, const std::byte* data = nullptr);
/// @}
/**
* Sets the texture wrapping modes.
*
@ -147,73 +181,25 @@ protected:
/// @}
private:
void update_cube_faces(unsigned int gl_internal_format, unsigned int gl_format, unsigned int gl_type, const std::byte* data);
friend class framebuffer;
friend class gl_shader_texture_1d;
friend class gl_shader_texture_2d;
friend class gl_shader_texture_3d;
friend class gl_shader_texture_cube;
unsigned int gl_texture_target{0};
unsigned int gl_texture_id{0};
std::array<std::uint16_t, 3> dimensions{0, 0, 0};
gl::pixel_type pixel_type{0};
gl::pixel_format pixel_format{0};
gl::color_space color_space{0};
std::array<texture_wrapping, 3> wrapping;
std::tuple<texture_min_filter, texture_mag_filter> filters;
float max_anisotropy{0.0f};
unsigned int m_gl_texture_target{};
unsigned int m_gl_texture_id{};
std::array<std::uint16_t, 3> m_dimensions{};
gl::pixel_type m_pixel_type{};
gl::pixel_format m_pixel_format{};
gl::color_space m_color_space{};
std::array<texture_wrapping, 3> m_wrapping{texture_wrapping::repeat, texture_wrapping::repeat, texture_wrapping::repeat};
std::tuple<texture_min_filter, texture_mag_filter> m_filters{texture_min_filter::linear_mipmap_linear, texture_mag_filter::linear};
float m_max_anisotropy{};
};
inline const std::array<std::uint16_t, 3>& texture::get_dimensions() const
{
return dimensions;
}
inline const std::uint16_t& texture::get_width() const
{
return dimensions[0];
}
inline const std::uint16_t& texture::get_height() const
{
return dimensions[1];
}
inline const std::uint16_t& texture::get_depth() const
{
return dimensions[2];
}
inline const pixel_type& texture::get_pixel_type() const
{
return pixel_type;
}
inline const pixel_format& texture::get_pixel_format() const
{
return pixel_format;
}
inline const color_space& texture::get_color_space() const
{
return color_space;
}
inline const std::array<texture_wrapping, 3>& texture::get_wrapping() const
{
return wrapping;
}
inline const std::tuple<texture_min_filter, texture_mag_filter>& texture::get_filters() const
{
return filters;
}
inline float texture::get_max_anisotropy() const
{
return max_anisotropy;
}
} // namespace gl
#endif // ANTKEEPER_GL_TEXTURE_HPP

+ 64
- 1
src/engine/render/material.cpp View File

@ -199,9 +199,68 @@ static bool load_texture_2d_property(resource_manager& resource_manager, render:
return true;
}
static bool load_texture_3d_property(resource_manager& resource_manager, render::material& material, hash::fnv1a32_t key, const nlohmann::json& json)
{
// If JSON element is an array
if (json.is_array())
{
// Create variable
auto variable = std::make_shared<render::material_texture_3d>(json.size());
// Load textures
std::size_t i = 0;
for (const auto& element: json)
{
variable->set(i, resource_manager.load<gl::texture_3d>(element.get<std::string>()));
++i;
}
material.set_variable(key, variable);
}
else
{
// Create variable
auto variable = std::make_shared<render::material_texture_3d>(json.size());
// Load texture
variable->set(resource_manager.load<gl::texture_3d>(json.get<std::string>()));
material.set_variable(key, variable);
}
return true;
}
static bool load_texture_cube_property(resource_manager& resource_manager, render::material& material, hash::fnv1a32_t key, const nlohmann::json& json)
{
return false;
// If JSON element is an array
if (json.is_array())
{
// Create variable
auto variable = std::make_shared<render::material_texture_cube>(json.size());
// Load textures
std::size_t i = 0;
for (const auto& element: json)
{
variable->set(i, resource_manager.load<gl::texture_cube>(element.get<std::string>()));
++i;
}
material.set_variable(key, variable);
}
else
{
// Create variable
auto variable = std::make_shared<render::material_texture_cube>(json.size());
// Load texture
variable->set(resource_manager.load<gl::texture_cube>(json.get<std::string>()));
material.set_variable(key, variable);
}
return true;
}
template <typename T>
@ -445,6 +504,10 @@ std::unique_ptr resource_loader::load(::reso
{
load_texture_2d_property(resource_manager, *material, key, value_element.value());
}
else if (type == "texture_3d")
{
load_texture_3d_property(resource_manager, *material, key, value_element.value());
}
else if (type == "texture_cube")
{
load_texture_cube_property(resource_manager, *material, key, value_element.value());

+ 4
- 1
src/engine/scene/light-type.hpp View File

@ -40,7 +40,10 @@ enum class light_type: std::uint8_t
point,
/// Rectangle light.
rectangle
rectangle,
/// Sky light.
sky
};
} // namespace scene

+ 25
- 0
src/engine/scene/sky-light.cpp View File

@ -0,0 +1,25 @@
/*
* Copyright (C) 2023 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include <engine/scene/sky-light.hpp>
namespace scene {
} // namespace scene

+ 47
- 0
src/engine/scene/sky-light.hpp View File

@ -0,0 +1,47 @@
/*
* Copyright (C) 2023 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_SCENE_SKY_LIGHT_HPP
#define ANTKEEPER_SCENE_SKY_LIGHT_HPP
#include <engine/scene/light.hpp>
#include <engine/math/vector.hpp>
namespace scene {
/**
*
*/
class sky_light: public light
{
public:
[[nodiscard]] inline light_type get_light_type() const noexcept override
{
return light_type::sky;
}
private:
};
} // namespace scene
#endif // ANTKEEPER_SCENE_SKY_LIGHT_HPP

+ 2
- 2
src/game/states/main-menu-state.cpp View File

@ -129,8 +129,8 @@ main_menu_state::main_menu_state(::game& ctx, bool fade_in):
[&ctx]()
{
ctx.state_machine.pop();
//ctx.state_machine.emplace(std::make_unique<nuptial_flight_state>(ctx));
//ctx.state_machine.emplace(std::make_unique<collection_menu_state>(ctx));
// ctx.state_machine.emplace(std::make_unique<nuptial_flight_state>(ctx));
// ctx.state_machine.emplace(std::make_unique<collection_menu_state>(ctx));
// ctx.state_machine.emplace(std::make_unique<nest_selection_state>(ctx));
ctx.state_machine.emplace(std::make_unique<nest_view_state>(ctx));
}

+ 15
- 2
src/game/states/nest-view-state.cpp View File

@ -193,7 +193,7 @@ nest_view_state::nest_view_state(::game& ctx):
larva_eid,
[&](auto& component)
{
component.object->set_translation({-10.0f, -1.5f, -10.0f});
component.object->set_translation({5.0f, 0.0f, 5.0f});
}
);
@ -206,7 +206,20 @@ nest_view_state::nest_view_state(::game& ctx):
suzanne_eid,
[&](auto& component)
{
component.object->set_translation({-13.0f, 0.5f, -6.0f});
component.object->set_translation({0.0f, 0.0f, 0.0f});
}
);
// Create sphere
auto sphere_eid = ctx.entity_registry->create();
auto sphere_static_mesh = std::make_shared<scene::static_mesh>(ctx.resource_manager->load<render::model>("sphere.mdl"));
ctx.entity_registry->emplace<scene_component>(sphere_eid, std::move(sphere_static_mesh), std::uint8_t{2});
ctx.entity_registry->patch<scene_component>
(
sphere_eid,
[&](auto& component)
{
component.object->set_translation({0.0f, 0.0f, 0.0f});
}
);

Loading…
Cancel
Save