Browse Source

Add 1D and 3D texture types. Add support for loading 1D textures

master
C. J. Howard 2 years ago
parent
commit
f77cfde13e
19 changed files with 973 additions and 311 deletions
  1. +0
    -1
      src/entity/components/model.hpp
  2. +3
    -3
      src/game/state/nuptial-flight.cpp
  3. +98
    -0
      src/gl/shader-input.cpp
  4. +8
    -0
      src/gl/shader-input.hpp
  5. +13
    -0
      src/gl/shader-program.cpp
  6. +2
    -0
      src/gl/shader-variable-type.hpp
  7. +41
    -0
      src/gl/texture-1d.cpp
  8. +48
    -0
      src/gl/texture-1d.hpp
  9. +7
    -181
      src/gl/texture-2d.cpp
  10. +10
    -122
      src/gl/texture-2d.hpp
  11. +41
    -0
      src/gl/texture-3d.cpp
  12. +48
    -0
      src/gl/texture-3d.hpp
  13. +0
    -1
      src/gl/texture-cube.hpp
  14. +6
    -0
      src/gl/texture-filter.hpp
  15. +267
    -0
      src/gl/texture.cpp
  16. +212
    -0
      src/gl/texture.hpp
  17. +14
    -0
      src/render/material-property.hpp
  18. +39
    -3
      src/resources/material-loader.cpp
  19. +116
    -0
      src/resources/texture-loader.cpp

+ 0
- 1
src/entity/components/model.hpp View File

@ -38,4 +38,3 @@ struct model
} // namespace entity } // namespace entity
#endif // ANTKEEPER_ENTITY_COMPONENT_MODEL_HPP #endif // ANTKEEPER_ENTITY_COMPONENT_MODEL_HPP

+ 3
- 3
src/game/state/nuptial-flight.cpp View File

@ -58,8 +58,8 @@ nuptial_flight::nuptial_flight(game::context& ctx):
ant::breed breed; ant::breed breed;
// Load morphological traits // Load morphological traits
breed.head = ctx.resource_manager->load<ant::trait::head>("square-harvester-head.dna");
breed.mandibles = ctx.resource_manager->load<ant::trait::mandibles>("harvester-mandibles.dna");
breed.head = ctx.resource_manager->load<ant::trait::head>("miller-head.dna");
breed.mandibles = ctx.resource_manager->load<ant::trait::mandibles>("miller-mandibles.dna");
breed.antennae = ctx.resource_manager->load<ant::trait::antennae>("slender-antennae.dna"); breed.antennae = ctx.resource_manager->load<ant::trait::antennae>("slender-antennae.dna");
breed.eyes = ctx.resource_manager->load<ant::trait::eyes>("oval-eyes.dna"); breed.eyes = ctx.resource_manager->load<ant::trait::eyes>("oval-eyes.dna");
breed.mesosoma = ctx.resource_manager->load<ant::trait::mesosoma>("humpback-mesosoma.dna"); breed.mesosoma = ctx.resource_manager->load<ant::trait::mesosoma>("humpback-mesosoma.dna");
@ -264,7 +264,7 @@ void nuptial_flight::setup_camera()
ctx.entity_registry->assign<entity::component::constraint_stack>(camera_eid, constraint_stack); ctx.entity_registry->assign<entity::component::constraint_stack>(camera_eid, constraint_stack);
} }
float ev100 = 14.0f;
float ev100 = 14.5f;
ctx.surface_camera->set_exposure(ev100); ctx.surface_camera->set_exposure(ev100);
} }

+ 98
- 0
src/gl/shader-input.cpp View File

