Browse Source

Asset+Render: Add Framebuffers

master
Riyyi 3 months ago
parent
commit
538d0b5ce7
  1. 1
      src/inferno/asset/asset-manager.h
  2. 68
      src/inferno/asset/texture.cpp
  3. 50
      src/inferno/asset/texture.h
  4. 13
      src/inferno/render/buffer.cpp
  5. 16
      src/inferno/render/buffer.h
  6. 62
      src/inferno/render/framebuffer.cpp
  7. 43
      src/inferno/render/framebuffer.h

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

@ -36,6 +36,7 @@ public:
virtual bool isTexture() const { return false; } virtual bool isTexture() const { return false; }
virtual bool isTexture2D() const { return false; } virtual bool isTexture2D() const { return false; }
virtual bool isTextureCubemap() const { return false; } virtual bool isTextureCubemap() const { return false; }
virtual bool isTextureFramebuffer() const { return false; }
protected: protected:
Asset(std::string_view path) Asset(std::string_view path)

68
src/inferno/asset/texture.cpp

@ -24,12 +24,20 @@ Texture::~Texture()
} }
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,
(channels == 3) ? GL_RGB8 : GL_RGBA8,
(channels == 3) ? GL_RGB : GL_RGBA,
GL_UNSIGNED_BYTE);
}
void Texture::init(uint32_t width, uint32_t height, uint32_t internalFormat, uint32_t dataFormat, uint32_t dataType)
{ {
m_width = width; m_width = width;
m_height = height; m_height = height;
m_internalFormat = internalFormat;
m_internalFormat = (channels == 3) ? GL_RGB8 : GL_RGBA8; m_dataFormat = dataFormat;
m_dataFormat = (channels == 3) ? GL_RGB : GL_RGBA; m_dataType = dataType;
} }
// ----------------------------------------- // -----------------------------------------
@ -49,7 +57,7 @@ std::shared_ptr<Texture2D> Texture2D::create(std::string_view path)
VERIFY(data, "failed to load image: '{}'", path); VERIFY(data, "failed to load image: '{}'", path);
result->init(width, height, channels); result->init(width, height, channels);
result->create(data); result->createImpl(data);
// Clean resources // Clean resources
stbi_image_free(data); stbi_image_free(data);
@ -78,7 +86,7 @@ std::shared_ptr<Texture2D> Texture2D::create(aiTexture* texture)
} }
result->init(width, height, channels); result->init(width, height, channels);
result->create(data); result->createImpl(data);
return result; return result;
} }
@ -99,7 +107,7 @@ void Texture2D::unbind() const
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
} }
void Texture2D::create(unsigned char* data) void Texture2D::createImpl(unsigned char* data)
{ {
m_id = UINT_MAX; m_id = UINT_MAX;
@ -121,7 +129,7 @@ void Texture2D::create(unsigned char* data)
m_width, m_height, // Image width/height m_width, m_height, // Image width/height
0, // Always 0 (legacy) 0, // Always 0 (legacy)
m_dataFormat, // Texture source format m_dataFormat, // Texture source format
GL_UNSIGNED_BYTE, // Texture source datatype m_dataType, // Texture source datatype
data); // Image data data); // Image data
// Set the texture wrapping / filtering options // Set the texture wrapping / filtering options
@ -143,7 +151,7 @@ std::shared_ptr<TextureCubemap> TextureCubemap::create(std::string_view path)
{ {
auto result = std::shared_ptr<TextureCubemap>(new TextureCubemap(path)); auto result = std::shared_ptr<TextureCubemap>(new TextureCubemap(path));
result->create(); result->createImpl();
return result; return result;
} }
@ -164,7 +172,7 @@ void TextureCubemap::unbind() const
glBindTexture(GL_TEXTURE_CUBE_MAP, 0); glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
} }
void TextureCubemap::create() void TextureCubemap::createImpl()
{ {
m_id = UINT_MAX; m_id = UINT_MAX;
@ -206,7 +214,7 @@ void TextureCubemap::create()
m_width, m_height, // Image width/height m_width, m_height, // Image width/height
0, // Always 0 (legacy) 0, // Always 0 (legacy)
m_dataFormat, // Texture source format m_dataFormat, // Texture source format
GL_UNSIGNED_BYTE, // Texture source datatype m_dataType, // Texture source datatype
data); // Image data data); // Image data
// Clean resources // Clean resources
@ -224,4 +232,44 @@ void TextureCubemap::create()
glBindTexture(GL_TEXTURE_CUBE_MAP, 0); glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
} }
// -----------------------------------------
std::shared_ptr<TextureFramebuffer> TextureFramebuffer::create(uint32_t width, uint32_t height, uint32_t internalFormat, uint32_t dataFormat, uint32_t dataType)
{
auto result = std::shared_ptr<TextureFramebuffer>(new TextureFramebuffer(""));
result->init(width, height, internalFormat, dataFormat, dataType);
result->createImpl();
return result;
}
void TextureFramebuffer::createImpl()
{
m_id = UINT_MAX;
// Create texture object
glGenTextures(1, &m_id);
// Bind texture object
glBindTexture(GL_TEXTURE_2D, m_id);
// Generate texture
glTexImage2D(
GL_TEXTURE_2D, // Texture target
0, // Midmap level, base starts at level 0
m_internalFormat, // Texture format
m_width, m_height, // Image width/height
0, // Always 0 (legacy)
m_dataFormat, // Texture source format
m_dataType, // Texture source datatype
NULL); // Image data
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Unbind texture object
glBindTexture(GL_TEXTURE_2D, 0);
}
} // namespace Inferno } // namespace Inferno

