@ -1,116 +0,0 @@ | |||
/* | |||
* 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/geom/csg.hpp> | |||
#include <tuple> | |||
namespace geom { | |||
namespace csg { | |||
enum class polygon_classification | |||
{ | |||
coplanar, | |||
front, | |||
back, | |||
spanning | |||
}; | |||
/** | |||
* Classifies a polygon relative to a partitioning plane. | |||
* | |||
* @param partition Partitioning plane relative to which the polygon should be classified. | |||
* @param poly Polygon to be classified. | |||
* @return Classification of the polygon, relative to the plane. | |||
*/ | |||
static polygon_classification classify_polygon(const plane& partition, const polygon& poly) | |||
{ | |||
for (const float3& vertex: poly.vertices) | |||
{ | |||
} | |||
return polygon_classification::coplanar; | |||
} | |||
/** | |||
* Splits a polygon along a partitioning plane. | |||
* | |||
* @param poly Polygon to split. | |||
* @param partition Partitioning plane along which the polygon should be split. | |||
* @return List of polygons which were formed by splitting the specified polygon along the partitioning plane, along with their respective classifications relative to the partition. | |||
*/ | |||
std::list<std::tuple<polygon, polygon_classification>> split_polygon(const polygon& poly, const plane& partition) | |||
{ | |||
return {}; | |||
} | |||
bsp_tree::bsp_tree(const std::list<polygon>& polygons): | |||
front(nullptr), | |||
back(nullptr) | |||
{ | |||
//partition = polygons.front(); | |||
std::list<polygon> front_polygons; | |||
std::list<polygon> back_polygons; | |||
// Classify all polygons relative to this node's partitioning plane | |||
for (const polygon& p: polygons) | |||
{ | |||
polygon_classification classification = classify_polygon(partition, p); | |||
switch (classification) | |||
{ | |||
case polygon_classification::coplanar: | |||
coplanar_polygons.push_back(p); | |||
break; | |||
case polygon_classification::front: | |||
front_polygons.push_back(p); | |||
break; | |||
case polygon_classification::back: | |||
back_polygons.push_back(p); | |||
break; | |||
case polygon_classification::spanning: | |||
break; | |||
} | |||
} | |||
if (!front_polygons.empty()) | |||
{ | |||
// Make subtree containing all polygons in front of this node's plane | |||
front = new bsp_tree(front_polygons); | |||
} | |||
if (!back_polygons.empty()) | |||
{ | |||
// Make subtree containing all polygons behind this node's plane | |||
back = new bsp_tree(back_polygons); | |||
} | |||
} | |||
bsp_tree::~bsp_tree() | |||
{ | |||
delete front; | |||
delete back; | |||
} | |||
} // namespace csg | |||
} // namespace geom |
@ -1,88 +0,0 @@ | |||
/* | |||
* 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_GEOM_CSG_HPP | |||
#define ANTKEEPER_GEOM_CSG_HPP | |||
#include <engine/utility/fundamental-types.hpp> | |||
#include <list> | |||
namespace geom { | |||
/// Constructive solid geometry (CSG) | |||
namespace csg { | |||
struct plane | |||
{ | |||
float3 normal; | |||
float distance; | |||
}; | |||
struct polygon | |||
{ | |||
std::list<float3> vertices; | |||
void* shared; | |||
}; | |||
/** | |||
* 3D solid represented by a collection of polygons. | |||
*/ | |||
typedef std::list<polygon> solid; | |||
/** | |||
* BSP tree node. | |||
*/ | |||
class bsp_tree | |||
{ | |||
public: | |||
/** | |||
* Recursively constructs a BSP tree from a collection of polygons. | |||
* | |||
* @param polygons Collection of polygons from which to create the BSP tree. | |||
*/ | |||
explicit bsp_tree(const std::list<polygon>& polygons); | |||
/** | |||
* Destroys a BSP tree. | |||
*/ | |||
~bsp_tree(); | |||
private: | |||
/// Partition which separates the front and back polygons. | |||
plane partition; | |||
/// Set of polygons which are coplanar with the partition. | |||
std::list<polygon> coplanar_polygons; | |||
/// Subtree containing all polygons in front of the partition. | |||
bsp_tree* front; | |||
/// Subtree containing all polygons behind the partition. | |||
bsp_tree* back; | |||
}; | |||
solid op_union(const solid& a, const solid& b); | |||
solid op_difference(const solid& a, const solid& b); | |||
solid op_intersect(const solid& a, const solid& b); | |||
} // namespace csg | |||
} // namespace geom | |||
#endif // ANTKEEPER_GEOM_CSG_HPP | |||
@ -0,0 +1,666 @@ | |||
/* | |||
* 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/gl/opengl/gl-shader-variables.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 <numeric> | |||
namespace gl { | |||
gl_shader_bool::gl_shader_bool(std::size_t size, GLint gl_uniform_location): | |||
shader_variable(size), | |||
gl_uniform_location{gl_uniform_location}, | |||
ivalues(size) | |||
{} | |||
void gl_shader_bool::update(bool value) const noexcept | |||
{ | |||
glUniform1i(gl_uniform_location, static_cast<GLint>(value)); | |||
} | |||
void gl_shader_bool::update(bool value, std::size_t index) const | |||
{ | |||
glUniform1i(gl_uniform_location + static_cast<GLint>(index), static_cast<GLint>(value)); | |||
} | |||
void gl_shader_bool::update(std::span<const bool> values, std::size_t index) const | |||
{ | |||
for (std::size_t i = 0; i < values.size(); ++i) | |||
{ | |||
ivalues[i] = static_cast<GLint>(values[i]); | |||
} | |||
glUniform1iv(gl_uniform_location + static_cast<GLint>(index), static_cast<GLsizei>(values.size()), ivalues.data()); | |||
} | |||
gl_shader_bool2::gl_shader_bool2(std::size_t size, GLint gl_uniform_location): | |||
shader_variable(size), | |||
gl_uniform_location{gl_uniform_location}, | |||
ivalues(size * 2) | |||
{} | |||
void gl_shader_bool2::update(const bool2& value) const noexcept | |||
{ | |||
glUniform2i(gl_uniform_location, static_cast<GLint>(value[0]), static_cast<GLint>(value[1])); | |||
} | |||
void gl_shader_bool2::update(const bool2& value, std::size_t index) const | |||
{ | |||
glUniform2i(gl_uniform_location + static_cast<GLint>(index), static_cast<GLint>(value[0]), static_cast<GLint>(value[1])); | |||
} | |||
void gl_shader_bool2::update(std::span<const bool2> values, std::size_t index) const | |||
{ | |||
GLint* ivalue = ivalues.data(); | |||
for (const auto& value: values) | |||
{ | |||
*(++ivalue) = static_cast<GLint>(value[0]); | |||
*(++ivalue) = static_cast<GLint>(value[1]); | |||
} | |||
glUniform2iv(gl_uniform_location + static_cast<GLint>(index), static_cast<GLsizei>(values.size()), ivalues.data()); | |||
} | |||
gl_shader_bool3::gl_shader_bool3(std::size_t size, GLint gl_uniform_location): | |||
shader_variable(size), | |||
gl_uniform_location{gl_uniform_location}, | |||
ivalues(size * 3) | |||
{} | |||
void gl_shader_bool3::update(const bool3& value) const noexcept | |||
{ | |||
glUniform3i(gl_uniform_location, static_cast<GLint>(value[0]), static_cast<GLint>(value[1]), static_cast<GLint>(value[2])); | |||
} | |||
void gl_shader_bool3::update(const bool3& value, std::size_t index) const | |||
{ | |||
glUniform3i(gl_uniform_location + static_cast<GLint>(index), static_cast<GLint>(value[0]), static_cast<GLint>(value[1]), static_cast<GLint>(value[2])); | |||
} | |||
void gl_shader_bool3::update(std::span<const bool3> values, std::size_t index) const | |||
{ | |||
GLint* ivalue = ivalues.data(); | |||
for (const auto& value: values) | |||
{ | |||
*(++ivalue) = static_cast<GLint>(value[0]); | |||
*(++ivalue) = static_cast<GLint>(value[1]); | |||
*(++ivalue) = static_cast<GLint>(value[2]); | |||
} | |||
glUniform3iv(gl_uniform_location + static_cast<GLint>(index), static_cast<GLsizei>(values.size()), ivalues.data()); | |||
} | |||
gl_shader_bool4::gl_shader_bool4(std::size_t size, GLint gl_uniform_location): | |||
shader_variable(size), | |||
gl_uniform_location{gl_uniform_location}, | |||
ivalues(size * 4) | |||
{} | |||
void gl_shader_bool4::update(const bool4& value) const noexcept | |||
{ | |||
glUniform4i(gl_uniform_location, static_cast<GLint>(value[0]), static_cast<GLint>(value[1]), static_cast<GLint>(value[2]), static_cast<GLint>(value[3])); | |||
} | |||
void gl_shader_bool4::update(const bool4& value, std::size_t index) const | |||
{ | |||
glUniform4i(gl_uniform_location + static_cast<GLint>(index), static_cast<GLint>(value[0]), static_cast<GLint>(value[1]), static_cast<GLint>(value[2]), static_cast<GLint>(value[3])); | |||
} | |||
void gl_shader_bool4::update(std::span<const bool4> values, std::size_t index) const | |||
{ | |||
GLint* ivalue = ivalues.data(); | |||
for (const auto& value: values) | |||
{ | |||
*(++ivalue) = static_cast<GLint>(value[0]); | |||
*(++ivalue) = static_cast<GLint>(value[1]); | |||
*(++ivalue) = static_cast<GLint>(value[2]); | |||
*(++ivalue) = static_cast<GLint>(value[3]); | |||
} | |||
glUniform4iv(gl_uniform_location + static_cast<GLint>(index), static_cast<GLsizei>(values.size()), ivalues.data()); | |||
} | |||
gl_shader_int::gl_shader_int(std::size_t size, GLint gl_uniform_location): | |||
shader_variable(size), | |||
gl_uniform_location{gl_uniform_location} | |||
{} | |||
void gl_shader_int::update(int value) const noexcept | |||
{ | |||
glUniform1i(gl_uniform_location, value); | |||
} | |||
void gl_shader_int::update(int value, std::size_t index) const | |||
{ | |||
glUniform1i(gl_uniform_location + static_cast<GLint>(index), value); | |||
} | |||
void gl_shader_int::update(std::span<const int> values, std::size_t index) const | |||
{ | |||
glUniform1iv(gl_uniform_location + static_cast<GLint>(index), static_cast<GLsizei>(values.size()), values.data()); | |||
} | |||
gl_shader_int2::gl_shader_int2(std::size_t size, GLint gl_uniform_location): | |||
shader_variable(size), | |||
gl_uniform_location{gl_uniform_location} | |||
{} | |||
void gl_shader_int2::update(const int2& value) const noexcept | |||
{ | |||
glUniform2iv(gl_uniform_location, 1, value.data()); | |||
} | |||
void gl_shader_int2::update(const int2& value, std::size_t index) const | |||
{ | |||
glUniform2iv(gl_uniform_location + static_cast<GLint>(index), 1, value.data()); | |||
} | |||
void gl_shader_int2::update(std::span<const int2> values, std::size_t index) const | |||
{ | |||
glUniform2iv(gl_uniform_location + static_cast<GLint>(index), static_cast<GLsizei>(values.size()), values.data()->data()); | |||
} | |||
gl_shader_int3::gl_shader_int3(std::size_t size, GLint gl_uniform_location): | |||
shader_variable(size), | |||
gl_uniform_location{gl_uniform_location} | |||
{} | |||
void gl_shader_int3::update(const int3& value) const noexcept | |||
{ | |||
glUniform3iv(gl_uniform_location, 1, value.data()); | |||
} | |||
void gl_shader_int3::update(const int3& value, std::size_t index) const | |||
{ | |||
glUniform3iv(gl_uniform_location + static_cast<GLint>(index), 1, value.data()); | |||
} | |||
void gl_shader_int3::update(std::span<const int3> values, std::size_t index) const | |||
{ | |||
glUniform3iv(gl_uniform_location + static_cast<GLint>(index), static_cast<GLsizei>(values.size()), values.data()->data()); | |||
} | |||
gl_shader_int4::gl_shader_int4(std::size_t size, GLint gl_uniform_location): | |||
shader_variable(size), | |||
gl_uniform_location{gl_uniform_location} | |||
{} | |||
void gl_shader_int4::update(const int4& value) const noexcept | |||
{ | |||
glUniform4iv(gl_uniform_location, 1, value.data()); | |||
} | |||
void gl_shader_int4::update(const int4& value, std::size_t index) const | |||
{ | |||
glUniform4iv(gl_uniform_location + static_cast<GLint>(index), 1, value.data()); | |||
} | |||
void gl_shader_int4::update(std::span<const int4> values, std::size_t index) const | |||
{ | |||
glUniform4iv(gl_uniform_location + static_cast<GLint>(index), static_cast<GLsizei>(values.size()), values.data()->data()); | |||
} | |||
gl_shader_uint::gl_shader_uint(std::size_t size, GLint gl_uniform_location): | |||
shader_variable(size), | |||
gl_uniform_location{gl_uniform_location} | |||
{} | |||
void gl_shader_uint::update(unsigned int value) const noexcept | |||
{ | |||
glUniform1ui(gl_uniform_location, value); | |||
} | |||
void gl_shader_uint::update(unsigned int value, std::size_t index) const | |||
{ | |||
glUniform1ui(gl_uniform_location + static_cast<GLint>(index), value); | |||
} | |||
void gl_shader_uint::update(std::span<const unsigned int> values, std::size_t index) const | |||
{ | |||
glUniform1uiv(gl_uniform_location + static_cast<GLint>(index), static_cast<GLsizei>(values.size()), values.data()); | |||
} | |||
gl_shader_uint2::gl_shader_uint2(std::size_t size, GLint gl_uniform_location): | |||
shader_variable(size), | |||
gl_uniform_location{gl_uniform_location} | |||
{} | |||
void gl_shader_uint2::update(const uint2& value) const noexcept | |||
{ | |||
glUniform2uiv(gl_uniform_location, 1, value.data()); | |||
} | |||
void gl_shader_uint2::update(const uint2& value, std::size_t index) const | |||
{ | |||
glUniform2uiv(gl_uniform_location + static_cast<GLint>(index), 1, value.data()); | |||
} | |||
void gl_shader_uint2::update(std::span<const uint2> values, std::size_t index) const | |||
{ | |||
glUniform2uiv(gl_uniform_location + static_cast<GLint>(index), static_cast<GLsizei>(values.size()), values.data()->data()); | |||
} | |||
gl_shader_uint3::gl_shader_uint3(std::size_t size, GLint gl_uniform_location): | |||
shader_variable(size), | |||
gl_uniform_location{gl_uniform_location} | |||
{} | |||
void gl_shader_uint3::update(const uint3& value) const noexcept | |||
{ | |||
glUniform3uiv(gl_uniform_location, 1, value.data()); | |||
} | |||
void gl_shader_uint3::update(const uint3& value, std::size_t index) const | |||
{ | |||
glUniform3uiv(gl_uniform_location + static_cast<GLint>(index), 1, value.data()); | |||
} | |||
void gl_shader_uint3::update(std::span<const uint3> values, std::size_t index) const | |||
{ | |||
glUniform3uiv(gl_uniform_location + static_cast<GLint>(index), static_cast<GLsizei>(values.size()), values.data()->data()); | |||
} | |||
gl_shader_uint4::gl_shader_uint4(std::size_t size, GLint gl_uniform_location): | |||
shader_variable(size), | |||
gl_uniform_location{gl_uniform_location} | |||
{} | |||
void gl_shader_uint4::update(const uint4& value) const noexcept | |||
{ | |||
glUniform4uiv(gl_uniform_location, 1, value.data()); | |||
} | |||
void gl_shader_uint4::update(const uint4& value, std::size_t index) const | |||
{ | |||
glUniform4uiv(gl_uniform_location + static_cast<GLint>(index), 1, value.data()); | |||
} | |||
void gl_shader_uint4::update(std::span<const uint4> values, std::size_t index) const | |||
{ | |||
glUniform4uiv(gl_uniform_location + static_cast<GLint>(index), static_cast<GLsizei>(values.size()), values.data()->data()); | |||
} | |||
gl_shader_float::gl_shader_float(std::size_t size, GLint gl_uniform_location): | |||
shader_variable(size), | |||
gl_uniform_location{gl_uniform_location} | |||
{} | |||
void gl_shader_float::update(float value) const noexcept | |||
{ | |||
glUniform1f(gl_uniform_location, value); | |||
} | |||
void gl_shader_float::update(float value, std::size_t index) const | |||
{ | |||
glUniform1f(gl_uniform_location + static_cast<GLint>(index), value); | |||
} | |||
void gl_shader_float::update(std::span<const float> values, std::size_t index) const | |||
{ | |||
glUniform1fv(gl_uniform_location + static_cast<GLint>(index), static_cast<GLsizei>(values.size()), values.data()); | |||
} | |||
gl_shader_float2::gl_shader_float2(std::size_t size, GLint gl_uniform_location): | |||
shader_variable(size), | |||
gl_uniform_location{gl_uniform_location} | |||
{} | |||
void gl_shader_float2::update(const float2& value) const noexcept | |||
{ | |||
glUniform2fv(gl_uniform_location, 1, value.data()); | |||
} | |||
void gl_shader_float2::update(const float2& value, std::size_t index) const | |||
{ | |||
glUniform2fv(gl_uniform_location + static_cast<GLint>(index), 1, value.data()); | |||
} | |||
void gl_shader_float2::update(std::span<const float2> values, std::size_t index) const | |||
{ | |||
glUniform2fv(gl_uniform_location + static_cast<GLint>(index), static_cast<GLsizei>(values.size()), values.data()->data()); | |||
} | |||
gl_shader_float3::gl_shader_float3(std::size_t size, GLint gl_uniform_location): | |||
shader_variable(size), | |||
gl_uniform_location{gl_uniform_location} | |||
{} | |||
void gl_shader_float3::update(const float3& value) const noexcept | |||
{ | |||
glUniform3fv(gl_uniform_location, 1, value.data()); | |||
} | |||
void gl_shader_float3::update(const float3& value, std::size_t index) const | |||
{ | |||
glUniform3fv(gl_uniform_location + static_cast<GLint>(index), 1, value.data()); | |||
} | |||
void gl_shader_float3::update(std::span<const float3> values, std::size_t index) const | |||
{ | |||
glUniform3fv(gl_uniform_location + static_cast<GLint>(index), static_cast<GLsizei>(values.size()), values.data()->data()); | |||
} | |||
gl_shader_float4::gl_shader_float4(std::size_t size, GLint gl_uniform_location): | |||
shader_variable(size), | |||
gl_uniform_location{gl_uniform_location} | |||
{} | |||
void gl_shader_float4::update(const float4& value) const noexcept | |||
{ | |||
glUniform4fv(gl_uniform_location, 1, value.data()); | |||
} | |||
void gl_shader_float4::update(const float4& value, std::size_t index) const | |||
{ | |||
glUniform4fv(gl_uniform_location + static_cast<GLint>(index), 1, value.data()); | |||
} | |||
void gl_shader_float4::update(std::span<const float4> values, std::size_t index) const | |||
{ | |||
glUniform4fv(gl_uniform_location + static_cast<GLint>(index), static_cast<GLsizei>(values.size()), values.data()->data()); | |||
} | |||
gl_shader_float2x2::gl_shader_float2x2(std::size_t size, GLint gl_uniform_location): | |||
shader_variable(size), | |||
gl_uniform_location{gl_uniform_location} | |||
{} | |||
void gl_shader_float2x2::update(const float2x2& value) const noexcept | |||
{ | |||
glUniformMatrix2fv(gl_uniform_location, 1, GL_FALSE, value.data()); | |||
} | |||
void gl_shader_float2x2::update(const float2x2& value, std::size_t index) const | |||
{ | |||
glUniformMatrix2fv(gl_uniform_location + static_cast<GLint>(index) * 2, 1, GL_FALSE, value.data()); | |||
} | |||
void gl_shader_float2x2::update(std::span<const float2x2> values, std::size_t index) const | |||
{ | |||
glUniformMatrix2fv(gl_uniform_location + static_cast<GLint>(index) * 2, static_cast<GLsizei>(values.size()), GL_FALSE, values.data()->data()); | |||
} | |||
gl_shader_float3x3::gl_shader_float3x3(std::size_t size, GLint gl_uniform_location): | |||
shader_variable(size), | |||
gl_uniform_location{gl_uniform_location} | |||
{} | |||
void gl_shader_float3x3::update(const float3x3& value) const noexcept | |||
{ | |||
glUniformMatrix3fv(gl_uniform_location, 1, GL_FALSE, value.data()); | |||
} | |||
void gl_shader_float3x3::update(const float3x3& value, std::size_t index) const | |||
{ | |||
glUniformMatrix3fv(gl_uniform_location + static_cast<GLint>(index) * 3, 1, GL_FALSE, value.data()); | |||
} | |||
void gl_shader_float3x3::update(std::span<const float3x3> values, std::size_t index) const | |||
{ | |||
glUniformMatrix3fv(gl_uniform_location + static_cast<GLint>(index) * 3, static_cast<GLsizei>(values.size()), GL_FALSE, values.data()->data()); | |||
} | |||
gl_shader_float4x4::gl_shader_float4x4(std::size_t size, GLint gl_uniform_location): | |||
shader_variable(size), | |||
gl_uniform_location{gl_uniform_location} | |||
{} | |||
void gl_shader_float4x4::update(const float4x4& value) const noexcept | |||
{ | |||
glUniformMatrix4fv(gl_uniform_location, 1, GL_FALSE, value.data()); | |||
} | |||
void gl_shader_float4x4::update(const float4x4& value, std::size_t index) const | |||
{ | |||
glUniformMatrix4fv(gl_uniform_location + static_cast<GLint>(index) * 4, 1, GL_FALSE, value.data()); | |||
} | |||
void gl_shader_float4x4::update(std::span<const float4x4> values, std::size_t index) const | |||
{ | |||
glUniformMatrix4fv(gl_uniform_location + static_cast<GLint>(index) * 4, static_cast<GLsizei>(values.size()), GL_FALSE, values.data()->data()); | |||
} | |||
gl_shader_texture_1d::gl_shader_texture_1d(std::size_t size, GLint gl_uniform_location, GLint gl_first_texture_unit_index): | |||
shader_variable(size), | |||
gl_uniform_location{gl_uniform_location}, | |||
gl_texture_unit_indices(size) | |||
{ | |||
std::iota(gl_texture_unit_indices.begin(), gl_texture_unit_indices.end(), gl_first_texture_unit_index); | |||
} | |||
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); | |||
// Pass texture unit index to shader | |||
glUniform1i(gl_uniform_location, gl_texture_unit_indices.front()); | |||
} | |||
void gl_shader_texture_1d::update(const texture_1d& value, std::size_t index) const | |||
{ | |||
const GLint gl_texture_index = gl_texture_unit_indices[index]; | |||
// Bind texture to texture unit | |||
glActiveTexture(GL_TEXTURE0 + static_cast<GLenum>(gl_texture_index)); | |||
glBindTexture(GL_TEXTURE_1D, value.gl_texture_id); | |||
// Pass texture unit index to shader | |||
glUniform1i(gl_uniform_location + static_cast<GLint>(index), gl_texture_index); | |||
} | |||
void gl_shader_texture_1d::update(std::span<const texture_1d* const> values, std::size_t index) const | |||
{ | |||
// Bind textures | |||
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); | |||
} | |||
// Pass texture unit indices to shader | |||
glUniform1iv(gl_uniform_location + static_cast<GLint>(index), static_cast<GLsizei>(values.size()), &gl_texture_unit_indices[index]); | |||
} | |||
void gl_shader_texture_1d::update(std::span<const std::shared_ptr<texture_1d>> values, std::size_t index) const | |||
{ | |||
// Bind textures | |||
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); | |||
} | |||
// Pass texture unit indices to shader | |||
glUniform1iv(gl_uniform_location + static_cast<GLint>(index), static_cast<GLsizei>(values.size()), &gl_texture_unit_indices[index]); | |||
} | |||
gl_shader_texture_2d::gl_shader_texture_2d(std::size_t size, GLint gl_uniform_location, GLint gl_first_texture_unit_index): | |||
shader_variable(size), | |||
gl_uniform_location{gl_uniform_location}, | |||
gl_texture_unit_indices(size) | |||
{ | |||
std::iota(gl_texture_unit_indices.begin(), gl_texture_unit_indices.end(), gl_first_texture_unit_index); | |||
} | |||
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); | |||
// Pass texture unit index to shader | |||
glUniform1i(gl_uniform_location, gl_texture_unit_indices.front()); | |||
} | |||
void gl_shader_texture_2d::update(const texture_2d& value, std::size_t index) const | |||
{ | |||
const GLint gl_texture_index = gl_texture_unit_indices[index]; | |||
// Bind texture to texture unit | |||
glActiveTexture(GL_TEXTURE0 + static_cast<GLenum>(gl_texture_index)); | |||
glBindTexture(GL_TEXTURE_2D, value.gl_texture_id); | |||
// Pass texture unit index to shader | |||
glUniform1i(gl_uniform_location + static_cast<GLint>(index), gl_texture_index); | |||
} | |||
void gl_shader_texture_2d::update(std::span<const texture_2d* const> values, std::size_t index) const | |||
{ | |||
// Bind textures | |||
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); | |||
} | |||
// Pass texture unit indices to shader | |||
glUniform1iv(gl_uniform_location + static_cast<GLint>(index), static_cast<GLsizei>(values.size()), &gl_texture_unit_indices[index]); | |||
} | |||
void gl_shader_texture_2d::update(std::span<const std::shared_ptr<texture_2d>> values, std::size_t index) const | |||
{ | |||
// Bind textures | |||
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); | |||
} | |||
// Pass texture unit indices to shader | |||
glUniform1iv(gl_uniform_location + static_cast<GLint>(index), static_cast<GLsizei>(values.size()), &gl_texture_unit_indices[index]); | |||
} | |||
gl_shader_texture_3d::gl_shader_texture_3d(std::size_t size, GLint gl_uniform_location, GLint gl_first_texture_unit_index): | |||
shader_variable(size), | |||
gl_uniform_location{gl_uniform_location}, | |||
gl_texture_unit_indices(size) | |||
{ | |||
std::iota(gl_texture_unit_indices.begin(), gl_texture_unit_indices.end(), gl_first_texture_unit_index); | |||
} | |||
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); | |||
// Pass texture unit index to shader | |||
glUniform1i(gl_uniform_location, gl_texture_unit_indices.front()); | |||
} | |||
void gl_shader_texture_3d::update(const texture_3d& value, std::size_t index) const | |||
{ | |||
const GLint gl_texture_index = gl_texture_unit_indices[index]; | |||
// Bind texture to texture unit | |||
glActiveTexture(GL_TEXTURE0 + static_cast<GLenum>(gl_texture_index)); | |||
glBindTexture(GL_TEXTURE_3D, value.gl_texture_id); | |||
// Pass texture unit index to shader | |||
glUniform1i(gl_uniform_location + static_cast<GLint>(index), gl_texture_index); | |||
} | |||
void gl_shader_texture_3d::update(std::span<const texture_3d* const> values, std::size_t index) const | |||
{ | |||
// Bind textures | |||
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); | |||
} | |||
// Pass texture unit indices to shader | |||
glUniform1iv(gl_uniform_location + static_cast<GLint>(index), static_cast<GLsizei>(values.size()), &gl_texture_unit_indices[index]); | |||
} | |||
void gl_shader_texture_3d::update(std::span<const std::shared_ptr<texture_3d>> values, std::size_t index) const | |||
{ | |||
// Bind textures | |||
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); | |||
} | |||
// Pass texture unit indices to shader | |||
glUniform1iv(gl_uniform_location + static_cast<GLint>(index), static_cast<GLsizei>(values.size()), &gl_texture_unit_indices[index]); | |||
} | |||
gl_shader_texture_cube::gl_shader_texture_cube(std::size_t size, GLint gl_uniform_location, GLint gl_first_texture_unit_index): | |||
shader_variable(size), | |||
gl_uniform_location{gl_uniform_location}, | |||
gl_texture_unit_indices(size) | |||
{ | |||
std::iota(gl_texture_unit_indices.begin(), gl_texture_unit_indices.end(), gl_first_texture_unit_index); | |||
} | |||
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); | |||
// Pass texture unit index to shader | |||
glUniform1i(gl_uniform_location, gl_texture_unit_indices.front()); | |||
} | |||
void gl_shader_texture_cube::update(const texture_cube& value, std::size_t index) const | |||
{ | |||
const GLint gl_texture_index = gl_texture_unit_indices[index]; | |||
// Bind texture to texture unit | |||
glActiveTexture(GL_TEXTURE0 + static_cast<GLenum>(gl_texture_index)); | |||
glBindTexture(GL_TEXTURE_CUBE_MAP, value.gl_texture_id); | |||
// Pass texture unit index to shader | |||
glUniform1i(gl_uniform_location + static_cast<GLint>(index), gl_texture_index); | |||
} | |||
void gl_shader_texture_cube::update(std::span<const texture_cube* const> values, std::size_t index) const | |||
{ | |||
// Bind textures | |||
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); | |||
} | |||
// Pass texture unit indices to shader | |||
glUniform1iv(gl_uniform_location + static_cast<GLint>(index), static_cast<GLsizei>(values.size()), &gl_texture_unit_indices[index]); | |||
} | |||
void gl_shader_texture_cube::update(std::span<const std::shared_ptr<texture_cube>> values, std::size_t index) const | |||
{ | |||
// Bind textures | |||
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); | |||
} | |||
// Pass texture unit indices to shader | |||
glUniform1iv(gl_uniform_location + static_cast<GLint>(index), static_cast<GLsizei>(values.size()), &gl_texture_unit_indices[index]); | |||
} | |||
} // namespace gl |
@ -0,0 +1,526 @@ | |||
/* | |||
* 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_GL_SHADER_VARIABLES_HPP | |||
#define ANTKEEPER_GL_GL_SHADER_VARIABLES_HPP | |||
#include <engine/gl/shader-variable.hpp> | |||
#include <glad/glad.h> | |||
#include <vector> | |||
namespace gl { | |||
/** | |||
* Boolean shader variable implementation using OpenGL. | |||
*/ | |||
class gl_shader_bool: public shader_variable | |||
{ | |||
public: | |||
gl_shader_bool(std::size_t size, GLint gl_uniform_location); | |||
[[nodiscard]] inline constexpr shader_variable_type type() const noexcept override | |||
{ | |||
return shader_variable_type::bool1; | |||
} | |||
void update(bool value) const noexcept override; | |||
void update(bool value, std::size_t index) const override; | |||
void update(std::span<const bool> values, std::size_t index = 0) const override; | |||
private: | |||
GLint gl_uniform_location; | |||
mutable std::vector<GLint> ivalues; | |||
}; | |||
/** | |||
* 2-dimensional boolean vector shader variable implementation using OpenGL. | |||
*/ | |||
class gl_shader_bool2: public shader_variable | |||
{ | |||
public: | |||
gl_shader_bool2(std::size_t size, GLint gl_uniform_location); | |||
[[nodiscard]] inline constexpr shader_variable_type type() const noexcept override | |||
{ | |||
return shader_variable_type::bool2; | |||
} | |||
void update(const bool2& value) const noexcept override; | |||
void update(const bool2& value, std::size_t index) const override; | |||
void update(std::span<const bool2> values, std::size_t index = 0) const override; | |||
private: | |||
GLint gl_uniform_location; | |||
mutable std::vector<GLint> ivalues; | |||
}; | |||
/** | |||
* 3-dimensional boolean vector shader variable implementation using OpenGL. | |||
*/ | |||
class gl_shader_bool3: public shader_variable | |||
{ | |||
public: | |||
gl_shader_bool3(std::size_t size, GLint gl_uniform_location); | |||
[[nodiscard]] inline constexpr shader_variable_type type() const noexcept override | |||
{ | |||
return shader_variable_type::bool3; | |||
} | |||
void update(const bool3& value) const noexcept override; | |||
void update(const bool3& value, std::size_t index) const override; | |||
void update(std::span<const bool3> values, std::size_t index = 0) const override; | |||
private: | |||
GLint gl_uniform_location; | |||
mutable std::vector<GLint> ivalues; | |||
}; | |||
/** | |||
* 4-dimensional boolean vector shader variable implementation using OpenGL. | |||
*/ | |||
class gl_shader_bool4: public shader_variable | |||
{ | |||
public: | |||
gl_shader_bool4(std::size_t size, GLint gl_uniform_location); | |||
[[nodiscard]] inline constexpr shader_variable_type type() const noexcept override | |||
{ | |||
return shader_variable_type::bool4; | |||
} | |||
void update(const bool4& value) const noexcept override; | |||
void update(const bool4& value, std::size_t index) const override; | |||
void update(std::span<const bool4> values, std::size_t index = 0) const override; | |||
private: | |||
GLint gl_uniform_location; | |||
mutable std::vector<GLint> ivalues; | |||
}; | |||
/** | |||
* Signed integer shader variable implementation using OpenGL. | |||
*/ | |||
class gl_shader_int: public shader_variable | |||
{ | |||
public: | |||
gl_shader_int(std::size_t size, GLint gl_uniform_location); | |||
[[nodiscard]] inline constexpr shader_variable_type type() const noexcept override | |||
{ | |||
return shader_variable_type::int1; | |||
} | |||
void update(int value) const noexcept override; | |||
void update(int value, std::size_t index) const override; | |||
void update(std::span<const int> values, std::size_t index = 0) const override; | |||
private: | |||
GLint gl_uniform_location; | |||
}; | |||
/** | |||
* 2-dimensional signed integer vector shader variable implementation using OpenGL. | |||
*/ | |||
class gl_shader_int2: public shader_variable | |||
{ | |||
public: | |||
gl_shader_int2(std::size_t size, GLint gl_uniform_location); | |||
[[nodiscard]] inline constexpr shader_variable_type type() const noexcept override | |||
{ | |||
return shader_variable_type::int2; | |||
} | |||
void update(const int2& value) const noexcept override; | |||
void update(const int2& value, std::size_t index) const override; | |||
void update(std::span<const int2> values, std::size_t index = 0) const override; | |||
private: | |||
GLint gl_uniform_location; | |||
}; | |||
/** | |||
* 3-dimensional signed integer vector shader variable implementation using OpenGL. | |||
*/ | |||
class gl_shader_int3: public shader_variable | |||
{ | |||
public: | |||
gl_shader_int3(std::size_t size, GLint gl_uniform_location); | |||
[[nodiscard]] inline constexpr shader_variable_type type() const noexcept override | |||
{ | |||
return shader_variable_type::int3; | |||
} | |||
void update(const int3& value) const noexcept override; | |||
void update(const int3& value, std::size_t index) const override; | |||
void update(std::span<const int3> values, std::size_t index = 0) const override; | |||
private: | |||
GLint gl_uniform_location; | |||
}; | |||
/** | |||
* 4-dimensional signed integer vector shader variable implementation using OpenGL. | |||
*/ | |||
class gl_shader_int4: public shader_variable | |||
{ | |||
public: | |||
gl_shader_int4(std::size_t size, GLint gl_uniform_location); | |||
[[nodiscard]] inline constexpr shader_variable_type type() const noexcept override | |||
{ | |||
return shader_variable_type::int4; | |||
} | |||
void update(const int4& value) const noexcept override; | |||
void update(const int4& value, std::size_t index) const override; | |||
void update(std::span<const int4> values, std::size_t index = 0) const override; | |||
private: | |||
GLint gl_uniform_location; | |||
}; | |||
/** | |||
* Unsigned integer shader variable implementation using OpenGL. | |||
*/ | |||
class gl_shader_uint: public shader_variable | |||
{ | |||
public: | |||
gl_shader_uint(std::size_t size, GLint gl_uniform_location); | |||
[[nodiscard]] inline constexpr shader_variable_type type() const noexcept override | |||
{ | |||
return shader_variable_type::uint1; | |||
} | |||
void update(unsigned int value) const noexcept override; | |||
void update(unsigned int value, std::size_t index) const override; | |||
void update(std::span<const unsigned int> values, std::size_t index = 0) const override; | |||
private: | |||
GLint gl_uniform_location; | |||
}; | |||
/** | |||
* 2-dimensional unsigned integer vector shader variable implementation using OpenGL. | |||
*/ | |||
class gl_shader_uint2: public shader_variable | |||
{ | |||
public: | |||
gl_shader_uint2(std::size_t size, GLint gl_uniform_location); | |||
[[nodiscard]] inline constexpr shader_variable_type type() const noexcept override | |||
{ | |||
return shader_variable_type::uint2; | |||
} | |||
void update(const uint2& value) const noexcept override; | |||
void update(const uint2& value, std::size_t index) const override; | |||
void update(std::span<const uint2> values, std::size_t index = 0) const override; | |||
private: | |||
GLint gl_uniform_location; | |||
}; | |||
/** | |||
* 3-dimensional unsigned integer vector shader variable implementation using OpenGL. | |||
*/ | |||
class gl_shader_uint3: public shader_variable | |||
{ | |||
public: | |||
gl_shader_uint3(std::size_t size, GLint gl_uniform_location); | |||
[[nodiscard]] inline constexpr shader_variable_type type() const noexcept override | |||
{ | |||
return shader_variable_type::uint3; | |||
} | |||
void update(const uint3& value) const noexcept override; | |||
void update(const uint3& value, std::size_t index) const override; | |||
void update(std::span<const uint3> values, std::size_t index = 0) const override; | |||
private: | |||
GLint gl_uniform_location; | |||
}; | |||
/** | |||
* 4-dimensional unsigned integer vector shader variable implementation using OpenGL. | |||
*/ | |||
class gl_shader_uint4: public shader_variable | |||
{ | |||
public: | |||
gl_shader_uint4(std::size_t size, GLint gl_uniform_location); | |||
[[nodiscard]] inline constexpr shader_variable_type type() const noexcept override | |||
{ | |||
return shader_variable_type::uint4; | |||
} | |||
void update(const uint4& value) const noexcept override; | |||
void update(const uint4& value, std::size_t index) const override; | |||
void update(std::span<const uint4> values, std::size_t index = 0) const override; | |||
private: | |||
GLint gl_uniform_location; | |||
}; | |||
/** | |||
* Floating-point shader variable implementation using OpenGL. | |||
*/ | |||
class gl_shader_float: public shader_variable | |||
{ | |||
public: | |||
gl_shader_float(std::size_t size, GLint gl_uniform_location); | |||
[[nodiscard]] inline constexpr shader_variable_type type() const noexcept override | |||
{ | |||
return shader_variable_type::float1; | |||
} | |||
void update(float value) const noexcept override; | |||
void update(float value, std::size_t index) const override; | |||
void update(std::span<const float> values, std::size_t index = 0) const override; | |||
private: | |||
GLint gl_uniform_location; | |||
}; | |||
/** | |||
* 2-dimensional floating-point vector shader variable implementation using OpenGL. | |||
*/ | |||
class gl_shader_float2: public shader_variable | |||
{ | |||
public: | |||
gl_shader_float2(std::size_t size, GLint gl_uniform_location); | |||
[[nodiscard]] inline constexpr shader_variable_type type() const noexcept override | |||
{ | |||
return shader_variable_type::float2; | |||
} | |||
void update(const float2& value) const noexcept override; | |||
void update(const float2& value, std::size_t index) const override; | |||
void update(std::span<const float2> values, std::size_t index = 0) const override; | |||
private: | |||
GLint gl_uniform_location; | |||
}; | |||
/** | |||
* 3-dimensional floating-point vector shader variable implementation using OpenGL. | |||
*/ | |||
class gl_shader_float3: public shader_variable | |||
{ | |||
public: | |||
gl_shader_float3(std::size_t size, GLint gl_uniform_location); | |||
[[nodiscard]] inline constexpr shader_variable_type type() const noexcept override | |||
{ | |||
return shader_variable_type::float3; | |||
} | |||
void update(const float3& value) const noexcept override; | |||
void update(const float3& value, std::size_t index) const override; | |||
void update(std::span<const float3> values, std::size_t index = 0) const override; | |||
private: | |||
GLint gl_uniform_location; | |||
}; | |||
/** | |||
* 4-dimensional floating-point vector shader variable implementation using OpenGL. | |||
*/ | |||
class gl_shader_float4: public shader_variable | |||
{ | |||
public: | |||
gl_shader_float4(std::size_t size, GLint gl_uniform_location); | |||
[[nodiscard]] inline constexpr shader_variable_type type() const noexcept override | |||
{ | |||
return shader_variable_type::float4; | |||
} | |||
void update(const float4& value) const noexcept override; | |||
void update(const float4& value, std::size_t index) const override; | |||
void update(std::span<const float4> values, std::size_t index = 0) const override; | |||
private: | |||
GLint gl_uniform_location; | |||
}; | |||
/** | |||
* 2x2 floating-point matrix shader variable implementation using OpenGL. | |||
*/ | |||
class gl_shader_float2x2: public shader_variable | |||
{ | |||
public: | |||
gl_shader_float2x2(std::size_t size, GLint gl_uniform_location); | |||
[[nodiscard]] inline constexpr shader_variable_type type() const noexcept override | |||
{ | |||
return shader_variable_type::float2x2; | |||
} | |||
void update(const float2x2& value) const noexcept override; | |||
void update(const float2x2& value, std::size_t index) const override; | |||
void update(std::span<const float2x2> values, std::size_t index = 0) const override; | |||
private: | |||
GLint gl_uniform_location; | |||
}; | |||
/** | |||
* 3x3 floating-point matrix shader variable implementation using OpenGL. | |||
*/ | |||
class gl_shader_float3x3: public shader_variable | |||
{ | |||
public: | |||
gl_shader_float3x3(std::size_t size, GLint gl_uniform_location); | |||
[[nodiscard]] inline constexpr shader_variable_type type() const noexcept override | |||
{ | |||
return shader_variable_type::float3x3; | |||
} | |||
void update(const float3x3& value) const noexcept override; | |||
void update(const float3x3& value, std::size_t index) const override; | |||
void update(std::span<const float3x3> values, std::size_t index = 0) const override; | |||
private: | |||
GLint gl_uniform_location; | |||
}; | |||
/** | |||
* 4x4 floating-point matrix shader variable implementation using OpenGL. | |||
*/ | |||
class gl_shader_float4x4: public shader_variable | |||
{ | |||
public: | |||
gl_shader_float4x4(std::size_t size, GLint gl_uniform_location); | |||
[[nodiscard]] inline constexpr shader_variable_type type() const noexcept override | |||
{ | |||
return shader_variable_type::float4x4; | |||
} | |||
void update(const float4x4& value) const noexcept override; | |||
void update(const float4x4& value, std::size_t index) const override; | |||
void update(std::span<const float4x4> values, std::size_t index = 0) const override; | |||
private: | |||
GLint gl_uniform_location; | |||
}; | |||
/** | |||
* 1-dimensional texture shader variable implementation using OpenGL. | |||
*/ | |||
class gl_shader_texture_1d: public shader_variable | |||
{ | |||
public: | |||
gl_shader_texture_1d(std::size_t size, GLint gl_uniform_location, GLint gl_first_texture_index); | |||
[[nodiscard]] inline constexpr shader_variable_type type() const noexcept override | |||
{ | |||
return shader_variable_type::texture_1d; | |||
} | |||
void update(const texture_1d& value) const noexcept override; | |||
void update(const texture_1d& value, std::size_t index) const override; | |||
void update(std::span<const texture_1d* const> values, std::size_t index = 0) const override; | |||
void update(std::span<const std::shared_ptr<texture_1d>> values, std::size_t index = 0) const override; | |||
private: | |||
GLint gl_uniform_location; | |||
std::vector<GLint> gl_texture_unit_indices; | |||
}; | |||
/** | |||
* 2-dimensional texture shader variable implementation using OpenGL. | |||
*/ | |||
class gl_shader_texture_2d: public shader_variable | |||
{ | |||
public: | |||
gl_shader_texture_2d(std::size_t size, GLint gl_uniform_location, GLint gl_first_texture_unit_index); | |||
[[nodiscard]] inline constexpr shader_variable_type type() const noexcept override | |||
{ | |||
return shader_variable_type::texture_2d; | |||
} | |||
void update(const texture_2d& value) const noexcept override; | |||
void update(const texture_2d& value, std::size_t index) const override; | |||
void update(std::span<const texture_2d* const> values, std::size_t index = 0) const override; | |||
void update(std::span<const std::shared_ptr<texture_2d>> values, std::size_t index = 0) const override; | |||
private: | |||
GLint gl_uniform_location; | |||
std::vector<GLint> gl_texture_unit_indices; | |||
}; | |||
/** | |||
* 3-dimensional texture shader variable implementation using OpenGL. | |||
*/ | |||
class gl_shader_texture_3d: public shader_variable | |||
{ | |||
public: | |||
gl_shader_texture_3d(std::size_t size, GLint gl_uniform_location, GLint gl_first_texture_index); | |||
[[nodiscard]] inline constexpr shader_variable_type type() const noexcept override | |||
{ | |||
return shader_variable_type::texture_3d; | |||
} | |||
void update(const texture_3d& value) const noexcept override; | |||
void update(const texture_3d& value, std::size_t index) const override; | |||
void update(std::span<const texture_3d* const> values, std::size_t index = 0) const override; | |||
void update(std::span<const std::shared_ptr<texture_3d>> values, std::size_t index = 0) const override; | |||
private: | |||
GLint gl_uniform_location; | |||
std::vector<GLint> gl_texture_unit_indices; | |||
}; | |||
/** | |||
* Cube texture shader variable implementation using OpenGL. | |||
*/ | |||
class gl_shader_texture_cube: public shader_variable | |||
{ | |||
public: | |||
gl_shader_texture_cube(std::size_t size, GLint gl_uniform_location, GLint gl_first_texture_index); | |||
[[nodiscard]] inline constexpr shader_variable_type type() const noexcept override | |||
{ | |||
return shader_variable_type::texture_cube; | |||
} | |||
void update(const texture_cube& value) const noexcept override; | |||
void update(const texture_cube& value, std::size_t index) const override; | |||
void update(std::span<const texture_cube* const> values, std::size_t index = 0) const override; | |||
void update(std::span<const std::shared_ptr<texture_cube>> values, std::size_t index = 0) const override; | |||
private: | |||
GLint gl_uniform_location; | |||
std::vector<GLint> gl_texture_unit_indices; | |||
}; | |||
} // namespace gl | |||
#endif // ANTKEEPER_GL_GL_SHADER_VARIABLES_HPP |
@ -1,773 +0,0 @@ | |||
/* | |||
* 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/gl/shader-input.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 <glad/glad.h> | |||
namespace gl { | |||
shader_input::shader_input(shader_program* program, std::size_t input_index, int gl_uniform_location, const std::string& name, shader_variable_type data_type, std::size_t element_count, int texture_unit): | |||
program(program), | |||
input_index(input_index), | |||
gl_uniform_location(gl_uniform_location), | |||
name(name), | |||
data_type(data_type), | |||
element_count(element_count), | |||
texture_unit(texture_unit) | |||
{} | |||
shader_input::~shader_input() | |||
{} | |||
bool shader_input::upload(const bool& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform1i(gl_uniform_location, static_cast<GLint>(value)); | |||
return true; | |||
} | |||
bool shader_input::upload(const bool2& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
const GLint values[] = {value[0], value[1]}; | |||
glUniform2iv(gl_uniform_location, 1, values); | |||
return true; | |||
} | |||
bool shader_input::upload(const bool3& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
const GLint values[] = {value[0], value[1], value[2]}; | |||
glUniform3iv(gl_uniform_location, 1, values); | |||
return true; | |||
} | |||
bool shader_input::upload(const bool4& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
const GLint values[] = {value[0], value[1], value[2], value[3]}; | |||
glUniform4iv(gl_uniform_location, 1, values); | |||
return true; | |||
} | |||
bool shader_input::upload(const int& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform1i(gl_uniform_location, value); | |||
return true; | |||
} | |||
bool shader_input::upload(const int2& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform2iv(gl_uniform_location, 1, value.data()); | |||
return true; | |||
} | |||
bool shader_input::upload(const int3& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform3iv(gl_uniform_location, 1, value.data()); | |||
return true; | |||
} | |||
bool shader_input::upload(const int4& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform4iv(gl_uniform_location, 1, value.data()); | |||
return true; | |||
} | |||
bool shader_input::upload(const unsigned int& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform1ui(gl_uniform_location, value); | |||
return true; | |||
} | |||
bool shader_input::upload(const uint2& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform2uiv(gl_uniform_location, 1, value.data()); | |||
return true; | |||
} | |||
bool shader_input::upload(const uint3& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform3uiv(gl_uniform_location, 1, value.data()); | |||
return true; | |||
} | |||
bool shader_input::upload(const uint4& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform4uiv(gl_uniform_location, 1, value.data()); | |||
return true; | |||
} | |||
bool shader_input::upload(const float& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform1f(gl_uniform_location, value); | |||
return true; | |||
} | |||
bool shader_input::upload(const float2& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform2fv(gl_uniform_location, 1, value.data()); | |||
return true; | |||
} | |||
bool shader_input::upload(const float3& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform3fv(gl_uniform_location, 1, value.data()); | |||
return true; | |||
} | |||
bool shader_input::upload(const float4& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform4fv(gl_uniform_location, 1, value.data()); | |||
return true; | |||
} | |||
bool shader_input::upload(const float2x2& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniformMatrix2fv(gl_uniform_location, 1, GL_FALSE, value[0].data()); | |||
return true; | |||
} | |||
bool shader_input::upload(const float3x3& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniformMatrix3fv(gl_uniform_location, 1, GL_FALSE, value[0].data()); | |||
return true; | |||
} | |||
bool shader_input::upload(const float4x4& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniformMatrix4fv(gl_uniform_location, 1, GL_FALSE, value[0].data()); | |||
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 | |||
{ | |||
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_2D, value->gl_texture_id); | |||
// Upload texture unit index to shader | |||
glUniform1i(gl_uniform_location, texture_unit); | |||
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 | |||
{ | |||
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_CUBE_MAP, value->gl_texture_id); | |||
// Upload texture unit index to shader | |||
glUniform1i(gl_uniform_location, texture_unit); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const bool& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform1i(gl_uniform_location + static_cast<int>(index), static_cast<GLint>(value)); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const bool2& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
const GLint values[] = {value[0], value[1]}; | |||
glUniform2iv(gl_uniform_location + static_cast<int>(index), 1, values); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const bool3& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
const GLint values[] = {value[0], value[1], value[3]}; | |||
glUniform3iv(gl_uniform_location + static_cast<int>(index), 1, values); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const bool4& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
const GLint values[] = {value[0], value[1], value[3], value[4]}; | |||
glUniform4iv(gl_uniform_location + static_cast<int>(index), 1, values); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const int& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform1i(gl_uniform_location + static_cast<int>(index), value); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const int2& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform2iv(gl_uniform_location + static_cast<int>(index), 1, value.data()); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const int3& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform3iv(gl_uniform_location + static_cast<int>(index), 1, value.data()); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const int4& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform4iv(gl_uniform_location + static_cast<int>(index), 1, value.data()); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const unsigned int& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform1ui(gl_uniform_location + static_cast<int>(index), value); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const uint2& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform2uiv(gl_uniform_location + static_cast<int>(index), 1, value.data()); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const uint3& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform3uiv(gl_uniform_location + static_cast<int>(index), 1, value.data()); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const uint4& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform4uiv(gl_uniform_location + static_cast<int>(index), 1, value.data()); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const float& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform1f(gl_uniform_location + static_cast<int>(index), value); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const float2& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform2fv(gl_uniform_location + static_cast<int>(index), 1, value.data()); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const float3& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform3fv(gl_uniform_location + static_cast<int>(index), 1, value.data()); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const float4& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform4fv(gl_uniform_location + static_cast<int>(index), 1, value.data()); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const float2x2& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniformMatrix2fv(gl_uniform_location + static_cast<int>(index) * 2, 1, GL_FALSE, value[0].data()); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const float3x3& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniformMatrix3fv(gl_uniform_location + static_cast<int>(index) * 3, 1, GL_FALSE, value[0].data()); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const float4x4& value) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniformMatrix4fv(gl_uniform_location + static_cast<int>(index) * 4, 1, GL_FALSE, value[0].data()); | |||
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 | |||
{ | |||
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_2D, 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_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 | |||
{ | |||
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_CUBE_MAP, 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 bool* values, std::size_t count) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
int* int_values = new int[count]; | |||
for (std::size_t i = 0; i < count; ++i) | |||
int_values[i] = values[i]; | |||
glUniform1iv(gl_uniform_location + static_cast<int>(index), static_cast<GLsizei>(count), &(*int_values)); | |||
delete[] int_values; | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const bool2* values, std::size_t count) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
int2* int2_values = new int2[count]; | |||
for (std::size_t i = 0; i < count; ++i) | |||
int2_values[i] = {values[i][0], values[i][1]}; | |||
glUniform2iv(gl_uniform_location + static_cast<int>(index), static_cast<GLsizei>(count), &((*int2_values)[0])); | |||
delete[] int2_values; | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const bool3* values, std::size_t count) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
int3* int3_values = new int3[count]; | |||
for (std::size_t i = 0; i < count; ++i) | |||
int3_values[i] = {values[i][0], values[i][1], values[i][2]}; | |||
glUniform3iv(gl_uniform_location + static_cast<int>(index), static_cast<GLsizei>(count), &((*int3_values)[0])); | |||
delete[] int3_values; | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const bool4* values, std::size_t count) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
int4* int4_values = new int4[count]; | |||
for (std::size_t i = 0; i < count; ++i) | |||
int4_values[i] = {values[i][0], values[i][1], values[i][2], values[i][3]}; | |||
glUniform4iv(gl_uniform_location + static_cast<int>(index), static_cast<GLsizei>(count), &((*int4_values)[0])); | |||
delete[] int4_values; | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const int* values, std::size_t count) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform1iv(gl_uniform_location + static_cast<int>(index), static_cast<GLsizei>(count), &(*values)); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const int2* values, std::size_t count) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform2iv(gl_uniform_location + static_cast<int>(index), static_cast<GLsizei>(count), (*values).data()); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const int3* values, std::size_t count) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform3iv(gl_uniform_location + static_cast<int>(index), static_cast<GLsizei>(count), (*values).data()); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const int4* values, std::size_t count) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform4iv(gl_uniform_location + static_cast<int>(index), static_cast<GLsizei>(count), (*values).data()); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const unsigned int* values, std::size_t count) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform1uiv(gl_uniform_location + static_cast<int>(index), static_cast<GLsizei>(count), &(*values)); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const uint2* values, std::size_t count) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform2uiv(gl_uniform_location + static_cast<int>(index), static_cast<GLsizei>(count), (*values).data()); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const uint3* values, std::size_t count) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform3uiv(gl_uniform_location + static_cast<int>(index), static_cast<GLsizei>(count), (*values).data()); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const uint4* values, std::size_t count) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform4uiv(gl_uniform_location + static_cast<int>(index), static_cast<GLsizei>(count), (*values).data()); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const float* values, std::size_t count) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform1fv(gl_uniform_location + static_cast<int>(index), static_cast<GLsizei>(count), &(*values)); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const float2* values, std::size_t count) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform2fv(gl_uniform_location + static_cast<int>(index), static_cast<GLsizei>(count), (*values).data()); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const float3* values, std::size_t count) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform3fv(gl_uniform_location + static_cast<int>(index), static_cast<GLsizei>(count), (*values).data()); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const float4* values, std::size_t count) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniform4fv(gl_uniform_location + static_cast<int>(index), static_cast<GLsizei>(count), (*values).data()); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const float2x2* values, std::size_t count) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniformMatrix2fv(gl_uniform_location + static_cast<int>(index) * 2, static_cast<GLsizei>(count), GL_FALSE, (*values)[0].data()); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const float3x3* values, std::size_t count) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniformMatrix3fv(gl_uniform_location + static_cast<int>(index) * 3, static_cast<GLsizei>(count), GL_FALSE, (*values)[0].data()); | |||
return true; | |||
} | |||
bool shader_input::upload(std::size_t index, const float4x4* values, std::size_t count) const | |||
{ | |||
if (gl_uniform_location == -1) | |||
return false; | |||
glUniformMatrix4fv(gl_uniform_location + static_cast<int>(index) * 4, static_cast<GLsizei>(count), GL_FALSE, (*values)[0].data()); | |||
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 | |||
{ | |||
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_2D, 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_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 | |||
{ | |||
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_CUBE_MAP, 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; | |||
} | |||
} // namespace gl |
@ -1,202 +0,0 @@ | |||
/* | |||
* 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_SHADER_INPUT_HPP | |||
#define ANTKEEPER_GL_SHADER_INPUT_HPP | |||
#include <engine/utility/fundamental-types.hpp> | |||
#include <string> | |||
namespace gl { | |||
class shader_program; | |||
class texture_1d; | |||
class texture_2d; | |||
class texture_3d; | |||
class texture_cube; | |||
enum class shader_variable_type; | |||
/** | |||
* Port through which data can be uploaded to shader variables. | |||
*/ | |||
class shader_input | |||
{ | |||
public: | |||
/** | |||
* Returns the type of data which can be passed through this input. | |||
*/ | |||
shader_variable_type get_data_type() const; | |||
/** | |||
* Returns `true` if the input data is stored in an array. | |||
*/ | |||
bool is_array() const; | |||
/** | |||
* Returns the number of elements the array can contain, or `1` if the data is not stored in an array. | |||
*/ | |||
std::size_t get_element_count() const; | |||
/** | |||
* Uploads a value to the shader. | |||
* | |||
* @param value Value to upload. | |||
* @return `true` if the value was uploaded successfully, `false` otherwise. | |||
*/ | |||
///@{ | |||
bool upload(const bool& value) const; | |||
bool upload(const bool2& value) const; | |||
bool upload(const bool3& value) const; | |||
bool upload(const bool4& value) const; | |||
bool upload(const int& value) const; | |||
bool upload(const int2& value) const; | |||
bool upload(const int3& value) const; | |||
bool upload(const int4& value) const; | |||
bool upload(const unsigned int& value) const; | |||
bool upload(const uint2& value) const; | |||
bool upload(const uint3& value) const; | |||
bool upload(const uint4& value) const; | |||
bool upload(const float& value) const; | |||
bool upload(const float2& value) const; | |||
bool upload(const float3& value) const; | |||
bool upload(const float4& value) const; | |||
bool upload(const float2x2& value) const; | |||
bool upload(const float3x3& 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_3d* value) const; | |||
bool upload(const texture_cube* value) const; | |||
///@} | |||
/** | |||
* Uploads a single array element to the shader. | |||
* | |||
* @param index Index of an array element. | |||
* @param values Value to upload. | |||
* @return `true` if the value was uploaded successfully, `false` otherwise. | |||
*/ | |||
///@{ | |||
bool upload(std::size_t index, const bool& value) const; | |||
bool upload(std::size_t index, const bool2& value) const; | |||
bool upload(std::size_t index, const bool3& value) const; | |||
bool upload(std::size_t index, const bool4& value) const; | |||
bool upload(std::size_t index, const int& value) const; | |||
bool upload(std::size_t index, const int2& value) const; | |||
bool upload(std::size_t index, const int3& value) const; | |||
bool upload(std::size_t index, const int4& value) const; | |||
bool upload(std::size_t index, const unsigned int& value) const; | |||
bool upload(std::size_t index, const uint2& value) const; | |||
bool upload(std::size_t index, const uint3& value) const; | |||
bool upload(std::size_t index, const uint4& value) const; | |||
bool upload(std::size_t index, const float& value) const; | |||
bool upload(std::size_t index, const float2& value) const; | |||
bool upload(std::size_t index, const float3& value) const; | |||
bool upload(std::size_t index, const float4& 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 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_3d* value) const; | |||
bool upload(std::size_t index, const texture_cube* value) const; | |||
///@} | |||
/** | |||
* Uploads a range of array elements to the shader. | |||
* | |||
* @param index Index of the first array element. | |||
* @param values Pointer to an array of values. | |||
* @param count Number of elements to upload. | |||
* @return `true` if the value was fed successfully, `false` otherwise. | |||
*/ | |||
///@{ | |||
bool upload(std::size_t index, const bool* values, std::size_t count) const; | |||
bool upload(std::size_t index, const bool2* values, std::size_t count) const; | |||
bool upload(std::size_t index, const bool3* values, std::size_t count) const; | |||
bool upload(std::size_t index, const bool4* values, std::size_t count) const; | |||
bool upload(std::size_t index, const int* values, std::size_t count) const; | |||
bool upload(std::size_t index, const int2* values, std::size_t count) const; | |||
bool upload(std::size_t index, const int3* values, std::size_t count) const; | |||
bool upload(std::size_t index, const int4* values, std::size_t count) const; | |||
bool upload(std::size_t index, const unsigned int* values, std::size_t count) const; | |||
bool upload(std::size_t index, const uint2* values, std::size_t count) const; | |||
bool upload(std::size_t index, const uint3* values, std::size_t count) const; | |||
bool upload(std::size_t index, const uint4* values, std::size_t count) const; | |||
bool upload(std::size_t index, const float* values, std::size_t count) const; | |||
bool upload(std::size_t index, const float2* values, std::size_t count) const; | |||
bool upload(std::size_t index, const float3* values, std::size_t count) const; | |||
bool upload(std::size_t index, const float4* 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 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_3d** values, std::size_t count) const; | |||
bool upload(std::size_t index, const texture_cube** values, std::size_t count) const; | |||
///@} | |||
private: | |||
friend class shader_program; | |||
/** | |||
* Creates a shader input. | |||
* | |||
* @param program Shader program with which this input is associated. | |||
* @param gl_uniform_location Location of the shader uniform with which this shader input is associated. | |||
* @param name Name of the input. | |||
* @param data_type Type of data which can be passed through this input. | |||
* @param element_count Number of elements which the array can contain, or `0` if input data is not stored in an array. | |||
* @param texture_unit Texture unit to which texture shader variables can be bound, or `-1` if the data type is not a texture type. | |||
*/ | |||
shader_input(shader_program* program, std::size_t input_index, int gl_uniform_location, const std::string& name, shader_variable_type data_type, std::size_t element_count, int texture_unit); | |||
/** | |||
* Destroys a shader input. | |||
*/ | |||
~shader_input(); | |||
shader_program* program; | |||
std::size_t input_index; | |||
int gl_uniform_location; | |||
std::string name; | |||
shader_variable_type data_type; | |||
std::size_t element_count; | |||
int texture_unit; | |||
}; | |||
inline shader_variable_type shader_input::get_data_type() const | |||
{ | |||
return data_type; | |||
} | |||
inline bool shader_input::is_array() const | |||
{ | |||
return (element_count > 1); | |||
} | |||
inline std::size_t shader_input::get_element_count() const | |||
{ | |||
return element_count; | |||
} | |||
} // namespace gl | |||
#endif // ANTKEEPER_GL_SHADER_INPUT_HPP | |||
@ -0,0 +1,364 @@ | |||
/* | |||
* 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/gl/shader-template.hpp> | |||
#include <algorithm> | |||
#include <engine/gl/shader-object.hpp> | |||
#include <engine/gl/shader-program.hpp> | |||
#include <engine/resources/resource-loader.hpp> | |||
#include <engine/resources/resource-manager.hpp> | |||
#include <engine/utility/text-file.hpp> | |||
#include <engine/utility/hash/combine.hpp> | |||
#include <sstream> | |||
#include <unordered_set> | |||
namespace gl { | |||
shader_template::shader_template(const text_file& source_code): | |||
template_source{source_code} | |||
{ | |||
find_directives(); | |||
rehash(); | |||
} | |||
shader_template::shader_template(text_file&& source_code): | |||
template_source{source_code} | |||
{ | |||
find_directives(); | |||
rehash(); | |||
} | |||
void shader_template::source(const text_file& source_code) | |||
{ | |||
template_source = source_code; | |||
find_directives(); | |||
rehash(); | |||
} | |||
void shader_template::source(text_file&& source_code) | |||
{ | |||
template_source = source_code; | |||
find_directives(); | |||
rehash(); | |||
} | |||
std::string shader_template::configure(gl::shader_stage stage, const dictionary_type& definitions) const | |||
{ | |||
replace_stage_directives(stage); | |||
replace_define_directives(definitions); | |||
// Join vector of source lines into single string | |||
std::string string; | |||
for (const auto& line: template_source.lines) | |||
{ | |||
string += line; | |||
string += '\n'; | |||
} | |||
return string; | |||
} | |||
std::unique_ptr<gl::shader_object> shader_template::compile(gl::shader_stage stage, const dictionary_type& definitions) const | |||
{ | |||
// Generate shader object source | |||
const std::string object_source = configure(stage, definitions); | |||
// Create shader object | |||
std::unique_ptr<gl::shader_object> object = std::make_unique<gl::shader_object>(stage); | |||
// Set shader object source | |||
object->source(object_source); | |||
// Compile shader object | |||
object->compile(); | |||
return object; | |||
} | |||
std::unique_ptr<gl::shader_program> shader_template::build(const dictionary_type& definitions) const | |||
{ | |||
std::unique_ptr<gl::shader_object> vertex_object; | |||
std::unique_ptr<gl::shader_object> fragment_object; | |||
std::unique_ptr<gl::shader_object> geometry_object; | |||
// Create shader program | |||
std::unique_ptr<gl::shader_program> program = std::make_unique<gl::shader_program>(); | |||
if (has_vertex_directive()) | |||
{ | |||
// Compile vertex shader object and attach to shader program | |||
vertex_object = compile(gl::shader_stage::vertex, definitions); | |||
program->attach(*vertex_object); | |||
} | |||
if (has_fragment_directive()) | |||
{ | |||
// Compile fragment shader object and attach to shader program | |||
fragment_object = compile(gl::shader_stage::fragment, definitions); | |||
program->attach(*fragment_object); | |||
} | |||
if (has_geometry_directive()) | |||
{ | |||
// Compile fragment shader object and attach to shader program | |||
geometry_object = compile(gl::shader_stage::geometry, definitions); | |||
program->attach(*geometry_object); | |||
} | |||
// Link attached shader objects into shader program | |||
program->link(); | |||
// Detach all attached shader objects | |||
program->detach_all(); | |||
return program; | |||
} | |||
void shader_template::find_directives() | |||
{ | |||
// Reset directives | |||
vertex_directives.clear(); | |||
fragment_directives.clear(); | |||
geometry_directives.clear(); | |||
define_directives.clear(); | |||
// Parse directives | |||
for (std::size_t i = 0; i < template_source.lines.size(); ++i) | |||
{ | |||
std::istringstream line_stream(template_source.lines[i]); | |||
std::string token; | |||
// Detect `#pragma` directives | |||
if (line_stream >> token && token == "#pragma") | |||
{ | |||
if (line_stream >> token) | |||
{ | |||
// Map line numbers of supported directives | |||
if (token == "define") | |||
{ | |||
if (line_stream >> token) | |||
{ | |||
define_directives.insert({token, i}); | |||
} | |||
} | |||
else if (token == "vertex") | |||
{ | |||
vertex_directives.insert(i); | |||
} | |||
else if (token == "fragment") | |||
{ | |||
fragment_directives.insert(i); | |||
} | |||
else if (token == "geometry") | |||
{ | |||
geometry_directives.insert(i); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
void shader_template::rehash() | |||
{ | |||
m_hash = 0; | |||
for (const auto& line: template_source.lines) | |||
{ | |||
m_hash = hash::combine(m_hash, std::hash<std::string>{}(line)); | |||
} | |||
} | |||
void shader_template::replace_stage_directives(gl::shader_stage stage) const | |||
{ | |||
// Determine stage directives according to the shader stage being generated | |||
const char* vertex_directive = (stage == gl::shader_stage::vertex) ? "#define __VERTEX__" : "/* #undef __VERTEX__ */"; | |||
const char* fragment_directive = (stage == gl::shader_stage::fragment) ? "#define __FRAGMENT__" : "/* #undef __FRAGMENT__ */"; | |||
const char* geometry_directive = (stage == gl::shader_stage::geometry) ? "#define __GEOMETRY__" : "/* #undef __GEOMETRY__ */"; | |||
// Handle `#pragma <stage>` directives | |||
for (const auto directive_line: vertex_directives) | |||
{ | |||
template_source.lines[directive_line] = vertex_directive; | |||
} | |||
for (const auto directive_line: fragment_directives) | |||
{ | |||
template_source.lines[directive_line] = fragment_directive; | |||
} | |||
for (const auto directive_line: geometry_directives) | |||
{ | |||
template_source.lines[directive_line] = geometry_directive; | |||
} | |||
} | |||
void shader_template::replace_define_directives(const dictionary_type& definitions) const | |||
{ | |||
// For each `#pragma define <key>` directive | |||
for (const auto& define_directive: define_directives) | |||
{ | |||
// Get a reference to the directive line | |||
std::string& line = template_source.lines[define_directive.second]; | |||
// Check if the corresponding definition was given by the configuration | |||
auto definitions_it = definitions.find(define_directive.first); | |||
if (definitions_it != definitions.end()) | |||
{ | |||
// Definition found, replace `#pragma define <key>` with `#define <key>` or `#define <key> <value>` | |||
line = "#define " + define_directive.first; | |||
if (!definitions_it->second.empty()) | |||
{ | |||
line += " " + definitions_it->second; | |||
} | |||
} | |||
else | |||
{ | |||
// Definition not found, replace `#pragma define <key>` with the comment `/* #undef <key> */`. | |||
line = "/* #undef " + define_directive.first + " */"; | |||
} | |||
} | |||
} | |||
bool shader_template::has_vertex_directive() const noexcept | |||
{ | |||
return !vertex_directives.empty(); | |||
} | |||
bool shader_template::has_fragment_directive() const noexcept | |||
{ | |||
return !fragment_directives.empty(); | |||
} | |||
bool shader_template::has_geometry_directive() const noexcept | |||
{ | |||
return !geometry_directives.empty(); | |||
} | |||
bool shader_template::has_define_directive(const std::string& key) const | |||
{ | |||
return (define_directives.find(key) != define_directives.end()); | |||
} | |||
} // namespace gl | |||
/** | |||
* Scans a text file for the presence of a `#pragma once` directive. | |||
* | |||
* @param source Text file to scan. | |||
* | |||
* @return `true` if the file contains a `#pragma once` directive, `false` otherwise. | |||
*/ | |||
static bool has_pragma_once(const text_file& source) | |||
{ | |||
for (const auto& line: source.lines) | |||
{ | |||
std::istringstream line_stream(line); | |||
std::string token; | |||
// If line contains a `#pragma once` directive | |||
if (line_stream >> token && token == "#pragma") | |||
{ | |||
if (line_stream >> token && token == "once") | |||
{ | |||
return true; | |||
} | |||
} | |||
} | |||
return false; | |||
} | |||
/** | |||
* Handles `#pragma include` directives by loading the specified text files and inserting them in place. | |||
*/ | |||
static void handle_includes(text_file& source, std::unordered_set<std::filesystem::path>& include_once, resource_manager& resource_manager) | |||
{ | |||
// For each line in the source | |||
for (std::size_t i = 0; i < source.lines.size(); ++i) | |||
{ | |||
std::string token; | |||
std::istringstream line_stream(source.lines[i]); | |||
// If line contains a `#pragma include` directive | |||
if (line_stream >> token && token == "#pragma" && | |||
line_stream >> token && token == "include") | |||
{ | |||
// If third token is enclosed in quotes or angled brackets | |||
if (line_stream >> token && token.size() > 2 && | |||
((token.front() == '\"' && token.back() == '\"') || | |||
(token.front() == '<' && token.back() == '>'))) | |||
{ | |||
// Extract include path | |||
const std::filesystem::path path = token.substr(1, token.length() - 2); | |||
// Skip pre-included files that contain a `#pragma once` directive | |||
if (include_once.contains(path)) | |||
{ | |||
source.lines[i] = "/* #pragma exclude " + token + " */"; | |||
continue; | |||
} | |||
// Load include file | |||
const auto include_file = resource_manager.load<text_file>(path); | |||
if (!include_file) | |||
{ | |||
source.lines[i] = "#error file not found: " + path.string(); | |||
continue; | |||
} | |||
// If file has `#pragma once` directive | |||
if (has_pragma_once(*include_file)) | |||
{ | |||
// Add file to set of files to include once | |||
include_once.insert(path); | |||
} | |||
// Create a copy of the include file | |||
text_file include_file_copy = *include_file; | |||
// Handle `#pragma include` directives inside include file | |||
handle_includes(include_file_copy, include_once, resource_manager); | |||
// Replace #pragma include directive with include file contents | |||
source.lines.erase(source.lines.begin() + i); | |||
source.lines.insert(source.lines.begin() + i, include_file_copy.lines.begin(), include_file_copy.lines.end()); | |||
i += include_file_copy.lines.size() - 1; | |||
} | |||
else | |||
{ | |||
source.lines[i] = "#error malformed include directive: \"" + source.lines[i] + "\""; | |||
} | |||
} | |||
} | |||
} | |||
template <> | |||
std::unique_ptr<gl::shader_template> resource_loader<gl::shader_template>::load(::resource_manager& resource_manager, deserialize_context& ctx) | |||
{ | |||
// Load shader template source file | |||
const auto source_file = resource_loader<text_file>::load(resource_manager, ctx); | |||
// Make a copy of the shader template source file | |||
text_file source_file_copy = *source_file; | |||
// Handle `#pragma include` directives | |||
std::unordered_set<std::filesystem::path> include_once; | |||
include_once.insert(ctx.path()); | |||
handle_includes(source_file_copy, include_once, resource_manager); | |||
// Construct shader template | |||
return std::make_unique<gl::shader_template>(std::move(source_file_copy)); | |||
} |
@ -0,0 +1,396 @@ | |||
/* | |||
* 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/gl/shader-variable.hpp> | |||
#include <stdexcept> | |||
namespace gl { | |||
static const char* type_mismatch_error = "Shader variable type mismatch"; | |||
shader_variable::shader_variable(std::size_t size) noexcept: | |||
m_size{size} | |||
{} | |||
void shader_variable::update(bool value) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const bool2& value) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const bool3& value) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const bool4& value) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(int value) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const int2& value) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const int3& value) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const int4& value) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(unsigned int value) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const uint2& value) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const uint3& value) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const uint4& value) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(float value) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const float2& value) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const float3& value) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const float4& value) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const float2x2& value) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const float3x3& value) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const float4x4& value) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const texture_1d& value) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const texture_2d& value) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const texture_3d& value) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const texture_cube& value) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(bool value, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const bool2& value, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const bool3& value, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const bool4& value, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(int value, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const int2& value, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const int3& value, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const int4& value, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(unsigned int value, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const uint2& value, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const uint3& value, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const uint4& value, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(float value, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const float2& value, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const float3& value, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const float4& value, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const float2x2& value, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const float3x3& value, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const float4x4& value, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const texture_1d& value, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const texture_2d& value, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const texture_3d& value, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(const texture_cube& value, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(std::span<const bool> values, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(std::span<const bool2> values, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(std::span<const bool3> values, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(std::span<const bool4> values, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(std::span<const int> values, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(std::span<const int2> values, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(std::span<const int3> values, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(std::span<const int4> values, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(std::span<const unsigned int> values, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(std::span<const uint2> values, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(std::span<const uint3> values, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(std::span<const uint4> values, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(std::span<const float> values, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(std::span<const float2> values, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(std::span<const float3> values, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(std::span<const float4> values, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(std::span<const float2x2> values, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(std::span<const float3x3> values, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(std::span<const float4x4> values, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(std::span<const texture_1d* const> values, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(std::span<const texture_2d* const> values, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(std::span<const texture_3d* const> values, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(std::span<const texture_cube* const> values, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(std::span<const std::shared_ptr<texture_1d>> values, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(std::span<const std::shared_ptr<texture_2d>> values, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(std::span<const std::shared_ptr<texture_3d>> values, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
void shader_variable::update(std::span<const std::shared_ptr<texture_cube>> values, std::size_t index) const | |||
{ | |||
throw std::invalid_argument(type_mismatch_error); | |||
} | |||
} // namespace gl |
@ -0,0 +1,195 @@ | |||
/* | |||
* 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_SHADER_INPUT_HPP | |||
#define ANTKEEPER_GL_SHADER_INPUT_HPP | |||
#include <engine/utility/fundamental-types.hpp> | |||
#include <engine/gl/shader-variable-type.hpp> | |||
#include <cstdint> | |||
#include <span> | |||
#include <memory> | |||
namespace gl { | |||
class texture_1d; | |||
class texture_2d; | |||
class texture_3d; | |||
class texture_cube; | |||
/** | |||
* Shader program variable. | |||
*/ | |||
class shader_variable | |||
{ | |||
public: | |||
/** | |||
* Destructs a shader variable. | |||
*/ | |||
virtual ~shader_variable() = default; | |||
/** | |||
* Returns the shader variable data type. | |||
*/ | |||
[[nodiscard]] virtual constexpr shader_variable_type type() const noexcept = 0; | |||
/** | |||
* Returns the number of elements in an array variable, or `1` if the variable is not an array. | |||
*/ | |||
[[nodiscard]] inline std::size_t size() const noexcept | |||
{ | |||
return m_size; | |||
} | |||
/** | |||
* Updates the value of the variable. If the variable is an array, the value of the first element will be updated. | |||
* | |||
* @param value Update value. | |||
* | |||
* @throw std::invalid_argument Shader variable type mismatch. | |||
*/ | |||
///@{ | |||
virtual void update(bool value) const; | |||
virtual void update(const bool2& value) const; | |||
virtual void update(const bool3& value) const; | |||
virtual void update(const bool4& value) const; | |||
virtual void update(int value) const; | |||
virtual void update(const int2& value) const; | |||
virtual void update(const int3& value) const; | |||
virtual void update(const int4& value) const; | |||
virtual void update(unsigned int value) const; | |||
virtual void update(const uint2& value) const; | |||
virtual void update(const uint3& value) const; | |||
virtual void update(const uint4& value) const; | |||
virtual void update(float value) const; | |||
virtual void update(const float2& value) const; | |||
virtual void update(const float3& value) const; | |||
virtual void update(const float4& value) const; | |||
virtual void update(const float2x2& value) const; | |||
virtual void update(const float3x3& value) const; | |||
virtual void update(const float4x4& value) const; | |||
virtual void update(const texture_1d& value) const; | |||
virtual void update(const texture_2d& value) const; | |||
virtual void update(const texture_3d& value) const; | |||
virtual void update(const texture_cube& value) const; | |||
///@} | |||
/** | |||
* Updates the value of a single element in an array variable. | |||
* | |||
* @param value Update value. | |||
* @param index Index of the element to update. | |||
* | |||
* @throw std::invalid_argument Shader variable type mismatch. | |||
*/ | |||
/// @{ | |||
virtual void update(bool value, std::size_t index) const; | |||
virtual void update(const bool2& value, std::size_t index) const; | |||
virtual void update(const bool3& value, std::size_t index) const; | |||
virtual void update(const bool4& value, std::size_t index) const; | |||
virtual void update(int value, std::size_t index) const; | |||
virtual void update(const int2& value, std::size_t index) const; | |||
virtual void update(const int3& value, std::size_t index) const; | |||
virtual void update(const int4& value, std::size_t index) const; | |||
virtual void update(unsigned int value, std::size_t index) const; | |||
virtual void update(const uint2& value, std::size_t index) const; | |||
virtual void update(const uint3& value, std::size_t index) const; | |||
virtual void update(const uint4& value, std::size_t index) const; | |||
virtual void update(float value, std::size_t index) const; | |||
virtual void update(const float2& value, std::size_t index) const; | |||
virtual void update(const float3& value, std::size_t index) const; | |||
virtual void update(const float4& value, std::size_t index) const; | |||
virtual void update(const float2x2& value, std::size_t index) const; | |||
virtual void update(const float3x3& value, std::size_t index) const; | |||
virtual void update(const float4x4& value, std::size_t index) const; | |||
virtual void update(const texture_1d& value, std::size_t index) const; | |||
virtual void update(const texture_2d& value, std::size_t index) const; | |||
virtual void update(const texture_3d& value, std::size_t index) const; | |||
virtual void update(const texture_cube& value, std::size_t index) const; | |||
///@} | |||
/** | |||
* Updates the values of one or more elements in an array variable. | |||
* | |||
* @param values Contiguous sequence of update values. | |||
* @param index Index of the first element to update. | |||
* | |||
* @throw std::invalid_argument Shader variable type mismatch. | |||
*/ | |||
///@{ | |||
virtual void update(std::span<const bool> values, std::size_t index = 0) const; | |||
virtual void update(std::span<const bool2> values, std::size_t index = 0) const; | |||
virtual void update(std::span<const bool3> values, std::size_t index = 0) const; | |||
virtual void update(std::span<const bool4> values, std::size_t index = 0) const; | |||
virtual void update(std::span<const int> values, std::size_t index = 0) const; | |||
virtual void update(std::span<const int2> values, std::size_t index = 0) const; | |||
virtual void update(std::span<const int3> values, std::size_t index = 0) const; | |||
virtual void update(std::span<const int4> values, std::size_t index = 0) const; | |||
virtual void update(std::span<const unsigned int> values, std::size_t index = 0) const; | |||
virtual void update(std::span<const uint2> values, std::size_t index = 0) const; | |||
virtual void update(std::span<const uint3> values, std::size_t index = 0) const; | |||
virtual void update(std::span<const uint4> values, std::size_t index = 0) const; | |||
virtual void update(std::span<const float> values, std::size_t index = 0) const; | |||
virtual void update(std::span<const float2> values, std::size_t index = 0) const; | |||
virtual void update(std::span<const float3> values, std::size_t index = 0) const; | |||
virtual void update(std::span<const float4> values, std::size_t index = 0) const; | |||
virtual void update(std::span<const float2x2> values, std::size_t index = 0) const; | |||
virtual void update(std::span<const float3x3> values, std::size_t index = 0) const; | |||
virtual void update(std::span<const float4x4> values, std::size_t index = 0) const; | |||
virtual void update(std::span<const texture_1d* const> values, std::size_t index = 0) const; | |||
virtual void update(std::span<const texture_2d* const> values, std::size_t index = 0) const; | |||
virtual void update(std::span<const texture_3d* const> values, std::size_t index = 0) const; | |||
virtual void update(std::span<const texture_cube* const> values, std::size_t index = 0) const; | |||
virtual void update(std::span<const std::shared_ptr<texture_1d>> values, std::size_t index = 0) const; | |||
virtual void update(std::span<const std::shared_ptr<texture_2d>> values, std::size_t index = 0) const; | |||
virtual void update(std::span<const std::shared_ptr<texture_3d>> values, std::size_t index = 0) const; | |||
virtual void update(std::span<const std::shared_ptr<texture_cube>> values, std::size_t index = 0) const; | |||
///@} | |||
protected: | |||
/** | |||
* Constructs a shader variable. | |||
* | |||
* @param size Number of elements in the array, or `1` if the variable is not an array. | |||
*/ | |||
explicit shader_variable(std::size_t size) noexcept; | |||
private: | |||
const std::size_t m_size; | |||
}; | |||
} // namespace gl | |||
#endif // ANTKEEPER_GL_SHADER_VARIABLE_HPP |
@ -0,0 +1,80 @@ | |||
/* | |||
* 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/i18n/string-table.hpp> | |||
#include <engine/resources/deserializer.hpp> | |||
#include <engine/resources/resource-loader.hpp> | |||
/** | |||
* Deserializes a string table. | |||
* | |||
* @param[out] file Text file to serialize. | |||
* @param[in,out] ctx Deserialize context. | |||
* | |||
* @throw deserialize_error Read error. | |||
*/ | |||
template <> | |||
void deserializer<i18n::string_table>::deserialize(i18n::string_table& table, deserialize_context& ctx) | |||
{ | |||
table.rows.clear(); | |||
std::vector<std::string> row; | |||
std::string entry; | |||
char c; | |||
while (ctx.read8(reinterpret_cast<std::byte*>(&c), 1) == 1) | |||
{ | |||
if (c == '\t') | |||
{ | |||
row.push_back(entry); | |||
entry.clear(); | |||
} | |||
else if (c == '\n') | |||
{ | |||
row.push_back(entry); | |||
entry.clear(); | |||
table.rows.push_back(row); | |||
row.clear(); | |||
} | |||
else if (c != '\r') | |||
{ | |||
entry.push_back(c); | |||
} | |||
} | |||
if (!entry.empty()) | |||
{ | |||
row.push_back(entry); | |||
} | |||
if (!row.empty()) | |||
{ | |||
table.rows.push_back(row); | |||
} | |||
} | |||
template <> | |||
std::unique_ptr<i18n::string_table> resource_loader<i18n::string_table>::load(::resource_manager& resource_manager, deserialize_context& ctx) | |||
{ | |||
auto resource = std::make_unique<i18n::string_table>(); | |||
deserializer<i18n::string_table>().deserialize(*resource, ctx); | |||
return resource; | |||
} |
@ -1,460 +0,0 @@ | |||
/* | |||
* 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_RENDER_MATERIAL_PROPERTY_HPP | |||
#define ANTKEEPER_RENDER_MATERIAL_PROPERTY_HPP | |||
#include <engine/animation/tween.hpp> | |||
#include <engine/gl/shader-variable-type.hpp> | |||
#include <engine/gl/shader-input.hpp> | |||
#include <engine/math/interpolation.hpp> | |||
#include <engine/utility/fundamental-types.hpp> | |||
#include <engine/gl/shader-program.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 <cstddef> | |||
namespace render { | |||
class material; | |||
/** | |||
* Abstract base class for material properties. | |||
*/ | |||
class material_property_base | |||
{ | |||
public: | |||
/** | |||
* Connects the material property to a shader input. | |||
* | |||
* @param input Shader input to which the material property should be connected. | |||
* @return `true` if the property was connected to the input successfully, `false` otherwise. | |||
*/ | |||
bool connect(const gl::shader_input* input); | |||
/** | |||
* Disconnects the material property from its shader input. | |||
*/ | |||
void disconnect(); | |||
/** | |||
* Sets state 0 = state 1. | |||
*/ | |||
virtual void update_tweens() = 0; | |||
/** | |||
* Uploads the material property to its shader program. | |||
* | |||
* @param a Interpolation factor. Should be on `[0.0, 1.0]`. | |||
* @return `true` if the property was uploaded successfully, `false` otherwise. | |||
*/ | |||
virtual bool upload(double a) const = 0; | |||
/** | |||
* Returns the type of data which the property contains. | |||
*/ | |||
virtual gl::shader_variable_type get_data_type() const = 0; | |||
/** | |||
* Returns `true` if the material property is connected to a shader input, `false` otherwise. | |||
*/ | |||
bool is_connected() const; | |||
/** | |||
* Creates a copy of this material property. | |||
*/ | |||
virtual material_property_base* clone() const = 0; | |||
protected: | |||
material_property_base(); | |||
const gl::shader_input* input; | |||
}; | |||
inline bool material_property_base::is_connected() const | |||
{ | |||
return (input != nullptr); | |||
} | |||
/** | |||
* A property of a material which can be uploaded to a shader program via a shader input. | |||
* | |||
* @tparam T Property data type. | |||
*/ | |||
template <class T> | |||
class material_property: public material_property_base | |||
{ | |||
public: | |||
typedef tween<T> tween_type; | |||
typedef typename tween<T>::interpolator_type interpolator_type; | |||
/// Default tween interpolator function for this material property type. | |||
static T default_interpolator(const T& x, const T& y, double a); | |||
/** | |||
* Creates a material property. | |||
* | |||
* @param element_count Number of elements in the property array. | |||
*/ | |||
material_property(std::size_t element_count); | |||
/** | |||
* Destroys a material property. | |||
*/ | |||
virtual ~material_property(); | |||
material_property(const material_property<T>&) = delete; | |||
material_property<T>& operator=(const material_property<T>&) = delete; | |||
/// @copydoc material_property_base::update_tweens() | |||
virtual void update_tweens(); | |||
/// @copydoc material_property_base::upload() const | |||
virtual bool upload(double a) const; | |||
/** | |||
* Sets the value of this property. | |||
* | |||
* @param value Value to set. | |||
*/ | |||
void set_value(const T& value); | |||
/** | |||
* Sets the value of a single element in this array property. | |||
* | |||
* @param index Index of an array element. | |||
* @param value Value to set. | |||
*/ | |||
void set_value(std::size_t index, const T& value); | |||
/** | |||
* Sets the values of a range of elements in this array property. | |||
* | |||
* @param index Index of the first array element to set. | |||
* @param values Pointer to an array of values to set. | |||
* @param count Number of elements to set. | |||
*/ | |||
void set_values(std::size_t index, const T* values, std::size_t count); | |||
/** | |||
* Sets the tween interpolator function. | |||
* | |||
* @param interpolator Tween interpolator function. | |||
*/ | |||
void set_tween_interpolator(interpolator_type interpolator); | |||
/// Returns the value of the first element in this property. | |||
const T& get_value() const; | |||
/** | |||
* Returns the value of the first element in this property. | |||
* | |||
* @param index Index of an array element. | |||
* @return Value of the element at the specified index. | |||
*/ | |||
const T& get_value(std::size_t index) const; | |||
/// @copydoc material_property_base::get_data_type() const | |||
virtual gl::shader_variable_type get_data_type() const; | |||
/// @copydoc material_property_base::clone() const | |||
virtual material_property_base* clone() const; | |||
private: | |||
std::size_t element_count; | |||
tween<T>* values; | |||
}; | |||
template <typename T> | |||
inline T material_property<T>::default_interpolator(const T& x, const T& y, double a) | |||
{ | |||
return y; | |||
} | |||
template <> | |||
inline float material_property<float>::default_interpolator(const float& x, const float& y, double a) | |||
{ | |||
return math::lerp<float, float>(x, y, static_cast<float>(a)); | |||
} | |||
template <> | |||
inline float2 material_property<float2>::default_interpolator(const float2& x, const float2& y, double a) | |||
{ | |||
return math::lerp<float2, float>(x, y, static_cast<float>(a)); | |||
} | |||
template <> | |||
inline float3 material_property<float3>::default_interpolator(const float3& x, const float3& y, double a) | |||
{ | |||
return math::lerp<float3, float>(x, y, static_cast<float>(a)); | |||
} | |||
template <> | |||
inline float4 material_property<float4>::default_interpolator(const float4& x, const float4& y, double a) | |||
{ | |||
return math::lerp<float4, float>(x, y, static_cast<float>(a)); | |||
} | |||
template <class T> | |||
material_property<T>::material_property(std::size_t element_count): | |||
element_count(element_count), | |||
values(nullptr) | |||
{ | |||
values = new tween<T>[element_count]; | |||
set_tween_interpolator(default_interpolator); | |||
} | |||
template <class T> | |||
material_property<T>::~material_property() | |||
{ | |||
delete[] values; | |||
} | |||
template <class T> | |||
void material_property<T>::update_tweens() | |||
{ | |||
for (std::size_t i = 0; i < element_count; ++i) | |||
{ | |||
values[i].update(); | |||
} | |||
} | |||
template <class T> | |||
bool material_property<T>::upload(double a) const | |||
{ | |||
if (!is_connected()) | |||
{ | |||
return false; | |||
} | |||
if (element_count > 1) | |||
{ | |||
for (std::size_t i = 0; i < element_count; ++i) | |||
{ | |||
if (!input->upload(i, values[i].interpolate(static_cast<float>(a)))) | |||
return false; | |||
} | |||
return true; | |||
} | |||
else | |||
{ | |||
return input->upload(values[0].interpolate(static_cast<float>(a))); | |||
} | |||
} | |||
template <class T> | |||
void material_property<T>::set_value(const T& value) | |||
{ | |||
values[0][1] = value; | |||
} | |||
template <class T> | |||
void material_property<T>::set_value(std::size_t index, const T& value) | |||
{ | |||
values[index][1] = value; | |||
} | |||
template <class T> | |||
void material_property<T>::set_values(std::size_t index, const T* values, std::size_t count) | |||
{ | |||
for (std::size_t i = 0; i < count; ++i) | |||
{ | |||
this->values[index + i][1] = values[i]; | |||
} | |||
} | |||
template <class T> | |||
void material_property<T>::set_tween_interpolator(interpolator_type interpolator) | |||
{ | |||
for (std::size_t i = 0; i < element_count; ++i) | |||
{ | |||
this->values[i].set_interpolator(interpolator); | |||
} | |||
} | |||
template <class T> | |||
inline const T& material_property<T>::get_value() const | |||
{ | |||
return values[0][1]; | |||
} | |||
template <class T> | |||
inline const T& material_property<T>::get_value(std::size_t index) const | |||
{ | |||
return values[index][1]; | |||
} | |||
template <> | |||
inline gl::shader_variable_type material_property<bool>::get_data_type() const | |||
{ | |||
return gl::shader_variable_type::bool1; | |||
} | |||
template <> | |||
inline gl::shader_variable_type material_property<bool2>::get_data_type() const | |||
{ | |||
return gl::shader_variable_type::bool2; | |||
} | |||
template <> | |||
inline gl::shader_variable_type material_property<bool3>::get_data_type() const | |||
{ | |||
return gl::shader_variable_type::bool3; | |||
} | |||
template <> | |||
inline gl::shader_variable_type material_property<bool4>::get_data_type() const | |||
{ | |||
return gl::shader_variable_type::bool4; | |||
} | |||
template <> | |||
inline gl::shader_variable_type material_property<int>::get_data_type() const | |||
{ | |||
return gl::shader_variable_type::int1; | |||
} | |||
template <> | |||
inline gl::shader_variable_type material_property<int2>::get_data_type() const | |||
{ | |||
return gl::shader_variable_type::int2; | |||
} | |||
template <> | |||
inline gl::shader_variable_type material_property<int3>::get_data_type() const | |||
{ | |||
return gl::shader_variable_type::int3; | |||
} | |||
template <> | |||
inline gl::shader_variable_type material_property<int4>::get_data_type() const | |||
{ | |||
return gl::shader_variable_type::int4; | |||
} | |||
template <> | |||
inline gl::shader_variable_type material_property<unsigned int>::get_data_type() const | |||
{ | |||
return gl::shader_variable_type::uint1; | |||
} | |||
template <> | |||
inline gl::shader_variable_type material_property<uint2>::get_data_type() const | |||
{ | |||
return gl::shader_variable_type::uint2; | |||
} | |||
template <> | |||
inline gl::shader_variable_type material_property<uint3>::get_data_type() const | |||
{ | |||
return gl::shader_variable_type::uint3; | |||
} | |||
template <> | |||
inline gl::shader_variable_type material_property<uint4>::get_data_type() const | |||
{ | |||
return gl::shader_variable_type::uint4; | |||
} | |||
template <> | |||
inline gl::shader_variable_type material_property<float>::get_data_type() const | |||
{ | |||
return gl::shader_variable_type::float1; | |||
} | |||
template <> | |||
inline gl::shader_variable_type material_property<float2>::get_data_type() const | |||
{ | |||
return gl::shader_variable_type::float2; | |||
} | |||
template <> | |||
inline gl::shader_variable_type material_property<float3>::get_data_type() const | |||
{ | |||
return gl::shader_variable_type::float3; | |||
} | |||
template <> | |||
inline gl::shader_variable_type material_property<float4>::get_data_type() const | |||
{ | |||
return gl::shader_variable_type::float4; | |||
} | |||
template <> | |||
inline gl::shader_variable_type material_property<float2x2>::get_data_type() const | |||
{ | |||
return gl::shader_variable_type::float2x2; | |||
} | |||
template <> | |||
inline gl::shader_variable_type material_property<float3x3>::get_data_type() const | |||
{ | |||
return gl::shader_variable_type::float3x3; | |||
} | |||
template <> | |||
inline gl::shader_variable_type material_property<float4x4>::get_data_type() const | |||
{ | |||
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 <> | |||
inline gl::shader_variable_type material_property<const gl::texture_2d*>::get_data_type() const | |||
{ | |||
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 <> | |||
inline gl::shader_variable_type material_property<const gl::texture_cube*>::get_data_type() const | |||
{ | |||
return gl::shader_variable_type::texture_cube; | |||
} | |||
template <class T> | |||
material_property_base* material_property<T>::clone() const | |||
{ | |||
material_property<T>* property = new material_property<T>(element_count); | |||
for (std::size_t i = 0; i < element_count; ++i) | |||
{ | |||
property->values[i][0] = values[i][0]; | |||
property->values[i][1] = values[i][1]; | |||
} | |||
property->input = input; | |||
return property; | |||
} | |||
} // namespace render | |||
#endif // ANTKEEPER_RENDER_MATERIAL_PROPERTY_HPP |
@ -0,0 +1,373 @@ | |||
/* | |||
* 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_RENDER_MATERIAL_VARIABLE_HPP | |||
#define ANTKEEPER_RENDER_MATERIAL_VARIABLE_HPP | |||
#include <engine/utility/fundamental-types.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 <engine/render/material-variable-type.hpp> | |||
#include <memory> | |||
#include <vector> | |||
namespace render { | |||
/** | |||
* Abstract base class for material variables. | |||
*/ | |||
class material_variable_base | |||
{ | |||
public: | |||
/** | |||
* Destructs a material variable base. | |||
*/ | |||
virtual ~material_variable_base() = default; | |||
/** | |||
* Returns the material variable data type. | |||
*/ | |||
[[nodiscard]] virtual constexpr material_variable_type type() const noexcept = 0; | |||
/** | |||
* Returns the number of elements in an array variable, or `1` if the variable is not an array. | |||
*/ | |||
[[nodiscard]] virtual std::size_t size() const noexcept = 0; | |||
/** | |||
* Creates a copy of this material property. | |||
*/ | |||
[[nodiscard]] virtual std::unique_ptr<material_variable_base> clone() const = 0; | |||
}; | |||
/** | |||
* Material variable. | |||
* | |||
* @tparam T Material variable value type. | |||
*/ | |||
template <class T> | |||
class material_variable: public material_variable_base | |||
{ | |||
public: | |||
/// Material variable element type. | |||
using element_type = T; | |||
/** | |||
* Constructs a material variable. | |||
* | |||
* @param size Number of elements in the array, or `1` if the variable is not an array. | |||
* @param value Value with which to initialize the elements. | |||
*/ | |||
inline material_variable(std::size_t size, const element_type& value = element_type()): | |||
elements(size, value) | |||
{} | |||
/** | |||
* Constructs a material variable with a single element. | |||
*/ | |||
inline material_variable(): | |||
material_variable(1) | |||
{} | |||
/** | |||
* Constructs a material variable from a list of element values. | |||
* | |||
* @param list List of element values. | |||
*/ | |||
inline material_variable(std::initializer_list<element_type> list): | |||
elements(list) | |||
{} | |||
[[nodiscard]] virtual constexpr material_variable_type type() const noexcept override; | |||
[[nodiscard]] inline std::size_t size() const noexcept override | |||
{ | |||
return elements.size(); | |||
} | |||
[[nodiscard]] inline std::unique_ptr<material_variable_base> clone() const override | |||
{ | |||
return std::make_unique<material_variable<T>>(*this); | |||
} | |||
/** | |||
* Sets the value of the the variable, or the value of the first element if the variable is an array. | |||
* | |||
* @param value Value to set. | |||
*/ | |||
inline void set(const element_type& value) | |||
{ | |||
elements.front() = value; | |||
} | |||
/** | |||
* Sets the value of a single element in an array variable. | |||
* | |||
* @param index Index of an element. | |||
* @param value Value to set. | |||
*/ | |||
inline void set(std::size_t index, const element_type& value) | |||
{ | |||
elements[index] = value; | |||
} | |||
/** | |||
* Returns a reference to the first element in the array. | |||
*/ | |||
[[nodiscard]] inline const element_type& get() const | |||
{ | |||
return elements.front(); | |||
} | |||
/** | |||
* Returns a reference to the element at a given index. | |||
* | |||
* @param index Index of an element. | |||
* | |||
* @return Reference to the element at @p index. | |||
*/ | |||
[[nodiscard]] inline const element_type& get(std::size_t index) const | |||
{ | |||
return elements[index]; | |||
} | |||
/** | |||
* Returns a pointer to the element array. | |||
*/ | |||
[[nodiscard]] inline const element_type* data() const noexcept | |||
{ | |||
return elements.data(); | |||
} | |||
private: | |||
std::vector<element_type> elements; | |||
}; | |||
/// Boolean material variable. | |||
using material_bool = material_variable<bool>; | |||
/// 2-dimensional boolean vector material variable. | |||
using material_bool2 = material_variable<bool2>; | |||
/// 3-dimensional boolean vector material variable. | |||
using material_bool3 = material_variable<bool3>; | |||
/// 4-dimensional boolean vector material variable. | |||
using material_bool4 = material_variable<bool4>; | |||
/// Integer material variable. | |||
using material_int = material_variable<int>; | |||
/// 2-dimensional integer vector material variable. | |||
using material_int2 = material_variable<int2>; | |||
/// 3-dimensional integer vector material variable. | |||
using material_int3 = material_variable<int3>; | |||
/// 4-dimensional integer vector material variable. | |||
using material_int4 = material_variable<int4>; | |||
/// Unsigned integer material variable. | |||
using material_uint = material_variable<unsigned int>; | |||
/// 2-dimensional unsigned integer vector material variable. | |||
using material_uint2 = material_variable<uint2>; | |||
/// 3-dimensional unsigned integer vector material variable. | |||
using material_uint3 = material_variable<uint3>; | |||
/// 4-dimensional unsigned integer vector material variable. | |||
using material_uint4 = material_variable<uint4>; | |||
/// Floating-point material variable. | |||
using material_float = material_variable<float>; | |||
/// 2-dimensional floating-point vector material variable. | |||
using material_float2 = material_variable<float2>; | |||
/// 3-dimensional floating-point vector material variable. | |||
using material_float3 = material_variable<float3>; | |||
/// 4-dimensional floating-point vector material variable. | |||
using material_float4 = material_variable<float4>; | |||
/// 2x2 floating-point matrix material variable. | |||
using material_float2x2 = material_variable<float2x2>; | |||
/// 3x3 floating-point matrix material variable. | |||
using material_float3x3 = material_variable<float3x3>; | |||
/// 4x4 floating-point matrix material variable. | |||
using material_float4x4 = material_variable<float4x4>; | |||
/// 1-dimensional texture material variable. | |||
using material_texture_1d = material_variable<std::shared_ptr<gl::texture_1d>>; | |||
/// 2-dimensional texture material variable. | |||
using material_texture_2d = material_variable<std::shared_ptr<gl::texture_2d>>; | |||
/// 3-dimensional texture material variable. | |||
using material_texture_3d = material_variable<std::shared_ptr<gl::texture_3d>>; | |||
/// Cube texture material variable. | |||
using material_texture_cube = material_variable<std::shared_ptr<gl::texture_cube>>; | |||
template <> | |||
inline constexpr material_variable_type material_bool::type() const noexcept | |||
{ | |||
return material_variable_type::bool1; | |||
} | |||
template <> | |||
inline constexpr material_variable_type material_bool2::type() const noexcept | |||
{ | |||
return material_variable_type::bool2; | |||
} | |||
template <> | |||
inline constexpr material_variable_type material_bool3::type() const noexcept | |||
{ | |||
return material_variable_type::bool3; | |||
} | |||
template <> | |||
inline constexpr material_variable_type material_bool4::type() const noexcept | |||
{ | |||
return material_variable_type::bool4; | |||
} | |||
template <> | |||
inline constexpr material_variable_type material_int::type() const noexcept | |||
{ | |||
return material_variable_type::int1; | |||
} | |||
template <> | |||
inline constexpr material_variable_type material_int2::type() const noexcept | |||
{ | |||
return material_variable_type::int2; | |||
} | |||
template <> | |||
inline constexpr material_variable_type material_int3::type() const noexcept | |||
{ | |||
return material_variable_type::int3; | |||
} | |||
template <> | |||
inline constexpr material_variable_type material_int4::type() const noexcept | |||
{ | |||
return material_variable_type::int4; | |||
} | |||
template <> | |||
inline constexpr material_variable_type material_uint::type() const noexcept | |||
{ | |||
return material_variable_type::uint1; | |||
} | |||
template <> | |||
inline constexpr material_variable_type material_uint2::type() const noexcept | |||
{ | |||
return material_variable_type::uint2; | |||
} | |||
template <> | |||
inline constexpr material_variable_type material_uint3::type() const noexcept | |||
{ | |||
return material_variable_type::uint3; | |||
} | |||
template <> | |||
inline constexpr material_variable_type material_uint4::type() const noexcept | |||
{ | |||
return material_variable_type::uint4; | |||
} | |||
template <> | |||
inline constexpr material_variable_type material_float::type() const noexcept | |||
{ | |||
return material_variable_type::float1; | |||
} | |||
template <> | |||
inline constexpr material_variable_type material_float2::type() const noexcept | |||
{ | |||
return material_variable_type::float2; | |||
} | |||
template <> | |||
inline constexpr material_variable_type material_float3::type() const noexcept | |||
{ | |||
return material_variable_type::float3; | |||
} | |||
template <> | |||
inline constexpr material_variable_type material_float4::type() const noexcept | |||
{ | |||
return material_variable_type::float4; | |||
} | |||
template <> | |||
inline constexpr material_variable_type material_float2x2::type() const noexcept | |||
{ | |||
return material_variable_type::float2x2; | |||
} | |||
template <> | |||
inline constexpr material_variable_type material_float3x3::type() const noexcept | |||
{ | |||
return material_variable_type::float3x3; | |||
} | |||
template <> | |||
inline constexpr material_variable_type material_float4x4::type() const noexcept | |||
{ | |||
return material_variable_type::float4x4; | |||
} | |||
template <> | |||
inline constexpr material_variable_type material_texture_1d::type() const noexcept | |||
{ | |||
return material_variable_type::texture_1d; | |||
} | |||
template <> | |||
inline constexpr material_variable_type material_texture_2d::type() const noexcept | |||
{ | |||
return material_variable_type::texture_2d; | |||
} | |||
template <> | |||
inline constexpr material_variable_type material_texture_3d::type() const noexcept | |||
{ | |||
return material_variable_type::texture_3d; | |||
} | |||
template <> | |||
inline constexpr material_variable_type material_texture_cube::type() const noexcept | |||
{ | |||
return material_variable_type::texture_cube; | |||
} | |||
} // namespace render | |||
#endif // ANTKEEPER_RENDER_MATERIAL_VARIABLE_HPP |