Compare commits

..

No commits in common. 'd16fade4972a23b296615e7c88779c47d2762164' and 'c5ed219ad27675434bde5dcd3f5d8c41adc40c98' have entirely different histories.

  1. 19
      assets/glsl/batch-2d.vert
  2. 18
      assets/glsl/batch-3d.frag
  3. 17
      assets/glsl/batch-3d.vert
  4. 4
      assets/glsl/batch-cubemap.frag
  5. 8
      assets/glsl/batch-cubemap.vert
  6. 4
      assets/glsl/batch-font.frag
  7. 4
      assets/glsl/batch-font.vert
  8. 4
      assets/glsl/batch-quad.frag
  9. 15
      assets/glsl/batch-quad.vert
  10. 14
      assets/glsl/lightsource.frag
  11. 78
      assets/glsl/post-process.frag
  12. 25
      assets/glsl/post-process.vert
  13. BIN
      assets/model/quad.blend
  14. 15
      assets/model/quad.obj
  15. 15
      assets/scene/scene1.json
  16. 2
      assets/settings.json
  17. 76
      src/inferno/application.cpp
  18. 2
      src/inferno/application.h
  19. 2
      src/inferno/asset/model.cpp
  20. 45
      src/inferno/asset/shader.cpp
  21. 18
      src/inferno/asset/shader.h
  22. 51
      src/inferno/asset/texture.cpp
  23. 3
      src/inferno/asset/texture.h
  24. 3
      src/inferno/component/cubemap-component.cpp
  25. 1
      src/inferno/component/cubemap-component.h
  26. 4
      src/inferno/component/model-component.cpp
  27. 1
      src/inferno/component/model-component.h
  28. 31
      src/inferno/event/keyevent.h
  29. 19
      src/inferno/keycodes.cpp
  30. 4
      src/inferno/keycodes.h
  31. 104
      src/inferno/render/buffer.cpp
  32. 30
      src/inferno/render/buffer.h
  33. 47
      src/inferno/render/framebuffer.cpp
  34. 12
      src/inferno/render/framebuffer.h
  35. 26
      src/inferno/render/render-command.cpp
  36. 4
      src/inferno/render/render-command.h
  37. 106
      src/inferno/render/renderer.cpp
  38. 95
      src/inferno/render/renderer.h
  39. 240
      src/inferno/render/uniformbuffer.cpp
  40. 130
      src/inferno/render/uniformbuffer.h
  41. 5
      src/inferno/scene/scene.cpp
  42. 13
      src/inferno/system/camerasystem.cpp
  43. 1
      src/inferno/system/camerasystem.h
  44. 178
      src/inferno/system/rendersystem.cpp
  45. 22
      src/inferno/system/rendersystem.h
  46. 6
      src/inferno/window.cpp

19
assets/glsl/batch-2d.vert

@ -1,19 +0,0 @@
#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);
}

18
assets/glsl/batch-3d.frag

@ -1,21 +1,17 @@
#version 450 core #version 450 core
layout(location = 0) out vec4 albedoSpec; // RGB diffuse color layout(location = 0) out vec4 color;
layout(location = 1) out vec4 position;
layout(location = 2) out vec4 normal;
in vec3 v_position;
in vec3 v_normal; in vec3 v_normal;
in vec4 v_color;
in vec2 v_textureCoordinates; in vec2 v_textureCoordinates;
in flat uint v_textureIndex; in flat float v_textureIndex;
uniform sampler2D u_textures[32]; uniform sampler2D u_textures[32];
void main() void main()
{ {
vec4 textureColor = v_color; vec4 textureColor = vec4(1.0f);
switch(v_textureIndex) { switch(int(v_textureIndex)) {
case 0: break; // Texture unit 0 is reserved for no texture case 0: break; // Texture unit 0 is reserved for no texture
case 1: textureColor *= texture(u_textures[1], v_textureCoordinates); break; case 1: textureColor *= texture(u_textures[1], v_textureCoordinates); break;
case 2: textureColor *= texture(u_textures[2], v_textureCoordinates); break; case 2: textureColor *= texture(u_textures[2], v_textureCoordinates); break;
@ -49,9 +45,5 @@ void main()
case 30: textureColor *= texture(u_textures[30], v_textureCoordinates); break; case 30: textureColor *= texture(u_textures[30], v_textureCoordinates); break;
case 31: textureColor *= texture(u_textures[31], 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);
} }

17
assets/glsl/batch-3d.vert

@ -2,27 +2,18 @@
layout(location = 0) in vec3 a_position; layout(location = 0) in vec3 a_position;
layout(location = 1) in vec3 a_normal; layout(location = 1) in vec3 a_normal;
layout(location = 2) in vec4 a_color; layout(location = 2) in vec2 a_textureCoordinates;
layout(location = 3) in vec2 a_textureCoordinates; layout(location = 3) in float a_textureIndex;
layout(location = 4) in uint a_textureIndex;
out vec3 v_position;
out vec3 v_normal; out vec3 v_normal;
out vec4 v_color;
out vec2 v_textureCoordinates; out vec2 v_textureCoordinates;
out flat uint v_textureIndex; out flat float v_textureIndex;
layout(std140, binding = 0) uniform Camera uniform mat4 u_projectionView;
{
mat4 u_projectionView;
vec3 u_position;
};
void main() void main()
{ {
v_position = a_position;
v_normal = a_normal; v_normal = a_normal;
v_color = a_color;
v_textureCoordinates = a_textureCoordinates; v_textureCoordinates = a_textureCoordinates;
v_textureIndex = a_textureIndex; v_textureIndex = a_textureIndex;
// Vclip = Camera projection * Camera view * Model transform * Vlocal // Vclip = Camera projection * Camera view * Model transform * Vlocal

4
assets/glsl/batch-cubemap.frag

@ -4,14 +4,14 @@ layout(location = 0) out vec4 color;
in vec4 v_color; in vec4 v_color;
in vec3 v_textureCoordinates; in vec3 v_textureCoordinates;
in flat uint v_textureIndex; in flat float v_textureIndex;
uniform samplerCube u_textures[32]; uniform samplerCube u_textures[32];
void main() void main()
{ {
vec4 textureColor = v_color; vec4 textureColor = v_color;
switch(v_textureIndex) { switch(int(v_textureIndex)) {
case 0: break; // Texture unit 0 is reserved for no texture case 0: break; // Texture unit 0 is reserved for no texture
case 1: textureColor *= texture(u_textures[1], v_textureCoordinates); break; case 1: textureColor *= texture(u_textures[1], v_textureCoordinates); break;
case 2: textureColor *= texture(u_textures[2], v_textureCoordinates); break; case 2: textureColor *= texture(u_textures[2], v_textureCoordinates); break;

8
assets/glsl/batch-cubemap.vert

@ -2,13 +2,13 @@
layout(location = 0) in vec3 a_position; layout(location = 0) in vec3 a_position;
layout(location = 1) in vec4 a_color; layout(location = 1) in vec4 a_color;
layout(location = 2) in uint a_textureIndex; layout(location = 2) in float a_textureIndex;
out vec4 v_color; out vec4 v_color;
out vec3 v_textureCoordinates; out vec3 v_textureCoordinates;
out flat uint v_textureIndex; out flat float v_textureIndex;
uniform mat4 u_projectionView2; uniform mat4 u_projectionView;
void main() void main()
{ {
@ -16,5 +16,5 @@ void main()
v_textureCoordinates = a_position; v_textureCoordinates = a_position;
v_textureIndex = a_textureIndex; v_textureIndex = a_textureIndex;
// Vclip = Camera projection * Camera view * Model transform * Vlocal // Vclip = Camera projection * Camera view * Model transform * Vlocal
gl_Position = u_projectionView2 * vec4(a_position, 1.0f); gl_Position = u_projectionView * vec4(a_position, 1.0f);
} }

4
assets/glsl/batch-font.frag

@ -4,7 +4,7 @@ layout(location = 0) out vec4 color;
in vec4 v_color; in vec4 v_color;
in vec2 v_textureCoordinates; in vec2 v_textureCoordinates;
in flat uint v_textureIndex; in flat float v_textureIndex;
in float v_width; in float v_width;
in float v_edge; in float v_edge;
in float v_borderWidth; in float v_borderWidth;
@ -25,7 +25,7 @@ float alpha(float textureAlpha)
void main() void main()
{ {
vec4 textureColor = v_color; vec4 textureColor = v_color;
switch(v_textureIndex) { switch(int(v_textureIndex)) {
case 0: break; // Texture unit 0 is reserved for no texture case 0: break; // Texture unit 0 is reserved for no texture
// case 1: textureColor.a = 1; break; // case 1: textureColor.a = 1; break;
case 1: textureColor.a = alpha(texture(u_textures[1], v_textureCoordinates).a); break; case 1: textureColor.a = alpha(texture(u_textures[1], v_textureCoordinates).a); break;

4
assets/glsl/batch-font.vert

@ -3,7 +3,7 @@
layout(location = 0) in vec3 a_position; layout(location = 0) in vec3 a_position;
layout(location = 1) in vec4 a_color; layout(location = 1) in vec4 a_color;
layout(location = 2) in vec2 a_textureCoordinates; layout(location = 2) in vec2 a_textureCoordinates;
layout(location = 3) in uint a_textureIndex; layout(location = 3) in float a_textureIndex;
layout(location = 4) in float a_width; layout(location = 4) in float a_width;
layout(location = 5) in float a_edge; layout(location = 5) in float a_edge;
layout(location = 6) in float a_borderWidth; layout(location = 6) in float a_borderWidth;
@ -13,7 +13,7 @@ layout(location = 9) in float a_offset;
out vec4 v_color; out vec4 v_color;
out vec2 v_textureCoordinates; out vec2 v_textureCoordinates;
out flat uint v_textureIndex; out flat float v_textureIndex;
out float v_width; out float v_width;
out float v_edge; out float v_edge;
out float v_borderWidth; out float v_borderWidth;

4
assets/glsl/batch-2d.frag → assets/glsl/batch-quad.frag

@ -4,14 +4,14 @@ layout(location = 0) out vec4 color;
in vec4 v_color; in vec4 v_color;
in vec2 v_textureCoordinates; in vec2 v_textureCoordinates;
in flat uint v_textureIndex; in flat float v_textureIndex;
uniform sampler2D u_textures[32]; uniform sampler2D u_textures[32];
void main() void main()
{ {
vec4 textureColor = v_color; vec4 textureColor = v_color;
switch(v_textureIndex) { switch(int(v_textureIndex)) {
case 0: break; // Texture unit 0 is reserved for no texture case 0: break; // Texture unit 0 is reserved for no texture
case 1: textureColor *= texture(u_textures[1], v_textureCoordinates); break; case 1: textureColor *= texture(u_textures[1], v_textureCoordinates); break;
case 2: textureColor *= texture(u_textures[2], v_textureCoordinates); break; case 2: textureColor *= texture(u_textures[2], v_textureCoordinates); break;

15
assets/glsl/lightsource.vert → assets/glsl/batch-quad.vert

@ -2,22 +2,19 @@
layout(location = 0) in vec3 a_position; layout(location = 0) in vec3 a_position;
layout(location = 1) in vec4 a_color; layout(location = 1) in vec4 a_color;
layout(location = 2) in uint a_textureIndex; layout(location = 2) in vec2 a_textureCoordinates;
layout(location = 3) in float a_textureIndex;
out vec4 v_color; out vec4 v_color;
out vec3 v_textureCoordinates; out vec2 v_textureCoordinates;
out flat uint v_textureIndex; out flat float v_textureIndex;
layout(std140, binding = 0) uniform Camera uniform mat4 u_projectionView;
{
mat4 u_projectionView;
vec3 u_position;
};
void main() void main()
{ {
v_color = a_color; v_color = a_color;
v_textureCoordinates = a_position; v_textureCoordinates = a_textureCoordinates;
v_textureIndex = a_textureIndex; v_textureIndex = a_textureIndex;
// Vclip = Camera projection * Camera view * Model transform * Vlocal // Vclip = Camera projection * Camera view * Model transform * Vlocal
gl_Position = u_projectionView * vec4(a_position, 1.0f); gl_Position = u_projectionView * vec4(a_position, 1.0f);

14
assets/glsl/lightsource.frag

@ -1,14 +0,0 @@
#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()
{
color = v_color;
}

78
assets/glsl/post-process.frag

@ -1,78 +0,0 @@
#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 = 32;
layout(std140, binding = 1) uniform 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);
}

25
assets/glsl/post-process.vert

@ -1,25 +0,0 @@
#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);
}

BIN
assets/model/quad.blend

Binary file not shown.

15
assets/model/quad.obj

@ -1,15 +0,0 @@
# 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

15
assets/scene/scene1.json

@ -35,9 +35,8 @@
"rotate": [ 0.0, 0.0, 0.0 ], "rotate": [ 0.0, 0.0, 0.0 ],
"scale": [ 1.0, 1.0, 1.0 ] "scale": [ 1.0, 1.0, 1.0 ]
}, },
"model": { "sprite": {
"color": [ 1.0, 1.0, 1.0, 1.0 ], "color": [ 1.0, 1.0, 1.0, 1.0 ],
"model": "assets/model/quad.obj",
"texture": "assets/gfx/test.png" "texture": "assets/gfx/test.png"
} }
}, },
@ -49,9 +48,8 @@
"rotate": [ 0.0, 0.0, 0.0 ], "rotate": [ 0.0, 0.0, 0.0 ],
"scale": [ 1.0, 1.0, 1.0 ] "scale": [ 1.0, 1.0, 1.0 ]
}, },
"model": { "sprite": {
"color": [ 0.5, 0.6, 0.8, 1.0 ], "color": [ 0.5, 0.6, 0.8, 1.0 ],
"model": "assets/model/quad.obj",
"texture": "assets/gfx/test.png" "texture": "assets/gfx/test.png"
} }
}, },
@ -63,9 +61,8 @@
"rotate": [ 0.0, 0.0, -20.0 ], "rotate": [ 0.0, 0.0, -20.0 ],
"scale": [ 1.0, 1.0, 1.0 ] "scale": [ 1.0, 1.0, 1.0 ]
}, },
"model": { "sprite": {
"color": [ 1.0, 1.0, 1.0, 1.0 ], "color": [ 1.0, 1.0, 1.0, 1.0 ],
"model": "assets/model/quad.obj",
"texture": "assets/gfx/test-inverted.png" "texture": "assets/gfx/test-inverted.png"
}, },
"children": [ "children": [
@ -77,9 +74,8 @@
"rotate": [ 0.0, 0.0, 0.0 ], "rotate": [ 0.0, 0.0, 0.0 ],
"scale": [ 0.5, 0.5, 1.0 ] "scale": [ 0.5, 0.5, 1.0 ]
}, },
"model": { "sprite": {
"color": [ 1.0, 1.0, 1.0, 1.0 ], "color": [ 1.0, 1.0, 1.0, 1.0 ],
"model": "assets/model/quad.obj",
"texture": "assets/gfx/test-inverted.png" "texture": "assets/gfx/test-inverted.png"
}, },
"children": [ "children": [
@ -91,9 +87,8 @@
"rotate": [ 0.0, 0.0, -20.0 ], "rotate": [ 0.0, 0.0, -20.0 ],
"scale": [ 0.5, 0.5, 1.0 ] "scale": [ 0.5, 0.5, 1.0 ]
}, },
"model": { "sprite": {
"color": [ 1.0, 1.0, 1.0, 1.0 ], "color": [ 1.0, 1.0, 1.0, 1.0 ],
"model": "assets/model/quad.obj",
"texture": "assets/gfx/test-inverted.png" "texture": "assets/gfx/test-inverted.png"
} }
} }

2
assets/settings.json

@ -3,7 +3,7 @@
"fullscreen": "windowed", "fullscreen": "windowed",
"height": 720, "height": 720,
"title": "Inferno", "title": "Inferno",
"vsync": false, "vsync": true,
"width": 1280 "width": 1280
} }
} }