@ -18,7 +18,9 @@
*/ */
#include "gl/shader-input.hpp" #include "gl/shader-input.hpp"
#include "gl/texture-1d.hpp"
#include "gl/texture-2d.hpp" #include "gl/texture-2d.hpp"
#include "gl/texture-3d.hpp"
#include "gl/texture-cube.hpp" #include "gl/texture-cube.hpp"
#include <glad/glad.h> #include <glad/glad.h>
@ -211,6 +213,21 @@ bool shader_input::upload(const float4x4& value) const
return true; return true;
} }
bool shader_input::upload(const texture_1d* value) const
{
if (gl_uniform_location == -1)
return false;
// Bind texture to a texture unit reserved by this shader input
glActiveTexture(GL_TEXTURE0 + texture_unit);
glBindTexture(GL_TEXTURE_1D, value->gl_texture_id);
// Upload texture unit index to shader
glUniform1i(gl_uniform_location, texture_unit);
return true;
}
bool shader_input::upload(const texture_2d* value) const bool shader_input::upload(const texture_2d* value) const
{ {
if (gl_uniform_location == -1) if (gl_uniform_location == -1)
@ -226,6 +243,21 @@ bool shader_input::upload(const texture_2d* value) const
return true; return true;
} }
bool shader_input::upload(const texture_3d* value) const
{
if (gl_uniform_location == -1)
return false;
// Bind texture to a texture unit reserved by this shader input
glActiveTexture(GL_TEXTURE0 + texture_unit);
glBindTexture(GL_TEXTURE_3D, value->gl_texture_id);
// Upload texture unit index to shader
glUniform1i(gl_uniform_location, texture_unit);
return true;
}
bool shader_input::upload(const texture_cube* value) const bool shader_input::upload(const texture_cube* value) const
{ {
if (gl_uniform_location == -1) if (gl_uniform_location == -1)
@ -415,6 +447,21 @@ bool shader_input::upload(std::size_t index, const float4x4& value) const
return true; return true;
} }
bool shader_input::upload(std::size_t index, const texture_1d* value) const
{
if (gl_uniform_location == -1)
return false;
// Bind texture to a texture unit reserved by this shader input
glActiveTexture(GL_TEXTURE0 + texture_unit + static_cast<int>(index));
glBindTexture(GL_TEXTURE_1D, value->gl_texture_id);
// Upload texture unit index to shader
glUniform1i(gl_uniform_location + static_cast<int>(index), texture_unit + static_cast<int>(index));
return true;
}
bool shader_input::upload(std::size_t index, const texture_2d* value) const bool shader_input::upload(std::size_t index, const texture_2d* value) const
{ {
if (gl_uniform_location == -1) if (gl_uniform_location == -1)
@ -430,6 +477,21 @@ bool shader_input::upload(std::size_t index, const texture_2d* value) const
return true; return true;
} }
bool shader_input::upload(std::size_t index, const texture_3d* value) const
{
if (gl_uniform_location == -1)
return false;
// Bind texture to a texture unit reserved by this shader input
glActiveTexture(GL_TEXTURE0 + texture_unit + static_cast<int>(index));
glBindTexture(GL_TEXTURE_3D, value->gl_texture_id);
// Upload texture unit index to shader
glUniform1i(gl_uniform_location + static_cast<int>(index), texture_unit + static_cast<int>(index));
return true;
}
bool shader_input::upload(std::size_t index, const texture_cube* value) const bool shader_input::upload(std::size_t index, const texture_cube* value) const
{ {
if (gl_uniform_location == -1) if (gl_uniform_location == -1)
@ -636,6 +698,24 @@ bool shader_input::upload(std::size_t index, const float4x4* values, std::size_t
return true; return true;
} }
bool shader_input::upload(std::size_t index, const texture_1d** values, std::size_t count) const
{
if (gl_uniform_location == -1)
return false;
for (std::size_t i = 0; i < count; ++i)
{
// Bind texture to a texture unit reserved by this shader input
glActiveTexture(GL_TEXTURE0 + texture_unit + static_cast<int>(index + i));
glBindTexture(GL_TEXTURE_1D, values[i]->gl_texture_id);
// Upload texture unit index to shader
glUniform1i(gl_uniform_location + static_cast<int>(index + i), texture_unit + static_cast<int>(index + i));
}
return true;
}
bool shader_input::upload(std::size_t index, const texture_2d** values, std::size_t count) const bool shader_input::upload(std::size_t index, const texture_2d** values, std::size_t count) const
{ {
if (gl_uniform_location == -1) if (gl_uniform_location == -1)
@ -654,6 +734,24 @@ bool shader_input::upload(std::size_t index, const texture_2d** values, std::siz
return true; return true;
} }
bool shader_input::upload(std::size_t index, const texture_3d** values, std::size_t count) const
{
if (gl_uniform_location == -1)
return false;
for (std::size_t i = 0; i < count; ++i)
{
// Bind texture to a texture unit reserved by this shader input
glActiveTexture(GL_TEXTURE0 + texture_unit + static_cast<int>(index + i));
glBindTexture(GL_TEXTURE_3D, values[i]->gl_texture_id);
// Upload texture unit index to shader
glUniform1i(gl_uniform_location + static_cast<int>(index + i), texture_unit + static_cast<int>(index + i));
}
return true;
}
bool shader_input::upload(std::size_t index, const texture_cube** values, std::size_t count) const bool shader_input::upload(std::size_t index, const texture_cube** values, std::size_t count) const
{ {
if (gl_uniform_location == -1) if (gl_uniform_location == -1)

+ 8
- 0
src/gl/shader-input.hpp View File

@ -26,7 +26,9 @@
namespace gl { namespace gl {
class shader_program; class shader_program;
class texture_1d;
class texture_2d; class texture_2d;
class texture_3d;
class texture_cube; class texture_cube;
enum class shader_variable_type; enum class shader_variable_type;
@ -77,7 +79,9 @@ public:
bool upload(const float2x2& value) const; bool upload(const float2x2& value) const;
bool upload(const float3x3& value) const; bool upload(const float3x3& value) const;
bool upload(const float4x4& value) const; bool upload(const float4x4& value) const;
bool upload(const texture_1d* value) const;
bool upload(const texture_2d* value) const; bool upload(const texture_2d* value) const;
bool upload(const texture_3d* value) const;
bool upload(const texture_cube* value) const; bool upload(const texture_cube* value) const;
///@} ///@}
@ -108,7 +112,9 @@ public:
bool upload(std::size_t index, const float2x2& value) const; bool upload(std::size_t index, const float2x2& value) const;
bool upload(std::size_t index, const float3x3& value) const; bool upload(std::size_t index, const float3x3& value) const;
bool upload(std::size_t index, const float4x4& value) const; bool upload(std::size_t index, const float4x4& value) const;
bool upload(std::size_t index, const texture_1d* value) const;
bool upload(std::size_t index, const texture_2d* value) const; bool upload(std::size_t index, const texture_2d* value) const;
bool upload(std::size_t index, const texture_3d* value) const;
bool upload(std::size_t index, const texture_cube* value) const; bool upload(std::size_t index, const texture_cube* value) const;
///@} ///@}
@ -140,7 +146,9 @@ public:
bool upload(std::size_t index, const float2x2* values, std::size_t count) const; bool upload(std::size_t index, const float2x2* values, std::size_t count) const;
bool upload(std::size_t index, const float3x3* values, std::size_t count) const; bool upload(std::size_t index, const float3x3* values, std::size_t count) const;
bool upload(std::size_t index, const float4x4* values, std::size_t count) const; bool upload(std::size_t index, const float4x4* values, std::size_t count) const;
bool upload(std::size_t index, const texture_1d** values, std::size_t count) const;
bool upload(std::size_t index, const texture_2d** values, std::size_t count) const; bool upload(std::size_t index, const texture_2d** values, std::size_t count) const;
bool upload(std::size_t index, const texture_3d** values, std::size_t count) const;
bool upload(std::size_t index, const texture_cube** values, std::size_t count) const; bool upload(std::size_t index, const texture_cube** values, std::size_t count) const;
///@} ///@}

+ 13
- 0
src/gl/shader-program.cpp View File

@ -267,6 +267,13 @@ void shader_program::find_inputs()
case GL_FLOAT_MAT4: case GL_FLOAT_MAT4:
variable_type = shader_variable_type::float4x4; variable_type = shader_variable_type::float4x4;
break; break;
case GL_SAMPLER_1D:
case GL_SAMPLER_1D_SHADOW:
variable_type = shader_variable_type::texture_1d;
texture_unit = available_texture_unit;
available_texture_unit += uniform_size;
break;
case GL_SAMPLER_2D: case GL_SAMPLER_2D:
case GL_SAMPLER_2D_SHADOW: case GL_SAMPLER_2D_SHADOW:
@ -275,6 +282,12 @@ void shader_program::find_inputs()
available_texture_unit += uniform_size; available_texture_unit += uniform_size;
break; break;
case GL_SAMPLER_3D:
variable_type = shader_variable_type::texture_3d;
texture_unit = available_texture_unit;
available_texture_unit += uniform_size;
break;
case GL_SAMPLER_CUBE: case GL_SAMPLER_CUBE:
variable_type = shader_variable_type::texture_cube; variable_type = shader_variable_type::texture_cube;
texture_unit = available_texture_unit; texture_unit = available_texture_unit;

+ 2
- 0
src/gl/shader-variable-type.hpp View File

@ -43,7 +43,9 @@ enum class shader_variable_type
float2x2, float2x2,
float3x3, float3x3,
float4x4, float4x4,
texture_1d,
texture_2d, texture_2d,
texture_3d,
texture_cube texture_cube
}; };

+ 41
- 0
src/gl/texture-1d.cpp View File

@ -0,0 +1,41 @@
/*
* Copyright (C) 2021 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 "gl/texture-1d.hpp"
namespace gl {
texture_1d::texture_1d(std::uint16_t width, gl::pixel_type type, gl::pixel_format format, gl::color_space color_space, const void* data):
texture(width, type, format, color_space, data)
{}
texture_1d::~texture_1d()
{}
void texture_1d::resize(std::uint16_t width, gl::pixel_type type, gl::pixel_format format, gl::color_space color_space, const void* data)
{
texture::resize(width, type, format, color_space, data);
}
void texture_1d::set_wrapping(gl::texture_wrapping wrap_s)
{
texture::set_wrapping(wrap_s);
}
} // namespace gl

+ 48
- 0
src/gl/texture-1d.hpp View File

@ -0,0 +1,48 @@
/*
* Copyright (C) 2021 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_1D_HPP
#define ANTKEEPER_GL_TEXTURE_1D_HPP
#include "gl/texture.hpp"
namespace gl {
/**
* A 1D texture which can be uploaded to shaders via shader inputs.
*/
class texture_1d: public texture
{
public:
/// @copydoc texture::texture(std::uint16_t, gl::pixel_type, gl::pixel_format, gl::color_space, const void*)
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 void* data = nullptr);
/// Destructs a 1D texture.
virtual ~texture_1d();
/// @copydoc texture::resize(std::uint16_t, gl::pixel_type, gl::pixel_format, gl::color_space, const void*)
virtual void resize(std::uint16_t width, gl::pixel_type type, gl::pixel_format format, gl::color_space color_space, const void* data);
/// @copydoc texture::set_wrapping(gl::texture_wrapping)
virtual void set_wrapping(gl::texture_wrapping wrap_s);
};
} // namespace gl
#endif // ANTKEEPER_GL_TEXTURE_1D_HPP

+ 7
- 181
src/gl/texture-2d.cpp View File

@ -18,198 +18,24 @@
*/ */
#include "gl/texture-2d.hpp" #include "gl/texture-2d.hpp"
#include "gl/texture-wrapping.hpp"
#include "gl/texture-filter.hpp"
#include <glad/glad.h>
#include <algorithm>
namespace gl { namespace gl {
static constexpr GLenum pixel_format_lut[] =
{
GL_DEPTH_COMPONENT,
GL_DEPTH_STENCIL,
GL_RED,
GL_RG,
GL_RGB,
GL_BGR,
GL_RGBA,
GL_BGRA
};
static constexpr GLenum pixel_type_lut[] =
{
GL_BYTE,
GL_UNSIGNED_BYTE,
GL_SHORT,
GL_UNSIGNED_SHORT,
GL_INT,
GL_UNSIGNED_INT,
GL_HALF_FLOAT,
GL_FLOAT
};
static constexpr GLenum linear_internal_format_lut[][8] =
{
{GL_NONE, GL_NONE, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT32, GL_NONE, GL_DEPTH_COMPONENT32F},
// Note: GL_DEPTH32F_STENCIL8 is actually a 64-bit format, 32 depth bits, 8 stencil bits, and 24 alignment bits.
{GL_NONE, GL_NONE, GL_NONE, GL_NONE, GL_DEPTH24_STENCIL8, GL_DEPTH24_STENCIL8, GL_NONE, GL_DEPTH32F_STENCIL8},
{GL_R8, GL_R8, GL_R16, GL_R16, GL_R32F, GL_R32F, GL_R16F, GL_R32F},
{GL_RG8, GL_RG8, GL_RG16, GL_RG16, GL_RG32F, GL_RG32F, GL_RG16F, GL_RG32F},
{GL_RGB8, GL_RGB8, GL_RGB16, GL_RGB16, GL_RGB32F, GL_RGB32F, GL_RGB16F, GL_RGB32F},
{GL_RGB8, GL_RGB8, GL_RGB16, GL_RGB16, GL_RGB32F, GL_RGB32F, GL_RGB16F, GL_RGB32F},
{GL_RGBA8, GL_RGBA8, GL_RGBA16, GL_RGBA16, GL_RGBA32F, GL_RGBA32F, GL_RGBA16F, GL_RGBA32F},
{GL_RGBA8, GL_RGBA8, GL_RGBA16, GL_RGBA16, GL_RGBA32F, GL_RGBA32F, GL_RGBA16F, GL_RGBA32F}
};
static constexpr GLenum srgb_internal_format_lut[][8] =
{
{GL_NONE, GL_NONE, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT32, GL_NONE, GL_DEPTH_COMPONENT32F},
{GL_NONE, GL_NONE, GL_NONE, GL_NONE, GL_DEPTH24_STENCIL8, GL_DEPTH24_STENCIL8, GL_NONE, GL_DEPTH32F_STENCIL8},
{GL_SRGB8, GL_SRGB8, GL_R16, GL_R16, GL_R32F, GL_R32F, GL_R16F, GL_R32F},
{GL_SRGB8, GL_SRGB8, GL_RG16, GL_RG16, GL_RG32F, GL_RG32F, GL_RG16F, GL_RG32F},
{GL_SRGB8, GL_SRGB8, GL_RGB16, GL_RGB16, GL_RGB32F, GL_RGB32F, GL_RGB16F, GL_RGB32F},
{GL_SRGB8, GL_SRGB8, GL_RGB16, GL_RGB16, GL_RGB32F, GL_RGB32F, GL_RGB16F, GL_RGB32F},
{GL_SRGB8_ALPHA8, GL_SRGB8_ALPHA8, GL_RGBA16, GL_RGBA16, GL_RGBA32F, GL_RGBA32F, GL_RGBA16F, GL_RGBA32F},
{GL_SRGB8_ALPHA8, GL_SRGB8_ALPHA8, GL_RGBA16, GL_RGBA16, GL_RGBA32F, GL_RGBA32F, GL_RGBA16F, GL_RGBA32F}
};
static constexpr GLint swizzle_mask_lut[][4] =
{
{GL_RED, GL_RED, GL_RED, GL_ONE},
{GL_RED, GL_GREEN, GL_ZERO, GL_ONE},
{GL_RED, GL_RED, GL_RED, GL_ONE},
{GL_RED, GL_RED, GL_RED, GL_GREEN},
{GL_RED, GL_GREEN, GL_BLUE, GL_ONE},
{GL_RED, GL_GREEN, GL_BLUE, GL_ONE},
{GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA},
{GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}
};
static constexpr GLenum wrapping_lut[] =
{
GL_CLAMP_TO_BORDER,
GL_CLAMP_TO_EDGE,
GL_REPEAT,
GL_MIRRORED_REPEAT
};
static constexpr GLenum min_filter_lut[] =
{
GL_NEAREST,
GL_LINEAR,
GL_NEAREST_MIPMAP_NEAREST,
GL_LINEAR_MIPMAP_NEAREST,
GL_NEAREST_MIPMAP_LINEAR,
GL_LINEAR_MIPMAP_LINEAR
};
static constexpr GLenum mag_filter_lut[] =
{
GL_NEAREST,
GL_LINEAR
};
texture_2d::texture_2d(int width, int height, gl::pixel_type type, gl::pixel_format format, gl::color_space color_space, const void* data):
gl_texture_id(0),
dimensions({0, 0}),
wrapping({texture_wrapping::repeat, texture_wrapping::repeat}),
filters({texture_min_filter::linear_mipmap_linear, texture_mag_filter::linear}),
max_anisotropy(0.0f)
{
glGenTextures(1, &gl_texture_id);
resize(width, height, type, format, color_space, data);
set_wrapping(std::get<0>(wrapping), std::get<1>(wrapping));
set_filters(std::get<0>(filters), std::get<1>(filters));
set_max_anisotropy(max_anisotropy);
}
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 void* data):
texture(width, height, type, format, color_space, data)
{}
texture_2d::~texture_2d() texture_2d::~texture_2d()
{
glDeleteTextures(1, &gl_texture_id);
}
{}
void texture_2d::resize(int width, int height, gl::pixel_type type, gl::pixel_format format, gl::color_space color_space, const void* 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 void* data)
{ {
dimensions = {width, height};
pixel_type = type;
pixel_format = format;
this->color_space = color_space;
GLenum gl_internal_format;
if (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)];
}
else
{
gl_internal_format = linear_internal_format_lut[static_cast<std::size_t>(format)][static_cast<std::size_t>(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_type = pixel_type_lut[static_cast<std::size_t>(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_2D, gl_texture_id);
glTexImage2D(GL_TEXTURE_2D, 0, gl_internal_format, width, height, 0, gl_format, gl_type, data);
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, gl_swizzle_mask);
/// TODO: remove this
if (format == pixel_format::d)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
}
texture::resize(width, height, type, format, color_space, data);
} }
void texture_2d::set_wrapping(gl::texture_wrapping wrap_s, texture_wrapping wrap_t) void texture_2d::set_wrapping(gl::texture_wrapping wrap_s, texture_wrapping wrap_t)
{ {
wrapping = {wrap_s, 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)];
glBindTexture(GL_TEXTURE_2D, gl_texture_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gl_wrap_s);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gl_wrap_t);
}
void texture_2d::set_filters(texture_min_filter min_filter, texture_mag_filter mag_filter)
{
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)];
glBindTexture(GL_TEXTURE_2D, gl_texture_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_min_filter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_mag_filter);
}
void texture_2d::set_max_anisotropy(float anisotropy)
{
this->max_anisotropy = std::max<float>(0.0f, std::min<float>(1.0f, anisotropy));
// Lerp between 1.0f and GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
float gl_max_texture_max_anisotropy;
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gl_max_texture_max_anisotropy);
float gl_max_anisotropy = 1.0f + this->max_anisotropy * (gl_max_texture_max_anisotropy - 1.0f);
glBindTexture(GL_TEXTURE_2D, gl_texture_id);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_max_anisotropy);
texture::set_wrapping(wrap_s, wrap_t);
} }
} // namespace gl } // namespace gl

