From 9f7b647a9acfafdd56d310677c1d363137695693 Mon Sep 17 00:00:00 2001 From: swd3e2 Date: Mon, 7 Sep 2020 20:59:43 +0500 Subject: [PATCH] new ui --- Snake/src/Application.h | 23 ++- Snake/src/ApplicationSettings.h | 14 +- Snake/src/DebugCameraController.h | 16 +- Snake/src/DebugUiBuilder.h | 114 +++++++++++ Snake/src/Graphics/DebugHelper.h | 5 +- Snake/src/Graphics/FontRenderer.h | 165 ++++++++++++---- .../Platform/DirectX/DX11BlendState.h | 44 +++++ .../Platform/DirectX/DX11DepthState.h | 48 +++++ .../Platform/DirectX/DX11Renderer.cpp | 10 + .../Graphics/Platform/DirectX/DX11Renderer.h | 4 + .../Graphics/Platform/DirectX/DX11Texture2D.h | 10 +- .../Graphics/Platform/DirectX/DX11Utils.cpp | 182 ++++++++++++------ .../src/Graphics/Platform/DirectX/DX11Utils.h | 5 + .../Graphics/Platform/DirectX/DX11Window.h | 4 +- Snake/src/Graphics/Renderer.h | 2 + Snake/src/Graphics/Renderer/BlendState.cpp | 11 ++ Snake/src/Graphics/Renderer/BlendState.h | 37 ++++ Snake/src/Graphics/Renderer/CommonTypes.h | 39 ++++ Snake/src/Graphics/Renderer/DepthState.cpp | 11 ++ Snake/src/Graphics/Renderer/DepthState.h | 41 ++++ Snake/src/Input/InputManager.h | 21 +- Snake/src/Systems/RenderSystem.h | 15 +- Snake/src/Systems/SystemManager.h | 5 +- Snake/src/UI/UiConstraints.h | 74 +++++++ Snake/src/UI/UiDisplay.h | 8 + Snake/src/UI/UiElement.h | 71 +++++++ Snake/src/UI/UiIcon.h | 52 +++++ Snake/src/UI/UiIconMenu.h | 34 ++++ Snake/src/UI/UiRenderer.h | 88 +++++++++ Snake/src/UI/UiSystem.cpp | 2 + Snake/src/UI/UiSystem.h | 79 ++++++++ Snake/src/UI/Widgets/UiBlock.h | 39 ++++ 32 files changed, 1128 insertions(+), 145 deletions(-) create mode 100644 Snake/src/DebugUiBuilder.h create mode 100644 Snake/src/Graphics/Platform/DirectX/DX11BlendState.h create mode 100644 Snake/src/Graphics/Platform/DirectX/DX11DepthState.h create mode 100644 Snake/src/Graphics/Renderer/BlendState.cpp create mode 100644 Snake/src/Graphics/Renderer/BlendState.h create mode 100644 Snake/src/Graphics/Renderer/DepthState.cpp create mode 100644 Snake/src/Graphics/Renderer/DepthState.h create mode 100644 Snake/src/UI/UiConstraints.h create mode 100644 Snake/src/UI/UiDisplay.h create mode 100644 Snake/src/UI/UiElement.h create mode 100644 Snake/src/UI/UiIcon.h create mode 100644 Snake/src/UI/UiIconMenu.h create mode 100644 Snake/src/UI/UiRenderer.h create mode 100644 Snake/src/UI/UiSystem.cpp create mode 100644 Snake/src/UI/UiSystem.h create mode 100644 Snake/src/UI/Widgets/UiBlock.h diff --git a/Snake/src/Application.h b/Snake/src/Application.h index 5557309..14c4464 100644 --- a/Snake/src/Application.h +++ b/Snake/src/Application.h @@ -1,7 +1,6 @@ #pragma once #include - #include "Components.h" #include "Interface/ImGuiInterface.h" #include "Import/TextureLoader.h" @@ -14,18 +13,21 @@ #include "Systems/SystemManager.h" #include "Scene/SceneManager.h" #include "Graphics/Renderer/Texture2D.h" - +#include "UI/UiSystem.h" +#include "UI/Widgets/UiBlock.h" +#include "DebugUiBuilder.h" class Application { private: ApplicationSettings settings; SystemManager systemManager; SceneManager sceneManager; + InputManager inputManager; + std::unique_ptr ui_system; std::unique_ptr eventSystem; Renderer* renderer; - std::shared_ptr minterface; std::chrono::time_point m_Start; @@ -47,7 +49,12 @@ class Application { renderer = Renderer::create(RendererType::DirectX); window = renderer->createWindow(settings.getWindowWidth(), settings.getWindowHeight()); - systemManager.initialize(&settings, &sceneManager, renderer); + ui_system.reset(new UiSystem(renderer, &inputManager, &settings)); + + DebugUiBuilder ui_builder; + ui_builder.build(ui_system.get()); + + systemManager.initialize(&settings, &sceneManager, renderer, ui_system.get()); sceneManager.loadSceneFromFile("test.scene"); initSystems(); } @@ -60,12 +67,12 @@ class Application { eventSystem->flush(); systemManager.update(dt); - + ui_system->update(); //minterface->update(dt); - InputManager::instance()->mouseMoveX = 0.0; - InputManager::instance()->mouseMoveY = 0.0; - InputManager::instance()->mouseMoveCnt = 0; + inputManager.mouseMoveX = 0.0; + inputManager.mouseMoveY = 0.0; + inputManager.mouseMoveCnt = 0; window->pollEvents(); dt = std::chrono::duration(std::chrono::high_resolution_clock::now() - m_Start).count(); diff --git a/Snake/src/ApplicationSettings.h b/Snake/src/ApplicationSettings.h index fa74f03..2ef7fe8 100644 --- a/Snake/src/ApplicationSettings.h +++ b/Snake/src/ApplicationSettings.h @@ -3,12 +3,14 @@ #define WIN32_LEAN_AND_MEAN #include #undef WIN32_LEAN_AND_MEAN +#include +#include "Common/Helper.h" class ApplicationSettings { private: - int windowHeight = 1080; - int windowWidth = 1920; + int windowHeight = 1440; + int windowWidth = 2560; int shadowMapWidth = 1024; int shadowMapHeight = 1024; @@ -30,9 +32,9 @@ class ApplicationSettings assetsDir = temp; } - inline int getWindowWidth() { return windowWidth; } - inline int getWindowHeight() { return windowHeight; } + inline int getWindowWidth() const { return windowWidth; } + inline int getWindowHeight() const { return windowHeight; } - inline int getShadowMapWidth() { return shadowMapWidth; } - inline int getShadowMapHeight() { return shadowMapHeight; } + inline int getShadowMapWidth() const { return shadowMapWidth; } + inline int getShadowMapHeight() const { return shadowMapHeight; } }; \ No newline at end of file diff --git a/Snake/src/DebugCameraController.h b/Snake/src/DebugCameraController.h index 82fb87d..e8b1c53 100644 --- a/Snake/src/DebugCameraController.h +++ b/Snake/src/DebugCameraController.h @@ -31,15 +31,15 @@ class DebugCameraController { void updateRpgCamera(Camera* camera, double dt) { - if (InputManager::instance()->instance()->isKeyPressed(87)) { + if (InputManager::instance()->isKeyPressed(87)) { camera->Position -= glm::vec3(1.0f, 0.0, 0.0) * 4.0f * (float)dt / 1000.0f; - } else if (InputManager::instance()->instance()->isKeyPressed(83)) { + } else if (InputManager::instance()->isKeyPressed(83)) { camera->Position += glm::vec3(1.0f, 0.0, 0.0) * 4.0f * (float)dt / 1000.0f; } - if (InputManager::instance()->instance()->isKeyPressed(65)) { + if (InputManager::instance()->isKeyPressed(65)) { camera->Position += glm::vec3(0.0f, 0.0, 1.0) * 4.0f * (float)dt / 1000.0f; - } else if (InputManager::instance()->instance()->isKeyPressed(68)) { + } else if (InputManager::instance()->isKeyPressed(68)) { camera->Position -= glm::vec3(0.0f, 0.0, 1.0) * 4.0f * (float)dt / 1000.0f; } } @@ -55,15 +55,15 @@ class DebugCameraController { } - if (InputManager::instance()->instance()->isKeyPressed(87)) { + if (InputManager::instance()->isKeyPressed(87)) { camera->Position -= camera->Front * 4.0f * (float)dt / 1000.0f; - } else if (InputManager::instance()->instance()->isKeyPressed(83)) { + } else if (InputManager::instance()->isKeyPressed(83)) { camera->Position += camera->Front * 4.0f * (float)dt / 1000.0f; } - if (InputManager::instance()->instance()->isKeyPressed(65)) { + if (InputManager::instance()->isKeyPressed(65)) { camera->Position += camera->Right * 4.0f * (float)dt / 1000.0f; - } else if (InputManager::instance()->instance()->isKeyPressed(68)) { + } else if (InputManager::instance()->isKeyPressed(68)) { camera->Position -= camera->Right * 4.0f * (float)dt / 1000.0f; } } diff --git a/Snake/src/DebugUiBuilder.h b/Snake/src/DebugUiBuilder.h new file mode 100644 index 0000000..6c2b8db --- /dev/null +++ b/Snake/src/DebugUiBuilder.h @@ -0,0 +1,114 @@ +#pragma once + +#include "UI/UiSystem.h" +#include "UI/Widgets/UiBlock.h" +#include "Import/Texture/RawTexture.h" +#include "UI/UiIcon.h" +#include "UI/UiIconMenu.h" + +class DebugUiBuilder +{ +public: + void build(UiSystem* ui_system) + { + UiBlock* block = new UiBlock(); + { + block->color = glm::vec4(0.9019607, 0.9215686, 0.91764705, 1.0); + block->bg_color = glm::vec4(0.9019607, 0.9215686, 0.91764705, 1.0); + + UiConstraints constraints; + constraints.setWidth({ ValueType::Relative, 100 }); + constraints.setHeight({ ValueType::Absolute, 20 }); + constraints.setXPos({ XPosition::Center }); + constraints.setYPos({ YPosition::Bottom }); + + ui_system->add(ui_system->getRootElement(), block, constraints); + } + + UiBlock* entity_list = new UiBlock(); + entity_list->visible = false; + + { + entity_list->color = glm::vec4(0.9019607, 0.9215686, 0.91764705, 1.0); + entity_list->bg_color = glm::vec4(0.9019607, 0.9215686, 0.91764705, 1.0); + + UiConstraints constraints2; + constraints2.setWidth({ ValueType::Relative, 20 }); + constraints2.setHeight({ ValueType::Relative, 20 }); + constraints2.setXPos({ XPosition::Center }); + constraints2.setYPos({ YPosition::Center }); + + ui_system->add(ui_system->getRootElement(), entity_list, constraints2); + } + + buildUiList(ui_system); + } + + void buildUiList(UiSystem* ui_system) + { + UiIconMenu* block1 = new UiIconMenu(); + { + block1->bg_color = glm::vec4(0.9019607, 0.9215686, 0.91764705, 1.0); + + UiConstraints constraints2; + constraints2.setWidth({ ValueType::Relative, 2 }); + constraints2.setHeight({ ValueType::Relative, 60 }); + constraints2.setXPos({ XPosition::Left }); + constraints2.setYPos({ YPosition::Center }); + + ui_system->add(ui_system->getRootElement(), block1, constraints2); + } + + { + RawTexture raw_icon_texture("icon/pencil.png"); + raw_icon_texture.import(); + + Texture2D* icon_texture = Texture2D::create( + raw_icon_texture.getWidth(), + raw_icon_texture.getHeight(), 0, + raw_icon_texture.getData(), + TextureFormat::RGBA8, + TextureFlags::TF_ShaderResource | TextureFlags::TF_GenerateMips, + 2 + ); + icon_texture->generateMips(); + + UiIcon* icon = new UiIcon(icon_texture); + { + icon->color = glm::vec4(0.9019607, 0.9215686, 0.91764705, 1.0); + icon->bg_color = glm::vec4(0.9019607, 0.9215686, 0.91764705, 1.0); + + UiConstraints constraints; + constraints.setWidth({ ValueType::Absolute, 42 }); + constraints.setHeight({ ValueType::Absolute, 42 }); + constraints.setXPos({ XPosition::Center }); + constraints.setYPos({ YPosition::Top }); + + ui_system->add(block1, icon, constraints); + } + } + { + RawTexture raw_icon_texture1("icon/entity.png"); + raw_icon_texture1.import(); + + Texture2D* icon_texture1 = Texture2D::create( + raw_icon_texture1.getWidth(), + raw_icon_texture1.getHeight(), 0, + raw_icon_texture1.getData(), + TextureFormat::RGBA8, + TextureFlags::TF_ShaderResource | TextureFlags::TF_GenerateMips, + 2 + ); + icon_texture1->generateMips(); + + UiConstraints constraints1; + constraints1.setWidth({ ValueType::Absolute, 42 }); + constraints1.setHeight({ ValueType::Absolute, 42 }); + constraints1.setXPos({ XPosition::Center }); + constraints1.setYPos({ YPosition::Top }); + + UiIcon* icon1 = new UiIcon(icon_texture1); + ui_system->add(block1, icon1, constraints1); + } + } +}; \ No newline at end of file diff --git a/Snake/src/Graphics/DebugHelper.h b/Snake/src/Graphics/DebugHelper.h index 1ba8052..1705661 100644 --- a/Snake/src/Graphics/DebugHelper.h +++ b/Snake/src/Graphics/DebugHelper.h @@ -4,7 +4,6 @@ #include "Renderer/IndexBuffer.h" #include "Renderer/VertexBuffer.h" #include "Renderer/ShaderPipeline.h" -#include "Common/Helper.h" #include #include "Renderer.h" #include @@ -75,7 +74,7 @@ class DebugHelper { prevShader->bind(context); } - void renderFont(const std::string& text, float x, float y) + void renderFont(const std::string& text, float x, float y, float scale) { Renderer* renderer = Renderer::instance(); RenderContext* context = renderer->getContext(); @@ -86,6 +85,6 @@ class DebugHelper { x = x * 2.0f - 1.0f; y = y * 2.0f - 1.0f; - fontRenderer.renderFont(text, x, y, 0.0015f); + fontRenderer.renderFont(text, x, y, scale); } }; \ No newline at end of file diff --git a/Snake/src/Graphics/FontRenderer.h b/Snake/src/Graphics/FontRenderer.h index 1a40e09..63222e5 100644 --- a/Snake/src/Graphics/FontRenderer.h +++ b/Snake/src/Graphics/FontRenderer.h @@ -5,6 +5,7 @@ #include #include "Graphics/Renderer/Texture2D.h" #include "Graphics/Renderer/VertexBuffer.h" +#include "Graphics/Renderer/BlendState.h" #include #include #include "vertex.h" @@ -12,16 +13,15 @@ class FontRenderer { private: - VertexBuffer* vbuffer = nullptr; - - struct Character { - Texture2D* texture; // ID текстуры глифа - glm::ivec2 Size; // Размеры глифа - glm::ivec2 Bearing; // Смещение верхней левой точки глифа - int Advance; // Горизонтальное смещение до начала следующего глифа - }; + struct glyph_info { + float x0, y0, x1, y1; // coords of glyph in the texture atlas + int x_off, y_off; // left & top bearing when rendering + int advance; // x advance when rendering + } info[128]; - std::map Characters; + VertexBuffer* vbuffer = nullptr; + std::unique_ptr font_atlas; + BlendState* blend_state = nullptr; public: FontRenderer() { @@ -29,32 +29,67 @@ class FontRenderer { if (FT_Init_FreeType(&ft)) std::cout << "ERROR::FREETYPE: Could not init FreeType Library" << std::endl; FT_Face face; - if (FT_New_Face(ft, "font/PTS55F.ttf", 0, &face)) + if (FT_New_Face(ft, "font/Roboto-Medium.ttf", 0, &face)) std::cout << "ERROR::FREETYPE: Failed to load font" << std::endl; FT_Set_Pixel_Sizes(face, 0, 48); - if (FT_Load_Char(face, 'X', FT_LOAD_RENDER)) - std::cout << "ERROR::FREETYTPE: Failed to load Glyph" << std::endl; + Texture2D* texture; + + std::vector data; + + int max_dim = (1 + (face->size->metrics.height >> 6)) * ceilf(sqrtf(128)); + int tex_width = 1; + while (tex_width < max_dim) tex_width <<= 1; + int tex_height = tex_width; + + // render glyphs to atlas + char* pixels = (char*)calloc(tex_width * tex_height, 1); + int pen_x = 0, pen_y = 0; - for (unsigned char c = 0; c < 128; c++) - { - // Load character glyph - if (FT_Load_Char(face, c, FT_LOAD_RENDER)) { - std::cout << "ERROR::FREETYTPE: Failed to load Glyph" << std::endl; - continue; + for (int i = 0; i < 128; ++i) { + FT_Load_Char(face, i, FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT); + FT_Bitmap* bmp = &face->glyph->bitmap; + + if (pen_x + bmp->width >= tex_width) { + pen_x = 0; + pen_y += ((face->size->metrics.height >> 6) + 1); } - Texture2D* texture = Texture2D::create(face->glyph->bitmap.width, face->glyph->bitmap.rows, 0, face->glyph->bitmap.buffer, TextureFormat::R8, TextureFlags::TF_RenderTarget | TextureFlags::TF_ShaderResource, 1); - - // Now store character for later use - Character character = { - texture, - glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows), - glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top), - face->glyph->advance.x - }; - Characters[c] = character; + + for (int row = 0; row < bmp->rows; ++row) { + for (int col = 0; col < bmp->width; ++col) { + int x = pen_x + col; + int y = pen_y + row; + pixels[y * tex_width + x] = bmp->buffer[row * bmp->pitch + col]; + } + } + + // this is stuff you'd need when rendering individual glyphs out of the atlas + info[i].x0 = pen_x; + info[i].y0 = pen_y; + info[i].x1 = pen_x + bmp->width; + info[i].y1 = pen_y + bmp->rows; + + info[i].x0 = info[i].x0 / tex_width; + info[i].y0 = info[i].y0 / tex_width; + info[i].x1 = info[i].x1 / tex_width; + info[i].y1 = info[i].y1 / tex_width; + + info[i].x_off = face->glyph->bitmap_left; + info[i].y_off = face->glyph->bitmap_top; + info[i].advance = face->glyph->advance.x >> 6; + + pen_x += bmp->width + 1; } + font_atlas.reset(Texture2D::create( + tex_width, + tex_height, + 1, + pixels, + TextureFormat::R8, + TextureFlags::TF_ShaderResource + )); + FT_Done_Face(face); FT_Done_FreeType(ft); @@ -68,6 +103,20 @@ class FontRenderer { vertex(1.0f, -1.0f, 0.0f, 1.0f, 1.0f), }; vbuffer = VertexBuffer::create(6, sizeof(vertex), vertices, true); + + BlendStateDesc blendStateDesc; + blendStateDesc.count = 1; + + blendStateDesc.blend[0].blendEnabled = true; + blendStateDesc.blend[0].blendOp = BlendOperation::ADD; + blendStateDesc.blend[0].srcBlend = BlendFunction::SRC_APLHA; + blendStateDesc.blend[0].dstBlend = BlendFunction::INV_SRC_APLHA; + + blendStateDesc.blend[0].blendOpAlpha = BlendOperation::ADD; + blendStateDesc.blend[0].srcBlendAlpha = BlendFunction::ZERO; + blendStateDesc.blend[0].dstBlendAlpha = BlendFunction::ZERO; + + blend_state = BlendState::create(blendStateDesc); } void renderFont(const std::string& text, float x, float y, float scale) @@ -75,31 +124,65 @@ class FontRenderer { Renderer* renderer = Renderer::instance(); RenderContext* context = renderer->getContext(); + blend_state->bind(context); + font_atlas->bindToUnit(0, context); + + /*temp->bindToUnit(0, context); + renderer->draw(6);*/ + + float xpos = x; + float ypos = y; + + for (auto& ch : text) { + glyph_info& character = info[ch]; + + float w = (character.x1 - character.x0) * scale * 0.8f; + float h = (character.y1 - character.y0) * scale; + + vertex vertices[6] = { + { xpos, ypos + h, 0.0f, character.x0, character.y0 }, + { xpos, ypos, 0.0f, character.x0, character.y1 }, + { xpos + w, ypos, 0.0f, character.x1, character.y1 }, + + { xpos, ypos + h, 0.0f, character.x0, character.y0 }, + { xpos + w, ypos, 0.0f, character.x1, character.y1 }, + { xpos + w, ypos + h, 0.0f, character.x1, character.y0 } + }; + + vbuffer->update(vertices, 6, sizeof(vertex)); + vbuffer->bind(context); + renderer->draw(6); + + xpos += ((float)character.advance / 1024.0f) * scale * 0.7f; + } + + renderer->setDefaultBlendState(); + return; + for (auto& ch : text) { - Character& character = Characters[ch]; + glyph_info& character = info[ch]; - float xpos = x + character.Bearing.x * scale; - float ypos = y - (character.Size.y - character.Bearing.y) * scale; + float xpos = x + character.x_off; + float ypos = y - character.y_off; - float w = character.Size.x * scale; - float h = character.Size.y * scale; + float w = (character.x0 - character.x1) * scale; + float h = (character.y0 - character.y1) * scale; vertex vertices[6] = { - { xpos, ypos + h, 0.0f, 0.0f, 0.0f }, - { xpos, ypos, 0.0f, 0.0f, 1.0f }, - { xpos + w, ypos, 0.0f, 1.0f, 1.0f }, + { xpos, ypos + h, 0.0f, character.x0, character.y0 }, + { xpos, ypos, 0.0f, character.x0, character.y1 }, + { xpos + w, ypos, 0.0f, character.x1, character.y1 }, - { xpos, ypos + h, 0.0f, 0.0f, 0.0f }, - { xpos + w, ypos, 0.0f, 1.0f, 1.0f }, - { xpos + w, ypos + h, 0.0f, 1.0f, 0.0f } + { xpos, ypos + h, 0.0f, character.x0, character.y0 }, + { xpos + w, ypos, 0.0f, character.x1, character.y1 }, + { xpos + w, ypos + h, 0.0f, character.x1, character.y0 } }; vbuffer->update(vertices, 6, sizeof(vertex)); vbuffer->bind(context); - character.texture->bindToUnit(0, context); renderer->draw(6); - x += (character.Advance >> 6) * scale; + x += (character.advance >> 6) * scale; } } }; \ No newline at end of file diff --git a/Snake/src/Graphics/Platform/DirectX/DX11BlendState.h b/Snake/src/Graphics/Platform/DirectX/DX11BlendState.h new file mode 100644 index 0000000..9918675 --- /dev/null +++ b/Snake/src/Graphics/Platform/DirectX/DX11BlendState.h @@ -0,0 +1,44 @@ +#pragma once + +#include "Graphics/Renderer.h" +#include "Graphics/Renderer/BlendState.h" +#include "DX11Renderer.h" +#include "DX11Utils.h" + +class DX11BlendState : public BlendState +{ +private: + ID3D11BlendState* blendState = nullptr; +public: + DX11BlendState(const BlendStateDesc& desc) : BlendState(desc) + { + DX11Renderer* renderer = (DX11Renderer*)Renderer::instance(); + ID3D11Device* device = ((DX11RenderContext*)renderer->getContext())->getDevice(); + + D3D11_BLEND_DESC blendDesc = { 0 }; + blendDesc.AlphaToCoverageEnable = desc.alphaToCoverageEnable; + blendDesc.IndependentBlendEnable = desc.independentBlendEnable; + + for (int i = 0; i < desc.count; i++) { + blendDesc.RenderTarget[i].BlendEnable = desc.blend[i].blendEnabled; + blendDesc.RenderTarget[i].SrcBlend = DirectX::getBlend(desc.blend[i].srcBlend); + blendDesc.RenderTarget[i].DestBlend = DirectX::getBlend(desc.blend[i].dstBlend); + blendDesc.RenderTarget[i].BlendOp = DirectX::getBlendOperation(desc.blend[i].blendOp); + blendDesc.RenderTarget[i].SrcBlendAlpha = DirectX::getBlend(desc.blend[i].srcBlendAlpha); + blendDesc.RenderTarget[i].DestBlendAlpha = DirectX::getBlend(desc.blend[i].dstBlendAlpha); + blendDesc.RenderTarget[i].BlendOpAlpha = DirectX::getBlendOperation(desc.blend[i].blendOpAlpha); + blendDesc.RenderTarget[i].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + } + + if (device->CreateBlendState(&blendDesc, &blendState) != S_OK) { + + } + } + + virtual void bind(RenderContext* context) + { + ID3D11DeviceContext* deviceContext = ((DX11RenderContext*)context)->getDeviceContext(); + float temp[4] = { 1.0f, 1.0f ,1.0f ,1.0f }; + deviceContext->OMSetBlendState(blendState, temp, 0xFFFFFFFF); + } +}; \ No newline at end of file diff --git a/Snake/src/Graphics/Platform/DirectX/DX11DepthState.h b/Snake/src/Graphics/Platform/DirectX/DX11DepthState.h new file mode 100644 index 0000000..7ffb283 --- /dev/null +++ b/Snake/src/Graphics/Platform/DirectX/DX11DepthState.h @@ -0,0 +1,48 @@ +#pragma once + +#include "Graphics/Renderer/DepthState.h" +#include "DX11Utils.h" +#include "DX11Renderer.h" + +class DX11DepthState : public DepthState +{ +private: + ID3D11DepthStencilState* depthStencilState = nullptr; +public: + DX11DepthState(const DepthStateDesc& desc) : DepthState(desc) + { + DX11Renderer* renderer = (DX11Renderer*)Renderer::instance(); + ID3D11Device* device = ((DX11RenderContext*)renderer->getContext())->getDevice(); + + D3D11_DEPTH_STENCIL_DESC dssDesc = { 0 }; + dssDesc.DepthEnable = desc.depthEnable; + dssDesc.DepthWriteMask = DirectX::getDepthWriteMask(desc.depthWriteMask); + dssDesc.DepthFunc = DirectX::getComparisonFunction(desc.depthFunc); + + if (desc.stencilEnable) { + dssDesc.StencilEnable = desc.stencilEnable; + dssDesc.StencilReadMask = desc.stencilReadMask; + dssDesc.StencilWriteMask = desc.stencilWriteMask; + + dssDesc.FrontFace.StencilDepthFailOp = DirectX::getDepthStencilOperation(desc.front.depthFailOp); + dssDesc.FrontFace.StencilFailOp = DirectX::getDepthStencilOperation(desc.front.failOp); + dssDesc.FrontFace.StencilPassOp = DirectX::getDepthStencilOperation(desc.front.passOp); + dssDesc.FrontFace.StencilFunc = DirectX::getComparisonFunction(desc.front.stencilFunc); + + dssDesc.BackFace.StencilDepthFailOp = DirectX::getDepthStencilOperation(desc.back.depthFailOp); + dssDesc.BackFace.StencilFailOp = DirectX::getDepthStencilOperation(desc.back.failOp); + dssDesc.BackFace.StencilPassOp = DirectX::getDepthStencilOperation(desc.back.passOp); + dssDesc.BackFace.StencilFunc = DirectX::getComparisonFunction(desc.back.stencilFunc); + } + + if (device->CreateDepthStencilState(&dssDesc, &depthStencilState) != S_OK) { + + } + } + + void bind(RenderContext* context) + { + ID3D11DeviceContext* deviceContext = ((DX11RenderContext*)context)->getDeviceContext(); + deviceContext->OMSetDepthStencilState(depthStencilState, 0xFF); + } +}; \ No newline at end of file diff --git a/Snake/src/Graphics/Platform/DirectX/DX11Renderer.cpp b/Snake/src/Graphics/Platform/DirectX/DX11Renderer.cpp index 5009c67..1caa522 100644 --- a/Snake/src/Graphics/Platform/DirectX/DX11Renderer.cpp +++ b/Snake/src/Graphics/Platform/DirectX/DX11Renderer.cpp @@ -139,6 +139,16 @@ void DX11Renderer::setViewport(const Viewport& viewport) setViewport(viewport.x0, viewport.y0, viewport.x1, viewport.y1); } +void DX11Renderer::setDefaultDepthStencil() +{ + deviceContext->OMSetDepthStencilState(nullptr, 0xFF); +} + +void DX11Renderer::setDefaultBlendState() +{ + deviceContext->OMSetBlendState(nullptr, nullptr, 0xFFFFFFFF); +} + void DX11Renderer::unbindResource(int slot) { deviceContext->PSSetShaderResources(slot, 1, nullShaderResourceView); diff --git a/Snake/src/Graphics/Platform/DirectX/DX11Renderer.h b/Snake/src/Graphics/Platform/DirectX/DX11Renderer.h index 18be3f7..dd4f997 100644 --- a/Snake/src/Graphics/Platform/DirectX/DX11Renderer.h +++ b/Snake/src/Graphics/Platform/DirectX/DX11Renderer.h @@ -41,5 +41,9 @@ class DX11Renderer : public Renderer virtual void setViewport(const Viewport& viewport) override; + virtual void setDefaultDepthStencil() override; + + virtual void setDefaultBlendState() override; + virtual void unbindResource(int slot) override; }; \ No newline at end of file diff --git a/Snake/src/Graphics/Platform/DirectX/DX11Texture2D.h b/Snake/src/Graphics/Platform/DirectX/DX11Texture2D.h index bf0e9ba..a6dd94f 100644 --- a/Snake/src/Graphics/Platform/DirectX/DX11Texture2D.h +++ b/Snake/src/Graphics/Platform/DirectX/DX11Texture2D.h @@ -27,6 +27,7 @@ class DX11Texture2D : public Texture2D { textureDesc.Format = DirectX::getTextureFormat(textureFormat); textureDesc.Usage = D3D11_USAGE_DEFAULT; textureDesc.BindFlags = 0; + textureDesc.MiscFlags = 0; if (flags & TextureFlags::TF_RenderTarget) { textureDesc.BindFlags |= D3D11_BIND_RENDER_TARGET; @@ -38,7 +39,8 @@ class DX11Texture2D : public Texture2D { textureDesc.BindFlags |= D3D11_BIND_DEPTH_STENCIL; } if (flags & TextureFlags::TF_GenerateMips) { - textureDesc.BindFlags |= D3D11_RESOURCE_MISC_GENERATE_MIPS; + textureDesc.MiscFlags |= D3D11_RESOURCE_MISC_GENERATE_MIPS; + textureDesc.BindFlags |= D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; } textureDesc.CPUAccessFlags = 0; @@ -115,14 +117,18 @@ class DX11Texture2D : public Texture2D { } virtual void generateMips() override { + DX11Renderer* renderer = (DX11Renderer*)Renderer::instance(); + DX11RenderContext* context = (DX11RenderContext*)renderer->getContext(); + ID3D11DeviceContext* deviceContext = ((DX11RenderContext*)context)->getDeviceContext(); + deviceContext->GenerateMips(m_TextureShaderResource); } virtual void bindToUnit(const int location, RenderContext* renderContext) override { DX11RenderContext* context = (DX11RenderContext*)renderContext; ID3D11DeviceContext* deviceContext = ((DX11RenderContext*)renderContext)->getDeviceContext(); - deviceContext->PSSetShaderResources(location, 1, &m_TextureShaderResource); + deviceContext->PSSetShaderResources(location, 1, &m_TextureShaderResource); context->boundTextures[location] = this; } }; \ No newline at end of file diff --git a/Snake/src/Graphics/Platform/DirectX/DX11Utils.cpp b/Snake/src/Graphics/Platform/DirectX/DX11Utils.cpp index 710fbda..02232e7 100644 --- a/Snake/src/Graphics/Platform/DirectX/DX11Utils.cpp +++ b/Snake/src/Graphics/Platform/DirectX/DX11Utils.cpp @@ -1,7 +1,8 @@ #include "DX11Utils.h" namespace DirectX { - const std::string getShaderTarget(const ShaderType type) { + const std::string getShaderTarget(const ShaderType type) + { switch (type) { case ShaderType::VERTEX: return "vs_5_0"; case ShaderType::PIXEL: return "ps_5_0"; @@ -13,7 +14,8 @@ namespace DirectX { return "vs_5_0"; } - std::string getInputLayoutShaderFormat(InputDataType type) { + std::string getInputLayoutShaderFormat(InputDataType type) + { switch (type) { case InputDataType::Float: return "float"; case InputDataType::Float2: return "float2"; @@ -28,7 +30,8 @@ namespace DirectX { return ""; } - DXGI_FORMAT getInputLayoutFormat(InputDataType type) { + DXGI_FORMAT getInputLayoutFormat(InputDataType type) + { switch (type) { case InputDataType::Float: return DXGI_FORMAT_R32_FLOAT; case InputDataType::Float2: return DXGI_FORMAT_R32G32_FLOAT; @@ -42,7 +45,8 @@ namespace DirectX { } } - DXGI_FORMAT getTextureFormat(TextureFormat textureFormat) { + DXGI_FORMAT getTextureFormat(TextureFormat textureFormat) + { switch (textureFormat) { case TextureFormat::R8: return DXGI_FORMAT_R8_UNORM; case TextureFormat::RG8: return DXGI_FORMAT_R8G8_UNORM; @@ -65,7 +69,8 @@ namespace DirectX { } } - const unsigned int getPitch(TextureFormat textureFormat, int width) { + const unsigned int getPitch(TextureFormat textureFormat, int width) + { switch (textureFormat) { case TextureFormat::R8: case TextureFormat::R16: @@ -90,7 +95,8 @@ namespace DirectX { } } - D3D11_TEXTURE_ADDRESS_MODE getAddressingMode(const AddressingMode& mode) { + D3D11_TEXTURE_ADDRESS_MODE getAddressingMode(const AddressingMode& mode) + { switch (mode) { case AddressingMode::WRAP: return D3D11_TEXTURE_ADDRESS_MODE::D3D11_TEXTURE_ADDRESS_WRAP; case AddressingMode::CLAMP: return D3D11_TEXTURE_ADDRESS_MODE::D3D11_TEXTURE_ADDRESS_CLAMP; @@ -100,66 +106,55 @@ namespace DirectX { return D3D11_TEXTURE_ADDRESS_MODE::D3D11_TEXTURE_ADDRESS_WRAP; } - D3D11_COMPARISON_FUNC getComparisonFunction(const ComparisonFunction& func) { - switch (func) { - case ComparisonFunction::NEVER: return D3D11_COMPARISON_FUNC::D3D11_COMPARISON_NEVER; - case ComparisonFunction::LESS: return D3D11_COMPARISON_FUNC::D3D11_COMPARISON_LESS; - case ComparisonFunction::EQUAL: return D3D11_COMPARISON_FUNC::D3D11_COMPARISON_EQUAL; - case ComparisonFunction::LEQUAL: return D3D11_COMPARISON_FUNC::D3D11_COMPARISON_LESS_EQUAL; - case ComparisonFunction::GREATER: return D3D11_COMPARISON_FUNC::D3D11_COMPARISON_GREATER; - case ComparisonFunction::NOT_EQUAL: return D3D11_COMPARISON_FUNC::D3D11_COMPARISON_NOT_EQUAL; - case ComparisonFunction::ALWAYS: return D3D11_COMPARISON_FUNC::D3D11_COMPARISON_ALWAYS; - } - return D3D11_COMPARISON_FUNC::D3D11_COMPARISON_NEVER; - } - D3D11_FILTER getFilteringMode(const FilterMode& _min, const FilterMode& mag, const FilterMode& mip, const bool comparison) { #define MERGE_FILTERS(_comparison, _min, _mag, _mip) ((_comparison << 16) | ((int)_min << 8) | ((int)_mag << 4) | ((int)_mip)) + switch ((MERGE_FILTERS((int)comparison, (int)_min, (int)mag, (int)mip))) { - case MERGE_FILTERS(true, (int)(int)FilterMode::POINT, (int)(int)FilterMode::POINT, (int)(int)FilterMode::POINT): - return D3D11_FILTER_COMPARISON_MIN_MAG_MIP_POINT; - case MERGE_FILTERS(true, (int)FilterMode::POINT, (int)FilterMode::POINT, (int)FilterMode::LINEAR): - return D3D11_FILTER_COMPARISON_MIN_MAG_POINT_MIP_LINEAR; - case MERGE_FILTERS(true, (int)FilterMode::POINT, (int)FilterMode::LINEAR, (int)FilterMode::POINT): - return D3D11_FILTER_COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT; - case MERGE_FILTERS(true, (int)FilterMode::POINT, (int)FilterMode::LINEAR, (int)FilterMode::LINEAR): - return D3D11_FILTER_COMPARISON_MIN_POINT_MAG_MIP_LINEAR; - case MERGE_FILTERS(true, (int)FilterMode::LINEAR, (int)FilterMode::POINT, (int)FilterMode::POINT): - return D3D11_FILTER_COMPARISON_MIN_LINEAR_MAG_MIP_POINT; - case MERGE_FILTERS(true, (int)FilterMode::LINEAR, (int)FilterMode::POINT, (int)FilterMode::LINEAR): - return D3D11_FILTER_COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR; - case MERGE_FILTERS(true, (int)FilterMode::LINEAR, (int)FilterMode::LINEAR, (int)FilterMode::POINT): - return D3D11_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT; - case MERGE_FILTERS(true, (int)FilterMode::LINEAR, (int)FilterMode::LINEAR, (int)FilterMode::LINEAR): - return D3D11_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR; - case MERGE_FILTERS(true, (int)FilterMode::ANISOTROPIC, (int)FilterMode::ANISOTROPIC, (int)FilterMode::ANISOTROPIC): - return D3D11_FILTER_COMPARISON_ANISOTROPIC; - case MERGE_FILTERS(false, (int)FilterMode::POINT, (int)FilterMode::POINT, (int)FilterMode::POINT): - return D3D11_FILTER_MIN_MAG_MIP_POINT; - case MERGE_FILTERS(false, (int)FilterMode::POINT, (int)FilterMode::POINT, (int)FilterMode::LINEAR): - return D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR; - case MERGE_FILTERS(false, (int)FilterMode::POINT, (int)FilterMode::LINEAR, (int)FilterMode::POINT): - return D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT; - case MERGE_FILTERS(false, (int)FilterMode::POINT, (int)FilterMode::LINEAR, (int)FilterMode::LINEAR): - return D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR; - case MERGE_FILTERS(false, (int)FilterMode::LINEAR, (int)FilterMode::POINT, (int)FilterMode::POINT): - return D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT; - case MERGE_FILTERS(false, (int)FilterMode::LINEAR, (int)FilterMode::POINT, (int)FilterMode::LINEAR): - return D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR; - case MERGE_FILTERS(false, (int)FilterMode::LINEAR, (int)FilterMode::LINEAR, (int)FilterMode::POINT): - return D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT; - case MERGE_FILTERS(false, (int)FilterMode::LINEAR, (int)FilterMode::LINEAR, (int)FilterMode::LINEAR): - return D3D11_FILTER_MIN_MAG_MIP_LINEAR; - case MERGE_FILTERS(false, (int)FilterMode::ANISOTROPIC, (int)FilterMode::ANISOTROPIC, (int)FilterMode::ANISOTROPIC): - return D3D11_FILTER_ANISOTROPIC; - default: - return D3D11_FILTER_MIN_MAG_MIP_LINEAR; + case MERGE_FILTERS(true, (int)(int)FilterMode::POINT, (int)(int)FilterMode::POINT, (int)(int)FilterMode::POINT): + return D3D11_FILTER_COMPARISON_MIN_MAG_MIP_POINT; + case MERGE_FILTERS(true, (int)FilterMode::POINT, (int)FilterMode::POINT, (int)FilterMode::LINEAR): + return D3D11_FILTER_COMPARISON_MIN_MAG_POINT_MIP_LINEAR; + case MERGE_FILTERS(true, (int)FilterMode::POINT, (int)FilterMode::LINEAR, (int)FilterMode::POINT): + return D3D11_FILTER_COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT; + case MERGE_FILTERS(true, (int)FilterMode::POINT, (int)FilterMode::LINEAR, (int)FilterMode::LINEAR): + return D3D11_FILTER_COMPARISON_MIN_POINT_MAG_MIP_LINEAR; + case MERGE_FILTERS(true, (int)FilterMode::LINEAR, (int)FilterMode::POINT, (int)FilterMode::POINT): + return D3D11_FILTER_COMPARISON_MIN_LINEAR_MAG_MIP_POINT; + case MERGE_FILTERS(true, (int)FilterMode::LINEAR, (int)FilterMode::POINT, (int)FilterMode::LINEAR): + return D3D11_FILTER_COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR; + case MERGE_FILTERS(true, (int)FilterMode::LINEAR, (int)FilterMode::LINEAR, (int)FilterMode::POINT): + return D3D11_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT; + case MERGE_FILTERS(true, (int)FilterMode::LINEAR, (int)FilterMode::LINEAR, (int)FilterMode::LINEAR): + return D3D11_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR; + case MERGE_FILTERS(true, (int)FilterMode::ANISOTROPIC, (int)FilterMode::ANISOTROPIC, (int)FilterMode::ANISOTROPIC): + return D3D11_FILTER_COMPARISON_ANISOTROPIC; + case MERGE_FILTERS(false, (int)FilterMode::POINT, (int)FilterMode::POINT, (int)FilterMode::POINT): + return D3D11_FILTER_MIN_MAG_MIP_POINT; + case MERGE_FILTERS(false, (int)FilterMode::POINT, (int)FilterMode::POINT, (int)FilterMode::LINEAR): + return D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR; + case MERGE_FILTERS(false, (int)FilterMode::POINT, (int)FilterMode::LINEAR, (int)FilterMode::POINT): + return D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT; + case MERGE_FILTERS(false, (int)FilterMode::POINT, (int)FilterMode::LINEAR, (int)FilterMode::LINEAR): + return D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR; + case MERGE_FILTERS(false, (int)FilterMode::LINEAR, (int)FilterMode::POINT, (int)FilterMode::POINT): + return D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT; + case MERGE_FILTERS(false, (int)FilterMode::LINEAR, (int)FilterMode::POINT, (int)FilterMode::LINEAR): + return D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR; + case MERGE_FILTERS(false, (int)FilterMode::LINEAR, (int)FilterMode::LINEAR, (int)FilterMode::POINT): + return D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT; + case MERGE_FILTERS(false, (int)FilterMode::LINEAR, (int)FilterMode::LINEAR, (int)FilterMode::LINEAR): + return D3D11_FILTER_MIN_MAG_MIP_LINEAR; + case MERGE_FILTERS(false, (int)FilterMode::ANISOTROPIC, (int)FilterMode::ANISOTROPIC, (int)FilterMode::ANISOTROPIC): + return D3D11_FILTER_ANISOTROPIC; + default: + return D3D11_FILTER_MIN_MAG_MIP_LINEAR; } #undef MERGE_FILTERS } - DXGI_FORMAT getDepthResourceFormat(TextureFormat textureFormat) { + DXGI_FORMAT getDepthResourceFormat(TextureFormat textureFormat) + { switch (textureFormat) { case TextureFormat::D16: return DXGI_FORMAT::DXGI_FORMAT_D16_UNORM; case TextureFormat::D24S8: return DXGI_FORMAT::DXGI_FORMAT_D24_UNORM_S8_UINT; @@ -169,7 +164,8 @@ namespace DirectX { return DXGI_FORMAT::DXGI_FORMAT_R24G8_TYPELESS; } - D3D_PRIMITIVE_TOPOLOGY getTopology(PrimitiveTopology topology) { + D3D_PRIMITIVE_TOPOLOGY getTopology(PrimitiveTopology topology) + { switch (topology) { case PrimitiveTopology::POINT: return D3D_PRIMITIVE_TOPOLOGY_POINTLIST; case PrimitiveTopology::LINELIST: return D3D_PRIMITIVE_TOPOLOGY_LINESTRIP; @@ -179,4 +175,72 @@ namespace DirectX { } return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; } + + D3D11_COMPARISON_FUNC getComparisonFunction(const ComparisonFunction& func) + { + switch (func) { + case ComparisonFunction::NEVER: return D3D11_COMPARISON_FUNC::D3D11_COMPARISON_NEVER; + case ComparisonFunction::LESS: return D3D11_COMPARISON_FUNC::D3D11_COMPARISON_LESS; + case ComparisonFunction::EQUAL: return D3D11_COMPARISON_FUNC::D3D11_COMPARISON_EQUAL; + case ComparisonFunction::LEQUAL: return D3D11_COMPARISON_FUNC::D3D11_COMPARISON_LESS_EQUAL; + case ComparisonFunction::GREATER: return D3D11_COMPARISON_FUNC::D3D11_COMPARISON_GREATER; + case ComparisonFunction::NOT_EQUAL: return D3D11_COMPARISON_FUNC::D3D11_COMPARISON_NOT_EQUAL; + case ComparisonFunction::ALWAYS: return D3D11_COMPARISON_FUNC::D3D11_COMPARISON_ALWAYS; + default: return D3D11_COMPARISON_FUNC::D3D11_COMPARISON_NEVER; + } + } + + D3D11_STENCIL_OP getDepthStencilOperation(const StencilOperation& stecnilOp) + { + switch (stecnilOp) { + case StencilOperation::KEEP: return D3D11_STENCIL_OP::D3D11_STENCIL_OP_KEEP; + case StencilOperation::ZERO: return D3D11_STENCIL_OP::D3D11_STENCIL_OP_ZERO; + case StencilOperation::INCR: return D3D11_STENCIL_OP::D3D11_STENCIL_OP_INCR; + case StencilOperation::INCR_WRAP: return D3D11_STENCIL_OP::D3D11_STENCIL_OP_INCR_SAT; + case StencilOperation::DECR: return D3D11_STENCIL_OP::D3D11_STENCIL_OP_DECR; + case StencilOperation::DECR_WRAP: return D3D11_STENCIL_OP::D3D11_STENCIL_OP_DECR_SAT; + case StencilOperation::REPLACE: return D3D11_STENCIL_OP::D3D11_STENCIL_OP_REPLACE; + case StencilOperation::INVERT: return D3D11_STENCIL_OP::D3D11_STENCIL_OP_INVERT; + default: return D3D11_STENCIL_OP::D3D11_STENCIL_OP_KEEP; + } + } + + D3D11_DEPTH_WRITE_MASK getDepthWriteMask(const DepthWriteMask& writeMask) + { + switch (writeMask) { + case DepthWriteMask::ALL: return D3D11_DEPTH_WRITE_MASK_ALL; + case DepthWriteMask::ZERO: return D3D11_DEPTH_WRITE_MASK_ZERO; + default: return D3D11_DEPTH_WRITE_MASK_ALL; + } + } + + D3D11_BLEND getBlend(const BlendFunction& blendFunc) + { + switch (blendFunc) { + case BlendFunction::ZERO: return D3D11_BLEND::D3D11_BLEND_ZERO; + case BlendFunction::ONE: return D3D11_BLEND::D3D11_BLEND_ONE; + case BlendFunction::SRC_COLOR: return D3D11_BLEND::D3D11_BLEND_SRC_COLOR; + case BlendFunction::INV_SRC_COLOR: return D3D11_BLEND::D3D11_BLEND_INV_SRC_COLOR; + case BlendFunction::SRC_APLHA: return D3D11_BLEND::D3D11_BLEND_SRC_ALPHA; + case BlendFunction::INV_SRC_APLHA: return D3D11_BLEND::D3D11_BLEND_INV_SRC_ALPHA; + case BlendFunction::DEST_APLHA: return D3D11_BLEND::D3D11_BLEND_DEST_ALPHA; + case BlendFunction::INV_DEST_APLHA: return D3D11_BLEND::D3D11_BLEND_DEST_ALPHA; + case BlendFunction::DEST_COLOR: return D3D11_BLEND::D3D11_BLEND_DEST_COLOR; + case BlendFunction::INV_DEST_COLOR: return D3D11_BLEND::D3D11_BLEND_INV_DEST_COLOR; + case BlendFunction::BLEND_FACTOR: return D3D11_BLEND::D3D11_BLEND_BLEND_FACTOR; + case BlendFunction::INV_BLEND_FACTOR: return D3D11_BLEND::D3D11_BLEND_INV_BLEND_FACTOR; + default: return D3D11_BLEND::D3D11_BLEND_ONE; + } + } + + D3D11_BLEND_OP getBlendOperation(const BlendOperation& blendOp) + { + switch (blendOp) { + case BlendOperation::ADD: return D3D11_BLEND_OP::D3D11_BLEND_OP_ADD; + case BlendOperation::SUBTRACT: return D3D11_BLEND_OP::D3D11_BLEND_OP_SUBTRACT; + case BlendOperation::REV_SUBTRACT: return D3D11_BLEND_OP::D3D11_BLEND_OP_SUBTRACT; + case BlendOperation::MIN: return D3D11_BLEND_OP::D3D11_BLEND_OP_MIN; + case BlendOperation::MAX: return D3D11_BLEND_OP::D3D11_BLEND_OP_MAX; + } + } } \ No newline at end of file diff --git a/Snake/src/Graphics/Platform/DirectX/DX11Utils.h b/Snake/src/Graphics/Platform/DirectX/DX11Utils.h index 0d9df47..47b97ef 100644 --- a/Snake/src/Graphics/Platform/DirectX/DX11Utils.h +++ b/Snake/src/Graphics/Platform/DirectX/DX11Utils.h @@ -18,4 +18,9 @@ namespace DirectX { D3D11_FILTER getFilteringMode(const FilterMode& _min, const FilterMode& mag, const FilterMode& mip, const bool comparison); DXGI_FORMAT getDepthResourceFormat(TextureFormat textureFormat); D3D_PRIMITIVE_TOPOLOGY getTopology(PrimitiveTopology topology); + D3D11_COMPARISON_FUNC getComparisonFunction(const ComparisonFunction& func); + D3D11_STENCIL_OP getDepthStencilOperation(const StencilOperation& stecnilOp); + D3D11_DEPTH_WRITE_MASK getDepthWriteMask(const DepthWriteMask& writeMask); + D3D11_BLEND getBlend(const BlendFunction& blendFunc); + D3D11_BLEND_OP getBlendOperation(const BlendOperation& blendOp); } \ No newline at end of file diff --git a/Snake/src/Graphics/Platform/DirectX/DX11Window.h b/Snake/src/Graphics/Platform/DirectX/DX11Window.h index 98893d9..deea855 100644 --- a/Snake/src/Graphics/Platform/DirectX/DX11Window.h +++ b/Snake/src/Graphics/Platform/DirectX/DX11Window.h @@ -49,7 +49,7 @@ class DX11Window : public Window windowRect.bottom = height + windowRect.top; AdjustWindowRect(&windowRect, WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU, FALSE); - int styles = WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_THICKFRAME; + int styles = WS_POPUP | WS_MINIMIZEBOX | WS_SYSMENU | WS_THICKFRAME; hWnd = CreateWindow("SnakeWindowClass", "Hollow", styles, windowRect.left, windowRect.top, @@ -64,7 +64,7 @@ class DX11Window : public Window Rid[0].hwndTarget = 0; RegisterRawInputDevices(Rid, 1, sizeof(Rid[0])); - ShowWindow(hWnd, SW_SHOW); // SW_SHOWMAXIMIZED + ShowWindow(hWnd, SW_SHOWMAXIMIZED); UpdateWindow(hWnd); //ShowCursor(true); } diff --git a/Snake/src/Graphics/Renderer.h b/Snake/src/Graphics/Renderer.h index ce75b9e..a840030 100644 --- a/Snake/src/Graphics/Renderer.h +++ b/Snake/src/Graphics/Renderer.h @@ -46,6 +46,8 @@ class Renderer virtual void swapBuffers() = 0; virtual void unbindResource(int slot) = 0; virtual void setPrimitiveTopology(PrimitiveTopology topology) = 0; + virtual void setDefaultDepthStencil() = 0; + virtual void setDefaultBlendState() = 0; static Renderer* create(RendererType type); diff --git a/Snake/src/Graphics/Renderer/BlendState.cpp b/Snake/src/Graphics/Renderer/BlendState.cpp new file mode 100644 index 0000000..43b9b6d --- /dev/null +++ b/Snake/src/Graphics/Renderer/BlendState.cpp @@ -0,0 +1,11 @@ +#include "BlendState.h" +#include "Graphics/Renderer.h" +#include "Graphics/Platform/DirectX/DX11BlendState.h" + +BlendState* BlendState::create(const BlendStateDesc& desc) +{ + switch (Renderer::getType()) { + case RendererType::DirectX: return new DX11BlendState(desc); + } + return nullptr; +} \ No newline at end of file diff --git a/Snake/src/Graphics/Renderer/BlendState.h b/Snake/src/Graphics/Renderer/BlendState.h new file mode 100644 index 0000000..afb7344 --- /dev/null +++ b/Snake/src/Graphics/Renderer/BlendState.h @@ -0,0 +1,37 @@ +#pragma once + +#include "CommonTypes.h" + +class RenderContext; + +struct RenderTargetBlendState +{ + bool blendEnabled = false; + BlendFunction srcBlend = BlendFunction::ONE; + BlendFunction srcBlendAlpha = BlendFunction::ONE; + BlendFunction dstBlend = BlendFunction::ZERO; + BlendFunction dstBlendAlpha = BlendFunction::ZERO; + BlendOperation blendOp = BlendOperation::ADD; + BlendOperation blendOpAlpha = BlendOperation::ADD; + + unsigned char writeMask; +}; + +struct BlendStateDesc +{ + bool alphaToCoverageEnable = false; + bool independentBlendEnable = false; + RenderTargetBlendState blend[8]; + int count = 0; +}; + +class BlendState +{ +private: + BlendStateDesc desc; +public: + BlendState(const BlendStateDesc& desc) : desc(desc) {} + static BlendState* create(const BlendStateDesc& state); + + virtual void bind(RenderContext* context) = 0; +}; \ No newline at end of file diff --git a/Snake/src/Graphics/Renderer/CommonTypes.h b/Snake/src/Graphics/Renderer/CommonTypes.h index 4bca3f9..e481adc 100644 --- a/Snake/src/Graphics/Renderer/CommonTypes.h +++ b/Snake/src/Graphics/Renderer/CommonTypes.h @@ -103,4 +103,43 @@ enum class PrimitiveTopology { LINESTRIP, TRIANGELIST, TRIANGESTRIP, +}; + +enum class StencilOperation { + KEEP, + ZERO, + INCR, + DECR, + INCR_WRAP, + DECR_WRAP, + INVERT, + REPLACE +}; + +enum class BlendFunction { + ZERO, + ONE, + SRC_COLOR, + INV_SRC_COLOR, + SRC_APLHA, + INV_SRC_APLHA, + DEST_APLHA, + INV_DEST_APLHA, + DEST_COLOR, + INV_DEST_COLOR, + BLEND_FACTOR, + INV_BLEND_FACTOR +}; + +enum class BlendOperation { + ADD, + SUBTRACT, + REV_SUBTRACT, + MIN, + MAX +}; + +enum class DepthWriteMask { + ZERO, + ALL }; \ No newline at end of file diff --git a/Snake/src/Graphics/Renderer/DepthState.cpp b/Snake/src/Graphics/Renderer/DepthState.cpp new file mode 100644 index 0000000..1fe43fb --- /dev/null +++ b/Snake/src/Graphics/Renderer/DepthState.cpp @@ -0,0 +1,11 @@ +#include "DepthState.h" +#include "Graphics/Renderer.h" +#include "Graphics/Platform/DirectX/DX11DepthState.h" + +DepthState* DepthState::create(const DepthStateDesc& desc) +{ + switch (Renderer::getType()) { + case RendererType::DirectX: return new DX11DepthState(desc); + } + return nullptr; +} \ No newline at end of file diff --git a/Snake/src/Graphics/Renderer/DepthState.h b/Snake/src/Graphics/Renderer/DepthState.h new file mode 100644 index 0000000..312ae36 --- /dev/null +++ b/Snake/src/Graphics/Renderer/DepthState.h @@ -0,0 +1,41 @@ +#pragma once + +#include "CommonTypes.h" + +class RenderContext; + +struct DepthStencilOpStateDesc +{ + StencilOperation failOp; + StencilOperation depthFailOp; + StencilOperation passOp; + ComparisonFunction stencilFunc; +}; + +struct DepthStateDesc +{ + bool depthEnable; + ComparisonFunction depthFunc; + DepthWriteMask depthWriteMask; + bool stencilEnable; + unsigned char stencilWriteMask; + unsigned char stencilReadMask; + DepthStencilOpStateDesc front; + DepthStencilOpStateDesc back; + + DepthStateDesc() : + depthEnable(true), depthFunc(ComparisonFunction::LESS), depthWriteMask(DepthWriteMask::ALL), + stencilEnable(false), stencilWriteMask(0xFF), stencilReadMask(0xFF) + {} +}; + +class DepthState +{ +public: + DepthStateDesc desc; +public: + DepthState(const DepthStateDesc& desc) : desc(desc) { } + static DepthState* create(const DepthStateDesc& desc); + + virtual void bind(RenderContext* context) = 0; +}; \ No newline at end of file diff --git a/Snake/src/Input/InputManager.h b/Snake/src/Input/InputManager.h index 749dc12..4e9fe55 100644 --- a/Snake/src/Input/InputManager.h +++ b/Snake/src/Input/InputManager.h @@ -1,6 +1,11 @@ #pragma once -class InputManager { +#include + +struct MousePos { double x, y; }; + +class InputManager +{ public: double mousePosX = 0.0; double mousePosY = 0.0; @@ -13,8 +18,10 @@ class InputManager { bool mouseButton[5]; static InputManager* _instance; -private: +public: InputManager() { + assert(_instance == nullptr && "Cant create more than one input manager"); + _instance = this; for (int i = 0; i < 348; i++) { keyboardKeys[i] = false; } @@ -22,18 +29,14 @@ class InputManager { mouseButton[i] = false; } } -public: - static InputManager* instance() { - if (_instance == nullptr) { - _instance = new InputManager(); - } - return _instance; - } + + static InputManager* instance() { return _instance; } inline bool isKeyPressed(int keyCode) { return keyboardKeys[keyCode]; } inline void setKeyPressed(int keyCode, bool state) { keyboardKeys[keyCode] = state; } inline bool isMouseKeyPressed(int mouseCode) { return mouseButton[mouseCode]; } inline void setMouseKeyPressed(int mouseCode, bool state) { mouseButton[mouseCode] = state; } + inline MousePos getMousePoistion() const { return { mousePosX, mousePosY }; } void setCursorPosition(double x, double y) { mouseMoveCnt++; diff --git a/Snake/src/Systems/RenderSystem.h b/Snake/src/Systems/RenderSystem.h index bd15e5d..c4307bd 100644 --- a/Snake/src/Systems/RenderSystem.h +++ b/Snake/src/Systems/RenderSystem.h @@ -31,6 +31,7 @@ #include "ApplicationSettings.h" #include "Graphics/RenderQueue/RenderQueue.h" #include +#include "UI/UiSystem.h" #include "RenderSystem/RenderSystemResourceManager.h" #include "RenderSystem/RenderGraphBuilder.h" @@ -48,6 +49,7 @@ class RenderSystem : public ISystem RenderQueue* renderQueue; DebugCameraController cameraController; RenderGraph* renderGraph; + UiSystem* ui_system; GridSystem gridSystem; PhysicsSystem* physicsSystem; @@ -65,9 +67,9 @@ class RenderSystem : public ISystem bool useDebugCamera = true; DebugHelper debug; public: - RenderSystem(SceneManager* sceneManager, ApplicationSettings* settings, PhysicsSystem* physics, Renderer* renderer): + RenderSystem(SceneManager* sceneManager, ApplicationSettings* settings, PhysicsSystem* physics, Renderer* renderer, UiSystem* ui): ISystem(sceneManager), physicsSystem(physics), renderer(renderer), context(renderer->getContext()), - eventSystem(eventSystem) + ui_system(ui), eventSystem(eventSystem) { renderQueue = new RenderQueue(); // Debug camera initialization @@ -78,6 +80,7 @@ class RenderSystem : public ISystem resources = resourceManager.initialize(renderer, settings); resources->point_repeat_sampler->bind(context); + resources->linear_clamp_sampler->bind(context); RenderGraphBuilder renderGraphBuilder; renderGraph = renderGraphBuilder.build(renderQueue, renderer, resources); @@ -92,6 +95,7 @@ class RenderSystem : public ISystem virtual void update(double dt) override { + renderer->setDefaultDepthStencil(); entt::registry* registry = sceneManager->getCurrentScene()->getRegistry(); glm::mat4 lightProjection, lightView; @@ -125,11 +129,12 @@ class RenderSystem : public ISystem renderGraph->execute(sceneManager->getCurrentScene()); //renderQueue->present(); - debug.renderTexture(0.0f, 0.0f, 0.5f, 0.5f, resources->textures["positions"].get()); - debug.renderFont("Dt: " + std::to_string(dt), 0.0f, 0.97f); - debug.renderFont("Draw calls: " + std::to_string(renderer->getContext()->getDrawCallCount()), 0.0f, 0.94f); + //debug.renderTexture(0.0f, 0.0f, 0.5f, 0.5f, resources->textures["positions"].get()); + //debug.renderFont("Settings", 0.435f, 0.45f); //debug.renderFont("Exit", 0.45f, 0.4f); + ui_system->render(); + debug.renderFont("Dt: " + std::to_string(dt) + " Draw calls: " + std::to_string(renderer->getContext()->getDrawCallCount()), 0.88f, 0.002f, 0.5f); renderer->swapBuffers(); diff --git a/Snake/src/Systems/SystemManager.h b/Snake/src/Systems/SystemManager.h index 3736f93..f1b00f3 100644 --- a/Snake/src/Systems/SystemManager.h +++ b/Snake/src/Systems/SystemManager.h @@ -13,6 +13,7 @@ #include "Graphics/Renderer.h" #include "EventSystem/EventSystem.h" #include "GltfTransformSystem.h" +#include "Ui/UiSystem.h" class SystemManager { @@ -26,10 +27,10 @@ class SystemManager std::unique_ptr moveSystem; std::unique_ptr gltfTransformSystem; public: - void initialize(ApplicationSettings* settings, SceneManager* sceneManager, Renderer* renderer) + void initialize(ApplicationSettings* settings, SceneManager* sceneManager, Renderer* renderer, UiSystem* ui) { physicsSystem = std::make_unique(sceneManager); - renderSystem = std::make_unique(sceneManager, settings, physicsSystem.get(), renderer); + renderSystem = std::make_unique(sceneManager, settings, physicsSystem.get(), renderer, ui); scriptSystem = std::make_unique(sceneManager); cameraSystem = std::make_unique(sceneManager); playerSystem = std::make_unique(sceneManager, physicsSystem.get()); diff --git a/Snake/src/UI/UiConstraints.h b/Snake/src/UI/UiConstraints.h new file mode 100644 index 0000000..29d4e33 --- /dev/null +++ b/Snake/src/UI/UiConstraints.h @@ -0,0 +1,74 @@ +#pragma once + +enum class ValueType { Absolute, Relative }; +struct Value { + ValueType type; + int value; + + int getNormalizedValue(size_t parent_value) + { + if (type == ValueType::Relative) { + return (int)(((float)parent_value / 100.0f) * value); + } else { + return value; + } + } +}; + +enum class XPosition { Right, Center, Left }; +class XPositionConstraint { +public: + XPosition position = XPosition::Center; + + int getNormalizedValue(int parent_x_pos, int parent_width, int width) + { + if (position == XPosition::Left) { + return parent_x_pos; + } else if (position == XPosition::Center) { + return (int)((float)parent_width / 2.0f) - ((float)width / 2.0f); + } else if (position == XPosition::Right) { + return parent_width - width; + } + assert("Unknown x pos type"); + } +}; + +enum class YPosition { Top, Center, Bottom }; +class YPositionConstraint { +public: + YPosition position = YPosition::Center; + + int getNormalizedValue(int parent_y_pos, int parent_height, int height, int parent_internal_height_occupied) + { + if (position == YPosition::Top) { + return parent_y_pos + parent_height - height - parent_internal_height_occupied; + } else if (position == YPosition::Center) { + return (int)((float)parent_height / 2) - ((float)height / 2.0f); + } else if (position == YPosition::Bottom) { + return parent_y_pos; + } + assert("Unknown y pos type"); + } +}; + +class UiConstraints +{ +private: + Value width; + Value height; + + XPositionConstraint x_position; + YPositionConstraint y_position; +public: + void setXPos(XPositionConstraint position) { x_position = position; } + XPositionConstraint getXPos() const { return x_position; } + + void setYPos(YPositionConstraint position) { y_position = position; } + YPositionConstraint getYPos() const { return y_position; } + + void setWidth(Value value) { width = value; } + Value getWidth() const { return width; } + + void setHeight(Value value) { height = value; } + Value getHeight() const { return height; } +}; \ No newline at end of file diff --git a/Snake/src/UI/UiDisplay.h b/Snake/src/UI/UiDisplay.h new file mode 100644 index 0000000..ff71d86 --- /dev/null +++ b/Snake/src/UI/UiDisplay.h @@ -0,0 +1,8 @@ +#pragma once + +#include "UiElement.h" + +class UiDisplay : public UiElement +{ + +}; \ No newline at end of file diff --git a/Snake/src/UI/UiElement.h b/Snake/src/UI/UiElement.h new file mode 100644 index 0000000..193636a --- /dev/null +++ b/Snake/src/UI/UiElement.h @@ -0,0 +1,71 @@ +#pragma once + +#include "Input/InputManager.h" +#include "Graphics/Renderer/VertexBuffer.h" +#include +#include +#include +#include "Graphics/Renderer.h" +#include "EventSystem/EventSystem.h" +#include + +class UiRenderer; + +class UiElement +{ +public: + UiElement* parent; + std::vector childs; + glm::vec4 color; + glm::vec4 bg_color; + + std::unique_ptr vBuffer; + + int width, height; + int x_start, y_start; + + int internal_width_occupied = 0; + int internal_height_occupied = 0; + + std::function onHover; + std::function onClick; + + bool hovered = false; + bool visible = true; +public: + UiElement() + { + EventSystem::instance()->addEventListener(new ClassEventDelegate(this, &UiElement::onMouseClick)); + } + + virtual void render(UiRenderer* renderer) {} + + virtual void update(const MousePos& mouse_pos) + { + if (mouse_pos.x > x_start && mouse_pos.x < x_start + width && mouse_pos.y > y_start && mouse_pos.y < y_start + height) { + hovered = true; + if (onHover) { + onHover(); + } + } else { + hovered = false; + } + + for (auto& it : childs) { + it->update(mouse_pos); + } + } + + void add(UiElement* element) + { + childs.push_back(element); + internal_height_occupied += element->height; + } + + void onMouseClick(Event* event) + { + if (hovered && onClick) { + onClick(); + } + } +}; \ No newline at end of file diff --git a/Snake/src/UI/UiIcon.h b/Snake/src/UI/UiIcon.h new file mode 100644 index 0000000..283ca23 --- /dev/null +++ b/Snake/src/UI/UiIcon.h @@ -0,0 +1,52 @@ +#pragma once + +#include "UiElement.h" +#include "Graphics/Renderer/Texture2D.h" +#include "UI/UiRenderer.h" + +class UiIcon : public UiElement +{ +public: + bool hovered = false; + bool selected = false; +private: + std::unique_ptr icon_texture; +public: + UiIcon(Texture2D* texture) + { + icon_texture.reset(texture); + EventSystem::instance()->addEventListener(new ClassEventDelegate(this, &UiIcon::onLeftMouseClick)); + } + + virtual void render(UiRenderer* ui_renderer) override + { + if (!visible) return; + + Renderer* renderer = ui_renderer->renderer; + + ui_renderer->ui_icon_shader->bind(renderer->getContext()); + + ColorBufferData data = { color, bg_color, true, hovered, selected }; + ui_renderer->buffer->update(&data); + ui_renderer->buffer->bind(renderer->getContext()); + + ui_renderer->blend_state->bind(renderer->getContext()); + vBuffer->bind(ui_renderer->renderer->getContext()); + icon_texture->bindToUnit(0, ui_renderer->renderer->getContext()); + + renderer->draw(6); + + ui_renderer->ui_shader->bind(renderer->getContext()); + renderer->setDefaultBlendState(); + } + + void onLeftMouseClick(Event* event) + { + if (hovered) { + selected = true; + return; + } else { + selected = false; + } + } +}; \ No newline at end of file diff --git a/Snake/src/UI/UiIconMenu.h b/Snake/src/UI/UiIconMenu.h new file mode 100644 index 0000000..6099bb8 --- /dev/null +++ b/Snake/src/UI/UiIconMenu.h @@ -0,0 +1,34 @@ +#pragma once + +#include "UiElement.h" +#include + +class UiIconMenu : public UiElement +{ +public: + UiIconMenu() + { + EventSystem::instance()->addEventListener(new ClassEventDelegate(this, &UiIconMenu::onLeftMouseClick)); + } + + + virtual void render(UiRenderer* ui_renderer) + { + Renderer* renderer = ui_renderer->renderer; + + ColorBufferData data = { color, bg_color, false, false }; + ui_renderer->buffer->update(&data); + ui_renderer->buffer->bind(renderer->getContext()); + + vBuffer->bind(renderer->getContext()); + renderer->draw(6); + + // Render stuff + UiElement::render(ui_renderer); + } + + void onLeftMouseClick(Event* event) + { + + } +}; \ No newline at end of file diff --git a/Snake/src/UI/UiRenderer.h b/Snake/src/UI/UiRenderer.h new file mode 100644 index 0000000..ab3f21b --- /dev/null +++ b/Snake/src/UI/UiRenderer.h @@ -0,0 +1,88 @@ +#pragma once + +#include "Graphics/Renderer.h" +#include "Graphics/Renderer/ShaderPipeline.h" +#include "Graphics/Renderer/ConstantBuffer.h" +#include "Graphics/Renderer/DepthState.h" +#include "Graphics/Renderer/BlendState.h" +#include "FileSystem/File.h" +#include + +//struct UiData { +// int width, height; +// int xPos, yPos; +//}; + +struct ColorBufferData { + glm::vec4 color; + glm::vec4 bg_color; + int has_texture = false; + int hovered = false; + int selected = false; +}; + +class UiRenderer +{ +public: + Renderer* renderer; + std::unique_ptr ui_shader; + std::unique_ptr ui_icon_shader; + std::unique_ptr buffer; + std::unique_ptr depthState; + std::unique_ptr blend_state; +public: + UiRenderer(Renderer* renderer): renderer(renderer) + { + buffer.reset(ConstantBuffer::create(0, sizeof(ColorBufferData), nullptr)); + + { + File filePS("shaders/dx/ui/pixel.hlsl"); + File fileVS("shaders/dx/ui/vertex.hlsl"); + ui_shader.reset(ShaderPipeline::create(fileVS.getConent(), filePS.getConent())); + } + { + File filePS("shaders/dx/ui_icon/pixel.hlsl"); + File fileVS("shaders/dx/ui_icon/vertex.hlsl"); + ui_icon_shader.reset(ShaderPipeline::create(fileVS.getConent(), filePS.getConent())); + } + + DepthStateDesc depthStateDesc; + depthStateDesc.depthEnable = false; + + depthState.reset(DepthState::create(depthStateDesc)); + + BlendStateDesc blendStateDesc; + blendStateDesc.count = 1; + + blendStateDesc.blend[0].blendEnabled = true; + blendStateDesc.blend[0].blendOp = BlendOperation::ADD; + blendStateDesc.blend[0].srcBlend = BlendFunction::SRC_APLHA; + blendStateDesc.blend[0].dstBlend = BlendFunction::INV_SRC_APLHA; + + blendStateDesc.blend[0].blendOpAlpha = BlendOperation::ADD; + blendStateDesc.blend[0].srcBlendAlpha = BlendFunction::ZERO; + blendStateDesc.blend[0].dstBlendAlpha = BlendFunction::ZERO; + + blend_state.reset(BlendState::create(blendStateDesc)); + } + + void render(UiElement* element) + { + depthState->bind(renderer->getContext()); + + ui_shader->bind(renderer->getContext()); + render_recursive(element); + + //renderer->setDefaultDepthStencil(); + } + + void render_recursive(UiElement* el) + { + el->render(this); + + for (auto& child : el->childs) + { + render_recursive(child); + } + } +}; \ No newline at end of file diff --git a/Snake/src/UI/UiSystem.cpp b/Snake/src/UI/UiSystem.cpp new file mode 100644 index 0000000..221cd5e --- /dev/null +++ b/Snake/src/UI/UiSystem.cpp @@ -0,0 +1,2 @@ +#include "UiSystem.h" + diff --git a/Snake/src/UI/UiSystem.h b/Snake/src/UI/UiSystem.h new file mode 100644 index 0000000..068459b --- /dev/null +++ b/Snake/src/UI/UiSystem.h @@ -0,0 +1,79 @@ +#pragma once + +#include "UiElement.h" +#include "UiRenderer.h" +#include "Input/InputManager.h" +#include "UiDisplay.h" +#include "UiConstraints.h" +#include +#include "ApplicationSettings.h" +#include "Graphics/vertex.h" +#include "EventSystem/EventSystem.h" + +class UiSystem +{ +private: + InputManager* input_manager = nullptr; + UiRenderer* ui_renderer = nullptr; + UiElement* root = nullptr; + ApplicationSettings* settings = nullptr; + + std::vector elements; +public: + UiSystem(Renderer* renderer, InputManager* inputManager, ApplicationSettings* settings) : input_manager(inputManager), settings(settings) + { + ui_renderer = new UiRenderer(renderer); + root = new UiDisplay(); + + root->width = settings->getWindowWidth(); + root->height = settings->getWindowHeight(); + root->y_start = 0; + root->x_start = 0; + } + + inline UiElement* getRootElement() { return root; } + + void update() + { + MousePos pos = input_manager->getMousePoistion(); + pos.y = settings->getWindowHeight() - pos.y; + + root->update(pos); + } + + void render() + { + ui_renderer->render(root); + } + + void add(UiElement* parent, UiElement* child, const UiConstraints& constraints) + { + child->width = constraints.getWidth().getNormalizedValue(parent->width); + child->height = constraints.getHeight().getNormalizedValue(parent->height); + + child->x_start = constraints.getXPos().getNormalizedValue(parent->x_start, parent->width, child->width); + child->y_start = constraints.getYPos().getNormalizedValue(parent->y_start, parent->height, child->height, parent->internal_height_occupied); + + float new_x_start = ((float)child->x_start / settings->getWindowWidth()) * 2.0f - 1.0f; + float new_y_start = ((float)child->y_start / settings->getWindowHeight()) * 2.0f - 1.0f; + float new_width = (float)child->width / settings->getWindowWidth() * 2.0f; + float new_height = (float)child->height / settings->getWindowHeight() * 2.0f; + + vertex vertices[] = { + vertex(new_x_start + new_width, new_y_start + new_height, 0.0f, 1.0f, 0.0f), + vertex(new_x_start + new_width, new_y_start, 0.0f, 1.0f, 1.0f), + vertex(new_x_start, new_y_start + new_height, 0.0f, 0.0f, 0.0f), + + vertex(new_x_start, new_y_start, 0.0f, 0.0f, 1.0f), + vertex(new_x_start, new_y_start + new_height, 0.0f, 0.0f, 0.0f), + vertex(new_x_start + new_width, new_y_start, 0.0f, 1.0f, 1.0f), + }; + + child->vBuffer.reset(VertexBuffer::create(6, sizeof(vertex), vertices)); + child->parent = parent; + + parent->add(child); + + elements.push_back(child); + } +}; \ No newline at end of file diff --git a/Snake/src/UI/Widgets/UiBlock.h b/Snake/src/UI/Widgets/UiBlock.h new file mode 100644 index 0000000..a33dc2e --- /dev/null +++ b/Snake/src/UI/Widgets/UiBlock.h @@ -0,0 +1,39 @@ +#pragma once + +#include "UI/UiElement.h" +#include "Graphics/Renderer/VertexBuffer.h" +#include "Graphics/vertex.h" +#include +#include "UI/UiRenderer.h" + +class UiBlock : public UiElement +{ +private: + bool hovered = false; +public: + virtual void render(UiRenderer* ui_renderer) override + { + Renderer* renderer = ui_renderer->renderer; + + ColorBufferData data = { color, bg_color, false, false }; + ui_renderer->buffer->update(&data); + ui_renderer->buffer->bind(renderer->getContext()); + + vBuffer->bind(renderer->getContext()); + renderer->draw(6); + + // Render stuff + UiElement::render(ui_renderer); + } + + virtual void update(const MousePos& mouse_pos) override + { + if (mouse_pos.x > x_start && mouse_pos.x < x_start + width && mouse_pos.y > y_start && mouse_pos.y < y_start + height) { + hovered = true; + } else { + hovered = false; + } + + UiElement::update(mouse_pos); + } +}; \ No newline at end of file