76
src/inferno/application.cpp

@ -23,8 +23,6 @@
#include "inferno/render/buffer.h" #include "inferno/render/buffer.h"
#include "inferno/render/context.h" #include "inferno/render/context.h"
#include "inferno/render/framebuffer.h" #include "inferno/render/framebuffer.h"
#include "inferno/render/uniformbuffer.h"
#include "inferno/system/rendersystem.h"
// #include "inferno/render/gltf.h" // #include "inferno/render/gltf.h"
#include "inferno/asset/shader.h" #include "inferno/asset/shader.h"
#include "inferno/asset/texture.h" #include "inferno/asset/texture.h"
@ -54,7 +52,20 @@ Application::Application()
Input::initialize(); Input::initialize();
RenderCommand::initialize(); RenderCommand::initialize();
RenderSystem::the().initialize(m_window->getWidth(), m_window->getHeight());
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,
});
m_scene = std::make_shared<Scene>(); m_scene = std::make_shared<Scene>();
m_scene->initialize(); m_scene->initialize();
@ -79,14 +90,11 @@ Application::Application()
Application::~Application() Application::~Application()
{ {
m_scene->destroy(); m_scene->destroy();
Uniformbuffer::destroy();
RendererFont::destroy(); RendererFont::destroy();
Renderer2D::destroy(); Renderer2D::destroy();
Renderer3D::destroy(); Renderer3D::destroy();
RendererCubemap::destroy(); RendererCubemap::destroy();
RendererPostProcess::destroy();
RendererLightCube::destroy();
RenderCommand::destroy(); RenderCommand::destroy();
AssetManager::destroy(); AssetManager::destroy();
// Input::destroy(); // Input::destroy();
@ -150,9 +158,11 @@ int Application::run()
// offset // offset
#endif #endif
double gametime = 0; constexpr glm::vec4 vectorOne { 1.0f, 1.0f, 1.0f, 1.0f };
uint64_t frames = 0; constexpr glm::mat4 matIdentity { 1.0f };
constexpr TransformComponent transformIdentity;
// m_window->setVSync(false);
while (!m_window->shouldClose()) { while (!m_window->shouldClose()) {
float time = Time::time(); float time = Time::time();
@ -160,9 +170,6 @@ int Application::run()
m_lastFrameTime = time; m_lastFrameTime = time;
// ruc::debug("Frametime {}ms", deltaTime * 1000); // ruc::debug("Frametime {}ms", deltaTime * 1000);
gametime += deltaTime;
frames++;
// --------------------------------- // ---------------------------------
// Update // Update
@ -175,15 +182,50 @@ int Application::run()
// --------------------------------- // ---------------------------------
// Render // 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(); 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(); m_window->render();
} }
ruc::debug("Application shutdown"); ruc::debug("Application shutdown");
ruc::debug("Average frametime: {:.2f}ms", (gametime / frames) * 1000);
return m_status; return m_status;
} }
@ -212,7 +254,8 @@ bool Application::onWindowResize(WindowResizeEvent& e)
{ {
ruc::info("WindowResizeEvent {}x{}", e.getWidth(), e.getHeight()); ruc::info("WindowResizeEvent {}x{}", e.getWidth(), e.getHeight());
RenderSystem::the().resize(e.getWidth(), e.getHeight()); RenderCommand::setViewport(0, 0, e.getWidth(), e.getHeight());
m_framebuffer->resize(e.getWidth(), e.getHeight());
return true; return true;
} }
@ -226,11 +269,6 @@ bool Application::onKeyPress(KeyPressEvent& e)
m_window->setShouldClose(true); 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; return true;
} }