+ 10
- 122
src/gl/texture-2d.hpp View File

@ -20,141 +20,29 @@
#ifndef ANTKEEPER_GL_TEXTURE_2D_HPP #ifndef ANTKEEPER_GL_TEXTURE_2D_HPP
#define ANTKEEPER_GL_TEXTURE_2D_HPP #define ANTKEEPER_GL_TEXTURE_2D_HPP
#include <array>
#include <tuple>
#include "gl/color-space.hpp"
#include "gl/pixel-format.hpp"
#include "gl/pixel-type.hpp"
#include "gl/texture.hpp"
namespace gl { namespace gl {
class framebuffer;
class shader_input;
enum class texture_mag_filter;
enum class texture_min_filter;
enum class texture_wrapping;
/** /**
* A 2D texture which can be uploaded to shaders via shader inputs. * A 2D texture which can be uploaded to shaders via shader inputs.
*/ */
class texture_2d
class texture_2d: public texture
{ {
public: public:
/**
* Creates a 2D texture.
*
* @param color_space Specifies the color space of the 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_2d(int width, int 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 void* data = nullptr);
/**
* Destroys a 2D texture.
*/
~texture_2d();
/**
* Resizes the texture.
*
* @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.
*/
void resize(int width, int height, gl::pixel_type type, gl::pixel_format format, gl::color_space color_space, const void* data);
/**
* Sets the texture wrapping modes.
*
* @param wrap_s Wrapping mode for s-coordinates.
* @param wrap_t Wrapping mode for t-coordinates.
*/
void set_wrapping(gl::texture_wrapping wrap_s, texture_wrapping wrap_t);
/**
* Sets the texture filtering modes.
*
* @param min_filter Texture minification filter.
* @param mag_filter Texture magnification filter.
*/
void set_filters(texture_min_filter min_filter, texture_mag_filter mag_filter);
/**
* Sets the maximum anisotropy.
*
* @param level Max anisotropy on `[0.0, 1.0]`, with `0.0` indicating normal filtering, and `1.0` indicating maximum anisotropic filtering.
*/
void set_max_anisotropy(float anisotropy);
/// Returns the dimensions of the texture, in pixels.
const std::array<int, 2>& get_dimensions() const;
/// @copydoc texture::texture(std::uint16_t, std::uint16_t, gl::pixel_type, gl::pixel_format, gl::color_space, const void*)
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 void* data = nullptr);
/// Returns the pixel type enumeration.
const pixel_type& get_pixel_type() const;
/// Destructs a 2D texture.
virtual ~texture_2d();
/// Returns the pixel format enumeration.
const pixel_format& get_pixel_format() const;
/// @copydoc texture::resize(std::uint16_t, std::uint16_t, gl::pixel_type, gl::pixel_format, gl::color_space, const void*)
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 void* data);
/// Returns the color space enumeration.
const color_space& get_color_space() const;
/// Returns the wrapping modes of the texture.
const std::tuple<texture_wrapping, texture_wrapping> get_wrapping() const;
/// Returns the filtering modes of the texture.
const std::tuple<texture_min_filter, texture_mag_filter> get_filters() const;
/// Returns the maximum anisotropy.
float get_max_anisotropy() const;
private:
friend class framebuffer;
friend class shader_input;
unsigned int gl_texture_id;
std::array<int, 2> dimensions;
gl::pixel_type pixel_type;
gl::pixel_format pixel_format;
gl::color_space color_space;
std::tuple<texture_wrapping, texture_wrapping> wrapping;
std::tuple<texture_min_filter, texture_mag_filter> filters;
float max_anisotropy;
/// @copydoc texture::set_wrapping(gl::texture_wrapping, gl::texture_wrapping)
virtual void set_wrapping(gl::texture_wrapping wrap_s, texture_wrapping wrap_t);
}; };
inline const std::array<int, 2>& texture_2d::get_dimensions() const
{
return dimensions;
}
inline const pixel_type& texture_2d::get_pixel_type() const
{
return pixel_type;
}
inline const pixel_format& texture_2d::get_pixel_format() const
{
return pixel_format;
}
inline const color_space& texture_2d::get_color_space() const
{
return color_space;
}
inline const std::tuple<texture_wrapping, texture_wrapping> texture_2d::get_wrapping() const
{
return wrapping;
}
inline const std::tuple<texture_min_filter, texture_mag_filter> texture_2d::get_filters() const
{
return filters;
}
inline float texture_2d::get_max_anisotropy() const
{
return max_anisotropy;
}
} // namespace gl } // namespace gl
#endif // ANTKEEPER_GL_TEXTURE_2D_HPP #endif // ANTKEEPER_GL_TEXTURE_2D_HPP

