From 5ba7ec3bfa7a643e071936e5ef142372718ac071 Mon Sep 17 00:00:00 2001 From: vladislavbelov Date: Tue, 15 Aug 2023 17:29:45 +0000 Subject: [PATCH] Removes scissor backend setup from GUI. Differential Revision: https://code.wildfiregames.com/D5051 This was SVN commit r27798. --- source/graphics/Canvas2D.cpp | 34 +++++++++++++++++++++++++++++++ source/graphics/Canvas2D.h | 34 +++++++++++++++++++++++++++++-- source/gui/CGUIText.cpp | 31 +++++----------------------- source/gui/ObjectTypes/CInput.cpp | 23 ++++----------------- 4 files changed, 75 insertions(+), 47 deletions(-) diff --git a/source/graphics/Canvas2D.cpp b/source/graphics/Canvas2D.cpp index 9154ebfea1..a1cd37a745 100644 --- a/source/graphics/Canvas2D.cpp +++ b/source/graphics/Canvas2D.cpp @@ -25,6 +25,7 @@ #include "graphics/TextureManager.h" #include "maths/Rect.h" #include "maths/Vector2D.h" +#include "ps/containers/StaticVector.h" #include "ps/CStrInternStatic.h" #include "renderer/Renderer.h" @@ -159,6 +160,22 @@ public: return transform; } + void ApplyScissors() + { + if (!Scissors.empty()) + { + CRect rect = Scissors.back(); + Renderer::Backend::IDeviceCommandContext::Rect scissorRect; + scissorRect.x = std::ceil(rect.left * Scale); + scissorRect.y = std::ceil(static_cast(HeightInPixels) - rect.bottom * Scale); + scissorRect.width = std::floor(rect.GetWidth() * Scale); + scissorRect.height = std::floor(rect.GetHeight() * Scale); + DeviceCommandContext->SetScissors(1, &scissorRect); + } + else + DeviceCommandContext->SetScissors(0, nullptr); + } + uint32_t WidthInPixels = 1; uint32_t HeightInPixels = 1; float Scale = 1.0f; @@ -173,6 +190,8 @@ public: // We assume that the shader can't be destroyed while it's bound. So these // bindings remain valid while the shader is alive. SBindingSlots BindingSlots; + + PS::StaticVector Scissors; }; CCanvas2D::CCanvas2D( @@ -186,6 +205,7 @@ CCanvas2D::CCanvas2D( CCanvas2D::~CCanvas2D() { Flush(); + ENSURE(m->Scissors.empty()); } void CCanvas2D::DrawLine(const std::vector& points, const float width, const CColor& color) @@ -448,6 +468,20 @@ void CCanvas2D::DrawText(CTextRenderer& textRenderer) m->DeviceCommandContext, m->Tech->GetShader(), m->TransformScale, m->Translation); } +void CCanvas2D::PushScissor(const CRect& scissor) +{ + ENSURE(!m->Scissors.full()); + m->Scissors.emplace_back(scissor); + m->ApplyScissors(); +} + +void CCanvas2D::PopScissor() +{ + ENSURE(!m->Scissors.empty()); + m->Scissors.pop_back(); + m->ApplyScissors(); +} + void CCanvas2D::Flush() { m->UnbindTech(); diff --git a/source/graphics/Canvas2D.h b/source/graphics/Canvas2D.h index 2eaf524efe..76dcf04301 100644 --- a/source/graphics/Canvas2D.h +++ b/source/graphics/Canvas2D.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -90,7 +90,37 @@ public: void DrawText(CTextRenderer& textRenderer); /** - * Unbinds all binded resources and clears caches. Frequent calls might + * Adds the scissor rect to a scissor stack. The only top scissor is + * applied. It's recommended to use as few nested scissors as possible. + */ + void PushScissor(const CRect& scissor); + + /** + * Removes the top scissor rect from a scissor stack. The stack must not be + * empty. + */ + void PopScissor(); + + class ScopedScissor + { + public: + ScopedScissor(CCanvas2D& canvas, const CRect& scissor) + : m_Canvas(canvas) + { + m_Canvas.PushScissor(scissor); + } + + ~ScopedScissor() + { + m_Canvas.PopScissor(); + } + + private: + CCanvas2D& m_Canvas; + }; + + /** + * Unbinds all bound resources and clears caches. Frequent calls might * affect performance. Useful to call a custom rendering code. */ void Flush(); diff --git a/source/gui/CGUIText.cpp b/source/gui/CGUIText.cpp index 9f3e72e0f7..fbf8f23c4d 100644 --- a/source/gui/CGUIText.cpp +++ b/source/gui/CGUIText.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -26,11 +26,9 @@ #include "gui/ObjectBases/IGUIObject.h" #include "gui/SettingTypes/CGUIString.h" #include "ps/CStrInternStatic.h" -#include "ps/VideoMode.h" -#include "renderer/backend/IDeviceCommandContext.h" -#include "renderer/Renderer.h" -#include +#include +#include extern int g_xres, g_yres; @@ -450,29 +448,13 @@ bool CGUIText::AssembleCalls( void CGUIText::Draw(CGUI& pGUI, CCanvas2D& canvas, const CGUIColor& DefaultColor, const CVector2D& pos, CRect clipping) const { - Renderer::Backend::IDeviceCommandContext* deviceCommandContext = - g_Renderer.GetDeviceCommandContext(); - const bool isClipped = clipping != CRect(); + std::optional scopedScissor; if (isClipped) { - // Make clipping rect as small as possible to prevent rounding errors - clipping.top = std::ceil(clipping.top); - clipping.bottom = std::floor(clipping.bottom); - clipping.left = std::ceil(clipping.left); - clipping.right = std::floor(clipping.right); - if (clipping.GetWidth() <= 0.0f || clipping.GetHeight() <= 0.0f) return; - - const float scale = g_VideoMode.GetScale(); - Renderer::Backend::IDeviceCommandContext::Rect scissorRect; - scissorRect.x = std::ceil(clipping.left * scale); - scissorRect.y = std::ceil(g_yres - clipping.bottom * scale); - scissorRect.width = std::floor(clipping.GetWidth() * scale); - scissorRect.height = std::floor(clipping.GetHeight() * scale); - // TODO: move scissors to CCanvas2D. - deviceCommandContext->SetScissors(1, &scissorRect); + scopedScissor.emplace(canvas, clipping); } CTextRenderer textRenderer; @@ -494,7 +476,4 @@ void CGUIText::Draw(CGUI& pGUI, CCanvas2D& canvas, const CGUIColor& DefaultColor for (const SSpriteCall& sc : m_SpriteCalls) pGUI.DrawSprite(sc.m_Sprite, canvas, sc.m_Area + pos); - - if (isClipped) - deviceCommandContext->SetScissors(0, nullptr); } diff --git a/source/gui/ObjectTypes/CInput.cpp b/source/gui/ObjectTypes/CInput.cpp index 4b87c702c1..5788c180c7 100644 --- a/source/gui/ObjectTypes/CInput.cpp +++ b/source/gui/ObjectTypes/CInput.cpp @@ -31,9 +31,6 @@ #include "ps/GameSetup/Config.h" #include "ps/Globals.h" #include "ps/Hotkey.h" -#include "ps/VideoMode.h" -#include "renderer/backend/IDeviceCommandContext.h" -#include "renderer/Renderer.h" #include @@ -1488,9 +1485,6 @@ void CInput::DrawContent(CCanvas2D& canvas) void CInput::Draw(CCanvas2D& canvas) { - Renderer::Backend::IDeviceCommandContext* deviceCommandContext = - g_Renderer.GetDeviceCommandContext(); - // We'll have to setup clipping manually, since we're doing the rendering manually. CRect cliparea(m_CachedActualSize); @@ -1513,20 +1507,11 @@ void CInput::Draw(CCanvas2D& canvas) { if (cliparea.GetWidth() <= 0.0f || cliparea.GetHeight() <= 0.0f) return; - const float scale = g_VideoMode.GetScale(); - Renderer::Backend::IDeviceCommandContext::Rect scissorRect; - scissorRect.x = cliparea.left * scale; - scissorRect.y = g_yres - cliparea.bottom * scale; - scissorRect.width = cliparea.GetWidth() * scale; - scissorRect.height = cliparea.GetHeight() * scale; - // TODO: move scissors to CCanvas2D. - deviceCommandContext->SetScissors(1, &scissorRect); + CCanvas2D::ScopedScissor scopedScissor(canvas, cliparea); + DrawContent(canvas); } - - DrawContent(canvas); - - if (isClipped) - deviceCommandContext->SetScissors(0, nullptr); + else + DrawContent(canvas); if (m_Caption->empty() && !m_PlaceholderText->GetRawString().empty()) DrawPlaceholderText(canvas, cliparea);