Compare commits

..
8 Commits
32 changed files with 1020 additions and 224 deletions
+22 -10
View File
@@ -11,6 +11,7 @@ endif()
# Options # Options
option(BUILD_SHARED_LIBS "Build shared libraries" OFF) option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
option(INFERNO_BUILD_EXAMPLES "Build the Inferno example programs" ${INFERNO_STANDALONE}) option(INFERNO_BUILD_EXAMPLES "Build the Inferno example programs" ${INFERNO_STANDALONE})
option(INFERNO_BUILD_WARNINGS "Build with warnings enabled" ${INFERNO_STANDALONE})
# ------------------------------------------ # ------------------------------------------
@@ -25,10 +26,15 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_EXTENSIONS OFF)
# Compiler flags used for all build types # Compiler flags used for all build types
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic") set(COMPILE_FLAGS_DEPS -w)
# -Wall = All warnings about contructions that are easily avoidable if(INFERNO_BUILD_WARNINGS)
# -Wextra = Extra warning flags not covered by -Wall set(COMPILE_FLAGS_PROJECT -Wall -Wextra -Wpedantic)
# -Wpedantic = Warnings for compiler extensions not part of the standard # -Wall = All warnings about contructions that are easily avoidable
# -Wextra = Extra warning flags not covered by -Wall
# -Wpedantic = Warnings for compiler extensions not part of the standard
else()
set(COMPILE_FLAGS_PROJECT ${COMPILE_FLAGS_DEPS})
endif()
# Set default build type if not specified # Set default build type if not specified
set(DEFAULT_BUILD_TYPE Release) set(DEFAULT_BUILD_TYPE Release)
@@ -42,14 +48,20 @@ endif()
# Set build type specific compiler flags # Set build type specific compiler flags
message("--- ${CMAKE_BUILD_TYPE} ---") message("--- ${CMAKE_BUILD_TYPE} ---")
if(${CMAKE_BUILD_TYPE} STREQUAL Debug) if(${CMAKE_BUILD_TYPE} STREQUAL Debug)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Og -g -pg") # Optimizations that do not interfere with debugging
# -Og = Optimizations that do not interfere with debugging string(APPEND CMAKE_CXX_FLAGS_DEBUG " -Og")
# -g = Produce debugging information in OS's native format # Produce debugging information in OS's native format
# -pg = Generate profile information for analysis with gprof string(APPEND CMAKE_CXX_FLAGS_DEBUG " -g")
# Generate profile information for analysis with gprof
# $ gprof <PROJECT> gmon.out > profile-data.txt # $ gprof <PROJECT> gmon.out > profile-data.txt
string(APPEND CMAKE_CXX_FLAGS_DEBUG " -pg")
# Enable ASan (Address Sanitizer) and UBSan (Undefined Behavior Sanitizer)
string(APPEND CMAKE_CXX_FLAGS_DEBUG " -fsanitize=address,undefined")
# Do not omit frame pointer, which helps with debugging.
string(APPEND CMAKE_CXX_FLAGS_DEBUG " -fno-omit-frame-pointer")
elseif(${CMAKE_BUILD_TYPE} STREQUAL Release) elseif(${CMAKE_BUILD_TYPE} STREQUAL Release)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3") # Optimizations that increase compilation time and performance
# -O3 = Optimizations that increase compilation time and performance string(APPEND CMAKE_CXX_FLAGS_RELEASE " -O3")
endif() endif()
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+2 -2
View File
@@ -8,7 +8,7 @@ out vec4 v_color;
out vec3 v_textureCoordinates; out vec3 v_textureCoordinates;
out flat uint v_textureIndex; out flat uint v_textureIndex;
uniform mat4 u_projectionView2; uniform mat4 u_projectionView;
void main() void main()
{ {
@@ -16,5 +16,5 @@ void main()
v_textureCoordinates = a_position; v_textureCoordinates = a_position;
v_textureIndex = a_textureIndex; v_textureIndex = a_textureIndex;
// Vclip = Camera projection * Camera view * Model transform * Vlocal // Vclip = Camera projection * Camera view * Model transform * Vlocal
gl_Position = u_projectionView2 * vec4(a_position, 1.0f); gl_Position = u_projectionView * vec4(a_position, 1.0f);
} }
+3
View File
@@ -10,5 +10,8 @@ uniform samplerCube u_textures[32];
void main() void main()
{ {
// Prevent u_textures variable from getting optimized away
if (texture(u_textures[0], vec3(0.0f)).x > 99999.0f) { discard; }
color = v_color; color = v_color;
} }
+2 -2
View File
@@ -25,8 +25,8 @@ struct DirectionalLight {
vec3 specular; vec3 specular;
}; };
const int MAX_DIRECTIONAL_LIGHTS = 32; const int MAX_DIRECTIONAL_LIGHTS = 4;
layout(std140, binding = 1) uniform DirectionalLights { layout(std430, binding = 0) buffer DirectionalLights {
DirectionalLight u_directionalLight[MAX_DIRECTIONAL_LIGHTS]; DirectionalLight u_directionalLight[MAX_DIRECTIONAL_LIGHTS];
}; };
+9
View File
@@ -0,0 +1,9 @@
#+TITLE: Documentation
#+AUTHOR: Riyyi
#+LANGUAGE: en
#+OPTIONS: toc:nil
Topics:
- [[./shaders.org][Shaders]]
- [[./references.org][References]]
+326
View File
@@ -0,0 +1,326 @@
#+TITLE: Memory Layout
#+AUTHOR: Riyyi
#+LANGUAGE: en
#+OPTIONS: toc:nil
This chapter is about the memory layout of interface blocks in GLSL.
An interface block is a group of variables, a struct if you will.
There are 4 types of memory layouts that can be used, where the first two aren't
widely used as those are implementation dependent and require querying the
OpenGL API for memory offsets.
- packed
- shared
- std140
- std430
** std140
This type is usable in Uniform Buffer Objects (=UBO=) and Shader Storage Buffer
Objects (=SSBO=).
** std430
This type is only usable in Shader Storage Buffer Objects (=SSBO=).
Main points:
- Memory is organized into chunks.
- One chunk has 4 slots, 4 bytes per slot.
- Can't fit? Move to next chunk.
- An interface block is at least the size of 1 chunk.
The rules:
- Scalar =bool=, =int=, =uint=, =float=, and =double=
#+BEGIN_SRC
Both the size and alignment are the size of the scalar in basic machine types
(e.g., sizeof(GLfloat))
#+END_SRC
- Two-componment Vectors (e.g., =ivec2=)
#+BEGIN_SRC
Both the size and alignment are twice the size of the underlying scalar type.
#+END_SRC
- Three-component Vectors (e.g., =vec3=) and Four-component Vectors (e.g., =vec4=)
#+BEGIN_SRC
Both the size and alignment are four times the size of the scalar type. However,
this is only true when the member is part of an array or nested structure
#+END_SRC
- Array of Scalars and Vectors
#+BEGIN_SRC
The size of each element in the array will be the same size of the element type,
where three-component vectors are rounded up to the size four-component
vectors. This is also the array's alignment. The array's size will be the
element size times the number of elements.
#+END_SRC
- Column-major matrix or an array of column-major matrices of size C columns and R rows
#+BEGIN_SRC
Same layout as an array of N vectors each with R components, where N is the
total number of columns present.
#+END_SRC
- Row-major matrix or an array of row-major matrices of size R rows and C columns
#+BEGIN_SRC
Same layout as an array of N vectors each with C components, where N is the
total number of rows present.
#+END_SRC
Both =GLSL= and the =GLM= math library we're using have column-major matrices!
- Single-structure definition or an array of structures
#+BEGIN_SRC
Structure alignment is the same as the alignment of the biggest structure
member, where three-component vectors are rounded up to the size of
four-component vectors. Each structure will start on this alignment, and its
size will be the space neeeded by its members, according to the previous rules,
rounded up to a multiple of the structure alignment.
#+END_SRC
All of the examples described in the following segments are verified by querying
the OpenGL API.
*** Scalars
These types take up 1 (or 2 with =double=) slot and can appear after anything.
In the example below you can see that due to the larger alignment, the ~double~
is forced to the next chunk.
#+BEGIN_SRC glsl
// Var Size Alignment Offset
bool a; // 4 4 0
int b; // 4 4 4
uint c; // 4 4 8
double d; // 8 8 16
float e; // 4 4 24
#+END_SRC
#+BEGIN_SRC
Chunks:
[a][b][c][ ] #1
[d][d][e][ ] #2
#+END_SRC
*** Two-component Vectors
**** Float
A Vec2 takes up 2 slots, so will be in the first or last half of a chunk.
#+BEGIN_SRC glsl
// Var Size Alignment Offset
vec2 a; // 8 8 0
float b; // 4 4 8
#+END_SRC
#+BEGIN_SRC
Chunks:
[a][a][b][ ] #1
#+END_SRC
#+BEGIN_SRC glsl
// Var Size Alignment Offset
float a; // 4 4 0
vec2 b; // 8 8 8
#+END_SRC
#+BEGIN_SRC
Chunks:
[a][ ][b][b] #1
#+END_SRC
**** Double
#+BEGIN_SRC glsl
// Var Size Alignment Offset
float a; // 4 4 0
dvec2 b; // 16 16 16
#+END_SRC
#+BEGIN_SRC
Chunks:
[a][ ][ ][ ] #1
[b][b][b][b] #2
#+END_SRC
*** Three-component and Four-component Vectors
A Vec3 takes up 3 slots, the alignment is 4 slots so only fits at the start of a
chunk.
#+BEGIN_SRC glsl
// Var Size Alignment Offset
vec3 a; // 12 16 0
float b; // 4 4 12
vec4 c; // 16 16 16
#+END_SRC
#+BEGIN_SRC
Chunks:
[a][a][a][b] #1
[c][c][c][c] #2
#+END_SRC
#+BEGIN_SRC glsl
// Var Size Alignment Offset
float a; // 4 4 0
vec3 b; // 12 16 16
vec4 c; // 16 16 32
#+END_SRC
#+BEGIN_SRC
Chunks:
[a][ ][ ][ ] #1
[b][b][b][ ] #2
[c][c][c][c] #3
#+END_SRC
*** Array of Scalars and Vectors
#+BEGIN_SRC glsl
// Var Size Alignment Offset
float[3] a; // 12 4 0
float b; // 4 4 12
float c; // 4 4 16
float[3] d; // 12 4 20
#+END_SRC
#+BEGIN_SRC
Chunks:
[a][a][a][b] #1
[c][d][d][d] #1
#+END_SRC
*Note* the optimizations in the alignment and strides are not applicable to
~vec3~ elements, these remain unchanged from =std140=.
#+BEGIN_SRC glsl
// Var Size Alignment Offset
float a; // 4 4 0
vec3[3] b; // 48 16 16
float c; // 4 4 64
float d; // 4 4 68
vec2[2] e; // 16 8 72
float f; // 4 4 88
#+END_SRC
#+BEGIN_SRC
Chunks:
[a][ ][ ][ ] #1, offset: 0
[b][b][b][ ] #2, offset: 16
[b][b][b][ ] #3, offset: 32
[b][b][b][ ] #4, offset: 48
[c][d][e][e] #5, offset: 64
[e][e][f][ ] #6, offset: 80
#+END_SRC
*Note* the offset needs to be a multiple of the alignment, forcing an entire
empty chunk in the example below.
#+BEGIN_SRC glsl
// Var Size Alignment Offset
float a; // 4 4 0
dvec2[2] b; // 32 16 16
dvec3[2] c; // 64 32 64
float d; // 4 4 128
#+END_SRC
#+BEGIN_SRC
Chunks:
[a][ ][ ][ ] #1, offset: 0
[d][d][d][d] #2, offset: 16
[d][d][d][d] #3, offset: 32
[ ][ ][ ][ ] #4, offset: 48
[c][c][c][c] #5, offset: 64
[c][c][ ][ ] #6, offset: 80
[c][c][c][c] #7, offset: 96
[c][c][ ][ ] #8, offset: 112
[d][ ][ ][ ] #9, offset: 128
#+END_SRC
*** Matrices
Alignment is the same as an array of 1 “row” of the matrix.
No padding between the “rows” of a matrix, but will pad at the end.
#+BEGIN_SRC glsl
// Var Size Alignment Offset
float a; // 4 4 0
mat2 b; // 16 8 8
vec2 c; // 4 4 24
float d; // 4 4 32
mat2[2] e; // 32 8 40
float f; // 4 4 72
#+END_SRC
#+BEGIN_SRC
Chunks:
[a][ ][b][b] #1, offset: 0
[b][b][c][c] #2, offset: 16
[d][ ][e][e] #3, offset: 32
[e][e][e][e] #4, offset: 48
[e][e][f][ ] #5, offset: 64
#+END_SRC
TODO: Add more examples
*** Structs
Alignment same as biggest struct member. Size is the size of all members,
rounded up to a multiple of the alignment.
In the example below you can see that the ~Stuff~ struct, including padding
between members, is 20 bytes in size. To make that a multiple of the alignment
additional padding needs to be put at the end, to make the total size 24 bytes.
Each element in the array of structs will apply the alignment again, as seen
with ~Stuff[1].a~.
#+BEGIN_SRC glsl
struct Stuff {
float a;
vec2 b;
float c;
};
// Var Size Alignment Offset
Stuff a; // 20 8
a.a; // 4 4 0
a.b; // 8 8 8
a.c; // 4 4 16
float b; // 4 4 24
Stuff[2] c; // 44 8
c.a; // 4 4 32
c.b; // 8 8 40
c.c; // 4 4 48
float d; // 4 4 80
#+END_SRC
#+BEGIN_SRC
Chunks:
[a][ ][a][a] #1, offset: 0
[a][ ][b][ ] #2, offset: 16
[c][ ][c][c] #3, offset: 32
[c][ ][c][ ] #4, offset: 48
[c][c][c][ ] #5, offset: 64
[d][ ][ ][ ] #6, offset: 80
#+END_SRC
TODO: Add more examples
* References
- https://learnopengl.com/Advanced-OpenGL/Advanced-GLSL
- https://www.khronos.org/opengl/wiki/Interface_Block_(GLSL)#Memory_layout
- [[https://www.oreilly.com/library/view/opengl-programming-guide/9780132748445/app09lev1sec2.html][The std140 Layout Rules]]
- [[https://www.youtube.com/watch?v=JPvbRko9lBg][(YouTube) WebGL 2: Uniform Buffer Objects]]
+1
View File
@@ -0,0 +1 @@
+8
View File
@@ -0,0 +1,8 @@
#+TITLE: Shaders
#+AUTHOR: Riyyi
#+LANGUAGE: en
#+OPTIONS: toc:nil
Topics:
- [[./memory-layout.org][Memory Layout]]
+1
View File
@@ -15,6 +15,7 @@ add_executable(${GAME} ${GAME_SOURCES})
target_include_directories(${GAME} PRIVATE target_include_directories(${GAME} PRIVATE
"src") "src")
target_link_libraries(${GAME} ${ENGINE}) target_link_libraries(${GAME} ${ENGINE})
target_compile_options(${GAME} PRIVATE ${COMPILE_FLAGS_PROJECT})
target_precompile_headers(${GAME} REUSE_FROM ${ENGINE}) target_precompile_headers(${GAME} REUSE_FROM ${ENGINE})
+1
View File
@@ -10,6 +10,7 @@ target_include_directories(${ENGINE} PUBLIC
"../vendor/sol2/include" "../vendor/sol2/include"
"../vendor/stb") "../vendor/stb")
target_link_libraries(${ENGINE} ${ENGINE}-dependencies) target_link_libraries(${ENGINE} ${ENGINE}-dependencies)
target_compile_options(${ENGINE} PRIVATE ${COMPILE_FLAGS_PROJECT})
# ------------------------------------------ # ------------------------------------------
+2
View File
@@ -4,6 +4,8 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
#pragma once
#include <cstdint> // int32_t, uint32_t #include <cstdint> // int32_t, uint32_t
#include <string_view> #include <string_view>
#include <unordered_map> #include <unordered_map>
+1 -1
View File
@@ -8,7 +8,7 @@
#include "inferno/asset/texture.h" #include "inferno/asset/texture.h"
#include "inferno/component/cubemap-component.h" #include "inferno/component/cubemap-component.h"
#include "inferno/component/spritecomponent.h" // TODO: Move glm::x toJson/fromJson to separate file #include "inferno/component/serialize.h" // not detected as used by clang-tidy
namespace Inferno { namespace Inferno {
+1 -1
View File
@@ -8,7 +8,7 @@
#include "inferno/asset/asset-manager.h" #include "inferno/asset/asset-manager.h"
#include "inferno/asset/model.h" #include "inferno/asset/model.h"
#include "inferno/asset/texture.h" #include "inferno/asset/texture.h"
#include "inferno/component/spritecomponent.h" // TODO: Move glm::x toJson/fromJson to separate file #include "inferno/component/serialize.h" // not detected as used by clang-tidy
namespace Inferno { namespace Inferno {
+127
View File
@@ -0,0 +1,127 @@
/*
* Copyright (C) 2024 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#include "glm/ext/matrix_float2x2.hpp"
#include "glm/ext/matrix_float3x3.hpp"
#include "glm/ext/matrix_float4x4.hpp"
#include "glm/ext/vector_float2.hpp"
#include "glm/ext/vector_float3.hpp"
#include "glm/ext/vector_float4.hpp"
#include "ruc/json/json.h"
#include "inferno/component/serialize.h"
namespace glm {
void toJson(ruc::Json& json, const vec2& value)
{
json = ruc::Json {
{ value.x, value.y },
};
}
void fromJson(const ruc::Json& json, vec2& value)
{
VERIFY(json.type() == ruc::Json::Type::Array);
auto& values = json.asArray();
VERIFY(values.size() == 2, "glm::vec2 expected 2 values, got: {}", values.size());
value.x = values.at(0).get<float>();
value.y = values.at(1).get<float>();
}
// -----------------------------------------
void toJson(ruc::Json& json, const vec3& value)
{
json = ruc::Json {
{ value.x, value.y, value.z },
};
}
void fromJson(const ruc::Json& json, vec3& value)
{
VERIFY(json.type() == ruc::Json::Type::Array);
auto& values = json.asArray();
VERIFY(values.size() == 3, "glm::vec3 expected 3 values, got: {}", values.size());
value.x = values.at(0).get<float>();
value.y = values.at(1).get<float>();
value.z = values.at(2).get<float>();
}
// -----------------------------------------
void toJson(ruc::Json& json, const vec4& value)
{
json = ruc::Json {
{ value.r, value.g, value.b, value.a },
};
}
void fromJson(const ruc::Json& json, vec4& value)
{
VERIFY(json.type() == ruc::Json::Type::Array);
auto& values = json.asArray();
VERIFY(values.size() == 4, "glm::vec4 expected 4 values, got: {}", values.size());
value.r = values.at(0).get<float>();
value.g = values.at(1).get<float>();
value.b = values.at(2).get<float>();
value.a = values.at(3).get<float>();
}
} // namespace glm
// -----------------------------------------
void ruc::format::Formatter<glm::vec2>::format(Builder& builder, glm::vec2 value) const
{
return Formatter<std::vector<float>>::format(builder, { value.x, value.y });
}
void ruc::format::Formatter<glm::vec3>::format(Builder& builder, glm::vec3 value) const
{
return Formatter<std::vector<float>>::format(builder, { value.x, value.y, value.z });
}
void ruc::format::Formatter<glm::vec4>::format(Builder& builder, glm::vec4 value) const
{
return Formatter<std::vector<float>>::format(builder, { value.x, value.y, value.z, value.w });
}
void ruc::format::Formatter<glm::mat2>::format(Builder& builder, glm::mat2 value) const
{
builder.putString("mat2 ");
Formatter<glm::vec2>::format(builder, value[0]);
builder.putString("\n ");
return Formatter<glm::vec2>::format(builder, value[1]);
}
void ruc::format::Formatter<glm::mat3>::format(Builder& builder, glm::mat3 value) const
{
builder.putString("mat3 ");
Formatter<glm::vec3>::format(builder, value[0]);
builder.putString("\n ");
Formatter<glm::vec3>::format(builder, value[1]);
builder.putString("\n ");
return Formatter<glm::vec3>::format(builder, value[2]);
}
void ruc::format::Formatter<glm::mat4>::format(Builder& builder, glm::mat4 value) const
{
builder.putString("mat4 ");
Formatter<glm::vec4>::format(builder, value[0]);
builder.putString("\n ");
Formatter<glm::vec4>::format(builder, value[1]);
builder.putString("\n ");
Formatter<glm::vec4>::format(builder, value[2]);
builder.putString("\n ");
return Formatter<glm::vec4>::format(builder, value[3]);
}
+58
View File
@@ -0,0 +1,58 @@
/*
* Copyright (C) 2024 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "glm/ext/matrix_float2x2.hpp"
#include "glm/ext/matrix_float3x3.hpp"
#include "glm/ext/matrix_float4x4.hpp"
#include "glm/ext/vector_float2.hpp"
#include "glm/ext/vector_float3.hpp"
#include "glm/ext/vector_float4.hpp"
#include "ruc/json/json.h"
namespace glm {
void toJson(ruc::Json& json, const vec2& value);
void fromJson(const ruc::Json& json, vec2& value);
void toJson(ruc::Json& json, const vec3& value);
void fromJson(const ruc::Json& json, vec3& value);
void toJson(ruc::Json& json, const vec4& value);
void fromJson(const ruc::Json& json, vec4& value);
} // namespace glm
template<>
struct ruc::format::Formatter<glm::vec2> : Formatter<std::vector<float>> {
void format(Builder& builder, glm::vec2 value) const;
};
template<>
struct ruc::format::Formatter<glm::vec3> : Formatter<std::vector<float>> {
void format(Builder& builder, glm::vec3 value) const;
};
template<>
struct ruc::format::Formatter<glm::vec4> : Formatter<std::vector<float>> {
void format(Builder& builder, glm::vec4 value) const;
};
template<>
struct ruc::format::Formatter<glm::mat2> : Formatter<glm::vec2> {
void format(Builder& builder, glm::mat2 value) const;
};
template<>
struct ruc::format::Formatter<glm::mat3> : Formatter<glm::vec3> {
void format(Builder& builder, glm::mat3 value) const;
};
template<>
struct ruc::format::Formatter<glm::mat4> : Formatter<glm::vec4> {
void format(Builder& builder, glm::mat4 value) const;
};
+4 -25
View File
@@ -4,9 +4,12 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
#include "inferno/component/spritecomponent.h" #include "ruc/json/json.h"
#include "inferno/asset/asset-manager.h" #include "inferno/asset/asset-manager.h"
#include "inferno/asset/texture.h" #include "inferno/asset/texture.h"
#include "inferno/component/serialize.h" // not detected as used by clang-tidy
#include "inferno/component/spritecomponent.h"
namespace Inferno { namespace Inferno {
@@ -23,27 +26,3 @@ void fromJson(const ruc::Json& json, SpriteComponent& value)
} }
} // namespace Inferno } // namespace Inferno
namespace glm {
void toJson(ruc::Json& json, const vec4& value)
{
json = ruc::Json {
{ value.r, value.g, value.b, value.a },
};
}
void fromJson(const ruc::Json& json, vec4& value)
{
VERIFY(json.type() == ruc::Json::Type::Array);
auto& values = json.asArray();
VERIFY(values.size() == 4, "glm::vec4 expects 4 values, not {}", values.size());
value.r = values.at(0).get<float>();
value.g = values.at(1).get<float>();
value.b = values.at(2).get<float>();
value.a = values.at(3).get<float>();
}
} // namespace glm
-7
View File
@@ -23,10 +23,3 @@ struct SpriteComponent {
void fromJson(const ruc::Json& json, SpriteComponent& value); void fromJson(const ruc::Json& json, SpriteComponent& value);
} // namespace Inferno } // namespace Inferno
namespace glm {
void toJson(ruc::Json& json, const vec4& value);
void fromJson(const ruc::Json& json, vec4& value);
} // namespace glm
+1 -50
View File
@@ -7,6 +7,7 @@
#include "ruc/format/format.h" #include "ruc/format/format.h"
#include "ruc/json/json.h" #include "ruc/json/json.h"
#include "inferno/component/serialize.h"
#include "inferno/component/transformcomponent.h" #include "inferno/component/transformcomponent.h"
namespace Inferno { namespace Inferno {
@@ -28,56 +29,6 @@ void fromJson(const ruc::Json& json, TransformComponent& value)
} // namespace Inferno } // namespace Inferno
namespace glm {
void toJson(ruc::Json& json, const vec3& value)
{
json = ruc::Json {
{ value.x, value.y, value.z },
};
}
void fromJson(const ruc::Json& json, vec3& value)
{
VERIFY(json.type() == ruc::Json::Type::Array);
auto& values = json.asArray();
VERIFY(values.size() == 3, "glm::vec3 expects 3 values, not {}", values.size());
value.x = values.at(0).get<float>();
value.y = values.at(1).get<float>();
value.z = values.at(2).get<float>();
}
} // namespace glm
void ruc::format::Formatter<glm::vec2>::format(Builder& builder, glm::vec2 value) const
{
return Formatter<std::vector<float>>::format(builder, { value.x, value.y });
}
void ruc::format::Formatter<glm::vec3>::format(Builder& builder, glm::vec3 value) const
{
return Formatter<std::vector<float>>::format(builder, { value.x, value.y, value.z });
}
void ruc::format::Formatter<glm::vec4>::format(Builder& builder, glm::vec4 value) const
{
return Formatter<std::vector<float>>::format(builder, { value.x, value.y, value.z, value.w });
}
void ruc::format::Formatter<glm::mat4>::format(Builder& builder, glm::mat4 value) const
{
builder.putString("mat4 ");
Formatter<glm::vec4>::format(builder, value[0]);
builder.putString("\n ");
Formatter<glm::vec4>::format(builder, value[1]);
builder.putString("\n ");
Formatter<glm::vec4>::format(builder, value[2]);
builder.putString("\n ");
return Formatter<glm::vec4>::format(builder, value[3]);
}
void ruc::format::Formatter<Inferno::TransformComponent>::format(Builder& builder, Inferno::TransformComponent value) const void ruc::format::Formatter<Inferno::TransformComponent>::format(Builder& builder, Inferno::TransformComponent value) const
{ {
builder.putString("transform "); builder.putString("transform ");
@@ -6,9 +6,6 @@
#pragma once #pragma once
#include <cstdint> // uint32_t
#include <optional>
#include "entt/entity/entity.hpp" // entt::null #include "entt/entity/entity.hpp" // entt::null
#include "entt/entity/fwd.hpp" // entt::entity #include "entt/entity/fwd.hpp" // entt::entity
#include "glm/ext/matrix_float4x4.hpp" // glm::mat4 #include "glm/ext/matrix_float4x4.hpp" // glm::mat4
@@ -31,33 +28,6 @@ void fromJson(const ruc::Json& json, TransformComponent& value);
} // namespace Inferno } // namespace Inferno
namespace glm {
void toJson(ruc::Json& json, const vec3& value);
void fromJson(const ruc::Json& json, vec3& value);
} // namespace glm
template<>
struct ruc::format::Formatter<glm::vec2> : Formatter<std::vector<float>> {
void format(Builder& builder, glm::vec2 value) const;
};
template<>
struct ruc::format::Formatter<glm::vec3> : Formatter<std::vector<float>> {
void format(Builder& builder, glm::vec3 value) const;
};
template<>
struct ruc::format::Formatter<glm::vec4> : Formatter<std::vector<float>> {
void format(Builder& builder, glm::vec4 value) const;
};
template<>
struct ruc::format::Formatter<glm::mat4> : Formatter<glm::vec4> {
void format(Builder& builder, glm::mat4 value) const;
};
template<> template<>
struct ruc::format::Formatter<Inferno::TransformComponent> : Formatter<glm::vec3> { struct ruc::format::Formatter<Inferno::TransformComponent> : Formatter<glm::vec3> {
void format(Builder& builder, Inferno::TransformComponent value) const; void format(Builder& builder, Inferno::TransformComponent value) const;
+59 -6
View File
@@ -42,7 +42,7 @@ uint32_t BufferElement::getTypeGL() const
return BufferElement::getTypeGL(m_type); return BufferElement::getTypeGL(m_type);
} }
uint32_t BufferElement::getTypeSize(const BufferElementType type) uint32_t BufferElement::getTypeSize(BufferElementType type)
{ {
switch (type) { switch (type) {
case BufferElementType::None: case BufferElementType::None:
@@ -86,7 +86,7 @@ uint32_t BufferElement::getTypeSize(const BufferElementType type)
return 0; return 0;
} }
uint32_t BufferElement::getTypeCount(const BufferElementType type) uint32_t BufferElement::getTypeCount(BufferElementType type)
{ {
switch (type) { switch (type) {
case BufferElementType::None: case BufferElementType::None:
@@ -133,7 +133,7 @@ uint32_t BufferElement::getTypeCount(const BufferElementType type)
return 0; return 0;
} }
uint32_t BufferElement::getTypeGL(const BufferElementType type) uint32_t BufferElement::getTypeGL(BufferElementType type)
{ {
switch (type) { switch (type) {
case BufferElementType::None: case BufferElementType::None:
@@ -177,6 +177,58 @@ uint32_t BufferElement::getTypeGL(const BufferElementType type)
return 0; return 0;
} }
uint32_t BufferElement::getGLTypeSize(uint32_t type)
{
switch (type) {
case GL_BOOL:
case GL_INT:
case GL_UNSIGNED_INT:
case GL_FLOAT:
return 4;
case GL_BOOL_VEC2:
case GL_INT_VEC2:
case GL_UNSIGNED_INT_VEC2:
case GL_FLOAT_VEC2:
return 4 * 2;
case GL_BOOL_VEC3:
case GL_INT_VEC3:
case GL_UNSIGNED_INT_VEC3:
case GL_FLOAT_VEC3:
return 4 * 3;
case GL_BOOL_VEC4:
case GL_INT_VEC4:
case GL_UNSIGNED_INT_VEC4:
case GL_FLOAT_VEC4:
return 4 * 4;
case GL_FLOAT_MAT2:
return 4 * 2 * 2;
case GL_FLOAT_MAT3:
return 4 * 3 * 3;
case GL_FLOAT_MAT4:
return 4 * 4 * 4;
case GL_DOUBLE:
return 8;
case GL_DOUBLE_VEC2:
return 8 * 2;
case GL_DOUBLE_VEC3:
return 8 * 3;
case GL_DOUBLE_VEC4:
return 8 * 4;
case GL_DOUBLE_MAT2:
return 8 * 2 * 2;
case GL_DOUBLE_MAT3:
return 8 * 3 * 3;
case GL_DOUBLE_MAT4:
return 8 * 4 * 4;
default:
VERIFY_NOT_REACHED();
};
return 0;
}
// ----------------------------------------- // -----------------------------------------
BufferLayout::BufferLayout(const std::initializer_list<BufferElement>& elements) BufferLayout::BufferLayout(const std::initializer_list<BufferElement>& elements)
@@ -372,10 +424,11 @@ void VertexArray::addVertexBuffer(std::shared_ptr<VertexBuffer> vertexBuffer)
index++; index++;
} }
m_vertexBuffers.push_back(std::move(vertexBuffer));
unbind(); unbind();
vertexBuffer->unbind(); vertexBuffer->unbind();
m_vertexBuffers.push_back(std::move(vertexBuffer));
} }
void VertexArray::setIndexBuffer(std::shared_ptr<IndexBuffer> indexBuffer) void VertexArray::setIndexBuffer(std::shared_ptr<IndexBuffer> indexBuffer)
@@ -383,10 +436,10 @@ void VertexArray::setIndexBuffer(std::shared_ptr<IndexBuffer> indexBuffer)
bind(); bind();
indexBuffer->bind(); indexBuffer->bind();
m_indexBuffer = std::move(indexBuffer);
unbind(); unbind();
indexBuffer->unbind(); indexBuffer->unbind();
m_indexBuffer = std::move(indexBuffer);
} }
} // namespace Inferno } // namespace Inferno
+9 -8
View File
@@ -16,7 +16,7 @@ namespace Inferno {
// clang-format off // clang-format off
// https://www.khronos.org/opengl/wiki/Data_Type_(GLSL) // https://www.khronos.org/opengl/wiki/Data_Type_(GLSL)
enum class BufferElementType { enum class BufferElementType : uint8_t {
None = 0, None = 0,
Bool, Bool2, Bool3, Bool4, // bvec Bool, Bool2, Bool3, Bool4, // bvec
Int, Int2, Int3, Int4, // ivec Int, Int2, Int3, Int4, // ivec
@@ -39,9 +39,10 @@ public:
uint32_t getTypeSize() const; uint32_t getTypeSize() const;
uint32_t getTypeCount() const; uint32_t getTypeCount() const;
uint32_t getTypeGL() const; uint32_t getTypeGL() const;
static uint32_t getTypeSize(const BufferElementType type); static uint32_t getTypeSize(BufferElementType type);
static uint32_t getTypeCount(const BufferElementType type); static uint32_t getTypeCount(BufferElementType type);
static uint32_t getTypeGL(const BufferElementType type); static uint32_t getTypeGL(BufferElementType type);
static uint32_t getGLTypeSize(uint32_t type);
BufferElementType type() const { return m_type; } BufferElementType type() const { return m_type; }
std::string name() const { return m_name; } std::string name() const { return m_name; }
@@ -49,11 +50,11 @@ public:
uint32_t offset() const { return m_offset; } uint32_t offset() const { return m_offset; }
bool normalized() const { return m_normalized; } bool normalized() const { return m_normalized; }
void setType(const BufferElementType& type) { m_type = type; } void setType(BufferElementType type) { m_type = type; }
void setName(const std::string& name) { m_name = name; } void setName(const std::string& name) { m_name = name; }
void setSize(const uint32_t& size) { m_size = size; } void setSize(uint32_t size) { m_size = size; }
void setOffset(const uint32_t& offset) { m_offset = offset; } void setOffset(uint32_t offset) { m_offset = offset; }
void setNormalized(const bool& normalized) { m_normalized = normalized; } void setNormalized(bool normalized) { m_normalized = normalized; }
private: private:
BufferElementType m_type; BufferElementType m_type;
+58 -23
View File
@@ -34,9 +34,6 @@ void Renderer<T>::endScene()
// ----------------------------------------- // -----------------------------------------
template<typename T>
uint32_t Renderer<T>::m_maxSupportedTextureSlots = 0;
template<typename T> template<typename T>
void Renderer<T>::initialize() void Renderer<T>::initialize()
{ {
@@ -68,7 +65,6 @@ void Renderer<T>::initialize()
template<typename T> template<typename T>
void Renderer<T>::destroy() void Renderer<T>::destroy()
{ {
delete[] m_vertexBufferBase;
} }
template<typename T> template<typename T>
@@ -164,7 +160,7 @@ void Renderer<T>::flush()
uploadElementBuffer(); uploadElementBuffer();
// Upload vertex data to GPU // Upload vertex data to GPU
m_vertexArray->at(0)->uploadData(m_vertexBufferBase, m_vertexIndex * sizeof(T)); m_vertexArray->at(0)->uploadData(m_vertexBufferBase.get(), m_vertexIndex * sizeof(T));
bind(); bind();
@@ -183,7 +179,7 @@ void Renderer<T>::startBatch()
{ {
m_vertexIndex = 0; m_vertexIndex = 0;
m_elementIndex = 0; m_elementIndex = 0;
m_vertexBufferPtr = m_vertexBufferBase; m_vertexBufferPtr = m_vertexBufferBase.get();
m_textureSlotIndex = 1; m_textureSlotIndex = 1;
} }
@@ -202,6 +198,10 @@ Renderer2D::Renderer2D(s)
Renderer2D::initialize(); Renderer2D::initialize();
} }
Renderer2D::~Renderer2D()
{
}
void Renderer2D::initialize() void Renderer2D::initialize()
{ {
Renderer::initialize(); Renderer::initialize();
@@ -210,8 +210,8 @@ void Renderer2D::initialize()
// CPU // CPU
// Create array for storing quads vertices // Create array for storing quads vertices
m_vertexBufferBase = new QuadVertex[maxVertices]; m_vertexBufferBase = std::make_unique<QuadVertex[]>(maxVertices);
m_vertexBufferPtr = m_vertexBufferBase; m_vertexBufferPtr = m_vertexBufferBase.get();
// Set default quad vertex positions // Set default quad vertex positions
m_vertexPositions[0] = { -1.0f, -1.0f, 0.0f, 1.0f }; m_vertexPositions[0] = { -1.0f, -1.0f, 0.0f, 1.0f };
@@ -283,7 +283,7 @@ void Renderer2D::drawQuad(const TransformComponent& transform, glm::mat4 color,
void Renderer2D::loadShader() void Renderer2D::loadShader()
{ {
m_shader = AssetManager::the().load<Shader>("assets/glsl/post-process"); m_shader = AssetManager::the().load<Shader>("assets/glsl/batch-2d");
} }
// ----------------------------------------- // -----------------------------------------
@@ -293,6 +293,10 @@ RendererCubemap::RendererCubemap(s)
RendererCubemap::initialize(); RendererCubemap::initialize();
} }
RendererCubemap::~RendererCubemap()
{
}
void RendererCubemap::initialize() void RendererCubemap::initialize()
{ {
Renderer::initialize(); Renderer::initialize();
@@ -301,8 +305,8 @@ void RendererCubemap::initialize()
// CPU // CPU
// Create array for storing quads vertices // Create array for storing quads vertices
m_vertexBufferBase = new CubemapVertex[maxVertices]; m_vertexBufferBase = std::make_unique<CubemapVertex[]>(maxVertices);
m_vertexBufferPtr = m_vertexBufferBase; m_vertexBufferPtr = m_vertexBufferBase.get();
// Set default cubemap vertex positions // Set default cubemap vertex positions
@@ -367,10 +371,10 @@ void RendererCubemap::beginScene(glm::mat4 cameraProjection, glm::mat4 cameraVie
// x x x 0 // x x x 0
// x x x 0 // x x x 0
// 0 0 0 1 // 0 0 0 1
// cameraView = glm::mat4(glm::mat3(cameraView)); cameraView = glm::mat4(glm::mat3(cameraView));
m_shader->bind(); m_shader->bind();
m_shader->setFloat("u_projectionView2", cameraProjection * cameraView); m_shader->setFloat("u_projectionView", cameraProjection * cameraView);
m_shader->unbind(); m_shader->unbind();
} }
@@ -416,8 +420,8 @@ RendererFont::RendererFont(s)
// CPU // CPU
// Create array for storing quads vertices // Create array for storing quads vertices
m_vertexBufferBase = new SymbolVertex[maxVertices]; m_vertexBufferBase = std::make_unique<SymbolVertex[]>(maxVertices);
m_vertexBufferPtr = m_vertexBufferBase; m_vertexBufferPtr = m_vertexBufferBase.get();
// --------------------------------- // ---------------------------------
// GPU // GPU
@@ -443,6 +447,10 @@ RendererFont::RendererFont(s)
ruc::info("RendererFont initialized"); ruc::info("RendererFont initialized");
} }
RendererFont::~RendererFont()
{
}
void RendererFont::drawSymbol(std::array<SymbolVertex, vertexPerQuad>& symbolQuad, std::shared_ptr<Texture> texture) void RendererFont::drawSymbol(std::array<SymbolVertex, vertexPerQuad>& symbolQuad, std::shared_ptr<Texture> texture)
{ {
// Create a new batch if the quad limit has been reached // Create a new batch if the quad limit has been reached
@@ -488,8 +496,8 @@ Renderer3D::Renderer3D(s)
// CPU // CPU
// Create array for storing quads vertices // Create array for storing quads vertices
m_vertexBufferBase = new Vertex[maxVertices]; m_vertexBufferBase = std::make_unique<Vertex[]>(maxVertices);
m_vertexBufferPtr = m_vertexBufferBase; m_vertexBufferPtr = m_vertexBufferBase.get();
// --------------------------------- // ---------------------------------
// GPU // GPU
@@ -511,6 +519,10 @@ Renderer3D::Renderer3D(s)
ruc::info("Renderer3D initialized"); ruc::info("Renderer3D initialized");
} }
Renderer3D::~Renderer3D()
{
}
void Renderer3D::drawModel(std::span<const Vertex> vertices, std::span<const uint32_t> elements, const TransformComponent& transform, glm::vec4 color, std::shared_ptr<Texture> texture) void Renderer3D::drawModel(std::span<const Vertex> vertices, std::span<const uint32_t> elements, const TransformComponent& transform, glm::vec4 color, std::shared_ptr<Texture> texture)
{ {
// ruc::error("drawModel"); // ruc::error("drawModel");
@@ -553,20 +565,20 @@ void Renderer3D::createElementBuffer()
// CPU // CPU
// Create array for storing quads vertices // Create array for storing quads vertices
m_elementBufferBase = new uint32_t[maxElements]; m_elementBufferBase = std::make_unique<uint32_t[]>(maxElements);
m_elementBufferPtr = m_elementBufferBase; m_elementBufferPtr = m_elementBufferBase.get();
// --------------------------------- // ---------------------------------
// GPU // GPU
// Create index buffer // Create index buffer
auto indexBuffer = std::make_shared<IndexBuffer>(m_elementBufferBase, sizeof(uint32_t) * maxElements); auto indexBuffer = std::make_shared<IndexBuffer>(m_elementBufferBase.get(), sizeof(uint32_t) * maxElements);
m_vertexArray->setIndexBuffer(indexBuffer); m_vertexArray->setIndexBuffer(indexBuffer);
} }
void Renderer3D::uploadElementBuffer() void Renderer3D::uploadElementBuffer()
{ {
m_vertexArray->indexBuffer()->uploadData(m_elementBufferBase, m_elementIndex * sizeof(uint32_t)); m_vertexArray->indexBuffer()->uploadData(m_elementBufferBase.get(), m_elementIndex * sizeof(uint32_t));
} }
void Renderer3D::loadShader() void Renderer3D::loadShader()
@@ -577,11 +589,22 @@ void Renderer3D::loadShader()
void Renderer3D::startBatch() void Renderer3D::startBatch()
{ {
Renderer<Vertex>::startBatch(); Renderer<Vertex>::startBatch();
m_elementBufferPtr = m_elementBufferBase; m_elementBufferPtr = m_elementBufferBase.get();
} }
// ----------------------------------------- // -----------------------------------------
RendererPostProcess::RendererPostProcess(s)
{
Renderer2D::initialize();
ruc::info("RendererPostProcess initialized");
}
RendererPostProcess::~RendererPostProcess()
{
}
void RendererPostProcess::drawQuad(const TransformComponent& transform, std::shared_ptr<Texture> albedo, std::shared_ptr<Texture> position, std::shared_ptr<Texture> normal) void RendererPostProcess::drawQuad(const TransformComponent& transform, std::shared_ptr<Texture> albedo, std::shared_ptr<Texture> position, std::shared_ptr<Texture> normal)
{ {
nextBatch(); nextBatch();
@@ -611,12 +634,24 @@ void RendererPostProcess::drawQuad(const TransformComponent& transform, std::sha
void RendererPostProcess::loadShader() void RendererPostProcess::loadShader()
{ {
ruc::error("POSTPROCESSING!");
m_shader = AssetManager::the().load<Shader>("assets/glsl/post-process"); m_shader = AssetManager::the().load<Shader>("assets/glsl/post-process");
} }
// ----------------------------------------- // -----------------------------------------
RendererLightCube::RendererLightCube(s)
{
RendererCubemap::initialize();
m_enableDepthBuffer = true;
ruc::info("RendererLightCube initialized");
}
RendererLightCube::~RendererLightCube()
{
}
void RendererLightCube::loadShader() void RendererLightCube::loadShader()
{ {
m_shader = AssetManager::the().load<Shader>("assets/glsl/lightsource"); m_shader = AssetManager::the().load<Shader>("assets/glsl/lightsource");
+21 -23
View File
@@ -16,9 +16,10 @@
#include "glm/ext/vector_float4.hpp" // glm::vec4 #include "glm/ext/vector_float4.hpp" // glm::vec4
#include "ruc/singleton.h" #include "ruc/singleton.h"
#include "inferno/asset/shader.h"
namespace Inferno { namespace Inferno {
class Shader;
class Texture; class Texture;
class TransformComponent; class TransformComponent;
class VertexArray; class VertexArray;
@@ -79,6 +80,8 @@ public:
void setEnableDepthBuffer(bool state) { m_enableDepthBuffer = state; } void setEnableDepthBuffer(bool state) { m_enableDepthBuffer = state; }
uint32_t shaderID() const { return m_shader->id(); }
protected: protected:
Renderer() {} Renderer() {}
virtual ~Renderer() { destroy(); }; virtual ~Renderer() { destroy(); };
@@ -102,11 +105,11 @@ protected:
// CPU quad vertices // CPU quad vertices
uint32_t m_vertexIndex { 0 }; uint32_t m_vertexIndex { 0 };
uint32_t m_elementIndex { 0 }; uint32_t m_elementIndex { 0 };
T* m_vertexBufferBase { nullptr }; std::unique_ptr<T[]> m_vertexBufferBase { nullptr };
T* m_vertexBufferPtr { nullptr }; T* m_vertexBufferPtr { nullptr };
// Texture units // Texture units
static uint32_t m_maxSupportedTextureSlots; static inline uint32_t m_maxSupportedTextureSlots { 0 };
uint32_t m_textureSlotIndex { 1 }; uint32_t m_textureSlotIndex { 1 };
std::array<std::shared_ptr<Texture>, maxTextureSlots> m_textureSlots; std::array<std::shared_ptr<Texture>, maxTextureSlots> m_textureSlots;
@@ -130,7 +133,7 @@ class Renderer2D
, public ruc::Singleton<Renderer2D> { , public ruc::Singleton<Renderer2D> {
public: public:
Renderer2D(s); Renderer2D(s);
virtual ~Renderer2D() = default; virtual ~Renderer2D();
using Singleton<Renderer2D>::destroy; using Singleton<Renderer2D>::destroy;
@@ -140,7 +143,7 @@ public:
void drawQuad(const TransformComponent& transform, glm::mat4 color, std::shared_ptr<Texture> texture); void drawQuad(const TransformComponent& transform, glm::mat4 color, std::shared_ptr<Texture> texture);
protected: protected:
Renderer2D() { Renderer2D::initialize(); } // Needed for derived classes Renderer2D() {} // Needed for derived classes
void initialize(); void initialize();
@@ -160,7 +163,7 @@ public:
public: public:
RendererCubemap(s); RendererCubemap(s);
virtual ~RendererCubemap() = default; virtual ~RendererCubemap();
using Singleton<RendererCubemap>::destroy; using Singleton<RendererCubemap>::destroy;
@@ -170,7 +173,7 @@ public:
void drawCubemap(const TransformComponent& transform, glm::mat4 color, std::shared_ptr<Texture> texture); void drawCubemap(const TransformComponent& transform, glm::mat4 color, std::shared_ptr<Texture> texture);
protected: protected:
RendererCubemap() { RendererCubemap::initialize(); } // Needed for derived classes RendererCubemap() {} // Needed for derived classes
void initialize(); void initialize();
@@ -188,7 +191,7 @@ class RendererFont final
, public ruc::Singleton<RendererFont> { , public ruc::Singleton<RendererFont> {
public: public:
RendererFont(s); RendererFont(s);
virtual ~RendererFont() = default; virtual ~RendererFont();
using Singleton<RendererFont>::destroy; using Singleton<RendererFont>::destroy;
@@ -205,7 +208,7 @@ class Renderer3D final
, public ruc::Singleton<Renderer3D> { , public ruc::Singleton<Renderer3D> {
public: public:
Renderer3D(s); Renderer3D(s);
virtual ~Renderer3D() = default; virtual ~Renderer3D();
using Singleton<Renderer3D>::destroy; using Singleton<Renderer3D>::destroy;
@@ -219,7 +222,7 @@ private:
private: private:
// CPU element vertices // CPU element vertices
uint32_t* m_elementBufferBase { nullptr }; std::unique_ptr<uint32_t[]> m_elementBufferBase { nullptr };
uint32_t* m_elementBufferPtr { nullptr }; uint32_t* m_elementBufferPtr { nullptr };
}; };
@@ -229,15 +232,13 @@ class RendererPostProcess final
: public Renderer2D : public Renderer2D
, public ruc::Singleton<RendererPostProcess> { , public ruc::Singleton<RendererPostProcess> {
public: public:
RendererPostProcess(ruc::Singleton<RendererPostProcess>::s) using Singleton<RendererPostProcess>::s;
: Renderer2D()
{
}
virtual ~RendererPostProcess() = default;
using Singleton<RendererPostProcess>::the; using Singleton<RendererPostProcess>::the;
using Singleton<RendererPostProcess>::destroy; using Singleton<RendererPostProcess>::destroy;
RendererPostProcess(s);
virtual ~RendererPostProcess();
void drawQuad(const TransformComponent& transform, std::shared_ptr<Texture> albedo, std::shared_ptr<Texture> position, std::shared_ptr<Texture> normal); void drawQuad(const TransformComponent& transform, std::shared_ptr<Texture> albedo, std::shared_ptr<Texture> position, std::shared_ptr<Texture> normal);
private: private:
@@ -250,16 +251,13 @@ class RendererLightCube final
: public RendererCubemap : public RendererCubemap
, public ruc::Singleton<RendererLightCube> { , public ruc::Singleton<RendererLightCube> {
public: public:
RendererLightCube(ruc::Singleton<RendererLightCube>::s) using Singleton<RendererLightCube>::s;
: RendererCubemap()
{
m_enableDepthBuffer = true;
}
virtual ~RendererLightCube() = default;
using Singleton<RendererLightCube>::the; using Singleton<RendererLightCube>::the;
using Singleton<RendererLightCube>::destroy; using Singleton<RendererLightCube>::destroy;
RendererLightCube(s);
virtual ~RendererLightCube();
void beginScene(glm::mat4, glm::mat4) override {} void beginScene(glm::mat4, glm::mat4) override {}
private: private:
@@ -0,0 +1,195 @@
/*
* Copyright (C) 2024 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#include <cstdint> // int32_t, uint8_t, uintt32_t
#include "glad/glad.h"
#include "glm/ext/matrix_float2x2.hpp" // glm::mat2
#include "glm/ext/matrix_float3x3.hpp" // glm::mat3
#include "glm/ext/vector_float4.hpp" // glm::vec4
#include "inferno/render/buffer.h"
#include "inferno/render/shader-storage-buffer.h"
namespace Inferno {
ShaderStorageBuffer::ShaderStorageBuffer(s)
{
// Get maximum uniformbuffer bindings the GPU supports
int32_t maxBindingPoints = 0;
glGetIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, &maxBindingPoints);
m_maxBindingPoints = static_cast<uint8_t>(maxBindingPoints);
}
ShaderStorageBuffer::~ShaderStorageBuffer()
{
}
// -----------------------------------------
// https://stackoverflow.com/questions/56512216#answer-56513136
void ShaderStorageBuffer::setLayout(std::string_view blockName, uint8_t bindingPoint, uint32_t shaderID)
{
VERIFY(bindingPoint < m_maxBindingPoints,
"shader storage buffer exceeded binding points: {}/{}", bindingPoint, m_maxBindingPoints);
if (!exists(blockName)) {
m_blocks[blockName.data()] = {};
}
BufferBlock& block = m_blocks[blockName.data()];
block.bindingPoint = bindingPoint;
block.memberOffsets.clear();
glBindBuffer(GL_SHADER_STORAGE_BUFFER, block.id);
// Get the shader block index
uint32_t resourceIndex = glGetProgramResourceIndex(shaderID, GL_SHADER_STORAGE_BLOCK, blockName.data());
VERIFY(resourceIndex != GL_INVALID_INDEX, "block doesnt exist in shader: {}::{}", blockName, shaderID);
// Get the amount of member variables
uint32_t prop = GL_NUM_ACTIVE_VARIABLES;
int32_t memberCount;
glGetProgramResourceiv(shaderID, GL_SHADER_STORAGE_BLOCK, resourceIndex, 1, &prop, 1, nullptr, &memberCount);
// Get the indices of the members
prop = GL_ACTIVE_VARIABLES;
std::vector<int32_t> members(memberCount);
glGetProgramResourceiv(shaderID, GL_SHADER_STORAGE_BLOCK, resourceIndex, 1, &prop, (int32_t)members.size(), nullptr, members.data());
// Reserve memory for the names of the members
int32_t memberNameSize;
glGetProgramInterfaceiv(shaderID, GL_BUFFER_VARIABLE, GL_MAX_NAME_LENGTH, &memberNameSize);
std::vector<char> memberNameBuffer(memberNameSize);
int32_t lastOffset = 0;
int32_t lastType = 0;
for (int32_t i = 0; i < memberCount; i++) {
// Get name of buffer variable
int32_t stringLength;
glGetProgramResourceName(shaderID, GL_BUFFER_VARIABLE, members[i], memberNameSize, &stringLength, memberNameBuffer.data());
std::string memberName = std::string(memberNameBuffer.begin(), memberNameBuffer.begin() + stringLength);
// Get the other data needed for computing
uint32_t props[7] = {
GL_OFFSET, // 0
GL_TYPE, // 1
GL_ARRAY_SIZE, // 2
GL_ARRAY_STRIDE, // 3
GL_MATRIX_STRIDE, // 4
GL_TOP_LEVEL_ARRAY_SIZE, // 5
GL_TOP_LEVEL_ARRAY_STRIDE, // 6
};
int32_t params[7];
glGetProgramResourceiv(shaderID, GL_BUFFER_VARIABLE, members[i], 7, props, 7, nullptr, params);
// ruc::error("{}", memberName);
// ruc::error("\n Offset: {}, type: {:#x}, arraySize: {}, arrayStride: {},\n matrixStride: {}, top level size: {}, top level stride: {}\n",
// params[0], params[1], params[2], params[3], params[4], params[5], params[6]);
// Array of structs
if (params[5] != 1 && params[6 != 0]) {
size_t bracketOpen = memberName.find_first_of('[');
size_t bracketClose = memberName.find_first_of(']');
std::string memberNameBegin = memberName.substr(0, bracketOpen); // name: myArray[0].member -> myArray
std::string memberNameMember = memberName.substr(bracketClose + 1); // name: myArray[0].member -> .member
for (int32_t j = 0; j < params[5]; ++j) {
lastOffset = params[0] + (j * params[6]); // calc offset
lastType = params[1];
// Only add the member variant the first time its encountered
if (j == 0 && block.memberOffsets.find(memberNameBegin) == block.memberOffsets.end()) {
block.memberOffsets.emplace(memberNameBegin, lastOffset); // name: myArray
}
// Only add the index variant the first time its encountered
std::string memberNameIndex = memberNameBegin + "[" + std::to_string(j) + "]"; // name: myArray -> myArray[i]
if (block.memberOffsets.find(memberNameIndex) == block.memberOffsets.end()) {
block.memberOffsets.emplace(memberNameIndex, lastOffset);
}
block.memberOffsets.emplace(memberNameIndex + memberNameMember, // name: myArray -> myArray[i].member
lastOffset);
}
}
// Array of primitives
else if (params[2] != 1 && params[3] != 0) {
std::string memberNameBegin = memberName.substr(0, memberName.find_first_of('[')); // name: myArray[0] -> myArray
for (int32_t j = 0; j < params[2]; ++j) {
lastOffset = params[0] + (j * params[3]); // calc offset
lastType = params[1];
// Only add the member variant the first time its encountered
if (j == 0) {
block.memberOffsets.emplace(memberNameBegin, lastOffset); // name: myArray
}
block.memberOffsets.emplace(memberNameBegin + "[" + std::to_string(j) + "]", // name: myArray -> myArray[i]
lastOffset);
}
}
// Matrix case
else if (params[4] != 0) {
lastType = params[1];
lastOffset = params[0];
block.memberOffsets.emplace(memberName, params[0]);
}
else {
lastType = params[1];
lastOffset = params[0];
block.memberOffsets.emplace(memberName, params[0]);
}
}
block.size = lastOffset + BufferElement::getGLTypeSize(lastType);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
// Results
// for (auto [k, v] : block.memberOffsets) {
// ruc::error("{}:{}", k, v);
// }
}
void ShaderStorageBuffer::create(std::string_view blockName)
{
VERIFY(exists(blockName), "shader storage buffer block doesnt exist");
BufferBlock& block = m_blocks[blockName.data()];
if (block.id != 0) {
glDeleteBuffers(1, &block.id);
}
// Allocate buffer
block.id = UINT_MAX;
glGenBuffers(1, &block.id);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, block.id);
glBufferData(GL_SHADER_STORAGE_BUFFER, block.size, NULL, GL_DYNAMIC_DRAW);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
// Bind buffer to binding point
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, block.bindingPoint, block.id);
}
void ShaderStorageBuffer::setValue(std::string_view blockName, std::string_view member, bool value)
{
setValue(blockName, member, static_cast<uint32_t>(value), sizeof(uint32_t));
}
void ShaderStorageBuffer::setValue(std::string_view blockName, std::string_view member, glm::mat2 value)
{
setValue(blockName, member, static_cast<glm::mat4>(value), sizeof(glm::vec4) * 2);
}
void ShaderStorageBuffer::setValue(std::string_view blockName, std::string_view member, glm::mat3 value)
{
setValue(blockName, member, static_cast<glm::mat4>(value), sizeof(glm::vec4) * 3);
}
} // namespace Inferno
@@ -0,0 +1,63 @@
/*
* Copyright (C) 2024 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <cstddef> // size_t
#include <cstdint> // uint8_t, uint32_t
#include <string_view>
#include <unordered_map>
#include "glad/glad.h"
#include "glm/ext/matrix_float2x2.hpp" // glm::mat2
#include "glm/ext/matrix_float3x3.hpp" // glm::mat3
#include "ruc/singleton.h"
#define CHECK_SET_CALL(blockName, member) \
VERIFY(exists(blockName), "shader storage buffer block doesnt exist: {}", blockName); \
const BufferBlock& block = m_blocks[blockName.data()]; \
VERIFY(block.memberOffsets.find(member.data()) != block.memberOffsets.end(), \
"shader storage buffer member doesnt exist: {}", member);
namespace Inferno {
struct BufferBlock {
uint32_t id { 0 };
uint32_t size { 0 };
uint8_t bindingPoint { 0 };
std::unordered_map<std::string, uint32_t> memberOffsets {};
};
class ShaderStorageBuffer final : public ruc::Singleton<ShaderStorageBuffer> { // Shader Storage Buffer Object, SSBO
public:
ShaderStorageBuffer(s);
virtual ~ShaderStorageBuffer();
void setLayout(std::string_view blockName, uint8_t bindingPoint, uint32_t shaderID);
void create(std::string_view blockName);
bool exists(std::string_view blockName) const { return m_blocks.find(blockName.data()) != m_blocks.end(); }
template<typename T> // Capture value by reference, instead of decaying to pointer
void setValue(std::string_view blockName, std::string_view member, T&& value, size_t size = 0)
{
CHECK_SET_CALL(blockName, member);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, block.id);
glBufferSubData(GL_SHADER_STORAGE_BUFFER, block.memberOffsets.at(member.data()), (size) ? size : sizeof(T), &value);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
}
// Exceptions:
void setValue(std::string_view blockName, std::string_view member, bool value);
void setValue(std::string_view blockName, std::string_view member, glm::mat2 value);
void setValue(std::string_view blockName, std::string_view member, glm::mat3 value);
private:
uint8_t m_maxBindingPoints { 0 };
std::unordered_map<std::string, BufferBlock> m_blocks;
};
} // namespace Inferno
+24
View File
@@ -0,0 +1,24 @@
/*
* Copyright (C) 2024 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "glm/ext/vector_float3.hpp" // glm::vec3
namespace Inferno {
// Shader storage block layouts, using std430 memory layout rules
#define MAX_DIRECTIONAL_LIGHTS 4
struct alignas(16) DirectionalLightBlock {
alignas(16) glm::vec3 direction { 0 };
alignas(16) glm::vec3 ambient { 0 };
alignas(16) glm::vec3 diffuse { 0 };
alignas(16) glm::vec3 specular { 0 };
};
} // namespace Inferno
+1
View File
@@ -59,6 +59,7 @@ void Uniformbuffer::setLayout(std::string_view blockName, uint8_t bindingPoint,
UniformbufferBlock& block = m_blocks[blockName]; UniformbufferBlock& block = m_blocks[blockName];
block.bindingPoint = bindingPoint; block.bindingPoint = bindingPoint;
block.uniformLocations.clear();
// Example block layout: // Example block layout:
// - mat3 // - mat3
+6 -22
View File
@@ -4,6 +4,8 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
#pragma once
#include <cstddef> // size_t #include <cstddef> // size_t
#include <cstdint> // uint8_t, uint32_t #include <cstdint> // uint8_t, uint32_t
#include <string> #include <string>
@@ -13,36 +15,18 @@
#include "glad/glad.h" #include "glad/glad.h"
#include "glm/ext/matrix_float2x2.hpp" // glm::mat2 #include "glm/ext/matrix_float2x2.hpp" // glm::mat2
#include "glm/ext/matrix_float3x3.hpp" // glm::mat3 #include "glm/ext/matrix_float3x3.hpp" // glm::mat3
#include "glm/ext/vector_float3.hpp" // glm::vec3
#include "ruc/singleton.h" #include "ruc/singleton.h"
#include "inferno/render/buffer.h" #include "inferno/render/buffer.h"
#define CHECK_SET_CALL(blockName, member) \ #define CHECK_UNIFORM_SET_CALL(blockName, member) \
VERIFY(exists(blockName), "uniformbuffer block doesnt exist"); \ VERIFY(exists(blockName), "uniformbuffer block doesnt exist: {}", blockName); \
const UniformbufferBlock& block = m_blocks[blockName]; \ const UniformbufferBlock& block = m_blocks[blockName]; \
VERIFY(block.uniformLocations.find(member.data()) != block.uniformLocations.end(), \ VERIFY(block.uniformLocations.find(member.data()) != block.uniformLocations.end(), \
"uniformbuffer block member doesnt exist"); "uniformbuffer member doesnt exist: {}", member);
namespace Inferno { namespace Inferno {
// Uniform block layouts, using std140 memory layout rules
#define MAX_DIRECTIONAL_LIGHTS 32
struct UniformDirectionalLight {
glm::vec3 direction { 0 };
float __padding0 { 0 };
glm::vec3 ambient { 0 };
float __padding1 { 0 };
glm::vec3 diffuse { 0 };
float __padding2 { 0 };
glm::vec3 specular { 0 };
float __padding3 { 0 };
};
// -----------------------------------------
struct UniformbufferBlock { struct UniformbufferBlock {
uint32_t id { 0 }; uint32_t id { 0 };
uint32_t size { 0 }; uint32_t size { 0 };
@@ -62,7 +46,7 @@ public:
template<typename T> // Capture value by reference, instead of decaying to pointer template<typename T> // Capture value by reference, instead of decaying to pointer
void setValue(std::string_view blockName, std::string_view member, T&& value, size_t size = 0) void setValue(std::string_view blockName, std::string_view member, T&& value, size_t size = 0)
{ {
CHECK_SET_CALL(blockName, member); CHECK_UNIFORM_SET_CALL(blockName, member);
glBindBuffer(GL_UNIFORM_BUFFER, block.id); glBindBuffer(GL_UNIFORM_BUFFER, block.id);
glBufferSubData(GL_UNIFORM_BUFFER, block.uniformLocations.at(member.data()), (size) ? size : sizeof(T), &value); glBufferSubData(GL_UNIFORM_BUFFER, block.uniformLocations.at(member.data()), (size) ? size : sizeof(T), &value);
+12 -12
View File
@@ -16,6 +16,8 @@
#include "inferno/render/framebuffer.h" #include "inferno/render/framebuffer.h"
#include "inferno/render/render-command.h" #include "inferno/render/render-command.h"
#include "inferno/render/renderer.h" #include "inferno/render/renderer.h"
#include "inferno/render/shader-storage-buffer.h"
#include "inferno/render/shader-structs.h"
#include "inferno/render/uniformbuffer.h" #include "inferno/render/uniformbuffer.h"
#include "inferno/system/camerasystem.h" #include "inferno/system/camerasystem.h"
#include "inferno/system/rendersystem.h" #include "inferno/system/rendersystem.h"
@@ -57,16 +59,8 @@ void RenderSystem::initialize(uint32_t width, uint32_t height)
}); });
Uniformbuffer::the().create("Camera"); Uniformbuffer::the().create("Camera");
Uniformbuffer::the().setLayout( ShaderStorageBuffer::the().setLayout("DirectionalLights", 0, RendererPostProcess::the().shaderID());
"DirectionalLights", ShaderStorageBuffer::the().create("DirectionalLights");
{
.size = sizeof(UniformDirectionalLight) * MAX_DIRECTIONAL_LIGHTS,
.bindingPoint = 1,
.uniformLocations = {
{ "u_directionalLight", 0 },
},
});
Uniformbuffer::the().create("DirectionalLights");
ruc::info("RenderSystem initialized"); ruc::info("RenderSystem initialized");
} }
@@ -137,15 +131,21 @@ void RenderSystem::renderGeometry()
Uniformbuffer::the().setValue("Camera", "u_projectionView", projection * view); Uniformbuffer::the().setValue("Camera", "u_projectionView", projection * view);
Uniformbuffer::the().setValue("Camera", "u_position", translate); Uniformbuffer::the().setValue("Camera", "u_position", translate);
static UniformDirectionalLight directionalLights[1] = { static DirectionalLightBlock directionalLights[2] = {
{ {
.direction = { -8.0f, -8.0f, -8.0f }, .direction = { -8.0f, -8.0f, -8.0f },
.ambient = { 0.1f, 0.1f, 0.1f }, .ambient = { 0.1f, 0.1f, 0.1f },
.diffuse = { 1.0f, 1.0f, 1.0f }, .diffuse = { 1.0f, 1.0f, 1.0f },
.specular = { 1.0f, 1.0f, 1.0f }, .specular = { 1.0f, 1.0f, 1.0f },
}, },
{
.direction = { 8.0f, 8.0f, 8.0f },
.ambient = { 0.1f, 0.1f, 0.1f },
.diffuse = { 1.0f, 1.0f, 1.0f },
.specular = { 1.0f, 0.0f, 0.0f },
},
}; };
Uniformbuffer::the().setValue("DirectionalLights", "u_directionalLight", directionalLights); ShaderStorageBuffer::the().setValue("DirectionalLights", "u_directionalLight", directionalLights);
auto modelView = m_registry->view<TransformComponent, ModelComponent>(); auto modelView = m_registry->view<TransformComponent, ModelComponent>();
+1 -1
View File
@@ -18,7 +18,7 @@
namespace Inferno { namespace Inferno {
using Symbols = std::vector<std::shared_ptr<Symbol>>; using Symbols = std::vector<std::shared_ptr<Symbol>>;
using SymbolQuad = std::array<SymbolVertex, Renderer<void>::vertexPerQuad>; using SymbolQuad = std::array<SymbolVertex, RendererFont::vertexPerQuad>;
class Scene; class Scene;
class TextAreaComponent; class TextAreaComponent;
+1
View File
@@ -33,3 +33,4 @@ target_include_directories(${ENGINE}-dependencies PUBLIC
"glad/include" "glad/include"
"lua") "lua")
target_link_libraries(${ENGINE}-dependencies glfw ruc ruc-test assimp) target_link_libraries(${ENGINE}-dependencies glfw ruc ruc-test assimp)
target_compile_options(${ENGINE}-dependencies PRIVATE ${COMPILE_FLAGS_DEPS})
Vendored
+1 -1
Submodule vendor/ruc updated: 8520952235...d5bf50715e