Browse Source

Asset+Render+App: Implement render to framebuffer

master
Riyyi 3 months ago
parent
commit
cd36841039
  1. 8
      assets/scene/scene1.json
  2. 33
      src/inferno/application.cpp
  3. 3
      src/inferno/application.h
  4. 8
      src/inferno/asset/asset-manager.cpp
  5. 12
      src/inferno/asset/asset-manager.h
  6. 22
      src/inferno/asset/texture.cpp
  7. 8
      src/inferno/asset/texture.h
  8. 85
      src/inferno/render/framebuffer.cpp
  9. 20
      src/inferno/render/framebuffer.h
  10. 7
      src/inferno/render/render-command.cpp
  11. 3
      src/inferno/render/render-command.h
  12. 32
      src/inferno/render/renderer.cpp
  13. 2
      src/inferno/render/renderer.h

8
assets/scene/scene1.json

@ -44,7 +44,7 @@
"id": { "id": 97897897 },
"tag": { "tag": "Quad 2" },
"transform" : {
"translate": [ 1.1, 0.0, 0.0 ],
"translate": [ 2.5, 0.0, 0.0 ],
"rotate": [ 0.0, 0.0, 0.0 ],
"scale": [ 1.0, 1.0, 1.0 ]
},
@ -57,7 +57,7 @@
"id": { "id": 3424242 },
"tag": { "tag": "Quad 3" },
"transform" : {
"translate": [ 2.2, 1.0, 0.0 ],
"translate": [ 5.0, 1.0, 0.0 ],
"rotate": [ 0.0, 0.0, -20.0 ],
"scale": [ 1.0, 1.0, 1.0 ]
},
@ -70,7 +70,7 @@
"id": { "id": 4345472 },
"tag": { "tag": "Quad 4" },
"transform" : {
"translate": [ 0.85, 0.0, 0.0 ],
"translate": [ 1.7, 0.0, 0.0 ],
"rotate": [ 0.0, 0.0, 0.0 ],
"scale": [ 0.5, 0.5, 1.0 ]
},
@ -83,7 +83,7 @@
"id": { "id": 5234723 },
"tag": { "tag": "Quad 5" },
"transform" : {
"translate": [ 1.0, 0.0, 0.0 ],
"translate": [ 2.0, 0.0, 0.0 ],
"rotate": [ 0.0, 0.0, -20.0 ],
"scale": [ 0.5, 0.5, 1.0 ]
},

33
src/inferno/application.cpp

@ -6,11 +6,13 @@
#include <utility> // std::pair
#include "glm/ext/vector_float3.hpp"
#include "glm/gtc/type_ptr.hpp" // glm::make_mat4
#include "ruc/format/log.h"
#include "ruc/meta/assert.h"
#include "inferno/application.h"
#include "inferno/component/transformcomponent.h"
#include "inferno/core.h"
#include "inferno/event/applicationevent.h"
#include "inferno/event/event.h"
@ -20,6 +22,7 @@
#include "inferno/keycodes.h"
#include "inferno/render/buffer.h"
#include "inferno/render/context.h"
#include "inferno/render/framebuffer.h"
// #include "inferno/render/gltf.h"
#include "inferno/asset/shader.h"
#include "inferno/asset/texture.h"
@ -50,6 +53,11 @@ Application::Application()
Input::initialize();
RenderCommand::initialize();
m_framebuffer = std::make_unique<Framebuffer>(
Framebuffer::Properties { .type = Framebuffer::Type::Color | Framebuffer::Type::Depth | Framebuffer::Type::Stencil,
.width = m_window->getWidth(),
.height = m_window->getHeight() });
m_scene = std::make_shared<Scene>();
m_scene->initialize();
@ -141,6 +149,10 @@ int Application::run()
// offset
#endif
constexpr glm::vec4 vectorOne { 1.0f, 1.0f, 1.0f, 1.0f };
constexpr glm::mat4 matIdentity { 1.0f };
constexpr TransformComponent transformIdentity;
// m_window->setVSync(false);
while (!m_window->shouldClose()) {
@ -149,6 +161,7 @@ int Application::run()
m_lastFrameTime = time;
// ruc::debug("Frametime {}ms", deltaTime * 1000);
// ---------------------------------
// Update
update();
@ -157,12 +170,15 @@ int Application::run()
m_window->update();
m_scene->update(deltaTime);
// ---------------------------------
// Render
m_framebuffer->bind();
render();
RenderCommand::clearColor({ 0.2f, 0.3f, 0.3f, 1.0f });
RenderCommand::clear();
RenderCommand::clearColorDepthBit();
std::pair<glm::mat4, glm::mat4> projectionView = m_scene->cameraProjectionView();
RendererCubemap::the().beginScene(projectionView.first, projectionView.second); // camera, lights, environment
@ -178,6 +194,20 @@ int Application::run()
Renderer2D::the().endScene();
RendererFont::the().endScene();
m_framebuffer->unbind();
// ---------------------------------
// Framebuffer
RenderCommand::clearColor({ 1.0f, 1.0f, 1.0f, 1.0f });
RenderCommand::clearColorBit();
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_window->render();
}
@ -212,6 +242,7 @@ bool Application::onWindowResize(WindowResizeEvent& e)
ruc::info("WindowResizeEvent {}x{}", e.getWidth(), e.getHeight());
RenderCommand::setViewport(0, 0, e.getWidth(), e.getHeight());
m_framebuffer->setSize(e.getWidth(), e.getHeight());
return true;
}