+ 41
- 0
src/gl/texture-3d.cpp View File

@ -0,0 +1,41 @@
/*
* Copyright (C) 2021 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 "gl/texture-3d.hpp"
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 void* data):
texture(width, height, depth, type, format, color_space, data)
{}
texture_3d::~texture_3d()
{}
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 void* data)
{
texture::resize(width, height, depth, type, format, color_space, data);
}
void texture_3d::set_wrapping(gl::texture_wrapping wrap_s, texture_wrapping wrap_t, texture_wrapping wrap_r)
{
texture::set_wrapping(wrap_s, wrap_t, wrap_r);
}
} // namespace gl

+ 48
- 0
src/gl/texture-3d.hpp View File

@ -0,0 +1,48 @@
/*
* Copyright (C) 2021 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_3D_HPP
#define ANTKEEPER_GL_TEXTURE_3D_HPP
#include "gl/texture.hpp"
namespace gl {
/**
* A 3D texture which can be uploaded to shaders via shader inputs.
*/
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 void*)
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 void* data = nullptr);
/// Destructs a 3D texture.
virtual ~texture_3d();
/// @copydoc texture::resize(std::uint16_t, std::uint16_t, std::uint16_t, gl::pixel_type, gl::pixel_format, gl::color_space, const void*)
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 void* 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);
};
} // namespace gl
#endif // ANTKEEPER_GL_TEXTURE_3D_HPP