50
src/inferno/asset/texture.h

@ -10,20 +10,20 @@
#include <memory> // std::shared_ptr #include <memory> // std::shared_ptr
#include <string_view> #include <string_view>
#include "glad/glad.h"
#include "inferno/asset/asset-manager.h" #include "inferno/asset/asset-manager.h"
struct aiTexture; struct aiTexture;
namespace Inferno { namespace Inferno {
class Texture2D;
class TextureCubemap;
class Texture : public Asset { class Texture : public Asset {
public: public:
virtual ~Texture(); virtual ~Texture();
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);
virtual void bind(uint32_t unit = 0) const = 0; virtual void bind(uint32_t unit = 0) const = 0;
virtual void unbind() const = 0; virtual void unbind() const = 0;
@ -33,12 +33,11 @@ public:
uint32_t id() const { return m_id; } uint32_t id() const { return m_id; }
uint32_t internalFormat() const { return m_internalFormat; } uint32_t internalFormat() const { return m_internalFormat; }
uint32_t dataFormat() const { return m_dataFormat; } uint32_t dataFormat() const { return m_dataFormat; }
uint32_t dataType() const { return m_dataType; }
virtual bool is2D() const { return false; } virtual bool isTexture2D() const override { return false; }
virtual bool isCubemap() const { return false; } virtual bool isTextureCubemap() const override { return false; }
virtual bool isTextureFramebuffer() const override { return false; }
friend Texture2D;
friend TextureCubemap;
protected: protected:
Texture(std::string_view path) Texture(std::string_view path)
@ -52,6 +51,7 @@ protected:
uint32_t m_id { 0 }; uint32_t m_id { 0 };
uint32_t m_internalFormat { 0 }; uint32_t m_internalFormat { 0 };
uint32_t m_dataFormat { 0 }; uint32_t m_dataFormat { 0 };
uint32_t m_dataType { GL_UNSIGNED_BYTE };
private: private:
virtual bool isTexture() const override { return true; } virtual bool isTexture() const override { return true; }
@ -76,10 +76,9 @@ private:
{ {
} }
virtual bool isTexture2D() const override { return true; } void createImpl(unsigned char* data);
private: virtual bool isTexture2D() const override { return true; }
void create(unsigned char* data);
}; };
// ------------------------------------- // -------------------------------------
@ -100,10 +99,34 @@ private:
{ {
} }
void createImpl();
virtual bool isTextureCubemap() const override { return true; } virtual bool isTextureCubemap() const override { return true; }
};
// -----------------------------------------
class TextureFramebuffer final : public Texture {
public:
virtual ~TextureFramebuffer() = default;
// 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);
virtual void bind(uint32_t) const override {}
virtual void unbind() const override {}
private: private:
void create(); TextureFramebuffer(std::string_view path)
: Texture(path)
{
}
void createImpl();
virtual bool isTextureFramebuffer() const override { return true; }
}; };
// ----------------------------------------- // -----------------------------------------
@ -117,6 +140,9 @@ inline bool Asset::fastIs<Texture2D>() const { return isTexture2D(); }
template<> template<>
inline bool Asset::fastIs<TextureCubemap>() const { return isTextureCubemap(); } inline bool Asset::fastIs<TextureCubemap>() const { return isTextureCubemap(); }
template<>
inline bool Asset::fastIs<TextureFramebuffer>() const { return isTextureFramebuffer(); }
// clang-format on // clang-format on
} // namespace Inferno } // namespace Inferno

