ECS with entt

This commit is contained in:
Erris
2026-02-17 00:50:43 +01:00
parent 86392e0790
commit d4c420d5b4
30 changed files with 1314 additions and 222 deletions

View File

@@ -1,209 +1,292 @@
#ifndef EDITOR_HPP
#define EDITOR_HPP
#include "open_engine/input/input_system.hpp"
#include <view_layer.hpp>
#include "open_engine/ref_scope.hpp"
#include "panels/scene_hierarchy.hpp"
#include <open_engine.hpp>
#include <glm/ext/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/matrix.hpp>
#include <glm/fwd.hpp>
#include <imgui.h>
#include <entt/entt.hpp>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <cstdint>
#include <imgui.h>
class EditorLayer : public OpenEngine::Layer
{
public:
EditorLayer(OpenEngine::Ref<ViewLayer>& view_layer)
: OpenEngine::Layer("editor_layer"),
view(view_layer)
namespace OpenEngine {
class CameraController : public NativeScriptableEntity
{
public:
void OnCreate()
{
};
void OnUpdate()
{
auto delta = Time::DeltaTime();
auto& transform = GetComponent<TransformComponent>();
if (Input::IsKeyPressed(KeyCode::Up))
transform.transform[3][1] += 5.0 * delta;
if (Input::IsKeyPressed(KeyCode::Down))
transform.transform[3][1] -= 5.0 * delta;
if (Input::IsKeyPressed(KeyCode::Right))
transform.transform[3][0] += 5.0 * delta;
if (Input::IsKeyPressed(KeyCode::Left))
transform.transform[3][0] -= 5.0 * delta;
};
void OnDestroy()
{
};
};
class EditorLayer : public Layer
{
public:
EditorLayer()
: Layer("editor_layer")/*,
camera((float)Application::Get().GetWindow().GetWidth() /
Application::Get().GetWindow().GetHeight(), 1.0f)
*/
{
}
~EditorLayer() {};
~EditorLayer() {};
void OnAttach() override
{
OE_PROFILE_FUNCTION();
}
entt::registry registry;
void OnDetach() override
{
}
void OnUpdate() override
{
OpenEngine::Renderer2D::ResetStats();
void OnAttach() override
{
OE_PROFILE_FUNCTION();
view->GetCamera().OnUpdate();
FramebufferSpecification specs;
specs.width = 1280;
specs.height = 720;
framebuffer = FrameBuffer::Create(specs);
scene = CreateRef<Scene>();
sq_entity = scene->CreateEntity("square");
sq_entity.AddComponents<TransformComponent>();
sq_entity.AddComponents<SpriteRendererComponent>(glm::vec4(1.0f, 0.0f, 0.0f, 1.0f));
camera_bis = scene->CreateEntity("Main camera");
camera_bis.AddComponents<TransformComponent>();
camera_bis.AddComponents<CameraComponent>();
camera_bis.AddComponents<NativeScriptComponent>().Bind<CameraController>();
scene_hierarchy.SetContext(scene);
}
OpenEngine::Renderer2D::EndScene();
}
void OnEvent(OpenEngine::Event& event) override
{
OE_PROFILE_FUNCTION();
void OnDetach() override
{
OE_PROFILE_SCOPE("Camera OnEvent");
view->GetCamera().OnEvent(event);
}
}
float remap(float value, float minInput, float maxInput, float minOutput, float maxOutput) {
// 1. Normalize the input to a 0.0 - 1.0 range
float t = (value - minInput) / (maxInput - minInput);
// 2. Use glm::mix to interpolate between the output range
return glm::mix(minOutput, maxOutput, t);
}
glm::vec3 ScreenToWorld(
float screenX,
float screenY,
float screenZ, // depth value (0.0 = near plane, 1.0 = far plane)
const glm::mat4& view,
const glm::mat4& projection,
int viewportWidth,
int viewportHeight)
{
// 1. Convert screen coordinates to normalized device coordinates (NDC)
// Screen space: origin at top-left, Y points down
// NDC space: origin at center, range [-1, 1] for x and y
float x = (2.0f * screenX) / viewportWidth - 1.0f;
float y = 1.0f - (2.0f * screenY) / viewportHeight; // Flip Y
float z = 2.0f * screenZ - 1.0f; // [0,1] -> [-1,1]
glm::vec4 clipCoords(x, y, z, 1.0f);
// 2. Transform from clip space to view space
glm::mat4 invProjection = glm::inverse(projection);
glm::vec4 viewCoords = invProjection * clipCoords;
// 3. Transform from view space to world space
glm::mat4 invView = glm::inverse(view);
glm::vec4 worldCoords = invView * viewCoords;
// 4. Perspective divide
if (worldCoords.w != 0.0f) {
worldCoords /= worldCoords.w;
}
return glm::vec3(worldCoords);
}
void OnImGuiRender() override
{
OE_PROFILE_FUNCTION();
OpenEngine::Ref<OpenEngine::FrameBuffer> framebuffer = view->GetFramebuffer();
ImGui::DockSpaceOverViewport();
ImGui::Begin("Square settings");
//ImGui::SliderFloat("Angle", &angle, -360, 360);
//ImGui::ColorPicker4("Rectangle color", &rectangle_color[0]);
for (auto& result : profiling_results)
void OnUpdate() override
{
char label[50];
strcpy(label, "%.3fms ");
strcat(label, result.name);
ImGui::Text(label, result.duration);
FramebufferSpecification spec = framebuffer->GetSpecification();
if (viewport_size.x > 0.0f && viewport_size.y > 0.0f &&
(spec.width != viewport_size.x || spec.height != viewport_size.y))
{
framebuffer->Resize((uint32_t)viewport_size.x, (uint32_t)viewport_size.y);
//camera.OnResize(viewport_size.x, viewport_size.y);
}
{
OE_PROFILE_SCOPE("Setting up Rendering");
//camera.OnUpdate();
framebuffer->Bind();
scene->OnViewportResize((uint32_t)viewport_size.x, (uint32_t)viewport_size.y);
}
Renderer2D::ResetStats();
RenderCommand::SetClearColor({0.11f, 0.11f, 0.15f, 1.0f});
RenderCommand::Clear();
//Renderer2D::BeginScene(camera.GetCamera());
/*
for (float y = -5.0f; y < 5.0f; y += 0.5f) {
for (float x = -5.0f; x < 5.0f; x += 0.5f) {
glm::vec4 gradient_color = {(x + 5.0f) / 10.0f, 0.3f, (y + 5.0f) / 10.0f, 1.0f};
Renderer2D::DrawQuad({{x, y, 0.0f}, glm::vec3(0.45f, 0.45f, 0.0f)}, gradient_color);
}
}
Transform tr5 = {
glm::vec3(world_pos_cursor.x, world_pos_cursor.y, 0.9f),
glm::vec3(0.1f, 0.1f, 0.0f), 0.0f};
Renderer2D::DrawQuad(tr5, {1, 1, 1, 1});
*/
scene->OnUpdate();
//Renderer2D::EndScene();
framebuffer->Unbind();
}
profiling_results.clear();
void OnEvent(Event& event) override
{
OE_PROFILE_FUNCTION();
//camera.OnEvent(event);
}
float remap(float value, float minInput, float maxInput, float minOutput, float maxOutput) {
// 1. Normalize the input to a 0.0 - 1.0 range
float t = (value - minInput) / (maxInput - minInput);
// 2. Use glm::mix to interpolate between the output range
return glm::mix(minOutput, maxOutput, t);
}
glm::vec3 ScreenToWorld(
float screenX,
float screenY,
float screenZ, // depth value (0.0 = near plane, 1.0 = far plane)
const glm::mat4& view,
const glm::mat4& projection,
int viewportWidth,
int viewportHeight)
{
// 1. Convert screen coordinates to normalized device coordinates (NDC)
// Screen space: origin at top-left, Y points down
// NDC space: origin at center, range [-1, 1] for x and y
float x = (2.0f * screenX) / viewportWidth - 1.0f;
float y = 1.0f - (2.0f * screenY) / viewportHeight; // Flip Y
float z = 2.0f * screenZ - 1.0f; // [0,1] -> [-1,1]
glm::vec4 clipCoords(x, y, z, 1.0f);
// 2. Transform from clip space to view space
glm::mat4 invProjection = glm::inverse(projection);
glm::vec4 viewCoords = invProjection * clipCoords;
// 3. Transform from view space to world space
glm::mat4 invView = glm::inverse(view);
glm::vec4 worldCoords = invView * viewCoords;
// 4. Perspective divide
if (worldCoords.w != 0.0f) {
worldCoords /= worldCoords.w;
}
return glm::vec3(worldCoords);
};
void DrawViewport()
{
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2{ 0, 0 });
ImGui::Begin("Viewport");
bool focused = ImGui::IsWindowFocused();
bool hovered = ImGui::IsWindowHovered();
Application::Get().GetImGuiLayer()->SetBlockEvents(!focused || !hovered);
ImVec2 viewport_panel_size = ImGui::GetContentRegionAvail();
ImGui::End();
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2{ 0, 0 });
ImGui::Begin("Viewport");
ImVec2 viewport_panel_size = ImGui::GetContentRegionAvail();
if (viewport_size != *((glm::vec2*)&viewport_panel_size)) {
framebuffer->Resize(viewport_panel_size.x, viewport_panel_size.y);
viewport_size = { viewport_panel_size.x, viewport_panel_size.y };
view->GetCamera().OnResize(viewport_panel_size.x, viewport_panel_size.y);
}
uint32_t texture_id = framebuffer->GetColorAttachmentRendererID();
ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None;
if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
ImVec2 imgui_cursor_position = ImGui::GetCursorScreenPos();
auto pair_position = Input::GetMousePosition();
glm::vec2 mouse_position = { pair_position.first, pair_position.second };
int max_x = viewport_size.x + imgui_cursor_position.x;
int max_y = viewport_size.y + imgui_cursor_position.y;
if (focused || hovered) {
float x = mouse_position.x - imgui_cursor_position.x;
float y = mouse_position.y - imgui_cursor_position.y;
/*
auto& cam = camera.GetCamera();
world_pos_cursor = ScreenToWorld(x, y, 0.0f,
cam.GetViewMatrix(),
cam.GetProjectionMatrix(),
viewport_size.x,
viewport_size.y);
*/
}
uint32_t texture_id = framebuffer->GetColorAttachmentRendererID();
ImGui::Image((void*)(uint64_t)texture_id, ImVec2{ viewport_size.x, viewport_size.y }, ImVec2{ 0, 1 }, ImVec2{ 1, 0 });
ImGui::End();
ImGui::PopStyleVar();
};
void DrawStats()
{
if (ImGui::BeginTabItem("Avocado"))
{
ImVec2 imgui_cursor_position = ImGui::GetCursorScreenPos();
auto stats = Renderer2D::GetStats();
static float time = 0;
auto pair_position = OpenEngine::Input::GetMousePosition();
glm::vec2 mouse_position = { pair_position.first, pair_position.second };
time += Time::DeltaTime();
int max_x = viewport_size.x + imgui_cursor_position.x;
int max_y = viewport_size.y + imgui_cursor_position.y;
if ((mouse_position.x <= max_x && mouse_position.x >= imgui_cursor_position.x)
&& (mouse_position.y <= max_y && mouse_position.y >= imgui_cursor_position.y)) {
float x = mouse_position.x - imgui_cursor_position.x;
float y = mouse_position.y - imgui_cursor_position.y;
auto& camera = view->GetCamera().GetCamera();
auto world_coords = ScreenToWorld(x, y, 0.0f,
camera.GetViewMatrix(),
camera.GetProjectionMatrix(),
viewport_size.x,
viewport_size.y);
view->SetCursorPos({ world_coords.x, world_coords.y });
}
ImGui::Image((void*)texture_id, ImVec2{ viewport_size.x, viewport_size.y }, ImVec2{ 0, 1 }, ImVec2{ 1, 0 });
ImGui::EndTabItem();
if (time >= 1) {
time = 0;
}
if (ImGui::BeginTabItem("Broccoli"))
{
ImGui::Text("This is the Broccoli tab!\nblah blah blah blah blah");
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Cucumber"))
{
ImGui::Text("This is the Cucumber tab!\nblah blah blah blah blah");
ImGui::EndTabItem();
}
ImGui::EndTabBar();
}
ImGui::End();
ImGui::PopStyleVar();
auto stats = OpenEngine::Renderer2D::GetStats();
static float time = 0;
ImGui::Begin("Statistics");
ImGui::Text("FPS: %0.0f", 1 / Time::DeltaTime());
ImGui::Text("Renderer2D:");
ImGui::Text("\t\tDraw calls: %d", stats.draw_calls);
ImGui::Text("\t\tQuad count: %d", stats.quad_count);
ImGui::Text("\t\tVertices count: %d", stats.GetToralVertexCount());
ImGui::Text("\t\tIndices count: %d", stats.GetToralIndexCount());
time += OpenEngine::Time::DeltaTime();
/*
for (auto& result : profiling_results)
{
char label[50];
strcpy(label, "%.3fms ");
strcat(label, result.name);
ImGui::Text(label, result.duration);
}
if (time >= 1) {
time = 0;
}
profiling_results.clear();
*/
ImGui::Begin("Statistics");
ImGui::Text("FPS: %0.0f", 1 / OpenEngine::Time::DeltaTime());
ImGui::Text("Renderer2D:");
ImGui::Text("\t\tDraw calls: %d", stats.draw_calls);
ImGui::Text("\t\tQuad count: %d", stats.quad_count);
ImGui::Text("\t\tVertices count: %d", stats.GetToralVertexCount());
ImGui::Text("\t\tIndices count: %d", stats.GetToralIndexCount());
ImGui::ShowDemoWindow();
ImGui::End();
}
ImGui::End();
};
private:
std::vector<OpenEngine::Time::ProfilingResult> profiling_results;
void OnImGuiRender() override
{
OE_PROFILE_FUNCTION();
glm::vec2 viewport_size = { 0.0f, 0.0f };
ImGui::DockSpaceOverViewport();
OpenEngine::Ref<ViewLayer> view;
};
DrawStats();
scene_hierarchy.OnImGuiRender();
DrawViewport();
ImGui::ShowDemoWindow();
};
private:
std::vector<Time::ProfilingResult> profiling_results;
glm::vec2 world_pos_cursor = { 0.0f, 0.0f };
glm::vec2 viewport_size = { 0.0f, 0.0f };
Ref<OpenEngine::FrameBuffer> framebuffer;
SceneHierarchy scene_hierarchy;
//OrthographicCameraController camera;
Entity camera_bis;
Ref<Scene> scene;
Entity sq_entity;
};
}
class EditorApp : public OpenEngine::Application
{

View File

@@ -31,7 +31,7 @@ class LevelEditor : public ViewLayer
GetCamera().OnUpdate();
GetFramebuffer()->Bind();
}
OpenEngine::RenderCommand::SetClearColor({0.11f, 0.11f, 0.15f, 1.0f});
OpenEngine::RenderCommand::Clear();
@@ -47,7 +47,6 @@ class LevelEditor : public ViewLayer
}
auto& cursor = GetCursorPos();
OE_TRACE("world coordinates: {} {}", cursor.x, cursor.y);
OpenEngine::Transform tr5 = {glm::vec3(cursor.x, cursor.y, 0.9f), glm::vec3(0.1f, 0.1f, 0.0f), 0.0f};
OpenEngine::Renderer2D::DrawQuad(tr5, {1, 1, 1, 1});
@@ -58,14 +57,8 @@ class LevelEditor : public ViewLayer
void OnEvent(OpenEngine::Event& event) override
{
auto& cursor = GetCursorPos();
OE_TRACE("world coordinates: {} {}", cursor.x, cursor.y);
OpenEngine::Transform tr5 = {glm::vec3(cursor.x, cursor.y, 0.9f), glm::vec3(1.0f, 1.0f, 0.0f), 0.0f};
OpenEngine::Renderer2D::DrawQuad(tr5, {1, 1, 1, 1});
OpenEngine::Renderer2D::EndScene();
GetFramebuffer()->Unbind();
OE_PROFILE_FUNCTION();
GetCamera().OnEvent(event);
};
void OnDetach() override {};

View File

@@ -0,0 +1,40 @@
#ifndef SCENE_HIERARCHY_HPP
#define SCENE_HIERARCHY_HPP
#include "imgui.h"
#include <open_engine.hpp>
namespace OpenEngine {
class SceneHierarchy
{
public:
SceneHierarchy() = default;
SceneHierarchy(const Ref<Scene>& scene);
void SetContext(const Ref<Scene>& scene);
void OnImGuiRender();
private:
void DrawEntityNode(Entity& entity);
void DrawComponents(Entity& entity);
template <typename T>
void DrawComponentDrawer(Entity& entity, const char* header)
{
if (entity.HasComponent<T>())
if (ImGui::TreeNodeEx((void*)typeid(T).hash_code(), ImGuiTreeNodeFlags_DefaultOpen, "%s", header)) {
entity.GetComponents<T>().OnImGuiRender(entity);
ImGui::TreePop();
ImGui::Separator();
}
}
private:
Ref<Scene> scene;
Entity selected_context, renamed_entity;
double last_selected_time = 10.0;
};
}
#endif // SCENE_HIERARCHY_HPP