Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd8973d10d | ||
|
|
bc3f2c9db5 | ||
|
|
0dd7a05d46 |
@@ -48,3 +48,5 @@ $ cmake .. && make
|
||||
- [[https://www.glfw.org/docs/latest/build_guide.html#build_link_cmake_source][Build GLFW using CMake]]
|
||||
- [[https://learnopengl.com][Learn OpenGL]]
|
||||
- [[https://www.youtube.com/playlist?list=PLlrATfBNZ98dC-V-N3m0Go4deliWHPFwT][Game Engine]] by The Cherno
|
||||
- [[https://www.youtube.com/watch?v=mnIQEQoHHCU][OpenGL 3D Game Tutorial 32: Font Rendering]]
|
||||
- [[https://youtu.be/d8cfgcJR9Tk][OpenGL 3D Game Tutorial 33: Distance Field Text Rendering]]
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 77 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 77 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 69 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 88 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 87 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 79 KiB |
@@ -0,0 +1,49 @@
|
||||
#version 450 core
|
||||
|
||||
layout(location = 0) out vec4 color;
|
||||
|
||||
in vec4 v_color;
|
||||
in vec3 v_textureCoordinates;
|
||||
in flat float v_textureIndex;
|
||||
|
||||
uniform samplerCube u_textures[32];
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 textureColor = v_color;
|
||||
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,20 @@
|
||||
#version 450 core
|
||||
|
||||
layout(location = 0) in vec3 a_position;
|
||||
layout(location = 1) in vec4 a_color;
|
||||
layout(location = 2) in float a_textureIndex;
|
||||
|
||||
out vec4 v_color;
|
||||
out vec3 v_textureCoordinates;
|
||||
out flat float v_textureIndex;
|
||||
|
||||
uniform mat4 u_projectionView;
|
||||
|
||||
void main()
|
||||
{
|
||||
v_color = a_color;
|
||||
v_textureCoordinates = a_position;
|
||||
v_textureIndex = a_textureIndex;
|
||||
// Vclip = Camera projection * Camera view * Model transform * Vlocal
|
||||
gl_Position = u_projectionView * vec4(a_position, 1.0f);
|
||||
}
|
||||
+80
-19
@@ -1,50 +1,111 @@
|
||||
{
|
||||
"init": "assets/lua/scene1-init.lua",
|
||||
"camera": {
|
||||
"name": "Camera",
|
||||
"entities": [
|
||||
{
|
||||
"id": { "id": 12312312 },
|
||||
"tag": { "tag": "Camera" },
|
||||
"transform" : {
|
||||
"translate": [0.0, 0.0, 1.0],
|
||||
"rotate": [0.0, 0.0, -1.0],
|
||||
"scale": [ 1.0, 1.0, 1.0 ],
|
||||
"type": "perspective",
|
||||
"script": {
|
||||
"type": "lua",
|
||||
"name": "assets/lua/cameracontroller.lua"
|
||||
}
|
||||
"scale": [1.0, 1.0, 1.0]
|
||||
},
|
||||
"camera": { "type": "perspective" },
|
||||
"lua-scripts": [
|
||||
{ "path": "assets/lua/cameracontroller.lua" }
|
||||
]
|
||||
},
|
||||
"quad": [
|
||||
{
|
||||
"name": "Quad",
|
||||
"id": { "id": 212563732 },
|
||||
"tag": { "tag": "Skybox" },
|
||||
"transform" : {
|
||||
"translate": [0.0, 0.0, 0.0],
|
||||
"rotate": [0.0, 0.0, 0.0],
|
||||
"scale": [ 1.0, 1.0, 1.0 ],
|
||||
"scale": [100.0, 100.0, 100.0]
|
||||
},
|
||||
"cubemap": {
|
||||
"color": [ 1.0, 1.0, 1.0, 1.0 ],
|
||||
"texture": "assets/gfx/skybox.jpg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": { "id": 564564564 },
|
||||
"tag": { "tag": "Quad" },
|
||||
"transform" : {
|
||||
"translate": [ 0.0, 0.0, 0.0 ],
|
||||
"rotate": [ 0.0, 0.0, 0.0 ],
|
||||
"scale": [ 1.0, 1.0, 1.0 ]
|
||||
},
|
||||
"sprite": {
|
||||
"color": [ 1.0, 1.0, 1.0, 1.0 ],
|
||||
"texture": "assets/gfx/test.png"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Quad 2",
|
||||
"id": { "id": 97897897 },
|
||||
"tag": { "tag": "Quad 2" },
|
||||
"transform" : {
|
||||
"translate": [ 1.1, 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 ]
|
||||
},
|
||||
"sprite": {
|
||||
"color": [ 0.5, 0.6, 0.8, 1.0 ],
|
||||
"texture": "assets/gfx/test.png"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Quad 3",
|
||||
"translate": [ 2.2, 0.0, 0.0 ],
|
||||
"id": { "id": 3424242 },
|
||||
"tag": { "tag": "Quad 3" },
|
||||
"transform" : {
|
||||
"translate": [ 2.2, 1.0, 0.0 ],
|
||||
"rotate": [ 0.0, 0.0, -20.0 ],
|
||||
"scale": [ 1.0, 1.0, 1.0 ]
|
||||
},
|
||||
"sprite": {
|
||||
"color": [ 1.0, 1.0, 1.0, 1.0 ],
|
||||
"texture": "assets/gfx/test-inverted.png"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": { "id": 4345472 },
|
||||
"tag": { "tag": "Quad 4" },
|
||||
"transform" : {
|
||||
"translate": [ 0.85, 0.0, 0.0 ],
|
||||
"rotate": [ 0.0, 0.0, 0.0 ],
|
||||
"scale": [ 1.0, 1.0, 1.0 ],
|
||||
"scale": [ 0.5, 0.5, 1.0 ]
|
||||
},
|
||||
"sprite": {
|
||||
"color": [ 1.0, 1.0, 1.0, 1.0 ],
|
||||
"texture": "assets/gfx/test-inverted.png"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": { "id": 5234723 },
|
||||
"tag": { "tag": "Quad 5" },
|
||||
"transform" : {
|
||||
"translate": [ 1.0, 0.0, 0.0 ],
|
||||
"rotate": [ 0.0, 0.0, -20.0 ],
|
||||
"scale": [ 0.5, 0.5, 1.0 ]
|
||||
},
|
||||
"sprite": {
|
||||
"color": [ 1.0, 1.0, 1.0, 1.0 ],
|
||||
"texture": "assets/gfx/test-inverted.png"
|
||||
}
|
||||
],
|
||||
"text": [
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Text",
|
||||
"id": { "id": 675754 },
|
||||
"tag": { "tag": "Text" },
|
||||
"text": {
|
||||
"content": "Hello World!",
|
||||
"font": "assets/fnt/open-sans",
|
||||
"font-size": 24,
|
||||
"line-spacing": 1.0,
|
||||
"width": 150
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Riyyi
|
||||
* Copyright (C) 2022,2024 Riyyi
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <utility> // std::pair
|
||||
|
||||
#include "glm/gtc/type_ptr.hpp" // glm::make_mat4
|
||||
#include "ruc/format/log.h"
|
||||
#include "ruc/meta/assert.h"
|
||||
@@ -78,6 +80,7 @@ Application::~Application()
|
||||
FontManager::destroy();
|
||||
RendererCharacter::destroy();
|
||||
Renderer2D::destroy();
|
||||
RendererCubemap::destroy();
|
||||
RenderCommand::destroy();
|
||||
TextureManager::destroy();
|
||||
ShaderManager::destroy();
|
||||
@@ -164,12 +167,15 @@ int Application::run()
|
||||
RenderCommand::clearColor({ 0.2f, 0.3f, 0.3f, 1.0f });
|
||||
RenderCommand::clear();
|
||||
|
||||
Renderer2D::the().beginScene(m_scene->cameraProjectionView()); // camera, lights, environment
|
||||
std::pair<glm::mat4, glm::mat4> projectionView = m_scene->cameraProjectionView();
|
||||
RendererCubemap::the().beginScene(projectionView.first, projectionView.second); // camera, lights, environment
|
||||
Renderer2D::the().beginScene(projectionView.first, projectionView.second); // camera, lights, environment
|
||||
RendererCharacter::the().beginScene();
|
||||
|
||||
m_scene->render();
|
||||
// RendererCharacter::the().drawCharacter(character, f->texture());
|
||||
|
||||
RendererCubemap::the().endScene();
|
||||
Renderer2D::the().endScene();
|
||||
RendererCharacter::the().endScene();
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Riyyi
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "ruc/format/print.h"
|
||||
#include "ruc/json/json.h"
|
||||
|
||||
#include "inferno/component/cameracomponent.h"
|
||||
|
||||
namespace Inferno {
|
||||
|
||||
void fromJson(const ruc::Json& json, CameraComponent& value)
|
||||
{
|
||||
VERIFY(json.type() == ruc::Json::Type::Object);
|
||||
|
||||
if (json.exists("type")) {
|
||||
value.type = json.at("type").get<std::string>() == "orthographic" ? CameraType::Orthographic : CameraType::Perspective;
|
||||
}
|
||||
if (json.exists("zoom-level")) {
|
||||
json.at("zoom-level").getTo(value.zoomLevel);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Inferno
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "glm/ext/matrix_float4x4.hpp" // glm::mat4
|
||||
#include "glm/ext/vector_float3.hpp" // glm::vec3
|
||||
#include "ruc/json/json.h"
|
||||
|
||||
namespace Inferno {
|
||||
|
||||
@@ -32,4 +33,6 @@ struct CameraComponent {
|
||||
glm::mat4 projection { 1.0f }; // Identity matrix
|
||||
};
|
||||
|
||||
void fromJson(const ruc::Json& json, CameraComponent& value);
|
||||
|
||||
} // namespace Inferno
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Riyyi
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "ruc/json/json.h"
|
||||
|
||||
#include "inferno/component/cubemap-component.h"
|
||||
#include "inferno/component/spritecomponent.h" // TODO: Move glm::x toJson/fromJson to separate file
|
||||
#include "inferno/render/texture.h"
|
||||
|
||||
namespace Inferno {
|
||||
|
||||
void fromJson(const ruc::Json& json, CubemapComponent& value)
|
||||
{
|
||||
VERIFY(json.type() == ruc::Json::Type::Object);
|
||||
|
||||
if (json.exists("color")) {
|
||||
json.at("color").getTo(value.color);
|
||||
}
|
||||
if (json.exists("texture") && json.at("texture").type() == ruc::Json::Type::String) {
|
||||
value.texture = TextureManager::the().load(json.at("texture").asString(), Texture::Type::Cubemap);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Inferno
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Riyyi
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory> // std::shared_ptr
|
||||
|
||||
#include "glm/ext/vector_float4.hpp" // glm::vec4
|
||||
#include "ruc/json/json.h"
|
||||
|
||||
#include "inferno/render/texture.h"
|
||||
|
||||
namespace Inferno {
|
||||
|
||||
struct CubemapComponent {
|
||||
glm::vec4 color { 1.0f };
|
||||
std::shared_ptr<Texture> texture;
|
||||
};
|
||||
|
||||
void fromJson(const ruc::Json& json, CubemapComponent& value);
|
||||
|
||||
} // namespace Inferno
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Riyyi
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "ruc/json/json.h"
|
||||
|
||||
#include "inferno/component/id-component.h"
|
||||
|
||||
namespace Inferno {
|
||||
|
||||
void fromJson(const ruc::Json& json, IDComponent& value)
|
||||
{
|
||||
VERIFY(json.type() == ruc::Json::Type::Object);
|
||||
|
||||
if (json.exists("id")) {
|
||||
json.at("id").getTo(value.id);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Inferno
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Riyyi
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ruc/json/json.h"
|
||||
|
||||
#include "inferno/uid.h"
|
||||
|
||||
namespace Inferno {
|
||||
|
||||
struct IDComponent {
|
||||
UID id;
|
||||
|
||||
IDComponent() = default;
|
||||
IDComponent(UID id)
|
||||
: id(id)
|
||||
{
|
||||
}
|
||||
IDComponent(const IDComponent&) = default;
|
||||
};
|
||||
|
||||
void fromJson(const ruc::Json& json, IDComponent& value);
|
||||
|
||||
} // namespace Inferno
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Riyyi
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "ruc/json/json.h"
|
||||
|
||||
#include "inferno/component/luascriptcomponent.h"
|
||||
|
||||
namespace Inferno {
|
||||
|
||||
void fromJson(const ruc::Json& json, LuaScriptComponent& value)
|
||||
{
|
||||
VERIFY(json.type() == ruc::Json::Type::Object);
|
||||
|
||||
VERIFY(json.exists("path"), "path not found");
|
||||
json.at("path").getTo(value.path);
|
||||
}
|
||||
|
||||
} // namespace Inferno
|
||||
@@ -6,9 +6,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string> // std::string
|
||||
#include <string>
|
||||
#include <utility> // std::move
|
||||
|
||||
#include "ruc/json/json.h"
|
||||
|
||||
namespace Inferno {
|
||||
|
||||
class LuaScript;
|
||||
@@ -24,4 +26,7 @@ struct LuaScriptComponent {
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
void fromJson(const ruc::Json& json, LuaScriptComponent& value);
|
||||
|
||||
} // namespace Inferno
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Riyyi
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "ruc/json/json.h"
|
||||
|
||||
#include "inferno/component/nativescriptcomponent.h"
|
||||
|
||||
namespace Inferno {
|
||||
|
||||
void fromJson(const ruc::Json& json, NativeScriptComponent& value)
|
||||
{
|
||||
VERIFY(json.type() == ruc::Json::Type::Object);
|
||||
|
||||
VERIFY(json.exists("name"), "name not found");
|
||||
json.at("name").getTo(value.name);
|
||||
}
|
||||
|
||||
} // namespace Inferno
|
||||
@@ -7,6 +7,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <utility> // std::move
|
||||
|
||||
#include "inferno/script/nativescript.h"
|
||||
|
||||
@@ -14,17 +15,29 @@ namespace Inferno {
|
||||
|
||||
struct NativeScriptComponent {
|
||||
NativeScript* instance { nullptr };
|
||||
std::string name;
|
||||
|
||||
NativeScript::InitializeFunction initialize { nullptr };
|
||||
NativeScript::DestroyFunction destroy { nullptr };
|
||||
|
||||
// Dont allow manually setting instance during construction
|
||||
NativeScriptComponent() {}
|
||||
NativeScriptComponent(const std::string& binding)
|
||||
NativeScriptComponent(const std::string& name)
|
||||
: name(std::move(name))
|
||||
{
|
||||
initialize = NativeScriptBinding::the().initializeBinding(binding);
|
||||
destroy = NativeScriptBinding::the().destroyBinding(binding);
|
||||
bind();
|
||||
}
|
||||
|
||||
void bind()
|
||||
{
|
||||
VERIFY(initialize == nullptr && destroy == nullptr, "NativeScript already bound");
|
||||
|
||||
VERIFY(name != "", "name not set");
|
||||
initialize = NativeScriptBinding::the().initializeBinding(name);
|
||||
destroy = NativeScriptBinding::the().destroyBinding(name);
|
||||
}
|
||||
};
|
||||
|
||||
void fromJson(const ruc::Json& json, NativeScriptComponent& value);
|
||||
|
||||
} // namespace Inferno
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Riyyi
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "ruc/json/json.h"
|
||||
|
||||
#include "inferno/component/tagcomponent.h"
|
||||
|
||||
namespace Inferno {
|
||||
|
||||
void fromJson(const ruc::Json& json, TagComponent& value)
|
||||
{
|
||||
VERIFY(json.type() == ruc::Json::Type::Object);
|
||||
|
||||
if (json.exists("tag")) {
|
||||
json.at("tag").getTo(value.tag);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Inferno
|
||||
@@ -9,6 +9,8 @@
|
||||
#include <string> // std::string
|
||||
#include <utility> // std::move
|
||||
|
||||
#include "ruc/json/json.h"
|
||||
|
||||
namespace Inferno {
|
||||
|
||||
struct TagComponent {
|
||||
@@ -23,4 +25,6 @@ struct TagComponent {
|
||||
operator const std::string&() const { return tag; }
|
||||
};
|
||||
|
||||
void fromJson(const ruc::Json& json, TagComponent& value);
|
||||
|
||||
} // namespace Inferno
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Riyyi
|
||||
* Copyright (C) 2022-2024 Riyyi
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
@@ -18,7 +18,7 @@ namespace Inferno {
|
||||
struct TextAreaComponent {
|
||||
std::string content;
|
||||
std::string font;
|
||||
unsigned char fontSize { 0 };
|
||||
unsigned char fontSize { 12 };
|
||||
float lineSpacing { 1.0f };
|
||||
uint32_t width { 0 };
|
||||
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Riyyi
|
||||
* Copyright (C) 2022,2024 Riyyi
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint> // uint32_t
|
||||
#include <optional>
|
||||
|
||||
#include "entt/entity/entity.hpp" // entt::null
|
||||
#include "entt/entity/fwd.hpp" // entt::entity
|
||||
#include "glm/ext/matrix_float4x4.hpp" // glm::mat4
|
||||
#include "glm/ext/vector_float3.hpp" // glm::vec3
|
||||
#include "ruc/format/format.h"
|
||||
@@ -17,6 +22,8 @@ struct TransformComponent {
|
||||
glm::vec3 translate { 0.0f, 0.0f, 0.0f };
|
||||
glm::vec3 rotate { 0.0f, 0.0f, 0.0f };
|
||||
glm::vec3 scale { 1.0f, 1.0f, 1.0f };
|
||||
entt::entity parent { entt::null };
|
||||
|
||||
glm::mat4 transform { 1.0f }; // Identity matrix
|
||||
};
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ Font::Font(const std::string& name)
|
||||
std::string font = ruc::File(path).data();
|
||||
parseFont(font);
|
||||
|
||||
m_texture = std::make_shared<Texture>(image);
|
||||
m_texture = Texture2D::create(image);
|
||||
}
|
||||
|
||||
// TODO: Move this to ruc
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Riyyi
|
||||
* Copyright (C) 2022,2024 Riyyi
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
@@ -216,10 +216,10 @@ Renderer2D::~Renderer2D()
|
||||
Renderer::destroy();
|
||||
}
|
||||
|
||||
void Renderer2D::beginScene(glm::mat4 cameraProjectionView)
|
||||
void Renderer2D::beginScene(glm::mat4 cameraProjection, glm::mat4 cameraView)
|
||||
{
|
||||
m_shader->bind();
|
||||
m_shader->setFloat("u_projectionView", cameraProjectionView);
|
||||
m_shader->setFloat("u_projectionView", cameraProjection * cameraView);
|
||||
m_shader->unbind();
|
||||
}
|
||||
|
||||
@@ -311,6 +311,184 @@ void Renderer2D::nextBatch()
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
RendererCubemap::RendererCubemap(s)
|
||||
{
|
||||
Renderer::initialize();
|
||||
|
||||
// CPU
|
||||
// ---------------------------------
|
||||
|
||||
// Create array for storing quads vertices
|
||||
m_vertexBufferBase = std::make_unique<CubemapVertex[]>(vertexCount);
|
||||
m_vertexBufferPtr = m_vertexBufferBase.get();
|
||||
|
||||
// Set default cubemap vertex positions
|
||||
|
||||
// Back face - v
|
||||
m_vertexPositions[0] = { 0.5f, -0.5f, 0.5f, 1.0f };
|
||||
m_vertexPositions[1] = { -0.5f, -0.5f, 0.5f, 1.0f };
|
||||
m_vertexPositions[2] = { -0.5f, 0.5f, 0.5f, 1.0f };
|
||||
m_vertexPositions[3] = { 0.5f, 0.5f, 0.5f, 1.0f };
|
||||
|
||||
// Left face - v
|
||||
m_vertexPositions[7] = { -0.5f, 0.5f, 0.5f, 1.0f };
|
||||
m_vertexPositions[6] = { -0.5f, 0.5f, -0.5f, 1.0f };
|
||||
m_vertexPositions[5] = { -0.5f, -0.5f, -0.5f, 1.0f };
|
||||
m_vertexPositions[4] = { -0.5f, -0.5f, 0.5f, 1.0f };
|
||||
|
||||
// Right face - v
|
||||
m_vertexPositions[8] = { 0.5f, -0.5f, -0.5f, 1.0f };
|
||||
m_vertexPositions[9] = { 0.5f, -0.5f, 0.5f, 1.0f };
|
||||
m_vertexPositions[10] = { 0.5f, 0.5f, 0.5f, 1.0f };
|
||||
m_vertexPositions[11] = { 0.5f, 0.5f, -0.5f, 1.0f };
|
||||
|
||||
// Front face - v
|
||||
m_vertexPositions[12] = { -0.5f, -0.5f, -0.5f, 1.0f };
|
||||
m_vertexPositions[13] = { 0.5f, -0.5f, -0.5f, 1.0f };
|
||||
m_vertexPositions[14] = { 0.5f, 0.5f, -0.5f, 1.0f };
|
||||
m_vertexPositions[15] = { -0.5f, 0.5f, -0.5f, 1.0f };
|
||||
|
||||
// Top face
|
||||
m_vertexPositions[16] = { -0.5f, 0.5f, -0.5f, 1.0f };
|
||||
m_vertexPositions[17] = { 0.5f, 0.5f, -0.5f, 1.0f };
|
||||
m_vertexPositions[18] = { 0.5f, 0.5f, 0.5f, 1.0f };
|
||||
m_vertexPositions[19] = { -0.5f, 0.5f, 0.5f, 1.0f };
|
||||
|
||||
// Bottom face
|
||||
m_vertexPositions[20] = { -0.5f, -0.5f, -0.5f, 1.0f };
|
||||
m_vertexPositions[21] = { -0.5f, -0.5f, 0.5f, 1.0f };
|
||||
m_vertexPositions[22] = { 0.5f, -0.5f, 0.5f, 1.0f };
|
||||
m_vertexPositions[23] = { 0.5f, -0.5f, -0.5f, 1.0f };
|
||||
|
||||
// Generate indices
|
||||
|
||||
uint32_t* indices = new uint32_t[indexCount];
|
||||
|
||||
uint32_t offset = 0;
|
||||
for (uint32_t i = 0; i < indexCount; 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 vertex buffer
|
||||
auto vertexBuffer = std::make_shared<VertexBuffer>(sizeof(CubemapVertex) * vertexCount);
|
||||
vertexBuffer->setLayout({
|
||||
{ BufferElementType::Vec3, "a_position" },
|
||||
{ BufferElementType::Vec4, "a_color" },
|
||||
{ BufferElementType::Float, "a_textureIndex" },
|
||||
});
|
||||
m_vertexArray->addVertexBuffer(vertexBuffer);
|
||||
|
||||
// Create index buffer
|
||||
auto indexBuffer = std::make_shared<IndexBuffer>(indices, sizeof(uint32_t) * indexCount);
|
||||
m_vertexArray->setIndexBuffer(indexBuffer);
|
||||
delete[] indices;
|
||||
|
||||
ruc::info("RendererCubemap initialized");
|
||||
}
|
||||
|
||||
RendererCubemap::~RendererCubemap()
|
||||
{
|
||||
Renderer::destroy();
|
||||
}
|
||||
|
||||
void RendererCubemap::beginScene(glm::mat4 cameraProjection, glm::mat4 cameraView)
|
||||
{
|
||||
// We want the skybox fixed in position, so only retain the rotation and scale.
|
||||
// Set the translation of the camera's view matrix to 0, meaning:
|
||||
// x x x 0
|
||||
// x x x 0
|
||||
// x x x 0
|
||||
// 0 0 0 1
|
||||
cameraView = glm::mat4(glm::mat3(cameraView));
|
||||
|
||||
m_shader->bind();
|
||||
m_shader->setFloat("u_projectionView", cameraProjection * cameraView);
|
||||
m_shader->unbind();
|
||||
}
|
||||
|
||||
void RendererCubemap::endScene()
|
||||
{
|
||||
nextBatch();
|
||||
}
|
||||
|
||||
void RendererCubemap::drawCubemap(const TransformComponent& transform, glm::vec4 color, std::shared_ptr<Texture> texture)
|
||||
{
|
||||
drawCubemap(transform, glm::mat4(color, color, color, color), texture);
|
||||
}
|
||||
|
||||
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 >= quadCount) {
|
||||
nextBatch();
|
||||
}
|
||||
|
||||
uint32_t textureUnitIndex = addTextureUnit(texture);
|
||||
|
||||
// Add the quads 4 vertices
|
||||
for (uint32_t i = 0; i < vertexPerQuad * quadPerCube; i++) {
|
||||
m_vertexBufferPtr->position = transform.transform * m_vertexPositions[i];
|
||||
m_vertexBufferPtr->color = color[i % 4];
|
||||
m_vertexBufferPtr->textureIndex = (float)textureUnitIndex;
|
||||
m_vertexBufferPtr++;
|
||||
}
|
||||
|
||||
m_quadIndex += quadPerCube;
|
||||
}
|
||||
|
||||
void RendererCubemap::loadShader()
|
||||
{
|
||||
m_shader = ShaderManager::the().load("assets/glsl/batch-cubemap");
|
||||
}
|
||||
|
||||
void RendererCubemap::flush()
|
||||
{
|
||||
if (m_quadIndex == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Upload vertex data to GPU
|
||||
m_vertexArray->getVertexBuffers().at(0)->uploadData(
|
||||
m_vertexBufferBase.get(),
|
||||
m_quadIndex * vertexPerQuad * sizeof(CubemapVertex));
|
||||
|
||||
bind();
|
||||
|
||||
// Render
|
||||
bool depthTest = RenderCommand::depthTest();
|
||||
RenderCommand::setDepthTest(false);
|
||||
RenderCommand::drawIndexed(*m_vertexArray, m_quadIndex * indexPerQuad);
|
||||
RenderCommand::setDepthTest(depthTest);
|
||||
|
||||
unbind();
|
||||
}
|
||||
|
||||
void RendererCubemap::startBatch()
|
||||
{
|
||||
m_quadIndex = 0;
|
||||
m_vertexBufferPtr = m_vertexBufferBase.get();
|
||||
|
||||
m_textureUnitIndex = 1;
|
||||
}
|
||||
|
||||
void RendererCubemap::nextBatch()
|
||||
{
|
||||
flush();
|
||||
startBatch();
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
RendererCharacter::RendererCharacter(s)
|
||||
{
|
||||
Renderer::initialize();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Riyyi
|
||||
* Copyright (C) 2022,2024 Riyyi
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
@@ -27,7 +27,13 @@ struct QuadVertex {
|
||||
glm::vec3 position { 0.0f, 0.0f, 0.0f };
|
||||
glm::vec4 color { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
glm::vec2 textureCoordinates { 0.0f, 0.0f };
|
||||
float textureIndex = 0; // @Todo get int to pass to fragment correctly
|
||||
float textureIndex = 0; // TODO: get int to pass to fragment correctly
|
||||
};
|
||||
|
||||
struct CubemapVertex {
|
||||
glm::vec3 position { 0.0f, 0.0f, 0.0f };
|
||||
glm::vec4 color { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
float textureIndex = 0; // TODO: get int to pass to fragment correctly
|
||||
};
|
||||
|
||||
struct CharacterVertex {
|
||||
@@ -66,9 +72,10 @@ public:
|
||||
|
||||
class Renderer {
|
||||
public:
|
||||
static const uint32_t vertexPerQuad = 4;
|
||||
static const uint32_t indexPerQuad = 6;
|
||||
static const uint32_t textureUnitPerBatch = 32;
|
||||
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 textureUnitPerBatch = 32;
|
||||
|
||||
protected:
|
||||
Renderer() {}
|
||||
@@ -108,11 +115,12 @@ public:
|
||||
|
||||
using Singleton<Renderer2D>::destroy;
|
||||
|
||||
static const uint32_t quadCount = 1000;
|
||||
static const uint32_t vertexCount = quadCount * vertexPerQuad;
|
||||
static const uint32_t indexCount = quadCount * indexPerQuad;
|
||||
// When to start a new batch
|
||||
static constexpr const uint32_t quadCount = 1000;
|
||||
static constexpr const uint32_t vertexCount = quadCount * vertexPerQuad;
|
||||
static constexpr const uint32_t indexCount = quadCount * indexPerQuad;
|
||||
|
||||
void beginScene(glm::mat4 cameraProjectionView);
|
||||
void beginScene(glm::mat4 cameraProjectionView, glm::mat4 cameraView);
|
||||
void endScene();
|
||||
|
||||
void drawQuad(const TransformComponent& transform, glm::vec4 color);
|
||||
@@ -133,6 +141,42 @@ private:
|
||||
// Default quad vertex positions
|
||||
glm::vec4 m_vertexPositions[vertexPerQuad];
|
||||
};
|
||||
// -------------------------------------
|
||||
|
||||
class RendererCubemap final
|
||||
: public Renderer
|
||||
, public ruc::Singleton<RendererCubemap> {
|
||||
public:
|
||||
RendererCubemap(s);
|
||||
virtual ~RendererCubemap();
|
||||
|
||||
using Singleton<RendererCubemap>::destroy;
|
||||
|
||||
// When to start a new batch
|
||||
static constexpr const uint32_t cubemapCount = 166;
|
||||
static constexpr const uint32_t quadCount = cubemapCount * quadPerCube;
|
||||
static constexpr const uint32_t vertexCount = quadCount * vertexPerQuad;
|
||||
static constexpr const uint32_t indexCount = quadCount * indexPerQuad;
|
||||
|
||||
void beginScene(glm::mat4 cameraProjectionView, glm::mat4 cameraView);
|
||||
void endScene();
|
||||
|
||||
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);
|
||||
|
||||
private:
|
||||
void loadShader() override;
|
||||
void flush() override;
|
||||
void startBatch() override;
|
||||
void nextBatch() override;
|
||||
|
||||
// CPU quad vertices
|
||||
std::unique_ptr<CubemapVertex[]> m_vertexBufferBase;
|
||||
CubemapVertex* m_vertexBufferPtr { nullptr };
|
||||
|
||||
// Default cubemap vertex positions
|
||||
glm::vec4 m_vertexPositions[vertexPerQuad * quadPerCube];
|
||||
};
|
||||
|
||||
// -------------------------------------
|
||||
|
||||
|
||||
+123
-42
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Riyyi
|
||||
* Copyright (C) 2022,2024 Riyyi
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
@@ -19,36 +19,47 @@
|
||||
|
||||
namespace Inferno {
|
||||
|
||||
Texture::Texture(const std::string& path)
|
||||
: m_path(std::move(path))
|
||||
Texture::~Texture()
|
||||
{
|
||||
unsigned char* data = nullptr;
|
||||
glDeleteTextures(1, &m_id);
|
||||
}
|
||||
|
||||
void Texture::init(uint32_t width, uint32_t height, uint8_t channels)
|
||||
{
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
|
||||
m_internalFormat = (channels == 3) ? GL_RGB8 : GL_RGBA8;
|
||||
m_dataFormat = (channels == 3) ? GL_RGB : GL_RGBA;
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
std::shared_ptr<Texture> Texture2D::create(const std::string& path)
|
||||
{
|
||||
auto result = std::shared_ptr<Texture2D>(new Texture2D);
|
||||
result->m_path = path;
|
||||
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
int channels = 0;
|
||||
unsigned char* data = nullptr;
|
||||
|
||||
// Load image data
|
||||
stbi_set_flip_vertically_on_load(1);
|
||||
data = stbi_load(path.c_str(), &width, &height, &channels, STBI_default);
|
||||
VERIFY(data, "failed to load image: '{}'", path);
|
||||
|
||||
init(data, width, height, channels);
|
||||
result->init(width, height, channels);
|
||||
result->create(data);
|
||||
|
||||
// Clean resources
|
||||
stbi_image_free(data);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Texture::Texture(unsigned char* data, uint32_t width, uint32_t height, uint8_t channels)
|
||||
{
|
||||
init(data, width, height, channels);
|
||||
}
|
||||
|
||||
Texture::~Texture()
|
||||
{
|
||||
glDeleteTextures(1, &m_id);
|
||||
}
|
||||
|
||||
void Texture::bind(uint32_t unit) const
|
||||
void Texture2D::bind(uint32_t unit) const
|
||||
{
|
||||
// Set active unit
|
||||
glActiveTexture(GL_TEXTURE0 + unit);
|
||||
@@ -59,31 +70,12 @@ void Texture::bind(uint32_t unit) const
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
|
||||
void Texture::unbind() const
|
||||
void Texture2D::unbind() const
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
void Texture::init(unsigned char* data, uint32_t width, uint32_t height, uint8_t channels)
|
||||
{
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
|
||||
if (channels == 4) {
|
||||
m_internalFormat = GL_RGBA8;
|
||||
m_dataFormat = GL_RGBA;
|
||||
}
|
||||
else if (channels == 3) {
|
||||
m_internalFormat = GL_RGB8;
|
||||
m_dataFormat = GL_RGB;
|
||||
}
|
||||
|
||||
create(data);
|
||||
}
|
||||
|
||||
void Texture::create(unsigned char* data)
|
||||
void Texture2D::create(unsigned char* data)
|
||||
{
|
||||
m_id = UINT_MAX;
|
||||
|
||||
@@ -109,10 +101,10 @@ void Texture::create(unsigned char* data)
|
||||
data); // Image data
|
||||
|
||||
// Set the texture wrapping / filtering options
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Magnify
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Minify
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // X
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Y
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Minify
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Magnify
|
||||
|
||||
// Automatically generate all mipmap levels
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
@@ -123,6 +115,94 @@ void Texture::create(unsigned char* data)
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
std::shared_ptr<Texture> TextureCubemap::create(const std::string& path)
|
||||
{
|
||||
auto result = std::shared_ptr<TextureCubemap>(new TextureCubemap);
|
||||
result->m_path = path;
|
||||
|
||||
result->create();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void TextureCubemap::bind(uint32_t unit) const
|
||||
{
|
||||
// Set active unit
|
||||
glActiveTexture(GL_TEXTURE0 + unit);
|
||||
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, m_id);
|
||||
|
||||
// Reset unit
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
|
||||
void TextureCubemap::unbind() const
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
||||
}
|
||||
|
||||
void TextureCubemap::create()
|
||||
{
|
||||
m_id = UINT_MAX;
|
||||
|
||||
// Create texture object
|
||||
glGenTextures(1, &m_id);
|
||||
|
||||
// Bind texture object
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, m_id);
|
||||
|
||||
// Set unpacking of pixel data to byte-alignment,
|
||||
// this prevents alignment issues when using a single byte for color
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
stbi_set_flip_vertically_on_load(0);
|
||||
|
||||
static constexpr const char* cubemapPaths[6] { "-px", "-nx", "-py", "-ny", "-pz", "-nz" };
|
||||
size_t dotIndex = m_path.find_last_of('.');
|
||||
std::string path = m_path.substr(0, dotIndex);
|
||||
std::string extension = m_path.substr(dotIndex);
|
||||
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
int channels = 0;
|
||||
unsigned char* data = nullptr;
|
||||
for (size_t i = 0; i < 6; ++i) {
|
||||
std::string facePath = path + cubemapPaths[i] + extension;
|
||||
|
||||
// Load image data
|
||||
data = stbi_load(facePath.c_str(), &width, &height, &channels, STBI_default);
|
||||
VERIFY(data, "failed to load image: '{}'", facePath.c_str());
|
||||
|
||||
init(width, height, channels);
|
||||
|
||||
// Generate texture face
|
||||
glTexImage2D(
|
||||
GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, // Texture target
|
||||
0, // Midmap level, base starts at level 0
|
||||
m_internalFormat, // Internal format
|
||||
m_width, m_height, // Image width/height
|
||||
0, // Always 0 (legacy)
|
||||
m_dataFormat, // Texture source format
|
||||
GL_UNSIGNED_BYTE, // Texture source datatype
|
||||
data); // Image data
|
||||
|
||||
// Clean resources
|
||||
stbi_image_free(data);
|
||||
}
|
||||
|
||||
// Set the texture wrapping / filtering options
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Magnify
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // Minify
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // X
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // Y
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); // Z
|
||||
|
||||
// Unbind texture object
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
TextureManager::TextureManager(s)
|
||||
{
|
||||
ruc::info("TextureManager initialized");
|
||||
@@ -138,15 +218,16 @@ void TextureManager::add(const std::string& path, std::shared_ptr<Texture> textu
|
||||
m_textureList.emplace(std::move(path), std::move(texture));
|
||||
}
|
||||
|
||||
std::shared_ptr<Texture> TextureManager::load(const std::string& path)
|
||||
std::shared_ptr<Texture> TextureManager::load(const std::string& path, Texture::Type type)
|
||||
{
|
||||
if (exists(path)) {
|
||||
return get(path);
|
||||
}
|
||||
|
||||
std::shared_ptr<Texture> texture = std::make_shared<Texture>(path);
|
||||
auto texture = (type == Texture::TwoDimensional) ? Texture2D::create(path) : TextureCubemap::create(path);
|
||||
add(path, texture);
|
||||
return get(path);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
std::shared_ptr<Texture> TextureManager::get(const std::string& path)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Riyyi
|
||||
* Copyright (C) 2022,2024 Riyyi
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
@@ -15,33 +15,88 @@
|
||||
|
||||
namespace Inferno {
|
||||
|
||||
class Texture2D;
|
||||
class TextureCubemap;
|
||||
|
||||
class Texture {
|
||||
public:
|
||||
Texture(const std::string& path);
|
||||
Texture(unsigned char* data, uint32_t width, uint32_t height, uint8_t channels = 3);
|
||||
virtual ~Texture();
|
||||
|
||||
void bind(uint32_t unit = 0) const;
|
||||
void unbind() const;
|
||||
enum Type : uint8_t {
|
||||
TwoDimensional = 0,
|
||||
Cubemap,
|
||||
};
|
||||
|
||||
inline std::string path() const { return m_path; }
|
||||
inline uint32_t width() const { return m_width; }
|
||||
inline uint32_t height() const { return m_height; }
|
||||
inline uint32_t id() const { return m_id; }
|
||||
inline uint32_t internalFormat() const { return m_internalFormat; }
|
||||
inline uint32_t dataFormat() const { return m_dataFormat; }
|
||||
void init(uint32_t width, uint32_t height, uint8_t channels);
|
||||
|
||||
virtual void bind(uint32_t unit = 0) const = 0;
|
||||
virtual void unbind() const = 0;
|
||||
|
||||
std::string path() const { return m_path; }
|
||||
uint32_t width() const { return m_width; }
|
||||
uint32_t height() const { return m_height; }
|
||||
uint32_t id() const { return m_id; }
|
||||
uint32_t internalFormat() const { return m_internalFormat; }
|
||||
uint32_t dataFormat() const { return m_dataFormat; }
|
||||
|
||||
virtual bool is2D() const { return false; }
|
||||
virtual bool isCubeMap() const { return false; }
|
||||
|
||||
friend Texture2D;
|
||||
friend TextureCubemap;
|
||||
|
||||
protected:
|
||||
void init(unsigned char* data, uint32_t width, uint32_t height, uint8_t channels);
|
||||
void create(unsigned char* data);
|
||||
Texture() {}
|
||||
|
||||
protected:
|
||||
std::string m_path;
|
||||
uint32_t m_width { 0 };
|
||||
uint32_t m_height { 0 };
|
||||
uint32_t m_id { 0 };
|
||||
uint32_t m_internalFormat { 0 };
|
||||
uint32_t m_dataFormat { 0 };
|
||||
};
|
||||
|
||||
// -------------------------------------
|
||||
|
||||
class Texture2D final : public Texture {
|
||||
public:
|
||||
virtual ~Texture2D() = default;
|
||||
|
||||
// Factory function
|
||||
static std::shared_ptr<Texture> create(const std::string& path);
|
||||
|
||||
virtual void bind(uint32_t unit = 0) const override;
|
||||
virtual void unbind() const override;
|
||||
|
||||
private:
|
||||
std::string m_path;
|
||||
uint32_t m_width;
|
||||
uint32_t m_height;
|
||||
uint32_t m_id;
|
||||
uint32_t m_internalFormat;
|
||||
uint32_t m_dataFormat;
|
||||
Texture2D() {}
|
||||
|
||||
virtual bool is2D() const override { return true; }
|
||||
|
||||
private:
|
||||
void create(unsigned char* data);
|
||||
};
|
||||
|
||||
// -------------------------------------
|
||||
|
||||
class TextureCubemap final : public Texture {
|
||||
public:
|
||||
virtual ~TextureCubemap() = default;
|
||||
|
||||
// Factory function
|
||||
static std::shared_ptr<Texture> create(const std::string& path);
|
||||
|
||||
virtual void bind(uint32_t unit = 0) const override;
|
||||
virtual void unbind() const override;
|
||||
|
||||
private:
|
||||
TextureCubemap() {};
|
||||
|
||||
virtual bool isCubeMap() const override { return true; }
|
||||
|
||||
private:
|
||||
void create();
|
||||
};
|
||||
|
||||
// -------------------------------------
|
||||
@@ -52,7 +107,7 @@ public:
|
||||
~TextureManager();
|
||||
|
||||
void add(const std::string& path, std::shared_ptr<Texture> texture);
|
||||
std::shared_ptr<Texture> load(const std::string& path);
|
||||
std::shared_ptr<Texture> load(const std::string& path, Texture::Type type = Texture::Type::TwoDimensional);
|
||||
std::shared_ptr<Texture> get(const std::string& path);
|
||||
bool exists(const std::string& path);
|
||||
|
||||
|
||||
+88
-52
@@ -1,18 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Riyyi
|
||||
* Copyright (C) 2022-2024 Riyyi
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdint> // uint32_t
|
||||
#include <limits> // std::numeric_limits
|
||||
#include <utility> // std::pair
|
||||
|
||||
#include "entt/entity/entity.hpp" // ent::entity
|
||||
#include "ruc/file.h"
|
||||
#include "ruc/format/log.h"
|
||||
#include "ruc/json/json.h"
|
||||
#include "ruc/meta/assert.h"
|
||||
|
||||
#include "inferno/component/cameracomponent.h"
|
||||
#include "inferno/component/cubemap-component.h"
|
||||
#include "inferno/component/id-component.h"
|
||||
#include "inferno/component/luascriptcomponent.h"
|
||||
#include "inferno/component/nativescriptcomponent.h"
|
||||
#include "inferno/component/spritecomponent.h"
|
||||
@@ -26,6 +31,7 @@
|
||||
#include "inferno/system/scriptsystem.h"
|
||||
#include "inferno/system/textareasystem.h"
|
||||
#include "inferno/system/transformsystem.h"
|
||||
#include "inferno/uid.h"
|
||||
|
||||
namespace Inferno {
|
||||
|
||||
@@ -47,54 +53,19 @@ void Scene::initialize()
|
||||
|
||||
auto sceneJson = ruc::Json::parse(ruc::File("assets/scene/scene1.json").data());
|
||||
|
||||
// Camera
|
||||
|
||||
VERIFY(sceneJson.exists("camera"), "scene doesnt contain a camera");
|
||||
auto& cameraJson = sceneJson.at("camera");
|
||||
uint32_t camera = loadEntity(cameraJson);
|
||||
|
||||
auto& cameraComponent = addComponent<CameraComponent>(camera);
|
||||
if (cameraJson.exists("type") && cameraJson.at("type").get<std::string>() == "orthographic") {
|
||||
cameraComponent.type = CameraType::Orthographic;
|
||||
}
|
||||
if (cameraJson.exists("zoom-level") && cameraJson.at("zoom-level").type() == ruc::Json::Type::Number) {
|
||||
cameraComponent.zoomLevel = cameraJson.at("zoom-level").asDouble();
|
||||
if (sceneJson.exists("init")) {
|
||||
// TODO: load either NativeScript or LuaScript?
|
||||
}
|
||||
|
||||
if (cameraJson.exists("script")) {
|
||||
auto& cameraScript = cameraJson.at("script");
|
||||
if (cameraScript.exists("type") && cameraScript.exists("name")) {
|
||||
auto name = cameraScript.at("name").get<std::string>();
|
||||
if (cameraScript.at("type").get<std::string>() == "lua") {
|
||||
addComponent<LuaScriptComponent>(camera, name);
|
||||
}
|
||||
else {
|
||||
addComponent<NativeScriptComponent>(camera, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Entities
|
||||
// -------------------------------------
|
||||
|
||||
// Quads
|
||||
|
||||
if (sceneJson.exists("quad") && sceneJson.at("quad").type() == ruc::Json::Type::Array) {
|
||||
auto& quads = sceneJson.at("quad").asArray().elements();
|
||||
for (const auto& quad : quads) {
|
||||
uint32_t quadEntity = loadEntity(quad);
|
||||
addComponent<SpriteComponent>(quadEntity);
|
||||
auto& spriteComponent = getComponent<SpriteComponent>(quadEntity);
|
||||
quad.getTo(spriteComponent);
|
||||
}
|
||||
}
|
||||
|
||||
// Text
|
||||
|
||||
if (sceneJson.exists("text") && sceneJson.at("text").type() == ruc::Json::Type::Array) {
|
||||
auto& texts = sceneJson.at("text").asArray().elements();
|
||||
for (const auto& text : texts) {
|
||||
uint32_t textEntity = loadEntity(text);
|
||||
addComponent<TextAreaComponent>(textEntity);
|
||||
auto& textAreaComponent = getComponent<TextAreaComponent>(textEntity);
|
||||
text.getTo(textAreaComponent);
|
||||
if (sceneJson.exists("entities")) {
|
||||
const auto& entityJson = sceneJson.at("entities");
|
||||
VERIFY(entityJson.type() == ruc::Json::Type::Array);
|
||||
const auto& entities = entityJson.asArray();
|
||||
for (size_t i = 0; i < entities.size(); ++i) {
|
||||
loadEntity(entities.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,22 +94,85 @@ void Scene::destroy()
|
||||
TransformSystem::destroy();
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
uint32_t Scene::createEntity(const std::string& name)
|
||||
{
|
||||
return createEntityWithUID(UID(), name);
|
||||
}
|
||||
|
||||
uint32_t Scene::createEntityWithUID(UID id, const std::string& name)
|
||||
{
|
||||
uint32_t entity = static_cast<uint32_t>(m_registry->create());
|
||||
addComponent<IDComponent>(entity, id);
|
||||
addComponent<TagComponent>(entity, name.empty() ? "Unnamed Entity" : name);
|
||||
addComponent<TransformComponent>(entity);
|
||||
|
||||
TransformSystem::the().add(entity);
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
uint32_t Scene::loadEntity(ruc::Json json)
|
||||
uint32_t Scene::loadEntity(ruc::Json components, uint32_t parentEntity)
|
||||
{
|
||||
uint32_t entity = createEntity((json.exists("name"))
|
||||
? json.at("name").get<std::string>()
|
||||
: "");
|
||||
VERIFY(components.type() == ruc::Json::Type::Object);
|
||||
|
||||
uint32_t entity = createEntity();
|
||||
|
||||
// At minimum, ID is required
|
||||
VERIFY(components.exists("id"), "id not found");
|
||||
auto& id = getComponent<IDComponent>(entity);
|
||||
components.at("id").getTo(id);
|
||||
|
||||
if (components.exists("tag")) {
|
||||
auto& tag = getComponent<TagComponent>(entity);
|
||||
components.at("tag").getTo(tag);
|
||||
}
|
||||
if (components.exists("transform")) {
|
||||
auto& transform = getComponent<TransformComponent>(entity);
|
||||
json.getTo(transform);
|
||||
components.at("transform").getTo(transform);
|
||||
transform.parent = static_cast<entt::entity>(parentEntity);
|
||||
}
|
||||
if (components.exists("camera")) {
|
||||
auto& camera = addComponent<CameraComponent>(entity);
|
||||
components.at("camera").getTo(camera);
|
||||
}
|
||||
if (components.exists("lua-scripts")) {
|
||||
VERIFY(components.at("lua-scripts").type() == ruc::Json::Type::Array);
|
||||
const auto& scripts = components.at("lua-scripts").asArray();
|
||||
for (size_t i = 0; i < scripts.size(); ++i) {
|
||||
auto& script = addComponent<LuaScriptComponent>(entity);
|
||||
scripts.at(i).getTo(script);
|
||||
}
|
||||
}
|
||||
if (components.exists("native-scripts")) {
|
||||
VERIFY(components.at("native-scripts").type() == ruc::Json::Type::Array);
|
||||
const auto& scripts = components.at("native-scripts").asArray();
|
||||
for (size_t i = 0; i < scripts.size(); ++i) {
|
||||
auto& script = addComponent<NativeScriptComponent>(entity);
|
||||
scripts.at(i).getTo(script);
|
||||
script.bind();
|
||||
}
|
||||
}
|
||||
if (components.exists("sprite")) {
|
||||
auto& sprite = addComponent<SpriteComponent>(entity);
|
||||
components.at("sprite").getTo(sprite);
|
||||
}
|
||||
if (components.exists("cubemap")) {
|
||||
auto& cubemap = addComponent<CubemapComponent>(entity);
|
||||
components.at("cubemap").getTo(cubemap);
|
||||
}
|
||||
if (components.exists("text")) {
|
||||
auto& text = addComponent<TextAreaComponent>(entity);
|
||||
components.at("text").getTo(text);
|
||||
}
|
||||
if (components.exists("children")) {
|
||||
VERIFY(components.at("children").type() == ruc::Json::Type::Array);
|
||||
const auto& children = components.at("children").asArray();
|
||||
for (size_t i = 0; i < children.size(); ++i) {
|
||||
loadEntity(components.at("children")[i], entity);
|
||||
}
|
||||
}
|
||||
|
||||
return entity;
|
||||
}
|
||||
@@ -162,7 +196,9 @@ void Scene::destroyEntity(uint32_t entity)
|
||||
m_registry->destroy(entt::entity { entity });
|
||||
}
|
||||
|
||||
glm::mat4 Scene::cameraProjectionView()
|
||||
// -----------------------------------------
|
||||
|
||||
std::pair<glm::mat4, glm::mat4> Scene::cameraProjectionView()
|
||||
{
|
||||
return CameraSystem::the().projectionView();
|
||||
}
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Riyyi
|
||||
* Copyright (C) 2022,2024 Riyyi
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdint> // uint32_t
|
||||
#include <memory> // std::shared_ptr
|
||||
#include <utility> // std::pair
|
||||
|
||||
#include "entt/entity/registry.hpp" // entt::entity, entt::registry
|
||||
#include "glm/ext/matrix_float4x4.hpp" // glm::mat4
|
||||
#include "ruc/format/format.h"
|
||||
#include "ruc/json/json.h"
|
||||
|
||||
#include "inferno/uid.h"
|
||||
|
||||
namespace Inferno {
|
||||
|
||||
class Camera;
|
||||
@@ -27,11 +31,15 @@ public:
|
||||
void destroy();
|
||||
|
||||
uint32_t createEntity(const std::string& name = "");
|
||||
uint32_t loadEntity(ruc::Json json);
|
||||
uint32_t createEntityWithUID(UID id, const std::string& name = "");
|
||||
uint32_t loadEntity(ruc::Json components, uint32_t parentEntity = entt::null);
|
||||
uint32_t findEntity(std::string_view name);
|
||||
void destroyEntity(uint32_t entity);
|
||||
|
||||
glm::mat4 cameraProjectionView();
|
||||
/**
|
||||
* @brief Return a pair from the camera component: { projection, view }
|
||||
*/
|
||||
std::pair<glm::mat4, glm::mat4> cameraProjectionView();
|
||||
|
||||
void validEntity(uint32_t entity) const;
|
||||
|
||||
@@ -49,7 +57,8 @@ public:
|
||||
return m_registry->any<T...>(entt::entity { entity });
|
||||
}
|
||||
|
||||
// @Todo Should replace be allowed? could trigger memory leaks with nativescript
|
||||
// TODO: Should replace be allowed? could trigger memory leaks with nativescript
|
||||
// TODO: Replace will make it so an entity cant have multiple scripts
|
||||
template<typename T, typename... P>
|
||||
T& addComponent(uint32_t entity, P&&... parameters) const
|
||||
{
|
||||
@@ -64,7 +73,7 @@ public:
|
||||
return m_registry->remove_if_exists<T>(entt::entity { entity });
|
||||
}
|
||||
|
||||
// @Todo Should replace be allowed? could trigger memory leaks with nativescript
|
||||
// TODO: Should replace be allowed? could trigger memory leaks with nativescript
|
||||
template<typename T, typename... P>
|
||||
T& getComponent(uint32_t entity, P&&... parameters) const
|
||||
{
|
||||
|
||||
@@ -55,8 +55,8 @@ public:
|
||||
m_detroyBindings.emplace(binding, destroy);
|
||||
}
|
||||
|
||||
NativeScript::InitializeFunction initializeBinding(const std::string& binding) { return m_initializeBindings[binding]; }
|
||||
NativeScript::DestroyFunction destroyBinding(const std::string& binding) { return m_detroyBindings[binding]; }
|
||||
NativeScript::InitializeFunction initializeBinding(const std::string& name) { return m_initializeBindings[name]; }
|
||||
NativeScript::DestroyFunction destroyBinding(const std::string& name) { return m_detroyBindings[name]; }
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, NativeScript::InitializeFunction> m_initializeBindings;
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Riyyi
|
||||
* Copyright (C) 2022,2024 Riyyi
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <utility> // std::pair
|
||||
|
||||
#include "glm/ext/matrix_clip_space.hpp" // glm::perspective, glm::ortho
|
||||
#include "glm/ext/matrix_transform.hpp" // glm::radians, glm::lookAt
|
||||
#include "ruc/format/log.h"
|
||||
@@ -42,17 +44,17 @@ void CameraSystem::update()
|
||||
}
|
||||
}
|
||||
|
||||
glm::mat4 CameraSystem::projectionView()
|
||||
std::pair<glm::mat4, glm::mat4> CameraSystem::projectionView()
|
||||
{
|
||||
auto view = m_registry->view<TransformComponent, CameraComponent>();
|
||||
|
||||
for (auto [entity, transform, camera] : view.each()) {
|
||||
return camera.projection * transform.transform;
|
||||
return { camera.projection, transform.transform };
|
||||
}
|
||||
|
||||
VERIFY_NOT_REACHED();
|
||||
|
||||
return glm::mat4 { 1.0f };
|
||||
return {};
|
||||
}
|
||||
|
||||
void CameraSystem::updateOrthographic(TransformComponent& transform, CameraComponent& camera)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Riyyi
|
||||
* Copyright (C) 2022,2024 Riyyi
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
@@ -7,6 +7,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory> //std::shared_ptr
|
||||
#include <utility> // std::pair
|
||||
|
||||
#include "entt/entity/registry.hpp" // entt::entity, entt::registry
|
||||
#include "glm/ext/matrix_float4x4.hpp" // glm::mat4
|
||||
@@ -27,7 +28,10 @@ public:
|
||||
|
||||
void update();
|
||||
|
||||
glm::mat4 projectionView();
|
||||
/**
|
||||
* @brief Return a pair from the camera component: { projection, view }
|
||||
*/
|
||||
std::pair<glm::mat4, glm::mat4> projectionView();
|
||||
|
||||
void setRegistry(std::shared_ptr<entt::registry> registry) { m_registry = registry; };
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Riyyi
|
||||
* Copyright (C) 2022,2024 Riyyi
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "glm/ext/matrix_transform.hpp" // glm::translate, glm::rotate, glm::scale, glm::radians
|
||||
#include "ruc/format/log.h"
|
||||
|
||||
#include "inferno/component/cubemap-component.h"
|
||||
#include "inferno/component/spritecomponent.h"
|
||||
#include "inferno/component/transformcomponent.h"
|
||||
#include "inferno/render/renderer.h"
|
||||
@@ -25,11 +26,17 @@ RenderSystem::~RenderSystem()
|
||||
|
||||
void RenderSystem::render()
|
||||
{
|
||||
auto group = m_registry->group<TransformComponent, SpriteComponent>();
|
||||
auto quadView = m_registry->view<TransformComponent, SpriteComponent>();
|
||||
|
||||
for (auto [entity, transform, sprite] : group.each()) {
|
||||
for (auto [entity, transform, sprite] : quadView.each()) {
|
||||
Renderer2D::the().drawQuad(transform, sprite.color, sprite.texture);
|
||||
}
|
||||
|
||||
auto cubemapView = m_registry->view<TransformComponent, CubemapComponent>();
|
||||
|
||||
for (auto [entity, transform, cubemap] : cubemapView.each()) {
|
||||
RendererCubemap::the().drawCubemap(transform, cubemap.color, cubemap.texture);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Inferno
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Riyyi
|
||||
* Copyright (C) 2022,2024 Riyyi
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <algorithm> // std::sort
|
||||
#include <cstdint> // uint32_t
|
||||
|
||||
#include "entt/entity/fwd.hpp" // entt:entity
|
||||
#include "glm/ext/matrix_transform.hpp" // glm::translate, glm::rotate, glm::scale, glm::radians
|
||||
#include "ruc/format/log.h"
|
||||
|
||||
@@ -25,7 +29,7 @@ void TransformSystem::update()
|
||||
{
|
||||
auto view = m_registry->view<TransformComponent>();
|
||||
|
||||
for (auto entity : view) {
|
||||
for (auto entity : m_hierarchy) {
|
||||
|
||||
auto& component = view.get<TransformComponent>(entity);
|
||||
|
||||
@@ -42,7 +46,29 @@ void TransformSystem::update()
|
||||
|
||||
// Scale
|
||||
component.transform = glm::scale(component.transform, component.scale);
|
||||
|
||||
// Apply the parent transform to the child transform
|
||||
if (component.parent != entt::null) {
|
||||
auto& parent = view.get<TransformComponent>(component.parent);
|
||||
component.transform = parent.transform * component.transform;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TransformSystem::add(uint32_t entity)
|
||||
{
|
||||
m_hierarchy.push_back(static_cast<entt::entity>(entity));
|
||||
}
|
||||
|
||||
void TransformSystem::sort()
|
||||
{
|
||||
std::sort(m_hierarchy.begin(), m_hierarchy.end(),
|
||||
[](entt::entity a, entt::entity b) {
|
||||
return (a == entt::null && b == entt::null) ? false
|
||||
: (a == entt::null) ? true
|
||||
: (b == entt::null) ? false
|
||||
: a < b;
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace Inferno
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Riyyi
|
||||
* Copyright (C) 2022,2024 Riyyi
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint> // uint32_t
|
||||
#include <memory> // std::shared_ptr
|
||||
#include <vector>
|
||||
|
||||
#include "entt/entity/registry.hpp" // entt::entity, entt::registry
|
||||
#include "ruc/singleton.h"
|
||||
@@ -20,9 +22,14 @@ public:
|
||||
|
||||
void update();
|
||||
|
||||
void add(uint32_t entity);
|
||||
void sort();
|
||||
|
||||
void setRegistry(std::shared_ptr<entt::registry> registry) { m_registry = registry; };
|
||||
|
||||
private:
|
||||
std::vector<entt::entity> m_hierarchy;
|
||||
|
||||
std::shared_ptr<entt::registry> m_registry;
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Riyyi
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#include <random>
|
||||
|
||||
#include "ruc/format/log.h"
|
||||
#include "ruc/json/json.h"
|
||||
|
||||
#include "inferno/uid.h"
|
||||
|
||||
namespace Inferno {
|
||||
|
||||
static std::random_device s_seed;
|
||||
static std::mt19937_64 s_engine(s_seed());
|
||||
static std::uniform_int_distribution<uint64_t> s_distribution;
|
||||
|
||||
UID::UID()
|
||||
: m_uid(s_distribution(s_engine))
|
||||
{
|
||||
}
|
||||
|
||||
UID::UID(uint64_t uid)
|
||||
: m_uid(uid)
|
||||
{
|
||||
}
|
||||
|
||||
void fromJson(const ruc::Json& json, UID& value)
|
||||
{
|
||||
VERIFY(json.type() == ruc::Json::Type::Number);
|
||||
|
||||
value = UID((int64_t)json.asDouble());
|
||||
}
|
||||
|
||||
} // namespace Inferno
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Riyyi
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint> // uint64_t
|
||||
|
||||
#include "ruc/json/json.h"
|
||||
|
||||
namespace Inferno {
|
||||
|
||||
class UID {
|
||||
public:
|
||||
UID();
|
||||
UID(uint64_t uid);
|
||||
|
||||
// Comparison operator for std::map
|
||||
bool operator<(const UID& other) const
|
||||
{
|
||||
return m_uid < other.m_uid;
|
||||
}
|
||||
|
||||
operator uint64_t() const { return m_uid; }
|
||||
|
||||
private:
|
||||
uint64_t m_uid;
|
||||
};
|
||||
|
||||
void fromJson(const ruc::Json& json, UID& value);
|
||||
|
||||
} // namespace Inferno
|
||||
|
||||
namespace std {
|
||||
|
||||
// Hash function for std::unordered_map
|
||||
template<>
|
||||
struct hash<Inferno::UID> {
|
||||
size_t operator()(const Inferno::UID& uid) const
|
||||
{
|
||||
return hash<uint64_t>()(static_cast<uint64_t>(uid));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
Reference in New Issue
Block a user