13
src/inferno/render/buffer.cpp

@ -246,18 +246,13 @@ void BufferLayout::calculateOffsetsAndStride()
// ----------------------------------------- // -----------------------------------------
VertexBuffer::VertexBuffer(size_t size) VertexBuffer::VertexBuffer(size_t size)
: VertexBuffer(size, nullptr)
{ {
glGenBuffers(1, &m_id);
bind();
// Reserve data on the GPU
glBufferData(GL_ARRAY_BUFFER, size, nullptr, GL_DYNAMIC_DRAW);
unbind();
} }
VertexBuffer::VertexBuffer(float* vertices, size_t size) VertexBuffer::VertexBuffer(size_t size, float* vertices)
{ {
m_id = UINT_MAX;
glGenBuffers(1, &m_id); glGenBuffers(1, &m_id);
bind(); bind();
@ -297,6 +292,7 @@ void VertexBuffer::uploadData(const void* data, uint32_t size)
IndexBuffer::IndexBuffer(uint32_t* indices, size_t size) IndexBuffer::IndexBuffer(uint32_t* indices, size_t size)
: m_count(size / sizeof(uint32_t)) : m_count(size / sizeof(uint32_t))
{ {
m_id = UINT_MAX;
glCreateBuffers(1, &m_id); glCreateBuffers(1, &m_id);
bind(); bind();
@ -335,6 +331,7 @@ void IndexBuffer::uploadData(const void* data, uint32_t size)
VertexArray::VertexArray() VertexArray::VertexArray()
{ {
m_id = UINT_MAX;
glCreateVertexArrays(1, &m_id); glCreateVertexArrays(1, &m_id);
} }

16
src/inferno/render/buffer.h

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2022 Riyyi * Copyright (C) 2022,2024 Riyyi
* *
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
@ -31,9 +31,10 @@ enum class BufferElementType {
// ----------------------------------------- // -----------------------------------------
// Describes one element of the BufferLayout // Describes one element of the BufferLayout
class BufferElement { class BufferElement final {
public: public:
BufferElement(BufferElementType type, std::string name, bool normalized = false); BufferElement(BufferElementType type, std::string name, bool normalized = false);
~BufferElement() = default;
uint32_t getTypeSize() const; uint32_t getTypeSize() const;
uint32_t getTypeCount() const; uint32_t getTypeCount() const;
@ -65,10 +66,11 @@ private:
// ----------------------------------------- // -----------------------------------------
// Layout that describes raw vertex data // Layout that describes raw vertex data
class BufferLayout { class BufferLayout final {
public: public:
BufferLayout() {} BufferLayout() {}
BufferLayout(const std::initializer_list<BufferElement>& elements); BufferLayout(const std::initializer_list<BufferElement>& elements);
~BufferLayout() = default;
const std::vector<BufferElement>& getElements() const { return m_elements; } const std::vector<BufferElement>& getElements() const { return m_elements; }
uint32_t getStride() const { return m_stride; } uint32_t getStride() const { return m_stride; }
@ -90,10 +92,10 @@ private:
// ----------------------------------------- // -----------------------------------------
// GPU memory which holds raw vertex data // GPU memory which holds raw vertex data
class VertexBuffer { // Vertex Buffer Object, VBO class VertexBuffer final { // Vertex Buffer Object, VBO
public: public:
VertexBuffer(size_t size); VertexBuffer(size_t size);
VertexBuffer(float* vertices, size_t size); VertexBuffer(size_t size, float* vertices);
~VertexBuffer(); ~VertexBuffer();
void bind() const; void bind() const;
@ -113,7 +115,7 @@ private:
// ----------------------------------------- // -----------------------------------------
// Vertices order of rendering // Vertices order of rendering
class IndexBuffer { // Element Buffer Object, EBO class IndexBuffer final { // Element Buffer Object, EBO
public: public:
IndexBuffer(uint32_t* indices, size_t size); IndexBuffer(uint32_t* indices, size_t size);
~IndexBuffer(); ~IndexBuffer();
@ -133,7 +135,7 @@ private:
// ----------------------------------------- // -----------------------------------------
// Array that holds the vertex attributes configuration // Array that holds the vertex attributes configuration
class VertexArray { // Vertex Array Object, VAO class VertexArray final { // Vertex Array Object, VAO
public: public:
VertexArray(); VertexArray();
~VertexArray(); ~VertexArray();

62
src/inferno/render/framebuffer.cpp

@ -1,21 +1,79 @@
/* /*
* Copyright (C) 2022 Riyyi * Copyright (C) 2022,2024 Riyyi
* *
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
#include <cstdint> // int8_t
#include "glad/glad.h"
#include "ruc/format/log.h"
#include "ruc/meta/assert.h"
#include "inferno/asset/texture.h"
#include "inferno/render/framebuffer.h" #include "inferno/render/framebuffer.h"
namespace Inferno { namespace Inferno {
Framebuffer::Framebuffer() Framebuffer::Framebuffer(const Properties& init)
{ {
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();
} }
Framebuffer::~Framebuffer() Framebuffer::~Framebuffer()
{ {
glDeleteFramebuffers(1, &m_id);
} }
// ----------------------------------------- // -----------------------------------------
bool Framebuffer::check() const
{
VERIFY(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE,
"malformed framebuffer: {:#x}", glCheckFramebufferStatus(GL_FRAMEBUFFER));
return true;
}
void Framebuffer::bind() const
{
glBindFramebuffer(GL_FRAMEBUFFER, m_id);
}
void Framebuffer::unbind() const
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
} // namespace Inferno } // namespace Inferno

43
src/inferno/render/framebuffer.h

@ -1,17 +1,52 @@
/* /*
* Copyright (C) 2022 Riyyi * Copyright (C) 2022,2024 Riyyi
* *
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
#pragma once #pragma once
#include <cstdint> // int8_t
#include <memory> // std::shared_ptr
#include "inferno/asset/texture.h"
#include "ruc/meta/core.h"
namespace Inferno { namespace Inferno {
class Framebuffer { class Framebuffer final { // Frame Buffer Object, FBO
public: public:
Framebuffer(); enum Type : int8_t {
virtual ~Framebuffer(); None = 0,
Color = BIT(0),
Depth = BIT(1),
Stencil = BIT(2),
};
struct Properties {
Type type { None };
uint32_t width { 1280 };
uint32_t height { 720 };
};
Framebuffer(const Properties& init);
~Framebuffer();
bool check() const;
void bind() const;
void unbind() const;
private:
uint32_t m_id { 0 };
std::shared_ptr<TextureFramebuffer> m_textures[4] { nullptr, nullptr, nullptr, nullptr };
}; };
// Make bitwise OR '|' return the enum type instead of int
inline Framebuffer::Type operator|(Framebuffer::Type lhs, Framebuffer::Type rhs)
{
return static_cast<Framebuffer::Type>(
static_cast<int8_t>(lhs) | static_cast<int8_t>(rhs));
}
} // namespace Inferno } // namespace Inferno

Loading…
Cancel
Save