From 69e86d1cc92c67c3175f8c08bcc31823e0c45af8 Mon Sep 17 00:00:00 2001 From: Jordi Pi Date: Wed, 8 Jul 2026 16:50:44 +0200 Subject: [PATCH 1/3] image cover mode --- Engine_Master_UPC/ModuleUI.cpp | 49 +++++++++++++++++++++++++++++----- Engine_Master_UPC/UIImage.cpp | 2 +- Engine_Master_UPC/UIImage.h | 15 ++++++++--- 3 files changed, 55 insertions(+), 11 deletions(-) diff --git a/Engine_Master_UPC/ModuleUI.cpp b/Engine_Master_UPC/ModuleUI.cpp index 6b07094d..5155ff5e 100644 --- a/Engine_Master_UPC/ModuleUI.cpp +++ b/Engine_Master_UPC/ModuleUI.cpp @@ -226,9 +226,43 @@ void ModuleUI::buildUIImage(GameObject* gameObject, const Rect2D& myRect, Canvas command.sheetOffset = Vector2(0.5f, 0.5f) * command.uvScale + uiImg->getSheetOffset(); const bool hasSheet = uiImg->getSheetColumns() > 1 || uiImg->getSheetRows() > 1; - if (uiImg->getStretchDrawMode() == UIImage::StretchDrawMode::Tile && !hasSheet) + const UIImage::StretchDrawMode drawMode = uiImg->getStretchDrawMode(); + + if (drawMode == UIImage::StretchDrawMode::Cover && !hasSheet) { + TextureAsset* textureAsset = uiImg->getTextureAsset(); + + if (textureAsset) + { + const float textureWidth = static_cast(textureAsset->getWidth()); + const float textureHeight = static_cast(textureAsset->getHeight()); + + if (textureWidth > 0.0f && textureHeight > 0.0f && myRect.w > 0.0f && myRect.h > 0.0f) + { + const float textureAspect = textureWidth / textureHeight; + const float rectAspect = myRect.w / myRect.h; + + if (rectAspect > textureAspect) + { + // if the rectAspect is wider than the texture, fill width and crop top/bottom. + const float visibleV = textureAspect / rectAspect; + + command.uvScale = { 1.0f, visibleV }; + command.sheetOffset = { 0.5f, 0.5f }; + } + else + { + // int he other hand, if the rect is taller/narrower than the texture, fill height and crop left/right. + const float visibleU = rectAspect / textureAspect; + command.uvScale = { visibleU, 1.0f }; + command.sheetOffset = { 0.5f, 0.5f }; + } + } + } + } + else if (drawMode == UIImage::StretchDrawMode::Tile && !hasSheet) + { if (t2d->getStretchMode() == StretchMode::HORIZONTAL) { command.uvScale.y *= t2d->getScale().y; @@ -236,16 +270,17 @@ void ModuleUI::buildUIImage(GameObject* gameObject, const Rect2D& myRect, Canvas else if (t2d->getStretchMode() == StretchMode::VERTICAL) { command.uvScale.x *= t2d->getScale().x; - } + } else if (t2d->getStretchMode() == StretchMode::BOTH) - { - command.uvScale *= Vector2(myRect.w / t2d->getBaseSize().x, myRect.h / t2d->getBaseSize().y); - } + { + command.uvScale *= Vector2(myRect.w / t2d->getBaseSize().x, myRect.h / t2d->getBaseSize().y); + } else { command.uvScale *= t2d->getScale(); - } - command.sheetOffset = Vector2(0.5f, 0.5f); + } + + command.sheetOffset = Vector2(0.5f, 0.5f); } command.renderMode = renderMode; diff --git a/Engine_Master_UPC/UIImage.cpp b/Engine_Master_UPC/UIImage.cpp index e6ab1939..e5694cc6 100644 --- a/Engine_Master_UPC/UIImage.cpp +++ b/Engine_Master_UPC/UIImage.cpp @@ -107,7 +107,7 @@ void UIImage::drawUi() ImGui::Separator(); ImGui::TextUnformatted("Stretch"); { - const char* modes[] = { "Stretch", "Tile" }; + const char* modes[] = { "Stretch", "Tile", "Cover" }; int mode = static_cast(m_stretchDrawMode); if (ImGui::Combo("When Stretched", &mode, modes, IM_ARRAYSIZE(modes))) { diff --git a/Engine_Master_UPC/UIImage.h b/Engine_Master_UPC/UIImage.h index abead62f..d4bf7926 100644 --- a/Engine_Master_UPC/UIImage.h +++ b/Engine_Master_UPC/UIImage.h @@ -13,18 +13,27 @@ class UIImage : public Component enum class StretchDrawMode { Stretch = 0, - Tile = 1 + Tile = 1, + Cover = 2 }; static const char* StretchDrawModeToString(uint32_t v) { - return v == 0 ? "Stretch" : "Tile"; + switch (static_cast(v)) + { + case StretchDrawMode::Stretch: return "Stretch"; + case StretchDrawMode::Tile: return "Tile"; + case StretchDrawMode::Cover: return "Cover"; + } } static uint32_t StringToStretchDrawMode(const char* s) { - return std::strcmp(s, "Tile") == 0 ? 1 : 0; + if (std::strcmp(s, "Tile") == 0) return 1; + if (std::strcmp(s, "Cover") == 0) return 2; + return 0; } + UIImage(UID id, GameObject* owner); std::unique_ptr clone(GameObject* newOwner) const override; From cd9a14ad7f992263e6d1887f8d28d12fbde0ec13 Mon Sep 17 00:00:00 2001 From: Jordi Pi Date: Wed, 8 Jul 2026 17:19:42 +0200 Subject: [PATCH 2/3] separating RenderSurface logical size from texture attachment --- Engine_Master_UPC/ModuleRender.cpp | 15 +++++++++++++++ Engine_Master_UPC/ModuleUI.cpp | 8 ++++++++ Engine_Master_UPC/RenderSurface.cpp | 13 +++++-------- Engine_Master_UPC/RenderSurface.h | 1 + Engine_Master_UPC/SwapChain.cpp | 8 +++++++- 5 files changed, 36 insertions(+), 9 deletions(-) diff --git a/Engine_Master_UPC/ModuleRender.cpp b/Engine_Master_UPC/ModuleRender.cpp index 56698b59..9c765ea8 100644 --- a/Engine_Master_UPC/ModuleRender.cpp +++ b/Engine_Master_UPC/ModuleRender.cpp @@ -168,6 +168,15 @@ void ModuleRender::preRender() continue; } + DEBUG_LOG( + "Rendering viewport: type=%s surface=%p size=%f,%f visible=%d", + entry.type == ViewportType::EDITOR ? "EDITOR" : "PLAY", + entry.surface, + entry.width, + entry.height, + entry.isVisible + ); + BEGIN_EVENT(commandList, "Prepare Render Target"); auto colorTex = entry.surface->getTexture(RenderSurface::COMPOSITE); @@ -366,6 +375,12 @@ void ModuleRender::renderScene(ID3D12GraphicsCommandList4* commandList, const Re const float w = static_cast(outputSurface.getWidth()); const float h = static_cast(outputSurface.getHeight()); + DEBUG_LOG( + "RenderSurface size: w=%u h=%u", + outputSurface.getWidth(), + outputSurface.getHeight() + ); + D3D12_VIEWPORT viewport = { 0.0f, 0.0f, w, h, 0.0f, 1.0f }; D3D12_RECT scissorRect = { 0, 0, static_cast(w), static_cast(h) }; diff --git a/Engine_Master_UPC/ModuleUI.cpp b/Engine_Master_UPC/ModuleUI.cpp index 5155ff5e..5193454d 100644 --- a/Engine_Master_UPC/ModuleUI.cpp +++ b/Engine_Master_UPC/ModuleUI.cpp @@ -283,6 +283,14 @@ void ModuleUI::buildUIImage(GameObject* gameObject, const Rect2D& myRect, Canvas command.sheetOffset = Vector2(0.5f, 0.5f); } + DEBUG_LOG( + "Home Background rect: x=%f y=%f w=%f h=%f", + command.rect.x, + command.rect.y, + command.rect.w, + command.rect.h + ); + command.renderMode = renderMode; command.world = (renderMode == CanvasRenderMode::SCREEN_SPACE) ? Matrix::Identity diff --git a/Engine_Master_UPC/RenderSurface.cpp b/Engine_Master_UPC/RenderSurface.cpp index bb184cb1..fd2c0858 100644 --- a/Engine_Master_UPC/RenderSurface.cpp +++ b/Engine_Master_UPC/RenderSurface.cpp @@ -16,14 +16,6 @@ RenderSurface::RenderSurface() : m_textures(AttachmentPoint::NUM_ATTACHMENT_POIN void RenderSurface::attachTexture(AttachmentPoint attachmentPoint, std::shared_ptr texture) { m_textures[attachmentPoint] = texture; - - if (texture && texture->getD3D12Resource()) - { - auto desc = texture->getD3D12ResourceDesc(); - - m_size.x = static_cast(desc.Width); - m_size.y = static_cast(desc.Height); - } } std::shared_ptr RenderSurface::getTexture(AttachmentPoint attachmentPoint) const @@ -88,6 +80,11 @@ void RenderSurface::resize(uint32_t width, uint32_t height) resize(Vector2(static_cast(width), static_cast(height))); } +void RenderSurface::setSize(uint32_t width, uint32_t height) +{ + m_size = Vector2(static_cast(width), static_cast(height)); +} + Vector2 RenderSurface::getSize() const { return m_size; diff --git a/Engine_Master_UPC/RenderSurface.h b/Engine_Master_UPC/RenderSurface.h index a214c5fc..d5dd7ad5 100644 --- a/Engine_Master_UPC/RenderSurface.h +++ b/Engine_Master_UPC/RenderSurface.h @@ -39,6 +39,7 @@ class RenderSurface void resize(Vector2 size); void resize(uint32_t width, uint32_t height); + void setSize(uint32_t width, uint32_t height); Vector2 getSize() const; uint32_t getWidth() const; diff --git a/Engine_Master_UPC/SwapChain.cpp b/Engine_Master_UPC/SwapChain.cpp index 19cfe7ca..618def10 100644 --- a/Engine_Master_UPC/SwapChain.cpp +++ b/Engine_Master_UPC/SwapChain.cpp @@ -60,6 +60,8 @@ SwapChain::SwapChain(HWND hWnd, ComPtr device, CommandQueue* queu auto* depthTexture = app->getModuleResources()->createDepthBuffer(float(m_windowWidth), float(m_windowHeight)); m_renderSurface.attachTexture( RenderSurface::DEPTH_STENCIL, std::shared_ptr(depthTexture)); + + m_renderSurface.setSize(m_windowWidth, m_windowHeight); } SwapChain::~SwapChain() @@ -114,7 +116,11 @@ void SwapChain::resize() DXCall(m_swapChain->ResizeBuffers(FRAMES_IN_FLIGHT, width, height, swapChainDesc.BufferDesc.Format, swapChainDesc.Flags)); createRenderTargetViews(app->getModuleD3D12()->getDevice()); - m_renderSurface.resize(m_windowWidth, m_windowHeight); + + auto* depthTexture = app->getModuleResources()->createDepthBuffer(float(m_windowWidth), float(m_windowHeight)); + m_renderSurface.attachTexture(RenderSurface::DEPTH_STENCIL, std::shared_ptr(depthTexture)); + + m_renderSurface.setSize(m_windowWidth, m_windowHeight); } } From 32a7a5ef6d4edd0382b1ec568b6f72a7d9f56b9b Mon Sep 17 00:00:00 2001 From: Jordi Pi Date: Wed, 8 Jul 2026 17:47:52 +0200 Subject: [PATCH 3/3] building UI commands per render viewport --- Engine_Master_UPC/ModuleRender.cpp | 15 +--------- Engine_Master_UPC/ModuleUI.cpp | 45 +++++++++++++----------------- Engine_Master_UPC/ModuleUI.h | 2 ++ 3 files changed, 23 insertions(+), 39 deletions(-) diff --git a/Engine_Master_UPC/ModuleRender.cpp b/Engine_Master_UPC/ModuleRender.cpp index 9c765ea8..8b771b33 100644 --- a/Engine_Master_UPC/ModuleRender.cpp +++ b/Engine_Master_UPC/ModuleRender.cpp @@ -168,15 +168,6 @@ void ModuleRender::preRender() continue; } - DEBUG_LOG( - "Rendering viewport: type=%s surface=%p size=%f,%f visible=%d", - entry.type == ViewportType::EDITOR ? "EDITOR" : "PLAY", - entry.surface, - entry.width, - entry.height, - entry.isVisible - ); - BEGIN_EVENT(commandList, "Prepare Render Target"); auto colorTex = entry.surface->getTexture(RenderSurface::COMPOSITE); @@ -375,11 +366,7 @@ void ModuleRender::renderScene(ID3D12GraphicsCommandList4* commandList, const Re const float w = static_cast(outputSurface.getWidth()); const float h = static_cast(outputSurface.getHeight()); - DEBUG_LOG( - "RenderSurface size: w=%u h=%u", - outputSurface.getWidth(), - outputSurface.getHeight() - ); + app->getModuleUI()->buildCommandsForViewport(w, h); D3D12_VIEWPORT viewport = { 0.0f, 0.0f, w, h, 0.0f, 1.0f }; D3D12_RECT scissorRect = { 0, 0, static_cast(w), static_cast(h) }; diff --git a/Engine_Master_UPC/ModuleUI.cpp b/Engine_Master_UPC/ModuleUI.cpp index 5193454d..2f3297a6 100644 --- a/Engine_Master_UPC/ModuleUI.cpp +++ b/Engine_Master_UPC/ModuleUI.cpp @@ -29,23 +29,26 @@ void ModuleUI::preRender() { m_textCommands.clear(); m_imageCommands.clear(); +} -#ifdef GAME_RELEASE - auto viewport = app->getModuleD3D12()->getSwapChain()->getViewport(); - const ImVec2 screenSize(viewport.Width, viewport.Height); -#else - const ImVec2 screenSize = app->getModuleEditor()->getWindowSceneEditor()->getSize(); -#endif +void ModuleUI::buildCommandsForViewport(float width, float height) +{ + m_textCommands.clear(); + m_imageCommands.clear(); - if (screenSize.x <= 0.0f || screenSize.y <= 0.0f) + if (width <= 0.0f || height <= 0.0f) + { return; + } - m_rootScreenRect = { 0.0f, 0.0f, screenSize.x, screenSize.y }; + m_rootScreenRect = { 0.0f, 0.0f, width, height }; for (GameObject* go : app->getModuleScene()->getScene()->getAllGameObjects()) { if (!go || !go->GetActive()) + { continue; + } Canvas* canvas = go->GetComponentAs(ComponentType::CANVAS); if (!canvas || !canvas->isActive()) @@ -60,22 +63,22 @@ void ModuleUI::preRender() if (isScreenSpace) { - uiScale = UILayoutUtils::CalculateScreenSpaceScale(screenSize.x, screenSize.y); + uiScale = UILayoutUtils::CalculateScreenSpaceScale(width, height); } else { rootRect = { -0.5f, -0.5f, 1.0f, 1.0f }; } - if (Transform2D* canvasTransform = go->GetComponentAs(ComponentType::TRANSFORM2D)) - { - if (canvasTransform->isActive()) - { - rootRect = canvasTransform->getRect(rootRect, { 1.0f, 1.0f }); - } - } + if (Transform2D* canvasTransform = go->GetComponentAs(ComponentType::TRANSFORM2D)) + { + if (canvasTransform->isActive()) + { + rootRect = canvasTransform->getRect(rootRect, { 1.0f, 1.0f }); + } + } - buildUIDrawCommands(go, rootRect, canvas->renderMode, go->GetTransform()->getGlobalMatrix(), canvas->zTest, uiScale); + buildUIDrawCommands(go, rootRect, canvas->renderMode, go->GetTransform()->getGlobalMatrix(), canvas->zTest, uiScale); } } @@ -283,14 +286,6 @@ void ModuleUI::buildUIImage(GameObject* gameObject, const Rect2D& myRect, Canvas command.sheetOffset = Vector2(0.5f, 0.5f); } - DEBUG_LOG( - "Home Background rect: x=%f y=%f w=%f h=%f", - command.rect.x, - command.rect.y, - command.rect.w, - command.rect.h - ); - command.renderMode = renderMode; command.world = (renderMode == CanvasRenderMode::SCREEN_SPACE) ? Matrix::Identity diff --git a/Engine_Master_UPC/ModuleUI.h b/Engine_Master_UPC/ModuleUI.h index dad4db6b..5c301c4d 100644 --- a/Engine_Master_UPC/ModuleUI.h +++ b/Engine_Master_UPC/ModuleUI.h @@ -17,6 +17,8 @@ class ModuleUI : public Module void preRender() override; bool cleanUp() override; + void buildCommandsForViewport(float width, float height); + const std::vector& getTextCommands() const { return m_textCommands; } const std::vector& getImageCommands() const { return m_imageCommands; }