From 9de9609deeb3d1396d68e8db1edc7f6d3b1342a3 Mon Sep 17 00:00:00 2001 From: Erris Date: Fri, 27 Feb 2026 10:45:44 +0100 Subject: [PATCH] content browser and textures on entity sprites --- editor/include/editor.hpp | 50 +- editor/include/panels/content_browser.hpp | 23 + editor/src/editor.cpp | 9 +- editor/src/editor_component.cpp | 11 + editor/src/panels/content_browser.cpp | 88 +++ .../include/open_engine/application.hpp | 21 +- .../include/open_engine/entry_point.hpp | 5 +- .../open_engine/opengl/opengl_shader.hpp | 16 +- .../opengl/opengl_uniform_buffer.hpp | 24 + .../open_engine/renderer/renderer2d.hpp | 6 + .../open_engine/renderer/uniform_buffer.cpp | 21 + .../open_engine/renderer/uniform_buffer.hpp | 20 + .../include/open_engine/scene/components.hpp | 3 + .../include/open_engine/scene/entity.hpp | 5 +- .../include/open_engine/scene/scene.hpp | 4 + open_engine/src/open_engine/application.cpp | 5 +- .../src/open_engine/opengl/opengl_shader.cpp | 507 ++++++++++++------ .../opengl/opengl_uniform_buffer.cpp | 27 + .../open_engine/renderer/editor_camera.cpp | 3 +- .../src/open_engine/renderer/renderer2d.cpp | 111 +++- .../open_engine/renderer/uniform_buffer.cpp | 21 + open_engine/src/open_engine/scene/camera.cpp | 2 + open_engine/src/open_engine/scene/scene.cpp | 40 +- 23 files changed, 809 insertions(+), 213 deletions(-) create mode 100644 editor/include/panels/content_browser.hpp create mode 100644 editor/src/panels/content_browser.cpp create mode 100644 open_engine/include/open_engine/opengl/opengl_uniform_buffer.hpp create mode 100644 open_engine/include/open_engine/renderer/uniform_buffer.cpp create mode 100644 open_engine/include/open_engine/renderer/uniform_buffer.hpp create mode 100644 open_engine/src/open_engine/opengl/opengl_uniform_buffer.cpp create mode 100644 open_engine/src/open_engine/renderer/uniform_buffer.cpp diff --git a/editor/include/editor.hpp b/editor/include/editor.hpp index db4373b..cba7bee 100755 --- a/editor/include/editor.hpp +++ b/editor/include/editor.hpp @@ -1,8 +1,13 @@ #ifndef EDITOR_HPP #define EDITOR_HPP +#include #include +#include "open_engine/application.hpp" +#include "open_engine/scene/entity.hpp" +#include "open_engine/scene/scene_serializer.hpp" +#include "panels/content_browser.hpp" #include "panels/scene_hierarchy.hpp" #include @@ -71,6 +76,13 @@ namespace OpenEngine { scene = CreateRef(); + auto command_line_args = Application::Get().GetCommandLineArgs(); + if (command_line_args.count > 1) { + auto scene_path = command_line_args[1]; + SceneSerializer serializer(scene); + serializer.Deserialize(scene_path); + } + editor_camera = EditorCamera(30.0f, 1920.0f/1080.0f, 0.1f, 1000.0f); /* @@ -255,6 +267,15 @@ namespace OpenEngine { 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 }); + if (ImGui::BeginDragDropTarget()) { + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("CONTENT_BROWSER_PAYLOAD")) { + std::filesystem::path path = (const char*)payload->Data; + if (path.extension() == ".oes") + OpenScene(path); + } + ImGui::EndDragDropTarget(); + } + viewport_bounds[0] = { imgui_cursor_position.x, imgui_cursor_position.y }; viewport_bounds[1] = { imgui_cursor_position.x + viewport_size.x, imgui_cursor_position.y + viewport_size.y }; @@ -337,6 +358,18 @@ namespace OpenEngine { guizmo_operation = -1; }; + void OpenScene(const std::string& file) + { + if (!file.empty()) { + scene = CreateRef(); + scene->OnViewportResize((uint32_t)viewport_size.x, (uint32_t)viewport_size.y); + scene_hierarchy.Init(scene); + + SceneSerializer serializer(scene); + serializer.Deserialize(file); + } + } + void OnImGuiRender() override { OE_PROFILE_FUNCTION(); @@ -355,15 +388,8 @@ namespace OpenEngine { } if (ImGui::MenuItem("Open Scene", "Ctrl+O")) { std::string file = FileDialogs::OpenFile("useless"); - OE_DEBUG("loading filename: {}", file); - if (!file.empty()) { - scene = CreateRef(); - scene->OnViewportResize((uint32_t)viewport_size.x, (uint32_t)viewport_size.y); - scene_hierarchy.Init(scene); - - SceneSerializer serializer(scene); - serializer.Deserialize(file); - } + OE_DEBUG("loading scene: {}", file); + OpenScene(file); } if (ImGui::MenuItem("New Scene", "Ctrl+N")) { scene = CreateRef(); @@ -383,6 +409,7 @@ namespace OpenEngine { DrawStats(); scene_hierarchy.OnImGuiRender(); + brower.OnImGuiRender(); DrawViewport(); ImGui::ShowDemoWindow(); @@ -390,6 +417,7 @@ namespace OpenEngine { }; private: + ContentBrowserPanel brower; std::vector profiling_results; glm::vec2 world_pos_cursor = { 0.0f, 0.0f }; @@ -406,13 +434,15 @@ namespace OpenEngine { Ref scene; Entity selected_entity; + + std::vector entities; }; } class EditorApp : public OpenEngine::Application { public: - EditorApp(); + EditorApp(OpenEngine::ApplicationCommandLineArgs args); ~EditorApp(); }; diff --git a/editor/include/panels/content_browser.hpp b/editor/include/panels/content_browser.hpp new file mode 100644 index 0000000..b799ce3 --- /dev/null +++ b/editor/include/panels/content_browser.hpp @@ -0,0 +1,23 @@ +#ifndef CONTENT_BROWSER_HPP +#define CONTENT_BROWSER_HPP + +#include "open_engine/renderer/texture.hpp" +#include + +namespace OpenEngine { + + class ContentBrowserPanel + { + public: + ContentBrowserPanel(); + + void OnImGuiRender(); + + private: + std::filesystem::path current_directory; + Ref folder_icon; + }; + +} + +#endif // CONTENT_BROWSER_HPP diff --git a/editor/src/editor.cpp b/editor/src/editor.cpp index fdf30fc..ae2c441 100644 --- a/editor/src/editor.cpp +++ b/editor/src/editor.cpp @@ -1,3 +1,4 @@ +#include "open_engine/application.hpp" #include #include @@ -9,8 +10,8 @@ #include #include -EditorApp::EditorApp() - : Application("OpenEngine Editor") +EditorApp::EditorApp(OpenEngine::ApplicationCommandLineArgs args) + : Application("OpenEngine Editor", args) { OpenEngine::Ref modding_layer = OpenEngine::CreateRef(); OpenEngine::Ref editor_layer = OpenEngine::CreateRef(); @@ -25,8 +26,8 @@ EditorApp::~EditorApp() { } -OpenEngine::Application* OpenEngine::CreateApplication() +OpenEngine::Application* OpenEngine::CreateApplication(OpenEngine::ApplicationCommandLineArgs args) { OE_INFO("Editor Starting..."); - return new EditorApp(); + return new EditorApp(args); } diff --git a/editor/src/editor_component.cpp b/editor/src/editor_component.cpp index e7f16f7..ffb847b 100644 --- a/editor/src/editor_component.cpp +++ b/editor/src/editor_component.cpp @@ -1,3 +1,4 @@ +#include "imgui.h" #include #include @@ -106,6 +107,16 @@ namespace OpenEngine { { auto& sprite = registry.get(entity); ImGui::ColorEdit4("color", glm::value_ptr(sprite.color)); + ImGui::Button("Texture", { 100, 0 }); + + if (ImGui::BeginDragDropTarget()) { + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("CONTENT_BROWSER_PAYLOAD")) + sprite.texture = Texture2D::Create(((const char*)payload->Data)); + + ImGui::EndDragDropTarget(); + } + + ImGui::DragFloat("Tiling factor", &sprite.tiling_factor); }; void CameraOnImGuiRender(entt::registry& registry, entt::entity entity) diff --git a/editor/src/panels/content_browser.cpp b/editor/src/panels/content_browser.cpp new file mode 100644 index 0000000..43ed493 --- /dev/null +++ b/editor/src/panels/content_browser.cpp @@ -0,0 +1,88 @@ +#include "imgui_internal.h" +#include +#include +#include + +#include +#include +#include +#include + +namespace OpenEngine { + + const std::filesystem::path assets_directory = "assets"; + + ContentBrowserPanel::ContentBrowserPanel() + : current_directory(assets_directory) + { + // TODO: Add file texture. Get free icons and add license + folder_icon = Texture2D::Create("resources/textures/folder.png"); + } + + void ContentBrowserPanel::OnImGuiRender() + { + ImGui::Begin("Assets"); + + ImGui::Text("%s", current_directory.c_str()); + + if (current_directory != assets_directory) + if (ImGui::Button("..")) + current_directory = current_directory.parent_path(); + + auto directory_it = std::filesystem::directory_iterator(current_directory); + + ImVec2 button_size = { 100, 100 }; + auto panel_width = ImGui::GetContentRegionAvail().x; + uint32_t table_columns = (int)(panel_width / button_size.x) - 1; + + if (table_columns <= 0) + table_columns = 1; + + ImVec2 padding( 9, 9 ); + + ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, padding); + + if (ImGui::BeginTable("table1", table_columns, ImGuiTableFlags_SizingFixedSame)) + { + for (auto& entry : directory_it) { + auto file_name = entry.path().filename().string(); + + ImGui::PushID(file_name.c_str()); + + ImGui::TableNextColumn(); + + ImGui::PushStyleColor(ImGuiCol_Button, { 0.0f, 0.0f, 0.0f, 0.0f }); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, { 0.192f, 0.196f, 0.266f, 1.0f }); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, { 0.270f, 0.278f, 0.352f, 1.0f }); + + ImGui::BeginGroup(); + ImGui::ImageButton("##X", (ImTextureID)folder_icon->GetID(), button_size, { 0, 1 }, { 1, 0 }); + if (entry.is_regular_file() && ImGui::BeginDragDropSource()) { + const char* source = entry.path().c_str(); + ImGui::SetDragDropPayload("CONTENT_BROWSER_PAYLOAD", source, (strlen(source) + 1) * sizeof(char), ImGuiCond_Once); + + ImGui::EndDragDropSource(); + } + + float columnWidth = ImGui::GetColumnWidth(); + float textWidth = ImGui::CalcTextSize(file_name.c_str()).x; + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (columnWidth - textWidth) * 0.5f); + ImGui::TextWrapped("%s", file_name.c_str()); + + ImGui::EndGroup(); + + if (entry.is_directory()) { + if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) + current_directory = entry.path().c_str(); + } + + ImGui::PopStyleColor(3); + ImGui::PopID(); + } + ImGui::EndTable(); + } + ImGui::PopStyleVar(); + + ImGui::End(); + } +} diff --git a/open_engine/include/open_engine/application.hpp b/open_engine/include/open_engine/application.hpp index 666e8cb..fb3d9ff 100644 --- a/open_engine/include/open_engine/application.hpp +++ b/open_engine/include/open_engine/application.hpp @@ -10,10 +10,25 @@ int main(int argc, char **argv); namespace OpenEngine { + + struct ApplicationCommandLineArgs + { + int count = 0; + char** args = nullptr; + + const char* operator[](int index) + { + OE_CORE_ASSERT(index < count, "Index is higher than argument count."); + + return args[index]; + }; + }; + class Application { public: - Application(const std::string& name = "OpenEngine Project"); + Application(const std::string& name, + ApplicationCommandLineArgs& args); ~Application(); virtual void OnEvent(Event& event); @@ -25,6 +40,7 @@ namespace OpenEngine { ImGuiLayer* GetImGuiLayer() { return imgui_layer.get(); }; inline static Application& Get() { return *instance; }; + ApplicationCommandLineArgs GetCommandLineArgs() const { return arguments; }; inline Window& GetWindow() { return *window; }; @@ -36,6 +52,7 @@ namespace OpenEngine { bool OnWindowResize(WindowResizeEvent& event); private: + ApplicationCommandLineArgs arguments; const std::string name; std::unique_ptr window; @@ -49,7 +66,7 @@ namespace OpenEngine { }; // Is defined by client - Application* CreateApplication(); + Application* CreateApplication(ApplicationCommandLineArgs args); } #endif // APPLICATION_HPP diff --git a/open_engine/include/open_engine/entry_point.hpp b/open_engine/include/open_engine/entry_point.hpp index 5658be2..1cf26f6 100755 --- a/open_engine/include/open_engine/entry_point.hpp +++ b/open_engine/include/open_engine/entry_point.hpp @@ -1,17 +1,16 @@ #ifndef ENTRY_POINT_HPP #define ENTRY_POINT_HPP -#include "open_engine/core.hpp" #include "open_engine/application.hpp" #include "open_engine/logging.hpp" -extern OpenEngine::Application* OpenEngine::CreateApplication(); +extern OpenEngine::Application* OpenEngine::CreateApplication(OpenEngine::ApplicationCommandLineArgs args); int main(int argc, char** argv) { OE_PROFILE_BEGIN_SESSION("Startup", "open_engine-startup.json"); OpenEngine::Logger::Init(); - auto app = OpenEngine::CreateApplication(); + auto app = OpenEngine::CreateApplication({ argc, argv }); OE_PROFILE_END_SESSION(); OE_PROFILE_BEGIN_SESSION("Runtime", "open_engine-runtime.json"); diff --git a/open_engine/include/open_engine/opengl/opengl_shader.hpp b/open_engine/include/open_engine/opengl/opengl_shader.hpp index bd3c09a..cc488d4 100755 --- a/open_engine/include/open_engine/opengl/opengl_shader.hpp +++ b/open_engine/include/open_engine/opengl/opengl_shader.hpp @@ -14,7 +14,7 @@ namespace OpenEngine { public: OpenGLShader(const std::string& shader_path); OpenGLShader(const std::string& name, const std::string& vertex_src, const std::string& frament_src); - virtual ~OpenGLShader() = default; + virtual ~OpenGLShader(); virtual const std::string& GetName() const override { return name; }; @@ -44,11 +44,21 @@ namespace OpenEngine { private: std::string ReadFile(const std::string& shader_path); std::unordered_map PreProcess(const std::string& shader_source); - void Compile(const std::unordered_map sources); - void CheckCompileErrors(unsigned int shader, const std::string& type); + void CompileOrGetVulkanBinaries(const std::unordered_map& shader_sources); + void CompileOrGetOpenGLBinaries(); + void CreateProgram(); + void Reflect(GLenum stage, const std::vector& shader_data); + //void CheckCompileErrors(unsigned int shader, const std::string& type); + private: std::string name; + std::string file_path; + + std::unordered_map> vulkan_spirv; + std::unordered_map> opengl_spirv; + + std::unordered_map m_OpenGLSourceCode; u_int32_t id; }; diff --git a/open_engine/include/open_engine/opengl/opengl_uniform_buffer.hpp b/open_engine/include/open_engine/opengl/opengl_uniform_buffer.hpp new file mode 100644 index 0000000..7815079 --- /dev/null +++ b/open_engine/include/open_engine/opengl/opengl_uniform_buffer.hpp @@ -0,0 +1,24 @@ +#ifndef OPENGL_UNIFORM_BUFFER_HPP +#define OPENGL_UNIFORM_BUFFER_HPP + +#include "open_engine/renderer/uniform_buffer.hpp" +#include + +namespace OpenEngine { + + class OpenGLUniformBuffer : public UniformBuffer + { + public: + OpenGLUniformBuffer(uint32_t size, uint32_t binding); + virtual ~OpenGLUniformBuffer(); + + virtual void SetData(const void* data, uint32_t size, + uint32_t offset = 0) override; + + private: + uint32_t id = 0; + }; + +} + +#endif // OPENGL_UNIFORM_BUFFER_HPP diff --git a/open_engine/include/open_engine/renderer/renderer2d.hpp b/open_engine/include/open_engine/renderer/renderer2d.hpp index 6c2303a..6c89326 100644 --- a/open_engine/include/open_engine/renderer/renderer2d.hpp +++ b/open_engine/include/open_engine/renderer/renderer2d.hpp @@ -44,6 +44,9 @@ namespace OpenEngine { static void DrawQuad(const Transform& transform_data, const Ref& texture, int entity_id, float tiling_factor = 1.0f); + static void DrawQuad(const Transform& transform_data, + const Ref& texture, const glm::vec4& color, + int entity_id, float tiling_factor = 1.0f); static void DrawQuad(const Transform& transform_data, const Ref& subtexture, int entity_id, float tiling_factor = 1.0f); @@ -53,6 +56,9 @@ namespace OpenEngine { static void DrawQuad(const glm::mat4& transform, const Ref& texture, int entity_id, float tiling_factor = 1.0f); + static void DrawQuad(const glm::mat4& transform, + const Ref& texture, const glm::vec4& color, + int entity_id, float tiling_factor = 1.0f); static void DrawQuad(const glm::mat4& transform, const Ref& subtexture, int entity_id, float tiling_factor = 1.0f); diff --git a/open_engine/include/open_engine/renderer/uniform_buffer.cpp b/open_engine/include/open_engine/renderer/uniform_buffer.cpp new file mode 100644 index 0000000..16492fc --- /dev/null +++ b/open_engine/include/open_engine/renderer/uniform_buffer.cpp @@ -0,0 +1,21 @@ +#include + +#include +#include +#include + +namespace OpenEngine { + + Ref UniformBuffer::Create(uint32_t size, uint32_t binding) + { + switch (Renderer::GetAPI()) + { + case RendererAPI::API::None: OE_CORE_ASSERT(false, "RendererAPI::None is currently not supported!"); return nullptr; + case RendererAPI::API::OpenGL: return CreateRef(size, binding); + } + + OE_CORE_ASSERT(false, "Unknown RendererAPI!"); + return nullptr; + } + +} diff --git a/open_engine/include/open_engine/renderer/uniform_buffer.hpp b/open_engine/include/open_engine/renderer/uniform_buffer.hpp new file mode 100644 index 0000000..c6ccf6f --- /dev/null +++ b/open_engine/include/open_engine/renderer/uniform_buffer.hpp @@ -0,0 +1,20 @@ +#ifndef UNIFORM_BUFFER_HPP +#define UNIFORM_BUFFER_HPP + +#include +#include +namespace OpenEngine { + + class UniformBuffer + { + public: + virtual ~UniformBuffer() {} + virtual void SetData(const void* data, uint32_t size, + uint32_t offset = 0) = 0; + + static Ref Create(uint32_t size, uint32_t binding); + + }; +} + +#endif // UNIFORM_BUFFER_HPP diff --git a/open_engine/include/open_engine/scene/components.hpp b/open_engine/include/open_engine/scene/components.hpp index d0d7065..8bce589 100644 --- a/open_engine/include/open_engine/scene/components.hpp +++ b/open_engine/include/open_engine/scene/components.hpp @@ -3,6 +3,7 @@ #include "open_engine/scene/native_scriptable_entity.hpp" #include "open_engine/scene/scene_camera.hpp" +#include "open_engine/renderer/texture.hpp" #include #include @@ -45,6 +46,8 @@ namespace OpenEngine { struct SpriteRendererComponent { glm::vec4 color{ 1.0f, 1.0f, 1.0f, 1.0f }; + Ref texture; + float tiling_factor = 1.0f; SpriteRendererComponent() = default; SpriteRendererComponent(const SpriteRendererComponent&) = default; diff --git a/open_engine/include/open_engine/scene/entity.hpp b/open_engine/include/open_engine/scene/entity.hpp index d473028..55c8de9 100644 --- a/open_engine/include/open_engine/scene/entity.hpp +++ b/open_engine/include/open_engine/scene/entity.hpp @@ -22,7 +22,10 @@ namespace OpenEngine { T& AddComponents(Args&&... args) { OE_ASSERT(!HasComponent(), "Entity already has component."); - return scene->registry.emplace(handle, std::forward(args)...); + + T& component = scene->registry.emplace(handle, std::forward(args)...); + scene->OnComponentAdded(*this, component); + return component; }; template diff --git a/open_engine/include/open_engine/scene/scene.hpp b/open_engine/include/open_engine/scene/scene.hpp index 5d3bd0e..c10800f 100644 --- a/open_engine/include/open_engine/scene/scene.hpp +++ b/open_engine/include/open_engine/scene/scene.hpp @@ -27,6 +27,10 @@ namespace OpenEngine { Entity GetPrimaryCamera(); + private: + template + void OnComponentAdded(Entity entity, T& component); + private: entt::registry registry; diff --git a/open_engine/src/open_engine/application.cpp b/open_engine/src/open_engine/application.cpp index ec8d2da..64b3e05 100755 --- a/open_engine/src/open_engine/application.cpp +++ b/open_engine/src/open_engine/application.cpp @@ -13,8 +13,9 @@ #include namespace OpenEngine { - Application::Application(const std::string& name) - : name(name) + Application::Application(const std::string& name, + ApplicationCommandLineArgs& args) + : name(name), arguments(args) { OE_PROFILE_FUNCTION(); diff --git a/open_engine/src/open_engine/opengl/opengl_shader.cpp b/open_engine/src/open_engine/opengl/opengl_shader.cpp index 0b453b2..f4d741f 100644 --- a/open_engine/src/open_engine/opengl/opengl_shader.cpp +++ b/open_engine/src/open_engine/opengl/opengl_shader.cpp @@ -1,28 +1,117 @@ #include -#include - #include -#include +#include +#include +#include #include -#include +#include +#include +#include +#include +#include +#include #include -#include -#include -#include +//#include namespace OpenEngine { - static GLenum ShaderTypeFromString(const std::string& type) + + namespace Utils { + + static GLenum ShaderTypeFromString(const std::string& type) + { + if (type == "vertex") + return GL_VERTEX_SHADER; + if (type == "fragment" || type == "pixel") + return GL_FRAGMENT_SHADER; + + OE_CORE_ASSERT(false, "Unknown shader type!"); + return 0; + } + + static shaderc_shader_kind GLShaderStageToShaderC(GLenum stage) + { + switch (stage) + { + case GL_VERTEX_SHADER: return shaderc_glsl_vertex_shader; + case GL_FRAGMENT_SHADER: return shaderc_glsl_fragment_shader; + } + OE_CORE_ASSERT(false, "No"); + return (shaderc_shader_kind)0; + } + + static const char* GLShaderStageToString(GLenum stage) + { + switch (stage) + { + case GL_VERTEX_SHADER: return "GL_VERTEX_SHADER"; + case GL_FRAGMENT_SHADER: return "GL_FRAGMENT_SHADER"; + } + OE_CORE_ASSERT(false, "No"); + return nullptr; + } + + static const char* GetCacheDirectory() + { + // TODO: make sure the assets directory is valid + return "assets/cache/shader/opengl"; + } + + static void CreateCacheDirectoryIfNeeded() + { + std::string cache_directory = GetCacheDirectory(); + if (!std::filesystem::exists(cache_directory)) + std::filesystem::create_directories(cache_directory); + } + + static const char* GLShaderStageCachedOpenGLFileExtension(uint32_t stage) + { + switch (stage) + { + case GL_VERTEX_SHADER: return ".cached_opengl.vert"; + case GL_FRAGMENT_SHADER: return ".cached_opengl.frag"; + } + OE_CORE_ASSERT(false, "No"); + return ""; + } + + static const char* GLShaderStageCachedVulkanFileExtension(uint32_t stage) + { + switch (stage) + { + case GL_VERTEX_SHADER: return ".cached_vulkan.vert"; + case GL_FRAGMENT_SHADER: return ".cached_vulkan.frag"; + } + OE_CORE_ASSERT(false, "No"); + return ""; + } + + + } + + OpenGLShader::OpenGLShader(const std::string& filepath) + : file_path(filepath) { - if (type == "vertex") - return GL_VERTEX_SHADER; - if (type == "fragment" || type == "pixel") - return GL_FRAGMENT_SHADER; + OE_PROFILE_FUNCTION(); - OE_CORE_ERROR("Could not compile shader! Unkown shader type: {}", type); + Utils::CreateCacheDirectoryIfNeeded(); - return 0; + std::string source = ReadFile(filepath); + auto shader_sources = PreProcess(source); + + { + CompileOrGetVulkanBinaries(shader_sources); + CompileOrGetOpenGLBinaries(); + CreateProgram(); + } + + // Extract name from filepath + auto last_slash = filepath.find_last_of("/\\"); + last_slash = last_slash == std::string::npos ? 0 : last_slash + 1; + auto lastDot = filepath.rfind('.'); + auto count = lastDot == std::string::npos ? filepath.size() - last_slash : lastDot - last_slash; + name = filepath.substr(last_slash, count); } OpenGLShader::OpenGLShader(const std::string& name, const std::string& vertex_src, const std::string& fragment_src) @@ -34,163 +123,263 @@ namespace OpenEngine { sources[GL_VERTEX_SHADER] = vertex_src; sources[GL_FRAGMENT_SHADER] = fragment_src; - Compile(sources); + CompileOrGetVulkanBinaries(sources); + CompileOrGetOpenGLBinaries(); + CreateProgram(); } - OpenGLShader::OpenGLShader(const std::string& shader_path) + OpenGLShader::~OpenGLShader() { OE_PROFILE_FUNCTION(); - { - OE_PROFILE_SCOPE("Compiling Shader"); - std::string source = ReadFile(shader_path); - auto shader_sources = PreProcess(source); - Compile(shader_sources); - } - - // Getting file name - auto last_slash = shader_path.find_last_of("/\\"); - last_slash = last_slash == std::string::npos ? 0 : last_slash + 1; - auto last_dot = shader_path.rfind('.'); - - auto count = last_dot == std::string::npos ? shader_path.size() - last_slash : last_dot - last_slash; - name = shader_path.substr(last_slash, count); + glDeleteProgram(id); } - void OpenGLShader::Compile(const std::unordered_map sources) - { - OE_PROFILE_FUNCTION(); - - GLuint program = glCreateProgram(); - GLenum *gl_shader_ids = (GLenum*)alloca(sources.size()); - - size_t shader_index = 0; - for (auto& kv_pair : sources) - { - GLenum type = kv_pair.first; - const std::string& source = kv_pair.second; - - GLuint shader = glCreateShader(type); - - const GLchar* source_cstr = source.c_str(); - glShaderSource(shader, 1, &source_cstr, 0); - - glCompileShader(shader); - - GLint is_compiled = 0; - glGetShaderiv(shader, GL_COMPILE_STATUS, &is_compiled); - if (is_compiled == GL_FALSE) - { - GLint max_length = 0; - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &max_length); - - std::vector info_log(max_length); - glGetShaderInfoLog(shader, max_length, &max_length, &info_log[0]); - - glDeleteShader(shader); - - OE_CORE_ERROR("{0}", info_log.data()); - OE_CORE_ERROR("Shader compilation failure!"); - break; - } - - glAttachShader(program, shader); - gl_shader_ids[shader_index++] = shader; - } - - id = program; - - glLinkProgram(program); - - GLint is_linked = 0; - glGetProgramiv(program, GL_LINK_STATUS, (int*)&is_linked); - if (is_linked == GL_FALSE) - { - GLint max_length = 0; - glGetProgramiv(program, GL_INFO_LOG_LENGTH, &max_length); - - // The maxLength includes the NULL character - std::vector infoLog(max_length); - glGetProgramInfoLog(program, max_length, &max_length, &infoLog[0]); - - // We don't need the program anymore. - glDeleteProgram(program); - - for (int i = 0; i < sources.size(); i++) - glDeleteShader(gl_shader_ids[i]); - - OE_CORE_ERROR("{0}", infoLog.data()); - OE_CORE_ERROR("Shader link failure!"); - return; - } - - for (int i = 0; i < sources.size(); i++) { - glDetachShader(program, gl_shader_ids[i]); - glDeleteShader(gl_shader_ids[i]); - } - } - - std::unordered_map OpenGLShader::PreProcess(const std::string& shader_source) - { - OE_PROFILE_FUNCTION(); - - // TODO: Perhaps consider using getline to get the position of errors. or even regexes - std::unordered_map sources; - const char* type_token = "#type"; - - size_t type_token_lenght = strlen(type_token); - size_t pos = shader_source.find(type_token, 0); - while (pos != std::string::npos) { - size_t eol = shader_source.find("\n", pos); - if (eol == std::string::npos) - OE_CORE_ERROR("Syntax error."); - size_t begin = pos + type_token_lenght + 1; - std::string type = shader_source.substr(begin, eol - begin); - if (type != "vertex" && type != "fragment" && type != "pixel") - OE_CORE_ERROR("Invalid shader type."); - - size_t next_line_pos = shader_source.find_first_not_of("\n", eol); - pos = shader_source.find(type_token, next_line_pos); - sources[ShaderTypeFromString(type)] = - shader_source.substr(next_line_pos, pos - (next_line_pos == std::string::npos ? shader_source.size() - 1 : next_line_pos)); - } - - return sources; - } - - std::string OpenGLShader::ReadFile(const std::string& shader_path) + std::string OpenGLShader::ReadFile(const std::string& filepath) { OE_PROFILE_FUNCTION(); std::string result; - - std::ifstream input(shader_path); - if (input) { - input.seekg(0, std::ios::end); - - size_t size = input.tellg(); - if (size != -1) { + std::ifstream in(filepath, std::ios::in | std::ios::binary); // ifstream closes itself due to RAII + if (in) + { + in.seekg(0, std::ios::end); + size_t size = in.tellg(); + if (size != -1) + { result.resize(size); - input.seekg(0, std::ios::beg); - input.read(&result[0], result.size()); - input.close(); - } else { - OE_CORE_ERROR("Could not read from file {}", shader_path); + in.seekg(0, std::ios::beg); + in.read(&result[0], size); } - } else { - OE_CORE_ERROR("Shader file could not be open or does not exist: {}", shader_path); + else + { + OE_CORE_ERROR("Could not read from file '{0}'", filepath); + } + } + else + { + OE_CORE_ERROR("Could not open file '{0}'", filepath); } return result; } + std::unordered_map OpenGLShader::PreProcess(const std::string& source) + { + OE_PROFILE_FUNCTION(); + + std::unordered_map shader_sources; + + const char* type_token = "#type"; + size_t type_token_length = strlen(type_token); + size_t pos = source.find(type_token, 0); //Start of shader type declaration line + while (pos != std::string::npos) + { + size_t eol = source.find_first_of("\r\n", pos); //End of shader type declaration line + OE_CORE_ASSERT(eol != std::string::npos, "Syntax error"); + size_t begin = pos + type_token_length + 1; //Start of shader type name (after "#type " keyword) + std::string type = source.substr(begin, eol - begin); + OE_CORE_ASSERT(Utils::ShaderTypeFromString(type), "Invalid shader type specified"); + + size_t next_line_pos = source.find_first_not_of("\r\n", eol); //Start of shader code after shader type declaration line + OE_CORE_ASSERT(next_line_pos != std::string::npos, "Syntax error"); + pos = source.find(type_token, next_line_pos); //Start of next shader type declaration line + + shader_sources[Utils::ShaderTypeFromString(type)] = (pos == std::string::npos) ? source.substr(next_line_pos) : source.substr(next_line_pos, pos - next_line_pos); + } + + return shader_sources; + } + + void OpenGLShader::CompileOrGetVulkanBinaries(const std::unordered_map& shaderSources) + { + GLuint program = glCreateProgram(); + + shaderc::Compiler compiler; + shaderc::CompileOptions options; + options.SetTargetEnvironment(shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_2); + const bool optimize = true; + if (optimize) + options.SetOptimizationLevel(shaderc_optimization_level_performance); + + std::filesystem::path cache_directory = Utils::GetCacheDirectory(); + + auto& shader_data = vulkan_spirv; + shader_data.clear(); + for (auto&& [stage, source] : shaderSources) + { + std::filesystem::path shader_file_path = file_path; + std::filesystem::path cached_path = cache_directory / (shader_file_path.filename().string() + Utils::GLShaderStageCachedVulkanFileExtension(stage)); + + std::ifstream in(cached_path, std::ios::in | std::ios::binary); + if (in.is_open()) + { + in.seekg(0, std::ios::end); + auto size = in.tellg(); + in.seekg(0, std::ios::beg); + + auto& data = shader_data[stage]; + data.resize(size / sizeof(uint32_t)); + in.read((char*)data.data(), size); + } + else + { + shaderc::SpvCompilationResult module = compiler.CompileGlslToSpv(source, Utils::GLShaderStageToShaderC(stage), file_path.c_str(), options); + if (module.GetCompilationStatus() != shaderc_compilation_status_success) + { + OE_CORE_ERROR(module.GetErrorMessage()); + OE_CORE_ASSERT(false, "No"); + } + + shader_data[stage] = std::vector(module.cbegin(), module.cend()); + + std::ofstream out(cached_path, std::ios::out | std::ios::binary); + if (out.is_open()) + { + auto& data = shader_data[stage]; + out.write((char*)data.data(), data.size() * sizeof(uint32_t)); + out.flush(); + out.close(); + } + } + } + + for (auto&& [stage, data]: shader_data) + Reflect(stage, data); + } + + void OpenGLShader::CompileOrGetOpenGLBinaries() + { + auto& shader_data = opengl_spirv; + + shaderc::Compiler compiler; + shaderc::CompileOptions options; + options.SetTargetEnvironment(shaderc_target_env_opengl, shaderc_env_version_opengl_4_5); + const bool optimize = false; + if (optimize) + options.SetOptimizationLevel(shaderc_optimization_level_performance); + + std::filesystem::path cache_directory = Utils::GetCacheDirectory(); + + shader_data.clear(); + m_OpenGLSourceCode.clear(); + for (auto&& [stage, spirv] : vulkan_spirv) + { + std::filesystem::path shader_file_path = file_path; + std::filesystem::path cached_path = cache_directory / (shader_file_path.filename().string() + Utils::GLShaderStageCachedOpenGLFileExtension(stage)); + + std::ifstream in(cached_path, std::ios::in | std::ios::binary); + if (in.is_open()) + { + in.seekg(0, std::ios::end); + auto size = in.tellg(); + in.seekg(0, std::ios::beg); + + auto& data = shader_data[stage]; + data.resize(size / sizeof(uint32_t)); + in.read((char*)data.data(), size); + } + else + { + spirv_cross::CompilerGLSL glsl_compiler(spirv); + m_OpenGLSourceCode[stage] = glsl_compiler.compile(); + auto& source = m_OpenGLSourceCode[stage]; + + shaderc::SpvCompilationResult module = compiler.CompileGlslToSpv(source, Utils::GLShaderStageToShaderC(stage), file_path.c_str()); + if (module.GetCompilationStatus() != shaderc_compilation_status_success) + { + OE_CORE_ERROR(module.GetErrorMessage()); + OE_CORE_ASSERT(false, "No"); + } + + shader_data[stage] = std::vector(module.cbegin(), module.cend()); + + std::ofstream out(cached_path, std::ios::out | std::ios::binary); + if (out.is_open()) + { + auto& data = shader_data[stage]; + out.write((char*)data.data(), data.size() * sizeof(uint32_t)); + out.flush(); + out.close(); + } + } + } + } + + void OpenGLShader::CreateProgram() + { + GLuint program = glCreateProgram(); + + std::vector shader_ids; + for (auto&& [stage, spirv] : opengl_spirv) + { + GLuint shaderID = shader_ids.emplace_back(glCreateShader(stage)); + glShaderBinary(1, &shaderID, GL_SHADER_BINARY_FORMAT_SPIR_V, spirv.data(), spirv.size() * sizeof(uint32_t)); + glSpecializeShader(shaderID, "main", 0, nullptr, nullptr); + glAttachShader(program, shaderID); + } + + glLinkProgram(program); + + GLint is_linked; + glGetProgramiv(program, GL_LINK_STATUS, &is_linked); + if (is_linked == GL_FALSE) + { + GLint max_length; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &max_length); + + std::vector info_log(max_length); + glGetProgramInfoLog(program, max_length, &max_length, info_log.data()); + OE_CORE_ERROR("Shader linking failed ({0}):\n{1}", file_path, info_log.data()); + + glDeleteProgram(program); + + for (auto id : shader_ids) + glDeleteShader(id); + } + + for (auto id : shader_ids) + { + glDetachShader(program, id); + glDeleteShader(id); + } + + id = program; + } + + void OpenGLShader::Reflect(GLenum stage, const std::vector& shader_data) + { + spirv_cross::Compiler compiler(shader_data); + spirv_cross::ShaderResources resources = compiler.get_shader_resources(); + + OE_CORE_TRACE("OpenGLShader::Reflect - {0} {1}", Utils::GLShaderStageToString(stage), file_path); + OE_CORE_TRACE(" {0} uniform buffers", resources.uniform_buffers.size()); + OE_CORE_TRACE(" {0} resources", resources.sampled_images.size()); + + OE_CORE_TRACE("Uniform buffers:"); + for (const auto& resource : resources.uniform_buffers) + { + const auto& buffer_type = compiler.get_type(resource.base_type_id); + uint32_t buffer_size = compiler.get_declared_struct_size(buffer_type); + uint32_t binding = compiler.get_decoration(resource.id, spv::DecorationBinding); + int member_count = buffer_type.member_types.size(); + + OE_CORE_TRACE(" {0}", resource.name); + OE_CORE_TRACE(" Size = {0}", buffer_size); + OE_CORE_TRACE(" Binding = {0}", binding); + OE_CORE_TRACE(" Members = {0}", member_count); + } + } + void OpenGLShader::Bind() const { + OE_PROFILE_FUNCTION(); glUseProgram(id); } void OpenGLShader::Unbind() const { + OE_PROFILE_FUNCTION(); glUseProgram(0); } @@ -275,30 +464,4 @@ namespace OpenEngine { { glUniform4fv(glGetUniformLocation(id, name.c_str()), 1, glm::value_ptr(value)); } - - void OpenGLShader::CheckCompileErrors(unsigned int shader, const std::string& type) - { - int success = GL_FALSE; - char infoLog[1024]; - if (type != "PROGRAM") { - glGetShaderiv(shader, GL_COMPILE_STATUS, &success); - if (success == GL_FALSE) { - glGetShaderInfoLog(shader, 1024, NULL, infoLog); - OE_CORE_ERROR("Shader of type {}, couldn't be compiled:", type); - OE_CORE_ERROR("\t{}", infoLog); - } - } else { - if (glGetProgramiv == nullptr) { - OE_CORE_ERROR("OpenGL functions are not loaded!"); - return; - } - glGetProgramiv(shader, GL_LINK_STATUS, &success); - if (success == GL_FALSE) - { - glGetProgramInfoLog(shader, 1024, NULL, infoLog); - OE_CORE_ERROR("Program of type {}, couldn't be compiled:", type); - OE_CORE_ERROR("\t{}", infoLog); - } - } - } } diff --git a/open_engine/src/open_engine/opengl/opengl_uniform_buffer.cpp b/open_engine/src/open_engine/opengl/opengl_uniform_buffer.cpp new file mode 100644 index 0000000..bfea6f6 --- /dev/null +++ b/open_engine/src/open_engine/opengl/opengl_uniform_buffer.cpp @@ -0,0 +1,27 @@ +#include + +#include + +#include + +namespace OpenEngine { + + OpenGLUniformBuffer::OpenGLUniformBuffer(uint32_t size, uint32_t binding) + { + glCreateBuffers(1, &id); + glNamedBufferData(id, size, nullptr, GL_DYNAMIC_DRAW); + glBindBufferBase(GL_UNIFORM_BUFFER, binding, id); + } + + OpenGLUniformBuffer::~OpenGLUniformBuffer() + { + glDeleteBuffers(1, &id); + } + + + void OpenGLUniformBuffer::SetData(const void* data, uint32_t size, uint32_t offset) + { + glNamedBufferSubData(id, offset, size, data); + } + +} diff --git a/open_engine/src/open_engine/renderer/editor_camera.cpp b/open_engine/src/open_engine/renderer/editor_camera.cpp index 7c8dd53..9017b10 100644 --- a/open_engine/src/open_engine/renderer/editor_camera.cpp +++ b/open_engine/src/open_engine/renderer/editor_camera.cpp @@ -63,8 +63,7 @@ namespace OpenEngine { void EditorCamera::OnUpdate() { - if (Input::IsKeyPressed(Key::LeftAlt)) - { + if (Input::IsKeyPressed(Key::LeftAlt)) { const glm::vec2& mouse{ Input::GetMouseX(), Input::GetMouseY() }; glm::vec2 delta = (mouse - initial_mouse_position) * 0.003f; initial_mouse_position = mouse; diff --git a/open_engine/src/open_engine/renderer/renderer2d.cpp b/open_engine/src/open_engine/renderer/renderer2d.cpp index 76ef848..536882a 100755 --- a/open_engine/src/open_engine/renderer/renderer2d.cpp +++ b/open_engine/src/open_engine/renderer/renderer2d.cpp @@ -1,4 +1,5 @@ #include "renderer/editor_camera.hpp" +#include "renderer/uniform_buffer.hpp" #include #include @@ -27,7 +28,7 @@ namespace OpenEngine { struct Renderer2DData { - static const uint32_t max_quads = 10000; + static const uint32_t max_quads = 20000; static const uint32_t max_vertices = max_quads * 4; static const uint32_t max_indices = max_quads * 6; static const uint32_t max_texture_slots = 32; @@ -47,6 +48,13 @@ namespace OpenEngine { glm::vec4 quad_vertex_positioning[4]; Statistics stats; + + struct CameraData + { + glm::mat4 view_projection; + }; + CameraData camera_buffer; + Ref camera_uniform_buffer; }; static Renderer2DData renderer_data; @@ -100,8 +108,6 @@ namespace OpenEngine { samplers[i] = i; renderer_data.texture_shader = Shader::Create("assets/shaders/texture.glsl"); - renderer_data.texture_shader->Bind(); - renderer_data.texture_shader->SetIntArray("u_Texture", samplers, renderer_data.max_texture_slots); renderer_data.texture_slots[0] = renderer_data.white_texture; @@ -109,6 +115,8 @@ namespace OpenEngine { renderer_data.quad_vertex_positioning[1] = {0.5, -0.5, 0.0f, 1.0f}; renderer_data.quad_vertex_positioning[2] = {0.5, 0.5, 0.0f, 1.0f}; renderer_data.quad_vertex_positioning[3] = {-0.5, 0.5, 0.0f, 1.0f}; + + renderer_data.camera_uniform_buffer = UniformBuffer::Create(sizeof(Renderer2DData), 0); } void Renderer2D::Shutdown() @@ -130,8 +138,8 @@ namespace OpenEngine { { OE_PROFILE_FUNCTION(); - renderer_data.texture_shader->Bind(); - renderer_data.texture_shader->SetMat4("u_ViewProjection", camera.GetViewProjectionMatrix()); + renderer_data.camera_buffer.view_projection = camera.GetViewProjectionMatrix(); + renderer_data.camera_uniform_buffer->SetData(&renderer_data.camera_buffer, sizeof(Renderer2DData::CameraData)); StartBatch(); } @@ -140,10 +148,8 @@ namespace OpenEngine { { OE_PROFILE_FUNCTION(); - glm::mat4 view_projection = camera.GetProjection() * glm::inverse(transform); - - renderer_data.texture_shader->Bind(); - renderer_data.texture_shader->SetMat4("u_ViewProjection", view_projection); + renderer_data.camera_buffer.view_projection = camera.GetProjection() * glm::inverse(transform); + renderer_data.camera_uniform_buffer->SetData(&renderer_data.camera_buffer, sizeof(Renderer2DData::CameraData)); StartBatch(); } @@ -152,10 +158,8 @@ namespace OpenEngine { { OE_PROFILE_FUNCTION(); - glm::mat4 view_projection = camera.GetViewProjection(); - - renderer_data.texture_shader->Bind(); - renderer_data.texture_shader->SetMat4("u_ViewProjection", view_projection); + renderer_data.camera_buffer.view_projection = camera.GetViewProjection(); + renderer_data.camera_uniform_buffer->SetData(&renderer_data.camera_buffer, sizeof(Renderer2DData::CameraData)); StartBatch(); } @@ -180,6 +184,7 @@ namespace OpenEngine { for (int i = 0; i < renderer_data.texture_slot_index; i++) renderer_data.texture_slots[i]->Bind(i); + renderer_data.texture_shader->Bind(); RenderCommand::DrawIndexed(renderer_data.vertex_array, renderer_data.quad_index_count); renderer_data.stats.draw_calls++; @@ -225,6 +230,43 @@ namespace OpenEngine { DrawQuad(transform, texture, entity_id); } + void Renderer2D::DrawQuad(const Transform& transform_data, + const Ref& texture, const glm::vec4& color, + int entity_id, float tiling_factor) + { + OE_PROFILE_FUNCTION(); + + constexpr size_t quad_vertex_count = 4; + constexpr glm::vec2 texture_coords[] = { { 0.0f, 0.0f }, { 1.0f, 0.0f }, { 1.0f, 1.0f }, { 0.0f, 1.0f }}; + + if (renderer_data.quad_index_count >= Renderer2DData::max_indices) + FlushAndReset(); + + glm::vec3 position = transform_data.position; + glm::vec3 size = transform_data.size; + + float texture_index = 0; + for (uint32_t i = 1; i < renderer_data.texture_slot_index; i++) { + if (*renderer_data.texture_slots[i].get() == *texture.get()) { + texture_index = (float)i; + break; + } + } + + if (texture_index == 0) { + if (renderer_data.texture_slot_index >= Renderer2DData::max_texture_slots) + FlushAndReset(); + + texture_index = (float)renderer_data.texture_slot_index; + renderer_data.texture_slots[renderer_data.texture_slot_index] = texture; + renderer_data.texture_slot_index++; + } + + glm::mat4 transform = glm::translate(glm::mat4(1.0f), transform_data.position) + * glm::rotate(glm::mat4(1.0f), glm::radians(transform_data.rotation), { 0.0f, 0.0f, 1.0f }) + * glm::scale(glm::mat4(1.0f), transform_data.size); + } + void Renderer2D::DrawQuad(const Transform& transform_data, const Ref& subtexture, int entity_id, float tiling_factor) @@ -333,6 +375,49 @@ namespace OpenEngine { renderer_data.stats.quad_count++; } + void Renderer2D::DrawQuad(const glm::mat4& transform, + const Ref& texture, const glm::vec4& color, + int entity_id, float tiling_factor) + { + OE_PROFILE_FUNCTION(); + + constexpr size_t quad_vertex_count = 4; + constexpr glm::vec2 texture_coords[] = { { 0.0f, 0.0f }, { 1.0f, 0.0f }, { 1.0f, 1.0f }, { 0.0f, 1.0f }}; + + if (renderer_data.quad_index_count >= Renderer2DData::max_indices) + FlushAndReset(); + + float texture_index = 0; + for (uint32_t i = 1; i < renderer_data.texture_slot_index; i++) { + if (*renderer_data.texture_slots[i].get() == *texture.get()) { + texture_index = (float)i; + break; + } + } + + if (texture_index == 0) { + if (renderer_data.texture_slot_index >= Renderer2DData::max_texture_slots) + FlushAndReset(); + + texture_index = (float)renderer_data.texture_slot_index; + renderer_data.texture_slots[renderer_data.texture_slot_index] = texture; + renderer_data.texture_slot_index++; + } + + for (size_t i = 0; i < quad_vertex_count; i++) { + renderer_data.quad_vertex_ptr->position = transform * renderer_data.quad_vertex_positioning[i]; + renderer_data.quad_vertex_ptr->color = color; + renderer_data.quad_vertex_ptr->tex_coord = texture_coords[i]; + renderer_data.quad_vertex_ptr->tex_index = texture_index; + renderer_data.quad_vertex_ptr->tiling_factor = tiling_factor; + renderer_data.quad_vertex_ptr->id = entity_id; + renderer_data.quad_vertex_ptr++; + } + + renderer_data.quad_index_count += 6; + renderer_data.stats.quad_count++; + } + void Renderer2D::DrawQuad(const glm::mat4& transform, const Ref& subtexture, int entity_id, float tiling_factor) diff --git a/open_engine/src/open_engine/renderer/uniform_buffer.cpp b/open_engine/src/open_engine/renderer/uniform_buffer.cpp new file mode 100644 index 0000000..16492fc --- /dev/null +++ b/open_engine/src/open_engine/renderer/uniform_buffer.cpp @@ -0,0 +1,21 @@ +#include + +#include +#include +#include + +namespace OpenEngine { + + Ref UniformBuffer::Create(uint32_t size, uint32_t binding) + { + switch (Renderer::GetAPI()) + { + case RendererAPI::API::None: OE_CORE_ASSERT(false, "RendererAPI::None is currently not supported!"); return nullptr; + case RendererAPI::API::OpenGL: return CreateRef(size, binding); + } + + OE_CORE_ASSERT(false, "Unknown RendererAPI!"); + return nullptr; + } + +} diff --git a/open_engine/src/open_engine/scene/camera.cpp b/open_engine/src/open_engine/scene/camera.cpp index 7d19685..1f16e2f 100755 --- a/open_engine/src/open_engine/scene/camera.cpp +++ b/open_engine/src/open_engine/scene/camera.cpp @@ -1,3 +1,4 @@ +#include "core.hpp" #include #include @@ -32,6 +33,7 @@ namespace OpenEngine { void SceneCamera::SetViewportSize(uint32_t width, uint32_t height) { + OE_CORE_ASSERT(width > 0 && height > 0, "Viewport size invalid."); aspect_ratio = (float)width / (float)height; RecalculateProjection(); diff --git a/open_engine/src/open_engine/scene/scene.cpp b/open_engine/src/open_engine/scene/scene.cpp index 88d5703..467a16d 100644 --- a/open_engine/src/open_engine/scene/scene.cpp +++ b/open_engine/src/open_engine/scene/scene.cpp @@ -76,7 +76,12 @@ namespace OpenEngine { { auto [transform, sprite] = group.get(entity); - Renderer2D::DrawQuad(GetTransformFromComp(transform), sprite.color, (int)entity); + if (sprite.texture) + Renderer2D::DrawQuad(GetTransformFromComp(transform), + sprite.texture, sprite.color, (int)entity, sprite.tiling_factor); + else + Renderer2D::DrawQuad(GetTransformFromComp(transform), + sprite.color, (int)entity); } Renderer2D::EndScene(); @@ -107,4 +112,37 @@ namespace OpenEngine { return {}; } + + template + void Scene::OnComponentAdded(Entity entity, T& component) + { + static_assert(false); + } + + template<> + void Scene::OnComponentAdded(Entity entity, TransformComponent& component) + { + } + + template<> + void Scene::OnComponentAdded(Entity entity, CameraComponent& component) + { + if (viewport_width > 0 && viewport_height > 0) + component.camera.SetViewportSize(viewport_width, viewport_height); + } + + template<> + void Scene::OnComponentAdded(Entity entity, SpriteRendererComponent& component) + { + } + + template<> + void Scene::OnComponentAdded(Entity entity, TagComponent& component) + { + } + + template<> + void Scene::OnComponentAdded(Entity entity, NativeScriptComponent& component) + { + } }