2
src/inferno/application.h

@ -51,6 +51,8 @@ private:
float m_lastFrameTime { 0.0f }; float m_lastFrameTime { 0.0f };
std::unique_ptr<Window> m_window; std::unique_ptr<Window> m_window;
std::shared_ptr<Framebuffer> m_framebuffer;
std::shared_ptr<Framebuffer> m_screenFramebuffer;
std::shared_ptr<Scene> m_scene; std::shared_ptr<Scene> m_scene;
// //

2
src/inferno/asset/model.cpp

@ -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) void Model::processScene(std::shared_ptr<Model> model, const aiScene* scene)
{ {
VERIFY(scene->HasMeshes(), "malformed model"); VERIFY(scene->HasMeshes(), "malformed model");
VERIFY(scene->mNumTextures < 2, "unsupported model type: {}/1", scene->mNumTextures); VERIFY(scene->mNumTextures < 2, "unsupported model type");
if (scene->mNumTextures == 1) { if (scene->mNumTextures == 1) {
aiTexture* texture = scene->mTextures[0]; aiTexture* texture = scene->mTextures[0];

45
src/inferno/asset/shader.cpp

@ -50,74 +50,65 @@ 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()); int32_t location = glGetUniformLocation(m_id, name.data());
VERIFY(location != -1, "Shader could not find uniform '{}'", name); VERIFY(location != -1, "Shader could not find uniform '{}'", name);
m_uniformLocations[name] = static_cast<uint32_t>(location);
return location; return location;
} }
void Shader::setInt(std::string_view name, int value) void Shader::setInt(std::string_view name, int value)
{ {
// Set uniform int // Set uniform int
glUniform1i(findUniformLocation(name), value); glUniform1i(findUniform(name), value);
} }
void Shader::setInt(std::string_view name, int* values, uint32_t count) void Shader::setInt(std::string_view name, int* values, uint32_t count)
{ {
// Set uniform int array // Set uniform int array
glUniform1iv(findUniformLocation(name), count, values); glUniform1iv(findUniform(name), count, values);
} }
void Shader::setFloat(std::string_view name, float value) void Shader::setFloat(std::string_view name, float value) const
{ {
// Set uniform float // Set uniform float
glUniform1f(findUniformLocation(name), value); glUniform1f(findUniform(name), value);
} }
void Shader::setFloat(std::string_view name, float v1, float v2, float v3, float v4) void Shader::setFloat(std::string_view name, float v1, float v2, float v3, float v4) const
{ {
// Set uniform vec4 data // Set uniform vec4 data
glUniform4f(findUniformLocation(name), v1, v2, v3, v4); glUniform4f(findUniform(name), v1, v2, v3, v4);
} }
void Shader::setFloat(std::string_view name, glm::vec2 value) void Shader::setFloat(std::string_view name, glm::vec2 value) const
{ {
// Set uniform vec2 data // Set uniform vec2 data
glUniform2f(findUniformLocation(name), value.x, value.y); glUniform2f(findUniform(name), value.x, value.y);
} }
void Shader::setFloat(std::string_view name, glm::vec3 value) void Shader::setFloat(std::string_view name, glm::vec3 value) const
{ {
// Set uniform vec3 data // Set uniform vec3 data
glUniform3f(findUniformLocation(name), value.x, value.y, value.z); glUniform3f(findUniform(name), value.x, value.y, value.z);
} }
void Shader::setFloat(std::string_view name, glm::vec4 value) void Shader::setFloat(std::string_view name, glm::vec4 value) const
{ {
// Set uniform vec4 data // Set uniform vec4 data
glUniform4f(findUniformLocation(name), value.x, value.y, value.z, value.w); glUniform4f(findUniform(name), value.x, value.y, value.z, value.w);
} }
void Shader::setFloat(std::string_view name, glm::mat3 matrix) void Shader::setFloat(std::string_view name, glm::mat3 matrix) const
{ {
// Set uniform mat3 data // Set uniform mat3 data
glUniformMatrix3fv(findUniformLocation(name), 1, GL_FALSE, glm::value_ptr(matrix)); glUniformMatrix3fv(findUniform(name), 1, GL_FALSE, glm::value_ptr(matrix));
} }
void Shader::setFloat(std::string_view name, glm::mat4 matrix) void Shader::setFloat(std::string_view name, glm::mat4 matrix) const
{ {
// Set uniform mat4 data // Set uniform mat4 data
glUniformMatrix4fv(findUniformLocation(name), 1, GL_FALSE, glm::value_ptr(matrix)); glUniformMatrix4fv(findUniform(name), 1, GL_FALSE, glm::value_ptr(matrix));
} }
void Shader::bind() const void Shader::bind() const
@ -130,8 +121,6 @@ void Shader::unbind() const
glUseProgram(0); glUseProgram(0);
} }
// -----------------------------------------
uint32_t Shader::compileShader(int32_t type, const char* source) const uint32_t Shader::compileShader(int32_t type, const char* source) const
{ {
// Create new shader // Create new shader

18
src/inferno/asset/shader.h

@ -6,7 +6,6 @@
#include <cstdint> // int32_t, uint32_t #include <cstdint> // int32_t, uint32_t
#include <string_view> #include <string_view>
#include <unordered_map>
#include "glm/fwd.hpp" // glm::mat3, glm::mat4, glm::vec2, glm::vec3 #include "glm/fwd.hpp" // glm::mat3, glm::mat4, glm::vec2, glm::vec3
@ -21,17 +20,17 @@ public:
// Factory function // Factory function
static std::shared_ptr<Shader> create(std::string_view path); static std::shared_ptr<Shader> create(std::string_view path);
uint32_t findUniformLocation(std::string_view name); int32_t findUniform(std::string_view name) const;
void setInt(std::string_view name, int value); void setInt(std::string_view name, int value);
void setInt(std::string_view name, int* values, uint32_t count); void setInt(std::string_view name, int* values, uint32_t count);
void setFloat(std::string_view name, float value); void setFloat(std::string_view name, float value) const;
void setFloat(std::string_view name, float v1, float v2, float v3, float v4); void setFloat(std::string_view name, float v1, float v2, float v3, float v4) const;
void setFloat(std::string_view name, glm::vec2 value); void setFloat(std::string_view name, glm::vec2 value) const;
void setFloat(std::string_view name, glm::vec3 value); void setFloat(std::string_view name, glm::vec3 value) const;
void setFloat(std::string_view name, glm::vec4 value); void setFloat(std::string_view name, glm::vec4 value) const;
void setFloat(std::string_view name, glm::mat3 matrix); void setFloat(std::string_view name, glm::mat3 matrix) const;
void setFloat(std::string_view name, glm::mat4 matrix); void setFloat(std::string_view name, glm::mat4 matrix) const;
void bind() const; void bind() const;
void unbind() const; void unbind() const;
@ -53,7 +52,6 @@ private:
private: private:
uint32_t m_id { 0 }; uint32_t m_id { 0 };
std::unordered_map<std::string_view, uint32_t> m_uniformLocations;
}; };
// ----------------------------------------- // -----------------------------------------

51
src/inferno/asset/texture.cpp

@ -13,8 +13,6 @@
#include "ruc/meta/assert.h" #include "ruc/meta/assert.h"
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
#include "stb/stb_image.h" #include "stb/stb_image.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb/stb_image_write.h"
#include "inferno/asset/texture.h" #include "inferno/asset/texture.h"
@ -25,51 +23,6 @@ Texture::~Texture()
glDeleteTextures(1, &m_id); 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) void Texture::init(uint32_t width, uint32_t height, uint8_t channels)
{ {
init(width, height, init(width, height,
@ -330,8 +283,8 @@ void TextureFramebuffer::createImpl()
m_dataType, // Texture source datatype m_dataType, // Texture source datatype
NULL); // Image data NULL); // Image data
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Unbind texture object // Unbind texture object
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);

3
src/inferno/asset/texture.h

@ -22,9 +22,6 @@ class Texture : public Asset {
public: public:
virtual ~Texture(); 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, uint8_t channels);
void init(uint32_t width, uint32_t height, uint32_t internalFormat, uint32_t dataFormat, uint32_t dataType); void init(uint32_t width, uint32_t height, uint32_t internalFormat, uint32_t dataFormat, uint32_t dataType);

3
src/inferno/component/cubemap-component.cpp

@ -22,9 +22,6 @@ void fromJson(const ruc::Json& json, CubemapComponent& value)
if (json.exists("texture") && json.at("texture").type() == ruc::Json::Type::String) { if (json.exists("texture") && json.at("texture").type() == ruc::Json::Type::String) {
value.texture = AssetManager::the().load<TextureCubemap>(json.at("texture").asString()); value.texture = AssetManager::the().load<TextureCubemap>(json.at("texture").asString());
} }
if (json.exists("isLight")) {
json.at("isLight").getTo(value.isLight);
}
} }
} // namespace Inferno } // namespace Inferno

1
src/inferno/component/cubemap-component.h