3
src/inferno/application.h

@ -12,12 +12,14 @@ namespace Inferno {
class Event;
class Font;
class Framebuffer;
class KeyPressEvent;
class MousePositionEvent;
class Scene;
class Window;
class WindowCloseEvent;
class WindowResizeEvent;
struct TransformComponent;
class Application {
public:
@ -50,6 +52,7 @@ private:
std::unique_ptr<Window> m_window;
std::shared_ptr<Scene> m_scene;
std::unique_ptr<Framebuffer> m_framebuffer;
//
std::shared_ptr<Font> m_font;

8
src/inferno/asset/asset-manager.cpp

@ -38,18 +38,22 @@ bool AssetManager::exists(std::string_view path)
return m_assetList.find(path.data()) != m_assetList.end();
}
void AssetManager::remove(std::string_view path)
std::nullptr_t AssetManager::remove(std::string_view path)
{
if (exists(path)) {
m_assetList.erase(path.data());
}
return nullptr;
}
void AssetManager::remove(std::shared_ptr<Asset> asset)
std::nullptr_t AssetManager::remove(std::shared_ptr<Asset> asset)
{
if (exists(asset->path())) {
m_assetList.erase(asset->path());
}
return nullptr;
}
} // namespace Inferno

12
src/inferno/asset/asset-manager.h

@ -6,10 +6,12 @@
#pragma once
#include <cstddef> // std::nullptr_t
#include <memory> // std::shared_ptr
#include <string>
#include <string_view>
#include <unordered_map>
#include <utility> // std::forward
#include "ruc/meta/assert.h"
#include "ruc/meta/types.h"
@ -62,8 +64,8 @@ public:
void add(std::string_view path, std::shared_ptr<Asset> asset);
bool exists(std::string_view path);
void remove(std::string_view path);
void remove(std::shared_ptr<Asset> asset);
std::nullptr_t remove(std::string_view path);
std::nullptr_t remove(std::shared_ptr<Asset> asset);
template<IsAsset T>
std::shared_ptr<T> get(std::string_view path)
@ -77,14 +79,14 @@ public:
return std::static_pointer_cast<T>(asset);
}
template<IsAsset T>
std::shared_ptr<T> load(std::string_view path)
template<IsAsset T, typename... Args>
std::shared_ptr<T> load(std::string_view path, Args&&... args)
{
if (exists(path)) {
return get<T>(path);
}
auto asset = T::create(path);
auto asset = T::create(path, std::forward<Args>(args)...);
add(path, asset);
return asset;
}

22
src/inferno/asset/texture.cpp