+ 0
- 1
src/gl/texture-cube.hpp View File

@ -58,4 +58,3 @@ inline int texture_cube::get_face_size() const
} // namespace gl } // namespace gl
#endif // ANTKEEPER_GL_TEXTURE_CUBE_HPP #endif // ANTKEEPER_GL_TEXTURE_CUBE_HPP

+ 6
- 0
src/gl/texture-filter.hpp View File

@ -22,6 +22,9 @@
namespace gl { namespace gl {
/**
* Texture minification filter modes.
*/
enum class texture_min_filter enum class texture_min_filter
{ {
nearest, nearest,
@ -32,6 +35,9 @@ enum class texture_min_filter
linear_mipmap_linear linear_mipmap_linear
}; };
/**
* Texture magnification filter modes.
*/
enum class texture_mag_filter enum class texture_mag_filter
{ {
nearest, nearest,

+ 267
- 0
src/gl/texture.cpp View File

@ -0,0 +1,267 @@
/*
* Copyright (C) 2021 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 "gl/texture.hpp"
#include "gl/texture-wrapping.hpp"
#include "gl/texture-filter.hpp"
#include <glad/glad.h>
#include <algorithm>
namespace gl {
static constexpr GLenum pixel_format_lut[] =
{
GL_DEPTH_COMPONENT,
GL_DEPTH_STENCIL,
GL_RED,
GL_RG,
GL_RGB,
GL_BGR,
GL_RGBA,
GL_BGRA
};
static constexpr GLenum pixel_type_lut[] =
{
GL_BYTE,
GL_UNSIGNED_BYTE,
GL_SHORT,
GL_UNSIGNED_SHORT,
GL_INT,
GL_UNSIGNED_INT,
GL_HALF_FLOAT,
GL_FLOAT
};
static constexpr GLenum linear_internal_format_lut[][8] =
{
{GL_NONE, GL_NONE, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT32, GL_NONE, GL_DEPTH_COMPONENT32F},
// Note: GL_DEPTH32F_STENCIL8 is actually a 64-bit format, 32 depth bits, 8 stencil bits, and 24 alignment bits.
{GL_NONE, GL_NONE, GL_NONE, GL_NONE, GL_DEPTH24_STENCIL8, GL_DEPTH24_STENCIL8, GL_NONE, GL_DEPTH32F_STENCIL8},
{GL_R8, GL_R8, GL_R16, GL_R16, GL_R32F, GL_R32F, GL_R16F, GL_R32F},
{GL_RG8, GL_RG8, GL_RG16, GL_RG16, GL_RG32F, GL_RG32F, GL_RG16F, GL_RG32F},
{GL_RGB8, GL_RGB8, GL_RGB16, GL_RGB16, GL_RGB32F, GL_RGB32F, GL_RGB16F, GL_RGB32F},
{GL_RGB8, GL_RGB8, GL_RGB16, GL_RGB16, GL_RGB32F, GL_RGB32F, GL_RGB16F, GL_RGB32F},
{GL_RGBA8, GL_RGBA8, GL_RGBA16, GL_RGBA16, GL_RGBA32F, GL_RGBA32F, GL_RGBA16F, GL_RGBA32F},
{GL_RGBA8, GL_RGBA8, GL_RGBA16, GL_RGBA16, GL_RGBA32F, GL_RGBA32F, GL_RGBA16F, GL_RGBA32F}
};
static constexpr GLenum srgb_internal_format_lut[][8] =
{
{GL_NONE, GL_NONE, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT32, GL_NONE, GL_DEPTH_COMPONENT32F},
{GL_NONE, GL_NONE, GL_NONE, GL_NONE, GL_DEPTH24_STENCIL8, GL_DEPTH24_STENCIL8, GL_NONE, GL_DEPTH32F_STENCIL8},
{GL_SRGB8, GL_SRGB8, GL_R16, GL_R16, GL_R32F, GL_R32F, GL_R16F, GL_R32F},
{GL_SRGB8, GL_SRGB8, GL_RG16, GL_RG16, GL_RG32F, GL_RG32F, GL_RG16F, GL_RG32F},
{GL_SRGB8, GL_SRGB8, GL_RGB16, GL_RGB16, GL_RGB32F, GL_RGB32F, GL_RGB16F, GL_RGB32F},
{GL_SRGB8, GL_SRGB8, GL_RGB16, GL_RGB16, GL_RGB32F, GL_RGB32F, GL_RGB16F, GL_RGB32F},
{GL_SRGB8_ALPHA8, GL_SRGB8_ALPHA8, GL_RGBA16, GL_RGBA16, GL_RGBA32F, GL_RGBA32F, GL_RGBA16F, GL_RGBA32F},
{GL_SRGB8_ALPHA8, GL_SRGB8_ALPHA8, GL_RGBA16, GL_RGBA16, GL_RGBA32F, GL_RGBA32F, GL_RGBA16F, GL_RGBA32F}
};
static constexpr GLint swizzle_mask_lut[][4] =
{
{GL_RED, GL_RED, GL_RED, GL_ONE},
{GL_RED, GL_GREEN, GL_ZERO, GL_ONE},
{GL_RED, GL_RED, GL_RED, GL_ONE},
{GL_RED, GL_RED, GL_RED, GL_GREEN},
{GL_RED, GL_GREEN, GL_BLUE, GL_ONE},
{GL_RED, GL_GREEN, GL_BLUE, GL_ONE},
{GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA},
{GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}
};
static constexpr GLenum wrapping_lut[] =
{
GL_CLAMP_TO_BORDER,
GL_CLAMP_TO_EDGE,
GL_REPEAT,
GL_MIRRORED_REPEAT
};
static constexpr GLenum min_filter_lut[] =
{
GL_NEAREST,
GL_LINEAR,
GL_NEAREST_MIPMAP_NEAREST,
GL_LINEAR_MIPMAP_NEAREST,
GL_NEAREST_MIPMAP_LINEAR,
GL_LINEAR_MIPMAP_LINEAR
};
static constexpr GLenum mag_filter_lut[] =
{
GL_NEAREST,
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 void* 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)
{
glGenTextures(1, &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);
}
texture::texture(std::uint16_t width, std::uint16_t height, gl::pixel_type type, gl::pixel_format format, gl::color_space color_space, const void* data):
texture(width, height, 0, 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 void* data):
texture(width, 0, 0, type, format, color_space, data)
{}
texture::~texture()
{
glDeleteTextures(1, &gl_texture_id);
}
void texture::set_filters(texture_min_filter min_filter, texture_mag_filter mag_filter)
{
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)];
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);
}
void texture::set_max_anisotropy(float anisotropy)
{
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);
glBindTexture(gl_texture_target, gl_texture_id);
glTexParameterf(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};
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)];
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);
}
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;
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)];
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);
}
void texture::set_wrapping(gl::texture_wrapping wrap_s)
{
std::get<0>(wrapping) = wrap_s;
GLenum gl_wrap_s = wrapping_lut[static_cast<std::size_t>(wrap_s)];
glBindTexture(gl_texture_target, gl_texture_id);
glTexParameteri(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 void* data)
{
dimensions = {width, height, depth};
pixel_type = type;
pixel_format = format;
this->color_space = color_space;
GLenum gl_internal_format;
if (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)];
}
else
{
gl_internal_format = linear_internal_format_lut[static_cast<std::size_t>(format)][static_cast<std::size_t>(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_type = pixel_type_lut[static_cast<std::size_t>(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);
glGenerateMipmap(gl_texture_target);
glTexParameteriv(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);
}
}
void texture::resize(std::uint16_t width, std::uint16_t height, gl::pixel_type type, gl::pixel_format format, gl::color_space color_space, const void* data)
{
resize(width, height, 0, type, format, color_space, data);
}
void texture::resize(std::uint16_t width, gl::pixel_type type, gl::pixel_format format, gl::color_space color_space, const void* data)
{
resize(width, 0, 0, type, format, color_space, data);
}
} // namespace gl

+ 212
- 0
src/gl/texture.hpp View File

@ -0,0 +1,212 @@
/*
* Copyright (C) 2021 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_HPP
#define ANTKEEPER_GL_TEXTURE_HPP
#include "gl/color-space.hpp"
#include "gl/pixel-format.hpp"
#include "gl/pixel-type.hpp"
#include "gl/texture-filter.hpp"
#include "gl/texture-wrapping.hpp"
#include <array>
#include <cstdint>
#include <tuple>
namespace gl {
class framebuffer;
class shader_input;
/**
* Abstract base class for 1D, 2D, 3D, and cube textures which can be uploaded to shaders via shader inputs.
*/
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 void* 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 void* data = nullptr);
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 void* data = nullptr);
/// @}
/**
* Destructs a texture.
*/
virtual ~texture() = 0;
/**
* Sets the texture filtering modes.
*
* @param min_filter Texture minification filter mode.
* @param mag_filter Texture magnification filter mode.
*/
void set_filters(texture_min_filter min_filter, texture_mag_filter mag_filter);
/**
* Sets the maximum anisotropy.
*
* @param level Max anisotropy on `[0.0, 1.0]`, with `0.0` indicating normal filtering, and `1.0` indicating maximum anisotropic filtering.
*/
void set_max_anisotropy(float anisotropy);
/// Returns the dimensions of the texture, in pixels.
const std::array<std::uint16_t, 3>& get_dimensions() const;
/// Returns the width of the texture, in pixels.
const std::uint16_t& get_width() const;
/// Returns the height of the texture, in pixels.
const std::uint16_t& get_height() const;
/// Returns the depth of the texture, in pixels.
const std::uint16_t& get_depth() const;
/// Returns the pixel type enumeration.
const pixel_type& get_pixel_type() const;
/// Returns the pixel format enumeration.
const pixel_format& get_pixel_format() const;
/// Returns the color space enumeration.
const color_space& get_color_space() const;
/// Returns the wrapping modes of the texture.
const std::array<texture_wrapping, 3>& get_wrapping() const;
/// Returns the filtering modes of the texture.
const std::tuple<texture_min_filter, texture_mag_filter>& get_filters() const;
/// Returns the maximum anisotropy.
float get_max_anisotropy() const;
protected:
/**
* Sets the texture wrapping modes.
*
* @param wrap_s Wrapping mode for s-coordinates.
* @param wrap_t Wrapping mode for t-coordinates.
* @param wrap_r Wrapping mode for r-coordinates.
*/
/// @{
virtual void set_wrapping(gl::texture_wrapping wrap_s, gl::texture_wrapping wrap_t, gl::texture_wrapping wrap_r);
virtual void set_wrapping(gl::texture_wrapping wrap_s, gl::texture_wrapping wrap_t);
virtual void set_wrapping(gl::texture_wrapping wrap_s);
/// @}
/**
* Resizes the 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.
*/
/// @{
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 void* data);
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 void* data);
virtual void resize(std::uint16_t width, gl::pixel_type type, gl::pixel_format format, gl::color_space color_space, const void* data);
/// @}
private:
friend class framebuffer;
friend class shader_input;
unsigned int gl_texture_target;
unsigned int gl_texture_id;
std::array<std::uint16_t, 3> dimensions;
gl::pixel_type pixel_type;
gl::pixel_format pixel_format;
gl::color_space color_space;
std::array<texture_wrapping, 3> wrapping;
std::tuple<texture_min_filter, texture_mag_filter> filters;
float 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