@ -18,7 +18,6 @@ namespace Inferno {
struct CubemapComponent { struct CubemapComponent {
glm::vec4 color { 1.0f }; glm::vec4 color { 1.0f };
std::shared_ptr<Texture> texture; std::shared_ptr<Texture> texture;
bool isLight { false };
}; };
void fromJson(const ruc::Json& json, CubemapComponent& value); void fromJson(const ruc::Json& json, CubemapComponent& value);

4
src/inferno/component/model-component.cpp

@ -8,7 +8,6 @@
#include "inferno/asset/asset-manager.h" #include "inferno/asset/asset-manager.h"
#include "inferno/asset/model.h" #include "inferno/asset/model.h"
#include "inferno/asset/texture.h" #include "inferno/asset/texture.h"
#include "inferno/component/spritecomponent.h" // TODO: Move glm::x toJson/fromJson to separate file
namespace Inferno { namespace Inferno {
@ -16,9 +15,6 @@ void fromJson(const ruc::Json& json, ModelComponent& value)
{ {
VERIFY(json.type() == ruc::Json::Type::Object); 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) { if (json.exists("model") && json.at("model").type() == ruc::Json::Type::String) {
value.model = AssetManager::the().load<Model>(json.at("model").asString()); value.model = AssetManager::the().load<Model>(json.at("model").asString());
} }

1
src/inferno/component/model-component.h

@ -16,7 +16,6 @@
namespace Inferno { namespace Inferno {
struct ModelComponent { struct ModelComponent {
glm::vec4 color { 1.0f };
std::shared_ptr<Model> model; std::shared_ptr<Model> model;
std::shared_ptr<Texture2D> texture; std::shared_ptr<Texture2D> texture;
}; };

31
src/inferno/event/keyevent.h

@ -14,27 +14,24 @@ namespace Inferno {
class KeyEvent : public Event { class KeyEvent : public Event {
public: public:
int getKey() const { return m_key; } inline int getKey() const { return m_key; }
int getMods() const { return m_mods; }
EVENT_CLASS_CATEGORY(InputEventCategory | KeyEventCategory) EVENT_CLASS_CATEGORY(InputEventCategory | KeyEventCategory)
protected: protected:
KeyEvent(int key, int mods) KeyEvent(int key)
: m_key(key) : m_key(key)
, m_mods(mods)
{ {
} }
private: private:
int m_key { 0 }; int m_key;
int m_mods { 0 };
}; };
class KeyPressEvent final : public KeyEvent { class KeyPressEvent : public KeyEvent {
public: public:
KeyPressEvent(int key, int mods) KeyPressEvent(int key)
: KeyEvent(key, mods) : KeyEvent(key)
{ {
} }
@ -48,10 +45,10 @@ public:
EVENT_CLASS_TYPE(KeyPress) EVENT_CLASS_TYPE(KeyPress)
}; };
class KeyReleaseEvent final : public KeyEvent { class KeyReleaseEvent : public KeyEvent {
public: public:
KeyReleaseEvent(int key, int mods) KeyReleaseEvent(int key)
: KeyEvent(key, mods) : KeyEvent(key)
{ {
} }
@ -62,13 +59,13 @@ public:
return ss.str(); return ss.str();
} }
EVENT_CLASS_TYPE(KeyRelease) EVENT_CLASS_TYPE(KeyPress)
}; };
class KeyRepeatEvent final : public KeyEvent { class KeyRepeatEvent : public KeyEvent {
public: public:
KeyRepeatEvent(int key, int mods) KeyRepeatEvent(int key)
: KeyEvent(key, mods) : KeyEvent(key)
{ {
} }
@ -79,7 +76,7 @@ public:
return ss.str(); return ss.str();
} }
EVENT_CLASS_TYPE(KeyRepeat) EVENT_CLASS_TYPE(KeyPress)
}; };
} // namespace Inferno } // namespace Inferno

19
src/inferno/keycodes.cpp

@ -139,33 +139,14 @@ static std::unordered_map<std::string_view, int> keys({
{ MAP_KEY(GLFW_KEY_MENU) }, { 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) int keyCode(std::string_view name)
{ {
VERIFY(keys.find(name) != keys.end(), "could not find key code: {}", name); VERIFY(keys.find(name) != keys.end(), "could not find key code: {}", name);
return keys.at(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) std::string_view keyName(int key)
{ {
auto it = std::find_if(keys.begin(), keys.end(), [key](const auto& keybind) { auto it = std::find_if(keys.begin(), keys.end(), [key](const auto& keybind) {

4
src/inferno/keycodes.h

@ -13,8 +13,6 @@
namespace Inferno { namespace Inferno {
int keyCode(std::string_view name); int keyCode(std::string_view name);
int keyMod(std::string_view name); std::string_view keyName(int);
std::string_view keyName(int key);
} // namespace Inferno } // namespace Inferno

104
src/inferno/render/buffer.cpp

@ -4,12 +4,6 @@
* SPDX-License-Identifier: MIT * 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 "glad/glad.h"
#include "ruc/meta/assert.h" #include "ruc/meta/assert.h"
@ -67,10 +61,10 @@ uint32_t BufferElement::getTypeSize(const BufferElementType type)
case BufferElementType::Vec3: case BufferElementType::Vec3:
case BufferElementType::Vec4: case BufferElementType::Vec4:
return sizeof(float) * getTypeCount(type); return sizeof(float) * getTypeCount(type);
case BufferElementType::Double: case BufferElementType::VecDouble:
case BufferElementType::Vec2Double: case BufferElementType::VecDouble2:
case BufferElementType::Vec3Double: case BufferElementType::VecDouble3:
case BufferElementType::Vec4Double: case BufferElementType::VecDouble4:
return sizeof(double) * getTypeCount(type); return sizeof(double) * getTypeCount(type);
case BufferElementType::Mat2: case BufferElementType::Mat2:
case BufferElementType::Mat3: case BufferElementType::Mat3:
@ -95,25 +89,25 @@ uint32_t BufferElement::getTypeCount(const BufferElementType type)
case BufferElementType::Int: case BufferElementType::Int:
case BufferElementType::Uint: case BufferElementType::Uint:
case BufferElementType::Float: case BufferElementType::Float:
case BufferElementType::Double: case BufferElementType::VecDouble:
return 1; return 1;
case BufferElementType::Bool2: case BufferElementType::Bool2:
case BufferElementType::Int2: case BufferElementType::Int2:
case BufferElementType::Uint2: case BufferElementType::Uint2:
case BufferElementType::Vec2: case BufferElementType::Vec2:
case BufferElementType::Vec2Double: case BufferElementType::VecDouble2:
return 2; return 2;
case BufferElementType::Bool3: case BufferElementType::Bool3:
case BufferElementType::Int3: case BufferElementType::Int3:
case BufferElementType::Uint3: case BufferElementType::Uint3:
case BufferElementType::Vec3: case BufferElementType::Vec3:
case BufferElementType::Vec3Double: case BufferElementType::VecDouble3:
return 3; return 3;
case BufferElementType::Bool4: case BufferElementType::Bool4:
case BufferElementType::Int4: case BufferElementType::Int4:
case BufferElementType::Uint4: case BufferElementType::Uint4:
case BufferElementType::Vec4: case BufferElementType::Vec4:
case BufferElementType::Vec4Double: case BufferElementType::VecDouble4:
return 4; return 4;
case BufferElementType::Mat2: case BufferElementType::Mat2:
return 2 * 2; return 2 * 2;
@ -158,10 +152,10 @@ uint32_t BufferElement::getTypeGL(const BufferElementType type)
case BufferElementType::Vec3: case BufferElementType::Vec3:
case BufferElementType::Vec4: case BufferElementType::Vec4:
return GL_FLOAT; return GL_FLOAT;
case BufferElementType::Double: case BufferElementType::VecDouble:
case BufferElementType::Vec2Double: case BufferElementType::VecDouble2:
case BufferElementType::Vec3Double: case BufferElementType::VecDouble3:
case BufferElementType::Vec4Double: case BufferElementType::VecDouble4:
return GL_DOUBLE; return GL_DOUBLE;
case BufferElementType::Mat2: case BufferElementType::Mat2:
case BufferElementType::Mat3: case BufferElementType::Mat3:
@ -190,7 +184,7 @@ void BufferLayout::calculateOffsetsAndStride()
m_stride = 0; m_stride = 0;
for (auto& element : m_elements) { for (auto& element : m_elements) {
element.setOffset(m_stride); element.setOffset(m_stride);
m_stride += element.size(); m_stride += element.getSize();
} }
} }
@ -208,7 +202,7 @@ VertexBuffer::VertexBuffer(size_t size, float* vertices)
bind(); bind();
// Upload data to the GPU // Upload data to the GPU
glBufferData(GL_ARRAY_BUFFER, size, vertices, GL_DYNAMIC_DRAW); glBufferData(GL_ARRAY_BUFFER, size, vertices, GL_STATIC_DRAW);
unbind(); unbind();
} }
@ -248,7 +242,7 @@ IndexBuffer::IndexBuffer(uint32_t* indices, size_t size)
bind(); bind();
// Upload data to the GPU // Upload data to the GPU
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, indices, GL_DYNAMIC_DRAW); glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, indices, GL_STATIC_DRAW);
unbind(); unbind();
} }
@ -303,8 +297,8 @@ void VertexArray::unbind() const
void VertexArray::addVertexBuffer(std::shared_ptr<VertexBuffer> vertexBuffer) void VertexArray::addVertexBuffer(std::shared_ptr<VertexBuffer> vertexBuffer)
{ {
const auto& layout = vertexBuffer->layout(); const auto& layout = vertexBuffer->getLayout();
VERIFY(layout.elements().size(), "VertexBuffer has no layout"); VERIFY(layout.getElements().size(), "VertexBuffer has no layout");
bind(); bind();
vertexBuffer->bind(); vertexBuffer->bind();
@ -312,63 +306,13 @@ void VertexArray::addVertexBuffer(std::shared_ptr<VertexBuffer> vertexBuffer)
uint32_t index = 0; uint32_t index = 0;
for (const auto& element : layout) { for (const auto& element : layout) {
glEnableVertexAttribArray(index); glEnableVertexAttribArray(index);
switch (element.type()) { glVertexAttribPointer(
case BufferElementType::None: index,
break; element.getTypeCount(),
case BufferElementType::Int: element.getTypeGL(),
case BufferElementType::Int2: element.getNormalized() ? GL_TRUE : GL_FALSE,
case BufferElementType::Int3: layout.getStride(),
case BufferElementType::Int4: reinterpret_cast<const void*>(element.getOffset()));
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++; index++;
} }

30
src/inferno/render/buffer.h

@ -7,10 +7,10 @@
#pragma once #pragma once
#include <cstddef> // size_t #include <cstddef> // size_t
#include <cstdint> // int32_t, uint8_t, uint32_t #include <cstdint> // int32_t, uint32_t
#include <memory> // std::shared_ptr #include <memory> // std::shared_ptr
#include <string> #include <string> // std::string
#include <vector> #include <vector> // std::vector
namespace Inferno { namespace Inferno {
@ -22,7 +22,7 @@ enum class BufferElementType {
Int, Int2, Int3, Int4, // ivec Int, Int2, Int3, Int4, // ivec
Uint, Uint2, Uint3, Uint4, // uvec Uint, Uint2, Uint3, Uint4, // uvec
Float, Vec2, Vec3, Vec4, // vec Float, Vec2, Vec3, Vec4, // vec
Double, Vec2Double, Vec3Double, Vec4Double, // dvec VecDouble, VecDouble2, VecDouble3, VecDouble4, // dvec
Mat2, Mat3, Mat4, // mat Mat2, Mat3, Mat4, // mat
MatDouble2, MatDouble3, MatDouble4, // dmat MatDouble2, MatDouble3, MatDouble4, // dmat
}; };
@ -43,11 +43,11 @@ public:
static uint32_t getTypeCount(const BufferElementType type); static uint32_t getTypeCount(const BufferElementType type);
static uint32_t getTypeGL(const BufferElementType type); static uint32_t getTypeGL(const BufferElementType type);
BufferElementType type() const { return m_type; } BufferElementType getType() const { return m_type; }
std::string name() const { return m_name; } std::string getName() const { return m_name; }
uint32_t size() const { return m_size; } uint32_t getSize() const { return m_size; }
uint32_t offset() const { return m_offset; } uint32_t getOffset() const { return m_offset; }
bool normalized() const { return m_normalized; } bool getNormalized() const { return m_normalized; }
void setType(const BufferElementType& type) { m_type = type; } void setType(const BufferElementType& type) { m_type = type; }
void setName(const std::string& name) { m_name = name; } void setName(const std::string& name) { m_name = name; }
@ -72,8 +72,8 @@ public:
BufferLayout(const std::initializer_list<BufferElement>& elements); BufferLayout(const std::initializer_list<BufferElement>& elements);
~BufferLayout() = default; ~BufferLayout() = default;
const std::vector<BufferElement>& elements() const { return m_elements; } const std::vector<BufferElement>& getElements() const { return m_elements; }
uint32_t stride() const { return m_stride; } uint32_t getStride() const { return m_stride; }
// Iterators // Iterators
std::vector<BufferElement>::iterator begin() { return m_elements.begin(); } std::vector<BufferElement>::iterator begin() { return m_elements.begin(); }
@ -103,9 +103,9 @@ public:
void uploadData(const void* data, uint32_t size); void uploadData(const void* data, uint32_t size);
const BufferLayout& layout() const { return m_layout; } const BufferLayout& getLayout() const { return m_layout; }
void setLayout(const BufferLayout& layout) { m_layout = layout; } inline void setLayout(const BufferLayout& layout) { m_layout = layout; }
private: private:
uint32_t m_id { 0 }; uint32_t m_id { 0 };
@ -125,7 +125,7 @@ public:
void uploadData(const void* data, uint32_t size); void uploadData(const void* data, uint32_t size);
uint32_t count() const { return m_count; } uint32_t getCount() const { return m_count; }
private: private:
uint32_t m_id { 0 }; uint32_t m_id { 0 };
@ -147,7 +147,7 @@ public:
void setIndexBuffer(std::shared_ptr<IndexBuffer> indexBuffer); void setIndexBuffer(std::shared_ptr<IndexBuffer> indexBuffer);
std::shared_ptr<VertexBuffer> at(size_t i) const { return m_vertexBuffers.at(i); } std::shared_ptr<VertexBuffer> at(size_t i) const { return m_vertexBuffers.at(i); }
std::shared_ptr<IndexBuffer> indexBuffer() const { return m_indexBuffer; } std::shared_ptr<IndexBuffer> getIndexBuffer() const { return m_indexBuffer; }
private: private:
uint32_t m_id { 0 }; uint32_t m_id { 0 };

47
src/inferno/render/framebuffer.cpp

@ -36,14 +36,6 @@ Framebuffer::~Framebuffer()
glDeleteFramebuffers(1, &m_id); 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 void Framebuffer::bind() const
@ -94,47 +86,22 @@ void Framebuffer::createTextures()
bind(); bind();
auto it = m_attachments.begin(); auto it = m_attachments.begin();
m_colorAttachmentCount = 0; uint8_t color_attachment = 0;
size_t size = m_attachments.size(); size_t size = m_attachments.size();
m_textures.resize(size); m_textures.resize(size);
for (size_t i = 0; i < size; ++i) { for (size_t i = 0; i < size; ++i) {
TypeProperties type = *(it + i); TypeProperties type = *(it + i);
if (type.type == Type::RGB8) { if (type.type == Type::Color) {
// Set color attachment 0 out of 32
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 // Set color attachment 0 out of 32
m_textures[i] = TextureFramebuffer::create("", m_width, m_height, GL_RGBA16F, GL_RGBA, GL_FLOAT); m_textures[i] = (TextureFramebuffer::create(
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + m_colorAttachmentCount, GL_TEXTURE_2D, m_textures[i]->id(), 0); "", m_width, m_height, GL_RGB, GL_RGB));
m_colorAttachmentCount++; glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + color_attachment, GL_TEXTURE_2D, m_textures[i]->id(), 0);
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 // This combined texture is required for older GPUs
if (type.type == Type::Depth24Stencil8) { // Depth if (type.type == Type::Depth24Stencil8) {
m_textures[i] = (TextureFramebuffer::create( m_textures[i] = (TextureFramebuffer::create(
"", m_width, m_height, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8)); "", 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); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_textures[i]->id(), 0);
@ -150,7 +117,7 @@ void Framebuffer::createTextures()
} }
} }
VERIFY(m_colorAttachmentCount <= 32, "maximum color attachments was exceeded: {}/32", m_colorAttachmentCount); VERIFY(color_attachment <= 32, "maximum color attachments was exceeded: {}/32", color_attachment);
check(); check();
unbind(); unbind();

12
src/inferno/render/framebuffer.h

@ -24,14 +24,11 @@ public:
None = 0, None = 0,
// Color // Color
RGB8 = 1, RGBA8 = 1,
RGBA8 = 2,
RGBA16F = 3,
RGBA32F = 4,
// Depth/stencil // Depth/stencil
Depth24Stencil8 = 5, Depth32F = 2,
Depth32F = 6, Depth24Stencil8 = 3,
// Defaults // Defaults
Color = RGBA8, Color = RGBA8,
@ -62,14 +59,12 @@ public:
// Factory function // Factory function
static std::shared_ptr<Framebuffer> create(const Properties& properties); 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 bind() const;
void unbind() const; void unbind() const;
bool check() const; bool check() const;
void resize(uint32_t width, uint32_t height); void resize(uint32_t width, uint32_t height);
uint8_t colorAttachmentCount() const { return m_colorAttachmentCount; }
uint32_t id() const { return m_id; } uint32_t id() const { return m_id; }
uint32_t width() const { return m_width; } uint32_t width() const { return m_width; }
uint32_t height() const { return m_height; } uint32_t height() const { return m_height; }
@ -92,7 +87,6 @@ private:
private: private:
bool m_renderToScreen { false }; bool m_renderToScreen { false };
uint8_t m_colorAttachmentCount { 1 };
uint32_t m_id { 0 }; uint32_t m_id { 0 };
uint32_t m_width { 0 }; uint32_t m_width { 0 };
uint32_t m_height { 0 }; uint32_t m_height { 0 };

26
src/inferno/render/render-command.cpp

@ -4,12 +4,10 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
#include <cstdint> // int32_t, uint32_t #include <memory> // std::shared_ptr
#include <memory> // std::shared_ptr
#include "glad/glad.h" #include "glad/glad.h"
#include "ruc/format/log.h" #include "ruc/format/log.h"
#include "ruc/meta/assert.h"
#include "inferno/render/buffer.h" #include "inferno/render/buffer.h"
#include "inferno/render/render-command.h" #include "inferno/render/render-command.h"
@ -44,7 +42,7 @@ void RenderCommand::clearColor(const glm::vec4& color)
void RenderCommand::drawIndexed(std::shared_ptr<VertexArray> vertexArray, uint32_t indexCount) void RenderCommand::drawIndexed(std::shared_ptr<VertexArray> vertexArray, uint32_t indexCount)
{ {
uint32_t count = indexCount ? indexCount : vertexArray->indexBuffer()->count(); uint32_t count = indexCount ? indexCount : vertexArray->getIndexBuffer()->getCount();
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, nullptr); glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, nullptr);
} }
@ -59,26 +57,6 @@ void RenderCommand::setDepthTest(bool enabled)
enabled ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST); 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() bool RenderCommand::depthTest()
{ {
unsigned char depthTest = GL_FALSE; unsigned char depthTest = GL_FALSE;

4
src/inferno/render/render-command.h

@ -6,8 +6,7 @@
#pragma once #pragma once
#include <cstdint> // int32_t, uint32_t #include <memory> // std::shadred_ptr
#include <memory> // std::shadred_ptr
#include "glm/ext/vector_float4.hpp" // glm::vec4 #include "glm/ext/vector_float4.hpp" // glm::vec4
@ -26,7 +25,6 @@ public:
static void setViewport(int32_t x, int32_t y, uint32_t width, uint32_t height); static void setViewport(int32_t x, int32_t y, uint32_t width, uint32_t height);
static void setDepthTest(bool enabled); static void setDepthTest(bool enabled);
static void setColorAttachmentCount(uint32_t count);
static bool depthTest(); static bool depthTest();
static int32_t textureUnitAmount(); static int32_t textureUnitAmount();

106
src/inferno/render/renderer.cpp

@ -8,7 +8,6 @@
#include <span> #include <span>
#include "glad/glad.h" #include "glad/glad.h"
#include "glm/ext/vector_float4.hpp" // glm::vec4
#include "ruc/format/log.h" #include "ruc/format/log.h"
#include "inferno/asset/asset-manager.h" #include "inferno/asset/asset-manager.h"
@ -171,7 +170,6 @@ void Renderer<T>::flush()
// Render // Render
bool depthTest = RenderCommand::depthTest(); bool depthTest = RenderCommand::depthTest();
RenderCommand::setDepthTest(m_enableDepthBuffer); RenderCommand::setDepthTest(m_enableDepthBuffer);
RenderCommand::setColorAttachmentCount(m_colorAttachmentCount);
RenderCommand::drawIndexed(m_vertexArray, m_elementIndex); RenderCommand::drawIndexed(m_vertexArray, m_elementIndex);
RenderCommand::setDepthTest(depthTest); RenderCommand::setDepthTest(depthTest);
@ -198,11 +196,6 @@ void Renderer<T>::nextBatch()
// ----------------------------------------- // -----------------------------------------
Renderer2D::Renderer2D(s) Renderer2D::Renderer2D(s)
{
Renderer2D::initialize();
}
void Renderer2D::initialize()
{ {
Renderer::initialize(); Renderer::initialize();
@ -222,21 +215,26 @@ void Renderer2D::initialize()
// --------------------------------- // ---------------------------------
// GPU // GPU
m_enableDepthBuffer = false;
// Create vertex buffer // Create vertex buffer
auto vertexBuffer = std::make_shared<VertexBuffer>(sizeof(QuadVertex) * maxVertices); auto vertexBuffer = std::make_shared<VertexBuffer>(sizeof(QuadVertex) * maxVertices);
vertexBuffer->setLayout({ vertexBuffer->setLayout({
{ BufferElementType::Vec3, "a_position" }, { BufferElementType::Vec3, "a_position" },
{ BufferElementType::Vec4, "a_color" }, { BufferElementType::Vec4, "a_color" },
{ BufferElementType::Vec2, "a_textureCoordinates" }, { BufferElementType::Vec2, "a_textureCoordinates" },
{ BufferElementType::Uint, "a_textureIndex" }, { BufferElementType::Float, "a_textureIndex" },
}); });
m_vertexArray->addVertexBuffer(vertexBuffer); m_vertexArray->addVertexBuffer(vertexBuffer);
ruc::info("Renderer2D initialized"); 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) void Renderer2D::drawQuad(const TransformComponent& transform, glm::vec4 color)
{ {
drawQuad(transform, color, nullptr); drawQuad(transform, color, nullptr);
@ -273,7 +271,7 @@ void Renderer2D::drawQuad(const TransformComponent& transform, glm::mat4 color,
m_vertexBufferPtr->position = transform.transform * m_vertexPositions[i]; m_vertexBufferPtr->position = transform.transform * m_vertexPositions[i];
m_vertexBufferPtr->color = color[i]; m_vertexBufferPtr->color = color[i];
m_vertexBufferPtr->textureCoordinates = textureCoordinates[i]; m_vertexBufferPtr->textureCoordinates = textureCoordinates[i];
m_vertexBufferPtr->textureIndex = textureUnitIndex; m_vertexBufferPtr->textureIndex = static_cast<float>(textureUnitIndex);
m_vertexBufferPtr++; m_vertexBufferPtr++;
} }
@ -283,17 +281,12 @@ void Renderer2D::drawQuad(const TransformComponent& transform, glm::mat4 color,
void Renderer2D::loadShader() void Renderer2D::loadShader()
{ {
m_shader = AssetManager::the().load<Shader>("assets/glsl/post-process"); m_shader = AssetManager::the().load<Shader>("assets/glsl/batch-quad");
} }
// ----------------------------------------- // -----------------------------------------
RendererCubemap::RendererCubemap(s) RendererCubemap::RendererCubemap(s)
{
RendererCubemap::initialize();
}
void RendererCubemap::initialize()
{ {
Renderer::initialize(); Renderer::initialize();
@ -352,7 +345,7 @@ void RendererCubemap::initialize()
vertexBuffer->setLayout({ vertexBuffer->setLayout({
{ BufferElementType::Vec3, "a_position" }, { BufferElementType::Vec3, "a_position" },
{ BufferElementType::Vec4, "a_color" }, { BufferElementType::Vec4, "a_color" },
{ BufferElementType::Uint, "a_textureIndex" }, { BufferElementType::Float, "a_textureIndex" },
}); });
m_vertexArray->addVertexBuffer(vertexBuffer); m_vertexArray->addVertexBuffer(vertexBuffer);
@ -367,10 +360,10 @@ void RendererCubemap::beginScene(glm::mat4 cameraProjection, glm::mat4 cameraVie
// x x x 0 // x x x 0
// x x x 0 // x x x 0
// 0 0 0 1 // 0 0 0 1
// cameraView = glm::mat4(glm::mat3(cameraView)); cameraView = glm::mat4(glm::mat3(cameraView));
m_shader->bind(); m_shader->bind();
m_shader->setFloat("u_projectionView2", cameraProjection * cameraView); m_shader->setFloat("u_projectionView", cameraProjection * cameraView);
m_shader->unbind(); m_shader->unbind();
} }
@ -393,7 +386,7 @@ void RendererCubemap::drawCubemap(const TransformComponent& transform, glm::mat4
for (uint32_t i = 0; i < vertexPerQuad * quadPerCube; i++) { for (uint32_t i = 0; i < vertexPerQuad * quadPerCube; i++) {
m_vertexBufferPtr->position = transform.transform * m_vertexPositions[i]; m_vertexBufferPtr->position = transform.transform * m_vertexPositions[i];
m_vertexBufferPtr->color = color[i % 4]; m_vertexBufferPtr->color = color[i % 4];
m_vertexBufferPtr->textureIndex = textureUnitIndex; m_vertexBufferPtr->textureIndex = static_cast<float>(textureUnitIndex);
m_vertexBufferPtr++; m_vertexBufferPtr++;
} }
@ -430,7 +423,7 @@ RendererFont::RendererFont(s)
{ BufferElementType::Vec3, "a_position" }, { BufferElementType::Vec3, "a_position" },
{ BufferElementType::Vec4, "a_color" }, { BufferElementType::Vec4, "a_color" },
{ BufferElementType::Vec2, "a_textureCoordinates" }, { BufferElementType::Vec2, "a_textureCoordinates" },
{ BufferElementType::Uint, "a_textureIndex" }, { BufferElementType::Float, "a_textureIndex" },
{ BufferElementType::Float, "a_width" }, { BufferElementType::Float, "a_width" },
{ BufferElementType::Float, "a_edge" }, { BufferElementType::Float, "a_edge" },
{ BufferElementType::Float, "a_borderWidth" }, { BufferElementType::Float, "a_borderWidth" },
@ -457,7 +450,7 @@ void RendererFont::drawSymbol(std::array<SymbolVertex, vertexPerQuad>& symbolQua
m_vertexBufferPtr->quad.position = symbolQuad[i].quad.position; m_vertexBufferPtr->quad.position = symbolQuad[i].quad.position;
m_vertexBufferPtr->quad.color = symbolQuad[i].quad.color; m_vertexBufferPtr->quad.color = symbolQuad[i].quad.color;
m_vertexBufferPtr->quad.textureCoordinates = symbolQuad[i].quad.textureCoordinates; m_vertexBufferPtr->quad.textureCoordinates = symbolQuad[i].quad.textureCoordinates;
m_vertexBufferPtr->quad.textureIndex = textureUnitIndex; m_vertexBufferPtr->quad.textureIndex = static_cast<float>(textureUnitIndex);
m_vertexBufferPtr->width = symbolQuad[i].width; m_vertexBufferPtr->width = symbolQuad[i].width;
m_vertexBufferPtr->edge = symbolQuad[i].edge; m_vertexBufferPtr->edge = symbolQuad[i].edge;
@ -495,28 +488,26 @@ Renderer3D::Renderer3D(s)
// GPU // GPU
m_enableDepthBuffer = true; m_enableDepthBuffer = true;
m_colorAttachmentCount = 3;
// Create vertex buffer // Create vertex buffer
auto vertexBuffer = std::make_shared<VertexBuffer>(sizeof(Vertex) * maxVertices); auto vertexBuffer = std::make_shared<VertexBuffer>(sizeof(Vertex) * maxVertices);
vertexBuffer->setLayout({ vertexBuffer->setLayout({
{ BufferElementType::Vec3, "a_position" }, { BufferElementType::Vec3, "a_position" },
{ BufferElementType::Vec3, "a_normal" }, { BufferElementType::Vec3, "a_normal" },
{ BufferElementType::Vec4, "a_color" },
{ BufferElementType::Vec2, "a_textureCoordinates" }, { BufferElementType::Vec2, "a_textureCoordinates" },
{ BufferElementType::Uint, "a_textureIndex" }, { BufferElementType::Float, "a_textureIndex" },
}); });
m_vertexArray->addVertexBuffer(vertexBuffer); m_vertexArray->addVertexBuffer(vertexBuffer);
ruc::info("Renderer3D initialized"); ruc::info("Renderer3D initialized");
} }
void Renderer3D::drawModel(std::span<const Vertex> vertices, std::span<const uint32_t> elements, const TransformComponent& transform, glm::vec4 color, std::shared_ptr<Texture> texture) void Renderer3D::drawModel(std::span<const Vertex> vertices, std::span<const uint32_t> elements, const TransformComponent& transform, std::shared_ptr<Texture> texture)
{ {
// ruc::error("drawModel"); // ruc::error("drawModel");
VERIFY(vertices.size() <= maxVertices, "model vertices too big for buffer, {}/{}", vertices.size(), maxVertices); VERIFY(vertices.size() <= maxVertices, "model vertices too big for buffer");
VERIFY(elements.size() <= maxElements, "model elements too big for buffer, {}/{}", elements.size(), maxElements); VERIFY(elements.size() <= maxElements, "model elements too big for buffer");
// Create a new batch if the quad limit has been reached // Create a new batch if the quad limit has been reached
if (m_vertexIndex + vertices.size() > maxVertices || m_elementIndex + elements.size() > maxElements) { if (m_vertexIndex + vertices.size() > maxVertices || m_elementIndex + elements.size() > maxElements) {
@ -526,13 +517,11 @@ void Renderer3D::drawModel(std::span<const Vertex> vertices, std::span<const uin
uint32_t textureUnitIndex = addTextureUnit(texture); uint32_t textureUnitIndex = addTextureUnit(texture);
// Add the vertices // Add the vertices
glm::mat3 normalMatrix = glm::mat3(glm::transpose(glm::inverse(transform.transform)));
for (const auto& vertex : vertices) { for (const auto& vertex : vertices) {
m_vertexBufferPtr->position = transform.transform * glm::vec4(vertex.position, 1.0f); m_vertexBufferPtr->position = transform.transform * glm::vec4(vertex.position, 1.0f);
m_vertexBufferPtr->normal = normalMatrix * vertex.normal; // take non-uniform scaling into consideration m_vertexBufferPtr->normal = vertex.normal;
m_vertexBufferPtr->color = color;
m_vertexBufferPtr->textureCoordinates = vertex.textureCoordinates; m_vertexBufferPtr->textureCoordinates = vertex.textureCoordinates;
m_vertexBufferPtr->textureIndex = textureUnitIndex; m_vertexBufferPtr->textureIndex = static_cast<float>(textureUnitIndex);
m_vertexBufferPtr++; m_vertexBufferPtr++;
} }
@ -547,6 +536,13 @@ void Renderer3D::drawModel(std::span<const Vertex> vertices, std::span<const uin
m_elementIndex += elements.size(); 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() void Renderer3D::createElementBuffer()
{ {
// --------------------------------- // ---------------------------------
@ -566,7 +562,7 @@ void Renderer3D::createElementBuffer()
void Renderer3D::uploadElementBuffer() void Renderer3D::uploadElementBuffer()
{ {
m_vertexArray->indexBuffer()->uploadData(m_elementBufferBase, m_elementIndex * sizeof(uint32_t)); m_vertexArray->getIndexBuffer()->uploadData(m_elementBufferBase, m_elementIndex * sizeof(uint32_t));
} }
void Renderer3D::loadShader() void Renderer3D::loadShader()
@ -580,46 +576,4 @@ void Renderer3D::startBatch()
m_elementBufferPtr = m_elementBufferBase; m_elementBufferPtr = m_elementBufferBase;
} }
// -----------------------------------------
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()
{
ruc::error("POSTPROCESSING!");
m_shader = AssetManager::the().load<Shader>("assets/glsl/post-process");
}
// -----------------------------------------
void RendererLightCube::loadShader()
{
m_shader = AssetManager::the().load<Shader>("assets/glsl/lightsource");
}
} // namespace Inferno } // namespace Inferno

95
src/inferno/render/renderer.h

@ -24,16 +24,16 @@ class TransformComponent;
class VertexArray; class VertexArray;
struct QuadVertex { struct QuadVertex {
glm::vec3 position { 0.0f }; glm::vec3 position { 0.0f, 0.0f, 0.0f };
glm::vec4 color { 1.0f }; glm::vec4 color { 1.0f, 1.0f, 1.0f, 1.0f };
glm::vec2 textureCoordinates { 0.0f }; glm::vec2 textureCoordinates { 0.0f, 0.0f };
uint32_t textureIndex { 0 }; float textureIndex = 0;
}; };
struct CubemapVertex { struct CubemapVertex {
glm::vec3 position { 0.0f }; glm::vec3 position { 0.0f, 0.0f, 0.0f };
glm::vec4 color { 1.0f }; glm::vec4 color { 1.0f, 1.0f, 1.0f, 1.0f };
uint32_t textureIndex { 0 }; float textureIndex = 0;
}; };
struct SymbolVertex { struct SymbolVertex {
@ -45,17 +45,16 @@ struct SymbolVertex {
// Outline // Outline
float borderWidth = 0.7f; float borderWidth = 0.7f;
float borderEdge = 0.1f; float borderEdge = 0.1f;
glm::vec4 borderColor { 1.0f }; glm::vec4 borderColor { 1.0f, 1.0f, 1.0f, 1.0f };
// Dropshadow // Dropshadow
float offset = 0.0f; float offset = 0.0f;
}; };
struct Vertex { struct Vertex {
glm::vec3 position { 0.0f }; glm::vec3 position { 0.0f, 0.0f, 0.0f };
glm::vec3 normal { 1.0f }; glm::vec3 normal { 1.0f, 1.0f, 1.0f };
glm::vec4 color { 1.0f }; glm::vec2 textureCoordinates { 0.0f, 0.0f };
glm::vec2 textureCoordinates { 0.0f }; float textureIndex = 0;
uint32_t textureIndex { 0 };
}; };
// ------------------------------------- // -------------------------------------
@ -112,7 +111,6 @@ protected:
// GPU objects // GPU objects
bool m_enableDepthBuffer { true }; bool m_enableDepthBuffer { true };
uint32_t m_colorAttachmentCount { 1 };
std::shared_ptr<Shader> m_shader; std::shared_ptr<Shader> m_shader;
std::shared_ptr<VertexArray> m_vertexArray; std::shared_ptr<VertexArray> m_vertexArray;
}; };
@ -125,7 +123,7 @@ protected:
// ------------------------------------- // -------------------------------------
class Renderer2D class Renderer2D final
: public Renderer<QuadVertex> : public Renderer<QuadVertex>
, public ruc::Singleton<Renderer2D> { , public ruc::Singleton<Renderer2D> {
public: public:
@ -134,25 +132,22 @@ public:
using Singleton<Renderer2D>::destroy; 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::vec4 color);
void drawQuad(const TransformComponent& transform, glm::mat4 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::vec4 color, std::shared_ptr<Texture> texture);
void drawQuad(const TransformComponent& transform, glm::mat4 color, std::shared_ptr<Texture> texture); void drawQuad(const TransformComponent& transform, glm::mat4 color, std::shared_ptr<Texture> texture);
protected: private:
Renderer2D() { Renderer2D::initialize(); } // Needed for derived classes void loadShader() override;
void initialize();
// Default quad vertex positions // Default quad vertex positions
glm::vec4 m_vertexPositions[vertexPerQuad]; glm::vec4 m_vertexPositions[vertexPerQuad];
private:
virtual void loadShader() override;
}; };
// ------------------------------------- // -------------------------------------
class RendererCubemap class RendererCubemap final
: public Renderer<CubemapVertex> : public Renderer<CubemapVertex>
, public ruc::Singleton<RendererCubemap> { , public ruc::Singleton<RendererCubemap> {
public: public:
@ -169,13 +164,8 @@ public:
void drawCubemap(const TransformComponent& transform, glm::vec4 color, std::shared_ptr<Texture> texture); 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); void drawCubemap(const TransformComponent& transform, glm::mat4 color, std::shared_ptr<Texture> texture);
protected:
RendererCubemap() { RendererCubemap::initialize(); } // Needed for derived classes
void initialize();
private: private:
virtual void loadShader() override; void loadShader() override;
// Default cubemap vertex positions // Default cubemap vertex positions
glm::vec4 m_vertexPositions[vertexPerQuad * quadPerCube]; glm::vec4 m_vertexPositions[vertexPerQuad * quadPerCube];
@ -209,7 +199,9 @@ public:
using Singleton<Renderer3D>::destroy; using Singleton<Renderer3D>::destroy;
void drawModel(std::span<const Vertex> vertices, std::span<const uint32_t> indices, const TransformComponent& transform, glm::vec4 color, std::shared_ptr<Texture> texture); 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);
private: private:
void createElementBuffer() override; void createElementBuffer() override;
@ -223,47 +215,4 @@ private:
uint32_t* m_elementBufferPtr { nullptr }; uint32_t* m_elementBufferPtr { nullptr };
}; };
// -----------------------------------------
class RendererPostProcess final
: public Renderer2D
, public ruc::Singleton<RendererPostProcess> {
public:
RendererPostProcess(ruc::Singleton<RendererPostProcess>::s)
: Renderer2D()
{
}
virtual ~RendererPostProcess() = default;
using Singleton<RendererPostProcess>::the;
using Singleton<RendererPostProcess>::destroy;
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:
RendererLightCube(ruc::Singleton<RendererLightCube>::s)
: RendererCubemap()
{
m_enableDepthBuffer = true;
}
virtual ~RendererLightCube() = default;
using Singleton<RendererLightCube>::the;
using Singleton<RendererLightCube>::destroy;
void beginScene(glm::mat4, glm::mat4) override {}
private:
virtual void loadShader() override;
};
} // namespace Inferno } // namespace Inferno

240
src/inferno/render/uniformbuffer.cpp

@ -1,240 +0,0 @@
/*
* 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;
// 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

130
src/inferno/render/uniformbuffer.h

@ -1,130 +0,0 @@
/*
* Copyright (C) 2024 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#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 "glm/ext/vector_float3.hpp" // glm::vec3
#include "ruc/singleton.h"
#include "inferno/render/buffer.h"
#define CHECK_SET_CALL(blockName, member) \
VERIFY(exists(blockName), "uniformbuffer block doesnt exist"); \
const UniformbufferBlock& block = m_blocks[blockName]; \
VERIFY(block.uniformLocations.find(member.data()) != block.uniformLocations.end(), \
"uniformbuffer block member doesnt exist");
namespace Inferno {
// Uniform block layouts, using std140 memory layout rules
#define MAX_DIRECTIONAL_LIGHTS 32
struct UniformDirectionalLight {
glm::vec3 direction { 0 };
float __padding0 { 0 };
glm::vec3 ambient { 0 };
float __padding1 { 0 };
glm::vec3 diffuse { 0 };
float __padding2 { 0 };
glm::vec3 specular { 0 };
float __padding3 { 0 };
};
// -----------------------------------------
struct UniformbufferBlock {
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_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)

5
src/inferno/scene/scene.cpp

@ -9,7 +9,7 @@
#include <limits> // std::numeric_limits #include <limits> // std::numeric_limits
#include <utility> // std::pair #include <utility> // std::pair
#include "entt/entity/fwd.hpp" // ent::entity #include "entt/entity/entity.hpp" // ent::entity
#include "ruc/file.h" #include "ruc/file.h"
#include "ruc/format/log.h" #include "ruc/format/log.h"
#include "ruc/json/json.h" #include "ruc/json/json.h"
@ -25,8 +25,6 @@
#include "inferno/component/tagcomponent.h" #include "inferno/component/tagcomponent.h"
#include "inferno/component/textareacomponent.h" #include "inferno/component/textareacomponent.h"
#include "inferno/component/transformcomponent.h" #include "inferno/component/transformcomponent.h"
#include "inferno/render/renderer.h"
#include "inferno/render/uniformbuffer.h"
#include "inferno/scene/scene.h" #include "inferno/scene/scene.h"
#include "inferno/script/nativescript.h" #include "inferno/script/nativescript.h"
#include "inferno/system/camerasystem.h" #include "inferno/system/camerasystem.h"
@ -86,6 +84,7 @@ void Scene::update(float deltaTime)
void Scene::render() void Scene::render()
{ {
RenderSystem::the().render(); RenderSystem::the().render();
TextAreaSystem::the().render();
} }
void Scene::destroy() void Scene::destroy()

13
src/inferno/system/camerasystem.cpp

@ -53,23 +53,10 @@ std::pair<glm::mat4, glm::mat4> CameraSystem::projectionView()
} }
VERIFY_NOT_REACHED(); 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 {}; return {};
} }
// -----------------------------------------
void CameraSystem::updateOrthographic(TransformComponent& transform, CameraComponent& camera) void CameraSystem::updateOrthographic(TransformComponent& transform, CameraComponent& camera)
{ {
// Update camera matrix // Update camera matrix

1
src/inferno/system/camerasystem.h

@ -32,7 +32,6 @@ public:
* @brief Return a pair from the camera component: { projection, view } * @brief Return a pair from the camera component: { projection, view }
*/ */
std::pair<glm::mat4, glm::mat4> projectionView(); std::pair<glm::mat4, glm::mat4> projectionView();
glm::vec3 translate();
void setRegistry(std::shared_ptr<entt::registry> registry) { m_registry = registry; }; void setRegistry(std::shared_ptr<entt::registry> registry) { m_registry = registry; };

178
src/inferno/system/rendersystem.cpp

@ -4,148 +4,41 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
#include <cstdint> // int32_t #include "glm/ext/matrix_transform.hpp" // glm::translate, glm::rotate, glm::scale, glm::radians
#include "inferno/component/model-component.h"
#include "glad/glad.h"
#include "ruc/format/log.h" #include "ruc/format/log.h"
#include "inferno/component/cubemap-component.h" #include "inferno/component/cubemap-component.h"
#include "inferno/component/model-component.h" #include "inferno/component/model-component.h"
#include "inferno/component/spritecomponent.h" #include "inferno/component/spritecomponent.h"
#include "inferno/component/transformcomponent.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/renderer.h"
#include "inferno/render/uniformbuffer.h"
#include "inferno/system/camerasystem.h"
#include "inferno/system/rendersystem.h" #include "inferno/system/rendersystem.h"
#include "inferno/system/textareasystem.h"
namespace Inferno { namespace Inferno {
RenderSystem::RenderSystem(s) RenderSystem::RenderSystem(s)
{ {
ruc::info("RenderSystem initialized");
} }
RenderSystem::~RenderSystem() 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");
Uniformbuffer::the().setLayout(
"DirectionalLights",
{
.size = sizeof(UniformDirectionalLight) * MAX_DIRECTIONAL_LIGHTS,
.bindingPoint = 1,
.uniformLocations = {
{ "u_directionalLight", 0 },
},
});
Uniformbuffer::the().create("DirectionalLights");
ruc::info("RenderSystem initialized");
}
void RenderSystem::render() void RenderSystem::render()
{ {
static constexpr TransformComponent transformIdentity; auto quadView = m_registry->view<TransformComponent, SpriteComponent>();
// ---------------------------------
// Deferred rendering to a framebuffer
framebufferSetup(m_framebuffer);
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); for (auto [entity, transform, sprite] : quadView.each()) {
} Renderer2D::the().drawQuad(transform, sprite.color, sprite.texture);
}
void RenderSystem::renderGeometry() auto cubemapView = m_registry->view<TransformComponent, CubemapComponent>();
{
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 UniformDirectionalLight directionalLights[1] = { for (auto [entity, transform, cubemap] : cubemapView.each()) {
{ RendererCubemap::the().drawCubemap(transform, cubemap.color, cubemap.texture);
.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 },
},
};
Uniformbuffer::the().setValue("DirectionalLights", "u_directionalLight", directionalLights);
auto modelView = m_registry->view<TransformComponent, ModelComponent>(); auto modelView = m_registry->view<TransformComponent, ModelComponent>();
@ -153,57 +46,8 @@ void RenderSystem::renderGeometry()
Renderer3D::the().drawModel(model.model->vertices(), Renderer3D::the().drawModel(model.model->vertices(),
model.model->elements(), model.model->elements(),
transform, transform,
model.color,
model.model->texture() ? model.model->texture() : model.texture); 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 } // namespace Inferno

22
src/inferno/system/rendersystem.h

@ -6,39 +6,25 @@
#pragma once #pragma once
#include <cstdint> // int32_t, uint32_t #include <memory> //std::shared_ptr
#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 "ruc/singleton.h"
namespace Inferno { #include "inferno/render/renderer.h"
class Framebuffer; namespace Inferno {
class RenderSystem final : public ruc::Singleton<RenderSystem> { class RenderSystem final : public ruc::Singleton<RenderSystem> {
public: public:
RenderSystem(s); RenderSystem(s);
virtual ~RenderSystem(); virtual ~RenderSystem();
void initialize(uint32_t width, uint32_t height);
void render(); void render();
void resize(int32_t width, int32_t height);
void setRegistry(std::shared_ptr<entt::registry> registry) { m_registry = registry; }; void setRegistry(std::shared_ptr<entt::registry> registry) { m_registry = registry; };
private: 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; std::shared_ptr<entt::registry> m_registry;
}; };

6
src/inferno/window.cpp

@ -122,17 +122,17 @@ void Window::initialize()
switch (action) { switch (action) {
case GLFW_PRESS: { case GLFW_PRESS: {
KeyPressEvent event(key, mods); KeyPressEvent event(key);
w.m_eventCallback(event); w.m_eventCallback(event);
break; break;
} }
case GLFW_RELEASE: { case GLFW_RELEASE: {
KeyReleaseEvent event(key, mods); KeyReleaseEvent event(key);
w.m_eventCallback(event); w.m_eventCallback(event);
break; break;
} }
case GLFW_REPEAT: { case GLFW_REPEAT: {
KeyRepeatEvent event(key, mods); KeyRepeatEvent event(key);
w.m_eventCallback(event); w.m_eventCallback(event);
break; break;
} }

Loading…
Cancel
Save