@ -234,9 +234,11 @@ void TextureCubemap::createImpl()
// -----------------------------------------
std::shared_ptr<TextureFramebuffer> TextureFramebuffer::create(uint32_t width, uint32_t height, uint32_t internalFormat, uint32_t dataFormat, uint32_t dataType)
std::shared_ptr<TextureFramebuffer> TextureFramebuffer::create(
std::string_view path,
uint32_t width, uint32_t height, uint32_t internalFormat, uint32_t dataFormat, uint32_t dataType)
{
auto result = std::shared_ptr<TextureFramebuffer>(new TextureFramebuffer(""));
auto result = std::shared_ptr<TextureFramebuffer>(new TextureFramebuffer(path));
result->init(width, height, internalFormat, dataFormat, dataType);
result->createImpl();
@ -244,6 +246,22 @@ std::shared_ptr<TextureFramebuffer> TextureFramebuffer::create(uint32_t width, u
return result;
}
void TextureFramebuffer::bind(uint32_t unit) const
{
// Set active unit
glActiveTexture(GL_TEXTURE0 + unit);
glBindTexture(GL_TEXTURE_2D, m_id);
// Reset unit
glActiveTexture(GL_TEXTURE0);
}
void TextureFramebuffer::unbind() const
{
glBindTexture(GL_TEXTURE_2D, 0);
}
void TextureFramebuffer::createImpl()
{
m_id = UINT_MAX;

8
src/inferno/asset/texture.h

@ -112,11 +112,11 @@ public:
// Factory function
static std::shared_ptr<TextureFramebuffer> create(
uint32_t width, uint32_t height,
uint32_t internalFormat, uint32_t dataFormat, uint32_t dataType = GL_UNSIGNED_BYTE);
std::string_view path,
uint32_t width, uint32_t height, uint32_t internalFormat, uint32_t dataFormat, uint32_t dataType = GL_UNSIGNED_BYTE);
virtual void bind(uint32_t) const override {}
virtual void unbind() const override {}
virtual void bind(uint32_t unit) const override;
virtual void unbind() const override;
private:
TextureFramebuffer(std::string_view path)

85
src/inferno/render/framebuffer.cpp

@ -7,7 +7,6 @@
#include <cstdint> // int8_t
#include "glad/glad.h"
#include "ruc/format/log.h"
#include "ruc/meta/assert.h"
#include "inferno/asset/texture.h"
@ -16,40 +15,17 @@
namespace Inferno {
Framebuffer::Framebuffer(const Properties& init)
: m_type(init.type)
, m_width(init.width)
, m_height(init.height)
{
VERIFY(static_cast<int8_t>(init.type) != 0,
"malformed framebuffer type: {}", init.type);
m_id = UINT_MAX;
glGenFramebuffers(1, &m_id);
bind();
if (init.type & Type::Color) {
ruc::error("color!");
// Set color attachment 0 out of 32
m_textures[0] = TextureFramebuffer::create(init.width, init.height, GL_RGB, GL_RGB);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_textures[0]->id(), 0);
}
// This combined texture is required for older GPUs
if (init.type & Type::Depth && init.type & Stencil) {
ruc::error("both!");
m_textures[3] = TextureFramebuffer::create(init.width, init.height, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_textures[3]->id(), 0);
}
else if (init.type & Type::Depth) {
ruc::error("depth!");
m_textures[1] = TextureFramebuffer::create(init.width, init.height, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_textures[1]->id(), 0);
}
else if (init.type & Type::Stencil) {
ruc::error("stencil!");
m_textures[2] = TextureFramebuffer::create(init.width, init.height, GL_STENCIL_INDEX, GL_STENCIL_INDEX);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_textures[2]->id(), 0);
}
check();
unbind();
createTextures();
}
Framebuffer::~Framebuffer()
@ -76,4 +52,57 @@ void Framebuffer::unbind() const
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void Framebuffer::setSize(uint32_t width, uint32_t height)
{
if (m_width == width && m_height == height) {
return;
}
m_width = width;
m_height = height;
createTextures();
}
// -----------------------------------------
void Framebuffer::createTextures()
{
bind();
m_textures[0] = AssetManager::the().remove(FRAMEBUFFER_TEXTURE_COLOR);
m_textures[1] = AssetManager::the().remove(FRAMEBUFFER_TEXTURE_DEPTH);
m_textures[2] = AssetManager::the().remove(FRAMEBUFFER_TEXTURE_STENCIL);
m_textures[3] = AssetManager::the().remove(FRAMEBUFFER_TEXTURE_DEPTH_STENCIL);
if (m_type & Type::Color) {
// Set color attachment 0 out of 32
m_textures[0] = AssetManager::the().load<TextureFramebuffer>(
FRAMEBUFFER_TEXTURE_COLOR, m_width, m_height, GL_RGB, GL_RGB);
m_textures[0]->bind(0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_textures[0]->id(), 0);
m_textures[0]->unbind();
}
// This combined texture is required for older GPUs
if (m_type & Type::Depth && m_type & Stencil) {
m_textures[3] = AssetManager::the().load<TextureFramebuffer>(
FRAMEBUFFER_TEXTURE_DEPTH_STENCIL, 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[3]->id(), 0);
}
else if (m_type & Type::Depth) {
m_textures[1] = AssetManager::the().load<TextureFramebuffer>(
FRAMEBUFFER_TEXTURE_DEPTH, m_width, m_height, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_textures[1]->id(), 0);
}
else if (m_type & Type::Stencil) {
m_textures[2] = AssetManager::the().load<TextureFramebuffer>(
FRAMEBUFFER_TEXTURE_STENCIL, m_width, m_height, GL_STENCIL_INDEX, GL_STENCIL_INDEX);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_textures[2]->id(), 0);
}
check();
unbind();
}
} // namespace Inferno

