Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c06b06ed62 | ||
|
|
5721b4249c | ||
|
|
95a64be4cd | ||
|
|
79b4f1c3d1 | ||
|
|
a266a27f88 | ||
|
|
08969e32d1 |
@@ -19,3 +19,6 @@
|
||||
[submodule "inferno/vendor/ruc"]
|
||||
path = vendor/ruc
|
||||
url = https://github.com/Riyyi/ruc
|
||||
[submodule "inferno/vendor/assimp"]
|
||||
path = vendor/assimp
|
||||
url = https://github.com/assimp/assimp
|
||||
|
||||
@@ -33,6 +33,7 @@ $ cmake .. && make
|
||||
|
||||
* Libraries
|
||||
|
||||
- [[https://github.com/assimp/assimp][assimp]]
|
||||
# - [[https://github.com/bulletphysics/bullet3][Bullet]]
|
||||
- [[https://github.com/skypjack/entt][EnTT]]
|
||||
- [[https://github.com/Dav1dde/glad][glad]]
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
#version 450 core
|
||||
|
||||
layout(location = 0) out vec4 color;
|
||||
|
||||
in vec3 v_normal;
|
||||
in vec2 v_textureCoordinates;
|
||||
in flat float v_textureIndex;
|
||||
|
||||
uniform sampler2D u_textures[32];
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 textureColor = vec4(1.0f);
|
||||
switch(int(v_textureIndex)) {
|
||||
case 0: break; // Texture unit 0 is reserved for no texture
|
||||
case 1: textureColor *= texture(u_textures[1], v_textureCoordinates); break;
|
||||
case 2: textureColor *= texture(u_textures[2], v_textureCoordinates); break;
|
||||
case 3: textureColor *= texture(u_textures[3], v_textureCoordinates); break;
|
||||
case 4: textureColor *= texture(u_textures[4], v_textureCoordinates); break;
|
||||
case 5: textureColor *= texture(u_textures[5], v_textureCoordinates); break;
|
||||
case 6: textureColor *= texture(u_textures[6], v_textureCoordinates); break;
|
||||
case 7: textureColor *= texture(u_textures[7], v_textureCoordinates); break;
|
||||
case 8: textureColor *= texture(u_textures[8], v_textureCoordinates); break;
|
||||
case 9: textureColor *= texture(u_textures[9], v_textureCoordinates); break;
|
||||
case 10: textureColor *= texture(u_textures[10], v_textureCoordinates); break;
|
||||
case 11: textureColor *= texture(u_textures[11], v_textureCoordinates); break;
|
||||
case 12: textureColor *= texture(u_textures[12], v_textureCoordinates); break;
|
||||
case 13: textureColor *= texture(u_textures[13], v_textureCoordinates); break;
|
||||
case 14: textureColor *= texture(u_textures[14], v_textureCoordinates); break;
|
||||
case 15: textureColor *= texture(u_textures[15], v_textureCoordinates); break;
|
||||
case 16: textureColor *= texture(u_textures[16], v_textureCoordinates); break;
|
||||
case 17: textureColor *= texture(u_textures[17], v_textureCoordinates); break;
|
||||
case 18: textureColor *= texture(u_textures[18], v_textureCoordinates); break;
|
||||
case 19: textureColor *= texture(u_textures[19], v_textureCoordinates); break;
|
||||
case 20: textureColor *= texture(u_textures[20], v_textureCoordinates); break;
|
||||
case 21: textureColor *= texture(u_textures[21], v_textureCoordinates); break;
|
||||
case 22: textureColor *= texture(u_textures[22], v_textureCoordinates); break;
|
||||
case 23: textureColor *= texture(u_textures[23], v_textureCoordinates); break;
|
||||
case 24: textureColor *= texture(u_textures[24], v_textureCoordinates); break;
|
||||
case 25: textureColor *= texture(u_textures[25], v_textureCoordinates); break;
|
||||
case 26: textureColor *= texture(u_textures[26], v_textureCoordinates); break;
|
||||
case 27: textureColor *= texture(u_textures[27], v_textureCoordinates); break;
|
||||
case 28: textureColor *= texture(u_textures[28], v_textureCoordinates); break;
|
||||
case 29: textureColor *= texture(u_textures[29], v_textureCoordinates); break;
|
||||
case 30: textureColor *= texture(u_textures[30], v_textureCoordinates); break;
|
||||
case 31: textureColor *= texture(u_textures[31], v_textureCoordinates); break;
|
||||
}
|
||||
color = textureColor;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#version 450 core
|
||||
|
||||
layout(location = 0) in vec3 a_position;
|
||||
layout(location = 1) in vec3 a_normal;
|
||||
layout(location = 2) in vec2 a_textureCoordinates;
|
||||
layout(location = 3) in float a_textureIndex;
|
||||
|
||||
out vec3 v_normal;
|
||||
out vec2 v_textureCoordinates;
|
||||
out flat float v_textureIndex;
|
||||
|
||||
uniform mat4 u_projectionView;
|
||||
|
||||
void main()
|
||||
{
|
||||
v_normal = a_normal;
|
||||
v_textureCoordinates = a_textureCoordinates;
|
||||
v_textureIndex = a_textureIndex;
|
||||
// Vclip = Camera projection * Camera view * Model transform * Vlocal
|
||||
gl_Position = u_projectionView * vec4(a_position, 1.0f);
|
||||
}
|
||||
@@ -33,7 +33,4 @@ void main()
|
||||
v_borderColor = a_borderColor;
|
||||
v_offset = a_offset;
|
||||
gl_Position = vec4(a_position, 1.0f);
|
||||
|
||||
// Vclip = Camera projection * Camera view * Model transform * Vlocal
|
||||
// gl_Position = u_projectionView * vec4(a_position, 1.0f);
|
||||
}
|
||||
|
||||
@@ -80,6 +80,7 @@ Application::~Application()
|
||||
|
||||
RendererFont::destroy();
|
||||
Renderer2D::destroy();
|
||||
Renderer3D::destroy();
|
||||
RendererCubemap::destroy();
|
||||
RenderCommand::destroy();
|
||||
AssetManager::destroy();
|
||||
@@ -168,6 +169,7 @@ int Application::run()
|
||||
|
||||
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
|
||||
|
||||
@@ -175,6 +177,7 @@ int Application::run()
|
||||
// RendererCharacter::the().drawCharacter(character, f->texture());
|
||||
|
||||
RendererCubemap::the().endScene();
|
||||
Renderer3D::the().endScene();
|
||||
Renderer2D::the().endScene();
|
||||
RendererFont::the().endScene();
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ public:
|
||||
bool fastIs() const = delete;
|
||||
|
||||
virtual bool isFont() const { return false; }
|
||||
virtual bool isModel() const { return false; }
|
||||
virtual bool isShader() const { return false; }
|
||||
virtual bool isTexture() const { return false; }
|
||||
virtual bool isTexture2D() const { return false; }
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Riyyi
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <cstdint> // uint32_t
|
||||
#include <memory> // std::shared_ptr
|
||||
|
||||
#include "assimp/Importer.hpp"
|
||||
#include "assimp/postprocess.h"
|
||||
#include "assimp/scene.h"
|
||||
#include "assimp/texture.h"
|
||||
#include "ruc/format/log.h"
|
||||
|
||||
#include "inferno/asset/model.h"
|
||||
#include "inferno/asset/texture.h"
|
||||
|
||||
namespace Inferno {
|
||||
|
||||
std::shared_ptr<Model> Model::create(std::string_view path)
|
||||
{
|
||||
auto result = std::shared_ptr<Model>(new Model(path));
|
||||
|
||||
Assimp::Importer importer; // importer destructor uses RAII cleanup
|
||||
const aiScene* scene = importer.ReadFile(
|
||||
path.data(),
|
||||
aiProcess_CalcTangentSpace | aiProcess_Triangulate | aiProcess_JoinIdenticalVertices | aiProcess_SortByPType);
|
||||
|
||||
VERIFY(scene != nullptr && (scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE) == 0 && scene->mRootNode != nullptr,
|
||||
"assimp loading file failed: {}", importer.GetErrorString());
|
||||
|
||||
processScene(result, scene);
|
||||
processNode(result, scene->mRootNode, scene);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Model::processScene(std::shared_ptr<Model> model, const aiScene* scene)
|
||||
{
|
||||
VERIFY(scene->HasMeshes(), "malformed model");
|
||||
VERIFY(scene->mNumTextures < 2, "unsupported model type");
|
||||
|
||||
if (scene->mNumTextures == 1) {
|
||||
aiTexture* texture = scene->mTextures[0];
|
||||
model->m_texture = Texture2D::create(texture);
|
||||
}
|
||||
}
|
||||
|
||||
void Model::processNode(std::shared_ptr<Model> model, aiNode* node, const aiScene* scene)
|
||||
{
|
||||
for (uint32_t i = 0; i < node->mNumMeshes; ++i) {
|
||||
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
|
||||
processMesh(model, mesh, scene);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < node->mNumChildren; ++i) {
|
||||
processNode(model, node->mChildren[i], scene);
|
||||
}
|
||||
}
|
||||
|
||||
void Model::processMesh(std::shared_ptr<Model> model, aiMesh* mesh, const aiScene* scene)
|
||||
{
|
||||
VERIFY(mesh->HasPositions(), "malformed model");
|
||||
VERIFY(mesh->HasNormals(), "malformed model");
|
||||
|
||||
// Pre-allocate memory
|
||||
model->m_vertices = std::vector<Vertex>(mesh->mNumVertices);
|
||||
|
||||
for (uint32_t i = 0; i < mesh->mNumVertices; ++i) {
|
||||
aiVector3D v = mesh->mVertices[i];
|
||||
model->m_vertices[i].position = { v.x, v.y, v.z };
|
||||
}
|
||||
|
||||
// Size of vertices == size of normals
|
||||
for (uint32_t i = 0; i < mesh->mNumVertices; ++i) {
|
||||
aiVector3D normal = mesh->mNormals[i];
|
||||
model->m_vertices[i].normal = { normal.x, normal.y, normal.x };
|
||||
}
|
||||
|
||||
if (mesh->HasTextureCoords(0)) {
|
||||
// Size of vertices == size of texture coordinates
|
||||
for (uint32_t i = 0; i < mesh->mNumVertices; ++i) {
|
||||
aiVector3D tc = mesh->mTextureCoords[0][i];
|
||||
model->m_vertices[i].textureCoordinates = { tc.x, tc.y };
|
||||
}
|
||||
}
|
||||
// TODO: position in the texture atlas
|
||||
|
||||
if (mesh->HasFaces()) {
|
||||
for (uint32_t i = 0; i < mesh->mNumFaces; ++i) {
|
||||
aiFace face = mesh->mFaces[i];
|
||||
for (uint32_t j = 0; j < face.mNumIndices; ++j) {
|
||||
model->m_elements.push_back(face.mIndices[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ruc::debug("mesh: {:p}", mesh->mTextureCoordsNames);
|
||||
// for (size_t i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
|
||||
// ruc::debug("mesh: {}", mesh->mTextureCoordsNames[i]);
|
||||
// }
|
||||
|
||||
ruc::debug("has texture: {}", scene->HasTextures());
|
||||
|
||||
ruc::error("asset::model vert {}", model->m_vertices.size());
|
||||
ruc::error("asset::model elem {}", model->m_elements.size());
|
||||
}
|
||||
|
||||
} // namespace Inferno
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Riyyi
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint> // uint32_t
|
||||
#include <memory>
|
||||
#include <span>
|
||||
#include <vector>
|
||||
|
||||
#include "assimp/scene.h"
|
||||
|
||||
#include "inferno/asset/asset-manager.h"
|
||||
#include "inferno/render/renderer.h"
|
||||
|
||||
namespace Inferno {
|
||||
|
||||
class Texture2D;
|
||||
|
||||
class Model final : public Asset {
|
||||
public:
|
||||
virtual ~Model() {}
|
||||
|
||||
// Factory function
|
||||
static std::shared_ptr<Model> create(std::string_view path);
|
||||
|
||||
std::span<const Vertex> vertices() const { return m_vertices; }
|
||||
std::span<const uint32_t> elements() const { return m_elements; }
|
||||
std::shared_ptr<Texture2D> texture() const { return m_texture; }
|
||||
|
||||
private:
|
||||
Model(std::string_view path)
|
||||
: Asset(path)
|
||||
{
|
||||
}
|
||||
|
||||
static void processScene(std::shared_ptr<Model> model, const aiScene* scene);
|
||||
static void processNode(std::shared_ptr<Model> model, aiNode* node, const aiScene* scene);
|
||||
static void processMesh(std::shared_ptr<Model> model, aiMesh* mesh, const aiScene* scene);
|
||||
|
||||
virtual bool isModel() const override { return true; }
|
||||
|
||||
private:
|
||||
std::vector<Vertex> m_vertices;
|
||||
std::vector<uint32_t> m_elements;
|
||||
// Some file formats embed their texture
|
||||
std::shared_ptr<Texture2D> m_texture;
|
||||
};
|
||||
|
||||
} // namespace Inferno
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <cstdint> // uint8_t, uint32_t
|
||||
#include <memory> // std::shared_ptr
|
||||
|
||||
#include "assimp/texture.h"
|
||||
#include "glad/glad.h"
|
||||
#include "ruc/meta/assert.h"
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
@@ -56,6 +57,32 @@ std::shared_ptr<Texture2D> Texture2D::create(std::string_view path)
|
||||
return result;
|
||||
}
|
||||
|
||||
std::shared_ptr<Texture2D> Texture2D::create(aiTexture* texture)
|
||||
{
|
||||
auto result = std::shared_ptr<Texture2D>(new Texture2D(texture->mFilename.C_Str()));
|
||||
|
||||
int width = static_cast<int>(texture->mWidth);
|
||||
int height = static_cast<int>(texture->mHeight);
|
||||
int channels = 0;
|
||||
unsigned char* data = reinterpret_cast<unsigned char*>(texture->pcData);
|
||||
bool isCompressed = height == 0; // height 0 is compression, byte length stored in width variable
|
||||
|
||||
if (isCompressed) {
|
||||
stbi_set_flip_vertically_on_load(0);
|
||||
data = stbi_load_from_memory(data, width, &width, &height, &channels, STBI_default);
|
||||
}
|
||||
else {
|
||||
channels = 4; // ARGB888
|
||||
// TODO: imprement format hints? `archFormatHint'
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
result->init(width, height, channels);
|
||||
result->create(data);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Texture2D::bind(uint32_t unit) const
|
||||
{
|
||||
// Set active unit
|
||||
@@ -198,6 +225,3 @@ void TextureCubemap::create()
|
||||
}
|
||||
|
||||
} // namespace Inferno
|
||||
|
||||
// FIXME
|
||||
// auto texture = (type == Texture::TwoDimensional) ? Texture2D::create(path) : TextureCubemap::create(path);
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
|
||||
#include "inferno/asset/asset-manager.h"
|
||||
|
||||
struct aiTexture;
|
||||
|
||||
namespace Inferno {
|
||||
|
||||
class Texture2D;
|
||||
@@ -63,6 +65,7 @@ public:
|
||||
|
||||
// Factory function
|
||||
static std::shared_ptr<Texture2D> create(std::string_view path);
|
||||
static std::shared_ptr<Texture2D> create(aiTexture* texture);
|
||||
|
||||
virtual void bind(uint32_t unit = 0) const override;
|
||||
virtual void unbind() const override;
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Riyyi
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "inferno/component/model-component.h"
|
||||
#include "inferno/asset/asset-manager.h"
|
||||
#include "inferno/asset/model.h"
|
||||
#include "inferno/asset/texture.h"
|
||||
|
||||
namespace Inferno {
|
||||
|
||||
void fromJson(const ruc::Json& json, ModelComponent& value)
|
||||
{
|
||||
VERIFY(json.type() == ruc::Json::Type::Object);
|
||||
|
||||
if (json.exists("model") && json.at("model").type() == ruc::Json::Type::String) {
|
||||
value.model = AssetManager::the().load<Model>(json.at("model").asString());
|
||||
}
|
||||
if (json.exists("texture") && json.at("texture").type() == ruc::Json::Type::String) {
|
||||
value.texture = AssetManager::the().load<Texture2D>(json.at("texture").asString());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Inferno
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Riyyi
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory> // std::shared_ptr
|
||||
|
||||
#include "ruc/json/json.h"
|
||||
|
||||
#include "inferno/asset/model.h"
|
||||
#include "inferno/asset/texture.h"
|
||||
|
||||
namespace Inferno {
|
||||
|
||||
struct ModelComponent {
|
||||
std::shared_ptr<Model> model;
|
||||
std::shared_ptr<Texture2D> texture;
|
||||
};
|
||||
|
||||
void fromJson(const ruc::Json& json, ModelComponent& value);
|
||||
|
||||
} // namespace Inferno
|
||||
@@ -321,6 +321,16 @@ void IndexBuffer::unbind() const
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
void IndexBuffer::uploadData(const void* data, uint32_t size)
|
||||
{
|
||||
bind();
|
||||
|
||||
// Upload data to the GPU
|
||||
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, size, data);
|
||||
|
||||
unbind();
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
VertexArray::VertexArray()
|
||||
|
||||
@@ -90,7 +90,7 @@ private:
|
||||
// -----------------------------------------
|
||||
|
||||
// GPU memory which holds raw vertex data
|
||||
class VertexBuffer {
|
||||
class VertexBuffer { // Vertex Buffer Object, VBO
|
||||
public:
|
||||
VertexBuffer(size_t size);
|
||||
VertexBuffer(float* vertices, size_t size);
|
||||
@@ -113,7 +113,7 @@ private:
|
||||
// -----------------------------------------
|
||||
|
||||
// Vertices order of rendering
|
||||
class IndexBuffer {
|
||||
class IndexBuffer { // Element Buffer Object, EBO
|
||||
public:
|
||||
IndexBuffer(uint32_t* indices, size_t size);
|
||||
~IndexBuffer();
|
||||
@@ -121,6 +121,8 @@ public:
|
||||
void bind() const;
|
||||
void unbind() const;
|
||||
|
||||
void uploadData(const void* data, uint32_t size);
|
||||
|
||||
uint32_t getCount() const { return m_count; }
|
||||
|
||||
private:
|
||||
@@ -131,7 +133,7 @@ private:
|
||||
// -----------------------------------------
|
||||
|
||||
// Array that holds the vertex attributes configuration
|
||||
class VertexArray {
|
||||
class VertexArray { // Vertex Array Object, VAO
|
||||
public:
|
||||
VertexArray();
|
||||
~VertexArray();
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <memory> // std::shadred_ptr
|
||||
|
||||
#include "glad/glad.h"
|
||||
#include "ruc/format/log.h"
|
||||
@@ -39,9 +39,9 @@ void RenderCommand::clearColor(const glm::vec4& color)
|
||||
glClearColor(color.r, color.g, color.b, color.a);
|
||||
}
|
||||
|
||||
void RenderCommand::drawIndexed(const VertexArray& vertexArray, uint32_t indexCount)
|
||||
void RenderCommand::drawIndexed(std::shared_ptr<VertexArray> vertexArray, uint32_t indexCount)
|
||||
{
|
||||
uint32_t count = indexCount ? indexCount : vertexArray.getIndexBuffer()->getCount();
|
||||
uint32_t count = indexCount ? indexCount : vertexArray->getIndexBuffer()->getCount();
|
||||
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, nullptr);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "glm/ext/matrix_float4x4.hpp" // glm::mat4
|
||||
#include <memory> // std::shadred_ptr
|
||||
|
||||
#include "glm/ext/vector_float4.hpp" // glm::vec4
|
||||
|
||||
namespace Inferno {
|
||||
|
||||
@@ -19,7 +21,7 @@ public:
|
||||
|
||||
static void clear();
|
||||
static void clearColor(const glm::vec4& color);
|
||||
static void drawIndexed(const VertexArray& vertexArray, uint32_t indexCount = 0);
|
||||
static void drawIndexed(std::shared_ptr<VertexArray> vertexArray, uint32_t indexCount = 0);
|
||||
|
||||
static void setViewport(int32_t x, int32_t y, uint32_t width, uint32_t height);
|
||||
static void setDepthTest(bool enabled);
|
||||
|
||||
+151
-40
@@ -4,8 +4,8 @@
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <algorithm> // std::min
|
||||
#include <utility> // std::move
|
||||
#include <algorithm> // std::copy, std::min
|
||||
#include <span>
|
||||
|
||||
#include "glad/glad.h"
|
||||
#include "ruc/format/log.h"
|
||||
@@ -61,32 +61,7 @@ void Renderer<T>::initialize()
|
||||
// Create vertex array
|
||||
m_vertexArray = std::make_shared<VertexArray>();
|
||||
|
||||
// CPU
|
||||
// ---------------------------------
|
||||
|
||||
// Generate indices
|
||||
|
||||
uint32_t* indices = new uint32_t[maxIndices];
|
||||
|
||||
uint32_t offset = 0;
|
||||
for (uint32_t i = 0; i < maxIndices; i += indexPerQuad) {
|
||||
indices[i + 0] = offset + 0;
|
||||
indices[i + 1] = offset + 1;
|
||||
indices[i + 2] = offset + 2;
|
||||
indices[i + 3] = offset + 2;
|
||||
indices[i + 4] = offset + 3;
|
||||
indices[i + 5] = offset + 0;
|
||||
|
||||
offset += vertexPerQuad;
|
||||
}
|
||||
|
||||
// GPU
|
||||
// ---------------------------------
|
||||
|
||||
// Create index buffer
|
||||
auto indexBuffer = std::make_shared<IndexBuffer>(indices, sizeof(uint32_t) * maxIndices);
|
||||
m_vertexArray->setIndexBuffer(indexBuffer);
|
||||
delete[] indices;
|
||||
createElementBuffer();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@@ -146,24 +121,56 @@ void Renderer<T>::unbind()
|
||||
m_shader->unbind();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Renderer<T>::createElementBuffer()
|
||||
{
|
||||
// CPU
|
||||
// ---------------------------------
|
||||
|
||||
// Generate indices
|
||||
|
||||
uint32_t* indices = new uint32_t[maxElements];
|
||||
|
||||
uint32_t offset = 0;
|
||||
for (uint32_t i = 0; i < maxElements; i += elementPerQuad) {
|
||||
indices[i + 0] = offset + 0;
|
||||
indices[i + 1] = offset + 1;
|
||||
indices[i + 2] = offset + 2;
|
||||
indices[i + 3] = offset + 2;
|
||||
indices[i + 4] = offset + 3;
|
||||
indices[i + 5] = offset + 0;
|
||||
|
||||
offset += vertexPerQuad;
|
||||
}
|
||||
|
||||
// GPU
|
||||
// ---------------------------------
|
||||
|
||||
// Create index buffer
|
||||
auto indexBuffer = std::make_shared<IndexBuffer>(indices, sizeof(uint32_t) * maxElements);
|
||||
m_vertexArray->setIndexBuffer(indexBuffer);
|
||||
delete[] indices;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Renderer<T>::flush()
|
||||
{
|
||||
if (m_quadIndex == 0) {
|
||||
if (m_vertexIndex == 0 || m_elementIndex == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Upload index data to GPU
|
||||
uploadElementBuffer();
|
||||
|
||||
// Upload vertex data to GPU
|
||||
m_vertexArray->at(0)->uploadData(
|
||||
m_vertexBufferBase,
|
||||
m_quadIndex * vertexPerQuad * sizeof(T));
|
||||
m_vertexArray->at(0)->uploadData(m_vertexBufferBase, m_vertexIndex * sizeof(T));
|
||||
|
||||
bind();
|
||||
|
||||
// Render
|
||||
bool depthTest = RenderCommand::depthTest();
|
||||
RenderCommand::setDepthTest(m_enableDepthBuffer);
|
||||
RenderCommand::drawIndexed(*m_vertexArray, m_quadIndex * indexPerQuad);
|
||||
RenderCommand::drawIndexed(m_vertexArray, m_elementIndex);
|
||||
RenderCommand::setDepthTest(depthTest);
|
||||
|
||||
unbind();
|
||||
@@ -172,7 +179,8 @@ void Renderer<T>::flush()
|
||||
template<typename T>
|
||||
void Renderer<T>::startBatch()
|
||||
{
|
||||
m_quadIndex = 0;
|
||||
m_vertexIndex = 0;
|
||||
m_elementIndex = 0;
|
||||
m_vertexBufferPtr = m_vertexBufferBase;
|
||||
|
||||
m_textureSlotIndex = 1;
|
||||
@@ -245,7 +253,7 @@ void Renderer2D::drawQuad(const TransformComponent& transform, glm::vec4 color,
|
||||
void Renderer2D::drawQuad(const TransformComponent& transform, glm::mat4 color, std::shared_ptr<Texture> texture)
|
||||
{
|
||||
// Create a new batch if the quad limit has been reached
|
||||
if (m_quadIndex >= maxQuads) {
|
||||
if (m_vertexIndex + vertexPerQuad > maxVertices || m_elementIndex + elementPerQuad > maxElements) {
|
||||
nextBatch();
|
||||
}
|
||||
|
||||
@@ -267,7 +275,8 @@ void Renderer2D::drawQuad(const TransformComponent& transform, glm::mat4 color,
|
||||
m_vertexBufferPtr++;
|
||||
}
|
||||
|
||||
m_quadIndex++;
|
||||
m_vertexIndex += vertexPerQuad;
|
||||
m_elementIndex += elementPerQuad;
|
||||
}
|
||||
|
||||
void Renderer2D::loadShader()
|
||||
@@ -366,7 +375,8 @@ void RendererCubemap::drawCubemap(const TransformComponent& transform, glm::vec4
|
||||
void RendererCubemap::drawCubemap(const TransformComponent& transform, glm::mat4 color, std::shared_ptr<Texture> texture)
|
||||
{
|
||||
// Create a new batch if the quad limit has been reached
|
||||
if (m_quadIndex >= maxQuads) {
|
||||
if (m_vertexIndex + (vertexPerQuad * quadPerCube) > maxVertices
|
||||
|| m_elementIndex + (elementPerQuad * quadPerCube) > maxElements) {
|
||||
nextBatch();
|
||||
}
|
||||
|
||||
@@ -380,7 +390,8 @@ void RendererCubemap::drawCubemap(const TransformComponent& transform, glm::mat4
|
||||
m_vertexBufferPtr++;
|
||||
}
|
||||
|
||||
m_quadIndex += quadPerCube;
|
||||
m_vertexIndex += vertexPerQuad * quadPerCube;
|
||||
m_elementIndex += elementPerQuad * quadPerCube;
|
||||
}
|
||||
|
||||
void RendererCubemap::loadShader()
|
||||
@@ -428,7 +439,7 @@ RendererFont::RendererFont(s)
|
||||
void RendererFont::drawSymbol(std::array<SymbolVertex, vertexPerQuad>& symbolQuad, std::shared_ptr<Texture> texture)
|
||||
{
|
||||
// Create a new batch if the quad limit has been reached
|
||||
if (m_quadIndex >= maxQuads) {
|
||||
if (m_vertexIndex + vertexPerQuad > maxVertices || m_elementIndex + elementPerQuad > maxElements) {
|
||||
nextBatch();
|
||||
}
|
||||
|
||||
@@ -451,7 +462,8 @@ void RendererFont::drawSymbol(std::array<SymbolVertex, vertexPerQuad>& symbolQua
|
||||
m_vertexBufferPtr++;
|
||||
}
|
||||
|
||||
m_quadIndex++;
|
||||
m_vertexIndex += vertexPerQuad;
|
||||
m_elementIndex += elementPerQuad;
|
||||
}
|
||||
|
||||
void RendererFont::loadShader()
|
||||
@@ -459,4 +471,103 @@ void RendererFont::loadShader()
|
||||
m_shader = AssetManager::the().load<Shader>("assets/glsl/batch-font");
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
Renderer3D::Renderer3D(s)
|
||||
{
|
||||
Renderer::initialize();
|
||||
|
||||
// CPU
|
||||
// ---------------------------------
|
||||
|
||||
// Create array for storing quads vertices
|
||||
m_vertexBufferBase = new Vertex[maxVertices];
|
||||
m_vertexBufferPtr = m_vertexBufferBase;
|
||||
|
||||
// GPU
|
||||
// ---------------------------------
|
||||
|
||||
m_enableDepthBuffer = true;
|
||||
|
||||
// Create vertex buffer
|
||||
auto vertexBuffer = std::make_shared<VertexBuffer>(sizeof(Vertex) * maxVertices);
|
||||
vertexBuffer->setLayout({
|
||||
{ BufferElementType::Vec3, "a_position" },
|
||||
{ BufferElementType::Vec3, "a_normal" },
|
||||
{ BufferElementType::Vec2, "a_textureCoordinates" },
|
||||
{ BufferElementType::Float, "a_textureIndex" },
|
||||
});
|
||||
m_vertexArray->addVertexBuffer(vertexBuffer);
|
||||
|
||||
ruc::info("Renderer3D initialized");
|
||||
}
|
||||
|
||||
void Renderer3D::drawModel(std::span<const Vertex> vertices, std::span<const uint32_t> indices, const TransformComponent& transform, std::shared_ptr<Texture> texture)
|
||||
{
|
||||
VERIFY(vertices.size() <= maxVertices, "model vertices too big for buffer");
|
||||
VERIFY(indices.size() <= maxElements, "model elements too big for buffer");
|
||||
|
||||
// Create a new batch if the quad limit has been reached
|
||||
if (m_vertexIndex + vertices.size() > maxVertices || m_elementIndex + indices.size() > maxElements) {
|
||||
nextBatch();
|
||||
}
|
||||
|
||||
uint32_t textureUnitIndex = addTextureUnit(texture);
|
||||
|
||||
// Add the vertices
|
||||
for (auto vertex : vertices) {
|
||||
m_vertexBufferPtr->position = transform.transform * glm::vec4(vertex.position, 1.0f);
|
||||
m_vertexBufferPtr->normal = vertex.normal;
|
||||
m_vertexBufferPtr->textureCoordinates = vertex.textureCoordinates;
|
||||
m_vertexBufferPtr->textureIndex = (float)textureUnitIndex;
|
||||
m_vertexBufferPtr++;
|
||||
}
|
||||
|
||||
std::copy(indices.begin(), indices.end(), m_elementBufferPtr);
|
||||
m_elementBufferPtr += indices.size();
|
||||
|
||||
m_vertexIndex += vertices.size();
|
||||
m_elementIndex += indices.size();
|
||||
}
|
||||
|
||||
void Renderer3D::beginScene(glm::mat4 cameraProjection, glm::mat4 cameraView)
|
||||
{
|
||||
m_shader->bind();
|
||||
m_shader->setFloat("u_projectionView", cameraProjection * cameraView);
|
||||
m_shader->unbind();
|
||||
}
|
||||
|
||||
void Renderer3D::createElementBuffer()
|
||||
{
|
||||
// CPU
|
||||
// ---------------------------------
|
||||
|
||||
// Create array for storing quads vertices
|
||||
m_elementBufferBase = new uint32_t[maxElements];
|
||||
m_elementBufferPtr = m_elementBufferBase;
|
||||
|
||||
// GPU
|
||||
// ---------------------------------
|
||||
|
||||
// Create index buffer
|
||||
auto indexBuffer = std::make_shared<IndexBuffer>(m_elementBufferBase, sizeof(uint32_t) * maxElements);
|
||||
m_vertexArray->setIndexBuffer(indexBuffer);
|
||||
}
|
||||
|
||||
void Renderer3D::uploadElementBuffer()
|
||||
{
|
||||
m_vertexArray->getIndexBuffer()->uploadData(m_elementBufferBase, m_elementIndex * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
void Renderer3D::loadShader()
|
||||
{
|
||||
m_shader = AssetManager::the().load<Shader>("assets/glsl/batch-3d");
|
||||
}
|
||||
|
||||
void Renderer3D::startBatch()
|
||||
{
|
||||
Renderer<Vertex>::startBatch();
|
||||
m_elementBufferPtr = m_elementBufferBase;
|
||||
}
|
||||
|
||||
} // namespace Inferno
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <cstdint> // int32_t, uint32_t
|
||||
#include <memory> // std::shared_ptr, std::unique_ptr, std::make_shared, std::make_unique
|
||||
#include <span>
|
||||
|
||||
#include "glm/ext/matrix_float4x4.hpp" // glm::mat4
|
||||
#include "glm/ext/vector_float2.hpp" // glm::vec2
|
||||
@@ -49,21 +50,27 @@ struct SymbolVertex {
|
||||
float offset = 0.0f;
|
||||
};
|
||||
|
||||
struct Vertex {
|
||||
glm::vec3 position { 0.0f, 0.0f, 0.0f };
|
||||
glm::vec3 normal { 1.0f, 1.0f, 1.0f };
|
||||
glm::vec2 textureCoordinates { 0.0f, 0.0f };
|
||||
float textureIndex = 0;
|
||||
};
|
||||
|
||||
// -------------------------------------
|
||||
|
||||
template<typename T>
|
||||
class Renderer {
|
||||
public:
|
||||
static constexpr const uint32_t vertexPerQuad = 4;
|
||||
static constexpr const uint32_t indexPerQuad = 6;
|
||||
static constexpr const uint32_t quadPerCube = 6;
|
||||
static constexpr const uint32_t elementPerQuad = 6;
|
||||
|
||||
// When to start a new batch
|
||||
static constexpr const uint32_t maxQuads = 20000;
|
||||
static constexpr const uint32_t maxVertices = maxQuads * vertexPerQuad;
|
||||
static constexpr const uint32_t maxIndices = maxQuads * indexPerQuad;
|
||||
static constexpr const uint32_t maxVertices = 60000;
|
||||
static constexpr const uint32_t maxElements = 60000;
|
||||
static constexpr const uint32_t maxTextureSlots = 32;
|
||||
|
||||
public:
|
||||
virtual void beginScene(glm::mat4 cameraProjection, glm::mat4 cameraView);
|
||||
virtual void endScene();
|
||||
|
||||
@@ -79,6 +86,8 @@ protected:
|
||||
void bind();
|
||||
void unbind();
|
||||
|
||||
virtual void createElementBuffer();
|
||||
virtual void uploadElementBuffer() {}
|
||||
virtual void loadShader() = 0;
|
||||
virtual void flush();
|
||||
virtual void startBatch();
|
||||
@@ -86,7 +95,8 @@ protected:
|
||||
|
||||
protected:
|
||||
// CPU quad vertices
|
||||
uint32_t m_quadIndex { 0 };
|
||||
uint32_t m_vertexIndex { 0 };
|
||||
uint32_t m_elementIndex { 0 };
|
||||
T* m_vertexBufferBase { nullptr };
|
||||
T* m_vertexBufferPtr { nullptr };
|
||||
|
||||
@@ -102,7 +112,7 @@ protected:
|
||||
};
|
||||
|
||||
// TOOD:
|
||||
// - Deduplicate flush()
|
||||
// v Deduplicate flush()
|
||||
// v Add bool for disabling depth buffer
|
||||
// - Add Size for uploadData (this is prob not needed, we got T already)
|
||||
// - Decide if its worth to remove template<T> from Renderer, just cast vertexBufferPtr before usage
|
||||
@@ -114,7 +124,7 @@ class Renderer2D final
|
||||
, public ruc::Singleton<Renderer2D> {
|
||||
public:
|
||||
Renderer2D(s);
|
||||
virtual ~Renderer2D() {};
|
||||
virtual ~Renderer2D() = default;
|
||||
|
||||
using Singleton<Renderer2D>::destroy;
|
||||
|
||||
@@ -136,9 +146,12 @@ private:
|
||||
class RendererCubemap final
|
||||
: public Renderer<CubemapVertex>
|
||||
, public ruc::Singleton<RendererCubemap> {
|
||||
public:
|
||||
static constexpr const uint32_t quadPerCube = 6;
|
||||
|
||||
public:
|
||||
RendererCubemap(s);
|
||||
virtual ~RendererCubemap() {};
|
||||
virtual ~RendererCubemap() = default;
|
||||
|
||||
using Singleton<RendererCubemap>::destroy;
|
||||
|
||||
@@ -161,7 +174,7 @@ class RendererFont final
|
||||
, public ruc::Singleton<RendererFont> {
|
||||
public:
|
||||
RendererFont(s);
|
||||
virtual ~RendererFont() {};
|
||||
virtual ~RendererFont() = default;
|
||||
|
||||
using Singleton<RendererFont>::destroy;
|
||||
|
||||
@@ -171,4 +184,31 @@ private:
|
||||
void loadShader() override;
|
||||
};
|
||||
|
||||
// -------------------------------------
|
||||
|
||||
class Renderer3D final
|
||||
: public Renderer<Vertex>
|
||||
, public ruc::Singleton<Renderer3D> {
|
||||
public:
|
||||
Renderer3D(s);
|
||||
virtual ~Renderer3D() = default;
|
||||
|
||||
using Singleton<Renderer3D>::destroy;
|
||||
|
||||
virtual void beginScene(glm::mat4 cameraProjection, glm::mat4 cameraView) override;
|
||||
|
||||
void drawModel(std::span<const Vertex> vertices, std::span<const uint32_t> indices, const TransformComponent& transform, std::shared_ptr<Texture> texture);
|
||||
|
||||
private:
|
||||
void createElementBuffer() override;
|
||||
void uploadElementBuffer() override;
|
||||
void loadShader() override;
|
||||
void startBatch() override;
|
||||
|
||||
private:
|
||||
// CPU element vertices
|
||||
uint32_t* m_elementBufferBase { nullptr };
|
||||
uint32_t* m_elementBufferPtr { nullptr };
|
||||
};
|
||||
|
||||
} // namespace Inferno
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "inferno/component/cubemap-component.h"
|
||||
#include "inferno/component/id-component.h"
|
||||
#include "inferno/component/luascriptcomponent.h"
|
||||
#include "inferno/component/model-component.h"
|
||||
#include "inferno/component/nativescriptcomponent.h"
|
||||
#include "inferno/component/spritecomponent.h"
|
||||
#include "inferno/component/tagcomponent.h"
|
||||
@@ -166,6 +167,10 @@ uint32_t Scene::loadEntity(ruc::Json components, uint32_t parentEntity)
|
||||
auto& text = addComponent<TextAreaComponent>(entity);
|
||||
components.at("text").getTo(text);
|
||||
}
|
||||
if (components.exists("model")) {
|
||||
auto& text = addComponent<ModelComponent>(entity);
|
||||
components.at("model").getTo(text);
|
||||
}
|
||||
if (components.exists("children")) {
|
||||
VERIFY(components.at("children").type() == ruc::Json::Type::Array);
|
||||
const auto& children = components.at("children").asArray();
|
||||
|
||||
@@ -5,9 +5,11 @@
|
||||
*/
|
||||
|
||||
#include "glm/ext/matrix_transform.hpp" // glm::translate, glm::rotate, glm::scale, glm::radians
|
||||
#include "inferno/component/model-component.h"
|
||||
#include "ruc/format/log.h"
|
||||
|
||||
#include "inferno/component/cubemap-component.h"
|
||||
#include "inferno/component/model-component.h"
|
||||
#include "inferno/component/spritecomponent.h"
|
||||
#include "inferno/component/transformcomponent.h"
|
||||
#include "inferno/render/renderer.h"
|
||||
@@ -37,6 +39,15 @@ void RenderSystem::render()
|
||||
for (auto [entity, transform, cubemap] : cubemapView.each()) {
|
||||
RendererCubemap::the().drawCubemap(transform, cubemap.color, cubemap.texture);
|
||||
}
|
||||
|
||||
auto modelView = m_registry->view<TransformComponent, ModelComponent>();
|
||||
|
||||
for (auto [entity, transform, model] : modelView.each()) {
|
||||
Renderer3D::the().drawModel(model.model->vertices(),
|
||||
model.model->elements(),
|
||||
transform,
|
||||
model.model->texture() ? model.model->texture() : model.texture);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Inferno
|
||||
|
||||
Vendored
+12
-1
@@ -9,6 +9,16 @@ add_subdirectory(glfw)
|
||||
# Add RUC target to project
|
||||
add_subdirectory(ruc)
|
||||
|
||||
# assimp options
|
||||
option(ASSIMP_BUILD_ASSIMP_VIEW OFF)
|
||||
option(ASSIMP_BUILD_TESTS OFF)
|
||||
option(ASSIMP_INSTALL OFF)
|
||||
option(ASSIMP_INSTALL_PDB OFF)
|
||||
option(ASSIMP_WARNINGS_AS_ERRORS OFF)
|
||||
|
||||
# Add assimp target to project
|
||||
add_subdirectory(assimp)
|
||||
|
||||
# Define engine source files
|
||||
file(GLOB_RECURSE GLAD "glad/*.c")
|
||||
file(GLOB LUA "lua/lua/*.c")
|
||||
@@ -19,6 +29,7 @@ set(ENGINE_SOURCES ${GLAD} ${LUA})
|
||||
|
||||
add_library(${ENGINE}-dependencies ${ENGINE_SOURCES})
|
||||
target_include_directories(${ENGINE}-dependencies PUBLIC
|
||||
"assimp/include"
|
||||
"glad/include"
|
||||
"lua")
|
||||
target_link_libraries(${ENGINE}-dependencies glfw ruc ruc-test)
|
||||
target_link_libraries(${ENGINE}-dependencies glfw ruc ruc-test assimp)
|
||||
|
||||
+1
Submodule vendor/assimp added at 762ad8e9b7
Reference in New Issue
Block a user