Compare commits
19
Commits
4dbac7ee38
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc33b5d481 | ||
|
|
67bb6a5671 | ||
|
|
3ff8838e01 | ||
|
|
3ae6ecae8a | ||
|
|
6b6c588378 | ||
|
|
9145f90c1d | ||
|
|
b9043dbb4b | ||
|
|
b6e68eccec | ||
|
|
d16fade497 | ||
|
|
b8e4d9ef3f | ||
|
|
03e8210165 | ||
|
|
dcf2a85208 | ||
|
|
b2ed951b1e | ||
|
|
d63dfe2f9f | ||
|
|
faacdca424 | ||
|
|
b5f3cae5ba | ||
|
|
1d5f5a1ad8 | ||
|
|
3cd2fab637 | ||
|
|
c5ed219ad2 |
+22
-10
@@ -11,6 +11,7 @@ endif()
|
||||
# Options
|
||||
option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
|
||||
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)
|
||||
|
||||
# Compiler flags used for all build types
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic")
|
||||
# -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
|
||||
set(COMPILE_FLAGS_DEPS -w)
|
||||
if(INFERNO_BUILD_WARNINGS)
|
||||
set(COMPILE_FLAGS_PROJECT -Wall -Wextra -Wpedantic)
|
||||
# -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 Release)
|
||||
@@ -42,14 +48,20 @@ endif()
|
||||
# Set build type specific compiler flags
|
||||
message("--- ${CMAKE_BUILD_TYPE} ---")
|
||||
if(${CMAKE_BUILD_TYPE} STREQUAL Debug)
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Og -g -pg")
|
||||
# -Og = Optimizations that do not interfere with debugging
|
||||
# -g = Produce debugging information in OS's native format
|
||||
# -pg = Generate profile information for analysis with gprof
|
||||
# Optimizations that do not interfere with debugging
|
||||
string(APPEND CMAKE_CXX_FLAGS_DEBUG " -Og")
|
||||
# Produce debugging information in OS's native format
|
||||
string(APPEND CMAKE_CXX_FLAGS_DEBUG " -g")
|
||||
# Generate profile information for analysis with gprof
|
||||
# $ 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)
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
|
||||
# -O3 = Optimizations that increase compilation time and performance
|
||||
# Optimizations that increase compilation time and performance
|
||||
string(APPEND CMAKE_CXX_FLAGS_RELEASE " -O3")
|
||||
endif()
|
||||
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
@@ -4,14 +4,14 @@ layout(location = 0) out vec4 color;
|
||||
|
||||
in vec4 v_color;
|
||||
in vec2 v_textureCoordinates;
|
||||
in flat float v_textureIndex;
|
||||
in flat uint v_textureIndex;
|
||||
|
||||
uniform sampler2D u_textures[32];
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 textureColor = v_color;
|
||||
switch(int(v_textureIndex)) {
|
||||
switch(v_textureIndex) {
|
||||
case 0: break; // Texture unit 0 is reserved for no texture
|
||||
case 1: textureColor *= texture(u_textures[1], v_textureCoordinates); break;
|
||||
case 2: textureColor *= texture(u_textures[2], v_textureCoordinates); break;
|
||||
@@ -0,0 +1,19 @@
|
||||
#version 450 core
|
||||
|
||||
layout(location = 0) in vec3 a_position;
|
||||
layout(location = 1) in vec4 a_color;
|
||||
layout(location = 2) in vec2 a_textureCoordinates;
|
||||
layout(location = 3) in uint a_textureIndex;
|
||||
|
||||
out vec4 v_color;
|
||||
out vec2 v_textureCoordinates;
|
||||
out flat uint v_textureIndex;
|
||||
|
||||
void main()
|
||||
{
|
||||
v_color = a_color;
|
||||
v_textureCoordinates = a_textureCoordinates;
|
||||
v_textureIndex = a_textureIndex;
|
||||
// Vclip = Model transform * Vlocal
|
||||
gl_Position = vec4(a_position, 1.0f);
|
||||
}
|
||||
@@ -1,17 +1,21 @@
|
||||
#version 450 core
|
||||
|
||||
layout(location = 0) out vec4 color;
|
||||
layout(location = 0) out vec4 albedoSpec; // RGB diffuse color
|
||||
layout(location = 1) out vec4 position;
|
||||
layout(location = 2) out vec4 normal;
|
||||
|
||||
in vec3 v_position;
|
||||
in vec3 v_normal;
|
||||
in vec4 v_color;
|
||||
in vec2 v_textureCoordinates;
|
||||
in flat float v_textureIndex;
|
||||
in flat uint v_textureIndex;
|
||||
|
||||
uniform sampler2D u_textures[32];
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 textureColor = vec4(1.0f);
|
||||
switch(int(v_textureIndex)) {
|
||||
vec4 textureColor = v_color;
|
||||
switch(v_textureIndex) {
|
||||
case 0: break; // Texture unit 0 is reserved for no texture
|
||||
case 1: textureColor *= texture(u_textures[1], v_textureCoordinates); break;
|
||||
case 2: textureColor *= texture(u_textures[2], v_textureCoordinates); break;
|
||||
@@ -45,5 +49,9 @@ void main()
|
||||
case 30: textureColor *= texture(u_textures[30], v_textureCoordinates); break;
|
||||
case 31: textureColor *= texture(u_textures[31], v_textureCoordinates); break;
|
||||
}
|
||||
color = textureColor;
|
||||
|
||||
albedoSpec.rgb = textureColor.rgb;
|
||||
albedoSpec.a = 1.0; // TODO: read specular from model material
|
||||
position = vec4(v_position, 1.0f);
|
||||
normal = vec4(normalize(v_normal), 1.0f);
|
||||
}
|
||||
|
||||
@@ -2,18 +2,27 @@
|
||||
|
||||
layout(location = 0) in vec3 a_position;
|
||||
layout(location = 1) in vec3 a_normal;
|
||||
layout(location = 2) in vec2 a_textureCoordinates;
|
||||
layout(location = 3) in float a_textureIndex;
|
||||
layout(location = 2) in vec4 a_color;
|
||||
layout(location = 3) in vec2 a_textureCoordinates;
|
||||
layout(location = 4) in uint a_textureIndex;
|
||||
|
||||
out vec3 v_position;
|
||||
out vec3 v_normal;
|
||||
out vec4 v_color;
|
||||
out vec2 v_textureCoordinates;
|
||||
out flat float v_textureIndex;
|
||||
out flat uint v_textureIndex;
|
||||
|
||||
uniform mat4 u_projectionView;
|
||||
layout(std140, binding = 0) uniform Camera
|
||||
{
|
||||
mat4 u_projectionView;
|
||||
vec3 u_position;
|
||||
};
|
||||
|
||||
void main()
|
||||
{
|
||||
v_position = a_position;
|
||||
v_normal = a_normal;
|
||||
v_color = a_color;
|
||||
v_textureCoordinates = a_textureCoordinates;
|
||||
v_textureIndex = a_textureIndex;
|
||||
// Vclip = Camera projection * Camera view * Model transform * Vlocal
|
||||
|
||||
@@ -4,14 +4,14 @@ layout(location = 0) out vec4 color;
|
||||
|
||||
in vec4 v_color;
|
||||
in vec3 v_textureCoordinates;
|
||||
in flat float v_textureIndex;
|
||||
in flat uint v_textureIndex;
|
||||
|
||||
uniform samplerCube u_textures[32];
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 textureColor = v_color;
|
||||
switch(int(v_textureIndex)) {
|
||||
switch(v_textureIndex) {
|
||||
case 0: break; // Texture unit 0 is reserved for no texture
|
||||
case 1: textureColor *= texture(u_textures[1], v_textureCoordinates); break;
|
||||
case 2: textureColor *= texture(u_textures[2], v_textureCoordinates); break;
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
layout(location = 0) in vec3 a_position;
|
||||
layout(location = 1) in vec4 a_color;
|
||||
layout(location = 2) in float a_textureIndex;
|
||||
layout(location = 2) in uint a_textureIndex;
|
||||
|
||||
out vec4 v_color;
|
||||
out vec3 v_textureCoordinates;
|
||||
out flat float v_textureIndex;
|
||||
out flat uint v_textureIndex;
|
||||
|
||||
uniform mat4 u_projectionView;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ layout(location = 0) out vec4 color;
|
||||
|
||||
in vec4 v_color;
|
||||
in vec2 v_textureCoordinates;
|
||||
in flat float v_textureIndex;
|
||||
in flat uint v_textureIndex;
|
||||
in float v_width;
|
||||
in float v_edge;
|
||||
in float v_borderWidth;
|
||||
@@ -25,7 +25,7 @@ float alpha(float textureAlpha)
|
||||
void main()
|
||||
{
|
||||
vec4 textureColor = v_color;
|
||||
switch(int(v_textureIndex)) {
|
||||
switch(v_textureIndex) {
|
||||
case 0: break; // Texture unit 0 is reserved for no texture
|
||||
// case 1: textureColor.a = 1; break;
|
||||
case 1: textureColor.a = alpha(texture(u_textures[1], v_textureCoordinates).a); break;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
layout(location = 0) in vec3 a_position;
|
||||
layout(location = 1) in vec4 a_color;
|
||||
layout(location = 2) in vec2 a_textureCoordinates;
|
||||
layout(location = 3) in float a_textureIndex;
|
||||
layout(location = 3) in uint a_textureIndex;
|
||||
layout(location = 4) in float a_width;
|
||||
layout(location = 5) in float a_edge;
|
||||
layout(location = 6) in float a_borderWidth;
|
||||
@@ -13,7 +13,7 @@ layout(location = 9) in float a_offset;
|
||||
|
||||
out vec4 v_color;
|
||||
out vec2 v_textureCoordinates;
|
||||
out flat float v_textureIndex;
|
||||
out flat uint v_textureIndex;
|
||||
out float v_width;
|
||||
out float v_edge;
|
||||
out float v_borderWidth;
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
#version 450 core
|
||||
|
||||
layout(location = 0) out vec4 color;
|
||||
|
||||
in vec4 v_color;
|
||||
in vec3 v_textureCoordinates;
|
||||
in flat uint v_textureIndex;
|
||||
|
||||
uniform samplerCube u_textures[32];
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -2,19 +2,22 @@
|
||||
|
||||
layout(location = 0) in vec3 a_position;
|
||||
layout(location = 1) in vec4 a_color;
|
||||
layout(location = 2) in vec2 a_textureCoordinates;
|
||||
layout(location = 3) in float a_textureIndex;
|
||||
layout(location = 2) in uint a_textureIndex;
|
||||
|
||||
out vec4 v_color;
|
||||
out vec2 v_textureCoordinates;
|
||||
out flat float v_textureIndex;
|
||||
out vec3 v_textureCoordinates;
|
||||
out flat uint v_textureIndex;
|
||||
|
||||
uniform mat4 u_projectionView;
|
||||
layout(std140, binding = 0) uniform Camera
|
||||
{
|
||||
mat4 u_projectionView;
|
||||
vec3 u_position;
|
||||
};
|
||||
|
||||
void main()
|
||||
{
|
||||
v_color = a_color;
|
||||
v_textureCoordinates = a_textureCoordinates;
|
||||
v_textureCoordinates = a_position;
|
||||
v_textureIndex = a_textureIndex;
|
||||
// Vclip = Camera projection * Camera view * Model transform * Vlocal
|
||||
gl_Position = u_projectionView * vec4(a_position, 1.0f);
|
||||
@@ -0,0 +1,78 @@
|
||||
#version 450 core
|
||||
|
||||
layout(location = 0) out vec4 color;
|
||||
|
||||
in vec4 v_color;
|
||||
in vec2 v_textureCoordinates;
|
||||
in flat uint v_textureIndex;
|
||||
|
||||
uniform sampler2D u_textures[32];
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
layout(std140, binding = 0) uniform Camera {
|
||||
mat4 u_projectionView;
|
||||
vec3 u_position;
|
||||
};
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
struct DirectionalLight {
|
||||
vec3 direction;
|
||||
|
||||
vec3 ambient;
|
||||
vec3 diffuse;
|
||||
vec3 specular;
|
||||
};
|
||||
|
||||
const int MAX_DIRECTIONAL_LIGHTS = 4;
|
||||
layout(std430, binding = 0) buffer DirectionalLights {
|
||||
DirectionalLight u_directionalLight[MAX_DIRECTIONAL_LIGHTS];
|
||||
};
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
void main()
|
||||
{
|
||||
float isObject = texture(u_textures[v_textureIndex + 1], v_textureCoordinates).a;
|
||||
if (isObject == 0.0f) {
|
||||
color = vec4(0,0,0,0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec3 albedo = texture(u_textures[v_textureIndex + 0], v_textureCoordinates).rgb;
|
||||
float specular = texture(u_textures[v_textureIndex + 0], v_textureCoordinates).a;
|
||||
vec3 position = texture(u_textures[v_textureIndex + 1], v_textureCoordinates).rgb;
|
||||
vec3 normal = texture(u_textures[v_textureIndex + 2], v_textureCoordinates).rgb;
|
||||
|
||||
|
||||
vec3 lighting = vec3(0.0f, 0.0f, 0.0f);//albedo * v_color.xyz;
|
||||
vec3 viewDirection = normalize(u_position - position);
|
||||
|
||||
// Loop through all directional lights
|
||||
for (int i = 0; i < MAX_DIRECTIONAL_LIGHTS; ++i) {
|
||||
// Diffuse
|
||||
vec3 lightDirection = normalize(-u_directionalLight[i].direction);
|
||||
float diffuse = max(dot(normal, lightDirection), 0.0f);
|
||||
|
||||
// Specular
|
||||
vec3 reflectionDirection = reflect(-lightDirection, normal);
|
||||
float specular = pow(max(dot(viewDirection, reflectionDirection), 0.0f), 32);
|
||||
|
||||
lighting +=
|
||||
(albedo * u_directionalLight[i].ambient) +
|
||||
(albedo * diffuse * u_directionalLight[i].diffuse) +
|
||||
(specular * u_directionalLight[i].specular);
|
||||
}
|
||||
|
||||
// Loop through all point lights
|
||||
// TODO
|
||||
// vec3 lightDirection = normalize(lightPosition - position);
|
||||
// float diffuse = max(dot(normal, lightDirection), 0.0f);
|
||||
// lighting += diffuse * albedo * u_lightColor;
|
||||
|
||||
// Loop through all spot lights
|
||||
// TODO
|
||||
|
||||
color = vec4(lighting, 1.0f);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#version 450 core
|
||||
|
||||
layout(location = 0) in vec3 a_position;
|
||||
layout(location = 1) in vec4 a_color;
|
||||
layout(location = 2) in vec2 a_textureCoordinates;
|
||||
layout(location = 3) in uint a_textureIndex;
|
||||
|
||||
out vec4 v_color;
|
||||
out vec2 v_textureCoordinates;
|
||||
out flat uint v_textureIndex;
|
||||
|
||||
layout(std140, binding = 0) uniform Camera
|
||||
{
|
||||
mat4 u_projectionView;
|
||||
vec3 u_position;
|
||||
};
|
||||
|
||||
void main()
|
||||
{
|
||||
v_color = a_color;
|
||||
v_textureCoordinates = a_textureCoordinates;
|
||||
v_textureIndex = a_textureIndex;
|
||||
// Vclip = Model transform * Vlocal
|
||||
gl_Position = vec4(a_position, 1.0f);
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,15 @@
|
||||
# Blender 4.2.0
|
||||
# www.blender.org
|
||||
usemtl (null)
|
||||
o Plane
|
||||
v -1.000000 -1.000000 -0.000000
|
||||
v 1.000000 -1.000000 -0.000000
|
||||
v -1.000000 1.000000 0.000000
|
||||
v 1.000000 1.000000 0.000000
|
||||
vn -0.0000 -0.0000 1.0000
|
||||
vt 0.000000 0.000000
|
||||
vt 1.000000 0.000000
|
||||
vt 1.000000 1.000000
|
||||
vt 0.000000 1.000000
|
||||
s 0
|
||||
f 1/1/1 2/2/1 4/3/1 3/4/1
|
||||
@@ -35,8 +35,9 @@
|
||||
"rotate": [ 0.0, 0.0, 0.0 ],
|
||||
"scale": [ 1.0, 1.0, 1.0 ]
|
||||
},
|
||||
"sprite": {
|
||||
"model": {
|
||||
"color": [ 1.0, 1.0, 1.0, 1.0 ],
|
||||
"model": "assets/model/quad.obj",
|
||||
"texture": "assets/gfx/test.png"
|
||||
}
|
||||
},
|
||||
@@ -48,8 +49,9 @@
|
||||
"rotate": [ 0.0, 0.0, 0.0 ],
|
||||
"scale": [ 1.0, 1.0, 1.0 ]
|
||||
},
|
||||
"sprite": {
|
||||
"model": {
|
||||
"color": [ 0.5, 0.6, 0.8, 1.0 ],
|
||||
"model": "assets/model/quad.obj",
|
||||
"texture": "assets/gfx/test.png"
|
||||
}
|
||||
},
|
||||
@@ -61,8 +63,9 @@
|
||||
"rotate": [ 0.0, 0.0, -20.0 ],
|
||||
"scale": [ 1.0, 1.0, 1.0 ]
|
||||
},
|
||||
"sprite": {
|
||||
"model": {
|
||||
"color": [ 1.0, 1.0, 1.0, 1.0 ],
|
||||
"model": "assets/model/quad.obj",
|
||||
"texture": "assets/gfx/test-inverted.png"
|
||||
},
|
||||
"children": [
|
||||
@@ -74,8 +77,9 @@
|
||||
"rotate": [ 0.0, 0.0, 0.0 ],
|
||||
"scale": [ 0.5, 0.5, 1.0 ]
|
||||
},
|
||||
"sprite": {
|
||||
"model": {
|
||||
"color": [ 1.0, 1.0, 1.0, 1.0 ],
|
||||
"model": "assets/model/quad.obj",
|
||||
"texture": "assets/gfx/test-inverted.png"
|
||||
},
|
||||
"children": [
|
||||
@@ -87,8 +91,9 @@
|
||||
"rotate": [ 0.0, 0.0, -20.0 ],
|
||||
"scale": [ 0.5, 0.5, 1.0 ]
|
||||
},
|
||||
"sprite": {
|
||||
"model": {
|
||||
"color": [ 1.0, 1.0, 1.0, 1.0 ],
|
||||
"model": "assets/model/quad.obj",
|
||||
"texture": "assets/gfx/test-inverted.png"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"fullscreen": "windowed",
|
||||
"height": 720,
|
||||
"title": "Inferno",
|
||||
"vsync": true,
|
||||
"vsync": false,
|
||||
"width": 1280
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#+TITLE: Documentation
|
||||
#+AUTHOR: Riyyi
|
||||
#+LANGUAGE: en
|
||||
#+OPTIONS: toc:nil
|
||||
|
||||
Topics:
|
||||
|
||||
- [[./shaders.org][Shaders]]
|
||||
- [[./references.org][References]]
|
||||
@@ -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]]
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
#+TITLE: Shaders
|
||||
#+AUTHOR: Riyyi
|
||||
#+LANGUAGE: en
|
||||
#+OPTIONS: toc:nil
|
||||
|
||||
Topics:
|
||||
|
||||
- [[./memory-layout.org][Memory Layout]]
|
||||
@@ -15,6 +15,7 @@ add_executable(${GAME} ${GAME_SOURCES})
|
||||
target_include_directories(${GAME} PRIVATE
|
||||
"src")
|
||||
target_link_libraries(${GAME} ${ENGINE})
|
||||
target_compile_options(${GAME} PRIVATE ${COMPILE_FLAGS_PROJECT})
|
||||
|
||||
target_precompile_headers(${GAME} REUSE_FROM ${ENGINE})
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ target_include_directories(${ENGINE} PUBLIC
|
||||
"../vendor/sol2/include"
|
||||
"../vendor/stb")
|
||||
target_link_libraries(${ENGINE} ${ENGINE}-dependencies)
|
||||
target_compile_options(${ENGINE} PRIVATE ${COMPILE_FLAGS_PROJECT})
|
||||
|
||||
# ------------------------------------------
|
||||
|
||||
|
||||
+19
-57
@@ -23,6 +23,8 @@
|
||||
#include "inferno/render/buffer.h"
|
||||
#include "inferno/render/context.h"
|
||||
#include "inferno/render/framebuffer.h"
|
||||
#include "inferno/render/uniformbuffer.h"
|
||||
#include "inferno/system/rendersystem.h"
|
||||
// #include "inferno/render/gltf.h"
|
||||
#include "inferno/asset/shader.h"
|
||||
#include "inferno/asset/texture.h"
|
||||
@@ -52,20 +54,7 @@ Application::Application()
|
||||
|
||||
Input::initialize();
|
||||
RenderCommand::initialize();
|
||||
|
||||
m_framebuffer = Framebuffer::create({
|
||||
.attachments = { Framebuffer::Type::Color, Framebuffer::Type::Depth },
|
||||
.width = m_window->getWidth(),
|
||||
.height = m_window->getHeight(),
|
||||
.clearColor = { 0.2f, 0.3f, 0.3f, 1.0f },
|
||||
.clearBit = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT,
|
||||
});
|
||||
|
||||
m_screenFramebuffer = Framebuffer::create({
|
||||
.renderToScreen = true,
|
||||
.clearColor = { 1.0f, 1.0f, 1.0f, 1.0f },
|
||||
.clearBit = GL_COLOR_BUFFER_BIT,
|
||||
});
|
||||
RenderSystem::the().initialize(m_window->getWidth(), m_window->getHeight());
|
||||
|
||||
m_scene = std::make_shared<Scene>();
|
||||
m_scene->initialize();
|
||||
@@ -90,11 +79,14 @@ Application::Application()
|
||||
Application::~Application()
|
||||
{
|
||||
m_scene->destroy();
|
||||
Uniformbuffer::destroy();
|
||||
|
||||
RendererFont::destroy();
|
||||
Renderer2D::destroy();
|
||||
Renderer3D::destroy();
|
||||
RendererCubemap::destroy();
|
||||
RendererPostProcess::destroy();
|
||||
RendererLightCube::destroy();
|
||||
RenderCommand::destroy();
|
||||
AssetManager::destroy();
|
||||
// Input::destroy();
|
||||
@@ -158,11 +150,9 @@ int Application::run()
|
||||
// offset
|
||||
#endif
|
||||
|
||||
constexpr glm::vec4 vectorOne { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
constexpr glm::mat4 matIdentity { 1.0f };
|
||||
constexpr TransformComponent transformIdentity;
|
||||
double gametime = 0;
|
||||
uint64_t frames = 0;
|
||||
|
||||
// m_window->setVSync(false);
|
||||
while (!m_window->shouldClose()) {
|
||||
|
||||
float time = Time::time();
|
||||
@@ -170,6 +160,9 @@ int Application::run()
|
||||
m_lastFrameTime = time;
|
||||
// ruc::debug("Frametime {}ms", deltaTime * 1000);
|
||||
|
||||
gametime += deltaTime;
|
||||
frames++;
|
||||
|
||||
// ---------------------------------
|
||||
// Update
|
||||
|
||||
@@ -182,50 +175,15 @@ int Application::run()
|
||||
// ---------------------------------
|
||||
// Render
|
||||
|
||||
m_framebuffer->bind();
|
||||
|
||||
RenderCommand::clearColor(m_framebuffer->clearColor());
|
||||
RenderCommand::clearBit(m_framebuffer->clearBit());
|
||||
|
||||
render();
|
||||
|
||||
std::pair<glm::mat4, glm::mat4> projectionView = m_scene->cameraProjectionView();
|
||||
RendererCubemap::the().beginScene(projectionView.first, projectionView.second); // camera, lights, environment
|
||||
Renderer3D::the().beginScene(projectionView.first, projectionView.second); // camera, lights, environment
|
||||
Renderer2D::the().beginScene(projectionView.first, projectionView.second); // camera, lights, environment
|
||||
RendererFont::the().beginScene(projectionView.first, projectionView.second); // camera, lights, environment
|
||||
|
||||
m_scene->render();
|
||||
// RendererCharacter::the().drawCharacter(character, f->texture());
|
||||
|
||||
RendererCubemap::the().endScene();
|
||||
Renderer3D::the().endScene();
|
||||
Renderer2D::the().endScene();
|
||||
RendererFont::the().endScene();
|
||||
|
||||
m_framebuffer->unbind();
|
||||
|
||||
// ---------------------------------
|
||||
// Framebuffer
|
||||
|
||||
m_screenFramebuffer->bind();
|
||||
|
||||
RenderCommand::clearColor(m_screenFramebuffer->clearColor());
|
||||
RenderCommand::clearBit(m_screenFramebuffer->clearBit());
|
||||
|
||||
Renderer2D::the().setEnableDepthBuffer(false);
|
||||
Renderer2D::the().beginScene(matIdentity, matIdentity);
|
||||
Renderer2D::the().drawQuad(transformIdentity, vectorOne, m_framebuffer->texture(0));
|
||||
Renderer2D::the().endScene();
|
||||
Renderer2D::the().setEnableDepthBuffer(true);
|
||||
|
||||
m_screenFramebuffer->unbind();
|
||||
|
||||
m_window->render();
|
||||
}
|
||||
|
||||
ruc::debug("Application shutdown");
|
||||
|
||||
ruc::debug("Average frametime: {:.2f}ms", (gametime / frames) * 1000);
|
||||
|
||||
return m_status;
|
||||
}
|
||||
|
||||
@@ -254,8 +212,7 @@ bool Application::onWindowResize(WindowResizeEvent& e)
|
||||
{
|
||||
ruc::info("WindowResizeEvent {}x{}", e.getWidth(), e.getHeight());
|
||||
|
||||
RenderCommand::setViewport(0, 0, e.getWidth(), e.getHeight());
|
||||
m_framebuffer->resize(e.getWidth(), e.getHeight());
|
||||
RenderSystem::the().resize(e.getWidth(), e.getHeight());
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -269,6 +226,11 @@ bool Application::onKeyPress(KeyPressEvent& e)
|
||||
m_window->setShouldClose(true);
|
||||
}
|
||||
|
||||
if (e.getKey() == keyCode("GLFW_KEY_F12")) {
|
||||
ruc::info("Taking screenshot..");
|
||||
Texture::saveScreenshotPNG("screenshot.png", m_window->getWidth(), m_window->getHeight());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,8 +51,6 @@ private:
|
||||
float m_lastFrameTime { 0.0f };
|
||||
|
||||
std::unique_ptr<Window> m_window;
|
||||
std::shared_ptr<Framebuffer> m_framebuffer;
|
||||
std::shared_ptr<Framebuffer> m_screenFramebuffer;
|
||||
std::shared_ptr<Scene> m_scene;
|
||||
|
||||
//
|
||||
|
||||
@@ -40,7 +40,7 @@ std::shared_ptr<Model> Model::create(std::string_view path)
|
||||
void Model::processScene(std::shared_ptr<Model> model, const aiScene* scene)
|
||||
{
|
||||
VERIFY(scene->HasMeshes(), "malformed model");
|
||||
VERIFY(scene->mNumTextures < 2, "unsupported model type");
|
||||
VERIFY(scene->mNumTextures < 2, "unsupported model type: {}/1", scene->mNumTextures);
|
||||
|
||||
if (scene->mNumTextures == 1) {
|
||||
aiTexture* texture = scene->mTextures[0];
|
||||
|
||||
@@ -50,65 +50,74 @@ Shader::~Shader()
|
||||
}
|
||||
}
|
||||
|
||||
int32_t Shader::findUniform(std::string_view name) const
|
||||
// -----------------------------------------
|
||||
|
||||
uint32_t Shader::findUniformLocation(std::string_view name)
|
||||
{
|
||||
// Cache uniform locations, prevent going to the GPU every call
|
||||
if (m_uniformLocations.find(name) != m_uniformLocations.end()) {
|
||||
return m_uniformLocations[name];
|
||||
}
|
||||
|
||||
int32_t location = glGetUniformLocation(m_id, name.data());
|
||||
VERIFY(location != -1, "Shader could not find uniform '{}'", name);
|
||||
m_uniformLocations[name] = static_cast<uint32_t>(location);
|
||||
|
||||
return location;
|
||||
}
|
||||
|
||||
void Shader::setInt(std::string_view name, int value)
|
||||
{
|
||||
// Set uniform int
|
||||
glUniform1i(findUniform(name), value);
|
||||
glUniform1i(findUniformLocation(name), value);
|
||||
}
|
||||
|
||||
void Shader::setInt(std::string_view name, int* values, uint32_t count)
|
||||
{
|
||||
// Set uniform int array
|
||||
glUniform1iv(findUniform(name), count, values);
|
||||
glUniform1iv(findUniformLocation(name), count, values);
|
||||
}
|
||||
|
||||
void Shader::setFloat(std::string_view name, float value) const
|
||||
void Shader::setFloat(std::string_view name, float value)
|
||||
{
|
||||
// Set uniform float
|
||||
glUniform1f(findUniform(name), value);
|
||||
glUniform1f(findUniformLocation(name), value);
|
||||
}
|
||||
|
||||
void Shader::setFloat(std::string_view name, float v1, float v2, float v3, float v4) const
|
||||
void Shader::setFloat(std::string_view name, float v1, float v2, float v3, float v4)
|
||||
{
|
||||
// Set uniform vec4 data
|
||||
glUniform4f(findUniform(name), v1, v2, v3, v4);
|
||||
glUniform4f(findUniformLocation(name), v1, v2, v3, v4);
|
||||
}
|
||||
|
||||
void Shader::setFloat(std::string_view name, glm::vec2 value) const
|
||||
void Shader::setFloat(std::string_view name, glm::vec2 value)
|
||||
{
|
||||
// Set uniform vec2 data
|
||||
glUniform2f(findUniform(name), value.x, value.y);
|
||||
glUniform2f(findUniformLocation(name), value.x, value.y);
|
||||
}
|
||||
|
||||
void Shader::setFloat(std::string_view name, glm::vec3 value) const
|
||||
void Shader::setFloat(std::string_view name, glm::vec3 value)
|
||||
{
|
||||
// Set uniform vec3 data
|
||||
glUniform3f(findUniform(name), value.x, value.y, value.z);
|
||||
glUniform3f(findUniformLocation(name), value.x, value.y, value.z);
|
||||
}
|
||||
|
||||
void Shader::setFloat(std::string_view name, glm::vec4 value) const
|
||||
void Shader::setFloat(std::string_view name, glm::vec4 value)
|
||||
{
|
||||
// Set uniform vec4 data
|
||||
glUniform4f(findUniform(name), value.x, value.y, value.z, value.w);
|
||||
glUniform4f(findUniformLocation(name), value.x, value.y, value.z, value.w);
|
||||
}
|
||||
|
||||
void Shader::setFloat(std::string_view name, glm::mat3 matrix) const
|
||||
void Shader::setFloat(std::string_view name, glm::mat3 matrix)
|
||||
{
|
||||
// Set uniform mat3 data
|
||||
glUniformMatrix3fv(findUniform(name), 1, GL_FALSE, glm::value_ptr(matrix));
|
||||
glUniformMatrix3fv(findUniformLocation(name), 1, GL_FALSE, glm::value_ptr(matrix));
|
||||
}
|
||||
|
||||
void Shader::setFloat(std::string_view name, glm::mat4 matrix) const
|
||||
void Shader::setFloat(std::string_view name, glm::mat4 matrix)
|
||||
{
|
||||
// Set uniform mat4 data
|
||||
glUniformMatrix4fv(findUniform(name), 1, GL_FALSE, glm::value_ptr(matrix));
|
||||
glUniformMatrix4fv(findUniformLocation(name), 1, GL_FALSE, glm::value_ptr(matrix));
|
||||
}
|
||||
|
||||
void Shader::bind() const
|
||||
@@ -121,6 +130,8 @@ void Shader::unbind() const
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
uint32_t Shader::compileShader(int32_t type, const char* source) const
|
||||
{
|
||||
// Create new shader
|
||||
|
||||
@@ -4,8 +4,11 @@
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint> // int32_t, uint32_t
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "glm/fwd.hpp" // glm::mat3, glm::mat4, glm::vec2, glm::vec3
|
||||
|
||||
@@ -20,17 +23,17 @@ public:
|
||||
// Factory function
|
||||
static std::shared_ptr<Shader> create(std::string_view path);
|
||||
|
||||
int32_t findUniform(std::string_view name) const;
|
||||
uint32_t findUniformLocation(std::string_view name);
|
||||
|
||||
void setInt(std::string_view name, int value);
|
||||
void setInt(std::string_view name, int* values, uint32_t count);
|
||||
void setFloat(std::string_view name, float value) const;
|
||||
void setFloat(std::string_view name, float v1, float v2, float v3, float v4) const;
|
||||
void setFloat(std::string_view name, glm::vec2 value) const;
|
||||
void setFloat(std::string_view name, glm::vec3 value) const;
|
||||
void setFloat(std::string_view name, glm::vec4 value) const;
|
||||
void setFloat(std::string_view name, glm::mat3 matrix) const;
|
||||
void setFloat(std::string_view name, glm::mat4 matrix) const;
|
||||
void setFloat(std::string_view name, float value);
|
||||
void setFloat(std::string_view name, float v1, float v2, float v3, float v4);
|
||||
void setFloat(std::string_view name, glm::vec2 value);
|
||||
void setFloat(std::string_view name, glm::vec3 value);
|
||||
void setFloat(std::string_view name, glm::vec4 value);
|
||||
void setFloat(std::string_view name, glm::mat3 matrix);
|
||||
void setFloat(std::string_view name, glm::mat4 matrix);
|
||||
|
||||
void bind() const;
|
||||
void unbind() const;
|
||||
@@ -52,6 +55,7 @@ private:
|
||||
|
||||
private:
|
||||
uint32_t m_id { 0 };
|
||||
std::unordered_map<std::string_view, uint32_t> m_uniformLocations;
|
||||
};
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#include "ruc/meta/assert.h"
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb/stb_image.h"
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include "stb/stb_image_write.h"
|
||||
|
||||
#include "inferno/asset/texture.h"
|
||||
|
||||
@@ -23,6 +25,51 @@ Texture::~Texture()
|
||||
glDeleteTextures(1, &m_id);
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
void Texture::savePNG(std::string_view path, std::shared_ptr<Texture> texture)
|
||||
{
|
||||
texture->bind();
|
||||
|
||||
// Allocate memory
|
||||
uint32_t dataFormat = texture->m_dataFormat == GL_RGBA ? 4 : 3;
|
||||
size_t dataSize = texture->m_width * texture->m_height * dataFormat;
|
||||
std::vector<unsigned char> data(dataSize);
|
||||
|
||||
// Read texture data from the GPU
|
||||
glGetTexImage(GL_TEXTURE_2D, 0, texture->m_dataFormat, texture->m_dataType, data.data());
|
||||
|
||||
// Write image to a file
|
||||
stbi_flip_vertically_on_write(1);
|
||||
stbi_write_png(
|
||||
path.data(),
|
||||
texture->m_width,
|
||||
texture->m_height,
|
||||
dataFormat,
|
||||
data.data(),
|
||||
texture->m_width * dataFormat);
|
||||
|
||||
texture->unbind();
|
||||
}
|
||||
|
||||
void Texture::saveScreenshotPNG(std::string_view path, uint32_t width, uint32_t height)
|
||||
{
|
||||
// Allocate memory
|
||||
size_t dataSize = width * height * 4;
|
||||
std::vector<unsigned char> data(dataSize);
|
||||
|
||||
// Set the pack alignment to 1 (to avoid row alignment issues)
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
|
||||
// Read the pixels from the default framebuffer
|
||||
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data.data());
|
||||
|
||||
stbi_flip_vertically_on_write(1);
|
||||
stbi_write_png(path.data(), width, height, 4, data.data(), width * 4);
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
void Texture::init(uint32_t width, uint32_t height, uint8_t channels)
|
||||
{
|
||||
init(width, height,
|
||||
@@ -283,8 +330,8 @@ void TextureFramebuffer::createImpl()
|
||||
m_dataType, // Texture source datatype
|
||||
NULL); // Image data
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
// Unbind texture object
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
@@ -22,6 +22,9 @@ class Texture : public Asset {
|
||||
public:
|
||||
virtual ~Texture();
|
||||
|
||||
static void savePNG(std::string_view path, std::shared_ptr<Texture> texture);
|
||||
static void saveScreenshotPNG(std::string_view path, uint32_t width, uint32_t height);
|
||||
|
||||
void init(uint32_t width, uint32_t height, uint8_t channels);
|
||||
void init(uint32_t width, uint32_t height, uint32_t internalFormat, uint32_t dataFormat, uint32_t dataType);
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#include "inferno/asset/texture.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 {
|
||||
|
||||
@@ -22,6 +22,9 @@ void fromJson(const ruc::Json& json, CubemapComponent& value)
|
||||
if (json.exists("texture") && json.at("texture").type() == ruc::Json::Type::String) {
|
||||
value.texture = AssetManager::the().load<TextureCubemap>(json.at("texture").asString());
|
||||
}
|
||||
if (json.exists("isLight")) {
|
||||
json.at("isLight").getTo(value.isLight);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Inferno
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace Inferno {
|
||||
struct CubemapComponent {
|
||||
glm::vec4 color { 1.0f };
|
||||
std::shared_ptr<Texture> texture;
|
||||
bool isLight { false };
|
||||
};
|
||||
|
||||
void fromJson(const ruc::Json& json, CubemapComponent& value);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "inferno/asset/asset-manager.h"
|
||||
#include "inferno/asset/model.h"
|
||||
#include "inferno/asset/texture.h"
|
||||
#include "inferno/component/serialize.h" // not detected as used by clang-tidy
|
||||
|
||||
namespace Inferno {
|
||||
|
||||
@@ -15,6 +16,9 @@ void fromJson(const ruc::Json& json, ModelComponent& value)
|
||||
{
|
||||
VERIFY(json.type() == ruc::Json::Type::Object);
|
||||
|
||||
if (json.exists("color")) {
|
||||
json.at("color").getTo(value.color);
|
||||
}
|
||||
if (json.exists("model") && json.at("model").type() == ruc::Json::Type::String) {
|
||||
value.model = AssetManager::the().load<Model>(json.at("model").asString());
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
namespace Inferno {
|
||||
|
||||
struct ModelComponent {
|
||||
glm::vec4 color { 1.0f };
|
||||
std::shared_ptr<Model> model;
|
||||
std::shared_ptr<Texture2D> texture;
|
||||
};
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
@@ -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,9 +4,12 @@
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "inferno/component/spritecomponent.h"
|
||||
#include "ruc/json/json.h"
|
||||
|
||||
#include "inferno/asset/asset-manager.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 {
|
||||
|
||||
@@ -23,27 +26,3 @@ void fromJson(const ruc::Json& json, SpriteComponent& value)
|
||||
}
|
||||
|
||||
} // 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
|
||||
|
||||
@@ -23,10 +23,3 @@ struct SpriteComponent {
|
||||
void fromJson(const ruc::Json& json, SpriteComponent& value);
|
||||
|
||||
} // namespace Inferno
|
||||
|
||||
namespace glm {
|
||||
|
||||
void toJson(ruc::Json& json, const vec4& value);
|
||||
void fromJson(const ruc::Json& json, vec4& value);
|
||||
|
||||
} // namespace glm
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "ruc/format/format.h"
|
||||
#include "ruc/json/json.h"
|
||||
|
||||
#include "inferno/component/serialize.h"
|
||||
#include "inferno/component/transformcomponent.h"
|
||||
|
||||
namespace Inferno {
|
||||
@@ -28,56 +29,6 @@ void fromJson(const ruc::Json& json, TransformComponent& value)
|
||||
|
||||
} // 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
|
||||
{
|
||||
builder.putString("transform ");
|
||||
|
||||
@@ -6,9 +6,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint> // uint32_t
|
||||
#include <optional>
|
||||
|
||||
#include "entt/entity/entity.hpp" // entt::null
|
||||
#include "entt/entity/fwd.hpp" // entt::entity
|
||||
#include "glm/ext/matrix_float4x4.hpp" // glm::mat4
|
||||
@@ -31,33 +28,6 @@ void fromJson(const ruc::Json& json, TransformComponent& value);
|
||||
|
||||
} // 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<>
|
||||
struct ruc::format::Formatter<Inferno::TransformComponent> : Formatter<glm::vec3> {
|
||||
void format(Builder& builder, Inferno::TransformComponent value) const;
|
||||
|
||||
@@ -14,24 +14,27 @@ namespace Inferno {
|
||||
|
||||
class KeyEvent : public Event {
|
||||
public:
|
||||
inline int getKey() const { return m_key; }
|
||||
int getKey() const { return m_key; }
|
||||
int getMods() const { return m_mods; }
|
||||
|
||||
EVENT_CLASS_CATEGORY(InputEventCategory | KeyEventCategory)
|
||||
|
||||
protected:
|
||||
KeyEvent(int key)
|
||||
KeyEvent(int key, int mods)
|
||||
: m_key(key)
|
||||
, m_mods(mods)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
int m_key;
|
||||
int m_key { 0 };
|
||||
int m_mods { 0 };
|
||||
};
|
||||
|
||||
class KeyPressEvent : public KeyEvent {
|
||||
class KeyPressEvent final : public KeyEvent {
|
||||
public:
|
||||
KeyPressEvent(int key)
|
||||
: KeyEvent(key)
|
||||
KeyPressEvent(int key, int mods)
|
||||
: KeyEvent(key, mods)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -45,10 +48,10 @@ public:
|
||||
EVENT_CLASS_TYPE(KeyPress)
|
||||
};
|
||||
|
||||
class KeyReleaseEvent : public KeyEvent {
|
||||
class KeyReleaseEvent final : public KeyEvent {
|
||||
public:
|
||||
KeyReleaseEvent(int key)
|
||||
: KeyEvent(key)
|
||||
KeyReleaseEvent(int key, int mods)
|
||||
: KeyEvent(key, mods)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -59,13 +62,13 @@ public:
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
EVENT_CLASS_TYPE(KeyPress)
|
||||
EVENT_CLASS_TYPE(KeyRelease)
|
||||
};
|
||||
|
||||
class KeyRepeatEvent : public KeyEvent {
|
||||
class KeyRepeatEvent final : public KeyEvent {
|
||||
public:
|
||||
KeyRepeatEvent(int key)
|
||||
: KeyEvent(key)
|
||||
KeyRepeatEvent(int key, int mods)
|
||||
: KeyEvent(key, mods)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -76,7 +79,7 @@ public:
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
EVENT_CLASS_TYPE(KeyPress)
|
||||
EVENT_CLASS_TYPE(KeyRepeat)
|
||||
};
|
||||
|
||||
} // namespace Inferno
|
||||
|
||||
@@ -139,14 +139,33 @@ static std::unordered_map<std::string_view, int> keys({
|
||||
{ MAP_KEY(GLFW_KEY_MENU) },
|
||||
});
|
||||
|
||||
static std::unordered_map<std::string_view, int> modifiers({
|
||||
{ MAP_KEY(GLFW_MOD_SHIFT) },
|
||||
{ MAP_KEY(GLFW_MOD_CONTROL) },
|
||||
{ MAP_KEY(GLFW_MOD_ALT) },
|
||||
{ MAP_KEY(GLFW_MOD_SUPER) },
|
||||
{ MAP_KEY(GLFW_MOD_CAPS_LOCK) }, // State, not really a modifier
|
||||
{ MAP_KEY(GLFW_MOD_NUM_LOCK) }, // State, not really a modifier
|
||||
});
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
// Example usage:
|
||||
// event.getKey() == keyCode("GLFW_KEY_ESCAPE")
|
||||
int keyCode(std::string_view name)
|
||||
{
|
||||
VERIFY(keys.find(name) != keys.end(), "could not find key code: {}", name);
|
||||
return keys.at(name);
|
||||
}
|
||||
|
||||
// Example usage:
|
||||
// event.getMods() & keyMod("GLFW_MOD_SHIFT")
|
||||
int keyMod(std::string_view name)
|
||||
{
|
||||
VERIFY(modifiers.find(name) != modifiers.end(), "could not find key modifier: {}", name);
|
||||
return modifiers.at(name);
|
||||
}
|
||||
|
||||
std::string_view keyName(int key)
|
||||
{
|
||||
auto it = std::find_if(keys.begin(), keys.end(), [key](const auto& keybind) {
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
namespace Inferno {
|
||||
|
||||
int keyCode(std::string_view name);
|
||||
std::string_view keyName(int);
|
||||
int keyMod(std::string_view name);
|
||||
|
||||
std::string_view keyName(int key);
|
||||
|
||||
} // namespace Inferno
|
||||
|
||||
+139
-30
@@ -4,6 +4,12 @@
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdint> // int32_t, uint8_t, uint32_t
|
||||
#include <memory> // std::shared_ptr
|
||||
#include <string>
|
||||
#include <utility> // std::pair
|
||||
|
||||
#include "glad/glad.h"
|
||||
#include "ruc/meta/assert.h"
|
||||
|
||||
@@ -36,7 +42,7 @@ uint32_t BufferElement::getTypeGL() const
|
||||
return BufferElement::getTypeGL(m_type);
|
||||
}
|
||||
|
||||
uint32_t BufferElement::getTypeSize(const BufferElementType type)
|
||||
uint32_t BufferElement::getTypeSize(BufferElementType type)
|
||||
{
|
||||
switch (type) {
|
||||
case BufferElementType::None:
|
||||
@@ -61,10 +67,10 @@ uint32_t BufferElement::getTypeSize(const BufferElementType type)
|
||||
case BufferElementType::Vec3:
|
||||
case BufferElementType::Vec4:
|
||||
return sizeof(float) * getTypeCount(type);
|
||||
case BufferElementType::VecDouble:
|
||||
case BufferElementType::VecDouble2:
|
||||
case BufferElementType::VecDouble3:
|
||||
case BufferElementType::VecDouble4:
|
||||
case BufferElementType::Double:
|
||||
case BufferElementType::Vec2Double:
|
||||
case BufferElementType::Vec3Double:
|
||||
case BufferElementType::Vec4Double:
|
||||
return sizeof(double) * getTypeCount(type);
|
||||
case BufferElementType::Mat2:
|
||||
case BufferElementType::Mat3:
|
||||
@@ -80,7 +86,7 @@ uint32_t BufferElement::getTypeSize(const BufferElementType type)
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t BufferElement::getTypeCount(const BufferElementType type)
|
||||
uint32_t BufferElement::getTypeCount(BufferElementType type)
|
||||
{
|
||||
switch (type) {
|
||||
case BufferElementType::None:
|
||||
@@ -89,25 +95,25 @@ uint32_t BufferElement::getTypeCount(const BufferElementType type)
|
||||
case BufferElementType::Int:
|
||||
case BufferElementType::Uint:
|
||||
case BufferElementType::Float:
|
||||
case BufferElementType::VecDouble:
|
||||
case BufferElementType::Double:
|
||||
return 1;
|
||||
case BufferElementType::Bool2:
|
||||
case BufferElementType::Int2:
|
||||
case BufferElementType::Uint2:
|
||||
case BufferElementType::Vec2:
|
||||
case BufferElementType::VecDouble2:
|
||||
case BufferElementType::Vec2Double:
|
||||
return 2;
|
||||
case BufferElementType::Bool3:
|
||||
case BufferElementType::Int3:
|
||||
case BufferElementType::Uint3:
|
||||
case BufferElementType::Vec3:
|
||||
case BufferElementType::VecDouble3:
|
||||
case BufferElementType::Vec3Double:
|
||||
return 3;
|
||||
case BufferElementType::Bool4:
|
||||
case BufferElementType::Int4:
|
||||
case BufferElementType::Uint4:
|
||||
case BufferElementType::Vec4:
|
||||
case BufferElementType::VecDouble4:
|
||||
case BufferElementType::Vec4Double:
|
||||
return 4;
|
||||
case BufferElementType::Mat2:
|
||||
return 2 * 2;
|
||||
@@ -127,7 +133,7 @@ uint32_t BufferElement::getTypeCount(const BufferElementType type)
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t BufferElement::getTypeGL(const BufferElementType type)
|
||||
uint32_t BufferElement::getTypeGL(BufferElementType type)
|
||||
{
|
||||
switch (type) {
|
||||
case BufferElementType::None:
|
||||
@@ -152,10 +158,10 @@ uint32_t BufferElement::getTypeGL(const BufferElementType type)
|
||||
case BufferElementType::Vec3:
|
||||
case BufferElementType::Vec4:
|
||||
return GL_FLOAT;
|
||||
case BufferElementType::VecDouble:
|
||||
case BufferElementType::VecDouble2:
|
||||
case BufferElementType::VecDouble3:
|
||||
case BufferElementType::VecDouble4:
|
||||
case BufferElementType::Double:
|
||||
case BufferElementType::Vec2Double:
|
||||
case BufferElementType::Vec3Double:
|
||||
case BufferElementType::Vec4Double:
|
||||
return GL_DOUBLE;
|
||||
case BufferElementType::Mat2:
|
||||
case BufferElementType::Mat3:
|
||||
@@ -171,6 +177,58 @@ uint32_t BufferElement::getTypeGL(const BufferElementType type)
|
||||
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)
|
||||
@@ -184,7 +242,7 @@ void BufferLayout::calculateOffsetsAndStride()
|
||||
m_stride = 0;
|
||||
for (auto& element : m_elements) {
|
||||
element.setOffset(m_stride);
|
||||
m_stride += element.getSize();
|
||||
m_stride += element.size();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,7 +260,7 @@ VertexBuffer::VertexBuffer(size_t size, float* vertices)
|
||||
bind();
|
||||
|
||||
// Upload data to the GPU
|
||||
glBufferData(GL_ARRAY_BUFFER, size, vertices, GL_STATIC_DRAW);
|
||||
glBufferData(GL_ARRAY_BUFFER, size, vertices, GL_DYNAMIC_DRAW);
|
||||
|
||||
unbind();
|
||||
}
|
||||
@@ -242,7 +300,7 @@ IndexBuffer::IndexBuffer(uint32_t* indices, size_t size)
|
||||
bind();
|
||||
|
||||
// Upload data to the GPU
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, indices, GL_STATIC_DRAW);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, indices, GL_DYNAMIC_DRAW);
|
||||
|
||||
unbind();
|
||||
}
|
||||
@@ -297,8 +355,8 @@ void VertexArray::unbind() const
|
||||
|
||||
void VertexArray::addVertexBuffer(std::shared_ptr<VertexBuffer> vertexBuffer)
|
||||
{
|
||||
const auto& layout = vertexBuffer->getLayout();
|
||||
VERIFY(layout.getElements().size(), "VertexBuffer has no layout");
|
||||
const auto& layout = vertexBuffer->layout();
|
||||
VERIFY(layout.elements().size(), "VertexBuffer has no layout");
|
||||
|
||||
bind();
|
||||
vertexBuffer->bind();
|
||||
@@ -306,20 +364,71 @@ void VertexArray::addVertexBuffer(std::shared_ptr<VertexBuffer> vertexBuffer)
|
||||
uint32_t index = 0;
|
||||
for (const auto& element : layout) {
|
||||
glEnableVertexAttribArray(index);
|
||||
glVertexAttribPointer(
|
||||
index,
|
||||
element.getTypeCount(),
|
||||
element.getTypeGL(),
|
||||
element.getNormalized() ? GL_TRUE : GL_FALSE,
|
||||
layout.getStride(),
|
||||
reinterpret_cast<const void*>(element.getOffset()));
|
||||
switch (element.type()) {
|
||||
case BufferElementType::None:
|
||||
break;
|
||||
case BufferElementType::Int:
|
||||
case BufferElementType::Int2:
|
||||
case BufferElementType::Int3:
|
||||
case BufferElementType::Int4:
|
||||
case BufferElementType::Uint:
|
||||
case BufferElementType::Uint2:
|
||||
case BufferElementType::Uint3:
|
||||
case BufferElementType::Uint4: {
|
||||
glVertexAttribIPointer(
|
||||
index,
|
||||
element.getTypeCount(),
|
||||
element.getTypeGL(),
|
||||
layout.stride(),
|
||||
reinterpret_cast<const void*>(element.offset()));
|
||||
break;
|
||||
}
|
||||
case BufferElementType::Bool:
|
||||
case BufferElementType::Bool2:
|
||||
case BufferElementType::Bool3:
|
||||
case BufferElementType::Bool4:
|
||||
case BufferElementType::Float:
|
||||
case BufferElementType::Vec2:
|
||||
case BufferElementType::Vec3:
|
||||
case BufferElementType::Vec4:
|
||||
case BufferElementType::Mat2:
|
||||
case BufferElementType::Mat3:
|
||||
case BufferElementType::Mat4: {
|
||||
glVertexAttribPointer(
|
||||
index,
|
||||
element.getTypeCount(),
|
||||
element.getTypeGL(),
|
||||
element.normalized() ? GL_TRUE : GL_FALSE,
|
||||
layout.stride(),
|
||||
reinterpret_cast<const void*>(element.offset()));
|
||||
break;
|
||||
}
|
||||
case BufferElementType::Double:
|
||||
case BufferElementType::Vec2Double:
|
||||
case BufferElementType::Vec3Double:
|
||||
case BufferElementType::Vec4Double:
|
||||
case BufferElementType::MatDouble2:
|
||||
case BufferElementType::MatDouble3:
|
||||
case BufferElementType::MatDouble4: {
|
||||
glVertexAttribLPointer(
|
||||
index,
|
||||
element.getTypeCount(),
|
||||
element.getTypeGL(),
|
||||
layout.stride(),
|
||||
reinterpret_cast<const void*>(element.offset()));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
};
|
||||
|
||||
index++;
|
||||
}
|
||||
m_vertexBuffers.push_back(std::move(vertexBuffer));
|
||||
|
||||
unbind();
|
||||
vertexBuffer->unbind();
|
||||
|
||||
m_vertexBuffers.push_back(std::move(vertexBuffer));
|
||||
}
|
||||
|
||||
void VertexArray::setIndexBuffer(std::shared_ptr<IndexBuffer> indexBuffer)
|
||||
@@ -327,10 +436,10 @@ void VertexArray::setIndexBuffer(std::shared_ptr<IndexBuffer> indexBuffer)
|
||||
bind();
|
||||
indexBuffer->bind();
|
||||
|
||||
m_indexBuffer = std::move(indexBuffer);
|
||||
|
||||
unbind();
|
||||
indexBuffer->unbind();
|
||||
|
||||
m_indexBuffer = std::move(indexBuffer);
|
||||
}
|
||||
|
||||
} // namespace Inferno
|
||||
|
||||
+24
-23
@@ -7,22 +7,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdint> // int32_t, uint32_t
|
||||
#include <cstdint> // int32_t, uint8_t, uint32_t
|
||||
#include <memory> // std::shared_ptr
|
||||
#include <string> // std::string
|
||||
#include <vector> // std::vector
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Inferno {
|
||||
|
||||
// clang-format off
|
||||
// https://www.khronos.org/opengl/wiki/Data_Type_(GLSL)
|
||||
enum class BufferElementType {
|
||||
enum class BufferElementType : uint8_t {
|
||||
None = 0,
|
||||
Bool, Bool2, Bool3, Bool4, // bvec
|
||||
Int, Int2, Int3, Int4, // ivec
|
||||
Uint, Uint2, Uint3, Uint4, // uvec
|
||||
Float, Vec2, Vec3, Vec4, // vec
|
||||
VecDouble, VecDouble2, VecDouble3, VecDouble4, // dvec
|
||||
Double, Vec2Double, Vec3Double, Vec4Double, // dvec
|
||||
Mat2, Mat3, Mat4, // mat
|
||||
MatDouble2, MatDouble3, MatDouble4, // dmat
|
||||
};
|
||||
@@ -39,21 +39,22 @@ public:
|
||||
uint32_t getTypeSize() const;
|
||||
uint32_t getTypeCount() const;
|
||||
uint32_t getTypeGL() const;
|
||||
static uint32_t getTypeSize(const BufferElementType type);
|
||||
static uint32_t getTypeCount(const BufferElementType type);
|
||||
static uint32_t getTypeGL(const BufferElementType type);
|
||||
static uint32_t getTypeSize(BufferElementType type);
|
||||
static uint32_t getTypeCount(BufferElementType type);
|
||||
static uint32_t getTypeGL(BufferElementType type);
|
||||
static uint32_t getGLTypeSize(uint32_t type);
|
||||
|
||||
BufferElementType getType() const { return m_type; }
|
||||
std::string getName() const { return m_name; }
|
||||
uint32_t getSize() const { return m_size; }
|
||||
uint32_t getOffset() const { return m_offset; }
|
||||
bool getNormalized() const { return m_normalized; }
|
||||
BufferElementType type() const { return m_type; }
|
||||
std::string name() const { return m_name; }
|
||||
uint32_t size() const { return m_size; }
|
||||
uint32_t offset() const { return m_offset; }
|
||||
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 setSize(const uint32_t& size) { m_size = size; }
|
||||
void setOffset(const uint32_t& offset) { m_offset = offset; }
|
||||
void setNormalized(const bool& normalized) { m_normalized = normalized; }
|
||||
void setSize(uint32_t size) { m_size = size; }
|
||||
void setOffset(uint32_t offset) { m_offset = offset; }
|
||||
void setNormalized(bool normalized) { m_normalized = normalized; }
|
||||
|
||||
private:
|
||||
BufferElementType m_type;
|
||||
@@ -72,8 +73,8 @@ public:
|
||||
BufferLayout(const std::initializer_list<BufferElement>& elements);
|
||||
~BufferLayout() = default;
|
||||
|
||||
const std::vector<BufferElement>& getElements() const { return m_elements; }
|
||||
uint32_t getStride() const { return m_stride; }
|
||||
const std::vector<BufferElement>& elements() const { return m_elements; }
|
||||
uint32_t stride() const { return m_stride; }
|
||||
|
||||
// Iterators
|
||||
std::vector<BufferElement>::iterator begin() { return m_elements.begin(); }
|
||||
@@ -103,9 +104,9 @@ public:
|
||||
|
||||
void uploadData(const void* data, uint32_t size);
|
||||
|
||||
const BufferLayout& getLayout() const { return m_layout; }
|
||||
const BufferLayout& layout() const { return m_layout; }
|
||||
|
||||
inline void setLayout(const BufferLayout& layout) { m_layout = layout; }
|
||||
void setLayout(const BufferLayout& layout) { m_layout = layout; }
|
||||
|
||||
private:
|
||||
uint32_t m_id { 0 };
|
||||
@@ -125,7 +126,7 @@ public:
|
||||
|
||||
void uploadData(const void* data, uint32_t size);
|
||||
|
||||
uint32_t getCount() const { return m_count; }
|
||||
uint32_t count() const { return m_count; }
|
||||
|
||||
private:
|
||||
uint32_t m_id { 0 };
|
||||
@@ -147,7 +148,7 @@ public:
|
||||
void setIndexBuffer(std::shared_ptr<IndexBuffer> indexBuffer);
|
||||
|
||||
std::shared_ptr<VertexBuffer> at(size_t i) const { return m_vertexBuffers.at(i); }
|
||||
std::shared_ptr<IndexBuffer> getIndexBuffer() const { return m_indexBuffer; }
|
||||
std::shared_ptr<IndexBuffer> indexBuffer() const { return m_indexBuffer; }
|
||||
|
||||
private:
|
||||
uint32_t m_id { 0 };
|
||||
|
||||
@@ -22,11 +22,6 @@ std::shared_ptr<Framebuffer> Framebuffer::create(const Properties& properties)
|
||||
|
||||
auto result = std::shared_ptr<Framebuffer>(new Framebuffer(properties));
|
||||
|
||||
if (!properties.renderToScreen) {
|
||||
result->m_id = UINT_MAX;
|
||||
glGenFramebuffers(1, &result->m_id);
|
||||
}
|
||||
|
||||
result->createTextures();
|
||||
|
||||
return result;
|
||||
@@ -41,6 +36,14 @@ Framebuffer::~Framebuffer()
|
||||
glDeleteFramebuffers(1, &m_id);
|
||||
}
|
||||
|
||||
void Framebuffer::copyBuffer(std::shared_ptr<Framebuffer> from, std::shared_ptr<Framebuffer> to, uint32_t bits, uint32_t filter)
|
||||
{
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, from->m_id);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); // write to default framebuffer
|
||||
glBlitFramebuffer(0, 0, from->m_width, from->m_height, 0, 0, to->m_width, to->m_height, bits, filter);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
void Framebuffer::bind() const
|
||||
@@ -91,22 +94,47 @@ void Framebuffer::createTextures()
|
||||
bind();
|
||||
|
||||
auto it = m_attachments.begin();
|
||||
uint8_t color_attachment = 0;
|
||||
m_colorAttachmentCount = 0;
|
||||
|
||||
size_t size = m_attachments.size();
|
||||
m_textures.resize(size);
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
TypeProperties type = *(it + i);
|
||||
|
||||
if (type.type == Type::Color) {
|
||||
if (type.type == Type::RGB8) {
|
||||
// Set color attachment 0 out of 32
|
||||
m_textures[i] = (TextureFramebuffer::create(
|
||||
"", m_width, m_height, GL_RGB, GL_RGB));
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + color_attachment, GL_TEXTURE_2D, m_textures[i]->id(), 0);
|
||||
m_textures[i] = TextureFramebuffer::create("", m_width, m_height, GL_RGB8, GL_RGB);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + m_colorAttachmentCount, GL_TEXTURE_2D, m_textures[i]->id(), 0);
|
||||
m_colorAttachmentCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type.type == Type::RGBA8) { // Color
|
||||
// Set color attachment 0 out of 32
|
||||
m_textures[i] = TextureFramebuffer::create("", m_width, m_height, GL_RGBA8, GL_RGBA);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + m_colorAttachmentCount, GL_TEXTURE_2D, m_textures[i]->id(), 0);
|
||||
m_colorAttachmentCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type.type == Type::RGBA16F) {
|
||||
// Set color attachment 0 out of 32
|
||||
m_textures[i] = TextureFramebuffer::create("", m_width, m_height, GL_RGBA16F, GL_RGBA, GL_FLOAT);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + m_colorAttachmentCount, GL_TEXTURE_2D, m_textures[i]->id(), 0);
|
||||
m_colorAttachmentCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type.type == Type::RGBA32F) {
|
||||
// Set color attachment 0 out of 32
|
||||
m_textures[i] = TextureFramebuffer::create("", m_width, m_height, GL_RGBA32F, GL_RGBA, GL_FLOAT);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + m_colorAttachmentCount, GL_TEXTURE_2D, m_textures[i]->id(), 0);
|
||||
m_colorAttachmentCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// This combined texture is required for older GPUs
|
||||
if (type.type == Type::Depth24Stencil8) {
|
||||
if (type.type == Type::Depth24Stencil8) { // Depth
|
||||
m_textures[i] = (TextureFramebuffer::create(
|
||||
"", m_width, m_height, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8));
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_textures[i]->id(), 0);
|
||||
@@ -122,7 +150,7 @@ void Framebuffer::createTextures()
|
||||
}
|
||||
}
|
||||
|
||||
VERIFY(color_attachment <= 32, "maximum color attachments was exceeded: {}/32", color_attachment);
|
||||
VERIFY(m_colorAttachmentCount <= 32, "maximum color attachments was exceeded: {}/32", m_colorAttachmentCount);
|
||||
check();
|
||||
|
||||
unbind();
|
||||
|
||||
@@ -24,11 +24,14 @@ public:
|
||||
None = 0,
|
||||
|
||||
// Color
|
||||
RGBA8 = 1,
|
||||
RGB8 = 1,
|
||||
RGBA8 = 2,
|
||||
RGBA16F = 3,
|
||||
RGBA32F = 4,
|
||||
|
||||
// Depth/stencil
|
||||
Depth32F = 2,
|
||||
Depth24Stencil8 = 3,
|
||||
Depth24Stencil8 = 5,
|
||||
Depth32F = 6,
|
||||
|
||||
// Defaults
|
||||
Color = RGBA8,
|
||||
@@ -59,12 +62,14 @@ public:
|
||||
|
||||
// Factory function
|
||||
static std::shared_ptr<Framebuffer> create(const Properties& properties);
|
||||
static void copyBuffer(std::shared_ptr<Framebuffer> from, std::shared_ptr<Framebuffer> to, uint32_t bits, uint32_t filter);
|
||||
|
||||
void bind() const;
|
||||
void unbind() const;
|
||||
bool check() const;
|
||||
void resize(uint32_t width, uint32_t height);
|
||||
|
||||
uint8_t colorAttachmentCount() const { return m_colorAttachmentCount; }
|
||||
uint32_t id() const { return m_id; }
|
||||
uint32_t width() const { return m_width; }
|
||||
uint32_t height() const { return m_height; }
|
||||
@@ -87,6 +92,7 @@ private:
|
||||
|
||||
private:
|
||||
bool m_renderToScreen { false };
|
||||
uint8_t m_colorAttachmentCount { 1 };
|
||||
uint32_t m_id { 0 };
|
||||
uint32_t m_width { 0 };
|
||||
uint32_t m_height { 0 };
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <memory> // std::shared_ptr
|
||||
#include <cstdint> // int32_t, uint32_t
|
||||
#include <memory> // std::shared_ptr
|
||||
|
||||
#include "glad/glad.h"
|
||||
#include "ruc/format/log.h"
|
||||
#include "ruc/meta/assert.h"
|
||||
|
||||
#include "inferno/render/buffer.h"
|
||||
#include "inferno/render/render-command.h"
|
||||
@@ -42,7 +44,7 @@ void RenderCommand::clearColor(const glm::vec4& color)
|
||||
|
||||
void RenderCommand::drawIndexed(std::shared_ptr<VertexArray> vertexArray, uint32_t indexCount)
|
||||
{
|
||||
uint32_t count = indexCount ? indexCount : vertexArray->getIndexBuffer()->getCount();
|
||||
uint32_t count = indexCount ? indexCount : vertexArray->indexBuffer()->count();
|
||||
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, nullptr);
|
||||
}
|
||||
|
||||
@@ -57,6 +59,26 @@ void RenderCommand::setDepthTest(bool enabled)
|
||||
enabled ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
||||
void RenderCommand::setColorAttachmentCount(uint32_t count)
|
||||
{
|
||||
static constexpr uint32_t colorAttachments[] = {
|
||||
GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2,
|
||||
GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5,
|
||||
GL_COLOR_ATTACHMENT6, GL_COLOR_ATTACHMENT7, GL_COLOR_ATTACHMENT8,
|
||||
GL_COLOR_ATTACHMENT9, GL_COLOR_ATTACHMENT10, GL_COLOR_ATTACHMENT11,
|
||||
GL_COLOR_ATTACHMENT12, GL_COLOR_ATTACHMENT13, GL_COLOR_ATTACHMENT14,
|
||||
GL_COLOR_ATTACHMENT15, GL_COLOR_ATTACHMENT16, GL_COLOR_ATTACHMENT17,
|
||||
GL_COLOR_ATTACHMENT18, GL_COLOR_ATTACHMENT19, GL_COLOR_ATTACHMENT20,
|
||||
GL_COLOR_ATTACHMENT21, GL_COLOR_ATTACHMENT22, GL_COLOR_ATTACHMENT23,
|
||||
GL_COLOR_ATTACHMENT24, GL_COLOR_ATTACHMENT25, GL_COLOR_ATTACHMENT26,
|
||||
GL_COLOR_ATTACHMENT27, GL_COLOR_ATTACHMENT28, GL_COLOR_ATTACHMENT29,
|
||||
GL_COLOR_ATTACHMENT30, GL_COLOR_ATTACHMENT31
|
||||
};
|
||||
static constexpr uint32_t maxCount = sizeof(colorAttachments) / sizeof(colorAttachments[0]);
|
||||
VERIFY(count > 0 && count <= maxCount, "incorrect colorbuffer count: {}/{}", count, maxCount);
|
||||
glDrawBuffers(static_cast<int32_t>(count), colorAttachments); // Multiple Render Targets (MRT)
|
||||
}
|
||||
|
||||
bool RenderCommand::depthTest()
|
||||
{
|
||||
unsigned char depthTest = GL_FALSE;
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory> // std::shadred_ptr
|
||||
#include <cstdint> // int32_t, uint32_t
|
||||
#include <memory> // std::shadred_ptr
|
||||
|
||||
#include "glm/ext/vector_float4.hpp" // glm::vec4
|
||||
|
||||
@@ -25,6 +26,7 @@ public:
|
||||
|
||||
static void setViewport(int32_t x, int32_t y, uint32_t width, uint32_t height);
|
||||
static void setDepthTest(bool enabled);
|
||||
static void setColorAttachmentCount(uint32_t count);
|
||||
|
||||
static bool depthTest();
|
||||
static int32_t textureUnitAmount();
|
||||
|
||||
+127
-46
@@ -8,6 +8,7 @@
|
||||
#include <span>
|
||||
|
||||
#include "glad/glad.h"
|
||||
#include "glm/ext/vector_float4.hpp" // glm::vec4
|
||||
#include "ruc/format/log.h"
|
||||
|
||||
#include "inferno/asset/asset-manager.h"
|
||||
@@ -33,9 +34,6 @@ void Renderer<T>::endScene()
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
template<typename T>
|
||||
uint32_t Renderer<T>::m_maxSupportedTextureSlots = 0;
|
||||
|
||||
template<typename T>
|
||||
void Renderer<T>::initialize()
|
||||
{
|
||||
@@ -67,7 +65,6 @@ void Renderer<T>::initialize()
|
||||
template<typename T>
|
||||
void Renderer<T>::destroy()
|
||||
{
|
||||
delete[] m_vertexBufferBase;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@@ -163,13 +160,14 @@ void Renderer<T>::flush()
|
||||
uploadElementBuffer();
|
||||
|
||||
// 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();
|
||||
|
||||
// Render
|
||||
bool depthTest = RenderCommand::depthTest();
|
||||
RenderCommand::setDepthTest(m_enableDepthBuffer);
|
||||
RenderCommand::setColorAttachmentCount(m_colorAttachmentCount);
|
||||
RenderCommand::drawIndexed(m_vertexArray, m_elementIndex);
|
||||
RenderCommand::setDepthTest(depthTest);
|
||||
|
||||
@@ -181,7 +179,7 @@ void Renderer<T>::startBatch()
|
||||
{
|
||||
m_vertexIndex = 0;
|
||||
m_elementIndex = 0;
|
||||
m_vertexBufferPtr = m_vertexBufferBase;
|
||||
m_vertexBufferPtr = m_vertexBufferBase.get();
|
||||
|
||||
m_textureSlotIndex = 1;
|
||||
}
|
||||
@@ -196,6 +194,15 @@ void Renderer<T>::nextBatch()
|
||||
// -----------------------------------------
|
||||
|
||||
Renderer2D::Renderer2D(s)
|
||||
{
|
||||
Renderer2D::initialize();
|
||||
}
|
||||
|
||||
Renderer2D::~Renderer2D()
|
||||
{
|
||||
}
|
||||
|
||||
void Renderer2D::initialize()
|
||||
{
|
||||
Renderer::initialize();
|
||||
|
||||
@@ -203,8 +210,8 @@ Renderer2D::Renderer2D(s)
|
||||
// CPU
|
||||
|
||||
// Create array for storing quads vertices
|
||||
m_vertexBufferBase = new QuadVertex[maxVertices];
|
||||
m_vertexBufferPtr = m_vertexBufferBase;
|
||||
m_vertexBufferBase = std::make_unique<QuadVertex[]>(maxVertices);
|
||||
m_vertexBufferPtr = m_vertexBufferBase.get();
|
||||
|
||||
// Set default quad vertex positions
|
||||
m_vertexPositions[0] = { -1.0f, -1.0f, 0.0f, 1.0f };
|
||||
@@ -215,26 +222,21 @@ Renderer2D::Renderer2D(s)
|
||||
// ---------------------------------
|
||||
// GPU
|
||||
|
||||
m_enableDepthBuffer = false;
|
||||
|
||||
// Create vertex buffer
|
||||
auto vertexBuffer = std::make_shared<VertexBuffer>(sizeof(QuadVertex) * maxVertices);
|
||||
vertexBuffer->setLayout({
|
||||
{ BufferElementType::Vec3, "a_position" },
|
||||
{ BufferElementType::Vec4, "a_color" },
|
||||
{ BufferElementType::Vec2, "a_textureCoordinates" },
|
||||
{ BufferElementType::Float, "a_textureIndex" },
|
||||
{ BufferElementType::Uint, "a_textureIndex" },
|
||||
});
|
||||
m_vertexArray->addVertexBuffer(vertexBuffer);
|
||||
|
||||
ruc::info("Renderer2D initialized");
|
||||
}
|
||||
|
||||
void Renderer2D::beginScene(glm::mat4 cameraProjection, glm::mat4 cameraView)
|
||||
{
|
||||
m_shader->bind();
|
||||
m_shader->setFloat("u_projectionView", cameraProjection * cameraView);
|
||||
m_shader->unbind();
|
||||
}
|
||||
|
||||
void Renderer2D::drawQuad(const TransformComponent& transform, glm::vec4 color)
|
||||
{
|
||||
drawQuad(transform, color, nullptr);
|
||||
@@ -271,7 +273,7 @@ void Renderer2D::drawQuad(const TransformComponent& transform, glm::mat4 color,
|
||||
m_vertexBufferPtr->position = transform.transform * m_vertexPositions[i];
|
||||
m_vertexBufferPtr->color = color[i];
|
||||
m_vertexBufferPtr->textureCoordinates = textureCoordinates[i];
|
||||
m_vertexBufferPtr->textureIndex = static_cast<float>(textureUnitIndex);
|
||||
m_vertexBufferPtr->textureIndex = textureUnitIndex;
|
||||
m_vertexBufferPtr++;
|
||||
}
|
||||
|
||||
@@ -281,12 +283,21 @@ void Renderer2D::drawQuad(const TransformComponent& transform, glm::mat4 color,
|
||||
|
||||
void Renderer2D::loadShader()
|
||||
{
|
||||
m_shader = AssetManager::the().load<Shader>("assets/glsl/batch-quad");
|
||||
m_shader = AssetManager::the().load<Shader>("assets/glsl/batch-2d");
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
RendererCubemap::RendererCubemap(s)
|
||||
{
|
||||
RendererCubemap::initialize();
|
||||
}
|
||||
|
||||
RendererCubemap::~RendererCubemap()
|
||||
{
|
||||
}
|
||||
|
||||
void RendererCubemap::initialize()
|
||||
{
|
||||
Renderer::initialize();
|
||||
|
||||
@@ -294,8 +305,8 @@ RendererCubemap::RendererCubemap(s)
|
||||
// CPU
|
||||
|
||||
// Create array for storing quads vertices
|
||||
m_vertexBufferBase = new CubemapVertex[maxVertices];
|
||||
m_vertexBufferPtr = m_vertexBufferBase;
|
||||
m_vertexBufferBase = std::make_unique<CubemapVertex[]>(maxVertices);
|
||||
m_vertexBufferPtr = m_vertexBufferBase.get();
|
||||
|
||||
// Set default cubemap vertex positions
|
||||
|
||||
@@ -345,7 +356,7 @@ RendererCubemap::RendererCubemap(s)
|
||||
vertexBuffer->setLayout({
|
||||
{ BufferElementType::Vec3, "a_position" },
|
||||
{ BufferElementType::Vec4, "a_color" },
|
||||
{ BufferElementType::Float, "a_textureIndex" },
|
||||
{ BufferElementType::Uint, "a_textureIndex" },
|
||||
});
|
||||
m_vertexArray->addVertexBuffer(vertexBuffer);
|
||||
|
||||
@@ -386,7 +397,7 @@ void RendererCubemap::drawCubemap(const TransformComponent& transform, glm::mat4
|
||||
for (uint32_t i = 0; i < vertexPerQuad * quadPerCube; i++) {
|
||||
m_vertexBufferPtr->position = transform.transform * m_vertexPositions[i];
|
||||
m_vertexBufferPtr->color = color[i % 4];
|
||||
m_vertexBufferPtr->textureIndex = static_cast<float>(textureUnitIndex);
|
||||
m_vertexBufferPtr->textureIndex = textureUnitIndex;
|
||||
m_vertexBufferPtr++;
|
||||
}
|
||||
|
||||
@@ -409,8 +420,8 @@ RendererFont::RendererFont(s)
|
||||
// CPU
|
||||
|
||||
// Create array for storing quads vertices
|
||||
m_vertexBufferBase = new SymbolVertex[maxVertices];
|
||||
m_vertexBufferPtr = m_vertexBufferBase;
|
||||
m_vertexBufferBase = std::make_unique<SymbolVertex[]>(maxVertices);
|
||||
m_vertexBufferPtr = m_vertexBufferBase.get();
|
||||
|
||||
// ---------------------------------
|
||||
// GPU
|
||||
@@ -423,7 +434,7 @@ RendererFont::RendererFont(s)
|
||||
{ BufferElementType::Vec3, "a_position" },
|
||||
{ BufferElementType::Vec4, "a_color" },
|
||||
{ BufferElementType::Vec2, "a_textureCoordinates" },
|
||||
{ BufferElementType::Float, "a_textureIndex" },
|
||||
{ BufferElementType::Uint, "a_textureIndex" },
|
||||
{ BufferElementType::Float, "a_width" },
|
||||
{ BufferElementType::Float, "a_edge" },
|
||||
{ BufferElementType::Float, "a_borderWidth" },
|
||||
@@ -436,6 +447,10 @@ RendererFont::RendererFont(s)
|
||||
ruc::info("RendererFont initialized");
|
||||
}
|
||||
|
||||
RendererFont::~RendererFont()
|
||||
{
|
||||
}
|
||||
|
||||
void RendererFont::drawSymbol(std::array<SymbolVertex, vertexPerQuad>& symbolQuad, std::shared_ptr<Texture> texture)
|
||||
{
|
||||
// Create a new batch if the quad limit has been reached
|
||||
@@ -450,7 +465,7 @@ void RendererFont::drawSymbol(std::array<SymbolVertex, vertexPerQuad>& symbolQua
|
||||
m_vertexBufferPtr->quad.position = symbolQuad[i].quad.position;
|
||||
m_vertexBufferPtr->quad.color = symbolQuad[i].quad.color;
|
||||
m_vertexBufferPtr->quad.textureCoordinates = symbolQuad[i].quad.textureCoordinates;
|
||||
m_vertexBufferPtr->quad.textureIndex = static_cast<float>(textureUnitIndex);
|
||||
m_vertexBufferPtr->quad.textureIndex = textureUnitIndex;
|
||||
|
||||
m_vertexBufferPtr->width = symbolQuad[i].width;
|
||||
m_vertexBufferPtr->edge = symbolQuad[i].edge;
|
||||
@@ -481,33 +496,39 @@ Renderer3D::Renderer3D(s)
|
||||
// CPU
|
||||
|
||||
// Create array for storing quads vertices
|
||||
m_vertexBufferBase = new Vertex[maxVertices];
|
||||
m_vertexBufferPtr = m_vertexBufferBase;
|
||||
m_vertexBufferBase = std::make_unique<Vertex[]>(maxVertices);
|
||||
m_vertexBufferPtr = m_vertexBufferBase.get();
|
||||
|
||||
// ---------------------------------
|
||||
// GPU
|
||||
|
||||
m_enableDepthBuffer = true;
|
||||
m_colorAttachmentCount = 3;
|
||||
|
||||
// Create vertex buffer
|
||||
auto vertexBuffer = std::make_shared<VertexBuffer>(sizeof(Vertex) * maxVertices);
|
||||
vertexBuffer->setLayout({
|
||||
{ BufferElementType::Vec3, "a_position" },
|
||||
{ BufferElementType::Vec3, "a_normal" },
|
||||
{ BufferElementType::Vec4, "a_color" },
|
||||
{ BufferElementType::Vec2, "a_textureCoordinates" },
|
||||
{ BufferElementType::Float, "a_textureIndex" },
|
||||
{ BufferElementType::Uint, "a_textureIndex" },
|
||||
});
|
||||
m_vertexArray->addVertexBuffer(vertexBuffer);
|
||||
|
||||
ruc::info("Renderer3D initialized");
|
||||
}
|
||||
|
||||
void Renderer3D::drawModel(std::span<const Vertex> vertices, std::span<const uint32_t> elements, const TransformComponent& transform, std::shared_ptr<Texture> texture)
|
||||
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)
|
||||
{
|
||||
// ruc::error("drawModel");
|
||||
|
||||
VERIFY(vertices.size() <= maxVertices, "model vertices too big for buffer");
|
||||
VERIFY(elements.size() <= maxElements, "model elements too big for buffer");
|
||||
VERIFY(vertices.size() <= maxVertices, "model vertices too big for buffer, {}/{}", vertices.size(), maxVertices);
|
||||
VERIFY(elements.size() <= maxElements, "model elements too big for buffer, {}/{}", elements.size(), maxElements);
|
||||
|
||||
// Create a new batch if the quad limit has been reached
|
||||
if (m_vertexIndex + vertices.size() > maxVertices || m_elementIndex + elements.size() > maxElements) {
|
||||
@@ -517,11 +538,13 @@ void Renderer3D::drawModel(std::span<const Vertex> vertices, std::span<const uin
|
||||
uint32_t textureUnitIndex = addTextureUnit(texture);
|
||||
|
||||
// Add the vertices
|
||||
glm::mat3 normalMatrix = glm::mat3(glm::transpose(glm::inverse(transform.transform)));
|
||||
for (const auto& vertex : vertices) {
|
||||
m_vertexBufferPtr->position = transform.transform * glm::vec4(vertex.position, 1.0f);
|
||||
m_vertexBufferPtr->normal = vertex.normal;
|
||||
m_vertexBufferPtr->normal = normalMatrix * vertex.normal; // take non-uniform scaling into consideration
|
||||
m_vertexBufferPtr->color = color;
|
||||
m_vertexBufferPtr->textureCoordinates = vertex.textureCoordinates;
|
||||
m_vertexBufferPtr->textureIndex = static_cast<float>(textureUnitIndex);
|
||||
m_vertexBufferPtr->textureIndex = textureUnitIndex;
|
||||
m_vertexBufferPtr++;
|
||||
}
|
||||
|
||||
@@ -536,33 +559,26 @@ void Renderer3D::drawModel(std::span<const Vertex> vertices, std::span<const uin
|
||||
m_elementIndex += elements.size();
|
||||
}
|
||||
|
||||
void Renderer3D::beginScene(glm::mat4 cameraProjection, glm::mat4 cameraView)
|
||||
{
|
||||
m_shader->bind();
|
||||
m_shader->setFloat("u_projectionView", cameraProjection * cameraView);
|
||||
m_shader->unbind();
|
||||
}
|
||||
|
||||
void Renderer3D::createElementBuffer()
|
||||
{
|
||||
// ---------------------------------
|
||||
// CPU
|
||||
|
||||
// Create array for storing quads vertices
|
||||
m_elementBufferBase = new uint32_t[maxElements];
|
||||
m_elementBufferPtr = m_elementBufferBase;
|
||||
m_elementBufferBase = std::make_unique<uint32_t[]>(maxElements);
|
||||
m_elementBufferPtr = m_elementBufferBase.get();
|
||||
|
||||
// ---------------------------------
|
||||
// GPU
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
void Renderer3D::uploadElementBuffer()
|
||||
{
|
||||
m_vertexArray->getIndexBuffer()->uploadData(m_elementBufferBase, m_elementIndex * sizeof(uint32_t));
|
||||
m_vertexArray->indexBuffer()->uploadData(m_elementBufferBase.get(), m_elementIndex * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
void Renderer3D::loadShader()
|
||||
@@ -573,7 +589,72 @@ void Renderer3D::loadShader()
|
||||
void Renderer3D::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)
|
||||
{
|
||||
nextBatch();
|
||||
|
||||
constexpr glm::vec2 textureCoordinates[] = {
|
||||
{ 0.0f, 0.0f },
|
||||
{ 1.0f, 0.0f },
|
||||
{ 1.0f, 1.0f },
|
||||
{ 0.0f, 1.0f }
|
||||
};
|
||||
|
||||
uint32_t textureUnitIndex = addTextureUnit(albedo);
|
||||
addTextureUnit(position);
|
||||
addTextureUnit(normal);
|
||||
|
||||
// Add the quads 4 vertices
|
||||
for (uint32_t i = 0; i < vertexPerQuad; i++) {
|
||||
m_vertexBufferPtr->position = transform.transform * m_vertexPositions[i];
|
||||
m_vertexBufferPtr->textureCoordinates = textureCoordinates[i];
|
||||
m_vertexBufferPtr->textureIndex = textureUnitIndex;
|
||||
m_vertexBufferPtr++;
|
||||
}
|
||||
|
||||
m_vertexIndex += vertexPerQuad;
|
||||
m_elementIndex += elementPerQuad;
|
||||
}
|
||||
|
||||
void RendererPostProcess::loadShader()
|
||||
{
|
||||
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()
|
||||
{
|
||||
m_shader = AssetManager::the().load<Shader>("assets/glsl/lightsource");
|
||||
}
|
||||
|
||||
} // namespace Inferno
|
||||
|
||||
@@ -16,24 +16,25 @@
|
||||
#include "glm/ext/vector_float4.hpp" // glm::vec4
|
||||
#include "ruc/singleton.h"
|
||||
|
||||
#include "inferno/asset/shader.h"
|
||||
|
||||
namespace Inferno {
|
||||
|
||||
class Shader;
|
||||
class Texture;
|
||||
class TransformComponent;
|
||||
class VertexArray;
|
||||
|
||||
struct QuadVertex {
|
||||
glm::vec3 position { 0.0f, 0.0f, 0.0f };
|
||||
glm::vec4 color { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
glm::vec2 textureCoordinates { 0.0f, 0.0f };
|
||||
float textureIndex = 0;
|
||||
glm::vec3 position { 0.0f };
|
||||
glm::vec4 color { 1.0f };
|
||||
glm::vec2 textureCoordinates { 0.0f };
|
||||
uint32_t textureIndex { 0 };
|
||||
};
|
||||
|
||||
struct CubemapVertex {
|
||||
glm::vec3 position { 0.0f, 0.0f, 0.0f };
|
||||
glm::vec4 color { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
float textureIndex = 0;
|
||||
glm::vec3 position { 0.0f };
|
||||
glm::vec4 color { 1.0f };
|
||||
uint32_t textureIndex { 0 };
|
||||
};
|
||||
|
||||
struct SymbolVertex {
|
||||
@@ -45,16 +46,17 @@ struct SymbolVertex {
|
||||
// Outline
|
||||
float borderWidth = 0.7f;
|
||||
float borderEdge = 0.1f;
|
||||
glm::vec4 borderColor { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
glm::vec4 borderColor { 1.0f };
|
||||
// Dropshadow
|
||||
float offset = 0.0f;
|
||||
};
|
||||
|
||||
struct Vertex {
|
||||
glm::vec3 position { 0.0f, 0.0f, 0.0f };
|
||||
glm::vec3 normal { 1.0f, 1.0f, 1.0f };
|
||||
glm::vec2 textureCoordinates { 0.0f, 0.0f };
|
||||
float textureIndex = 0;
|
||||
glm::vec3 position { 0.0f };
|
||||
glm::vec3 normal { 1.0f };
|
||||
glm::vec4 color { 1.0f };
|
||||
glm::vec2 textureCoordinates { 0.0f };
|
||||
uint32_t textureIndex { 0 };
|
||||
};
|
||||
|
||||
// -------------------------------------
|
||||
@@ -78,6 +80,8 @@ public:
|
||||
|
||||
void setEnableDepthBuffer(bool state) { m_enableDepthBuffer = state; }
|
||||
|
||||
uint32_t shaderID() const { return m_shader->id(); }
|
||||
|
||||
protected:
|
||||
Renderer() {}
|
||||
virtual ~Renderer() { destroy(); };
|
||||
@@ -101,16 +105,17 @@ protected:
|
||||
// CPU quad vertices
|
||||
uint32_t m_vertexIndex { 0 };
|
||||
uint32_t m_elementIndex { 0 };
|
||||
T* m_vertexBufferBase { nullptr };
|
||||
std::unique_ptr<T[]> m_vertexBufferBase { nullptr };
|
||||
T* m_vertexBufferPtr { nullptr };
|
||||
|
||||
// Texture units
|
||||
static uint32_t m_maxSupportedTextureSlots;
|
||||
static inline uint32_t m_maxSupportedTextureSlots { 0 };
|
||||
uint32_t m_textureSlotIndex { 1 };
|
||||
std::array<std::shared_ptr<Texture>, maxTextureSlots> m_textureSlots;
|
||||
|
||||
// GPU objects
|
||||
bool m_enableDepthBuffer { true };
|
||||
uint32_t m_colorAttachmentCount { 1 };
|
||||
std::shared_ptr<Shader> m_shader;
|
||||
std::shared_ptr<VertexArray> m_vertexArray;
|
||||
};
|
||||
@@ -123,31 +128,34 @@ protected:
|
||||
|
||||
// -------------------------------------
|
||||
|
||||
class Renderer2D final
|
||||
class Renderer2D
|
||||
: public Renderer<QuadVertex>
|
||||
, public ruc::Singleton<Renderer2D> {
|
||||
public:
|
||||
Renderer2D(s);
|
||||
virtual ~Renderer2D() = default;
|
||||
virtual ~Renderer2D();
|
||||
|
||||
using Singleton<Renderer2D>::destroy;
|
||||
|
||||
virtual void beginScene(glm::mat4 cameraProjection, glm::mat4 cameraView) override;
|
||||
|
||||
void drawQuad(const TransformComponent& transform, glm::vec4 color);
|
||||
void drawQuad(const TransformComponent& transform, glm::mat4 color);
|
||||
void drawQuad(const TransformComponent& transform, glm::vec4 color, std::shared_ptr<Texture> texture);
|
||||
void drawQuad(const TransformComponent& transform, glm::mat4 color, std::shared_ptr<Texture> texture);
|
||||
|
||||
private:
|
||||
void loadShader() override;
|
||||
protected:
|
||||
Renderer2D() {} // Needed for derived classes
|
||||
|
||||
void initialize();
|
||||
|
||||
// Default quad vertex positions
|
||||
glm::vec4 m_vertexPositions[vertexPerQuad];
|
||||
|
||||
private:
|
||||
virtual void loadShader() override;
|
||||
};
|
||||
// -------------------------------------
|
||||
|
||||
class RendererCubemap final
|
||||
class RendererCubemap
|
||||
: public Renderer<CubemapVertex>
|
||||
, public ruc::Singleton<RendererCubemap> {
|
||||
public:
|
||||
@@ -155,7 +163,7 @@ public:
|
||||
|
||||
public:
|
||||
RendererCubemap(s);
|
||||
virtual ~RendererCubemap() = default;
|
||||
virtual ~RendererCubemap();
|
||||
|
||||
using Singleton<RendererCubemap>::destroy;
|
||||
|
||||
@@ -164,8 +172,13 @@ public:
|
||||
void drawCubemap(const TransformComponent& transform, glm::vec4 color, std::shared_ptr<Texture> texture);
|
||||
void drawCubemap(const TransformComponent& transform, glm::mat4 color, std::shared_ptr<Texture> texture);
|
||||
|
||||
protected:
|
||||
RendererCubemap() {} // Needed for derived classes
|
||||
|
||||
void initialize();
|
||||
|
||||
private:
|
||||
void loadShader() override;
|
||||
virtual void loadShader() override;
|
||||
|
||||
// Default cubemap vertex positions
|
||||
glm::vec4 m_vertexPositions[vertexPerQuad * quadPerCube];
|
||||
@@ -178,7 +191,7 @@ class RendererFont final
|
||||
, public ruc::Singleton<RendererFont> {
|
||||
public:
|
||||
RendererFont(s);
|
||||
virtual ~RendererFont() = default;
|
||||
virtual ~RendererFont();
|
||||
|
||||
using Singleton<RendererFont>::destroy;
|
||||
|
||||
@@ -195,13 +208,11 @@ class Renderer3D final
|
||||
, public ruc::Singleton<Renderer3D> {
|
||||
public:
|
||||
Renderer3D(s);
|
||||
virtual ~Renderer3D() = default;
|
||||
virtual ~Renderer3D();
|
||||
|
||||
using Singleton<Renderer3D>::destroy;
|
||||
|
||||
virtual void beginScene(glm::mat4 cameraProjection, glm::mat4 cameraView) override;
|
||||
|
||||
void drawModel(std::span<const Vertex> vertices, std::span<const uint32_t> indices, const TransformComponent& transform, std::shared_ptr<Texture> texture);
|
||||
void drawModel(std::span<const Vertex> vertices, std::span<const uint32_t> indices, const TransformComponent& transform, glm::vec4 color, std::shared_ptr<Texture> texture);
|
||||
|
||||
private:
|
||||
void createElementBuffer() override;
|
||||
@@ -211,8 +222,46 @@ private:
|
||||
|
||||
private:
|
||||
// CPU element vertices
|
||||
uint32_t* m_elementBufferBase { nullptr };
|
||||
std::unique_ptr<uint32_t[]> m_elementBufferBase { nullptr };
|
||||
uint32_t* m_elementBufferPtr { nullptr };
|
||||
};
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
class RendererPostProcess final
|
||||
: public Renderer2D
|
||||
, public ruc::Singleton<RendererPostProcess> {
|
||||
public:
|
||||
using Singleton<RendererPostProcess>::s;
|
||||
using Singleton<RendererPostProcess>::the;
|
||||
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);
|
||||
|
||||
private:
|
||||
virtual void loadShader() override;
|
||||
};
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
class RendererLightCube final
|
||||
: public RendererCubemap
|
||||
, public ruc::Singleton<RendererLightCube> {
|
||||
public:
|
||||
using Singleton<RendererLightCube>::s;
|
||||
using Singleton<RendererLightCube>::the;
|
||||
using Singleton<RendererLightCube>::destroy;
|
||||
|
||||
RendererLightCube(s);
|
||||
virtual ~RendererLightCube();
|
||||
|
||||
void beginScene(glm::mat4, glm::mat4) override {}
|
||||
|
||||
private:
|
||||
virtual void loadShader() override;
|
||||
};
|
||||
|
||||
} // namespace Inferno
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Riyyi
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdint> // int32_t, uint32_t, uint8_t
|
||||
#include <string_view>
|
||||
|
||||
#include "glad/glad.h"
|
||||
#include "glm/ext/matrix_float2x2.hpp" // glm::mat2
|
||||
#include "glm/ext/matrix_float3x3.hpp" // glm::mat3
|
||||
#include "glm/gtc/type_ptr.hpp" // glm::value_ptr
|
||||
#include "ruc/meta/assert.h"
|
||||
|
||||
#include "inferno/render/buffer.h"
|
||||
#include "inferno/render/uniformbuffer.h"
|
||||
|
||||
namespace Inferno {
|
||||
|
||||
Uniformbuffer::Uniformbuffer(s)
|
||||
{
|
||||
// Get maximum uniformbuffer bindings the GPU supports
|
||||
int32_t maxBindingPoints = 0;
|
||||
glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &maxBindingPoints);
|
||||
m_maxBindingPoints = static_cast<uint8_t>(maxBindingPoints);
|
||||
}
|
||||
|
||||
Uniformbuffer::~Uniformbuffer()
|
||||
{
|
||||
for (const auto& [_, block] : m_blocks) {
|
||||
glDeleteBuffers(1, &block.id);
|
||||
}
|
||||
m_blocks.clear();
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
void Uniformbuffer::setLayout(std::string_view blockName, const UniformbufferBlock& block)
|
||||
{
|
||||
VERIFY(block.size && block.bindingPoint && block.uniformLocations.size(),
|
||||
"invalid uniformbuffer block definition: {}", blockName);
|
||||
|
||||
VERIFY(block.bindingPoint < m_maxBindingPoints,
|
||||
"uniformbuffer exceeded binding points: {}/{}", block.bindingPoint, m_maxBindingPoints);
|
||||
|
||||
m_blocks[blockName] = block;
|
||||
}
|
||||
|
||||
void Uniformbuffer::setLayout(std::string_view blockName, uint8_t bindingPoint, const BufferLayout& layout)
|
||||
{
|
||||
VERIFY(bindingPoint < m_maxBindingPoints,
|
||||
"uniformbuffer exceeded binding points: {}/{}", bindingPoint, m_maxBindingPoints);
|
||||
|
||||
if (!exists(blockName)) {
|
||||
m_blocks[blockName] = {};
|
||||
}
|
||||
|
||||
UniformbufferBlock& block = m_blocks[blockName];
|
||||
block.bindingPoint = bindingPoint;
|
||||
block.uniformLocations.clear();
|
||||
|
||||
// Example block layout:
|
||||
// - mat3
|
||||
// - float
|
||||
// - vec2
|
||||
// - vec2
|
||||
// - float
|
||||
|
||||
// Chunks, 4 slots, 4 bytes per slot
|
||||
// [x][x][x][ ] #1
|
||||
// [x][x][x][ ] #2
|
||||
// [x][x][x][ ] #3
|
||||
// [x][ ][x][x] #4
|
||||
// [x][x][x][ ] #5
|
||||
|
||||
size_t chunk = 0;
|
||||
uint8_t offset = 0;
|
||||
|
||||
for (auto it = layout.begin(); it != layout.end(); ++it) {
|
||||
BufferElementType type = it->type();
|
||||
const std::string& name = it->name();
|
||||
|
||||
// Calculate offset
|
||||
switch (type) {
|
||||
// Scalar 1
|
||||
case BufferElementType::Bool:
|
||||
case BufferElementType::Int:
|
||||
case BufferElementType::Uint:
|
||||
case BufferElementType::Float: {
|
||||
// Offset
|
||||
block.uniformLocations[name] = (chunk * 16) + (offset * 4);
|
||||
// Jump
|
||||
offset += 1;
|
||||
break;
|
||||
}
|
||||
// Scalar 2
|
||||
case BufferElementType::Bool2:
|
||||
case BufferElementType::Int2:
|
||||
case BufferElementType::Uint2:
|
||||
case BufferElementType::Vec2: {
|
||||
// Add padding
|
||||
if (offset == 1) {
|
||||
offset++;
|
||||
}
|
||||
if (offset == 3) {
|
||||
offset = 0;
|
||||
chunk++;
|
||||
}
|
||||
// Offset
|
||||
block.uniformLocations[name] = (chunk * 16) + (offset * 4);
|
||||
// Jump
|
||||
offset += 2;
|
||||
break;
|
||||
}
|
||||
// Scalar 3
|
||||
case BufferElementType::Bool3:
|
||||
case BufferElementType::Int3:
|
||||
case BufferElementType::Uint3:
|
||||
case BufferElementType::Vec3: {
|
||||
// Add padding
|
||||
if (offset != 0) {
|
||||
offset = 0;
|
||||
chunk++;
|
||||
}
|
||||
// Offset
|
||||
block.uniformLocations[name] = (chunk * 16) + (offset * 4);
|
||||
// Jump
|
||||
offset += 3;
|
||||
break;
|
||||
}
|
||||
// Scalar 4
|
||||
case BufferElementType::Bool4:
|
||||
case BufferElementType::Int4:
|
||||
case BufferElementType::Uint4:
|
||||
case BufferElementType::Vec4: {
|
||||
// Add padding
|
||||
if (offset != 0) {
|
||||
offset = 0;
|
||||
chunk++;
|
||||
}
|
||||
// Offset
|
||||
block.uniformLocations[name] = (chunk * 16) + (offset * 4);
|
||||
// Jump
|
||||
offset += 4;
|
||||
break;
|
||||
}
|
||||
// Array types
|
||||
case BufferElementType::Mat2:
|
||||
case BufferElementType::Mat3:
|
||||
case BufferElementType::Mat4: {
|
||||
// Add padding
|
||||
if (offset != 0) {
|
||||
offset = 0;
|
||||
chunk++;
|
||||
}
|
||||
// Offset
|
||||
block.uniformLocations[name] = (chunk * 16) + (offset * 4);
|
||||
|
||||
// Additional rows
|
||||
if (type == BufferElementType::Mat2) {
|
||||
chunk += 1;
|
||||
}
|
||||
else if (type == BufferElementType::Mat3) {
|
||||
chunk += 2;
|
||||
}
|
||||
else {
|
||||
chunk += 3;
|
||||
}
|
||||
|
||||
// Jump
|
||||
offset += 4;
|
||||
break;
|
||||
}
|
||||
// TODO: Implement these types
|
||||
case BufferElementType::Double:
|
||||
case BufferElementType::Vec2Double:
|
||||
case BufferElementType::Vec3Double:
|
||||
case BufferElementType::Vec4Double:
|
||||
case BufferElementType::MatDouble2:
|
||||
case BufferElementType::MatDouble3:
|
||||
case BufferElementType::MatDouble4:
|
||||
VERIFY_NOT_REACHED();
|
||||
case BufferElementType::None:
|
||||
VERIFY_NOT_REACHED();
|
||||
};
|
||||
|
||||
// Overflow slots to next chunk
|
||||
if (offset > 3) {
|
||||
offset = 0;
|
||||
chunk++;
|
||||
}
|
||||
}
|
||||
|
||||
// Pad the end of the buffer
|
||||
if (offset != 0) {
|
||||
offset = 0;
|
||||
chunk++;
|
||||
}
|
||||
|
||||
block.size = chunk * 16;
|
||||
}
|
||||
|
||||
void Uniformbuffer::create(std::string_view blockName)
|
||||
{
|
||||
VERIFY(exists(blockName), "uniformbuffer block doesnt exist");
|
||||
|
||||
UniformbufferBlock& block = m_blocks[blockName];
|
||||
|
||||
if (block.id != 0) {
|
||||
glDeleteBuffers(1, &block.id);
|
||||
}
|
||||
|
||||
// Allocate buffer
|
||||
block.id = UINT_MAX;
|
||||
glGenBuffers(1, &block.id);
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, block.id);
|
||||
glBufferData(GL_UNIFORM_BUFFER, block.size, NULL, GL_DYNAMIC_DRAW);
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||
|
||||
// Bind buffer to binding point
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, block.bindingPoint, block.id);
|
||||
}
|
||||
|
||||
void Uniformbuffer::setValue(std::string_view blockName, std::string_view member, bool value)
|
||||
{
|
||||
setValue(blockName, member, static_cast<uint32_t>(value), sizeof(uint32_t));
|
||||
}
|
||||
|
||||
void Uniformbuffer::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 Uniformbuffer::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,114 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Riyyi
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdint> // uint8_t, uint32_t
|
||||
#include <string>
|
||||
#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"
|
||||
|
||||
#include "inferno/render/buffer.h"
|
||||
|
||||
#define CHECK_UNIFORM_SET_CALL(blockName, member) \
|
||||
VERIFY(exists(blockName), "uniformbuffer block doesnt exist: {}", blockName); \
|
||||
const UniformbufferBlock& block = m_blocks[blockName]; \
|
||||
VERIFY(block.uniformLocations.find(member.data()) != block.uniformLocations.end(), \
|
||||
"uniformbuffer member doesnt exist: {}", member);
|
||||
|
||||
namespace Inferno {
|
||||
|
||||
struct UniformbufferBlock {
|
||||
uint32_t id { 0 };
|
||||
uint32_t size { 0 };
|
||||
uint8_t bindingPoint { 0 };
|
||||
std::unordered_map<std::string, uint32_t> uniformLocations {};
|
||||
};
|
||||
|
||||
class Uniformbuffer final : public ruc::Singleton<Uniformbuffer> { // Uniform Buffer Object, UBO
|
||||
public:
|
||||
Uniformbuffer(s);
|
||||
~Uniformbuffer();
|
||||
|
||||
void setLayout(std::string_view blockName, const UniformbufferBlock& block);
|
||||
void setLayout(std::string_view blockName, uint8_t bindingPoint, const BufferLayout& layout);
|
||||
void create(std::string_view blockName);
|
||||
|
||||
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_UNIFORM_SET_CALL(blockName, member);
|
||||
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, block.id);
|
||||
glBufferSubData(GL_UNIFORM_BUFFER, block.uniformLocations.at(member.data()), (size) ? size : sizeof(T), &value);
|
||||
glBindBuffer(GL_UNIFORM_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);
|
||||
|
||||
bool exists(std::string_view blockName) const { return m_blocks.find(blockName) != m_blocks.end(); }
|
||||
|
||||
private:
|
||||
uint8_t m_maxBindingPoints { 0 };
|
||||
std::unordered_map<std::string_view, UniformbufferBlock> m_blocks;
|
||||
};
|
||||
|
||||
} // namespace Inferno
|
||||
|
||||
#if 0
|
||||
|
||||
// -----------------------------------------
|
||||
// Example usage:
|
||||
|
||||
Uniformbuffer::the().setLayout(
|
||||
"ExampleBlock", 0,
|
||||
{
|
||||
{ BufferElementType::Mat3, "a" },
|
||||
{ BufferElementType::Float, "b" },
|
||||
{ BufferElementType::Vec2, "c" },
|
||||
{ BufferElementType::Vec2, "d" },
|
||||
{ BufferElementType::Float, "e" },
|
||||
});
|
||||
Uniformbuffer::the().create("ExampleBlock");
|
||||
|
||||
#endif
|
||||
|
||||
// -----------------------------------------
|
||||
// Memory alignment of uniform blocks using std140
|
||||
//
|
||||
// Main points:
|
||||
// - Memory is organized into chunks.
|
||||
// - A block is at least the size of 1 chunk.
|
||||
// - One chunk has 4 slots, 4 bytes per slot.
|
||||
// - Can't fit? Move to next chunk.
|
||||
//
|
||||
// The rules:
|
||||
// 1. Scalar (bool, int, uint, float) takes up 1 slot, can appear after anything
|
||||
// 2. Vec2 takes up 2 slots, in first or last half of a chunk
|
||||
// 3. Vec3 takes up 3 slots, only at the start of a chunk
|
||||
// 4. Everything else:
|
||||
// - Take up maxumum room
|
||||
// - As often as needed
|
||||
// - Add padding as needed
|
||||
// 5. Mat3 (or any matrix) are treated like arrays
|
||||
// 6. Each member of *any* array gets its own chunk
|
||||
|
||||
// TODO: How do double types work?
|
||||
|
||||
// -----------------------------------------
|
||||
// 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 (WebGL 2: Uniform Buffer Objects)
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <limits> // std::numeric_limits
|
||||
#include <utility> // std::pair
|
||||
|
||||
#include "entt/entity/entity.hpp" // ent::entity
|
||||
#include "entt/entity/fwd.hpp" // ent::entity
|
||||
#include "ruc/file.h"
|
||||
#include "ruc/format/log.h"
|
||||
#include "ruc/json/json.h"
|
||||
@@ -25,6 +25,8 @@
|
||||
#include "inferno/component/tagcomponent.h"
|
||||
#include "inferno/component/textareacomponent.h"
|
||||
#include "inferno/component/transformcomponent.h"
|
||||
#include "inferno/render/renderer.h"
|
||||
#include "inferno/render/uniformbuffer.h"
|
||||
#include "inferno/scene/scene.h"
|
||||
#include "inferno/script/nativescript.h"
|
||||
#include "inferno/system/camerasystem.h"
|
||||
@@ -84,7 +86,6 @@ void Scene::update(float deltaTime)
|
||||
void Scene::render()
|
||||
{
|
||||
RenderSystem::the().render();
|
||||
TextAreaSystem::the().render();
|
||||
}
|
||||
|
||||
void Scene::destroy()
|
||||
|
||||
@@ -53,10 +53,23 @@ std::pair<glm::mat4, glm::mat4> CameraSystem::projectionView()
|
||||
}
|
||||
|
||||
VERIFY_NOT_REACHED();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
glm::vec3 CameraSystem::translate()
|
||||
{
|
||||
auto view = m_registry->view<TransformComponent, CameraComponent>();
|
||||
|
||||
for (auto [entity, transform, camera] : view.each()) {
|
||||
return transform.translate;
|
||||
}
|
||||
|
||||
VERIFY_NOT_REACHED();
|
||||
return {};
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
void CameraSystem::updateOrthographic(TransformComponent& transform, CameraComponent& camera)
|
||||
{
|
||||
// Update camera matrix
|
||||
|
||||
@@ -32,6 +32,7 @@ public:
|
||||
* @brief Return a pair from the camera component: { projection, view }
|
||||
*/
|
||||
std::pair<glm::mat4, glm::mat4> projectionView();
|
||||
glm::vec3 translate();
|
||||
|
||||
void setRegistry(std::shared_ptr<entt::registry> registry) { m_registry = registry; };
|
||||
|
||||
|
||||
@@ -4,41 +4,148 @@
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "glm/ext/matrix_transform.hpp" // glm::translate, glm::rotate, glm::scale, glm::radians
|
||||
#include "inferno/component/model-component.h"
|
||||
#include <cstdint> // int32_t
|
||||
|
||||
#include "glad/glad.h"
|
||||
#include "ruc/format/log.h"
|
||||
|
||||
#include "inferno/component/cubemap-component.h"
|
||||
#include "inferno/component/model-component.h"
|
||||
#include "inferno/component/spritecomponent.h"
|
||||
#include "inferno/component/transformcomponent.h"
|
||||
#include "inferno/render/framebuffer.h"
|
||||
#include "inferno/render/render-command.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/system/camerasystem.h"
|
||||
#include "inferno/system/rendersystem.h"
|
||||
#include "inferno/system/textareasystem.h"
|
||||
|
||||
namespace Inferno {
|
||||
|
||||
RenderSystem::RenderSystem(s)
|
||||
{
|
||||
ruc::info("RenderSystem initialized");
|
||||
}
|
||||
|
||||
RenderSystem::~RenderSystem()
|
||||
{
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
void RenderSystem::initialize(uint32_t width, uint32_t height)
|
||||
{
|
||||
m_framebuffer = Framebuffer::create({
|
||||
.attachments = { Framebuffer::Type::Color, Framebuffer::Type::RGBA16F, Framebuffer::Type::RGBA16F, Framebuffer::Type::Depth },
|
||||
.width = width,
|
||||
.height = height,
|
||||
.clearColor = { 0.0f, 0.0f, 0.0f, 0.0f },
|
||||
.clearBit = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT,
|
||||
});
|
||||
|
||||
m_screenFramebuffer = Framebuffer::create({
|
||||
.renderToScreen = true,
|
||||
.clearColor = { 1.0f, 1.0f, 1.0f, 1.0f },
|
||||
.clearBit = GL_COLOR_BUFFER_BIT,
|
||||
});
|
||||
|
||||
Uniformbuffer::the().setLayout(
|
||||
"Camera", 0,
|
||||
{
|
||||
{ BufferElementType::Mat4, "u_projectionView" },
|
||||
{ BufferElementType::Vec3, "u_position" },
|
||||
});
|
||||
Uniformbuffer::the().create("Camera");
|
||||
|
||||
ShaderStorageBuffer::the().setLayout("DirectionalLights", 0, RendererPostProcess::the().shaderID());
|
||||
ShaderStorageBuffer::the().create("DirectionalLights");
|
||||
|
||||
ruc::info("RenderSystem initialized");
|
||||
}
|
||||
|
||||
void RenderSystem::render()
|
||||
{
|
||||
auto quadView = m_registry->view<TransformComponent, SpriteComponent>();
|
||||
static constexpr TransformComponent transformIdentity;
|
||||
|
||||
for (auto [entity, transform, sprite] : quadView.each()) {
|
||||
Renderer2D::the().drawQuad(transform, sprite.color, sprite.texture);
|
||||
}
|
||||
// ---------------------------------
|
||||
// Deferred rendering to a framebuffer
|
||||
|
||||
auto cubemapView = m_registry->view<TransformComponent, CubemapComponent>();
|
||||
framebufferSetup(m_framebuffer);
|
||||
|
||||
for (auto [entity, transform, cubemap] : cubemapView.each()) {
|
||||
RendererCubemap::the().drawCubemap(transform, cubemap.color, cubemap.texture);
|
||||
}
|
||||
renderGeometry();
|
||||
|
||||
framebufferTeardown(m_framebuffer);
|
||||
|
||||
// ---------------------------------
|
||||
// Forward rendering to the screen
|
||||
|
||||
framebufferSetup(m_screenFramebuffer);
|
||||
|
||||
renderSkybox();
|
||||
|
||||
// Render 3D geometry post-processing
|
||||
RendererPostProcess::the().drawQuad(transformIdentity, m_framebuffer->texture(0), m_framebuffer->texture(1), m_framebuffer->texture(2));
|
||||
RendererPostProcess::the().endScene();
|
||||
|
||||
// Visual representation of light sources
|
||||
Framebuffer::copyBuffer(m_framebuffer, m_screenFramebuffer, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
|
||||
renderLightCubes();
|
||||
|
||||
// Render 2D, UI
|
||||
renderOverlay();
|
||||
|
||||
framebufferTeardown(m_screenFramebuffer);
|
||||
}
|
||||
|
||||
void RenderSystem::resize(int32_t width, int32_t height)
|
||||
{
|
||||
RenderCommand::setViewport(0, 0, width, height);
|
||||
m_framebuffer->resize(width, height);
|
||||
m_screenFramebuffer->resize(width, height);
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
void RenderSystem::framebufferSetup(std::shared_ptr<Framebuffer> framebuffer)
|
||||
{
|
||||
framebuffer->bind();
|
||||
|
||||
RenderCommand::setColorAttachmentCount(framebuffer->colorAttachmentCount());
|
||||
RenderCommand::clearColor(framebuffer->clearColor());
|
||||
RenderCommand::clearBit(framebuffer->clearBit());
|
||||
}
|
||||
|
||||
void RenderSystem::framebufferTeardown(std::shared_ptr<Framebuffer> framebuffer)
|
||||
{
|
||||
framebuffer->unbind();
|
||||
|
||||
RenderCommand::setColorAttachmentCount(1);
|
||||
}
|
||||
|
||||
void RenderSystem::renderGeometry()
|
||||
{
|
||||
auto [projection, view] = CameraSystem::the().projectionView();
|
||||
auto translate = CameraSystem::the().translate();
|
||||
Uniformbuffer::the().setValue("Camera", "u_projectionView", projection * view);
|
||||
Uniformbuffer::the().setValue("Camera", "u_position", translate);
|
||||
|
||||
static DirectionalLightBlock directionalLights[2] = {
|
||||
{
|
||||
.direction = { -8.0f, -8.0f, -8.0f },
|
||||
.ambient = { 0.1f, 0.1f, 0.1f },
|
||||
.diffuse = { 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 },
|
||||
},
|
||||
};
|
||||
ShaderStorageBuffer::the().setValue("DirectionalLights", "u_directionalLight", directionalLights);
|
||||
|
||||
auto modelView = m_registry->view<TransformComponent, ModelComponent>();
|
||||
|
||||
@@ -46,8 +153,57 @@ void RenderSystem::render()
|
||||
Renderer3D::the().drawModel(model.model->vertices(),
|
||||
model.model->elements(),
|
||||
transform,
|
||||
model.color,
|
||||
model.model->texture() ? model.model->texture() : model.texture);
|
||||
}
|
||||
|
||||
Renderer3D::the().endScene();
|
||||
}
|
||||
|
||||
void RenderSystem::renderSkybox()
|
||||
{
|
||||
auto [projection, view] = CameraSystem::the().projectionView();
|
||||
RendererCubemap::the().beginScene(projection, view); // camera, lights, environment
|
||||
|
||||
auto cubemapView = m_registry->view<TransformComponent, CubemapComponent>();
|
||||
|
||||
for (auto [entity, transform, cubemap] : cubemapView.each()) {
|
||||
if (!cubemap.isLight) {
|
||||
RendererCubemap::the().drawCubemap(transform, cubemap.color, cubemap.texture);
|
||||
}
|
||||
}
|
||||
|
||||
RendererCubemap::the().endScene();
|
||||
}
|
||||
|
||||
void RenderSystem::renderLightCubes()
|
||||
{
|
||||
auto [projection, view] = CameraSystem::the().projectionView();
|
||||
RendererLightCube::the().beginScene(projection, view); // camera, lights, environment
|
||||
|
||||
auto cubemapView = m_registry->view<TransformComponent, CubemapComponent>();
|
||||
|
||||
for (auto [entity, transform, cubemap] : cubemapView.each()) {
|
||||
if (cubemap.isLight) {
|
||||
RendererLightCube::the().drawCubemap(transform, cubemap.color, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
RendererLightCube::the().endScene();
|
||||
}
|
||||
|
||||
void RenderSystem::renderOverlay()
|
||||
{
|
||||
auto quadView = m_registry->view<TransformComponent, SpriteComponent>();
|
||||
|
||||
for (auto [entity, transform, sprite] : quadView.each()) {
|
||||
Renderer2D::the().drawQuad(transform, sprite.color, sprite.texture);
|
||||
}
|
||||
|
||||
Renderer2D::the().endScene();
|
||||
|
||||
TextAreaSystem::the().render();
|
||||
RendererFont::the().endScene();
|
||||
}
|
||||
|
||||
} // namespace Inferno
|
||||
|
||||
@@ -6,25 +6,39 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory> //std::shared_ptr
|
||||
#include <cstdint> // int32_t, uint32_t
|
||||
#include <memory> //std::shared_ptr
|
||||
|
||||
#include "entt/entity/fwd.hpp" // entt::registry
|
||||
|
||||
#include "entt/entity/registry.hpp" // entt::entity, entt::registry
|
||||
#include "ruc/singleton.h"
|
||||
|
||||
#include "inferno/render/renderer.h"
|
||||
|
||||
namespace Inferno {
|
||||
|
||||
class Framebuffer;
|
||||
|
||||
class RenderSystem final : public ruc::Singleton<RenderSystem> {
|
||||
public:
|
||||
RenderSystem(s);
|
||||
virtual ~RenderSystem();
|
||||
|
||||
void initialize(uint32_t width, uint32_t height);
|
||||
void render();
|
||||
|
||||
void resize(int32_t width, int32_t height);
|
||||
|
||||
void setRegistry(std::shared_ptr<entt::registry> registry) { m_registry = registry; };
|
||||
|
||||
private:
|
||||
void framebufferSetup(std::shared_ptr<Framebuffer> framebuffer);
|
||||
void framebufferTeardown(std::shared_ptr<Framebuffer> framebuffer);
|
||||
void renderGeometry();
|
||||
void renderSkybox();
|
||||
void renderLightCubes();
|
||||
void renderOverlay();
|
||||
|
||||
std::shared_ptr<Framebuffer> m_framebuffer;
|
||||
std::shared_ptr<Framebuffer> m_screenFramebuffer;
|
||||
std::shared_ptr<entt::registry> m_registry;
|
||||
};
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
namespace Inferno {
|
||||
|
||||
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 TextAreaComponent;
|
||||
|
||||
@@ -122,17 +122,17 @@ void Window::initialize()
|
||||
|
||||
switch (action) {
|
||||
case GLFW_PRESS: {
|
||||
KeyPressEvent event(key);
|
||||
KeyPressEvent event(key, mods);
|
||||
w.m_eventCallback(event);
|
||||
break;
|
||||
}
|
||||
case GLFW_RELEASE: {
|
||||
KeyReleaseEvent event(key);
|
||||
KeyReleaseEvent event(key, mods);
|
||||
w.m_eventCallback(event);
|
||||
break;
|
||||
}
|
||||
case GLFW_REPEAT: {
|
||||
KeyRepeatEvent event(key);
|
||||
KeyRepeatEvent event(key, mods);
|
||||
w.m_eventCallback(event);
|
||||
break;
|
||||
}
|
||||
|
||||
Vendored
+1
@@ -33,3 +33,4 @@ target_include_directories(${ENGINE}-dependencies PUBLIC
|
||||
"glad/include"
|
||||
"lua")
|
||||
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
Reference in New Issue
Block a user