+ 14
- 0
src/render/material-property.hpp View File

@ -26,7 +26,9 @@
#include "math/interpolation.hpp" #include "math/interpolation.hpp"
#include "utility/fundamental-types.hpp" #include "utility/fundamental-types.hpp"
#include "gl/shader-program.hpp" #include "gl/shader-program.hpp"
#include "gl/texture-1d.hpp"
#include "gl/texture-2d.hpp" #include "gl/texture-2d.hpp"
#include "gl/texture-3d.hpp"
#include "gl/texture-cube.hpp" #include "gl/texture-cube.hpp"
#include <cstddef> #include <cstddef>
@ -415,12 +417,24 @@ inline gl::shader_variable_type material_property::get_data_type() con
return gl::shader_variable_type::float4x4; return gl::shader_variable_type::float4x4;
} }
template <>
inline gl::shader_variable_type material_property<const gl::texture_1d*>::get_data_type() const
{
return gl::shader_variable_type::texture_1d;
}
template <> template <>
inline gl::shader_variable_type material_property<const gl::texture_2d*>::get_data_type() const inline gl::shader_variable_type material_property<const gl::texture_2d*>::get_data_type() const
{ {
return gl::shader_variable_type::texture_2d; return gl::shader_variable_type::texture_2d;
} }
template <>
inline gl::shader_variable_type material_property<const gl::texture_3d*>::get_data_type() const
{
return gl::shader_variable_type::texture_3d;
}
template <> template <>
inline gl::shader_variable_type material_property<const gl::texture_cube*>::get_data_type() const inline gl::shader_variable_type material_property<const gl::texture_cube*>::get_data_type() const
{ {

+ 39
- 3
src/resources/material-loader.cpp View File

@ -39,6 +39,40 @@ static bool read_value(T* value, const nlohmann::json& json, const std::string&
return false; return false;
} }
static bool load_texture_1d_property(resource_manager* resource_manager, render::material* material, const std::string& name, const nlohmann::json& json)
{
// If JSON element is an array
if (json.is_array())
{
// Determine size of the array
std::size_t array_size = json.size();
// Create property
render::material_property<const gl::texture_1d*>* property = material->add_property<const gl::texture_1d*>(name, array_size);
// Load textures
std::size_t i = 0;
for (const auto& element: json)
{
std::string filename = element.get<std::string>();
const gl::texture_1d* texture = resource_manager->load<gl::texture_1d>(filename);
property->set_value(i++, texture);
}
}
else
{
// Create property
render::material_property<const gl::texture_1d*>* property = material->add_property<const gl::texture_1d*>(name);
// Load texture
std::string filename = json.get<std::string>();
const gl::texture_1d* texture = resource_manager->load<gl::texture_1d>(filename);
property->set_value(texture);
}
return true;
}
static bool load_texture_2d_property(resource_manager* resource_manager, render::material* material, const std::string& name, const nlohmann::json& json) static bool load_texture_2d_property(resource_manager* resource_manager, render::material* material, const std::string& name, const nlohmann::json& json)
{ {
// If JSON element is an array // If JSON element is an array
@ -315,12 +349,14 @@ render::material* resource_loader::load(resource_manager* reso
// Ignore valueless properties // Ignore valueless properties
continue; continue;
// If property type is a 2D texture
if (type == "texture_2d")
if (type == "texture_1d")
{
load_texture_1d_property(resource_manager, material, name, value_element.value());
}
else if (type == "texture_2d")
{ {
load_texture_2d_property(resource_manager, material, name, value_element.value()); load_texture_2d_property(resource_manager, material, name, value_element.value());
} }
// If property type is a cubic texture
else if (type == "texture_cube") else if (type == "texture_cube")
{ {
load_texture_cube_property(resource_manager, material, name, value_element.value()); load_texture_cube_property(resource_manager, material, name, value_element.value());

+ 116
- 0
src/resources/texture-loader.cpp View File

@ -23,13 +23,127 @@
#include "gl/pixel-type.hpp" #include "gl/pixel-type.hpp"
#include "gl/pixel-format.hpp" #include "gl/pixel-format.hpp"
#include "gl/color-space.hpp" #include "gl/color-space.hpp"
#include "gl/texture-1d.hpp"
#include "gl/texture-2d.hpp" #include "gl/texture-2d.hpp"
#include "gl/texture-wrapping.hpp" #include "gl/texture-wrapping.hpp"
#include "gl/texture-filter.hpp" #include "gl/texture-filter.hpp"
#include <sstream> #include <sstream>
#include <stdexcept>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <physfs.h> #include <physfs.h>
template <>
gl::texture_1d* resource_loader<gl::texture_1d>::load(resource_manager* resource_manager, PHYSFS_File* file, const std::filesystem::path& path)
{
// Read file into buffer
std::size_t size = static_cast<int>(PHYSFS_fileLength(file));
std::string buffer;
buffer.resize(size);
PHYSFS_readBytes(file, &buffer[0], size);
// Parse json from file buffer
nlohmann::json json = nlohmann::json::parse(buffer);
// Read image filename
std::string image_filename;
if (auto element = json.find("image"); element != json.end())
image_filename = element.value().get<std::string>();
// Read color space
gl::color_space color_space = gl::color_space::linear;
if (auto element = json.find("color_space"); element != json.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.find("extension"); element != json.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.find("interpolation"); element != json.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.find("max_anisotropy"); element != json.end())
max_anisotropy = element.value().get<float>();
// Load image
::image* image = resource_manager->load<::image>(image_filename);
// Determine pixel type
gl::pixel_type type = (image->get_component_size() == sizeof(float)) ? gl::pixel_type::float_32 : gl::pixel_type::uint_8;
// Determine pixel format
gl::pixel_format format;
if (image->get_channel_count() == 1)
{
format = gl::pixel_format::r;
}
else if (image->get_channel_count() == 2)
{
format = gl::pixel_format::rg;
}
else if (image->get_channel_count() == 3)
{
format = gl::pixel_format::rgb;
}
else if (image->get_channel_count() == 4)
{
format = gl::pixel_format::rgba;
}
else
{
std::stringstream stream;
stream << std::string("Texture cannot be created from an image with an unsupported number of channels (") << image->get_channel_count() << std::string(").");
delete image;
throw std::runtime_error(stream.str().c_str());
}
// Create texture
gl::texture_1d* texture = new gl::texture_1d(image->get_width(), type, format, color_space, image->get_pixels());
// Set wrapping and filtering
texture->set_wrapping(wrapping);
texture->set_filters(min_filter, mag_filter);
texture->set_max_anisotropy(max_anisotropy);
// Free loaded image
resource_manager->unload(image_filename);
return texture;
}
template <> template <>
gl::texture_2d* resource_loader<gl::texture_2d>::load(resource_manager* resource_manager, PHYSFS_File* file, const std::filesystem::path& path) gl::texture_2d* resource_loader<gl::texture_2d>::load(resource_manager* resource_manager, PHYSFS_File* file, const std::filesystem::path& path)
{ {
@ -141,3 +255,5 @@ gl::texture_2d* resource_loader::load(resource_manager* resource
return texture; return texture;
} }

Loading…
Cancel
Save