20
src/inferno/render/framebuffer.h

@ -12,6 +12,12 @@
#include "inferno/asset/texture.h"
#include "ruc/meta/core.h"
// AssetManager paths to the global framebuffer textures
#define FRAMEBUFFER_TEXTURE_COLOR "@framebuffer-color"
#define FRAMEBUFFER_TEXTURE_DEPTH "@framebuffer-depth"
#define FRAMEBUFFER_TEXTURE_STENCIL "@framebuffer-stencil"
#define FRAMEBUFFER_TEXTURE_DEPTH_STENCIL "@framebuffer-depth-stencil"
namespace Inferno {
class Framebuffer final { // Frame Buffer Object, FBO
@ -37,7 +43,21 @@ public:
void bind() const;
void unbind() const;
void setSize(uint32_t width, uint32_t height);
Type type() const { return m_type; }
uint32_t width() const { return m_width; }
uint32_t height() const { return m_height; }
uint32_t id() const { return m_id; }
std::shared_ptr<TextureFramebuffer> texture(uint8_t index) const { return m_textures[index]; }
private:
void createTextures();
private:
Type m_type { None };
uint32_t m_width { 0 };
uint32_t m_height { 0 };
uint32_t m_id { 0 };
std::shared_ptr<TextureFramebuffer> m_textures[4] { nullptr, nullptr, nullptr, nullptr };
};

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

@ -29,11 +29,16 @@ void RenderCommand::destroy()
{
}
void RenderCommand::clear()
void RenderCommand::clearColorDepthBit()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void RenderCommand::clearColorBit()
{
glClear(GL_COLOR_BUFFER_BIT);
}
void RenderCommand::clearColor(const glm::vec4& color)
{
glClearColor(color.r, color.g, color.b, color.a);

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

@ -19,7 +19,8 @@ public:
static void initialize();
static void destroy();
static void clear();
static void clearColorDepthBit();
static void clearColorBit();
static void clearColor(const glm::vec4& color);
static void drawIndexed(std::shared_ptr<VertexArray> vertexArray, uint32_t indexCount = 0);

32
src/inferno/render/renderer.cpp

@ -124,8 +124,8 @@ void Renderer<T>::unbind()
template<typename T>
void Renderer<T>::createElementBuffer()
{
// CPU
// ---------------------------------
// CPU
// Generate indices
@ -143,8 +143,8 @@ void Renderer<T>::createElementBuffer()
offset += vertexPerQuad;
}
// GPU
// ---------------------------------
// GPU
// Create index buffer
auto indexBuffer = std::make_shared<IndexBuffer>(elements, sizeof(uint32_t) * maxElements);
@ -199,21 +199,21 @@ Renderer2D::Renderer2D(s)
{
Renderer::initialize();
// CPU
// ---------------------------------
// CPU
// Create array for storing quads vertices
m_vertexBufferBase = new QuadVertex[maxVertices];
m_vertexBufferPtr = m_vertexBufferBase;
// Set default quad vertex positions
m_vertexPositions[0] = { -0.5f, -0.5f, 0.0f, 1.0f };
m_vertexPositions[1] = { 0.5f, -0.5f, 0.0f, 1.0f };
m_vertexPositions[2] = { 0.5f, 0.5f, 0.0f, 1.0f };
m_vertexPositions[3] = { -0.5f, 0.5f, 0.0f, 1.0f };
m_vertexPositions[0] = { -1.0f, -1.0f, 0.0f, 1.0f };
m_vertexPositions[1] = { 1.0f, -1.0f, 0.0f, 1.0f };
m_vertexPositions[2] = { 1.0f, 1.0f, 0.0f, 1.0f };
m_vertexPositions[3] = { -1.0f, 1.0f, 0.0f, 1.0f };
// GPU
// ---------------------------------
// GPU
// Create vertex buffer
auto vertexBuffer = std::make_shared<VertexBuffer>(sizeof(QuadVertex) * maxVertices);
@ -290,8 +290,8 @@ RendererCubemap::RendererCubemap(s)
{
Renderer::initialize();
// CPU
// ---------------------------------
// CPU
// Create array for storing quads vertices
m_vertexBufferBase = new CubemapVertex[maxVertices];
@ -335,8 +335,8 @@ RendererCubemap::RendererCubemap(s)
m_vertexPositions[22] = { 0.5f, -0.5f, 0.5f, 1.0f };
m_vertexPositions[23] = { 0.5f, -0.5f, -0.5f, 1.0f };
// GPU
// ---------------------------------
// GPU
m_enableDepthBuffer = false;
@ -405,15 +405,15 @@ RendererFont::RendererFont(s)
{
Renderer::initialize();
// CPU
// ---------------------------------
// CPU
// Create array for storing quads vertices
m_vertexBufferBase = new SymbolVertex[maxVertices];
m_vertexBufferPtr = m_vertexBufferBase;
// GPU
// ---------------------------------
// GPU
m_enableDepthBuffer = false;
@ -477,15 +477,15 @@ Renderer3D::Renderer3D(s)
{
Renderer::initialize();
// CPU
// ---------------------------------
// CPU
// Create array for storing quads vertices
m_vertexBufferBase = new Vertex[maxVertices];
m_vertexBufferPtr = m_vertexBufferBase;
// GPU
// ---------------------------------
// GPU
m_enableDepthBuffer = true;
@ -545,15 +545,15 @@ void Renderer3D::beginScene(glm::mat4 cameraProjection, glm::mat4 cameraView)
void Renderer3D::createElementBuffer()
{
// CPU
// ---------------------------------
// CPU
// Create array for storing quads vertices
m_elementBufferBase = new uint32_t[maxElements];
m_elementBufferPtr = m_elementBufferBase;
// GPU
// ---------------------------------
// GPU
// Create index buffer
auto indexBuffer = std::make_shared<IndexBuffer>(m_elementBufferBase, sizeof(uint32_t) * maxElements);

2
src/inferno/render/renderer.h

@ -76,6 +76,8 @@ public:
virtual void beginScene(glm::mat4 cameraProjection, glm::mat4 cameraView);
virtual void endScene();
void setEnableDepthBuffer(bool state) { m_enableDepthBuffer = state; }
protected:
Renderer() {}
virtual ~Renderer() { destroy(); };

Loading…
Cancel
Save