diff --git a/source/graphics/Canvas2D.cpp b/source/graphics/Canvas2D.cpp new file mode 100644 index 0000000000..c67f448e3c --- /dev/null +++ b/source/graphics/Canvas2D.cpp @@ -0,0 +1,64 @@ +/* Copyright (C) 2021 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "Canvas2D.h" + +#include "graphics/Color.h" +#include "graphics/ShaderManager.h" +#include "gui/GUIMatrix.h" +#include "maths/Vector2D.h" +#include "ps/CStrInternStatic.h" +#include "renderer/Renderer.h" + +void CCanvas2D::DrawLine(const std::vector& points, const float width, const CColor& color) +{ + std::vector vertices; + vertices.reserve(points.size() * 3); + for (const CVector2D& point : points) + { + vertices.emplace_back(point.X); + vertices.emplace_back(point.Y); + vertices.emplace_back(0.0f); + } + + // Setup the render state + CMatrix3D transform = GetDefaultGuiMatrix(); + CShaderDefines lineDefines; + CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_gui_solid, g_Renderer.GetSystemShaderDefines(), lineDefines); + tech->BeginPass(); + CShaderProgramPtr shader = tech->GetShader(); + + shader->Uniform(str_transform, transform); + shader->Uniform(str_color, color ); + shader->VertexPointer(3, GL_FLOAT, 0, &vertices[0]); + shader->AssertPointersBound(); + +#if !CONFIG2_GLES + glEnable(GL_LINE_SMOOTH); +#endif + glLineWidth(width); + if (!g_Renderer.DoSkipSubmit()) + glDrawArrays(GL_LINE_STRIP, 0, vertices.size() / 3); + glLineWidth(1.0f); +#if !CONFIG2_GLES + glDisable(GL_LINE_SMOOTH); +#endif + + tech->EndPass(); +} diff --git a/source/graphics/Canvas2D.h b/source/graphics/Canvas2D.h new file mode 100644 index 0000000000..40a5fc74de --- /dev/null +++ b/source/graphics/Canvas2D.h @@ -0,0 +1,35 @@ +/* Copyright (C) 2021 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_CANVAS2D +#define INCLUDED_CANVAS2D + +#include "maths/Vector2D.h" + +#include + +struct CColor; + +// Encapsulates 2D drawing functionality to hide and optimize +// low level API calls. +class CCanvas2D +{ +public: + void DrawLine(const std::vector& points, const float width, const CColor& color); +}; + +#endif // INCLUDED_CANVAS2D diff --git a/source/gui/CGUI.cpp b/source/gui/CGUI.cpp index 6a55d21a99..a9efc2b91c 100644 --- a/source/gui/CGUI.cpp +++ b/source/gui/CGUI.cpp @@ -19,6 +19,7 @@ #include "CGUI.h" +#include "graphics/Canvas2D.h" #include "gui/IGUIScrollBar.h" #include "gui/ObjectBases/IGUIObject.h" #include "gui/ObjectTypes/CGUIDummyObject.h" @@ -343,8 +344,10 @@ void CGUI::Draw() return visibleObject1.bufferedZ < visibleObject2.bufferedZ; return visibleObject1.index < visibleObject2.index; }); + + CCanvas2D canvas; for (const VisibleObject& visibleObject : visibleObjects) - visibleObject.object->Draw(); + visibleObject.object->Draw(canvas); } void CGUI::DrawSprite(const CGUISpriteInstance& Sprite, const CRect& Rect, const CRect& UNUSED(Clipping)) diff --git a/source/gui/ObjectBases/IGUIObject.h b/source/gui/ObjectBases/IGUIObject.h index 4fcad61c0b..6c47dfc4d3 100644 --- a/source/gui/ObjectBases/IGUIObject.h +++ b/source/gui/ObjectBases/IGUIObject.h @@ -37,6 +37,7 @@ #include #include +class CCanvas2D; class CGUI; class CGUISize; class IGUIObject; @@ -264,7 +265,7 @@ protected: /** * Draws the object. */ - virtual void Draw() = 0; + virtual void Draw(CCanvas2D& canvas) = 0; /** * Some objects need to be able to pre-emptively process SDL_Event_. diff --git a/source/gui/ObjectTypes/CButton.cpp b/source/gui/ObjectTypes/CButton.cpp index 2593c59797..fdd8d99b59 100644 --- a/source/gui/ObjectTypes/CButton.cpp +++ b/source/gui/ObjectTypes/CButton.cpp @@ -80,7 +80,7 @@ void CButton::HandleMessage(SGUIMessage& Message) IGUITextOwner::HandleMessage(Message); } -void CButton::Draw() +void CButton::Draw(CCanvas2D& UNUSED(canvas)) { m_pGUI.DrawSprite( GetButtonSprite(m_Sprite, m_SpriteOver, m_SpritePressed, m_SpriteDisabled), diff --git a/source/gui/ObjectTypes/CButton.h b/source/gui/ObjectTypes/CButton.h index 1604be98c2..478a9788f4 100644 --- a/source/gui/ObjectTypes/CButton.h +++ b/source/gui/ObjectTypes/CButton.h @@ -56,7 +56,7 @@ public: /** * Draws the Button */ - virtual void Draw(); + virtual void Draw(CCanvas2D& canvas); /** * @see IGUIObject#IsMouseOver() diff --git a/source/gui/ObjectTypes/CChart.cpp b/source/gui/ObjectTypes/CChart.cpp index 5c9c4893c9..34538aa18a 100644 --- a/source/gui/ObjectTypes/CChart.cpp +++ b/source/gui/ObjectTypes/CChart.cpp @@ -19,6 +19,7 @@ #include "CChart.h" +#include "graphics/Canvas2D.h" #include "graphics/ShaderManager.h" #include "gui/GUIMatrix.h" #include "gui/SettingTypes/CGUIList.h" @@ -65,24 +66,6 @@ void CChart::HandleMessage(SGUIMessage& Message) UpdateSeries(); } -void CChart::DrawLine(const CShaderProgramPtr& shader, const CGUIColor& color, const std::vector& vertices) const -{ - shader->Uniform(str_color, color); - shader->VertexPointer(3, GL_FLOAT, 0, &vertices[0]); - shader->AssertPointersBound(); - -#if !CONFIG2_GLES - glEnable(GL_LINE_SMOOTH); -#endif - glLineWidth(1.1f); - if (!g_Renderer.DoSkipSubmit()) - glDrawArrays(GL_LINE_STRIP, 0, vertices.size() / 3); - glLineWidth(1.0f); -#if !CONFIG2_GLES - glDisable(GL_LINE_SMOOTH); -#endif -} - void CChart::DrawTriangleStrip(const CShaderProgramPtr& shader, const CGUIColor& color, const std::vector& vertices) const { shader->Uniform(str_color, color); @@ -109,7 +92,7 @@ void CChart::DrawAxes(const CShaderProgramPtr& shader) const DrawTriangleStrip(shader, m_AxisColor, vertices); } -void CChart::Draw() +void CChart::Draw(CCanvas2D& canvas) { PROFILE3("render chart"); @@ -120,6 +103,32 @@ void CChart::Draw() const float width = rect.GetWidth(); const float height = rect.GetHeight(); + CVector2D scale(width / (m_RightTop.X - m_LeftBottom.X), height / (m_RightTop.Y - m_LeftBottom.Y)); + std::vector linePoints; + for (const CChartData& data : m_Series) + { + if (data.m_Points.empty()) + continue; + + linePoints.clear(); + for (const CVector2D& point : data.m_Points) + { + if (fabs(point.X) != std::numeric_limits::infinity() && fabs(point.Y) != std::numeric_limits::infinity()) + { + linePoints.emplace_back( + rect.left + (point.X - m_LeftBottom.X) * scale.X, + rect.bottom - (point.Y - m_LeftBottom.Y) * scale.Y); + } + else + { + canvas.DrawLine(linePoints, 1.1f, data.m_Color); + linePoints.clear(); + } + } + if (!linePoints.empty()) + canvas.DrawLine(linePoints, 1.1f, data.m_Color); + } + // Setup the render state CMatrix3D transform = GetDefaultGuiMatrix(); CShaderDefines lineDefines; @@ -128,31 +137,6 @@ void CChart::Draw() CShaderProgramPtr shader = tech->GetShader(); shader->Uniform(str_transform, transform); - CVector2D scale(width / (m_RightTop.X - m_LeftBottom.X), height / (m_RightTop.Y - m_LeftBottom.Y)); - for (const CChartData& data : m_Series) - { - if (data.m_Points.empty()) - continue; - - std::vector vertices; - for (const CVector2D& point : data.m_Points) - { - if (fabs(point.X) != std::numeric_limits::infinity() && fabs(point.Y) != std::numeric_limits::infinity()) - { - vertices.push_back(rect.left + (point.X - m_LeftBottom.X) * scale.X); - vertices.push_back(rect.bottom - (point.Y - m_LeftBottom.Y) * scale.Y); - vertices.push_back(0.0f); - } - else - { - DrawLine(shader, data.m_Color, vertices); - vertices.clear(); - } - } - if (!vertices.empty()) - DrawLine(shader, data.m_Color, vertices); - } - if (m_AxisWidth > 0) DrawAxes(shader); diff --git a/source/gui/ObjectTypes/CChart.h b/source/gui/ObjectTypes/CChart.h index 73db31f2ea..d6a8d9e243 100644 --- a/source/gui/ObjectTypes/CChart.h +++ b/source/gui/ObjectTypes/CChart.h @@ -65,7 +65,7 @@ protected: /** * Draws the Chart */ - virtual void Draw(); + virtual void Draw(CCanvas2D& canvas); virtual CRect GetChartRect() const; diff --git a/source/gui/ObjectTypes/CCheckBox.cpp b/source/gui/ObjectTypes/CCheckBox.cpp index d4fd8de039..0867112b50 100644 --- a/source/gui/ObjectTypes/CCheckBox.cpp +++ b/source/gui/ObjectTypes/CCheckBox.cpp @@ -64,7 +64,7 @@ void CCheckBox::HandleMessage(SGUIMessage& Message) } } -void CCheckBox::Draw() +void CCheckBox::Draw(CCanvas2D& UNUSED(canvas)) { m_pGUI.DrawSprite( m_Checked ? diff --git a/source/gui/ObjectTypes/CCheckBox.h b/source/gui/ObjectTypes/CCheckBox.h index f674c8fd21..2267f44fcc 100644 --- a/source/gui/ObjectTypes/CCheckBox.h +++ b/source/gui/ObjectTypes/CCheckBox.h @@ -43,7 +43,7 @@ public: /** * Draws the control */ - virtual void Draw(); + virtual void Draw(CCanvas2D& canvas); protected: // Settings diff --git a/source/gui/ObjectTypes/CDropDown.cpp b/source/gui/ObjectTypes/CDropDown.cpp index 2332786be4..a7861d86bd 100644 --- a/source/gui/ObjectTypes/CDropDown.cpp +++ b/source/gui/ObjectTypes/CDropDown.cpp @@ -420,7 +420,7 @@ bool CDropDown::IsMouseOver() const return m_CachedActualSize.PointInside(m_pGUI.GetMousePos()); } -void CDropDown::Draw() +void CDropDown::Draw(CCanvas2D& UNUSED(canvas)) { const CGUISpriteInstance& sprite = m_Enabled ? m_Sprite : m_SpriteDisabled; const CGUISpriteInstance& spriteOverlay = m_Enabled ? m_SpriteOverlay : m_SpriteOverlayDisabled; diff --git a/source/gui/ObjectTypes/CDropDown.h b/source/gui/ObjectTypes/CDropDown.h index 55e69c515b..42d2b07e6a 100644 --- a/source/gui/ObjectTypes/CDropDown.h +++ b/source/gui/ObjectTypes/CDropDown.h @@ -65,7 +65,7 @@ public: /** * Draws the Button */ - virtual void Draw(); + virtual void Draw(CCanvas2D& canvas); // This is one of the few classes we actually need to redefine this function // this is because the size of the control changes whether it is open diff --git a/source/gui/ObjectTypes/CGUIDummyObject.h b/source/gui/ObjectTypes/CGUIDummyObject.h index be4f306978..24f353c196 100644 --- a/source/gui/ObjectTypes/CGUIDummyObject.h +++ b/source/gui/ObjectTypes/CGUIDummyObject.h @@ -35,7 +35,7 @@ class CGUIDummyObject : public IGUIObject public: CGUIDummyObject(CGUI& pGUI) : IGUIObject(pGUI) {} - virtual void Draw() {} + virtual void Draw(CCanvas2D& UNUSED(canvas)) {} /** * Empty can never be hovered. It is only a category. diff --git a/source/gui/ObjectTypes/CHotkeyPicker.h b/source/gui/ObjectTypes/CHotkeyPicker.h index b00aca751b..401c98db95 100644 --- a/source/gui/ObjectTypes/CHotkeyPicker.h +++ b/source/gui/ObjectTypes/CHotkeyPicker.h @@ -43,7 +43,7 @@ public: virtual ~CHotkeyPicker(); // Do nothing. - virtual void Draw() {}; + virtual void Draw(CCanvas2D& UNUSED(canvas)) {}; // Checks if the timer has passed and we need to fire a "combination" event. virtual void Tick(); diff --git a/source/gui/ObjectTypes/CImage.cpp b/source/gui/ObjectTypes/CImage.cpp index 5c9ffd382d..5fd54ed1c6 100644 --- a/source/gui/ObjectTypes/CImage.cpp +++ b/source/gui/ObjectTypes/CImage.cpp @@ -31,7 +31,7 @@ CImage::~CImage() { } -void CImage::Draw() +void CImage::Draw(CCanvas2D& UNUSED(canvas)) { m_pGUI.DrawSprite(m_Sprite, m_CachedActualSize); } diff --git a/source/gui/ObjectTypes/CImage.h b/source/gui/ObjectTypes/CImage.h index cd02e4082d..f7fcc3cd1d 100644 --- a/source/gui/ObjectTypes/CImage.h +++ b/source/gui/ObjectTypes/CImage.h @@ -43,7 +43,7 @@ protected: /** * Draws the Image */ - virtual void Draw(); + virtual void Draw(CCanvas2D& canvas); CGUISimpleSetting m_Sprite; }; diff --git a/source/gui/ObjectTypes/CInput.cpp b/source/gui/ObjectTypes/CInput.cpp index 90edfb1b8e..25684cbebf 100644 --- a/source/gui/ObjectTypes/CInput.cpp +++ b/source/gui/ObjectTypes/CInput.cpp @@ -1187,7 +1187,7 @@ void CInput::UpdateCachedSize() m_GeneratedPlaceholderTextValid = false; } -void CInput::Draw() +void CInput::Draw(CCanvas2D& UNUSED(canvas)) { if (m_CursorBlinkRate > 0.0) { diff --git a/source/gui/ObjectTypes/CInput.h b/source/gui/ObjectTypes/CInput.h index f4e2245f23..f3f078cbe7 100644 --- a/source/gui/ObjectTypes/CInput.h +++ b/source/gui/ObjectTypes/CInput.h @@ -95,7 +95,7 @@ protected: /** * Draws the Text */ - virtual void Draw(); + virtual void Draw(CCanvas2D& canvas); /** * Calculate m_CharacterPosition diff --git a/source/gui/ObjectTypes/CList.cpp b/source/gui/ObjectTypes/CList.cpp index f98f786325..8aa2613380 100644 --- a/source/gui/ObjectTypes/CList.cpp +++ b/source/gui/ObjectTypes/CList.cpp @@ -299,7 +299,7 @@ InReaction CList::ManuallyHandleKeys(const SDL_Event_* ev) return result; } -void CList::Draw() +void CList::Draw(CCanvas2D& UNUSED(canvas)) { DrawList(m_Selected, m_Sprite, m_SpriteOverlay, m_SpriteSelectArea, m_SpriteSelectAreaOverlay, m_TextColor); } diff --git a/source/gui/ObjectTypes/CList.h b/source/gui/ObjectTypes/CList.h index 7b369c42f1..9bb4d7fedd 100644 --- a/source/gui/ObjectTypes/CList.h +++ b/source/gui/ObjectTypes/CList.h @@ -84,7 +84,7 @@ protected: /** * Draws the List box */ - virtual void Draw(); + virtual void Draw(CCanvas2D& canvas); virtual void CreateJSObject(); diff --git a/source/gui/ObjectTypes/CMiniMap.cpp b/source/gui/ObjectTypes/CMiniMap.cpp index ea08fd216a..a89ee87d6e 100644 --- a/source/gui/ObjectTypes/CMiniMap.cpp +++ b/source/gui/ObjectTypes/CMiniMap.cpp @@ -422,7 +422,7 @@ void CMiniMap::DrawTexture(CShaderProgramPtr shader, float coordMax, float angle // most of the time, updating the framebuffer twice a frame. // Here it updates as ping-pong either texture or vertex array each sec to lower gpu stalling // (those operations cause a gpu sync, which slows down the way gpu works) -void CMiniMap::Draw() +void CMiniMap::Draw(CCanvas2D& UNUSED(canvas)) { PROFILE3("render minimap"); diff --git a/source/gui/ObjectTypes/CMiniMap.h b/source/gui/ObjectTypes/CMiniMap.h index 065a3b1390..cb25246647 100644 --- a/source/gui/ObjectTypes/CMiniMap.h +++ b/source/gui/ObjectTypes/CMiniMap.h @@ -39,7 +39,7 @@ public: static float GetShallowPassageHeight(); protected: - virtual void Draw(); + virtual void Draw(CCanvas2D& canvas); /** * @see IGUIObject#HandleMessage() diff --git a/source/gui/ObjectTypes/CProgressBar.cpp b/source/gui/ObjectTypes/CProgressBar.cpp index e45b18bd99..f8abee95ba 100644 --- a/source/gui/ObjectTypes/CProgressBar.cpp +++ b/source/gui/ObjectTypes/CProgressBar.cpp @@ -53,7 +53,7 @@ void CProgressBar::HandleMessage(SGUIMessage& Message) } } -void CProgressBar::Draw() +void CProgressBar::Draw(CCanvas2D& UNUSED(canvas)) { m_pGUI.DrawSprite(m_SpriteBackground, m_CachedActualSize); diff --git a/source/gui/ObjectTypes/CProgressBar.h b/source/gui/ObjectTypes/CProgressBar.h index 61cfd3d457..8fb91654e0 100644 --- a/source/gui/ObjectTypes/CProgressBar.h +++ b/source/gui/ObjectTypes/CProgressBar.h @@ -36,7 +36,7 @@ protected: /** * Draws the progress bar */ - virtual void Draw(); + virtual void Draw(CCanvas2D& canvas); /** * @see IGUIObject#HandleMessage() diff --git a/source/gui/ObjectTypes/CSlider.cpp b/source/gui/ObjectTypes/CSlider.cpp index c7be28b23b..1419f56554 100644 --- a/source/gui/ObjectTypes/CSlider.cpp +++ b/source/gui/ObjectTypes/CSlider.cpp @@ -102,7 +102,7 @@ void CSlider::HandleMessage(SGUIMessage& Message) } } -void CSlider::Draw() +void CSlider::Draw(CCanvas2D& UNUSED(canvas)) { CRect slider_line(m_CachedActualSize); slider_line.left += m_ButtonSide / 2.0f; diff --git a/source/gui/ObjectTypes/CSlider.h b/source/gui/ObjectTypes/CSlider.h index 5d81264c49..05f98637da 100644 --- a/source/gui/ObjectTypes/CSlider.h +++ b/source/gui/ObjectTypes/CSlider.h @@ -44,7 +44,7 @@ protected: */ virtual void HandleMessage(SGUIMessage& Message); - virtual void Draw(); + virtual void Draw(CCanvas2D& canvas); /** * Change settings and send the script event diff --git a/source/gui/ObjectTypes/CText.cpp b/source/gui/ObjectTypes/CText.cpp index 344eed5eac..cf6347aa91 100644 --- a/source/gui/ObjectTypes/CText.cpp +++ b/source/gui/ObjectTypes/CText.cpp @@ -183,7 +183,7 @@ void CText::HandleMessage(SGUIMessage& Message) IGUITextOwner::HandleMessage(Message); } -void CText::Draw() +void CText::Draw(CCanvas2D& UNUSED(canvas)) { m_pGUI.DrawSprite(m_Sprite, m_CachedActualSize); diff --git a/source/gui/ObjectTypes/CText.h b/source/gui/ObjectTypes/CText.h index 745eeb5b89..d91ab18745 100644 --- a/source/gui/ObjectTypes/CText.h +++ b/source/gui/ObjectTypes/CText.h @@ -65,7 +65,7 @@ protected: /** * Draws the Text */ - virtual void Draw(); + virtual void Draw(CCanvas2D& canvas); virtual void CreateJSObject(); diff --git a/source/gui/ObjectTypes/CTooltip.cpp b/source/gui/ObjectTypes/CTooltip.cpp index eb7184ee54..3d8b4f5317 100644 --- a/source/gui/ObjectTypes/CTooltip.cpp +++ b/source/gui/ObjectTypes/CTooltip.cpp @@ -131,7 +131,7 @@ void CTooltip::HandleMessage(SGUIMessage& Message) IGUITextOwner::HandleMessage(Message); } -void CTooltip::Draw() +void CTooltip::Draw(CCanvas2D& UNUSED(canvas)) { // Normally IGUITextOwner will handle this updating but since SetupText can modify the position // we need to call it now *before* we do the rest of the drawing diff --git a/source/gui/ObjectTypes/CTooltip.h b/source/gui/ObjectTypes/CTooltip.h index 854f6ff73e..7cddcad972 100644 --- a/source/gui/ObjectTypes/CTooltip.h +++ b/source/gui/ObjectTypes/CTooltip.h @@ -53,7 +53,7 @@ protected: */ virtual void HandleMessage(SGUIMessage& Message); - virtual void Draw(); + virtual void Draw(CCanvas2D& canvas); virtual float GetBufferedZ() const;