From 8a33c932c4c84d95851dec6b6efeab5bc902b966 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Wed, 1 Jul 2026 15:40:52 +0200 Subject: [PATCH 01/40] Draw UI with OpenGL, delete Surf_Display Keep small surface per UI component that is drawn with OpenGL Avoids big 4K penalty while keeping change small --- CGame.cpp | 3 -- CGame.h | 6 ++-- CGame_Init.cpp | 5 --- CGame_Render.cpp | 78 +++++++++++++++++++++++++++-------------- CIO/CControlContainer.h | 11 ++++-- CIO/CMinimapWindow.cpp | 23 ++++++++++++ CIO/CMinimapWindow.h | 15 ++++++++ CIO/CWindow.cpp | 20 ++++++----- CIO/CWindow.h | 5 +-- Texture.cpp | 14 ++------ Texture.h | 12 +++++++ callbacks.cpp | 29 +++++++-------- 12 files changed, 143 insertions(+), 78 deletions(-) create mode 100644 CIO/CMinimapWindow.cpp create mode 100644 CIO/CMinimapWindow.h diff --git a/CGame.cpp b/CGame.cpp index 18f90ed..d322c63 100644 --- a/CGame.cpp +++ b/CGame.cpp @@ -77,9 +77,6 @@ int CGame::Execute() void CGame::RenderPresent() { - displayTexture_.upload(Surf_Display->pixels); - displayTexture_.Draw(Rect(0, 0, GameResolution.x, GameResolution.y)); - const auto& cursorImg = Cursor.clicked ? (Cursor.button.right ? cross_ : cursorClicked_) : cursor_; cursorImg.Draw(Cursor.pos); diff --git a/CGame.h b/CGame.h index f4a78e5..249b4ac 100644 --- a/CGame.h +++ b/CGame.h @@ -6,7 +6,6 @@ #pragma once #include "CIO/CFont.h" -#include "SdlSurface.h" #include "Texture.h" #include #include @@ -27,8 +26,6 @@ class CGame bool Running; bool showLoadScreen; - SdlSurface Surf_Display; - Texture displayTexture_; SDL_GLContext glContext_ = nullptr; SdlWindow window_; @@ -52,6 +49,8 @@ class CGame Texture cursor_; Texture cursorClicked_; Texture cross_; + Texture fpsTex_; ///< Texture for the FPS counter + Texture mapTex_; ///< Texture for the map/terrain (Surf_Map may be 8-bit) // structure for mouse cursor struct @@ -111,6 +110,5 @@ class CGame CMap* getMapObj(); void delMapObj(); void enterEditor(const boost::filesystem::path& filepath); - SDL_Surface* getDisplaySurface() const { return Surf_Display.get(); }; auto getRes() const { return GameResolution; } }; diff --git a/CGame_Init.cpp b/CGame_Init.cpp index 7f437db..8d5617c 100644 --- a/CGame_Init.cpp +++ b/CGame_Init.cpp @@ -38,8 +38,6 @@ bool CGame::CreateWindow() SDL_ShowWindow(window_.get()); ApplyWindowChanges(); - if(!displayTexture_.isValid() || !Surf_Display) - return false; SetAppIcon(); @@ -125,9 +123,6 @@ void CGame::UpdateDisplaySize(const Extent& newSize) appliedResolution_ = GameResolution; appliedFullscreen_ = fullscreen; - Surf_Display = makeRGBSurface(GameResolution.x, GameResolution.y, true); - displayTexture_.createEmpty(GameResolution); - setGLViewport(); for(auto& menu : Menus) { diff --git a/CGame_Render.cpp b/CGame_Render.cpp index 93da104..1f5dd34 100644 --- a/CGame_Render.cpp +++ b/CGame_Render.cpp @@ -40,7 +40,6 @@ void CGame::SetAppIcon() void CGame::Render() { glClear(GL_COLOR_BUFFER_BIT); - SDL_FillRect(Surf_Display.get(), nullptr, SDL_MapRGBA(Surf_Display->format, 0, 0, 0, 0)); // if the S2 loading screen is shown, render only this until user clicks a mouse button if(showLoadScreen) @@ -53,33 +52,35 @@ void CGame::Render() // render the map if active if(MapObj && MapObj->isActive()) { - CSurface::Draw(Surf_Display, MapObj->getSurface(), 0, 0); - std::array textBuffer; - // text for x and y of vertex (shown in upper left corner) - std::snprintf(textBuffer.data(), textBuffer.size(), "%d %d", MapObj->getVertexX(), MapObj->getVertexY()); - CFont::writeText(Surf_Display, textBuffer.data(), Position(20, 20)); - // text for MinReduceHeight and MaxRaiseHeight - std::snprintf(textBuffer.data(), textBuffer.size(), - "min. height: %#04x/0x3C max. height: %#04x/0x3C NormalNull: 0x0A", - MapObj->getMinReduceHeight(), MapObj->getMaxRaiseHeight()); - CFont::writeText(Surf_Display, textBuffer.data(), Position(100, 20)); - // text for MovementLocked - if(MapObj->isHorizontalMovementLocked() && MapObj->isVerticalMovementLocked()) - CFont::writeText(Surf_Display, "Movement locked (F9 or F10 to unlock)", Position(20, 40), FontSize::Large, - FontColor::Orange); - else if(MapObj->isHorizontalMovementLocked()) - CFont::writeText(Surf_Display, "Horizontal movement locked (F9 to unlock)", Position(20, 40), - FontSize::Large, FontColor::Orange); - else if(MapObj->isVerticalMovementLocked()) - CFont::writeText(Surf_Display, "Vertical movement locked (F10 to unlock)", Position(20, 40), - FontSize::Large, FontColor::Orange); + if(auto* mapSurf = MapObj->getSurface()) + { + std::array textBuffer; + std::snprintf(textBuffer.data(), textBuffer.size(), "%d %d", MapObj->getVertexX(), MapObj->getVertexY()); + CFont::writeText(mapSurf, textBuffer.data(), 20, 20); + std::snprintf(textBuffer.data(), textBuffer.size(), + "min. height: %#04x/0x3C max. height: %#04x/0x3C NormalNull: 0x0A", + MapObj->getMinReduceHeight(), MapObj->getMaxRaiseHeight()); + CFont::writeText(mapSurf, textBuffer.data(), 100, 20); + if(MapObj->isHorizontalMovementLocked() && MapObj->isVerticalMovementLocked()) + CFont::writeText(mapSurf, "Movement locked (F9 or F10 to unlock)", 20, 40, FontSize::Large, + FontColor::Orange); + else if(MapObj->isHorizontalMovementLocked()) + CFont::writeText(mapSurf, "Horizontal movement locked (F9 to unlock)", 20, 40, FontSize::Large, + FontColor::Orange); + else if(MapObj->isVerticalMovementLocked()) + CFont::writeText(mapSurf, "Vertical movement locked (F10 to unlock)", 20, 40, FontSize::Large, + FontColor::Orange); + + mapTex_.load(mapSurf); + mapTex_.Draw(Rect(0, 0, GameResolution.x, GameResolution.y)); + } } // render active menus for(auto& Menu : Menus) { if(Menu->isActive()) - CSurface::Draw(Surf_Display, Menu->getSurface(), 0, 0); + Menu->getTexture().Draw(Rect(0, 0, GameResolution.x, GameResolution.y)); } // render windows ordered by priority @@ -96,7 +97,7 @@ void CGame::Render() for(auto& Window : Windows) { if(Window->getPriority() == actualPriority) - CSurface::Draw(Surf_Display, Window->getSurface(), Window->getX(), Window->getY()); + Window->getTexture().Draw(Position(Window->getX(), Window->getY())); } } @@ -105,7 +106,6 @@ void CGame::Render() #endif ++framesPassedSinceLastFps; - const auto curTicks = SDL_GetTicks(); const auto diffTicks = curTicks - lastFpsTick; if(diffTicks > 1000) @@ -114,9 +114,35 @@ void CGame::Render() framesPassedSinceLastFps = 0; lastFpsTick = curTicks; } - CSurface::Draw(Surf_Display, lastFps.getSurface(), 0, 0); + { + if(auto* fpsSurf = lastFps.getSurface()) + { + fpsTex_.load(fpsSurf); + glBindTexture(GL_TEXTURE_2D, fpsTex_.getHandle()); + glBegin(GL_QUADS); + glTexCoord2f(0, 0); + glVertex2i(0, 0); + glTexCoord2f(1, 0); + glVertex2i(fpsSurf->w, 0); + glTexCoord2f(1, 1); + glVertex2i(fpsSurf->w, fpsSurf->h); + glTexCoord2f(0, 1); + glVertex2i(0, fpsSurf->h); + glEnd(); + } + } - RenderPresent(); + // ---- 5. Cursor on top of everything ---- + { + const auto& cursorImg = Cursor.clicked ? (Cursor.button.right ? cross_ : cursorClicked_) : cursor_; + cursorImg.Draw(Cursor.pos); + } + + SDL_GL_SwapWindow(window_.get()); + +#ifdef _ADMINMODE + FrameCounter++; +#endif if(msWait) SDL_Delay(msWait); diff --git a/CIO/CControlContainer.h b/CIO/CControlContainer.h index dacc91f..7802e61 100644 --- a/CIO/CControlContainer.h +++ b/CIO/CControlContainer.h @@ -5,6 +5,7 @@ #pragma once +#include "../Texture.h" #include "defines.h" #include #include @@ -45,6 +46,7 @@ class CControlContainer protected: SdlSurface surface; bool needRender = true; + Texture surfaceTex_; ///< Texture for this container's surface (used by CWindow) void renderElements(); auto& getTextFields() { return textfields; } @@ -54,17 +56,20 @@ class CControlContainer public: CControlContainer(int pic_background); CControlContainer(int pic_background, Extent borderBeginSize, Extent borderEndSize); - ~CControlContainer() noexcept; + virtual ~CControlContainer() noexcept; // Access Extent getBorderSize() const { return borderBeginSize + borderEndSize; } void setBackgroundPicture(int pic_background); virtual void setMouseData(SDL_MouseMotionEvent motion); virtual void setMouseData(SDL_MouseButtonEvent button); void setKeyboardData(const SDL_KeyboardEvent& key); - SDL_Surface* getSurface() + /// Get the texture for this container's rendered content. + const Texture& getTexture() { render(); - return surface.get(); + if(surface) + surfaceTex_.load(surface.get()); + return surfaceTex_; } void setWaste() { waste = true; } bool isWaste() const { return waste; } diff --git a/CIO/CMinimapWindow.cpp b/CIO/CMinimapWindow.cpp new file mode 100644 index 0000000..0ecbbd7 --- /dev/null +++ b/CIO/CMinimapWindow.cpp @@ -0,0 +1,23 @@ +// Copyright (C) 2026 - 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "CMinimapWindow.h" +#include "../CGame.h" +#include "../CMap.h" +#include "../globals.h" + +bool CMinimapWindow::render() +{ + // Always re-render: the minimap terrain overlay may have changed + needRender = true; + // Draw window chrome (frame, title, close button, background, child elements) + CWindow::render(); + // Draw minimap terrain overlay on top of the chrome + if(surface) + { + if(auto* map = global::s2->getMapObj()) + map->drawMinimap(surface.get()); + } + return true; +} diff --git a/CIO/CMinimapWindow.h b/CIO/CMinimapWindow.h new file mode 100644 index 0000000..2d16dd6 --- /dev/null +++ b/CIO/CMinimapWindow.h @@ -0,0 +1,15 @@ +// Copyright (C) 2026 - 2026 Settlers Freaks +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "CWindow.h" + +class CMinimapWindow final : public CWindow +{ + bool render() final; + +public: + using CWindow::CWindow; +}; diff --git a/CIO/CWindow.cpp b/CIO/CWindow.cpp index 66146a5..ec4fa36 100644 --- a/CIO/CWindow.cpp +++ b/CIO/CWindow.cpp @@ -42,8 +42,10 @@ CWindow::CWindow(void callback(int), int callbackQuitMessage, Position pos, Exte static Position makePos(WindowPos pos, Extent size) { if(pos == WindowPos::Center) - return Position(global::s2->getDisplaySurface()->w, global::s2->getDisplaySurface()->h) / 2 - size / 2; - else + { + const auto res = global::s2->getRes(); + return Position(res.x / 2, res.y / 2) - size / 2; + } else return {}; } @@ -91,12 +93,14 @@ void CWindow::setMouseData(SDL_MouseMotionEvent motion) // make sure to not move the window outside the display surface if(x_ < 0) x_ = 0; - if(x_ + w_ >= global::s2->getDisplaySurface()->w) //-V807 - x_ = global::s2->getDisplaySurface()->w - w_ - 1; - if(y_ < 0) - y_ = 0; - if(y_ + h_ >= global::s2->getDisplaySurface()->h) - y_ = global::s2->getDisplaySurface()->h - h_ - 1; + { + const auto res = global::s2->getRes(); + const int resW = res.x, resH = res.y; + if(x_ + w_ >= resW) //-V807 + x_ = resW - w_ - 1; + if(y_ + h_ >= resH) + y_ = resH - h_ - 1; + } } // check whats happen to the close button diff --git a/CIO/CWindow.h b/CIO/CWindow.h index db92045..2faf97e 100644 --- a/CIO/CWindow.h +++ b/CIO/CWindow.h @@ -12,7 +12,7 @@ enum class WindowPos Center }; -class CWindow final : public CControlContainer +class CWindow : public CControlContainer { friend class CDebug; @@ -43,7 +43,8 @@ class CWindow final : public CControlContainer void (*callback_)(int); int callbackQuitMessage; - bool render() final; +protected: + bool render() override; public: CWindow(void callback(int), int callbackQuitMessage, Position pos, Extent size, const char* title = nullptr, diff --git a/Texture.cpp b/Texture.cpp index 5ff6a56..5064573 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -98,21 +98,13 @@ bool Texture::load(SDL_Surface* surface, bool filterLinear) return true; } - // 32-bit surface: convert to destination format (BGRA), force full opacity + // 32-bit surface: convert to destination format (BGRA). + // SDL_ConvertSurfaceFormat preserves color keys and alpha, so + // transparent pixels keep alpha=0 and text anti-aliasing is retained. SDL_Surface* converted = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ARGB8888, 0); if(!converted) return false; - // Force alpha to opaque (LBM palette entries often have alpha=0) - SDL_LockSurface(converted); - for(int y = 0; y < converted->h; y++) - { - auto* row = (Uint32*)((Uint8*)converted->pixels + y * converted->pitch); - for(int x = 0; x < converted->w; x++) - row[x] |= 0xFF000000u; // set alpha bits - } - SDL_UnlockSurface(converted); - load(converted->pixels, Extent(converted->w, converted->h), filterLinear); SDL_FreeSurface(converted); return true; diff --git a/Texture.h b/Texture.h index 5c19b8c..2d6c26c 100644 --- a/Texture.h +++ b/Texture.h @@ -38,6 +38,18 @@ class Texture /// Draw the texture at native size at the given position. void Draw(Position pos) const; + /// Convenience overload for callers using separate x/y. + void Draw(int x, int y) const { Draw(Position(x, y)); } + + /// Returns the raw GL texture name (for use with glBindTexture). + unsigned getHandle() const { return texture_; } + + /// Width in pixels. + int getWidth() const { return size_.x; } + + /// Height in pixels. + int getHeight() const { return size_.y; } + /// Returns true if the texture has been created. bool isValid() const { return texture_ != 0; } diff --git a/callbacks.cpp b/callbacks.cpp index 6e16659..38ec75b 100644 --- a/callbacks.cpp +++ b/callbacks.cpp @@ -10,6 +10,7 @@ #include "CIO/CFile.h" #include "CIO/CFont.h" #include "CIO/CMenu.h" +#include "CIO/CMinimapWindow.h" #include "CIO/CPicture.h" #include "CIO/CSelectBox.h" #include "CIO/CTextfield.h" @@ -19,6 +20,7 @@ #include "globals.h" #include "helpers/format.hpp" #include "s25util/strAlgos.h" +#include #include #include #include @@ -51,9 +53,12 @@ void callback::PleaseWait(int Param) WNDWait->addText("Please wait ...", Position(10, 10), FontSize::Large); // we need to render this window NOW, cause the render loop will do it too late (when the operation // is done and we don't need the "Please wait"-window anymore) - CSurface::Draw(global::s2->getDisplaySurface(), WNDWait->getSurface(), - global::s2->getDisplaySurface()->w / 2 - 106, global::s2->getDisplaySurface()->h / 2 - 35); - global::s2->RenderPresent(); + { + const auto res = global::s2->getRes(); + glClear(GL_COLOR_BUFFER_BIT); + WNDWait->getTexture().Draw(Position(res.x / 2 - 106, res.y / 2 - 35)); + global::s2->RenderPresent(); + } break; case CALL_FROM_GAMELOOP: // This window gives a "Please Wait"-string, so it is shown while there is an intensive @@ -2820,7 +2825,6 @@ void callback::MinimapMenu(int Param) { static CWindow* WNDMinimap = nullptr; static CMap* MapObj = nullptr; - static SDL_Surface* WndSurface = nullptr; static int scaleNum = 1; // only in case INITIALIZING_CALL needed to create the window int width; @@ -2849,22 +2853,16 @@ void callback::MinimapMenu(int Param) height = map->height / scaleNum; //--> 12px is width of left and right window frame and 30px is height of the upper and lower window // frame - if((global::s2->getDisplaySurface()->w - 12 < width) - || (global::s2->getDisplaySurface()->h - 30 < height)) + if((static_cast(global::s2->getRes().x) - 12 < width) + || (static_cast(global::s2->getRes().y) - 30 < height)) break; - WNDMinimap = global::s2->RegisterWindow( - std::make_unique(MinimapMenu, WINDOWQUIT, WindowPos::Center, Extent(width + 12, height + 30), - "Overview", WINDOW_NOTHING, WINDOW_CLOSE | WINDOW_MOVE)); + WNDMinimap = global::s2->RegisterWindow(std::make_unique( + MinimapMenu, WINDOWQUIT, WindowPos::Center, Extent(width + 12, height + 30), "Overview", + WINDOW_NOTHING, WINDOW_CLOSE | WINDOW_MOVE)); global::s2->RegisterCallback(MinimapMenu); - WndSurface = WNDMinimap->getSurface(); } break; - case CALL_FROM_GAMELOOP: - if(MapObj && WndSurface) - MapObj->drawMinimap(WndSurface); - break; - case WINDOW_CLICKED_CALL: if(MapObj) { @@ -2894,7 +2892,6 @@ void callback::MinimapMenu(int Param) WNDMinimap = nullptr; } MapObj = nullptr; - WndSurface = nullptr; global::s2->UnregisterCallback(MinimapMenu); break; From c650bddf363ab2fbd4b8321bc865b5fe32fe61b4 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Fri, 3 Jul 2026 20:39:41 +0200 Subject: [PATCH 02/40] Draw() --- CGame.h | 1 - CGame_Init.cpp | 6 - CGame_Render.cpp | 36 ++--- CIO/CButton.cpp | 215 +++++------------------------- CIO/CButton.h | 16 +-- CIO/CControlContainer.cpp | 40 +++--- CIO/CControlContainer.h | 26 +--- CIO/CFont.cpp | 186 ++++++++++++-------------- CIO/CFont.h | 36 ++--- CIO/CMenu.cpp | 35 ++--- CIO/CMenu.h | 14 +- CIO/CMinimapWindow.cpp | 42 ++++-- CIO/CMinimapWindow.h | 7 +- CIO/CPicture.cpp | 33 ++--- CIO/CPicture.h | 12 +- CIO/CSelectBox.cpp | 101 ++++---------- CIO/CSelectBox.h | 17 +-- CIO/CTextfield.cpp | 223 +++++++------------------------ CIO/CTextfield.h | 12 +- CIO/CWindow.cpp | 267 +++++++++++++++----------------------- CIO/CWindow.h | 14 +- Texture.cpp | 159 ++++++++++++++++++++++- Texture.h | 32 +++++ callbacks.cpp | 3 +- include/defines.h | 2 + 25 files changed, 632 insertions(+), 903 deletions(-) diff --git a/CGame.h b/CGame.h index 249b4ac..d62ea65 100644 --- a/CGame.h +++ b/CGame.h @@ -49,7 +49,6 @@ class CGame Texture cursor_; Texture cursorClicked_; Texture cross_; - Texture fpsTex_; ///< Texture for the FPS counter Texture mapTex_; ///< Texture for the map/terrain (Surf_Map may be 8-bit) // structure for mouse cursor diff --git a/CGame_Init.cpp b/CGame_Init.cpp index 8d5617c..49118a6 100644 --- a/CGame_Init.cpp +++ b/CGame_Init.cpp @@ -124,12 +124,6 @@ void CGame::UpdateDisplaySize(const Extent& newSize) appliedFullscreen_ = fullscreen; setGLViewport(); - for(auto& menu : Menus) - { - menu->resetSurface(); - } - for(auto& wnd : Windows) - wnd->resetSurface(); } bool CGame::Init() diff --git a/CGame_Render.cpp b/CGame_Render.cpp index 1f5dd34..f239089 100644 --- a/CGame_Render.cpp +++ b/CGame_Render.cpp @@ -9,6 +9,7 @@ #include "CIO/CWindow.h" #include "CMap.h" #include "CSurface.h" +#include "Texture.h" #include "globals.h" #include #ifdef _WIN32 @@ -40,6 +41,8 @@ void CGame::SetAppIcon() void CGame::Render() { glClear(GL_COLOR_BUFFER_BIT); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // if the S2 loading screen is shown, render only this until user clicks a mouse button if(showLoadScreen) @@ -76,11 +79,11 @@ void CGame::Render() } } - // render active menus + // render active menus — each draws itself with OpenGL for(auto& Menu : Menus) { if(Menu->isActive()) - Menu->getTexture().Draw(Rect(0, 0, GameResolution.x, GameResolution.y)); + Menu->Draw(Position(0, 0)); } // render windows ordered by priority @@ -97,7 +100,7 @@ void CGame::Render() for(auto& Window : Windows) { if(Window->getPriority() == actualPriority) - Window->getTexture().Draw(Position(Window->getX(), Window->getY())); + Window->Draw(Position(0, 0)); } } @@ -114,29 +117,12 @@ void CGame::Render() framesPassedSinceLastFps = 0; lastFpsTick = curTicks; } - { - if(auto* fpsSurf = lastFps.getSurface()) - { - fpsTex_.load(fpsSurf); - glBindTexture(GL_TEXTURE_2D, fpsTex_.getHandle()); - glBegin(GL_QUADS); - glTexCoord2f(0, 0); - glVertex2i(0, 0); - glTexCoord2f(1, 0); - glVertex2i(fpsSurf->w, 0); - glTexCoord2f(1, 1); - glVertex2i(fpsSurf->w, fpsSurf->h); - glTexCoord2f(0, 1); - glVertex2i(0, fpsSurf->h); - glEnd(); - } - } + // Draw FPS counter directly with OpenGL text rendering + lastFps.Draw(Position(0, 0)); - // ---- 5. Cursor on top of everything ---- - { - const auto& cursorImg = Cursor.clicked ? (Cursor.button.right ? cross_ : cursorClicked_) : cursor_; - cursorImg.Draw(Cursor.pos); - } + // ---- Cursor on top of everything ---- + const auto& cursorImg = Cursor.clicked ? (Cursor.button.right ? cross_ : cursorClicked_) : cursor_; + cursorImg.Draw(Cursor.pos); SDL_GL_SwapWindow(window_.get()); diff --git a/CIO/CButton.cpp b/CIO/CButton.cpp index f5f2c7b..19c494f 100644 --- a/CIO/CButton.cpp +++ b/CIO/CButton.cpp @@ -4,10 +4,11 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "CButton.h" -#include "../CSurface.h" +#include "../Texture.h" #include "../globals.h" #include "CFont.h" #include "CollisionDetection.h" +#include CButton::CButton(void callback(int), int clickedParam, Position pos, Extent size, int color, const char* text, int button_picture) @@ -23,19 +24,16 @@ CButton::CButton(void callback(int), int clickedParam, Position pos, Extent size this->clickedParam = clickedParam; motionEntryParam = -1; motionLeaveParam = -1; - needRender = true; } void CButton::setButtonPicture(int picture) { this->button_picture = picture; - needRender = true; } void CButton::setButtonText(const char* text) { button_text = text; - needRender = true; } void CButton::setColor(int color) @@ -84,14 +82,12 @@ void CButton::setColor(int color) pic_background = BUTTON_GREY_BACKGROUND; break; } - - needRender = true; } void CButton::setMouseData(const SDL_MouseMotionEvent& motion) { // cursor is on the button (and mouse button not pressed while moving on the button) - if(IsPointInRect(Position(motion.x, motion.y), Rect(pos_, size_))) + if(IsPointInRect(motion.x, motion.y, Rect(pos_, size_))) { if(motion.state == SDL_RELEASED) { @@ -106,7 +102,6 @@ void CButton::setMouseData(const SDL_MouseMotionEvent& motion) callback_(motionLeaveParam); marked = false; } - needRender = true; } void CButton::setMouseData(const SDL_MouseButtonEvent& button) @@ -115,7 +110,7 @@ void CButton::setMouseData(const SDL_MouseButtonEvent& button) if(button.button == SDL_BUTTON_LEFT) { // if mouse button is pressed ON the button, set marked=true - if((button.state == SDL_PRESSED) && IsPointInRect(Position(button.x, button.y), Rect(pos_, size_))) + if(button.state == SDL_PRESSED && IsPointInRect(button.x, button.y, Rect(pos_, size_))) { marked = true; clicked = true; @@ -127,191 +122,53 @@ void CButton::setMouseData(const SDL_MouseButtonEvent& button) callback_(clickedParam); } } - needRender = true; } -bool CButton::render() +void CButton::Draw(Position parentOrigin) const { - // position in the Surface 'Surf_Button' - Position pos{0, 0}; - // width and height of the button color source picture - Extent pic{0, 0}; - // foreground of the button --> marked or unmarked, NOT the picture - int foreground; - - // if we don't need to render, all is up to date, return true - if(!needRender) - return true; - needRender = false; - // if we need a new surface - if(!Surf_Button) - { - if((Surf_Button = makeRGBSurface(size_.x, size_.y)) == nullptr) - return false; - } - - // at first completly fill the background (not the fastest way, but simplier) - if(size_.x <= global::bmpArray[pic_background].w) - pic.x = size_.x; - else - pic.x = global::bmpArray[pic_background].w; - - if(size_.y <= global::bmpArray[pic_background].h) - pic.y = size_.y; - else - pic.y = global::bmpArray[pic_background].h; - - while(pos.x + pic.x <= static_cast(Surf_Button->w)) - { - while(pos.y + pic.y <= static_cast(Surf_Button->h)) - { - CSurface::Draw(Surf_Button, global::bmpArray[pic_background].surface, pos, Position(0, 0), pic); - pos.y += pic.y; - } - - if(pos.y < Surf_Button->h) - CSurface::Draw(Surf_Button, global::bmpArray[pic_background].surface, pos, Position(0, 0), - Extent(pic.x, static_cast(Surf_Button->h - pos.y))); + const Position absPos = parentOrigin + pos_; - pos.y = 0; - pos.x += pic.x; - } - - if(pos.x < Surf_Button->w) - { - while(pos.y + pic.y <= static_cast(Surf_Button->h)) - { - CSurface::Draw(Surf_Button, global::bmpArray[pic_background].surface, pos, Position(0, 0), - Extent(static_cast(Surf_Button->w - pos.x), pic.y)); - pos.y += pic.y; - } + // 1. Draw background (tiled) + drawTiledBmp(pic_background, Rect(absPos, size_)); - if(pos.y < Surf_Button->h) - CSurface::Draw( - Surf_Button, global::bmpArray[pic_background].surface, pos, Position(0, 0), - Extent(static_cast(Surf_Button->w - pos.x), static_cast(Surf_Button->h - pos.y))); - } - - // draw partial black frame + // 2. Draw black frame (2px) using filled rectangles if(clicked) { - // black frame is left and up - // draw vertical line - pos.x = 0; - for(unsigned y = 0; y < size_.y; y++) - CSurface::DrawPixel_RGB(Surf_Button, Position(pos.x, y), 0, 0, 0); - - // draw vertical line - pos.x = 1; - for(unsigned y = 0; y < size_.y - 1; y++) - CSurface::DrawPixel_RGB(Surf_Button, Position(pos.x, y), 0, 0, 0); - - // draw horizontal line - pos.y = 0; - for(unsigned x = 0; x < size_.x; x++) - CSurface::DrawPixel_RGB(Surf_Button, Position(x, pos.y), 0, 0, 0); - - // draw horizontal line - pos.y = 1; - for(unsigned x = 0; x < size_.x - 1; x++) - CSurface::DrawPixel_RGB(Surf_Button, Position(x, pos.y), 0, 0, 0); + // Left border (2px wide, full height) + DrawRect(Rect(absPos.x, absPos.y, 2, size_.y), 0, 0, 0); + // Top border (2px tall, full width) + DrawRect(Rect(absPos.x, absPos.y, size_.x, 2), 0, 0, 0); } else { - // black frame is right and down - // draw vertical line - pos.x = size_.x - 1; - for(unsigned y = 0; y < size_.y; y++) - CSurface::DrawPixel_RGB(Surf_Button, Position(pos.x, y), 0, 0, 0); - - // draw vertical line - pos.x = size_.x - 2; - for(unsigned y = 1; y < size_.y; y++) - CSurface::DrawPixel_RGB(Surf_Button, Position(pos.x, y), 0, 0, 0); - - // draw horizontal line - pos.y = size_.y - 1; - for(unsigned x = 0; x < size_.x; x++) - CSurface::DrawPixel_RGB(Surf_Button, Position(x, pos.y), 0, 0, 0); - - // draw horizontal line - pos.y = size_.y - 2; - for(unsigned x = 1; x < size_.x; x++) - CSurface::DrawPixel_RGB(Surf_Button, Position(x, pos.y), 0, 0, 0); - } - - // draw the foreground --> at first the color (marked or unmarked) and then the picture or text - if(size_.x <= global::bmpArray[pic_normal].w) - pic.x = size_.x; - else - pic.x = global::bmpArray[pic_normal].w; - - if(size_.y <= global::bmpArray[pic_normal].h) - pic.y = size_.y; - else - pic.y = global::bmpArray[pic_normal].h; - - // beware overdrawing the left and upper frame - pos.x = 2; - pos.y = 2; - - // decide if button lights or not - if(marked && !clicked) - foreground = pic_marked; - else - foreground = pic_normal; - - // '-2' follows a few times, this means: beware overdrawing the right and lower frame - while(pos.x + pic.x <= static_cast(Surf_Button->w - 2)) - { - while(pos.y + pic.y <= static_cast(Surf_Button->h - 2)) - { - CSurface::Draw(Surf_Button, global::bmpArray[foreground].surface, pos, Position(0, 0), pic); - pos.y += pic.y; - } - - if(pos.y + 2 < Surf_Button->h) - CSurface::Draw(Surf_Button, global::bmpArray[foreground].surface, pos, Position(0, 0), - Extent(pic.x, static_cast(Surf_Button->h - pos.y))); - - pos.y = 2; - pos.x += pic.x; + // Right border (2px wide, full height) + DrawRect(Rect(absPos.x + static_cast(size_.x) - 2, absPos.y, 2, size_.y), 0, 0, 0); + // Bottom border (2px tall, full width) + DrawRect(Rect(absPos.x, absPos.y + static_cast(size_.y) - 2, size_.x, 2), 0, 0, 0); } - if(pos.x + 2 < Surf_Button->w) - { - while(pos.y + pic.y <= static_cast(Surf_Button->h - 2)) - { - CSurface::Draw(Surf_Button, global::bmpArray[foreground].surface, pos, Position(0, 0), - Extent(static_cast(Surf_Button->w - 2 - pos.x), pic.y)); - pos.y += pic.y; - } + // 3. Draw foreground (tiled, inset by 2px for the black frame) + const int foreground = (marked && !clicked) ? pic_marked : pic_normal; + const Rect fgRect(absPos + Position(2, 2), size_ - Extent(4, 4)); + drawTiledBmp(foreground, fgRect); - if(pos.y + 2 < Surf_Button->h) - CSurface::Draw(Surf_Button, global::bmpArray[foreground].surface, pos, Position(0, 0), - Extent(static_cast(Surf_Button->w - 2 - pos.x), - static_cast(Surf_Button->h - 2 - pos.y))); - } - - // positioning the picture or write text + // 4. Draw picture or text centered inside the button if(button_picture >= 0) { - // picture may not be bigger than the button - if(size_.x <= static_cast(Surf_Button->w) && size_.y <= static_cast(Surf_Button->h)) - { - // get coordinates of the left upper corner where to positionate the picture - Position leftup = Position(Surf_Button->w, Surf_Button->h) / 2 - - Position(global::bmpArray[button_picture].w, global::bmpArray[button_picture].h) / 2; - // blit it - CSurface::Draw(Surf_Button, global::bmpArray[button_picture].surface, leftup); - } else + auto& picTex = getBmpTexture(button_picture); + if(picTex.isValid()) { - button_picture = -1; - button_text = "PIC"; + const auto& picBmp = global::bmpArray[button_picture]; + const Position picPos = + absPos + Position(size_) / 2 - Position(static_cast(picBmp.w), static_cast(picBmp.h)) / 2; + picTex.Draw(picPos); } } else if(button_text) - CFont::writeText(Surf_Button, button_text, - Position(static_cast(size_.x / 2), static_cast((size_.y - 11) / 2)), - FontSize::Medium, button_text_color, FontAlign::Middle); - - return true; + { + // Draw text centered (using native-size texture drawing for each character) + const unsigned textW = CFont::getTextWidth(button_text, FontSize::Medium); + const unsigned textH = static_cast(FontSize::Medium); + const Position textPos = + absPos + Position(static_cast(size_.x / 2 - textW / 2), static_cast((size_.y - textH) / 2)); + CFont::Draw(button_text, textPos, FontSize::Medium, button_text_color, FontAlign::Left); + } } diff --git a/CIO/CButton.h b/CIO/CButton.h index d9b54e7..034d93d 100644 --- a/CIO/CButton.h +++ b/CIO/CButton.h @@ -5,7 +5,6 @@ #pragma once -#include "SdlSurface.h" #include "defines.h" class CButton @@ -13,8 +12,6 @@ class CButton friend class CDebug; private: - SdlSurface Surf_Button; - bool needRender; Position pos_; Extent size_; int pic_normal; @@ -44,18 +41,9 @@ class CButton void setButtonText(const char* text); void setMouseData(const SDL_MouseMotionEvent& motion); void setMouseData(const SDL_MouseButtonEvent& button); - bool render(); - SDL_Surface* getSurface() - { - render(); - return Surf_Button.get(); - }; + void Draw(Position parentOrigin) const; void setColor(int color); - void setTextColor(FontColor color) - { - button_text_color = color; - needRender = true; - }; + void setTextColor(FontColor color) { button_text_color = color; }; void setMotionParams(int entry, int leave) { motionEntryParam = entry; diff --git a/CIO/CControlContainer.cpp b/CIO/CControlContainer.cpp index e839f38..d404370 100644 --- a/CIO/CControlContainer.cpp +++ b/CIO/CControlContainer.cpp @@ -4,7 +4,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "CControlContainer.h" -#include "../CSurface.h" +#include "../Texture.h" #include "../globals.h" #include "CButton.h" #include "CFont.h" @@ -25,7 +25,6 @@ CControlContainer::~CControlContainer() noexcept = default; void CControlContainer::setBackgroundPicture(int pic_background) { this->pic_background = pic_background; - needRender = true; } void CControlContainer::setMouseData(const SDL_MouseMotionEvent motion) @@ -42,7 +41,6 @@ void CControlContainer::setMouseData(const SDL_MouseMotionEvent motion) { selectbox->setMouseData(motion); } - needRender = true; } void CControlContainer::setMouseData(const SDL_MouseButtonEvent button) @@ -63,7 +61,6 @@ void CControlContainer::setMouseData(const SDL_MouseButtonEvent button) { selectbox->setMouseData(button); } - needRender = true; } void CControlContainer::setKeyboardData(const SDL_KeyboardEvent& key) @@ -81,7 +78,6 @@ bool CControlContainer::eraseElement(T& collection, const U* element) if(it != collection.end()) { collection.erase(it); - needRender = true; return true; } return false; @@ -93,7 +89,6 @@ CButton* CControlContainer::addButton(void callback(int), int clickedParam, Posi pos = pos + borderBeginSize; buttons.emplace_back(std::make_unique(callback, clickedParam, pos, size, color, text, picture)); - needRender = true; return buttons.back().get(); } @@ -107,7 +102,6 @@ CFont* CControlContainer::addText(std::string string, Position pos, FontSize fon pos = pos + borderBeginSize; texts.emplace_back(std::make_unique(std::move(string), pos, fontsize, color)); - needRender = true; return texts.back().get(); } @@ -121,7 +115,6 @@ CPicture* CControlContainer::addPicture(void callback(int), int clickedParam, Po pos = pos + borderBeginSize; pictures.emplace_back(std::make_unique(callback, clickedParam, pos, picture)); - needRender = true; return pictures.back().get(); } @@ -138,7 +131,6 @@ int CControlContainer::addStaticPicture(Position pos, int picture) unsigned id = static_pictures.empty() ? 0u : static_pictures.back().id + 1u; static_pictures.emplace_back(Picture{pos, picture, id}); - needRender = true; return id; } @@ -151,7 +143,6 @@ bool CControlContainer::delStaticPicture(int picId) if(it != static_pictures.end()) { static_pictures.erase(it); - needRender = true; return true; } return false; @@ -164,7 +155,6 @@ CTextfield* CControlContainer::addTextfield(Position pos, Uint16 cols, Uint16 ro textfields.emplace_back( std::make_unique(pos, cols, rows, fontsize, text_color, bg_color, button_style)); - needRender = true; return textfields.back().get(); } @@ -179,7 +169,6 @@ CSelectBox* CControlContainer::addSelectBox(Position pos, Extent size, FontSize pos += Position(borderBeginSize); selectboxes.emplace_back(std::make_unique(pos, size, fontsize, text_color, bg_color)); - needRender = true; return selectboxes.back().get(); } @@ -188,18 +177,31 @@ bool CControlContainer::delSelectBox(CSelectBox* SelectBoxToDelete) return eraseElement(selectboxes, SelectBoxToDelete); } -void CControlContainer::renderElements() +// --------------------------------------------------------------------------- +// Draw & DrawChildren +// --------------------------------------------------------------------------- + +void CControlContainer::Draw(Position parentOrigin) +{ + DrawChildren(parentOrigin); +} + +void CControlContainer::DrawChildren(Position origin) { for(const auto& picture : pictures) - CSurface::Draw(surface, picture->getSurface(), picture->getX(), picture->getY()); + picture->Draw(origin); for(const auto& text : texts) - CSurface::Draw(surface, text->getSurface(), text->getX(), text->getY()); + text->Draw(origin); for(const auto& textfield : textfields) - CSurface::Draw(surface, textfield->getSurface(), textfield->getX(), textfield->getY()); + textfield->Draw(origin); for(const auto& selectbox : selectboxes) - CSurface::Draw(surface, selectbox->getSurface(), selectbox->getPos()); + selectbox->Draw(origin); for(const auto& button : buttons) - CSurface::Draw(surface, button->getSurface(), button->getX(), button->getY()); + button->Draw(origin); for(const auto& static_picture : static_pictures) - CSurface::Draw(surface, global::bmpArray[static_picture.pic].surface, static_picture.pos); + { + auto& tex = getBmpTexture(static_picture.pic); + if(tex.isValid()) + tex.Draw(origin + static_picture.pos); + } } diff --git a/CIO/CControlContainer.h b/CIO/CControlContainer.h index 7802e61..31304cb 100644 --- a/CIO/CControlContainer.h +++ b/CIO/CControlContainer.h @@ -5,7 +5,6 @@ #pragma once -#include "../Texture.h" #include "defines.h" #include #include @@ -41,14 +40,14 @@ class CControlContainer template bool eraseElement(T& collection, const U* element); - virtual bool render() = 0; protected: - SdlSurface surface; - bool needRender = true; - Texture surfaceTex_; ///< Texture for this container's surface (used by CWindow) + /// Draw the container's background and child elements using OpenGL. + /// @param parentOrigin Absolute position of the parent container. + virtual void Draw(Position parentOrigin); + /// Draw children at the given origin (calls each child's Draw). + void DrawChildren(Position origin); - void renderElements(); auto& getTextFields() { return textfields; } const auto& getTextFields() const { return textfields; } int getBackground() const { return pic_background; } @@ -59,25 +58,14 @@ class CControlContainer virtual ~CControlContainer() noexcept; // Access Extent getBorderSize() const { return borderBeginSize + borderEndSize; } + Extent getBorderBegin() const { return borderBeginSize; } + Extent getBorderEnd() const { return borderEndSize; } void setBackgroundPicture(int pic_background); virtual void setMouseData(SDL_MouseMotionEvent motion); virtual void setMouseData(SDL_MouseButtonEvent button); void setKeyboardData(const SDL_KeyboardEvent& key); - /// Get the texture for this container's rendered content. - const Texture& getTexture() - { - render(); - if(surface) - surfaceTex_.load(surface.get()); - return surfaceTex_; - } void setWaste() { waste = true; } bool isWaste() const { return waste; } - void resetSurface() - { - surface.reset(); - needRender = true; - } // Methods CButton* addButton(void callback(int), int clickedParam, Position pos = {0, 0}, Extent size = {20, 20}, int color = BUTTON_GREY, const char* text = nullptr, int picture = -1); diff --git a/CIO/CFont.cpp b/CIO/CFont.cpp index d7b421a..73ebe18 100644 --- a/CIO/CFont.cpp +++ b/CIO/CFont.cpp @@ -5,46 +5,37 @@ #include "CFont.h" #include "../CSurface.h" +#include "../Texture.h" #include "../globals.h" +#include "CollisionDetection.h" #include CFont::CFont(std::string text, Position pos, FontSize fontsize, FontColor color) - : x_(pos.x), y_(pos.y), string_(std::move(text)), fontsize_(fontsize), color_(color), initialColor_(color), - clickedParam(0) -{} + : pos_(pos), string_(std::move(text)), fontsize_(fontsize), color_(color), initialColor_(color), clickedParam(0) +{ + size_ = Extent(getTextWidth(string_, fontsize_), getLineHeight(fontsize_)); +} void CFont::setPos(Position pos) { - if(pos != Position(x_, y_)) - { - x_ = pos.x; - y_ = pos.y; - Surf_Font.reset(); - } + pos_ = pos; } void CFont::setFontsize(FontSize fontsize) { - if(fontsize != fontsize_) - { - fontsize_ = fontsize; - Surf_Font.reset(); - } + fontsize_ = fontsize; + size_ = Extent(getTextWidth(string_, fontsize_), getLineHeight(fontsize_)); } void CFont::setColor(FontColor color) { - if(color != color_) - Surf_Font.reset(); initialColor_ = color_ = color; } void CFont::setText(std::string text) { - if(text == string_) - return; - Surf_Font.reset(); this->string_ = std::move(text); + size_ = Extent(getTextWidth(string_, fontsize_), getLineHeight(fontsize_)); } void CFont::setMouseData(SDL_MouseButtonEvent button) @@ -54,10 +45,10 @@ void CFont::setMouseData(SDL_MouseButtonEvent button) // left button is pressed if(button.button == SDL_BUTTON_LEFT) { - if((button.x >= x_) && (button.x < x_ + w) && (button.y >= y_) && (button.y < y_ + h)) + if(IsPointInRect(button.x, button.y, Rect(pos_, size_))) { // if mouse button is pressed ON the text - if((button.state == SDL_PRESSED) && getColor() == initialColor_) + if(button.state == SDL_PRESSED && getColor() == initialColor_) { const auto tmpInitialColor = initialColor_; setColor(FontColor::Orange); @@ -71,19 +62,14 @@ void CFont::setMouseData(SDL_MouseButtonEvent button) } } -SDL_Surface* CFont::getSurface() -{ - if(!Surf_Font) - writeText(); - return Surf_Font.get(); -} +// --------------------------------------------------------------------------- +// Character-index helpers (shared by SDL and GL paths) +// --------------------------------------------------------------------------- namespace { unsigned getIndexForChar(uint8_t c) { // subtract 32 shows that we start by spacebar as 'zero-position' - // subtract another value after subtracting 32 means the skipped chiffres in ansi in compare to our enumeration - // (cause we dont have all ansi-values as pictures) if(c >= 32 && c <= 90) return c - 32; /* \ */ @@ -197,100 +183,82 @@ unsigned getIndexForChar(uint8_t c, FontSize fontsize, FontColor color) } unsigned getCharWidth(uint8_t c, FontSize fontsize, FontColor color) -{ // NOTE: there is a bug in the ansi 236 'ì' at fontsize 9, the width is 39, this is not useable, we will use the width - // of ansi 237 - // 'í' instead +{ + // NOTE: there is a bug in the ansi 236 'ì' at fontsize 9, the width is 39, this is not useable, we will use the + // width of ansi 237 'í' instead if(fontsize == FontSize::Small && c == 236) c = 109; return global::bmpArray[getIndexForChar(c, fontsize, color)].w; } } // namespace -void CFont::writeText() +// --------------------------------------------------------------------------- +// OpenGL Draw methods +// --------------------------------------------------------------------------- + +void CFont::Draw(Position parentOrigin) const { if(string_.empty()) return; - // data for counting pixels to create the surface - unsigned pixel_ctr_w = 0; - unsigned pixel_ctr_w_tmp = 0; - const unsigned lineHeight = getLineHeight(fontsize_); - auto pixel_ctr_h = static_cast(fontsize_); - bool pixel_count_loop = true; - // counter for the drawed pixels (cause we dont want to draw outside of the surface) - Position pos{0, 0}; + Draw(string_, parentOrigin + pos_, fontsize_, color_, FontAlign::Left); +} - // now lets draw the chiffres - auto chiffre = string_.begin(); - while(chiffre != string_.end()) - { - const auto charW = getCharWidth(*chiffre, fontsize_, color_); - // if we only count pixels in this round - if(pixel_count_loop) - { - if(*chiffre == '\n') - { - pixel_ctr_h += lineHeight; - if(pixel_ctr_w_tmp > pixel_ctr_w) - pixel_ctr_w = pixel_ctr_w_tmp; - pixel_ctr_w_tmp = 0; - ++chiffre; - } else - { - pixel_ctr_w_tmp += charW; - ++chiffre; - } +void CFont::Draw(const std::string& string, Position pos, FontSize fontsize, FontColor color, FontAlign align) +{ + if(string.empty()) + return; - // if this was the last chiffre setup width, create surface and go in normal mode to write text to the - // surface - if(chiffre == string_.end()) - { - if(pixel_ctr_w_tmp > pixel_ctr_w) - pixel_ctr_w = pixel_ctr_w_tmp; - w = pixel_ctr_w; - h = pixel_ctr_h; - Surf_Font = makeRGBSurface(w, h); - if(!Surf_Font) - return; - SDL_SetColorKey(Surf_Font.get(), SDL_TRUE, SDL_MapRGB(Surf_Font->format, 0, 0, 0)); - chiffre = string_.begin(); - pixel_count_loop = false; - continue; - } else - continue; - } + // Measure text width for alignment + const unsigned lineHeight = getLineHeight(fontsize); + unsigned totalWidth = 0; + for(unsigned char c : string) + { + if(c == '\n') + break; + totalWidth += getCharWidth(c, fontsize, color); + } - // now we have our index and can use global::bmpArray[chiffre_index] to get the picture + // Apply alignment + switch(align) + { + case FontAlign::Middle: pos.x -= static_cast(totalWidth / 2); break; + case FontAlign::Right: pos.x -= static_cast(totalWidth); break; + case FontAlign::Left: break; // no adjustment + } - // test for new line - if(*chiffre == '\n') + // Draw each character as a textured quad + Position curPos = pos; + for(unsigned char c : string) + { + if(c == '\n') { - pos.x = 0; - pos.y += lineHeight; - ++chiffre; + curPos.x = pos.x; + curPos.y += lineHeight; continue; } - // if right end of surface is reached, stop drawing chiffres - if(Surf_Font->w < static_cast(pos.x + charW)) - break; - - const auto chiffre_index = getIndexForChar(*chiffre, fontsize_, color_); - - // if lower end of surface is reached, stop drawing chiffres - if(Surf_Font->h < static_cast(pos.y + global::bmpArray[chiffre_index].h)) - break; - - // draw the chiffre to the destination - CSurface::Draw(Surf_Font, global::bmpArray[chiffre_index].surface, pos); + const unsigned idx = getIndexForChar(c, fontsize, color); + if(idx >= global::bmpArray.size()) + continue; - // set position for next chiffre - pos.x += charW; + auto& tex = getBmpTexture(idx); + if(!tex.isValid()) + { + curPos.x += getCharWidth(c, fontsize, color); + continue; + } - // go to next chiffre - ++chiffre; + const auto& bmp = global::bmpArray[idx]; + const unsigned charW = bmp.w; + tex.Draw(Rect(curPos.x, curPos.y, charW, bmp.h)); + curPos.x += charW; } } +// --------------------------------------------------------------------------- +// SDL surface writeText (for terrain / minimap rendering) +// --------------------------------------------------------------------------- + bool CFont::writeText(SDL_Surface* Surf_Dest, const std::string& string, unsigned x, unsigned y, FontSize fontsize, FontColor color, FontAlign align) { @@ -362,3 +330,19 @@ bool CFont::writeText(SDL_Surface* Surf_Dest, const std::string& string, unsigne return true; } + +// --------------------------------------------------------------------------- +// getTextWidth +// --------------------------------------------------------------------------- + +unsigned CFont::getTextWidth(const std::string& string, FontSize fontsize) +{ + unsigned w = 0; + for(unsigned char c : string) + { + if(c == '\n') + break; + w += getCharWidth(c, fontsize, FontColor::Yellow); // width is same for all colors + } + return w; +} diff --git a/CIO/CFont.h b/CIO/CFont.h index e73e480..53c841f 100644 --- a/CIO/CFont.h +++ b/CIO/CFont.h @@ -16,28 +16,25 @@ class CFont friend class CDebug; private: - SdlSurface Surf_Font; - int x_; - int y_; - Uint16 w; - Uint16 h; + Position pos_; ///< Position of the text (top-left) + Extent size_; ///< Pixel extent of the rendered text std::string string_; FontSize fontsize_; FontColor color_, initialColor_; std::function callback; int clickedParam; - void writeText(); - public: CFont(std::string text, Position pos = {0, 0}, FontSize fontsize = FontSize::Small, FontColor color = FontColor::Yellow); // Access - int getX() const { return x_; }; - int getY() const { return y_; }; + int getX() const { return pos_.x; } + int getY() const { return pos_.y; } + const Position& getPos() const { return pos_; } + const Extent& getSize() const { return size_; } + unsigned getW() const { return size_.x; } + unsigned getH() const { return static_cast(fontsize_); } void setPos(Position pos); - unsigned getW() const { return w; }; - unsigned getH() const { return static_cast(fontsize_); }; void setFontsize(FontSize fontsize); void setColor(FontColor color); FontColor getColor() const { return color_; } @@ -53,10 +50,16 @@ class CFont clickedParam = 0; } void setMouseData(SDL_MouseButtonEvent button); - SDL_Surface* getSurface(); - // Methods - // fontsize can be 9, 11 or 14 (otherwise it will be set to 9) ---- '\n' is possible - // this function can be used as CFont::writeText to write text directly to a surface without creating an object + + /// Draw this font's text at the given absolute position using OpenGL. + void Draw(Position parentOrigin) const; + + /// Static helpers for drawing text with OpenGL directly. + /// @param pos Absolute position (top-left of the text, adjusted for alignment). + static void Draw(const std::string& string, Position pos, FontSize fontsize = FontSize::Small, + FontColor color = FontColor::Yellow, FontAlign align = FontAlign::Left); + + /// Static helper: draw text onto an SDL surface (for terrain / minimap rendering). static bool writeText(SDL_Surface* Surf_Dest, const std::string& string, unsigned x = 0, unsigned y = 0, FontSize fontsize = FontSize::Small, FontColor color = FontColor::Yellow, FontAlign align = FontAlign::Left); @@ -66,4 +69,7 @@ class CFont { return writeText(Surf_Dest.get(), string, pos.x, pos.y, fontsize, color, align); } + + /// Compute the pixel width of a string without drawing it. + static unsigned getTextWidth(const std::string& string, FontSize fontsize); }; diff --git a/CIO/CMenu.cpp b/CIO/CMenu.cpp index af68a28..4591948 100644 --- a/CIO/CMenu.cpp +++ b/CIO/CMenu.cpp @@ -10,35 +10,20 @@ CMenu::CMenu(int pic_background) : CControlContainer(pic_background) {} -bool CMenu::render() +void CMenu::Draw(Position /*parentOrigin*/) { - if(getBackground() < 0) - return false; - - if(!bgTexture_) + // Draw full-screen background texture + const int picIdx = getBackground(); + if(picIdx >= 0 && picIdx < static_cast(global::bmpArray.size())) { - const int picIdx = getBackground(); - if(picIdx >= 0 && picIdx < static_cast(global::bmpArray.size()) && global::bmpArray[picIdx].surface) + auto& tex = getBmpTexture(picIdx, true); + if(tex.isValid()) { - bgTexture_ = std::make_unique(); - bgTexture_->load(global::bmpArray[picIdx].surface.get(), true); + const auto res = global::s2->getRes(); + tex.Draw(Rect(0, 0, res.x, res.y)); } } - if(bgTexture_) - bgTexture_->Draw(Rect(0, 0, global::s2->getRes().x, global::s2->getRes().y)); - - if(!needRender) - return true; - needRender = false; - // if we need a new surface - if(!surface) - { - surface = makeRGBSurface(global::s2->getRes().x, global::s2->getRes().y, true); - if(!surface) - return false; - } - - renderElements(); - return true; + // Draw children + DrawChildren(Position(0, 0)); } diff --git a/CIO/CMenu.h b/CIO/CMenu.h index 59d8400..487e658 100644 --- a/CIO/CMenu.h +++ b/CIO/CMenu.h @@ -6,21 +6,17 @@ #pragma once #include "CControlContainer.h" -#include - -class Texture; class CMenu final : public CControlContainer { // if active is false, the menu will not be render within the game loop bool active = true; - mutable std::unique_ptr bgTexture_; - - bool render() final; public: CMenu(int pic_background); - void setActive() { active = true; }; - void setInactive() { active = false; }; - bool isActive() const { return active; }; + void setActive() { active = true; } + void setInactive() { active = false; } + bool isActive() const { return active; } + + void Draw(Position parentOrigin) override; }; diff --git a/CIO/CMinimapWindow.cpp b/CIO/CMinimapWindow.cpp index 0ecbbd7..a91eb0f 100644 --- a/CIO/CMinimapWindow.cpp +++ b/CIO/CMinimapWindow.cpp @@ -5,19 +5,43 @@ #include "CMinimapWindow.h" #include "../CGame.h" #include "../CMap.h" +#include "../Texture.h" #include "../globals.h" -bool CMinimapWindow::render() +void CMinimapWindow::Draw(Position /*parentOrigin*/) { - // Always re-render: the minimap terrain overlay may have changed - needRender = true; // Draw window chrome (frame, title, close button, background, child elements) - CWindow::render(); - // Draw minimap terrain overlay on top of the chrome - if(surface) + CWindow::Draw(Position(x_, y_)); + + // Compute content area (inside the frames) + const auto borderBegin = getBorderBegin(); + const auto borderEnd = getBorderEnd(); + const int contentX = x_ + static_cast(borderBegin.x); + const int contentY = y_ + static_cast(borderBegin.y); + const int contentW = static_cast(w_) - static_cast(borderBegin.x) - static_cast(borderEnd.x); + const int contentH = static_cast(h_) - static_cast(borderBegin.y) - static_cast(borderEnd.y); + + if(contentW <= 0 || contentH <= 0) + return; + + // Draw minimap terrain overlay onto a temporary SDL surface, then upload to texture + if(auto* map = global::s2->getMapObj()) { - if(auto* map = global::s2->getMapObj()) - map->drawMinimap(surface.get()); + // Create or resize the minimap surface + if(!minimapSurface_ || minimapSurface_->w != contentW || minimapSurface_->h != contentH) + minimapSurface_ = makeRGBSurface(static_cast(contentW), static_cast(contentH), true); + + if(minimapSurface_) + { + // Clear with transparency + SDL_FillRect(minimapSurface_.get(), nullptr, SDL_MapRGBA(minimapSurface_->format, 0, 0, 0, 0)); + + // Draw minimap onto the temporary surface + map->drawMinimap(minimapSurface_.get()); + + // Upload to texture and draw + minimapTex_.load(minimapSurface_.get()); + minimapTex_.Draw(Rect(contentX, contentY, contentW, contentH)); + } } - return true; } diff --git a/CIO/CMinimapWindow.h b/CIO/CMinimapWindow.h index 2d16dd6..7817e06 100644 --- a/CIO/CMinimapWindow.h +++ b/CIO/CMinimapWindow.h @@ -4,11 +4,16 @@ #pragma once +#include "../Texture.h" #include "CWindow.h" class CMinimapWindow final : public CWindow { - bool render() final; + /// Temporary SDL surface for minimap terrain overlay (kept until terrain is also OpenGL) + SdlSurface minimapSurface_; + Texture minimapTex_; + + void Draw(Position parentOrigin) override; public: using CWindow::CWindow; diff --git a/CIO/CPicture.cpp b/CIO/CPicture.cpp index 7130a1c..b75863e 100644 --- a/CIO/CPicture.cpp +++ b/CIO/CPicture.cpp @@ -4,7 +4,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "CPicture.h" -#include "../CSurface.h" +#include "../Texture.h" #include "../globals.h" #include "CollisionDetection.h" @@ -22,13 +22,12 @@ CPicture::CPicture(void callback(int), int clickedParam, Position pos, int pictu this->clickedParam = clickedParam; motionEntryParam = -1; motionLeaveParam = -1; - needRender = true; } void CPicture::setMouseData(const SDL_MouseMotionEvent& motion) { // cursor is on the picture - if(IsPointInRect(Position(motion.x, motion.y), Rect(pos_, size_))) + if(IsPointInRect(motion.x, motion.y, Rect(pos_, size_))) { if(motion.state == SDL_RELEASED) { @@ -43,7 +42,6 @@ void CPicture::setMouseData(const SDL_MouseMotionEvent& motion) callback(motionLeaveParam); marked = false; } - needRender = true; } void CPicture::setMouseData(const SDL_MouseButtonEvent& button) @@ -52,7 +50,7 @@ void CPicture::setMouseData(const SDL_MouseButtonEvent& button) if(button.button == SDL_BUTTON_LEFT) { // if mouse button is pressed ON the button, set marked=true - if((button.state == SDL_PRESSED) && IsPointInRect(Position(button.x, button.y), Rect(pos_, size_))) + if(button.state == SDL_PRESSED && IsPointInRect(button.x, button.y, Rect(pos_, size_))) { marked = true; clicked = true; @@ -64,25 +62,14 @@ void CPicture::setMouseData(const SDL_MouseButtonEvent& button) callback(clickedParam); } } - needRender = true; } -bool CPicture::render() +void CPicture::Draw(Position parentOrigin) const { - // if we don't need to render, all is up to date, return true - if(!needRender) - return true; - needRender = false; - // if we need a new surface - if(!Surf_Picture) - { - Surf_Picture = makeRGBSurface(size_.x, size_.y); - if(!Surf_Picture) - return false; - SDL_SetColorKey(Surf_Picture.get(), SDL_TRUE, SDL_MapRGB(Surf_Picture->format, 0, 0, 0)); - } - - CSurface::Draw(Surf_Picture, global::bmpArray[picture_].surface); - - return true; + if(picture_ < 0 || picture_ >= static_cast(global::bmpArray.size())) + return; + auto& tex = getBmpTexture(picture_); + if(!tex.isValid()) + return; + tex.Draw(parentOrigin + pos_); } diff --git a/CIO/CPicture.h b/CIO/CPicture.h index 6b648c2..797998e 100644 --- a/CIO/CPicture.h +++ b/CIO/CPicture.h @@ -6,15 +6,13 @@ #pragma once #include "Point.h" -#include "SdlSurface.h" +#include "defines.h" class CPicture { friend class CDebug; private: - SdlSurface Surf_Picture; - bool needRender; Position pos_; Extent size_; int picture_; @@ -30,17 +28,13 @@ class CPicture // Access int getX() const { return pos_.x; }; int getY() const { return pos_.y; }; + const Position& getPos() const { return pos_; } const Extent& getSize() const { return size_; }; void setX(int x) { pos_.x = x; }; void setY(int y) { pos_.y = y; }; void setMouseData(const SDL_MouseMotionEvent& motion); void setMouseData(const SDL_MouseButtonEvent& button); - bool render(); - SDL_Surface* getSurface() - { - render(); - return Surf_Picture.get(); - }; + void Draw(Position parentOrigin) const; void setMotionParams(int entry, int leave) { motionEntryParam = entry; diff --git a/CIO/CSelectBox.cpp b/CIO/CSelectBox.cpp index 04da9b4..ceda380 100644 --- a/CIO/CSelectBox.cpp +++ b/CIO/CSelectBox.cpp @@ -4,10 +4,12 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "CSelectBox.h" -#include "../CSurface.h" +#include "../CGame.h" +#include "../Texture.h" #include "../globals.h" #include "CButton.h" #include "CFont.h" +#include CSelectBox::CSelectBox(Position pos, Extent size, FontSize fontsize, FontColor text_color, int bg_color) : pos_(pos), size_(size), fontsize(fontsize), text_color(text_color) @@ -82,8 +84,6 @@ void CSelectBox::setColor(int color) pic_background = -1; break; } - - needRender = true; } void CSelectBox::setMouseData(SDL_MouseMotionEvent motion) @@ -94,7 +94,6 @@ void CSelectBox::setMouseData(SDL_MouseMotionEvent motion) motion.y -= pos_.y; ScrollUpButton->setMouseData(motion); ScrollDownButton->setMouseData(motion); - needRender = true; } void CSelectBox::setMouseData(SDL_MouseButtonEvent button) @@ -199,8 +198,6 @@ void CSelectBox::setMouseData(SDL_MouseButtonEvent button) ScrollUpButton->setMouseData(button); ScrollDownButton->setMouseData(button); } - - needRender = true; } void CSelectBox::setSize(Extent size) @@ -208,8 +205,6 @@ void CSelectBox::setSize(Extent size) if(size_ != size) { size_ = size; - Surf_SelectBox.reset(); - needRender = true; // update scroll down button position ScrollDownButton->setY(size_.y - 1 - 20); } @@ -218,84 +213,40 @@ void CSelectBox::setSize(Extent size) void CSelectBox::setPos(Position pos) { pos_ = pos; - needRender = true; } -bool CSelectBox::render() +void CSelectBox::Draw(Position parentOrigin) { - // position in the Surface 'Surf_SelectBox' - Position pos{0, 0}; - // width and height of the button color source picture - Extent pic{0, 0}; + const Position absPos = parentOrigin + pos_; + const Rect area(absPos, size_); - // if we don't need to render, all is up to date, return true - if(!needRender) - return true; - needRender = false; - // if we need a new surface - if(!Surf_SelectBox) - { - if((Surf_SelectBox = makeRGBSurface(size_.x, size_.y)) == nullptr) - return false; - } - - // draw the pictures for background and foreground or, if not set, fill with black color + // Draw background if(pic_background >= 0 && pic_foreground >= 0) { - // at first completly fill the background (not the fastest way, but simplier) - if(size_.x <= global::bmpArray[pic_foreground].w) - pic.x = size_.x; - else - pic.x = global::bmpArray[pic_foreground].w; - - if(size_.y <= global::bmpArray[pic_foreground].h) - pic.y = size_.y; - else - pic.y = global::bmpArray[pic_foreground].h; - - while(pos.x + pic.x <= static_cast(Surf_SelectBox->w)) - { - while(pos.y + pic.y <= static_cast(Surf_SelectBox->h)) - { - CSurface::Draw(Surf_SelectBox, global::bmpArray[pic_foreground].surface, pos, Position(0, 0), pic); - pos.y += pic.y; - } - - if(pos.y < Surf_SelectBox->h) - CSurface::Draw(Surf_SelectBox, global::bmpArray[pic_foreground].surface, pos.x, pos.y, 0, 0, pic.x, - static_cast(Surf_SelectBox->h - pos.y)); - - pos.y = 0; - pos.x += pic.x; - } - - if(pos.x < Surf_SelectBox->w) - { - while(pos.y + pic.y <= static_cast(Surf_SelectBox->h)) - { - CSurface::Draw(Surf_SelectBox, global::bmpArray[pic_foreground].surface, pos.x, pos.y, 0, 0, - static_cast(Surf_SelectBox->w - pos.x), pic.y); - pos.y += pic.y; - } - - if(pos.y < Surf_SelectBox->h) - CSurface::Draw(Surf_SelectBox, global::bmpArray[pic_foreground].surface, pos.x, pos.y, 0, 0, - static_cast(Surf_SelectBox->w - pos.x), - static_cast(Surf_SelectBox->h - pos.y)); - } + drawTiledBmp(pic_foreground, area); } else - SDL_FillRect(Surf_SelectBox.get(), nullptr, SDL_MapRGB(Surf_SelectBox->format, 0, 0, 0)); + { + // Fill with black + DrawRect(area, 0, 0, 0, 255); + } - for(auto& entry : Entries) + // Clip entries to the select box area + const auto viewH = global::s2->getRes().y; + glEnable(GL_SCISSOR_TEST); + glScissor(area.left, viewH - (area.top + static_cast(size_.y)), static_cast(size_.x), + static_cast(size_.y)); + + // Draw entries + for(const auto& entry : Entries) { - CSurface::Draw(Surf_SelectBox, entry->getSurface(), entry->getX(), entry->getY()); + entry->Draw(absPos); } - CSurface::Draw(Surf_SelectBox, ScrollUpButton->getSurface(), static_cast(size_.x) - 1 - 20, 0); - CSurface::Draw(Surf_SelectBox, ScrollDownButton->getSurface(), static_cast(size_.x) - 1 - 20, - static_cast(size_.y) - 1 - 20); + glDisable(GL_SCISSOR_TEST); - rendered = true; + // Draw scroll buttons (on top, within the select box) + ScrollUpButton->Draw(absPos); + ScrollDownButton->Draw(absPos); - return true; + rendered = true; } diff --git a/CIO/CSelectBox.h b/CIO/CSelectBox.h index 8a62d13..88e277b 100644 --- a/CIO/CSelectBox.h +++ b/CIO/CSelectBox.h @@ -5,7 +5,6 @@ #pragma once -#include "SdlSurface.h" #include "defines.h" #include #include @@ -19,7 +18,6 @@ class CSelectBox friend class CDebug; private: - SdlSurface Surf_SelectBox; std::vector> Entries; Position pos_; Extent size_; @@ -30,9 +28,7 @@ class CSelectBox std::unique_ptr ScrollUpButton; std::unique_ptr ScrollDownButton; Uint16 last_text_pos_y = 10; - // we need this to say the window if it needs to render, otherwise no chiffre are shown bool rendered = false; - bool needRender = true; public: CSelectBox(Position pos, Extent size, FontSize fontsize = FontSize::Large, FontColor text_color = FontColor::Yellow, @@ -42,18 +38,9 @@ class CSelectBox bool hasRendered(); void setMouseData(SDL_MouseButtonEvent button); void setMouseData(SDL_MouseMotionEvent motion); - bool render(); - SdlSurface& getSurface() - { - render(); - return Surf_SelectBox; - } + void Draw(Position parentOrigin); void setColor(int color); - void setTextColor(FontColor color) - { - text_color = color; - needRender = true; - } + void setTextColor(FontColor color) { text_color = color; } void addOption(const std::string& string, std::function callback = nullptr, int param = 0); void setSize(Extent size); void setPos(Position pos); diff --git a/CIO/CTextfield.cpp b/CIO/CTextfield.cpp index 81a7c49..1c7e2fa 100644 --- a/CIO/CTextfield.cpp +++ b/CIO/CTextfield.cpp @@ -4,10 +4,12 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "CTextfield.h" -#include "../CSurface.h" +#include "../Texture.h" #include "../globals.h" #include "CFont.h" #include "CollisionDetection.h" +#include +#include CTextfield::CTextfield(Position pos, Uint16 cols, Uint16 rows, FontSize fontsize, FontColor text_color, int bg_color, bool button_style) @@ -24,7 +26,6 @@ CTextfield::CTextfield(Position pos, Uint16 cols, Uint16 rows, FontSize fontsize // allocate memory for the text: chiffres (cols) + '\n' for each line * rows + blinking chiffre + '\0' text_.resize((this->cols + 1) * this->rows + 2); - needRender = true; rendered = false; this->button_style = button_style; textObj = std::make_unique("", pos, fontsize, text_color); @@ -89,14 +90,11 @@ void CTextfield::setColor(int color) pic_background = -1; break; } - - needRender = true; } void CTextfield::setTextColor(FontColor color) { textObj->setColor(color); - needRender = true; } void CTextfield::setX(int x) @@ -145,10 +143,9 @@ void CTextfield::setMouseData(SDL_MouseButtonEvent button) // if mouse button is pressed ON the textfield, set active=true if(button.state == SDL_PRESSED) { - active = IsPointInRect(Position(button.x, button.y), Rect(Position(getX(), getY()), size_)); + active = IsPointInRect(button.x, button.y, Rect(Position(getX(), getY()), size_)); } } - needRender = true; } void CTextfield::setKeyboardData(const SDL_KeyboardEvent& key) @@ -239,213 +236,83 @@ void CTextfield::setKeyboardData(const SDL_KeyboardEvent& key) } break; } - needRender = true; } } -bool CTextfield::render() +void CTextfield::Draw(Position parentOrigin) { - // position in the Surface 'Surf_Text' - Position pos{0, 0}; - // width and height of the picture tile - Extent pic{0, 0}; - // we save the time to let a chiffre blink - static Uint32 currentTime; - static Uint32 lastTime = SDL_GetTicks(); - static bool blinking_chiffre = false; - // if the textfield is active, we need to render to show the blinking chiffre + const Position absPos = parentOrigin + Position(getX(), getY()); + const Rect area(absPos, size_); + + // Update cursor blink state + static Uint32 lastTime = 0; // Shared timer is OK here if(active) { - currentTime = SDL_GetTicks(); + const Uint32 currentTime = SDL_GetTicks(); + if(lastTime == 0) + lastTime = currentTime; if(currentTime - lastTime > 500) { lastTime = currentTime; - blinking_chiffre = !blinking_chiffre; } - needRender = true; - } - - // if we don't need to render, all is up to date, return true - if(!needRender) - return true; - needRender = false; - // if we need a new surface - if(!Surf_Text) + } else { - Surf_Text = makeRGBSurface(size_.x, size_.y); - if(!Surf_Text) - return false; + blinking_chiffre = false; } - // draw the pictures for background and foreground or, if not set, fill with black color + // Ensure rendered flag is cleared each frame + rendered = false; + + // Draw the background / foreground if(pic_background >= 0 && pic_foreground >= 0) { - // in case the textfield should look like a button, we do it, otherwise we use pic_foreground for the background const int bmpIdx = button_style ? pic_background : pic_foreground; + drawTiledBmp(bmpIdx, area); - // at first completly fill the background (not the fastest way, but simplier) - if(size_.x <= global::bmpArray[bmpIdx].w) - pic.x = size_.x; - else - pic.x = global::bmpArray[bmpIdx].w; - - if(size_.y <= global::bmpArray[bmpIdx].h) - pic.y = size_.y; - else - pic.y = global::bmpArray[bmpIdx].h; - - while(pos.x + pic.x <= static_cast(Surf_Text->w)) - { - while(pos.y + pic.y <= static_cast(Surf_Text->h)) - { - CSurface::Draw(Surf_Text, global::bmpArray[bmpIdx].surface, pos, Position(0, 0), pic); - pos.y += pic.y; - } - - if(pos.y < Surf_Text->h) - CSurface::Draw(Surf_Text, global::bmpArray[bmpIdx].surface, pos.x, pos.y, 0, 0, pic.x, - static_cast(Surf_Text->h - pos.y)); - - pos.y = 0; - pos.x += pic.x; - } - - if(pos.x < Surf_Text->w) - { - while(pos.y + pic.y <= static_cast(Surf_Text->h)) - { - CSurface::Draw(Surf_Text, global::bmpArray[bmpIdx].surface, pos.x, pos.y, 0, 0, - static_cast(Surf_Text->w - pos.x), pic.y); - pos.y += pic.y; - } - - if(pos.y < Surf_Text->h) - CSurface::Draw(Surf_Text, global::bmpArray[bmpIdx].surface, pos.x, pos.y, 0, 0, - static_cast(Surf_Text->w - pos.x), - static_cast(Surf_Text->h - pos.y)); - } - - // if not button_style, we are finished, otherwise continue drawing if(button_style) { - // draw partial black frame + // Draw black frame (2px) using filled rectangles + const int w = area.right - area.left; + const int h = area.bottom - area.top; + if(active) { - // black frame is left and up - // draw vertical line - for(unsigned y = 0; y < size_.y; y++) - CSurface::DrawPixel_RGB(Surf_Text, Position(0, y), 0, 0, 0); - - // draw vertical line - for(unsigned y = 0; y < size_.y - 1; y++) - CSurface::DrawPixel_RGB(Surf_Text, Position(1, y), 0, 0, 0); - - // draw horizontal line - for(unsigned x = 0; x < size_.x; x++) - CSurface::DrawPixel_RGB(Surf_Text, Position(x, 0), 0, 0, 0); - - // draw horizontal line - for(unsigned x = 0; x < size_.x - 1; x++) - CSurface::DrawPixel_RGB(Surf_Text, Position(x, 1), 0, 0, 0); + // Black frame is left and up + DrawRect(Rect(area.left, area.top, 2, h), 0, 0, 0); + DrawRect(Rect(area.left, area.top, w, 2), 0, 0, 0); } else { - // black frame is right and down - // draw vertical line - for(unsigned y = 0; y < size_.y; y++) - CSurface::DrawPixel_RGB(Surf_Text, Position(size_.x - 1, y), 0, 0, 0); - - // draw vertical line - for(unsigned y = 1; y < size_.y; y++) - CSurface::DrawPixel_RGB(Surf_Text, Position(size_.x - 2, y), 0, 0, 0); - - // draw horizontal line - for(unsigned x = 0; x < size_.x; x++) - CSurface::DrawPixel_RGB(Surf_Text, Position(x, size_.y - 1), 0, 0, 0); - - // draw horizontal line - for(unsigned x = 1; x < size_.x; x++) - CSurface::DrawPixel_RGB(Surf_Text, Position(x, size_.y - 2), 0, 0, 0); - } - - // draw the foreground --> at first the color (marked or unmarked) and then the picture or text - if(size_.x <= global::bmpArray[pic_foreground].w) - pic.x = size_.x; - else - pic.x = global::bmpArray[pic_foreground].w; - - if(size_.y <= global::bmpArray[pic_foreground].h) - pic.y = size_.y; - else - pic.y = global::bmpArray[pic_foreground].h; - - // beware overdrawing the left and upper frame - pos.x = 2; - pos.y = 2; - - // '-2' follows a few times, this means: beware overdrawing the right and lower frame - while(pos.x + pic.x <= static_cast(Surf_Text->w - 2)) - { - while(pos.y + pic.y <= static_cast(Surf_Text->h - 2)) - { - CSurface::Draw(Surf_Text, global::bmpArray[pic_foreground].surface, pos.x, pos.y, 0, 0, pic.x, - pic.y); - pos.y += pic.y; - } - - if(pos.y + 2 < Surf_Text->h) - CSurface::Draw(Surf_Text, global::bmpArray[pic_foreground].surface, pos.x, pos.y, 0, 0, pic.x, - static_cast(Surf_Text->h - 2 - pos.y)); - - pos.y = 2; - pos.x += pic.x; + // Black frame is right and down + DrawRect(Rect(area.right - 2, area.top, 2, h), 0, 0, 0); + DrawRect(Rect(area.left, area.bottom - 2, w, 2), 0, 0, 0); } - if(pos.x + 2 < Surf_Text->w) - { - while(pos.y + pic.y <= static_cast(Surf_Text->h - 2)) - { - CSurface::Draw(Surf_Text, global::bmpArray[pic_foreground].surface, pos.x, pos.y, 0, 0, - static_cast(Surf_Text->w - 2 - pos.x), pic.y); - pos.y += pic.y; - } - - if(pos.y + 2 < Surf_Text->h) - CSurface::Draw(Surf_Text, global::bmpArray[pic_foreground].surface, pos.x, pos.y, 0, 0, - static_cast(Surf_Text->w - 2 - pos.x), - static_cast(Surf_Text->h - 2 - pos.y)); - } + // Draw foreground (inset by 2px) + const Rect fgRect(area.getOrigin() + Position(2, 2), size_ - Extent(4, 4)); + drawTiledBmp(pic_foreground, fgRect); } } else - SDL_FillRect(Surf_Text.get(), nullptr, SDL_MapRGB(Surf_Text->format, 0, 0, 0)); - - char* txtPtr = text_.data(); - - // go to '\0' - while(*txtPtr != '\0') - txtPtr++; - // add blinking chiffre if necessary - if(blinking_chiffre && active) { - *txtPtr = '>'; - txtPtr++; - *txtPtr = '\0'; + // Fill with black + DrawRect(area, 0, 0, 0, 255); } - // write text - textObj->setText(text_.data()); + // Prepare text with cursor + std::string displayText = text_.data(); - // delete blinking chiffre (otherwise it could be written between user input chiffres) + // Add blinking cursor if active if(blinking_chiffre && active) { - txtPtr--; - *txtPtr = '\0'; + displayText += '>'; } - // blit text surface - CSurface::Draw(Surf_Text, textObj->getSurface(), 2, 2); + // Draw the text + if(!displayText.empty()) + { + textObj->setText(displayText); + textObj->Draw(Position(area.left + 2, area.top + 2)); + } rendered = true; - - return true; } diff --git a/CIO/CTextfield.h b/CIO/CTextfield.h index 73761b1..2a3c9d8 100644 --- a/CIO/CTextfield.h +++ b/CIO/CTextfield.h @@ -7,6 +7,7 @@ #include "defines.h" #include +#include #include class CFont; @@ -16,9 +17,7 @@ class CTextfield friend class CDebug; private: - SdlSurface Surf_Text; std::unique_ptr textObj; - bool needRender; Extent size_; Uint16 cols; Uint16 rows; @@ -31,6 +30,8 @@ class CTextfield bool rendered; // if true, the textfield looks like a button bool button_style; + // Cursor blink state + bool blinking_chiffre = false; public: // Constructor - Destructor @@ -51,12 +52,7 @@ class CTextfield bool hasRendered(); void setMouseData(SDL_MouseButtonEvent button); void setKeyboardData(const SDL_KeyboardEvent& key); - bool render(); - SDL_Surface* getSurface() - { - render(); - return Surf_Text.get(); - } + void Draw(Position parentOrigin); void setColor(int color); void setTextColor(FontColor color); std::string getText() const { return text_.data(); } diff --git a/CIO/CWindow.cpp b/CIO/CWindow.cpp index ec4fa36..5d9d575 100644 --- a/CIO/CWindow.cpp +++ b/CIO/CWindow.cpp @@ -5,7 +5,7 @@ #include "CWindow.h" #include "../CGame.h" -#include "../CSurface.h" +#include "../Texture.h" #include "../globals.h" #include "CButton.h" #include "CFont.h" @@ -14,6 +14,7 @@ #include "CTextfield.h" #include "CollisionDetection.h" #include "helpers/containerUtils.h" +#include #include CWindow::CWindow(void callback(int), int callbackQuitMessage, Position pos, Extent size, const char* title, int color, @@ -24,15 +25,6 @@ CWindow::CWindow(void callback(int), int callbackQuitMessage, Position pos, Exte callbackQuitMessage(callbackQuitMessage) { assert(callback); - // ensure window is big enough to take all basic pictures needed - // if ( w < (global::bmpArray[WINDOW_LEFT_UPPER_CORNER].w + global::bmpArray[WINDOW_UPPER_FRAME].w + - // global::bmpArray[WINDOW_RIGHT_UPPER_CORNER].w) ) - // this->w = global::bmpArray[WINDOW_LEFT_UPPER_CORNER].w + global::bmpArray[WINDOW_UPPER_FRAME].w + - // global::bmpArray[WINDOW_RIGHT_UPPER_CORNER].w; - // else - // if ( h < (global::bmpArray[WINDOW_UPPER_FRAME].h + global::bmpArray[WINDOW_CORNER_RECTANGLE].h) ) - // this->h = global::bmpArray[WINDOW_UPPER_FRAME].h + global::bmpArray[WINDOW_CORNER_RECTANGLE].h; - // else canMove = (flags & WINDOW_MOVE) != 0; canClose = (flags & WINDOW_CLOSE) != 0; canMinimize = (flags & WINDOW_MINIMIZE) != 0; @@ -57,7 +49,6 @@ CWindow::CWindow(void callback(int), int callbackQuitMessage, WindowPos pos, Ext void CWindow::setTitle(const char* title) { this->title = title; - needRender = true; } void CWindow::setColor(int color) @@ -76,7 +67,7 @@ void CWindow::setMouseData(SDL_MouseMotionEvent motion) const Position titleFrameLT = Position(x_, y_) + Position(global::bmpArray[WINDOW_LEFT_UPPER_CORNER].w + 2, 4); const Position titleFrameRB = Position(x_ + w_ - global::bmpArray[WINDOW_RIGHT_UPPER_CORNER].w - 2, y_ + global::bmpArray[WINDOW_UPPER_FRAME].h - 4); - if(IsPointInRect(Position(motion.x, motion.y), Rect(titleFrameLT, Extent(titleFrameRB - titleFrameLT)))) + if(IsPointInRect(motion.x, motion.y, Rect(titleFrameLT, Extent(titleFrameRB - titleFrameLT)))) { // left button was pressed while moving if(clicked) @@ -144,9 +135,6 @@ void CWindow::setMouseData(SDL_MouseMotionEvent motion) // MISSING: we have to test if window size is under minimum - // the window has resized, so we need a new surface - surface.reset(); - // notify the callback that the window has been resized callback_(WINDOW_RESIZED_CALL); } @@ -154,7 +142,7 @@ void CWindow::setMouseData(SDL_MouseMotionEvent motion) } // deliver mouse data to the content objects of the window (if mouse cursor is inside the window) - if(IsPointInRect(Position(motion.x, motion.y), Rect(getPos(), getSize()))) + if(IsPointInRect(motion.x, motion.y, Rect(getPos(), getSize()))) { // IMPORTANT: we use the left upper corner of the window as (x,y)=(0,0), so we have to manipulate // the motion-structure before give it to buttons, pictures....: x_absolute - x_window, y_absolute - @@ -163,8 +151,6 @@ void CWindow::setMouseData(SDL_MouseMotionEvent motion) motion.y -= y_; CControlContainer::setMouseData(motion); } - - needRender = true; } void CWindow::setMouseData(SDL_MouseButtonEvent button) @@ -195,7 +181,7 @@ void CWindow::setMouseData(SDL_MouseButtonEvent button) clicked = true; } // pressed inside the window - if((button.state == SDL_PRESSED) && (button.x >= x_) && (button.x <= x_ + w_) && (button.y >= y_) + if(button.state == SDL_PRESSED && (button.x >= x_) && (button.x <= x_ + w_) && (button.y >= y_) && (button.y <= y_ + h_)) marked = true; // else pressed outside of the window @@ -230,14 +216,10 @@ void CWindow::setMouseData(SDL_MouseButtonEvent button) if(minimized) // maximize now { h_ = maximized_h; - // the window has resized, so we need a new surface - surface.reset(); minimized = false; } else // minimize now { h_ = global::bmpArray[WINDOW_UPPER_FRAME].h + global::bmpArray[WINDOW_CORNER_RECTANGLE].h; - // the window has resized, so we need a new surface - surface.reset(); minimized = true; } } @@ -251,7 +233,7 @@ void CWindow::setMouseData(SDL_MouseButtonEvent button) } // deliver mouse data to the content objects of the window (if mouse cursor is inside the window) - if(IsPointInRect(Position(button.x, button.y), Rect(getPos(), getSize()))) + if(IsPointInRect(button.x, button.y, Rect(getPos(), getSize()))) { // IMPORTANT: we use the left upper corner of the window as (x,y)=(0,0), so we have to manipulate // the motion-structure before give it to buttons, pictures....: x_absolute - x_window, y_absolute - @@ -263,85 +245,42 @@ void CWindow::setMouseData(SDL_MouseButtonEvent button) // at least call the callback callback_(WINDOW_CLICKED_CALL); - - needRender = true; } -bool CWindow::render() +// --------------------------------------------------------------------------- +// Draw — OpenGL version of the old render() +// --------------------------------------------------------------------------- + +void CWindow::Draw(Position /*parentOrigin*/) { - // position in the Surface 'surface' - Position pos = {0, 0}; - // width and height of the window background color source picture - Uint16 pic_w = 0; - Uint16 pic_h = 0; - // upper frame (can be marked, clicked or normal) - int upperframe; - // close button (can be marked, clicked or normal) - int closebutton = WINDOW_BUTTON_CLOSE; - // minimize button (can be marked, clicked or normal) - int minimizebutton = WINDOW_BUTTON_MINIMIZE; - // resize button (can be marked, clicked or normal) - int resizebutton = WINDOW_BUTTON_RESIZE; - - // test if a textfield has changed - needRender |= helpers::contains_if(getTextFields(), [](const auto& textfield) { return textfield->hasRendered(); }); - - // if we don't need to render, all is up to date, return true - if(!needRender) - return true; - needRender = false; - // if we need a new surface - if(!surface) - { - if(!(surface = makeRGBSurface(w_, h_))) - return false; - } + const Position origin(x_, y_); + const Rect winRect(origin, Extent(w_, h_)); - // at first completly fill the background (not the fastest way, but simpler) + // 1. Background fill (tiled) if(getBackground() != WINDOW_NOTHING) - { - pic_w = std::min(w_, global::bmpArray[getBackground()].w); - pic_h = std::min(h_, global::bmpArray[getBackground()].h); - - while(pos.x + pic_w <= surface->w) - { - while(pos.y + pic_h <= surface->h) - { - CSurface::Draw(surface.get(), global::bmpArray[getBackground()].surface, pos.x, pos.y, 0, 0, pic_w, - pic_h); - pos.y += pic_h; - } + drawTiledBmp(getBackground(), winRect); - if(surface->h - pos.y > 0) - CSurface::Draw(surface.get(), global::bmpArray[getBackground()].surface, pos.x, pos.y, 0, 0, pic_w, - surface->h - pos.y); - - pos.y = 0; - pos.x += pic_w; - } - - if(surface->w - pos.x > 0) - { - while(pos.y + pic_h <= surface->h) - { - CSurface::Draw(surface.get(), global::bmpArray[getBackground()].surface, pos.x, pos.y, 0, 0, - surface->w - pos.x, pic_h); - pos.y += pic_h; - } - - if(surface->h - pos.y > 0) - CSurface::Draw(surface.get(), global::bmpArray[getBackground()].surface, pos.x, pos.y, 0, 0, - surface->w - pos.x, surface->h - pos.y); - } - } - - // if not minimized, draw the content now (this stands here to prevent the frames and corners from being overdrawn) + // 2. Content (if not minimized) — clipped to the area inside frames if(!minimized) { - renderElements(); + const auto viewH = global::s2->getRes().y; + const auto contentX = origin.x + static_cast(getBorderBegin().x); + const auto contentY = origin.y + static_cast(getBorderBegin().y); + const auto contentW = + static_cast(w_) - static_cast(getBorderBegin().x) - static_cast(getBorderEnd().x); + const auto contentH = + static_cast(h_) - static_cast(getBorderBegin().y) - static_cast(getBorderEnd().y); + if(contentW > 0 && contentH > 0) + { + glEnable(GL_SCISSOR_TEST); + glScissor(contentX, viewH - (contentY + contentH), contentW, contentH); + DrawChildren(origin); + glDisable(GL_SCISSOR_TEST); + } } - // now draw the upper frame to the top + // 3. Upper frame (state depends on marked/clicked) + int upperframe; if(clicked) upperframe = WINDOW_UPPER_FRAME_CLICKED; else if(marked) @@ -349,110 +288,117 @@ bool CWindow::render() else upperframe = WINDOW_UPPER_FRAME; - pic_w = std::min(w_, global::bmpArray[upperframe].w); - - pos.x = 0; - pos.y = 0; - while(pos.x + pic_w <= surface->w) + // Draw upper frame tile across the top of the window { - CSurface::Draw(surface, global::bmpArray[upperframe].surface, pos); - pos.x += pic_w; + const auto& bmp = global::bmpArray[upperframe]; + const Rect upperFrameRect(origin, Extent(w_, bmp.h)); + drawTiledBmp(upperframe, upperFrameRect); } - if(surface->w - pos.x > 0) - CSurface::Draw(surface.get(), global::bmpArray[upperframe].surface, pos.x, pos.y, 0, 0, surface->w - pos.x, - pic_h); - // write text in the upper frame + // 4. Title text if(title) - CFont::writeText(surface.get(), title, (int)w_ / 2, (int)((global::bmpArray[WINDOW_UPPER_FRAME].h - 9) / 2), - FontSize::Small, FontColor::Yellow, FontAlign::Middle); - - // now draw the other frames (left, right, down) - // down - pic_w = std::min(w_, global::bmpArray[WINDOW_LOWER_FRAME].w); - pic_h = global::bmpArray[WINDOW_LOWER_FRAME].h; - pos.x = 0; - pos.y = h_ - global::bmpArray[WINDOW_LOWER_FRAME].h; - while(pos.x + pic_w <= surface->w) { - CSurface::Draw(surface, global::bmpArray[WINDOW_LOWER_FRAME].surface, pos); - pos.x += pic_w; + const int titleY = origin.y + (static_cast(global::bmpArray[WINDOW_UPPER_FRAME].h) - 9) / 2; + CFont::Draw(title, Position(origin.x + static_cast(w_) / 2, titleY), FontSize::Small, FontColor::Yellow, + FontAlign::Middle); + } + + // 5. Lower frame (tiled across bottom) + { + const auto& bmp = global::bmpArray[WINDOW_LOWER_FRAME]; + const Rect lowerFrameRect(Position(origin.x, origin.y + static_cast(h_) - static_cast(bmp.h)), + Extent(w_, bmp.h)); + drawTiledBmp(WINDOW_LOWER_FRAME, lowerFrameRect); + } + + // 6. Left frame (tiled down left side) + { + const auto& bmp = global::bmpArray[WINDOW_LEFT_FRAME]; + const Rect leftFrameRect(origin, Extent(bmp.w, h_)); + drawTiledBmp(WINDOW_LEFT_FRAME, leftFrameRect); } - if(surface->w - pos.x > 0) - CSurface::Draw(surface.get(), global::bmpArray[WINDOW_LOWER_FRAME].surface, pos.x, pos.y, 0, 0, - surface->w - pos.x, pic_h); - // left - pic_h = std::min(h_, global::bmpArray[WINDOW_LEFT_FRAME].h); - pos.x = 0; - pos.y = 0; - while(pos.y + pic_h <= surface->h) + + // 7. Right frame (tiled down right side) { - CSurface::Draw(surface, global::bmpArray[WINDOW_LEFT_FRAME].surface, pos); - pos.y += pic_h; + const auto& bmp = global::bmpArray[WINDOW_RIGHT_FRAME]; + const Rect rightFrameRect(Position(origin.x + static_cast(w_) - static_cast(bmp.w), origin.y), + Extent(bmp.w, h_)); + drawTiledBmp(WINDOW_RIGHT_FRAME, rightFrameRect); } - if(surface->w - pos.x > 0) - CSurface::Draw(surface.get(), global::bmpArray[WINDOW_LEFT_FRAME].surface, pos.x, pos.y, 0, 0, - surface->w - pos.x, pic_h); - // right - pic_h = std::min(h_, global::bmpArray[WINDOW_RIGHT_FRAME].h); - pos.x = w_ - global::bmpArray[WINDOW_RIGHT_FRAME].w; - pos.y = 0; - while(pos.y + pic_h <= surface->h) + + // 8. Corners { - CSurface::Draw(surface, global::bmpArray[WINDOW_RIGHT_FRAME].surface, pos); - pos.y += pic_h; + auto& texLU = getBmpTexture(WINDOW_LEFT_UPPER_CORNER); + if(texLU.isValid()) + texLU.Draw(origin); + + auto& texRU = getBmpTexture(WINDOW_RIGHT_UPPER_CORNER); + if(texRU.isValid()) + { + const auto& ruBmp = global::bmpArray[WINDOW_RIGHT_UPPER_CORNER]; + texRU.Draw(Position(origin.x + static_cast(w_) - static_cast(ruBmp.w), origin.y)); + } + + auto& texCR = getBmpTexture(WINDOW_CORNER_RECTANGLE); + if(texCR.isValid()) + { + const auto& crBmp = global::bmpArray[WINDOW_CORNER_RECTANGLE]; + texCR.Draw(Position(origin.x, origin.y + static_cast(h_) - static_cast(crBmp.h))); + texCR.Draw(Position(origin.x + static_cast(w_) - static_cast(crBmp.w), + origin.y + static_cast(h_) - static_cast(crBmp.h))); + } } - if(surface->w - pos.x > 0) - CSurface::Draw(surface.get(), global::bmpArray[WINDOW_RIGHT_FRAME].surface, pos.x, pos.y, 0, 0, - surface->w - pos.x, pic_h); - - // now draw the corners - CSurface::Draw(surface, global::bmpArray[WINDOW_LEFT_UPPER_CORNER].surface); - CSurface::Draw(surface, global::bmpArray[WINDOW_RIGHT_UPPER_CORNER].surface, - Position(w_ - global::bmpArray[WINDOW_RIGHT_UPPER_CORNER].w, 0)); - CSurface::Draw(surface, global::bmpArray[WINDOW_CORNER_RECTANGLE].surface, - Position(0, h_ - global::bmpArray[WINDOW_CORNER_RECTANGLE].h)); - CSurface::Draw( - surface, global::bmpArray[WINDOW_CORNER_RECTANGLE].surface, - Position(w_ - global::bmpArray[WINDOW_CORNER_RECTANGLE].w, h_ - global::bmpArray[WINDOW_CORNER_RECTANGLE].h)); - // now the corner buttons - // close + + // 9. Close button if(canClose) { + int closebutton; if(canClose_clicked) closebutton = WINDOW_BUTTON_CLOSE_CLICKED; else if(canClose_marked) closebutton = WINDOW_BUTTON_CLOSE_MARKED; else closebutton = WINDOW_BUTTON_CLOSE; - CSurface::Draw(surface, global::bmpArray[closebutton].surface); + auto& tex = getBmpTexture(closebutton); + if(tex.isValid()) + tex.Draw(origin); } - // minimize + + // 10. Minimize button if(canMinimize) { + int minimizebutton; if(canMinimize_clicked) minimizebutton = WINDOW_BUTTON_MINIMIZE_CLICKED; else if(canMinimize_marked) minimizebutton = WINDOW_BUTTON_MINIMIZE_MARKED; else minimizebutton = WINDOW_BUTTON_MINIMIZE; - CSurface::Draw(surface, global::bmpArray[minimizebutton].surface, - Position(w_ - global::bmpArray[minimizebutton].w, 0)); + auto& tex = getBmpTexture(minimizebutton); + if(tex.isValid()) + { + const auto& bmp = global::bmpArray[minimizebutton]; + tex.Draw(Position(origin.x + static_cast(w_) - static_cast(bmp.w), origin.y)); + } } - // resize + + // 11. Resize button if(canResize) { + int resizebutton; if(canResize_clicked) resizebutton = WINDOW_BUTTON_RESIZE_CLICKED; else if(canResize_marked) resizebutton = WINDOW_BUTTON_RESIZE_MARKED; else resizebutton = WINDOW_BUTTON_RESIZE; - CSurface::Draw(surface, global::bmpArray[resizebutton].surface, - Position(w_, h_) - global::bmpArray[resizebutton].getSize()); + auto& tex = getBmpTexture(resizebutton); + if(tex.isValid()) + { + const auto& bmp = global::bmpArray[resizebutton]; + tex.Draw(Position(origin + Position(w_, h_)) - Position(static_cast(bmp.w), static_cast(bmp.h))); + } } - - return true; } void CWindow::setInactive() @@ -460,7 +406,6 @@ void CWindow::setInactive() active = false; clicked = false; marked = false; - needRender = true; for(auto& textfield : getTextFields()) { diff --git a/CIO/CWindow.h b/CIO/CWindow.h index 2faf97e..a236853 100644 --- a/CIO/CWindow.h +++ b/CIO/CWindow.h @@ -16,13 +16,16 @@ class CWindow : public CControlContainer { friend class CDebug; -private: // if active is false, the window will be render behind the active windows within the game loop bool active = true; + +protected: Sint16 x_; Sint16 y_; Uint16 w_; Uint16 h_; + +private: const char* title; bool marked = true; bool clicked = false; @@ -43,10 +46,10 @@ class CWindow : public CControlContainer void (*callback_)(int); int callbackQuitMessage; -protected: - bool render() override; - public: + /// Draw the window using OpenGL (chrome + children). + void Draw(Position parentOrigin) override; + CWindow(void callback(int), int callbackQuitMessage, Position pos, Extent size, const char* title = nullptr, int color = WINDOW_GREEN1, Uint8 flags = 0); CWindow(void callback(int), int callbackQuitMessage, WindowPos pos, Extent size, const char* title = nullptr, @@ -68,14 +71,13 @@ class CWindow : public CControlContainer { active = true; marked = true; - needRender = true; } void setInactive(); bool isActive() const { return active; } bool isMoving() const { return moving; } bool isResizing() const { return resizing; } bool isMarked() const { return marked; } - void setDirty() { needRender = true; } + void setDirty() {} // we can not trust this information, cause if minimized is false, it is possible, that we still have the old // minimized surface bool isMinimized() { return minimized; }; we need an information if a input-element (textfield // etc.) is active to not deliver the input to other gui-element in the event system diff --git a/Texture.cpp b/Texture.cpp index 5064573..1c64a61 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -3,10 +3,18 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "Texture.h" +#include "defines.h" +#include "globals.h" #include +#include +#include #include #include +// --------------------------------------------------------------------------- +// Texture +// --------------------------------------------------------------------------- + Texture::~Texture() { if(texture_) @@ -115,15 +123,19 @@ void Texture::Draw(const Rect& destRect) const if(!texture_) return; + const float uScale = 1.0f; + const float vScale = 1.0f; + + glColor4f(1, 1, 1, 1); glBindTexture(GL_TEXTURE_2D, texture_); glBegin(GL_QUADS); glTexCoord2f(0, 0); glVertex2i(destRect.left, destRect.top); - glTexCoord2f(1, 0); + glTexCoord2f(uScale, 0); glVertex2i(destRect.right, destRect.top); - glTexCoord2f(1, 1); + glTexCoord2f(uScale, vScale); glVertex2i(destRect.right, destRect.bottom); - glTexCoord2f(0, 1); + glTexCoord2f(0, vScale); glVertex2i(destRect.left, destRect.bottom); glEnd(); } @@ -133,6 +145,7 @@ void Texture::Draw(Position pos) const if(!texture_) return; + glColor4f(1, 1, 1, 1); glBindTexture(GL_TEXTURE_2D, texture_); glBegin(GL_QUADS); glTexCoord2f(0, 0); @@ -145,3 +158,143 @@ void Texture::Draw(Position pos) const glVertex2i(pos.x, pos.y + size_.y); glEnd(); } + +void Texture::Draw(const Rect& destRect, const Rect& srcRect) const +{ + if(!texture_) + return; + + // Clamp source rect to texture bounds + int srcL = std::max(0, srcRect.left); + int srcT = std::max(0, srcRect.top); + int srcR = std::min(static_cast(size_.x), srcRect.right); + int srcB = std::min(static_cast(size_.y), srcRect.bottom); + if(srcL >= srcR || srcT >= srcB) + return; + + const float u0 = float(srcL) / float(size_.x); + const float v0 = float(srcT) / float(size_.y); + const float u1 = float(srcR) / float(size_.x); + const float v1 = float(srcB) / float(size_.y); + + glBindTexture(GL_TEXTURE_2D, texture_); + glBegin(GL_QUADS); + glTexCoord2f(u0, v0); + glVertex2i(destRect.left, destRect.top); + glTexCoord2f(u1, v0); + glVertex2i(destRect.right, destRect.top); + glTexCoord2f(u1, v1); + glVertex2i(destRect.right, destRect.bottom); + glTexCoord2f(u0, v1); + glVertex2i(destRect.left, destRect.bottom); + glEnd(); +} + +// --------------------------------------------------------------------------- +// DrawRect / DrawLine helpers +// --------------------------------------------------------------------------- + +void DrawRect(const Rect& rect, unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + glDisable(GL_TEXTURE_2D); + glColor4ub(r, g, b, a); + glBegin(GL_QUADS); + glVertex2i(rect.left, rect.top); + glVertex2i(rect.right, rect.top); + glVertex2i(rect.right, rect.bottom); + glVertex2i(rect.left, rect.bottom); + glEnd(); + glEnable(GL_TEXTURE_2D); +} + +void DrawRect(const Rect& rect, unsigned color) +{ + DrawRect(rect, (color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF, (color >> 24) & 0xFF); +} + +void DrawLine(Position p1, Position p2, unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + glDisable(GL_TEXTURE_2D); + glColor4ub(r, g, b, a); + glBegin(GL_LINES); + glVertex2i(p1.x, p1.y); + glVertex2i(p2.x, p2.y); + glEnd(); + glEnable(GL_TEXTURE_2D); +} + +// --------------------------------------------------------------------------- +// Texture-drawing helpers +// --------------------------------------------------------------------------- + +Texture& getBmpTexture(int idx, bool filterLinear) +{ + static std::vector> cache; + static std::vector linearFlags; + if(idx < 0 || idx >= static_cast(global::bmpArray.size())) + { + static Texture dummy; + return dummy; + } + if(static_cast(cache.size()) <= idx) + { + cache.resize(idx + 1); + linearFlags.resize(idx + 1, false); + } + if(!cache[idx] || linearFlags[idx] != filterLinear) + { + if(!cache[idx]) + cache[idx] = std::make_unique(); + linearFlags[idx] = filterLinear; + auto& bmp = global::bmpArray[idx]; + if(bmp.surface) + cache[idx]->load(bmp.surface.get(), filterLinear); + } + return *cache[idx]; +} + +void ensureBmpTex(int idx) +{ + if(idx < 0 || idx >= static_cast(global::bmpArray.size())) + return; + getBmpTexture(idx); +} + +void drawTiledBmp(int bmpIdx, const Rect& destRect) +{ + if(bmpIdx < 0 || bmpIdx >= static_cast(global::bmpArray.size())) + return; + auto& tex = getBmpTexture(bmpIdx); + if(!tex.isValid()) + return; + + const auto& bmp = global::bmpArray[bmpIdx]; + const unsigned tileW = bmp.w; + const unsigned tileH = bmp.h; + if(tileW == 0 || tileH == 0) + return; + + glColor4f(1, 1, 1, 1); + glBindTexture(GL_TEXTURE_2D, tex.getHandle()); + glBegin(GL_QUADS); + for(int y = destRect.top; y < destRect.bottom; y += static_cast(tileH)) + { + const int rowH = std::min(static_cast(tileH), static_cast(destRect.bottom - y)); + const float v1 = static_cast(rowH) / static_cast(tileH); + for(int x = destRect.left; x < destRect.right; x += static_cast(tileW)) + { + const int colW = std::min(static_cast(tileW), static_cast(destRect.right - x)); + const float u1 = static_cast(colW) / static_cast(tileW); + + glTexCoord2f(0, 0); + glVertex2i(x, y); + glTexCoord2f(u1, 0); + glVertex2i(x + colW, y); + glTexCoord2f(u1, v1); + glVertex2i(x + colW, y + rowH); + glTexCoord2f(0, v1); + glVertex2i(x, y + rowH); + } + } + glEnd(); +} diff --git a/Texture.h b/Texture.h index 2d6c26c..33d7419 100644 --- a/Texture.h +++ b/Texture.h @@ -41,6 +41,10 @@ class Texture /// Convenience overload for callers using separate x/y. void Draw(int x, int y) const { Draw(Position(x, y)); } + /// Draw a sub-rectangle of the texture to fill the given destination rect. + /// srcRect is in texture-local coordinates (may be clipped). + void Draw(const Rect& destRect, const Rect& srcRect) const; + /// Returns the raw GL texture name (for use with glBindTexture). unsigned getHandle() const { return texture_; } @@ -60,3 +64,31 @@ class Texture /// Internal: create or recreate texture from raw BGRA pixel data. void load(const void* bgraPixels, Extent size, bool filterLinear); }; + +// --------------------------------------------------------------------------- +// Free functions for simple GL drawing (rect, line) used by UI components. +// --------------------------------------------------------------------------- + +/// Draw a filled rectangle (disables texturing). +void DrawRect(const Rect& rect, unsigned char r, unsigned char g, unsigned char b, unsigned char a = 255); + +/// Draw a filled rectangle with a 32-bit RGBA colour. +void DrawRect(const Rect& rect, unsigned color); + +/// Draw a 1-pixel-wide axis-aligned line (disables texturing). +void DrawLine(Position p1, Position p2, unsigned char r, unsigned char g, unsigned char b, unsigned char a = 255); + +// --------------------------------------------------------------------------- +// Texture-drawing helpers for UI components +// --------------------------------------------------------------------------- + +/// Ensure the OpenGL texture for a bitmap index is loaded from its SDL surface. +void ensureBmpTex(int idx); + +/// Draw a bitmap texture tiled to fill the given rectangle. +void drawTiledBmp(int bmpIdx, const Rect& destRect); + +/// Get or create the cached OpenGL texture for a bitmap index. +/// The texture is loaded from the SDL surface on first access. +/// @param filterLinear Whether to use linear filtering (for scaled backgrounds). +Texture& getBmpTexture(int idx, bool filterLinear = false); diff --git a/callbacks.cpp b/callbacks.cpp index 38ec75b..6c57267 100644 --- a/callbacks.cpp +++ b/callbacks.cpp @@ -54,9 +54,8 @@ void callback::PleaseWait(int Param) // we need to render this window NOW, cause the render loop will do it too late (when the operation // is done and we don't need the "Please wait"-window anymore) { - const auto res = global::s2->getRes(); glClear(GL_COLOR_BUFFER_BIT); - WNDWait->getTexture().Draw(Position(res.x / 2 - 106, res.y / 2 - 35)); + WNDWait->Draw(Position(0, 0)); global::s2->RenderPresent(); } break; diff --git a/include/defines.h b/include/defines.h index 5adf11c..11bc44a 100644 --- a/include/defines.h +++ b/include/defines.h @@ -85,6 +85,8 @@ struct bobBMP SdlSurface surface; }; +class Texture; + // Structure for Bobtype 5 (Palette) struct bobPAL { From 76531bd18aae56cb5333621daa9eceb57cf8f157 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Fri, 3 Jul 2026 20:53:20 +0200 Subject: [PATCH 03/40] drawMinimap --- CIO/CMinimapWindow.cpp | 61 +++++++++++++++++++++++++++++++++--------- CIO/CMinimapWindow.h | 4 +-- CMap.cpp | 51 +++++++++++------------------------ CMap.h | 6 ++++- 4 files changed, 71 insertions(+), 51 deletions(-) diff --git a/CIO/CMinimapWindow.cpp b/CIO/CMinimapWindow.cpp index a91eb0f..3c418cf 100644 --- a/CIO/CMinimapWindow.cpp +++ b/CIO/CMinimapWindow.cpp @@ -7,6 +7,7 @@ #include "../CMap.h" #include "../Texture.h" #include "../globals.h" +#include "CFont.h" void CMinimapWindow::Draw(Position /*parentOrigin*/) { @@ -24,24 +25,58 @@ void CMinimapWindow::Draw(Position /*parentOrigin*/) if(contentW <= 0 || contentH <= 0) return; - // Draw minimap terrain overlay onto a temporary SDL surface, then upload to texture - if(auto* map = global::s2->getMapObj()) + auto* map = global::s2->getMapObj(); + if(!map) + return; + + // Fill pixel buffer with minimap terrain + int num_x = 1, num_y = 1; + map->drawMinimap(pixels_, contentW, contentH, num_x, num_y); + + // Upload to texture and draw + if(!minimapTex_.isValid() || minimapTex_.getWidth() != contentW || minimapTex_.getHeight() != contentH) + minimapTex_.createEmpty(Extent(contentW, contentH)); + minimapTex_.upload(pixels_.data()); + minimapTex_.Draw(Rect(contentX, contentY, contentW, contentH)); + + // Draw player flags and numbers on top + for(int i = 0; i < MAXPLAYERS; i++) { - // Create or resize the minimap surface - if(!minimapSurface_ || minimapSurface_->w != contentW || minimapSurface_->h != contentH) - minimapSurface_ = makeRGBSurface(static_cast(contentW), static_cast(contentH), true); + const auto hqX = map->getPlayerHQx()[i]; + const auto hqY = map->getPlayerHQy()[i]; + if(hqX == 0xFFFF || hqY == 0xFFFF) + continue; - if(minimapSurface_) + const int flagIdx = FLAG_BLUE_DARK + i % 7; + const auto& flagBmp = global::bmpArray[flagIdx]; + auto& flagTex = getBmpTexture(flagIdx); + if(flagTex.isValid()) { - // Clear with transparency - SDL_FillRect(minimapSurface_.get(), nullptr, SDL_MapRGBA(minimapSurface_->format, 0, 0, 0, 0)); + const int fx = contentX + hqX / num_x - static_cast(flagBmp.nx); + const int fy = contentY + hqY / num_y - static_cast(flagBmp.ny); + flagTex.Draw(Position(fx, fy)); + } - // Draw minimap onto the temporary surface - map->drawMinimap(minimapSurface_.get()); + // Player number + CFont::Draw(std::to_string(i + 1), Position(contentX + hqX / num_x, contentY + hqY / num_y), FontSize::Small, + FontColor::MintGreen); + } - // Upload to texture and draw - minimapTex_.load(minimapSurface_.get()); - minimapTex_.Draw(Rect(contentX, contentY, contentW, contentH)); + // Draw the position arrow + { + const int arrowIdx = MAPPIC_ARROWCROSS_ORANGE; + const auto& arrowBmp = global::bmpArray[arrowIdx]; + auto& arrowTex = getBmpTexture(arrowIdx); + if(arrowTex.isValid()) + { + const auto& dispRect = map->getDisplayRect(); + const int ax = contentX + + (dispRect.left + static_cast(dispRect.getSize().x) / 2) / triangleWidth / num_x + - static_cast(arrowBmp.nx); + const int ay = contentY + + (dispRect.top + static_cast(dispRect.getSize().y) / 2) / triangleHeight / num_y + - static_cast(arrowBmp.ny); + arrowTex.Draw(Position(ax, ay)); } } } diff --git a/CIO/CMinimapWindow.h b/CIO/CMinimapWindow.h index 7817e06..dc76cda 100644 --- a/CIO/CMinimapWindow.h +++ b/CIO/CMinimapWindow.h @@ -6,11 +6,11 @@ #include "../Texture.h" #include "CWindow.h" +#include class CMinimapWindow final : public CWindow { - /// Temporary SDL surface for minimap terrain overlay (kept until terrain is also OpenGL) - SdlSurface minimapSurface_; + std::vector pixels_; ///< Pixel buffer for minimap terrain Texture minimapTex_; void Draw(Position parentOrigin) override; diff --git a/CMap.cpp b/CMap.cpp index dd63715..a7e80eb 100644 --- a/CMap.cpp +++ b/CMap.cpp @@ -1328,18 +1328,18 @@ static void getTriangleColor(const bobMAP& map, Uint8 rawTextureId, Sint16& r, S b = 128; } -void CMap::drawMinimap(SDL_Surface* Window) +void CMap::drawMinimap(std::vector& pixels, int w, int h, int& num_x, int& num_y) { - // this variables are needed to reduce the size of minimap-windows of big maps - int num_x = (map->width > 256 ? map->width / 256 : 1); - int num_y = (map->height > 256 ? map->height / 256 : 1); + // Scale factors to keep minimap within a reasonable size + num_x = (map->width > 256 ? map->width / 256 : 1); + num_y = (map->height > 256 ? map->height / 256 : 1); - // make sure the minimap has the same proportions as the "real" map, so scale the same rate + // Keep aspect ratio uniform num_x = (num_x > num_y ? num_x : num_y); - num_y = (num_x > num_y ? num_x : num_y); + num_y = num_x; - // if (Window->w < map->width || Window->h < map->height) - // return; + // Ensure pixel buffer is the right size + pixels.assign(static_cast(w) * h, 0); for(int y = 0; y < map->height; y++) { @@ -1354,9 +1354,12 @@ void CMap::drawMinimap(SDL_Surface* Window) Sint16 r, g, b; getTriangleColor(*map, map->getVertex(x, y).rsuTexture, r, g, b); - Uint32* row = (Uint32*)Window->pixels + (y / num_y + 20) * Window->pitch / 4; //-V206 - //+6 because of the left window frame - Uint32* pixel = row + x / num_x + 6; + const int py = y / num_y; + const int px = x / num_x; + if(py >= h || px >= w) + continue; + + auto& pixel = pixels[static_cast(py) * w + px]; Sint32 vertexLighting = map->getVertex(x, y).i; r = ((r * vertexLighting) >> 16); @@ -1365,32 +1368,10 @@ void CMap::drawMinimap(SDL_Surface* Window) const auto r8 = (Uint8)(r > 255 ? 255 : (r < 0 ? 0 : r)); const auto g8 = (Uint8)(g > 255 ? 255 : (g < 0 ? 0 : g)); const auto b8 = (Uint8)(b > 255 ? 255 : (b < 0 ? 0 : b)); - *pixel = ((r8 << Window->format->Rshift) + (g8 << Window->format->Gshift) + (b8 << Window->format->Bshift)); - } - } - - // draw the player flags - for(int i = 0; i < MAXPLAYERS; i++) - { - if(PlayerHQx[i] != 0xFFFF && PlayerHQy[i] != 0xFFFF) - { - // draw flag - //%7 cause in the original game there are only 7 players and 7 different flags - CSurface::Draw(Window, global::bmpArray[FLAG_BLUE_DARK + i % 7].surface, - 6 + PlayerHQx[i] / num_x - global::bmpArray[FLAG_BLUE_DARK + i % 7].nx, - 20 + PlayerHQy[i] / num_y - global::bmpArray[FLAG_BLUE_DARK + i % 7].ny); - // write player number - CFont::writeText(Window, std::to_string(i + 1), 6 + PlayerHQx[i] / num_x, 20 + PlayerHQy[i] / num_y, - FontSize::Small, FontColor::MintGreen); + // BGRA format: A<<24 | R<<16 | G<<8 | B + pixel = (0xFFu << 24) | (r8 << 16) | (g8 << 8) | b8; } } - - // draw the arrow --> 6px is width of left window frame and 20px is the height of the upper window frame - CSurface::Draw(Window, global::bmpArray[MAPPIC_ARROWCROSS_ORANGE].surface, - 6 + (displayRect.left + displayRect.getSize().x / 2) / triangleWidth / num_x - - global::bmpArray[MAPPIC_ARROWCROSS_ORANGE].nx, - 20 + (displayRect.top + displayRect.getSize().y / 2) / triangleHeight / num_y - - global::bmpArray[MAPPIC_ARROWCROSS_ORANGE].ny); } void CMap::modifyVertex() diff --git a/CMap.h b/CMap.h index 431f2c3..ab6341b 100644 --- a/CMap.h +++ b/CMap.h @@ -161,7 +161,11 @@ class CMap std::string getAuthor() const { return map->getAuthor(); } void setAuthor(const std::string& author) { map->setAuthor(author); } - void drawMinimap(SDL_Surface* Window); + /// Fill a pixel buffer with the minimap terrain view. + /// @param pixels BGRA pixel buffer (w * h entries, 0xAARRGGBB layout). + /// @param w,h Dimensions of the pixel buffer. + /// @param num_x,num_y Output: scaling factors (map coords → pixel coords). + void drawMinimap(std::vector& pixels, int w, int h, int& num_x, int& num_y); void render(); // get and set some variables necessary for cursor behavior void setHexagonMode(bool HexagonMode) From 4332feb57a51fe942cf07b4f1c37b752cf0758d5 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sat, 4 Jul 2026 19:47:04 +0200 Subject: [PATCH 04/40] Obvious review fixes, remove multiline --- CGame_Render.cpp | 6 ++-- CIO/CButton.cpp | 4 +-- CIO/CFont.cpp | 22 ++---------- CIO/CPicture.cpp | 2 -- CIO/CTextfield.cpp | 2 +- CIO/CWindow.cpp | 83 ++++++++++++++++++---------------------------- CIO/CWindow.h | 2 +- CMap.cpp | 1 - Texture.cpp | 28 +++------------- Texture.h | 9 ++--- callbacks.cpp | 11 +++--- 11 files changed, 53 insertions(+), 117 deletions(-) diff --git a/CGame_Render.cpp b/CGame_Render.cpp index f239089..664e3af 100644 --- a/CGame_Render.cpp +++ b/CGame_Render.cpp @@ -79,7 +79,7 @@ void CGame::Render() } } - // render active menus — each draws itself with OpenGL + // render active menus for(auto& Menu : Menus) { if(Menu->isActive()) @@ -117,10 +117,10 @@ void CGame::Render() framesPassedSinceLastFps = 0; lastFpsTick = curTicks; } - // Draw FPS counter directly with OpenGL text rendering + // Draw FPS counter lastFps.Draw(Position(0, 0)); - // ---- Cursor on top of everything ---- + // Cursor on top of everything const auto& cursorImg = Cursor.clicked ? (Cursor.button.right ? cross_ : cursorClicked_) : cursor_; cursorImg.Draw(Cursor.pos); diff --git a/CIO/CButton.cpp b/CIO/CButton.cpp index 19c494f..3c836bc 100644 --- a/CIO/CButton.cpp +++ b/CIO/CButton.cpp @@ -157,9 +157,7 @@ void CButton::Draw(Position parentOrigin) const auto& picTex = getBmpTexture(button_picture); if(picTex.isValid()) { - const auto& picBmp = global::bmpArray[button_picture]; - const Position picPos = - absPos + Position(size_) / 2 - Position(static_cast(picBmp.w), static_cast(picBmp.h)) / 2; + const Position picPos = absPos + size_ / 2 - Position(picTex.getWidth(), picTex.getHeight()) / 2; picTex.Draw(picPos); } } else if(button_text) diff --git a/CIO/CFont.cpp b/CIO/CFont.cpp index 73ebe18..7ed89ad 100644 --- a/CIO/CFont.cpp +++ b/CIO/CFont.cpp @@ -209,14 +209,9 @@ void CFont::Draw(const std::string& string, Position pos, FontSize fontsize, Fon return; // Measure text width for alignment - const unsigned lineHeight = getLineHeight(fontsize); unsigned totalWidth = 0; for(unsigned char c : string) - { - if(c == '\n') - break; totalWidth += getCharWidth(c, fontsize, color); - } // Apply alignment switch(align) @@ -230,13 +225,6 @@ void CFont::Draw(const std::string& string, Position pos, FontSize fontsize, Fon Position curPos = pos; for(unsigned char c : string) { - if(c == '\n') - { - curPos.x = pos.x; - curPos.y += lineHeight; - continue; - } - const unsigned idx = getIndexForChar(c, fontsize, color); if(idx >= global::bmpArray.size()) continue; @@ -249,9 +237,8 @@ void CFont::Draw(const std::string& string, Position pos, FontSize fontsize, Fon } const auto& bmp = global::bmpArray[idx]; - const unsigned charW = bmp.w; - tex.Draw(Rect(curPos.x, curPos.y, charW, bmp.h)); - curPos.x += charW; + tex.Draw(Rect(curPos.x, curPos.y, bmp.w, bmp.h)); + curPos.x += bmp.w; } } @@ -339,10 +326,7 @@ unsigned CFont::getTextWidth(const std::string& string, FontSize fontsize) { unsigned w = 0; for(unsigned char c : string) - { - if(c == '\n') - break; w += getCharWidth(c, fontsize, FontColor::Yellow); // width is same for all colors - } + return w; } diff --git a/CIO/CPicture.cpp b/CIO/CPicture.cpp index b75863e..12bd5f2 100644 --- a/CIO/CPicture.cpp +++ b/CIO/CPicture.cpp @@ -66,8 +66,6 @@ void CPicture::setMouseData(const SDL_MouseButtonEvent& button) void CPicture::Draw(Position parentOrigin) const { - if(picture_ < 0 || picture_ >= static_cast(global::bmpArray.size())) - return; auto& tex = getBmpTexture(picture_); if(!tex.isValid()) return; diff --git a/CIO/CTextfield.cpp b/CIO/CTextfield.cpp index 1c7e2fa..de37a7d 100644 --- a/CIO/CTextfield.cpp +++ b/CIO/CTextfield.cpp @@ -299,7 +299,7 @@ void CTextfield::Draw(Position parentOrigin) } // Prepare text with cursor - std::string displayText = text_.data(); + std::string displayText = getText(); // Add blinking cursor if active if(blinking_chiffre && active) diff --git a/CIO/CWindow.cpp b/CIO/CWindow.cpp index 5d9d575..04917c4 100644 --- a/CIO/CWindow.cpp +++ b/CIO/CWindow.cpp @@ -86,11 +86,10 @@ void CWindow::setMouseData(SDL_MouseMotionEvent motion) x_ = 0; { const auto res = global::s2->getRes(); - const int resW = res.x, resH = res.y; - if(x_ + w_ >= resW) //-V807 - x_ = resW - w_ - 1; - if(y_ + h_ >= resH) - y_ = resH - h_ - 1; + if(x_ + w_ >= static_cast(res.x)) //-V807 + x_ = static_cast(res.x) - w_ - 1; + if(y_ + h_ >= static_cast(res.y)) + y_ = static_cast(res.y) - h_ - 1; } } @@ -279,7 +278,7 @@ void CWindow::Draw(Position /*parentOrigin*/) } } - // 3. Upper frame (state depends on marked/clicked) + // 3. Upper frame int upperframe; if(clicked) upperframe = WINDOW_UPPER_FRAME_CLICKED; @@ -290,63 +289,55 @@ void CWindow::Draw(Position /*parentOrigin*/) // Draw upper frame tile across the top of the window { - const auto& bmp = global::bmpArray[upperframe]; - const Rect upperFrameRect(origin, Extent(w_, bmp.h)); + const Rect upperFrameRect(origin, Extent(w_, getBmpTexture(upperframe).getHeight())); drawTiledBmp(upperframe, upperFrameRect); } // 4. Title text if(title) { - const int titleY = origin.y + (static_cast(global::bmpArray[WINDOW_UPPER_FRAME].h) - 9) / 2; + const int titleY = origin.y + (getBmpTexture(WINDOW_UPPER_FRAME).getHeight() - 9) / 2; CFont::Draw(title, Position(origin.x + static_cast(w_) / 2, titleY), FontSize::Small, FontColor::Yellow, FontAlign::Middle); } // 5. Lower frame (tiled across bottom) { - const auto& bmp = global::bmpArray[WINDOW_LOWER_FRAME]; - const Rect lowerFrameRect(Position(origin.x, origin.y + static_cast(h_) - static_cast(bmp.h)), - Extent(w_, bmp.h)); + const int lowerH = getBmpTexture(WINDOW_LOWER_FRAME).getHeight(); + const Rect lowerFrameRect(Position(origin.x, origin.y + static_cast(h_) - lowerH), + Extent(w_, lowerH)); drawTiledBmp(WINDOW_LOWER_FRAME, lowerFrameRect); } // 6. Left frame (tiled down left side) { - const auto& bmp = global::bmpArray[WINDOW_LEFT_FRAME]; - const Rect leftFrameRect(origin, Extent(bmp.w, h_)); + const Rect leftFrameRect(origin, Extent(getBmpTexture(WINDOW_LEFT_FRAME).getWidth(), h_)); drawTiledBmp(WINDOW_LEFT_FRAME, leftFrameRect); } // 7. Right frame (tiled down right side) { - const auto& bmp = global::bmpArray[WINDOW_RIGHT_FRAME]; - const Rect rightFrameRect(Position(origin.x + static_cast(w_) - static_cast(bmp.w), origin.y), - Extent(bmp.w, h_)); + const int rightW = getBmpTexture(WINDOW_RIGHT_FRAME).getWidth(); + const Rect rightFrameRect(Position(origin.x + static_cast(w_) - rightW, origin.y), + Extent(rightW, h_)); drawTiledBmp(WINDOW_RIGHT_FRAME, rightFrameRect); } // 8. Corners { - auto& texLU = getBmpTexture(WINDOW_LEFT_UPPER_CORNER); - if(texLU.isValid()) - texLU.Draw(origin); - - auto& texRU = getBmpTexture(WINDOW_RIGHT_UPPER_CORNER); - if(texRU.isValid()) - { - const auto& ruBmp = global::bmpArray[WINDOW_RIGHT_UPPER_CORNER]; - texRU.Draw(Position(origin.x + static_cast(w_) - static_cast(ruBmp.w), origin.y)); - } - - auto& texCR = getBmpTexture(WINDOW_CORNER_RECTANGLE); - if(texCR.isValid()) - { - const auto& crBmp = global::bmpArray[WINDOW_CORNER_RECTANGLE]; - texCR.Draw(Position(origin.x, origin.y + static_cast(h_) - static_cast(crBmp.h))); - texCR.Draw(Position(origin.x + static_cast(w_) - static_cast(crBmp.w), - origin.y + static_cast(h_) - static_cast(crBmp.h))); - } + getBmpTexture(WINDOW_LEFT_UPPER_CORNER).Draw(origin); + + const int ruW = getBmpTexture(WINDOW_RIGHT_UPPER_CORNER).getWidth(); + getBmpTexture(WINDOW_RIGHT_UPPER_CORNER) + .Draw(Position(origin.x + static_cast(w_) - ruW, origin.y)); + + const int crW = getBmpTexture(WINDOW_CORNER_RECTANGLE).getWidth(); + const int crH = getBmpTexture(WINDOW_CORNER_RECTANGLE).getHeight(); + getBmpTexture(WINDOW_CORNER_RECTANGLE) + .Draw(Position(origin.x, origin.y + static_cast(h_) - crH)); + getBmpTexture(WINDOW_CORNER_RECTANGLE) + .Draw(Position(origin.x + static_cast(w_) - crW, + origin.y + static_cast(h_) - crH)); } // 9. Close button @@ -359,9 +350,7 @@ void CWindow::Draw(Position /*parentOrigin*/) closebutton = WINDOW_BUTTON_CLOSE_MARKED; else closebutton = WINDOW_BUTTON_CLOSE; - auto& tex = getBmpTexture(closebutton); - if(tex.isValid()) - tex.Draw(origin); + getBmpTexture(closebutton).Draw(origin); } // 10. Minimize button @@ -374,12 +363,8 @@ void CWindow::Draw(Position /*parentOrigin*/) minimizebutton = WINDOW_BUTTON_MINIMIZE_MARKED; else minimizebutton = WINDOW_BUTTON_MINIMIZE; - auto& tex = getBmpTexture(minimizebutton); - if(tex.isValid()) - { - const auto& bmp = global::bmpArray[minimizebutton]; - tex.Draw(Position(origin.x + static_cast(w_) - static_cast(bmp.w), origin.y)); - } + getBmpTexture(minimizebutton) + .Draw(Position(origin.x + static_cast(w_) - getBmpTexture(minimizebutton).getWidth(), origin.y)); } // 11. Resize button @@ -392,12 +377,8 @@ void CWindow::Draw(Position /*parentOrigin*/) resizebutton = WINDOW_BUTTON_RESIZE_MARKED; else resizebutton = WINDOW_BUTTON_RESIZE; - auto& tex = getBmpTexture(resizebutton); - if(tex.isValid()) - { - const auto& bmp = global::bmpArray[resizebutton]; - tex.Draw(Position(origin + Position(w_, h_)) - Position(static_cast(bmp.w), static_cast(bmp.h))); - } + getBmpTexture(resizebutton) + .Draw(Position(origin + Position(w_, h_)) - Position(getBmpTexture(resizebutton).getWidth(), getBmpTexture(resizebutton).getHeight())); } } diff --git a/CIO/CWindow.h b/CIO/CWindow.h index a236853..62cdf9e 100644 --- a/CIO/CWindow.h +++ b/CIO/CWindow.h @@ -47,7 +47,7 @@ class CWindow : public CControlContainer int callbackQuitMessage; public: - /// Draw the window using OpenGL (chrome + children). + /// Draw the window using OpenGL (frame and children). void Draw(Position parentOrigin) override; CWindow(void callback(int), int callbackQuitMessage, Position pos, Extent size, const char* title = nullptr, diff --git a/CMap.cpp b/CMap.cpp index a7e80eb..c1a07b6 100644 --- a/CMap.cpp +++ b/CMap.cpp @@ -1368,7 +1368,6 @@ void CMap::drawMinimap(std::vector& pixels, int w, int h, int& num_x, const auto r8 = (Uint8)(r > 255 ? 255 : (r < 0 ? 0 : r)); const auto g8 = (Uint8)(g > 255 ? 255 : (g < 0 ? 0 : g)); const auto b8 = (Uint8)(b > 255 ? 255 : (b < 0 ? 0 : b)); - // BGRA format: A<<24 | R<<16 | G<<8 | B pixel = (0xFFu << 24) | (r8 << 16) | (g8 << 8) | b8; } } diff --git a/Texture.cpp b/Texture.cpp index 1c64a61..51677f5 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -11,10 +11,6 @@ #include #include -// --------------------------------------------------------------------------- -// Texture -// --------------------------------------------------------------------------- - Texture::~Texture() { if(texture_) @@ -123,19 +119,16 @@ void Texture::Draw(const Rect& destRect) const if(!texture_) return; - const float uScale = 1.0f; - const float vScale = 1.0f; - glColor4f(1, 1, 1, 1); glBindTexture(GL_TEXTURE_2D, texture_); glBegin(GL_QUADS); glTexCoord2f(0, 0); glVertex2i(destRect.left, destRect.top); - glTexCoord2f(uScale, 0); + glTexCoord2f(1, 0); glVertex2i(destRect.right, destRect.top); - glTexCoord2f(uScale, vScale); + glTexCoord2f(1, 1); glVertex2i(destRect.right, destRect.bottom); - glTexCoord2f(0, vScale); + glTexCoord2f(0, 1); glVertex2i(destRect.left, destRect.bottom); glEnd(); } @@ -190,10 +183,6 @@ void Texture::Draw(const Rect& destRect, const Rect& srcRect) const glEnd(); } -// --------------------------------------------------------------------------- -// DrawRect / DrawLine helpers -// --------------------------------------------------------------------------- - void DrawRect(const Rect& rect, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { glDisable(GL_TEXTURE_2D); @@ -223,10 +212,6 @@ void DrawLine(Position p1, Position p2, unsigned char r, unsigned char g, unsign glEnable(GL_TEXTURE_2D); } -// --------------------------------------------------------------------------- -// Texture-drawing helpers -// --------------------------------------------------------------------------- - Texture& getBmpTexture(int idx, bool filterLinear) { static std::vector> cache; @@ -262,15 +247,12 @@ void ensureBmpTex(int idx) void drawTiledBmp(int bmpIdx, const Rect& destRect) { - if(bmpIdx < 0 || bmpIdx >= static_cast(global::bmpArray.size())) - return; auto& tex = getBmpTexture(bmpIdx); if(!tex.isValid()) return; - const auto& bmp = global::bmpArray[bmpIdx]; - const unsigned tileW = bmp.w; - const unsigned tileH = bmp.h; + const unsigned tileW = static_cast(tex.getWidth()); + const unsigned tileH = static_cast(tex.getHeight()); if(tileW == 0 || tileH == 0) return; diff --git a/Texture.h b/Texture.h index 33d7419..f84cd7f 100644 --- a/Texture.h +++ b/Texture.h @@ -38,9 +38,6 @@ class Texture /// Draw the texture at native size at the given position. void Draw(Position pos) const; - /// Convenience overload for callers using separate x/y. - void Draw(int x, int y) const { Draw(Position(x, y)); } - /// Draw a sub-rectangle of the texture to fill the given destination rect. /// srcRect is in texture-local coordinates (may be clipped). void Draw(const Rect& destRect, const Rect& srcRect) const; @@ -69,13 +66,13 @@ class Texture // Free functions for simple GL drawing (rect, line) used by UI components. // --------------------------------------------------------------------------- -/// Draw a filled rectangle (disables texturing). +/// Draw a filled rectangle. void DrawRect(const Rect& rect, unsigned char r, unsigned char g, unsigned char b, unsigned char a = 255); -/// Draw a filled rectangle with a 32-bit RGBA colour. +/// Draw a filled rectangle with a 32-bit ARGB colour. void DrawRect(const Rect& rect, unsigned color); -/// Draw a 1-pixel-wide axis-aligned line (disables texturing). +/// Draw a 1-pixel-wide line. void DrawLine(Position p1, Position p2, unsigned char r, unsigned char g, unsigned char b, unsigned char a = 255); // --------------------------------------------------------------------------- diff --git a/callbacks.cpp b/callbacks.cpp index 6c57267..3dd7851 100644 --- a/callbacks.cpp +++ b/callbacks.cpp @@ -53,11 +53,9 @@ void callback::PleaseWait(int Param) WNDWait->addText("Please wait ...", Position(10, 10), FontSize::Large); // we need to render this window NOW, cause the render loop will do it too late (when the operation // is done and we don't need the "Please wait"-window anymore) - { - glClear(GL_COLOR_BUFFER_BIT); - WNDWait->Draw(Position(0, 0)); - global::s2->RenderPresent(); - } + glClear(GL_COLOR_BUFFER_BIT); + WNDWait->Draw(Position(0, 0)); + global::s2->RenderPresent(); break; case CALL_FROM_GAMELOOP: // This window gives a "Please Wait"-string, so it is shown while there is an intensive @@ -3101,8 +3099,7 @@ void callback::submenu1(int Param) "Create window"); picObject = SubMenu->addPicture(submenu1, PICOBJECT, Position(200, 30), MIS0BOBS_SHIP); picObject->setMotionParams(PICOBJECTENTRY, PICOBJECTLEAVE); - // text block with \n - SubMenu->addText("\nTextblock:\n\nNeue Zeile\nNoch eine neue Zeile", Position(400, 200), FontSize::Large); + SubMenu->addText("Textblock", Position(400, 200), FontSize::Large); testTextfield = SubMenu->addTextfield(Position(400, 300), 10, 3); testSelectBox = SubMenu->addSelectBox(Position(500, 500), Extent(300, 200)); testSelectBox->addOption("Erste Option", submenu1, SELECTBOX_OPTION1); From eca9e132e9e85200b497354dddd40637ae8835bd Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sat, 4 Jul 2026 20:44:27 +0200 Subject: [PATCH 05/40] Revert changes to Texture --- Texture.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/Texture.cpp b/Texture.cpp index 51677f5..77a2e52 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -102,13 +102,21 @@ bool Texture::load(SDL_Surface* surface, bool filterLinear) return true; } - // 32-bit surface: convert to destination format (BGRA). - // SDL_ConvertSurfaceFormat preserves color keys and alpha, so - // transparent pixels keep alpha=0 and text anti-aliasing is retained. + // 32-bit surface: convert to destination format (BGRA), preserving colorkey transparency SDL_Surface* converted = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ARGB8888, 0); if(!converted) return false; + // Force alpha to opaque (some source images may have wrong alpha=0) + SDL_LockSurface(converted); + for(int y = 0; y < converted->h; y++) + { + auto* row = (Uint32*)((Uint8*)converted->pixels + y * converted->pitch); + for(int x = 0; x < converted->w; x++) + row[x] |= 0xFF000000u; + } + SDL_UnlockSurface(converted); + load(converted->pixels, Extent(converted->w, converted->h), filterLinear); SDL_FreeSurface(converted); return true; @@ -119,7 +127,6 @@ void Texture::Draw(const Rect& destRect) const if(!texture_) return; - glColor4f(1, 1, 1, 1); glBindTexture(GL_TEXTURE_2D, texture_); glBegin(GL_QUADS); glTexCoord2f(0, 0); @@ -138,7 +145,6 @@ void Texture::Draw(Position pos) const if(!texture_) return; - glColor4f(1, 1, 1, 1); glBindTexture(GL_TEXTURE_2D, texture_); glBegin(GL_QUADS); glTexCoord2f(0, 0); From 71ace85df87f3af92f1376d9039cb02766d477a1 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sat, 4 Jul 2026 21:33:46 +0200 Subject: [PATCH 06/40] getPos and struct FrameInserts --- CIO/CControlContainer.cpp | 18 +++++++++--------- CIO/CControlContainer.h | 18 +++++++++++++----- CIO/CFont.h | 4 ---- CIO/CMinimapWindow.cpp | 11 +++++------ CIO/CSelectBox.cpp | 8 ++++---- CIO/CTextfield.cpp | 22 ++++++---------------- CIO/CTextfield.h | 6 ++---- CIO/CWindow.cpp | 15 +++++++-------- 8 files changed, 46 insertions(+), 56 deletions(-) diff --git a/CIO/CControlContainer.cpp b/CIO/CControlContainer.cpp index d404370..674fca2 100644 --- a/CIO/CControlContainer.cpp +++ b/CIO/CControlContainer.cpp @@ -14,10 +14,10 @@ #include "helpers/containerUtils.h" CControlContainer::CControlContainer(int pic_background) - : CControlContainer(pic_background, Extent::all(0), Extent::all(0)) + : CControlContainer(pic_background, FrameInsets{}) {} -CControlContainer::CControlContainer(int pic_background, Extent borderBeginSize, Extent borderEndSize) - : borderBeginSize(borderBeginSize), borderEndSize(borderEndSize), pic_background(pic_background) +CControlContainer::CControlContainer(int pic_background, FrameInsets border) + : border(border), pic_background(pic_background) {} CControlContainer::~CControlContainer() noexcept = default; @@ -86,7 +86,7 @@ bool CControlContainer::eraseElement(T& collection, const U* element) CButton* CControlContainer::addButton(void callback(int), int clickedParam, Position pos, Extent size, int color, const char* text, int picture) { - pos = pos + borderBeginSize; + pos = pos + Position(border.left, border.top); buttons.emplace_back(std::make_unique(callback, clickedParam, pos, size, color, text, picture)); return buttons.back().get(); @@ -99,7 +99,7 @@ bool CControlContainer::delButton(CButton* ButtonToDelete) CFont* CControlContainer::addText(std::string string, Position pos, FontSize fontsize, FontColor color) { - pos = pos + borderBeginSize; + pos = pos + Position(border.left, border.top); texts.emplace_back(std::make_unique(std::move(string), pos, fontsize, color)); return texts.back().get(); @@ -112,7 +112,7 @@ bool CControlContainer::delText(CFont* TextToDelete) CPicture* CControlContainer::addPicture(void callback(int), int clickedParam, Position pos, int picture) { - pos = pos + borderBeginSize; + pos = pos + Position(border.left, border.top); pictures.emplace_back(std::make_unique(callback, clickedParam, pos, picture)); return pictures.back().get(); @@ -127,7 +127,7 @@ int CControlContainer::addStaticPicture(Position pos, int picture) { if(picture < 0) return -1; - pos = pos + borderBeginSize; + pos = pos + Position(border.left, border.top); unsigned id = static_pictures.empty() ? 0u : static_pictures.back().id + 1u; static_pictures.emplace_back(Picture{pos, picture, id}); @@ -151,7 +151,7 @@ bool CControlContainer::delStaticPicture(int picId) CTextfield* CControlContainer::addTextfield(Position pos, Uint16 cols, Uint16 rows, FontSize fontsize, FontColor text_color, int bg_color, bool button_style) { - pos = pos + borderBeginSize; + pos = pos + Position(border.left, border.top); textfields.emplace_back( std::make_unique(pos, cols, rows, fontsize, text_color, bg_color, button_style)); @@ -166,7 +166,7 @@ bool CControlContainer::delTextfield(CTextfield* TextfieldToDelete) CSelectBox* CControlContainer::addSelectBox(Position pos, Extent size, FontSize fontsize, FontColor text_color, int bg_color) { - pos += Position(borderBeginSize); + pos += Position(border.left, border.top); selectboxes.emplace_back(std::make_unique(pos, size, fontsize, text_color, bg_color)); return selectboxes.back().get(); diff --git a/CIO/CControlContainer.h b/CIO/CControlContainer.h index 31304cb..25de573 100644 --- a/CIO/CControlContainer.h +++ b/CIO/CControlContainer.h @@ -15,6 +15,15 @@ class CPicture; class CTextfield; class CSelectBox; +/// Pixel thickness of a window's frame border on each edge. +struct FrameInsets +{ + int left = 0; + int top = 0; + int right = 0; + int bottom = 0; +}; + class CControlContainer { friend class CDebug; @@ -28,7 +37,7 @@ class CControlContainer }; // if waste is true, the menu will be delete within the game loop - Extent borderBeginSize, borderEndSize; // Width and height of border at left/top and right/bottom + FrameInsets border; bool waste = false; int pic_background; std::vector> buttons; @@ -54,12 +63,11 @@ class CControlContainer public: CControlContainer(int pic_background); - CControlContainer(int pic_background, Extent borderBeginSize, Extent borderEndSize); + CControlContainer(int pic_background, FrameInsets border); virtual ~CControlContainer() noexcept; // Access - Extent getBorderSize() const { return borderBeginSize + borderEndSize; } - Extent getBorderBegin() const { return borderBeginSize; } - Extent getBorderEnd() const { return borderEndSize; } + const FrameInsets& getBorder() const { return border; } + Extent getBorderSize() const { return {static_cast(border.left + border.right), static_cast(border.top + border.bottom)}; } void setBackgroundPicture(int pic_background); virtual void setMouseData(SDL_MouseMotionEvent motion); virtual void setMouseData(SDL_MouseButtonEvent button); diff --git a/CIO/CFont.h b/CIO/CFont.h index 53c841f..37289f8 100644 --- a/CIO/CFont.h +++ b/CIO/CFont.h @@ -28,12 +28,8 @@ class CFont CFont(std::string text, Position pos = {0, 0}, FontSize fontsize = FontSize::Small, FontColor color = FontColor::Yellow); // Access - int getX() const { return pos_.x; } - int getY() const { return pos_.y; } const Position& getPos() const { return pos_; } const Extent& getSize() const { return size_; } - unsigned getW() const { return size_.x; } - unsigned getH() const { return static_cast(fontsize_); } void setPos(Position pos); void setFontsize(FontSize fontsize); void setColor(FontColor color); diff --git a/CIO/CMinimapWindow.cpp b/CIO/CMinimapWindow.cpp index 3c418cf..661dae8 100644 --- a/CIO/CMinimapWindow.cpp +++ b/CIO/CMinimapWindow.cpp @@ -15,12 +15,11 @@ void CMinimapWindow::Draw(Position /*parentOrigin*/) CWindow::Draw(Position(x_, y_)); // Compute content area (inside the frames) - const auto borderBegin = getBorderBegin(); - const auto borderEnd = getBorderEnd(); - const int contentX = x_ + static_cast(borderBegin.x); - const int contentY = y_ + static_cast(borderBegin.y); - const int contentW = static_cast(w_) - static_cast(borderBegin.x) - static_cast(borderEnd.x); - const int contentH = static_cast(h_) - static_cast(borderBegin.y) - static_cast(borderEnd.y); + const auto& b = getBorder(); + const int contentX = x_ + b.left; + const int contentY = y_ + b.top; + const int contentW = static_cast(w_) - b.left - b.right; + const int contentH = static_cast(h_) - b.top - b.bottom; if(contentW <= 0 || contentH <= 0) return; diff --git a/CIO/CSelectBox.cpp b/CIO/CSelectBox.cpp index ceda380..3bb1262 100644 --- a/CIO/CSelectBox.cpp +++ b/CIO/CSelectBox.cpp @@ -146,11 +146,11 @@ void CSelectBox::setMouseData(SDL_MouseButtonEvent button) if((button.x > pos_.x + static_cast(size_.x) - 20) && (button.y < pos_.y + 20)) { // test if first entry is on the most upper position - if(!Entries.empty() && Entries.front()->getY() < 10) + if(!Entries.empty() && Entries.front()->getPos().y < 10) { for(auto& entry : Entries) { - entry->setPos(Position(entry->getX(), entry->getY() + 10)); + entry->setPos(Position(entry->getPos().x, entry->getPos().y + 10)); } } } @@ -162,11 +162,11 @@ void CSelectBox::setMouseData(SDL_MouseButtonEvent button) && (button.y > pos_.y + static_cast(size_.y) - 20)) { // test if last entry is on the most lower position - if(!Entries.empty() && Entries.back()->getY() > static_cast(size_.y) - 10) + if(!Entries.empty() && Entries.back()->getPos().y > static_cast(size_.y) - 10) { for(auto& entry : Entries) { - entry->setPos(Position(entry->getX(), entry->getY() - 10)); + entry->setPos(Position(entry->getPos().x, entry->getPos().y - 10)); } } } diff --git a/CIO/CTextfield.cpp b/CIO/CTextfield.cpp index de37a7d..9e0b155 100644 --- a/CIO/CTextfield.cpp +++ b/CIO/CTextfield.cpp @@ -31,14 +31,14 @@ CTextfield::CTextfield(Position pos, Uint16 cols, Uint16 rows, FontSize fontsize textObj = std::make_unique("", pos, fontsize, text_color); } -int CTextfield::getX() const +Position CTextfield::getPos() const { - return textObj->getX(); + return textObj->getPos(); } -int CTextfield::getY() const +void CTextfield::setPos(Position pos) { - return textObj->getY(); + textObj->setPos(pos); } bool CTextfield::hasRendered() @@ -97,16 +97,6 @@ void CTextfield::setTextColor(FontColor color) textObj->setColor(color); } -void CTextfield::setX(int x) -{ - textObj->setPos(Position(x, getY())); -} - -void CTextfield::setY(int y) -{ - textObj->setPos(Position(getX(), y)); -} - void CTextfield::setText(const std::string& text) { char* txtPtr = this->text_.data(); @@ -143,7 +133,7 @@ void CTextfield::setMouseData(SDL_MouseButtonEvent button) // if mouse button is pressed ON the textfield, set active=true if(button.state == SDL_PRESSED) { - active = IsPointInRect(button.x, button.y, Rect(Position(getX(), getY()), size_)); + active = IsPointInRect(button.x, button.y, Rect(getPos(), size_)); } } } @@ -241,7 +231,7 @@ void CTextfield::setKeyboardData(const SDL_KeyboardEvent& key) void CTextfield::Draw(Position parentOrigin) { - const Position absPos = parentOrigin + Position(getX(), getY()); + const Position absPos = parentOrigin + getPos(); const Rect area(absPos, size_); // Update cursor blink state diff --git a/CIO/CTextfield.h b/CIO/CTextfield.h index 2a3c9d8..c689f5b 100644 --- a/CIO/CTextfield.h +++ b/CIO/CTextfield.h @@ -38,13 +38,11 @@ class CTextfield CTextfield(Position pos = {0, 0}, Uint16 cols = 10, Uint16 rows = 1, FontSize fontsize = FontSize::Large, FontColor text_color = FontColor::Yellow, int bg_color = -1, bool button_style = false); // Access - int getX() const; - int getY() const; + Position getPos() const; + void setPos(Position pos); const Extent& getSize() const { return size_; }; int getCols() const { return cols; } int getRows() const { return rows; } - void setX(int x); - void setY(int y); void setText(const std::string& text); void setActive() { active = true; } void setInactive() { active = false; } diff --git a/CIO/CWindow.cpp b/CIO/CWindow.cpp index 04917c4..835024f 100644 --- a/CIO/CWindow.cpp +++ b/CIO/CWindow.cpp @@ -19,8 +19,8 @@ CWindow::CWindow(void callback(int), int callbackQuitMessage, Position pos, Extent size, const char* title, int color, Uint8 flags) - : CControlContainer(color, {global::bmpArray[WINDOW_LEFT_FRAME].w, global::bmpArray[WINDOW_UPPER_FRAME].h}, - {global::bmpArray[WINDOW_RIGHT_FRAME].w, global::bmpArray[WINDOW_LOWER_FRAME].h}), + : CControlContainer(color, {global::bmpArray[WINDOW_LEFT_FRAME].w, global::bmpArray[WINDOW_UPPER_FRAME].h, + global::bmpArray[WINDOW_RIGHT_FRAME].w, global::bmpArray[WINDOW_LOWER_FRAME].h}), x_(pos.x), y_(pos.y), w_(size.x), h_(size.y), title(title), callback_(callback), callbackQuitMessage(callbackQuitMessage) { @@ -263,12 +263,11 @@ void CWindow::Draw(Position /*parentOrigin*/) if(!minimized) { const auto viewH = global::s2->getRes().y; - const auto contentX = origin.x + static_cast(getBorderBegin().x); - const auto contentY = origin.y + static_cast(getBorderBegin().y); - const auto contentW = - static_cast(w_) - static_cast(getBorderBegin().x) - static_cast(getBorderEnd().x); - const auto contentH = - static_cast(h_) - static_cast(getBorderBegin().y) - static_cast(getBorderEnd().y); + const auto& b = getBorder(); + const auto contentX = origin.x + b.left; + const auto contentY = origin.y + b.top; + const auto contentW = static_cast(w_) - b.left - b.right; + const auto contentH = static_cast(h_) - b.top - b.bottom; if(contentW > 0 && contentH > 0) { glEnable(GL_SCISSOR_TEST); From e4163e899be326b9a7db4a6ed90ab6dd5258109a Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sat, 4 Jul 2026 21:44:35 +0200 Subject: [PATCH 07/40] drawButtonBox() --- CIO/CButton.cpp | 23 ++--------------------- CIO/CTextfield.cpp | 27 +++------------------------ Texture.cpp | 23 +++++++++++++++++++++++ Texture.h | 4 ++++ 4 files changed, 32 insertions(+), 45 deletions(-) diff --git a/CIO/CButton.cpp b/CIO/CButton.cpp index 3c836bc..3ac7d5a 100644 --- a/CIO/CButton.cpp +++ b/CIO/CButton.cpp @@ -128,28 +128,9 @@ void CButton::Draw(Position parentOrigin) const { const Position absPos = parentOrigin + pos_; - // 1. Draw background (tiled) - drawTiledBmp(pic_background, Rect(absPos, size_)); - - // 2. Draw black frame (2px) using filled rectangles - if(clicked) - { - // Left border (2px wide, full height) - DrawRect(Rect(absPos.x, absPos.y, 2, size_.y), 0, 0, 0); - // Top border (2px tall, full width) - DrawRect(Rect(absPos.x, absPos.y, size_.x, 2), 0, 0, 0); - } else - { - // Right border (2px wide, full height) - DrawRect(Rect(absPos.x + static_cast(size_.x) - 2, absPos.y, 2, size_.y), 0, 0, 0); - // Bottom border (2px tall, full width) - DrawRect(Rect(absPos.x, absPos.y + static_cast(size_.y) - 2, size_.x, 2), 0, 0, 0); - } - - // 3. Draw foreground (tiled, inset by 2px for the black frame) + // Draw 3D button box const int foreground = (marked && !clicked) ? pic_marked : pic_normal; - const Rect fgRect(absPos + Position(2, 2), size_ - Extent(4, 4)); - drawTiledBmp(foreground, fgRect); + drawButtonBox(Rect(absPos, size_), clicked, pic_background, foreground); // 4. Draw picture or text centered inside the button if(button_picture >= 0) diff --git a/CIO/CTextfield.cpp b/CIO/CTextfield.cpp index 9e0b155..e148ea2 100644 --- a/CIO/CTextfield.cpp +++ b/CIO/CTextfield.cpp @@ -257,31 +257,10 @@ void CTextfield::Draw(Position parentOrigin) // Draw the background / foreground if(pic_background >= 0 && pic_foreground >= 0) { - const int bmpIdx = button_style ? pic_background : pic_foreground; - drawTiledBmp(bmpIdx, area); - if(button_style) - { - // Draw black frame (2px) using filled rectangles - const int w = area.right - area.left; - const int h = area.bottom - area.top; - - if(active) - { - // Black frame is left and up - DrawRect(Rect(area.left, area.top, 2, h), 0, 0, 0); - DrawRect(Rect(area.left, area.top, w, 2), 0, 0, 0); - } else - { - // Black frame is right and down - DrawRect(Rect(area.right - 2, area.top, 2, h), 0, 0, 0); - DrawRect(Rect(area.left, area.bottom - 2, w, 2), 0, 0, 0); - } - - // Draw foreground (inset by 2px) - const Rect fgRect(area.getOrigin() + Position(2, 2), size_ - Extent(4, 4)); - drawTiledBmp(pic_foreground, fgRect); - } + drawButtonBox(area, active, pic_background, pic_foreground); + else + drawTiledBmp(pic_foreground, area); } else { // Fill with black diff --git a/Texture.cpp b/Texture.cpp index 77a2e52..0e3f883 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -286,3 +286,26 @@ void drawTiledBmp(int bmpIdx, const Rect& destRect) } glEnd(); } + +void drawButtonBox(const Rect& area, bool pressed, int baseTex, int faceTex) +{ + drawTiledBmp(baseTex, area); + + const int w = area.right - area.left; + const int h = area.bottom - area.top; + + // 2px black frame: left+top if pressed, right+bottom otherwise + if(pressed) + { + DrawRect(Rect(area.left, area.top, 2, h), 0, 0, 0); + DrawRect(Rect(area.left, area.top, w, 2), 0, 0, 0); + } else + { + DrawRect(Rect(area.right - 2, area.top, 2, h), 0, 0, 0); + DrawRect(Rect(area.left, area.bottom - 2, w, 2), 0, 0, 0); + } + + // Foreground inset by 2px + const Rect fgRect(area.getOrigin() + Position(2, 2), Extent(w - 4, h - 4)); + drawTiledBmp(faceTex, fgRect); +} diff --git a/Texture.h b/Texture.h index f84cd7f..1969038 100644 --- a/Texture.h +++ b/Texture.h @@ -85,6 +85,10 @@ void ensureBmpTex(int idx); /// Draw a bitmap texture tiled to fill the given rectangle. void drawTiledBmp(int bmpIdx, const Rect& destRect); +/// Draw a 3D-style button box: tiled background, 2px black frame (sunken if pressed, raised otherwise), +/// and tiled foreground inset by 2px. +void drawButtonBox(const Rect& area, bool pressed, int baseTex, int faceTex); + /// Get or create the cached OpenGL texture for a bitmap index. /// The texture is loaded from the SDL surface on first access. /// @param filterLinear Whether to use linear filtering (for scaled backgrounds). From fcf7e678b411f17e087fa6c4b03bd18bfdbd7b17 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sat, 4 Jul 2026 22:15:42 +0200 Subject: [PATCH 08/40] Rect/Position/Extent --- CIO/CMinimapWindow.cpp | 52 ++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/CIO/CMinimapWindow.cpp b/CIO/CMinimapWindow.cpp index 661dae8..0fd1934 100644 --- a/CIO/CMinimapWindow.cpp +++ b/CIO/CMinimapWindow.cpp @@ -16,13 +16,12 @@ void CMinimapWindow::Draw(Position /*parentOrigin*/) // Compute content area (inside the frames) const auto& b = getBorder(); - const int contentX = x_ + b.left; - const int contentY = y_ + b.top; - const int contentW = static_cast(w_) - b.left - b.right; - const int contentH = static_cast(h_) - b.top - b.bottom; - - if(contentW <= 0 || contentH <= 0) + const Position contentPos(x_ + b.left, y_ + b.top); + const int cw = static_cast(w_) - b.left - b.right; + const int ch = static_cast(h_) - b.top - b.bottom; + if(cw <= 0 || ch <= 0) return; + const Extent contentSize(cw, ch); auto* map = global::s2->getMapObj(); if(!map) @@ -30,13 +29,13 @@ void CMinimapWindow::Draw(Position /*parentOrigin*/) // Fill pixel buffer with minimap terrain int num_x = 1, num_y = 1; - map->drawMinimap(pixels_, contentW, contentH, num_x, num_y); + map->drawMinimap(pixels_, cw, ch, num_x, num_y); // Upload to texture and draw - if(!minimapTex_.isValid() || minimapTex_.getWidth() != contentW || minimapTex_.getHeight() != contentH) - minimapTex_.createEmpty(Extent(contentW, contentH)); + if(!minimapTex_.isValid() || minimapTex_.getWidth() != cw || minimapTex_.getHeight() != ch) + minimapTex_.createEmpty(contentSize); minimapTex_.upload(pixels_.data()); - minimapTex_.Draw(Rect(contentX, contentY, contentW, contentH)); + minimapTex_.Draw(Rect(contentPos, contentSize)); // Draw player flags and numbers on top for(int i = 0; i < MAXPLAYERS; i++) @@ -47,35 +46,24 @@ void CMinimapWindow::Draw(Position /*parentOrigin*/) continue; const int flagIdx = FLAG_BLUE_DARK + i % 7; - const auto& flagBmp = global::bmpArray[flagIdx]; - auto& flagTex = getBmpTexture(flagIdx); - if(flagTex.isValid()) - { - const int fx = contentX + hqX / num_x - static_cast(flagBmp.nx); - const int fy = contentY + hqY / num_y - static_cast(flagBmp.ny); - flagTex.Draw(Position(fx, fy)); - } + const Position hqPos(hqX / num_x, hqY / num_y); + getBmpTexture(flagIdx).Draw(contentPos + hqPos - Position(static_cast(global::bmpArray[flagIdx].nx), + static_cast(global::bmpArray[flagIdx].ny))); // Player number - CFont::Draw(std::to_string(i + 1), Position(contentX + hqX / num_x, contentY + hqY / num_y), FontSize::Small, + CFont::Draw(std::to_string(i + 1), contentPos + hqPos, FontSize::Small, FontColor::MintGreen); } // Draw the position arrow { const int arrowIdx = MAPPIC_ARROWCROSS_ORANGE; - const auto& arrowBmp = global::bmpArray[arrowIdx]; - auto& arrowTex = getBmpTexture(arrowIdx); - if(arrowTex.isValid()) - { - const auto& dispRect = map->getDisplayRect(); - const int ax = contentX - + (dispRect.left + static_cast(dispRect.getSize().x) / 2) / triangleWidth / num_x - - static_cast(arrowBmp.nx); - const int ay = contentY - + (dispRect.top + static_cast(dispRect.getSize().y) / 2) / triangleHeight / num_y - - static_cast(arrowBmp.ny); - arrowTex.Draw(Position(ax, ay)); - } + const auto& dispRect = map->getDisplayRect(); + const Position arrowPos = contentPos + + Position((dispRect.left + static_cast(dispRect.getSize().x) / 2) / triangleWidth / num_x, + (dispRect.top + static_cast(dispRect.getSize().y) / 2) / triangleHeight / num_y) + - Position(static_cast(global::bmpArray[arrowIdx].nx), + static_cast(global::bmpArray[arrowIdx].ny)); + getBmpTexture(arrowIdx).Draw(arrowPos); } } From b20ae0d645ada9cc2bce210bce78cf25a98fbe94 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sat, 4 Jul 2026 22:40:09 +0200 Subject: [PATCH 09/40] Rect/Position/Extent --- CGame_Event.cpp | 13 ++--- CIO/CControlContainer.cpp | 4 +- CIO/CControlContainer.h | 5 +- CIO/CMinimapWindow.cpp | 22 ++++---- CIO/CWindow.cpp | 112 ++++++++++++++++++++------------------ CIO/CWindow.h | 16 ++---- callbacks.cpp | 10 ++-- 7 files changed, 88 insertions(+), 94 deletions(-) diff --git a/CGame_Event.cpp b/CGame_Event.cpp index 7839c79..93ed86c 100644 --- a/CGame_Event.cpp +++ b/CGame_Event.cpp @@ -8,6 +8,7 @@ #include "CIO/CWindow.h" #include "CMap.h" #include "CSurface.h" +#include "CollisionDetection.h" #include "callbacks.h" #include "globals.h" @@ -195,9 +196,7 @@ void CGame::EventHandling(SDL_Event* Event) if(!Window->isWaste() && Window->getPriority() == actualPriority) { // is the cursor INSIDE the window or does the user move or resize the window? - if(((Event->motion.x >= Window->getX()) && (Event->motion.x < Window->getX() + Window->getW()) - && (Event->motion.y >= Window->getY()) - && (Event->motion.y < Window->getY() + Window->getH())) + if(IsPointInRect(Event->motion.x, Event->motion.y, Rect(Window->getPos(), Window->getSize())) || Window->isMoving() || Window->isResizing()) { // Windows[i]->setActive(); @@ -275,9 +274,7 @@ void CGame::EventHandling(SDL_Event* Event) if(!Window->isWaste() && Window->getPriority() == actualPriority) { // is the cursor INSIDE the window? - if((Event->button.x >= Window->getX()) && (Event->button.x < Window->getX() + Window->getW()) - && (Event->button.y >= Window->getY()) - && (Event->button.y < Window->getY() + Window->getH())) + if(IsPointInRect(Event->button.x, Event->button.y, Rect(Window->getPos(), Window->getSize()))) { Window->setActive(); Window->setPriority(highestPriority + 1); @@ -338,9 +335,7 @@ void CGame::EventHandling(SDL_Event* Event) if(!Window->isWaste() && Window->getPriority() == actualPriority) { // is the cursor INSIDE the window? - if((Event->button.x >= Window->getX()) && (Event->button.x < Window->getX() + Window->getW()) - && (Event->button.y >= Window->getY()) - && (Event->button.y < Window->getY() + Window->getH())) + if(IsPointInRect(Event->button.x, Event->button.y, Rect(Window->getPos(), Window->getSize()))) { // Windows[i]->setActive(); // Windows[i]->setPriority(highestPriority+1); diff --git a/CIO/CControlContainer.cpp b/CIO/CControlContainer.cpp index 674fca2..e561bb1 100644 --- a/CIO/CControlContainer.cpp +++ b/CIO/CControlContainer.cpp @@ -13,9 +13,7 @@ #include "CTextfield.h" #include "helpers/containerUtils.h" -CControlContainer::CControlContainer(int pic_background) - : CControlContainer(pic_background, FrameInsets{}) -{} +CControlContainer::CControlContainer(int pic_background) : CControlContainer(pic_background, FrameInsets{}) {} CControlContainer::CControlContainer(int pic_background, FrameInsets border) : border(border), pic_background(pic_background) {} diff --git a/CIO/CControlContainer.h b/CIO/CControlContainer.h index 25de573..e815cdc 100644 --- a/CIO/CControlContainer.h +++ b/CIO/CControlContainer.h @@ -67,7 +67,10 @@ class CControlContainer virtual ~CControlContainer() noexcept; // Access const FrameInsets& getBorder() const { return border; } - Extent getBorderSize() const { return {static_cast(border.left + border.right), static_cast(border.top + border.bottom)}; } + Extent getBorderSize() const + { + return {static_cast(border.left + border.right), static_cast(border.top + border.bottom)}; + } void setBackgroundPicture(int pic_background); virtual void setMouseData(SDL_MouseMotionEvent motion); virtual void setMouseData(SDL_MouseButtonEvent button); diff --git a/CIO/CMinimapWindow.cpp b/CIO/CMinimapWindow.cpp index 0fd1934..7501837 100644 --- a/CIO/CMinimapWindow.cpp +++ b/CIO/CMinimapWindow.cpp @@ -12,13 +12,13 @@ void CMinimapWindow::Draw(Position /*parentOrigin*/) { // Draw window chrome (frame, title, close button, background, child elements) - CWindow::Draw(Position(x_, y_)); + CWindow::Draw(pos_); // Compute content area (inside the frames) const auto& b = getBorder(); - const Position contentPos(x_ + b.left, y_ + b.top); - const int cw = static_cast(w_) - b.left - b.right; - const int ch = static_cast(h_) - b.top - b.bottom; + const Position contentPos(pos_.x + b.left, pos_.y + b.top); + const int cw = static_cast(size_.x) - b.left - b.right; + const int ch = static_cast(size_.y) - b.top - b.bottom; if(cw <= 0 || ch <= 0) return; const Extent contentSize(cw, ch); @@ -47,23 +47,23 @@ void CMinimapWindow::Draw(Position /*parentOrigin*/) const int flagIdx = FLAG_BLUE_DARK + i % 7; const Position hqPos(hqX / num_x, hqY / num_y); - getBmpTexture(flagIdx).Draw(contentPos + hqPos - Position(static_cast(global::bmpArray[flagIdx].nx), - static_cast(global::bmpArray[flagIdx].ny))); + getBmpTexture(flagIdx).Draw( + contentPos + hqPos + - Position(static_cast(global::bmpArray[flagIdx].nx), static_cast(global::bmpArray[flagIdx].ny))); // Player number - CFont::Draw(std::to_string(i + 1), contentPos + hqPos, FontSize::Small, - FontColor::MintGreen); + CFont::Draw(std::to_string(i + 1), contentPos + hqPos, FontSize::Small, FontColor::MintGreen); } // Draw the position arrow { const int arrowIdx = MAPPIC_ARROWCROSS_ORANGE; const auto& dispRect = map->getDisplayRect(); - const Position arrowPos = contentPos + const Position arrowPos = + contentPos + Position((dispRect.left + static_cast(dispRect.getSize().x) / 2) / triangleWidth / num_x, (dispRect.top + static_cast(dispRect.getSize().y) / 2) / triangleHeight / num_y) - - Position(static_cast(global::bmpArray[arrowIdx].nx), - static_cast(global::bmpArray[arrowIdx].ny)); + - Position(static_cast(global::bmpArray[arrowIdx].nx), static_cast(global::bmpArray[arrowIdx].ny)); getBmpTexture(arrowIdx).Draw(arrowPos); } } diff --git a/CIO/CWindow.cpp b/CIO/CWindow.cpp index 835024f..98789bf 100644 --- a/CIO/CWindow.cpp +++ b/CIO/CWindow.cpp @@ -21,8 +21,7 @@ CWindow::CWindow(void callback(int), int callbackQuitMessage, Position pos, Exte Uint8 flags) : CControlContainer(color, {global::bmpArray[WINDOW_LEFT_FRAME].w, global::bmpArray[WINDOW_UPPER_FRAME].h, global::bmpArray[WINDOW_RIGHT_FRAME].w, global::bmpArray[WINDOW_LOWER_FRAME].h}), - x_(pos.x), y_(pos.y), w_(size.x), h_(size.y), title(title), callback_(callback), - callbackQuitMessage(callbackQuitMessage) + pos_(pos), size_(size), title(title), callback_(callback), callbackQuitMessage(callbackQuitMessage) { assert(callback); canMove = (flags & WINDOW_MOVE) != 0; @@ -64,9 +63,10 @@ bool CWindow::hasActiveInputElement() void CWindow::setMouseData(SDL_MouseMotionEvent motion) { // cursor is on the title frame (+/-2 and +/-4 are only for a good optic) - const Position titleFrameLT = Position(x_, y_) + Position(global::bmpArray[WINDOW_LEFT_UPPER_CORNER].w + 2, 4); - const Position titleFrameRB = Position(x_ + w_ - global::bmpArray[WINDOW_RIGHT_UPPER_CORNER].w - 2, - y_ + global::bmpArray[WINDOW_UPPER_FRAME].h - 4); + const Position titleFrameLT = pos_ + Position(global::bmpArray[WINDOW_LEFT_UPPER_CORNER].w + 2, 4); + const Position titleFrameRB = + Position(pos_.x + static_cast(size_.x) - global::bmpArray[WINDOW_RIGHT_UPPER_CORNER].w - 2, + pos_.y + global::bmpArray[WINDOW_UPPER_FRAME].h - 4); if(IsPointInRect(motion.x, motion.y, Rect(titleFrameLT, Extent(titleFrameRB - titleFrameLT)))) { // left button was pressed while moving @@ -79,17 +79,19 @@ void CWindow::setMouseData(SDL_MouseMotionEvent motion) moving = false; if(moving && canMove) { - x_ += motion.xrel; - y_ += motion.yrel; + pos_.x += motion.xrel; + pos_.y += motion.yrel; // make sure to not move the window outside the display surface - if(x_ < 0) - x_ = 0; + if(pos_.x < 0) + pos_.x = 0; { const auto res = global::s2->getRes(); - if(x_ + w_ >= static_cast(res.x)) //-V807 - x_ = static_cast(res.x) - w_ - 1; - if(y_ + h_ >= static_cast(res.y)) - y_ = static_cast(res.y) - h_ - 1; + const int resX = static_cast(res.x); + const int resY = static_cast(res.y); + if(pos_.x + static_cast(size_.x) >= resX) //-V807 + pos_.x = resX - static_cast(size_.x) - 1; + if(pos_.y + static_cast(size_.y) >= resY) + pos_.y = resY - static_cast(size_.y) - 1; } } @@ -97,23 +99,27 @@ void CWindow::setMouseData(SDL_MouseMotionEvent motion) if(canClose) { // cursor is on the button (+/-2 is only for the optic) - canClose_marked = (motion.x >= x_ + 2) && (motion.x < x_ + global::bmpArray[WINDOW_BUTTON_CLOSE].w - 2) - && (motion.y >= y_ + 2) && (motion.y < y_ + global::bmpArray[WINDOW_BUTTON_CLOSE].h - 2); + canClose_marked = (motion.x >= pos_.x + 2) && (motion.x < pos_.x + global::bmpArray[WINDOW_BUTTON_CLOSE].w - 2) + && (motion.y >= pos_.y + 2) + && (motion.y < pos_.y + global::bmpArray[WINDOW_BUTTON_CLOSE].h - 2); } // check whats happen to the minimize button if(canMinimize) { // cursor is on the button (+/-2 is only for the optic) - canMinimize_marked = (motion.x >= x_ + w_ - global::bmpArray[WINDOW_BUTTON_MINIMIZE].w + 2) - && (motion.x < x_ + w_ - 2) && (motion.y >= y_ + 2) - && (motion.y < y_ + global::bmpArray[WINDOW_BUTTON_MINIMIZE].h - 2); + canMinimize_marked = + (motion.x >= pos_.x + static_cast(size_.x) - global::bmpArray[WINDOW_BUTTON_MINIMIZE].w + 2) + && (motion.x < pos_.x + static_cast(size_.x) - 2) && (motion.y >= pos_.y + 2) + && (motion.y < pos_.y + global::bmpArray[WINDOW_BUTTON_MINIMIZE].h - 2); } // check whats happen to the resize button if(canResize) { // cursor is on the button (+/-2 is only for the optic) - if((motion.x >= x_ + w_ - global::bmpArray[WINDOW_BUTTON_RESIZE].w + 2) && (motion.x < x_ + w_ - 2) - && (motion.y >= y_ + h_ - global::bmpArray[WINDOW_BUTTON_RESIZE].h + 2) && (motion.y < y_ + h_ - 2)) + if((motion.x >= pos_.x + static_cast(size_.x) - global::bmpArray[WINDOW_BUTTON_RESIZE].w + 2) + && (motion.x < pos_.x + static_cast(size_.x) - 2) + && (motion.y >= pos_.y + static_cast(size_.y) - global::bmpArray[WINDOW_BUTTON_RESIZE].h + 2) + && (motion.y < pos_.y + static_cast(size_.y) - 2)) { // left button was pressed while moving if(SDL_GetMouseState(nullptr, nullptr) & SDL_BUTTON(SDL_BUTTON_LEFT)) @@ -129,8 +135,7 @@ void CWindow::setMouseData(SDL_MouseMotionEvent motion) // only resize if not minimized if(!minimized) { - w_ += motion.xrel; - h_ += motion.yrel; + size_ = Extent(static_cast(size_.x) + motion.xrel, static_cast(size_.y) + motion.yrel); // MISSING: we have to test if window size is under minimum @@ -146,8 +151,8 @@ void CWindow::setMouseData(SDL_MouseMotionEvent motion) // IMPORTANT: we use the left upper corner of the window as (x,y)=(0,0), so we have to manipulate // the motion-structure before give it to buttons, pictures....: x_absolute - x_window, y_absolute - // y_window - motion.x -= x_; - motion.y -= y_; + motion.x -= pos_.x; + motion.y -= pos_.y; CControlContainer::setMouseData(motion); } } @@ -166,22 +171,23 @@ void CWindow::setMouseData(SDL_MouseButtonEvent button) // will not happen) static int maximized_h = global::bmpArray[WINDOW_UPPER_FRAME].h + global::bmpArray[WINDOW_CORNER_RECTANGLE].h; if(!minimized) - maximized_h = h_; + maximized_h = static_cast(size_.y); // left button is pressed if(button.button == SDL_BUTTON_LEFT) { // cursor is on the title frame (+/-2 and +/-4 are only for a good optic) - if((button.x >= x_ + global::bmpArray[WINDOW_LEFT_UPPER_CORNER].w + 2) - && (button.x < x_ + w_ - global::bmpArray[WINDOW_RIGHT_UPPER_CORNER].w - 2) && (button.y >= y_ + 4) - && (button.y < y_ + +global::bmpArray[WINDOW_UPPER_FRAME].h - 4)) + if((button.x >= pos_.x + global::bmpArray[WINDOW_LEFT_UPPER_CORNER].w + 2) + && (button.x < pos_.x + static_cast(size_.x) - global::bmpArray[WINDOW_RIGHT_UPPER_CORNER].w - 2) + && (button.y >= pos_.y + 4) + && (button.y < pos_.y + static_cast(global::bmpArray[WINDOW_UPPER_FRAME].h) - 4)) { marked = true; clicked = true; } // pressed inside the window - if(button.state == SDL_PRESSED && (button.x >= x_) && (button.x <= x_ + w_) && (button.y >= y_) - && (button.y <= y_ + h_)) + if(button.state == SDL_PRESSED && (button.x >= pos_.x) && (button.x <= pos_.x + static_cast(size_.x)) + && (button.y >= pos_.y) && (button.y <= pos_.y + static_cast(size_.y))) marked = true; // else pressed outside of the window else if(button.state == SDL_PRESSED) @@ -214,11 +220,11 @@ void CWindow::setMouseData(SDL_MouseButtonEvent button) { if(minimized) // maximize now { - h_ = maximized_h; + size_.y = static_cast(maximized_h); minimized = false; } else // minimize now { - h_ = global::bmpArray[WINDOW_UPPER_FRAME].h + global::bmpArray[WINDOW_CORNER_RECTANGLE].h; + size_.y = global::bmpArray[WINDOW_UPPER_FRAME].h + global::bmpArray[WINDOW_CORNER_RECTANGLE].h; minimized = true; } } @@ -237,8 +243,8 @@ void CWindow::setMouseData(SDL_MouseButtonEvent button) // IMPORTANT: we use the left upper corner of the window as (x,y)=(0,0), so we have to manipulate // the motion-structure before give it to buttons, pictures....: x_absolute - x_window, y_absolute - // y_window - button.x -= x_; - button.y -= y_; + button.x -= pos_.x; + button.y -= pos_.y; CControlContainer::setMouseData(button); } @@ -252,8 +258,8 @@ void CWindow::setMouseData(SDL_MouseButtonEvent button) void CWindow::Draw(Position /*parentOrigin*/) { - const Position origin(x_, y_); - const Rect winRect(origin, Extent(w_, h_)); + const Position origin = pos_; + const Rect winRect(origin, size_); // 1. Background fill (tiled) if(getBackground() != WINDOW_NOTHING) @@ -266,8 +272,8 @@ void CWindow::Draw(Position /*parentOrigin*/) const auto& b = getBorder(); const auto contentX = origin.x + b.left; const auto contentY = origin.y + b.top; - const auto contentW = static_cast(w_) - b.left - b.right; - const auto contentH = static_cast(h_) - b.top - b.bottom; + const auto contentW = static_cast(size_.x) - b.left - b.right; + const auto contentH = static_cast(size_.y) - b.top - b.bottom; if(contentW > 0 && contentH > 0) { glEnable(GL_SCISSOR_TEST); @@ -288,7 +294,7 @@ void CWindow::Draw(Position /*parentOrigin*/) // Draw upper frame tile across the top of the window { - const Rect upperFrameRect(origin, Extent(w_, getBmpTexture(upperframe).getHeight())); + const Rect upperFrameRect(origin, Extent(size_.x, getBmpTexture(upperframe).getHeight())); drawTiledBmp(upperframe, upperFrameRect); } @@ -296,29 +302,29 @@ void CWindow::Draw(Position /*parentOrigin*/) if(title) { const int titleY = origin.y + (getBmpTexture(WINDOW_UPPER_FRAME).getHeight() - 9) / 2; - CFont::Draw(title, Position(origin.x + static_cast(w_) / 2, titleY), FontSize::Small, FontColor::Yellow, - FontAlign::Middle); + CFont::Draw(title, Position(origin.x + static_cast(size_.x) / 2, titleY), FontSize::Small, + FontColor::Yellow, FontAlign::Middle); } // 5. Lower frame (tiled across bottom) { const int lowerH = getBmpTexture(WINDOW_LOWER_FRAME).getHeight(); - const Rect lowerFrameRect(Position(origin.x, origin.y + static_cast(h_) - lowerH), - Extent(w_, lowerH)); + const Rect lowerFrameRect(Position(origin.x, origin.y + static_cast(size_.y) - lowerH), + Extent(size_.x, lowerH)); drawTiledBmp(WINDOW_LOWER_FRAME, lowerFrameRect); } // 6. Left frame (tiled down left side) { - const Rect leftFrameRect(origin, Extent(getBmpTexture(WINDOW_LEFT_FRAME).getWidth(), h_)); + const Rect leftFrameRect(origin, Extent(getBmpTexture(WINDOW_LEFT_FRAME).getWidth(), size_.y)); drawTiledBmp(WINDOW_LEFT_FRAME, leftFrameRect); } // 7. Right frame (tiled down right side) { const int rightW = getBmpTexture(WINDOW_RIGHT_FRAME).getWidth(); - const Rect rightFrameRect(Position(origin.x + static_cast(w_) - rightW, origin.y), - Extent(rightW, h_)); + const Rect rightFrameRect(Position(origin.x + static_cast(size_.x) - rightW, origin.y), + Extent(rightW, size_.y)); drawTiledBmp(WINDOW_RIGHT_FRAME, rightFrameRect); } @@ -327,16 +333,13 @@ void CWindow::Draw(Position /*parentOrigin*/) getBmpTexture(WINDOW_LEFT_UPPER_CORNER).Draw(origin); const int ruW = getBmpTexture(WINDOW_RIGHT_UPPER_CORNER).getWidth(); - getBmpTexture(WINDOW_RIGHT_UPPER_CORNER) - .Draw(Position(origin.x + static_cast(w_) - ruW, origin.y)); + getBmpTexture(WINDOW_RIGHT_UPPER_CORNER).Draw(Position(origin.x + static_cast(size_.x) - ruW, origin.y)); const int crW = getBmpTexture(WINDOW_CORNER_RECTANGLE).getWidth(); const int crH = getBmpTexture(WINDOW_CORNER_RECTANGLE).getHeight(); + getBmpTexture(WINDOW_CORNER_RECTANGLE).Draw(Position(origin.x, origin.y + static_cast(size_.y) - crH)); getBmpTexture(WINDOW_CORNER_RECTANGLE) - .Draw(Position(origin.x, origin.y + static_cast(h_) - crH)); - getBmpTexture(WINDOW_CORNER_RECTANGLE) - .Draw(Position(origin.x + static_cast(w_) - crW, - origin.y + static_cast(h_) - crH)); + .Draw(Position(origin.x + static_cast(size_.x) - crW, origin.y + static_cast(size_.y) - crH)); } // 9. Close button @@ -363,7 +366,7 @@ void CWindow::Draw(Position /*parentOrigin*/) else minimizebutton = WINDOW_BUTTON_MINIMIZE; getBmpTexture(minimizebutton) - .Draw(Position(origin.x + static_cast(w_) - getBmpTexture(minimizebutton).getWidth(), origin.y)); + .Draw(Position(origin.x + static_cast(size_.x) - getBmpTexture(minimizebutton).getWidth(), origin.y)); } // 11. Resize button @@ -377,7 +380,8 @@ void CWindow::Draw(Position /*parentOrigin*/) else resizebutton = WINDOW_BUTTON_RESIZE; getBmpTexture(resizebutton) - .Draw(Position(origin + Position(w_, h_)) - Position(getBmpTexture(resizebutton).getWidth(), getBmpTexture(resizebutton).getHeight())); + .Draw(Position(origin + Position(static_cast(size_.x), static_cast(size_.y))) + - Position(getBmpTexture(resizebutton).getWidth(), getBmpTexture(resizebutton).getHeight())); } } diff --git a/CIO/CWindow.h b/CIO/CWindow.h index 62cdf9e..ef9d96d 100644 --- a/CIO/CWindow.h +++ b/CIO/CWindow.h @@ -20,10 +20,8 @@ class CWindow : public CControlContainer bool active = true; protected: - Sint16 x_; - Sint16 y_; - Uint16 w_; - Uint16 h_; + Position pos_; + Extent size_; private: const char* title; @@ -55,13 +53,9 @@ class CWindow : public CControlContainer CWindow(void callback(int), int callbackQuitMessage, WindowPos pos, Extent size, const char* title = nullptr, int color = WINDOW_GREEN1, Uint8 flags = 0); // Access - Position getPos() const { return {x_, y_}; } - Extent getSize() const { return {w_, h_}; } - int getX() const { return x_; }; - int getY() const { return y_; }; - int getW() const { return w_; }; - int getH() const { return h_; }; - Rect getRect() const { return Rect(x_, y_, w_, h_); } + const Position& getPos() const { return pos_; } + const Extent& getSize() const { return size_; } + Rect getRect() const { return Rect(pos_, size_); } int getPriority() const { return priority; } void setPriority(int priority) { this->priority = priority; } void setTitle(const char* title); diff --git a/callbacks.cpp b/callbacks.cpp index 3dd7851..f8dce58 100644 --- a/callbacks.cpp +++ b/callbacks.cpp @@ -17,6 +17,7 @@ #include "CIO/CWindow.h" #include "CMap.h" #include "CSurface.h" +#include "CollisionDetection.h" #include "globals.h" #include "helpers/format.hpp" #include "s25util/strAlgos.h" @@ -815,8 +816,8 @@ void callback::EditorLoadMenu(int Param) int borderT = global::bmpArray[WINDOW_UPPER_FRAME].h; int borderB = global::bmpArray[WINDOW_LOWER_FRAME].h; - int window_w = WNDLoad->getW(); - int window_h = WNDLoad->getH(); + int window_w = static_cast(WNDLoad->getSize().x); + int window_h = static_cast(WNDLoad->getSize().y); int client_w = window_w - borderL - borderR; int client_h = window_h - borderT - borderB; @@ -2866,9 +2867,8 @@ void callback::MinimapMenu(int Param) Position mouse; if(SDL_GetMouseState(&mouse.x, &mouse.y) & SDL_BUTTON(1)) { - if(mouse.x > (WNDMinimap->getX() + 6) && mouse.x < (WNDMinimap->getX() + WNDMinimap->getW() - 6) - && mouse.y > (WNDMinimap->getY() + 20) - && mouse.y < (WNDMinimap->getY() + WNDMinimap->getH() - 10)) + if(IsPointInRect( + mouse, Rect(WNDMinimap->getPos() + Position(6, 20), WNDMinimap->getSize() - Extent(12, 30)))) { DisplayRectangle displayRect = MapObj->getDisplayRect(); displayRect.setOrigin((mouse - WNDMinimap->getRect().getOrigin() - Position(6, 20) From 96e188cf5904a45afece2d3ec9445b6b269ae7d6 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sat, 4 Jul 2026 22:54:42 +0200 Subject: [PATCH 10/40] draw() --- CGame.cpp | 2 +- CGame_Init.cpp | 2 +- CGame_Render.cpp | 12 ++++++------ CIO/CButton.cpp | 6 +++--- CIO/CButton.h | 2 +- CIO/CControlContainer.cpp | 18 +++++++++--------- CIO/CControlContainer.h | 4 ++-- CIO/CFont.cpp | 8 ++++---- CIO/CFont.h | 4 ++-- CIO/CMenu.cpp | 6 +++--- CIO/CMenu.h | 2 +- CIO/CMinimapWindow.cpp | 12 ++++++------ CIO/CMinimapWindow.h | 2 +- CIO/CPicture.cpp | 4 ++-- CIO/CPicture.h | 2 +- CIO/CSelectBox.cpp | 10 +++++----- CIO/CSelectBox.h | 2 +- CIO/CTextfield.cpp | 6 +++--- CIO/CTextfield.h | 2 +- CIO/CWindow.cpp | 20 ++++++++++---------- CIO/CWindow.h | 2 +- Texture.cpp | 22 +++++++++++----------- Texture.h | 12 ++++++------ callbacks.cpp | 2 +- 24 files changed, 82 insertions(+), 82 deletions(-) diff --git a/CGame.cpp b/CGame.cpp index d322c63..e399ac8 100644 --- a/CGame.cpp +++ b/CGame.cpp @@ -78,7 +78,7 @@ int CGame::Execute() void CGame::RenderPresent() { const auto& cursorImg = Cursor.clicked ? (Cursor.button.right ? cross_ : cursorClicked_) : cursor_; - cursorImg.Draw(Cursor.pos); + cursorImg.draw(Cursor.pos); SDL_GL_SwapWindow(window_.get()); } diff --git a/CGame_Init.cpp b/CGame_Init.cpp index 49118a6..c386977 100644 --- a/CGame_Init.cpp +++ b/CGame_Init.cpp @@ -171,7 +171,7 @@ bool CGame::Init() // std::cout << "\nShow loading screen..."; showLoadScreen = true; glClear(GL_COLOR_BUFFER_BIT); - splashBg_.Draw(Rect(0, 0, GameResolution.x, GameResolution.y)); + splashBg_.draw(Rect(0, 0, GameResolution.x, GameResolution.y)); SDL_GL_SwapWindow(window_.get()); GameDataLoader gdLoader(global::worldDesc); diff --git a/CGame_Render.cpp b/CGame_Render.cpp index 664e3af..657dca4 100644 --- a/CGame_Render.cpp +++ b/CGame_Render.cpp @@ -47,7 +47,7 @@ void CGame::Render() // if the S2 loading screen is shown, render only this until user clicks a mouse button if(showLoadScreen) { - splashBg_.Draw(Rect(0, 0, GameResolution.x, GameResolution.y)); + splashBg_.draw(Rect(0, 0, GameResolution.x, GameResolution.y)); SDL_GL_SwapWindow(window_.get()); return; } @@ -75,7 +75,7 @@ void CGame::Render() FontColor::Orange); mapTex_.load(mapSurf); - mapTex_.Draw(Rect(0, 0, GameResolution.x, GameResolution.y)); + mapTex_.draw(Rect(0, 0, GameResolution.x, GameResolution.y)); } } @@ -83,7 +83,7 @@ void CGame::Render() for(auto& Menu : Menus) { if(Menu->isActive()) - Menu->Draw(Position(0, 0)); + Menu->draw(Position(0, 0)); } // render windows ordered by priority @@ -100,7 +100,7 @@ void CGame::Render() for(auto& Window : Windows) { if(Window->getPriority() == actualPriority) - Window->Draw(Position(0, 0)); + Window->draw(Position(0, 0)); } } @@ -118,11 +118,11 @@ void CGame::Render() lastFpsTick = curTicks; } // Draw FPS counter - lastFps.Draw(Position(0, 0)); + lastFps.draw(Position(0, 0)); // Cursor on top of everything const auto& cursorImg = Cursor.clicked ? (Cursor.button.right ? cross_ : cursorClicked_) : cursor_; - cursorImg.Draw(Cursor.pos); + cursorImg.draw(Cursor.pos); SDL_GL_SwapWindow(window_.get()); diff --git a/CIO/CButton.cpp b/CIO/CButton.cpp index 3ac7d5a..38cc5f6 100644 --- a/CIO/CButton.cpp +++ b/CIO/CButton.cpp @@ -124,7 +124,7 @@ void CButton::setMouseData(const SDL_MouseButtonEvent& button) } } -void CButton::Draw(Position parentOrigin) const +void CButton::draw(Position parentOrigin) const { const Position absPos = parentOrigin + pos_; @@ -139,7 +139,7 @@ void CButton::Draw(Position parentOrigin) const if(picTex.isValid()) { const Position picPos = absPos + size_ / 2 - Position(picTex.getWidth(), picTex.getHeight()) / 2; - picTex.Draw(picPos); + picTex.draw(picPos); } } else if(button_text) { @@ -148,6 +148,6 @@ void CButton::Draw(Position parentOrigin) const const unsigned textH = static_cast(FontSize::Medium); const Position textPos = absPos + Position(static_cast(size_.x / 2 - textW / 2), static_cast((size_.y - textH) / 2)); - CFont::Draw(button_text, textPos, FontSize::Medium, button_text_color, FontAlign::Left); + CFont::draw(button_text, textPos, FontSize::Medium, button_text_color, FontAlign::Left); } } diff --git a/CIO/CButton.h b/CIO/CButton.h index 034d93d..531a728 100644 --- a/CIO/CButton.h +++ b/CIO/CButton.h @@ -41,7 +41,7 @@ class CButton void setButtonText(const char* text); void setMouseData(const SDL_MouseMotionEvent& motion); void setMouseData(const SDL_MouseButtonEvent& button); - void Draw(Position parentOrigin) const; + void draw(Position parentOrigin) const; void setColor(int color); void setTextColor(FontColor color) { button_text_color = color; }; void setMotionParams(int entry, int leave) diff --git a/CIO/CControlContainer.cpp b/CIO/CControlContainer.cpp index e561bb1..26fd05b 100644 --- a/CIO/CControlContainer.cpp +++ b/CIO/CControlContainer.cpp @@ -179,27 +179,27 @@ bool CControlContainer::delSelectBox(CSelectBox* SelectBoxToDelete) // Draw & DrawChildren // --------------------------------------------------------------------------- -void CControlContainer::Draw(Position parentOrigin) +void CControlContainer::draw(Position parentOrigin) { - DrawChildren(parentOrigin); + drawChildren(parentOrigin); } -void CControlContainer::DrawChildren(Position origin) +void CControlContainer::drawChildren(Position origin) { for(const auto& picture : pictures) - picture->Draw(origin); + picture->draw(origin); for(const auto& text : texts) - text->Draw(origin); + text->draw(origin); for(const auto& textfield : textfields) - textfield->Draw(origin); + textfield->draw(origin); for(const auto& selectbox : selectboxes) - selectbox->Draw(origin); + selectbox->draw(origin); for(const auto& button : buttons) - button->Draw(origin); + button->draw(origin); for(const auto& static_picture : static_pictures) { auto& tex = getBmpTexture(static_picture.pic); if(tex.isValid()) - tex.Draw(origin + static_picture.pos); + tex.draw(origin + static_picture.pos); } } diff --git a/CIO/CControlContainer.h b/CIO/CControlContainer.h index e815cdc..6367a05 100644 --- a/CIO/CControlContainer.h +++ b/CIO/CControlContainer.h @@ -53,9 +53,9 @@ class CControlContainer protected: /// Draw the container's background and child elements using OpenGL. /// @param parentOrigin Absolute position of the parent container. - virtual void Draw(Position parentOrigin); + virtual void draw(Position parentOrigin); /// Draw children at the given origin (calls each child's Draw). - void DrawChildren(Position origin); + void drawChildren(Position origin); auto& getTextFields() { return textfields; } const auto& getTextFields() const { return textfields; } diff --git a/CIO/CFont.cpp b/CIO/CFont.cpp index 7ed89ad..c39f2d5 100644 --- a/CIO/CFont.cpp +++ b/CIO/CFont.cpp @@ -196,14 +196,14 @@ unsigned getCharWidth(uint8_t c, FontSize fontsize, FontColor color) // OpenGL Draw methods // --------------------------------------------------------------------------- -void CFont::Draw(Position parentOrigin) const +void CFont::draw(Position parentOrigin) const { if(string_.empty()) return; - Draw(string_, parentOrigin + pos_, fontsize_, color_, FontAlign::Left); + draw(string_, parentOrigin + pos_, fontsize_, color_, FontAlign::Left); } -void CFont::Draw(const std::string& string, Position pos, FontSize fontsize, FontColor color, FontAlign align) +void CFont::draw(const std::string& string, Position pos, FontSize fontsize, FontColor color, FontAlign align) { if(string.empty()) return; @@ -237,7 +237,7 @@ void CFont::Draw(const std::string& string, Position pos, FontSize fontsize, Fon } const auto& bmp = global::bmpArray[idx]; - tex.Draw(Rect(curPos.x, curPos.y, bmp.w, bmp.h)); + tex.draw(Rect(curPos.x, curPos.y, bmp.w, bmp.h)); curPos.x += bmp.w; } } diff --git a/CIO/CFont.h b/CIO/CFont.h index 37289f8..230fc59 100644 --- a/CIO/CFont.h +++ b/CIO/CFont.h @@ -48,11 +48,11 @@ class CFont void setMouseData(SDL_MouseButtonEvent button); /// Draw this font's text at the given absolute position using OpenGL. - void Draw(Position parentOrigin) const; + void draw(Position parentOrigin) const; /// Static helpers for drawing text with OpenGL directly. /// @param pos Absolute position (top-left of the text, adjusted for alignment). - static void Draw(const std::string& string, Position pos, FontSize fontsize = FontSize::Small, + static void draw(const std::string& string, Position pos, FontSize fontsize = FontSize::Small, FontColor color = FontColor::Yellow, FontAlign align = FontAlign::Left); /// Static helper: draw text onto an SDL surface (for terrain / minimap rendering). diff --git a/CIO/CMenu.cpp b/CIO/CMenu.cpp index 4591948..96f53f4 100644 --- a/CIO/CMenu.cpp +++ b/CIO/CMenu.cpp @@ -10,7 +10,7 @@ CMenu::CMenu(int pic_background) : CControlContainer(pic_background) {} -void CMenu::Draw(Position /*parentOrigin*/) +void CMenu::draw(Position /*parentOrigin*/) { // Draw full-screen background texture const int picIdx = getBackground(); @@ -20,10 +20,10 @@ void CMenu::Draw(Position /*parentOrigin*/) if(tex.isValid()) { const auto res = global::s2->getRes(); - tex.Draw(Rect(0, 0, res.x, res.y)); + tex.draw(Rect(0, 0, res.x, res.y)); } } // Draw children - DrawChildren(Position(0, 0)); + drawChildren(Position(0, 0)); } diff --git a/CIO/CMenu.h b/CIO/CMenu.h index 487e658..0b4fedb 100644 --- a/CIO/CMenu.h +++ b/CIO/CMenu.h @@ -18,5 +18,5 @@ class CMenu final : public CControlContainer void setInactive() { active = false; } bool isActive() const { return active; } - void Draw(Position parentOrigin) override; + void draw(Position parentOrigin) override; }; diff --git a/CIO/CMinimapWindow.cpp b/CIO/CMinimapWindow.cpp index 7501837..f439b9d 100644 --- a/CIO/CMinimapWindow.cpp +++ b/CIO/CMinimapWindow.cpp @@ -9,10 +9,10 @@ #include "../globals.h" #include "CFont.h" -void CMinimapWindow::Draw(Position /*parentOrigin*/) +void CMinimapWindow::draw(Position /*parentOrigin*/) { // Draw window chrome (frame, title, close button, background, child elements) - CWindow::Draw(pos_); + CWindow::draw(pos_); // Compute content area (inside the frames) const auto& b = getBorder(); @@ -35,7 +35,7 @@ void CMinimapWindow::Draw(Position /*parentOrigin*/) if(!minimapTex_.isValid() || minimapTex_.getWidth() != cw || minimapTex_.getHeight() != ch) minimapTex_.createEmpty(contentSize); minimapTex_.upload(pixels_.data()); - minimapTex_.Draw(Rect(contentPos, contentSize)); + minimapTex_.draw(Rect(contentPos, contentSize)); // Draw player flags and numbers on top for(int i = 0; i < MAXPLAYERS; i++) @@ -47,12 +47,12 @@ void CMinimapWindow::Draw(Position /*parentOrigin*/) const int flagIdx = FLAG_BLUE_DARK + i % 7; const Position hqPos(hqX / num_x, hqY / num_y); - getBmpTexture(flagIdx).Draw( + getBmpTexture(flagIdx).draw( contentPos + hqPos - Position(static_cast(global::bmpArray[flagIdx].nx), static_cast(global::bmpArray[flagIdx].ny))); // Player number - CFont::Draw(std::to_string(i + 1), contentPos + hqPos, FontSize::Small, FontColor::MintGreen); + CFont::draw(std::to_string(i + 1), contentPos + hqPos, FontSize::Small, FontColor::MintGreen); } // Draw the position arrow @@ -64,6 +64,6 @@ void CMinimapWindow::Draw(Position /*parentOrigin*/) + Position((dispRect.left + static_cast(dispRect.getSize().x) / 2) / triangleWidth / num_x, (dispRect.top + static_cast(dispRect.getSize().y) / 2) / triangleHeight / num_y) - Position(static_cast(global::bmpArray[arrowIdx].nx), static_cast(global::bmpArray[arrowIdx].ny)); - getBmpTexture(arrowIdx).Draw(arrowPos); + getBmpTexture(arrowIdx).draw(arrowPos); } } diff --git a/CIO/CMinimapWindow.h b/CIO/CMinimapWindow.h index dc76cda..715442b 100644 --- a/CIO/CMinimapWindow.h +++ b/CIO/CMinimapWindow.h @@ -13,7 +13,7 @@ class CMinimapWindow final : public CWindow std::vector pixels_; ///< Pixel buffer for minimap terrain Texture minimapTex_; - void Draw(Position parentOrigin) override; + void draw(Position parentOrigin) override; public: using CWindow::CWindow; diff --git a/CIO/CPicture.cpp b/CIO/CPicture.cpp index 12bd5f2..a4d5975 100644 --- a/CIO/CPicture.cpp +++ b/CIO/CPicture.cpp @@ -64,10 +64,10 @@ void CPicture::setMouseData(const SDL_MouseButtonEvent& button) } } -void CPicture::Draw(Position parentOrigin) const +void CPicture::draw(Position parentOrigin) const { auto& tex = getBmpTexture(picture_); if(!tex.isValid()) return; - tex.Draw(parentOrigin + pos_); + tex.draw(parentOrigin + pos_); } diff --git a/CIO/CPicture.h b/CIO/CPicture.h index 797998e..758bd48 100644 --- a/CIO/CPicture.h +++ b/CIO/CPicture.h @@ -34,7 +34,7 @@ class CPicture void setY(int y) { pos_.y = y; }; void setMouseData(const SDL_MouseMotionEvent& motion); void setMouseData(const SDL_MouseButtonEvent& button); - void Draw(Position parentOrigin) const; + void draw(Position parentOrigin) const; void setMotionParams(int entry, int leave) { motionEntryParam = entry; diff --git a/CIO/CSelectBox.cpp b/CIO/CSelectBox.cpp index 3bb1262..598b800 100644 --- a/CIO/CSelectBox.cpp +++ b/CIO/CSelectBox.cpp @@ -215,7 +215,7 @@ void CSelectBox::setPos(Position pos) pos_ = pos; } -void CSelectBox::Draw(Position parentOrigin) +void CSelectBox::draw(Position parentOrigin) { const Position absPos = parentOrigin + pos_; const Rect area(absPos, size_); @@ -227,7 +227,7 @@ void CSelectBox::Draw(Position parentOrigin) } else { // Fill with black - DrawRect(area, 0, 0, 0, 255); + drawRect(area, 0, 0, 0, 255); } // Clip entries to the select box area @@ -239,14 +239,14 @@ void CSelectBox::Draw(Position parentOrigin) // Draw entries for(const auto& entry : Entries) { - entry->Draw(absPos); + entry->draw(absPos); } glDisable(GL_SCISSOR_TEST); // Draw scroll buttons (on top, within the select box) - ScrollUpButton->Draw(absPos); - ScrollDownButton->Draw(absPos); + ScrollUpButton->draw(absPos); + ScrollDownButton->draw(absPos); rendered = true; } diff --git a/CIO/CSelectBox.h b/CIO/CSelectBox.h index 88e277b..4257cc1 100644 --- a/CIO/CSelectBox.h +++ b/CIO/CSelectBox.h @@ -38,7 +38,7 @@ class CSelectBox bool hasRendered(); void setMouseData(SDL_MouseButtonEvent button); void setMouseData(SDL_MouseMotionEvent motion); - void Draw(Position parentOrigin); + void draw(Position parentOrigin); void setColor(int color); void setTextColor(FontColor color) { text_color = color; } void addOption(const std::string& string, std::function callback = nullptr, int param = 0); diff --git a/CIO/CTextfield.cpp b/CIO/CTextfield.cpp index e148ea2..40ccdfb 100644 --- a/CIO/CTextfield.cpp +++ b/CIO/CTextfield.cpp @@ -229,7 +229,7 @@ void CTextfield::setKeyboardData(const SDL_KeyboardEvent& key) } } -void CTextfield::Draw(Position parentOrigin) +void CTextfield::draw(Position parentOrigin) { const Position absPos = parentOrigin + getPos(); const Rect area(absPos, size_); @@ -264,7 +264,7 @@ void CTextfield::Draw(Position parentOrigin) } else { // Fill with black - DrawRect(area, 0, 0, 0, 255); + drawRect(area, 0, 0, 0, 255); } // Prepare text with cursor @@ -280,7 +280,7 @@ void CTextfield::Draw(Position parentOrigin) if(!displayText.empty()) { textObj->setText(displayText); - textObj->Draw(Position(area.left + 2, area.top + 2)); + textObj->draw(Position(area.left + 2, area.top + 2)); } rendered = true; diff --git a/CIO/CTextfield.h b/CIO/CTextfield.h index c689f5b..e0234fa 100644 --- a/CIO/CTextfield.h +++ b/CIO/CTextfield.h @@ -50,7 +50,7 @@ class CTextfield bool hasRendered(); void setMouseData(SDL_MouseButtonEvent button); void setKeyboardData(const SDL_KeyboardEvent& key); - void Draw(Position parentOrigin); + void draw(Position parentOrigin); void setColor(int color); void setTextColor(FontColor color); std::string getText() const { return text_.data(); } diff --git a/CIO/CWindow.cpp b/CIO/CWindow.cpp index 98789bf..94b2a65 100644 --- a/CIO/CWindow.cpp +++ b/CIO/CWindow.cpp @@ -256,7 +256,7 @@ void CWindow::setMouseData(SDL_MouseButtonEvent button) // Draw — OpenGL version of the old render() // --------------------------------------------------------------------------- -void CWindow::Draw(Position /*parentOrigin*/) +void CWindow::draw(Position /*parentOrigin*/) { const Position origin = pos_; const Rect winRect(origin, size_); @@ -278,7 +278,7 @@ void CWindow::Draw(Position /*parentOrigin*/) { glEnable(GL_SCISSOR_TEST); glScissor(contentX, viewH - (contentY + contentH), contentW, contentH); - DrawChildren(origin); + drawChildren(origin); glDisable(GL_SCISSOR_TEST); } } @@ -302,7 +302,7 @@ void CWindow::Draw(Position /*parentOrigin*/) if(title) { const int titleY = origin.y + (getBmpTexture(WINDOW_UPPER_FRAME).getHeight() - 9) / 2; - CFont::Draw(title, Position(origin.x + static_cast(size_.x) / 2, titleY), FontSize::Small, + CFont::draw(title, Position(origin.x + static_cast(size_.x) / 2, titleY), FontSize::Small, FontColor::Yellow, FontAlign::Middle); } @@ -330,16 +330,16 @@ void CWindow::Draw(Position /*parentOrigin*/) // 8. Corners { - getBmpTexture(WINDOW_LEFT_UPPER_CORNER).Draw(origin); + getBmpTexture(WINDOW_LEFT_UPPER_CORNER).draw(origin); const int ruW = getBmpTexture(WINDOW_RIGHT_UPPER_CORNER).getWidth(); - getBmpTexture(WINDOW_RIGHT_UPPER_CORNER).Draw(Position(origin.x + static_cast(size_.x) - ruW, origin.y)); + getBmpTexture(WINDOW_RIGHT_UPPER_CORNER).draw(Position(origin.x + static_cast(size_.x) - ruW, origin.y)); const int crW = getBmpTexture(WINDOW_CORNER_RECTANGLE).getWidth(); const int crH = getBmpTexture(WINDOW_CORNER_RECTANGLE).getHeight(); - getBmpTexture(WINDOW_CORNER_RECTANGLE).Draw(Position(origin.x, origin.y + static_cast(size_.y) - crH)); + getBmpTexture(WINDOW_CORNER_RECTANGLE).draw(Position(origin.x, origin.y + static_cast(size_.y) - crH)); getBmpTexture(WINDOW_CORNER_RECTANGLE) - .Draw(Position(origin.x + static_cast(size_.x) - crW, origin.y + static_cast(size_.y) - crH)); + .draw(Position(origin.x + static_cast(size_.x) - crW, origin.y + static_cast(size_.y) - crH)); } // 9. Close button @@ -352,7 +352,7 @@ void CWindow::Draw(Position /*parentOrigin*/) closebutton = WINDOW_BUTTON_CLOSE_MARKED; else closebutton = WINDOW_BUTTON_CLOSE; - getBmpTexture(closebutton).Draw(origin); + getBmpTexture(closebutton).draw(origin); } // 10. Minimize button @@ -366,7 +366,7 @@ void CWindow::Draw(Position /*parentOrigin*/) else minimizebutton = WINDOW_BUTTON_MINIMIZE; getBmpTexture(minimizebutton) - .Draw(Position(origin.x + static_cast(size_.x) - getBmpTexture(minimizebutton).getWidth(), origin.y)); + .draw(Position(origin.x + static_cast(size_.x) - getBmpTexture(minimizebutton).getWidth(), origin.y)); } // 11. Resize button @@ -380,7 +380,7 @@ void CWindow::Draw(Position /*parentOrigin*/) else resizebutton = WINDOW_BUTTON_RESIZE; getBmpTexture(resizebutton) - .Draw(Position(origin + Position(static_cast(size_.x), static_cast(size_.y))) + .draw(Position(origin + Position(static_cast(size_.x), static_cast(size_.y))) - Position(getBmpTexture(resizebutton).getWidth(), getBmpTexture(resizebutton).getHeight())); } } diff --git a/CIO/CWindow.h b/CIO/CWindow.h index ef9d96d..a0e7c77 100644 --- a/CIO/CWindow.h +++ b/CIO/CWindow.h @@ -46,7 +46,7 @@ class CWindow : public CControlContainer public: /// Draw the window using OpenGL (frame and children). - void Draw(Position parentOrigin) override; + void draw(Position parentOrigin) override; CWindow(void callback(int), int callbackQuitMessage, Position pos, Extent size, const char* title = nullptr, int color = WINDOW_GREEN1, Uint8 flags = 0); diff --git a/Texture.cpp b/Texture.cpp index 0e3f883..2ee2827 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -122,7 +122,7 @@ bool Texture::load(SDL_Surface* surface, bool filterLinear) return true; } -void Texture::Draw(const Rect& destRect) const +void Texture::draw(const Rect& destRect) const { if(!texture_) return; @@ -140,7 +140,7 @@ void Texture::Draw(const Rect& destRect) const glEnd(); } -void Texture::Draw(Position pos) const +void Texture::draw(Position pos) const { if(!texture_) return; @@ -158,7 +158,7 @@ void Texture::Draw(Position pos) const glEnd(); } -void Texture::Draw(const Rect& destRect, const Rect& srcRect) const +void Texture::draw(const Rect& destRect, const Rect& srcRect) const { if(!texture_) return; @@ -189,7 +189,7 @@ void Texture::Draw(const Rect& destRect, const Rect& srcRect) const glEnd(); } -void DrawRect(const Rect& rect, unsigned char r, unsigned char g, unsigned char b, unsigned char a) +void drawRect(const Rect& rect, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { glDisable(GL_TEXTURE_2D); glColor4ub(r, g, b, a); @@ -202,12 +202,12 @@ void DrawRect(const Rect& rect, unsigned char r, unsigned char g, unsigned char glEnable(GL_TEXTURE_2D); } -void DrawRect(const Rect& rect, unsigned color) +void drawRect(const Rect& rect, unsigned color) { - DrawRect(rect, (color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF, (color >> 24) & 0xFF); + drawRect(rect, (color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF, (color >> 24) & 0xFF); } -void DrawLine(Position p1, Position p2, unsigned char r, unsigned char g, unsigned char b, unsigned char a) +void drawLine(Position p1, Position p2, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { glDisable(GL_TEXTURE_2D); glColor4ub(r, g, b, a); @@ -297,12 +297,12 @@ void drawButtonBox(const Rect& area, bool pressed, int baseTex, int faceTex) // 2px black frame: left+top if pressed, right+bottom otherwise if(pressed) { - DrawRect(Rect(area.left, area.top, 2, h), 0, 0, 0); - DrawRect(Rect(area.left, area.top, w, 2), 0, 0, 0); + drawRect(Rect(area.left, area.top, 2, h), 0, 0, 0); + drawRect(Rect(area.left, area.top, w, 2), 0, 0, 0); } else { - DrawRect(Rect(area.right - 2, area.top, 2, h), 0, 0, 0); - DrawRect(Rect(area.left, area.bottom - 2, w, 2), 0, 0, 0); + drawRect(Rect(area.right - 2, area.top, 2, h), 0, 0, 0); + drawRect(Rect(area.left, area.bottom - 2, w, 2), 0, 0, 0); } // Foreground inset by 2px diff --git a/Texture.h b/Texture.h index 1969038..b9243c9 100644 --- a/Texture.h +++ b/Texture.h @@ -33,14 +33,14 @@ class Texture void upload(const void* bgraPixels); /// Draw the texture stretched to fill the given rect. - void Draw(const Rect& destRect) const; + void draw(const Rect& destRect) const; /// Draw the texture at native size at the given position. - void Draw(Position pos) const; + void draw(Position pos) const; /// Draw a sub-rectangle of the texture to fill the given destination rect. /// srcRect is in texture-local coordinates (may be clipped). - void Draw(const Rect& destRect, const Rect& srcRect) const; + void draw(const Rect& destRect, const Rect& srcRect) const; /// Returns the raw GL texture name (for use with glBindTexture). unsigned getHandle() const { return texture_; } @@ -67,13 +67,13 @@ class Texture // --------------------------------------------------------------------------- /// Draw a filled rectangle. -void DrawRect(const Rect& rect, unsigned char r, unsigned char g, unsigned char b, unsigned char a = 255); +void drawRect(const Rect& rect, unsigned char r, unsigned char g, unsigned char b, unsigned char a = 255); /// Draw a filled rectangle with a 32-bit ARGB colour. -void DrawRect(const Rect& rect, unsigned color); +void drawRect(const Rect& rect, unsigned color); /// Draw a 1-pixel-wide line. -void DrawLine(Position p1, Position p2, unsigned char r, unsigned char g, unsigned char b, unsigned char a = 255); +void drawLine(Position p1, Position p2, unsigned char r, unsigned char g, unsigned char b, unsigned char a = 255); // --------------------------------------------------------------------------- // Texture-drawing helpers for UI components diff --git a/callbacks.cpp b/callbacks.cpp index f8dce58..d05f979 100644 --- a/callbacks.cpp +++ b/callbacks.cpp @@ -55,7 +55,7 @@ void callback::PleaseWait(int Param) // we need to render this window NOW, cause the render loop will do it too late (when the operation // is done and we don't need the "Please wait"-window anymore) glClear(GL_COLOR_BUFFER_BIT); - WNDWait->Draw(Position(0, 0)); + WNDWait->draw(Position(0, 0)); global::s2->RenderPresent(); break; From 37be0aefeaab9f45385ee5bf304e7d9c3014e2d9 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sat, 4 Jul 2026 23:02:21 +0200 Subject: [PATCH 11/40] unsigned idx --- Texture.cpp | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/Texture.cpp b/Texture.cpp index 2ee2827..ab10a1b 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -164,27 +164,25 @@ void Texture::draw(const Rect& destRect, const Rect& srcRect) const return; // Clamp source rect to texture bounds - int srcL = std::max(0, srcRect.left); - int srcT = std::max(0, srcRect.top); - int srcR = std::min(static_cast(size_.x), srcRect.right); - int srcB = std::min(static_cast(size_.y), srcRect.bottom); - if(srcL >= srcR || srcT >= srcB) + const Position clampedOrigin(std::max(0, srcRect.left), std::max(0, srcRect.top)); + const Position clampedEnd(std::min(static_cast(size_.x), srcRect.right), + std::min(static_cast(size_.y), srcRect.bottom)); + if(clampedOrigin.x >= clampedEnd.x || clampedOrigin.y >= clampedEnd.y) return; - const float u0 = float(srcL) / float(size_.x); - const float v0 = float(srcT) / float(size_.y); - const float u1 = float(srcR) / float(size_.x); - const float v1 = float(srcB) / float(size_.y); + const auto texSize = Position(static_cast(size_.x), static_cast(size_.y)); + const Point uv0 = Point(clampedOrigin) / Point(texSize); + const Point uv1 = Point(clampedEnd) / Point(texSize); glBindTexture(GL_TEXTURE_2D, texture_); glBegin(GL_QUADS); - glTexCoord2f(u0, v0); + glTexCoord2f(uv0.x, uv0.y); glVertex2i(destRect.left, destRect.top); - glTexCoord2f(u1, v0); + glTexCoord2f(uv1.x, uv0.y); glVertex2i(destRect.right, destRect.top); - glTexCoord2f(u1, v1); + glTexCoord2f(uv1.x, uv1.y); glVertex2i(destRect.right, destRect.bottom); - glTexCoord2f(u0, v1); + glTexCoord2f(uv0.x, uv1.y); glVertex2i(destRect.left, destRect.bottom); glEnd(); } @@ -222,15 +220,15 @@ Texture& getBmpTexture(int idx, bool filterLinear) { static std::vector> cache; static std::vector linearFlags; - if(idx < 0 || idx >= static_cast(global::bmpArray.size())) + if(static_cast(idx) >= global::bmpArray.size()) { static Texture dummy; return dummy; } - if(static_cast(cache.size()) <= idx) + if(static_cast(idx) >= cache.size()) { - cache.resize(idx + 1); - linearFlags.resize(idx + 1, false); + cache.resize(static_cast(idx) + 1); + linearFlags.resize(static_cast(idx) + 1, false); } if(!cache[idx] || linearFlags[idx] != filterLinear) { @@ -246,7 +244,7 @@ Texture& getBmpTexture(int idx, bool filterLinear) void ensureBmpTex(int idx) { - if(idx < 0 || idx >= static_cast(global::bmpArray.size())) + if(static_cast(idx) >= global::bmpArray.size()) return; getBmpTexture(idx); } From 19e0f0fc78b956351f0fedb8ff7c4bbfa563ab45 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sat, 4 Jul 2026 23:11:07 +0200 Subject: [PATCH 12/40] Position/Extent --- CIO/CButton.cpp | 2 +- CIO/CWindow.cpp | 2 +- Texture.cpp | 19 +++++++++---------- Texture.h | 3 +++ 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/CIO/CButton.cpp b/CIO/CButton.cpp index 38cc5f6..dfe210f 100644 --- a/CIO/CButton.cpp +++ b/CIO/CButton.cpp @@ -138,7 +138,7 @@ void CButton::draw(Position parentOrigin) const auto& picTex = getBmpTexture(button_picture); if(picTex.isValid()) { - const Position picPos = absPos + size_ / 2 - Position(picTex.getWidth(), picTex.getHeight()) / 2; + const Position picPos = absPos + size_ / 2 - Position(picTex.getSize()) / 2; picTex.draw(picPos); } } else if(button_text) diff --git a/CIO/CWindow.cpp b/CIO/CWindow.cpp index 94b2a65..8001bfa 100644 --- a/CIO/CWindow.cpp +++ b/CIO/CWindow.cpp @@ -381,7 +381,7 @@ void CWindow::draw(Position /*parentOrigin*/) resizebutton = WINDOW_BUTTON_RESIZE; getBmpTexture(resizebutton) .draw(Position(origin + Position(static_cast(size_.x), static_cast(size_.y))) - - Position(getBmpTexture(resizebutton).getWidth(), getBmpTexture(resizebutton).getHeight())); + - Position(getBmpTexture(resizebutton).getSize())); } } diff --git a/Texture.cpp b/Texture.cpp index ab10a1b..2524846 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -170,7 +170,7 @@ void Texture::draw(const Rect& destRect, const Rect& srcRect) const if(clampedOrigin.x >= clampedEnd.x || clampedOrigin.y >= clampedEnd.y) return; - const auto texSize = Position(static_cast(size_.x), static_cast(size_.y)); + const auto texSize = Position(getSize()); const Point uv0 = Point(clampedOrigin) / Point(texSize); const Point uv1 = Point(clampedEnd) / Point(texSize); @@ -255,22 +255,21 @@ void drawTiledBmp(int bmpIdx, const Rect& destRect) if(!tex.isValid()) return; - const unsigned tileW = static_cast(tex.getWidth()); - const unsigned tileH = static_cast(tex.getHeight()); - if(tileW == 0 || tileH == 0) + const Position tileSize(tex.getSize()); + if(tileSize.x <= 0 || tileSize.y <= 0) return; glColor4f(1, 1, 1, 1); glBindTexture(GL_TEXTURE_2D, tex.getHandle()); glBegin(GL_QUADS); - for(int y = destRect.top; y < destRect.bottom; y += static_cast(tileH)) + for(int y = destRect.top; y < destRect.bottom; y += tileSize.y) { - const int rowH = std::min(static_cast(tileH), static_cast(destRect.bottom - y)); - const float v1 = static_cast(rowH) / static_cast(tileH); - for(int x = destRect.left; x < destRect.right; x += static_cast(tileW)) + const int rowH = std::min(tileSize.y, destRect.bottom - y); + const float v1 = float(rowH) / float(tileSize.y); + for(int x = destRect.left; x < destRect.right; x += tileSize.x) { - const int colW = std::min(static_cast(tileW), static_cast(destRect.right - x)); - const float u1 = static_cast(colW) / static_cast(tileW); + const int colW = std::min(tileSize.x, destRect.right - x); + const float u1 = float(colW) / float(tileSize.x); glTexCoord2f(0, 0); glVertex2i(x, y); diff --git a/Texture.h b/Texture.h index b9243c9..4e4a02a 100644 --- a/Texture.h +++ b/Texture.h @@ -45,6 +45,9 @@ class Texture /// Returns the raw GL texture name (for use with glBindTexture). unsigned getHandle() const { return texture_; } + /// Size in pixels. + Extent getSize() const { return size_; } + /// Width in pixels. int getWidth() const { return size_.x; } From 795cbbb41bf53d88e01e8bba88bdd70e5badd8f3 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sat, 4 Jul 2026 23:17:03 +0200 Subject: [PATCH 13/40] color args --- CIO/CSelectBox.cpp | 2 +- CIO/CTextfield.cpp | 2 +- Texture.cpp | 17 ++++++----------- Texture.h | 3 --- 4 files changed, 8 insertions(+), 16 deletions(-) diff --git a/CIO/CSelectBox.cpp b/CIO/CSelectBox.cpp index 598b800..ff6618d 100644 --- a/CIO/CSelectBox.cpp +++ b/CIO/CSelectBox.cpp @@ -227,7 +227,7 @@ void CSelectBox::draw(Position parentOrigin) } else { // Fill with black - drawRect(area, 0, 0, 0, 255); + drawRect(area, 0xFF000000); } // Clip entries to the select box area diff --git a/CIO/CTextfield.cpp b/CIO/CTextfield.cpp index 40ccdfb..544a9c9 100644 --- a/CIO/CTextfield.cpp +++ b/CIO/CTextfield.cpp @@ -264,7 +264,7 @@ void CTextfield::draw(Position parentOrigin) } else { // Fill with black - drawRect(area, 0, 0, 0, 255); + drawRect(area, 0xFF000000); } // Prepare text with cursor diff --git a/Texture.cpp b/Texture.cpp index 2524846..b8354cd 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -187,10 +187,10 @@ void Texture::draw(const Rect& destRect, const Rect& srcRect) const glEnd(); } -void drawRect(const Rect& rect, unsigned char r, unsigned char g, unsigned char b, unsigned char a) +void drawRect(const Rect& rect, unsigned color) { glDisable(GL_TEXTURE_2D); - glColor4ub(r, g, b, a); + glColor4ub((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF, (color >> 24) & 0xFF); glBegin(GL_QUADS); glVertex2i(rect.left, rect.top); glVertex2i(rect.right, rect.top); @@ -200,11 +200,6 @@ void drawRect(const Rect& rect, unsigned char r, unsigned char g, unsigned char glEnable(GL_TEXTURE_2D); } -void drawRect(const Rect& rect, unsigned color) -{ - drawRect(rect, (color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF, (color >> 24) & 0xFF); -} - void drawLine(Position p1, Position p2, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { glDisable(GL_TEXTURE_2D); @@ -294,12 +289,12 @@ void drawButtonBox(const Rect& area, bool pressed, int baseTex, int faceTex) // 2px black frame: left+top if pressed, right+bottom otherwise if(pressed) { - drawRect(Rect(area.left, area.top, 2, h), 0, 0, 0); - drawRect(Rect(area.left, area.top, w, 2), 0, 0, 0); + drawRect(Rect(area.left, area.top, 2, h), 0xFF000000); + drawRect(Rect(area.left, area.top, w, 2), 0xFF000000); } else { - drawRect(Rect(area.right - 2, area.top, 2, h), 0, 0, 0); - drawRect(Rect(area.left, area.bottom - 2, w, 2), 0, 0, 0); + drawRect(Rect(area.right - 2, area.top, 2, h), 0xFF000000); + drawRect(Rect(area.left, area.bottom - 2, w, 2), 0xFF000000); } // Foreground inset by 2px diff --git a/Texture.h b/Texture.h index 4e4a02a..706d3a2 100644 --- a/Texture.h +++ b/Texture.h @@ -69,9 +69,6 @@ class Texture // Free functions for simple GL drawing (rect, line) used by UI components. // --------------------------------------------------------------------------- -/// Draw a filled rectangle. -void drawRect(const Rect& rect, unsigned char r, unsigned char g, unsigned char b, unsigned char a = 255); - /// Draw a filled rectangle with a 32-bit ARGB colour. void drawRect(const Rect& rect, unsigned color); From 22c6a56c9a4cd8a25c28ec4a887f6aa7ac90814f Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sat, 4 Jul 2026 23:20:03 +0200 Subject: [PATCH 14/40] draw() checks isValid --- CIO/CFont.cpp | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/CIO/CFont.cpp b/CIO/CFont.cpp index c39f2d5..cbafd58 100644 --- a/CIO/CFont.cpp +++ b/CIO/CFont.cpp @@ -225,20 +225,9 @@ void CFont::draw(const std::string& string, Position pos, FontSize fontsize, Fon Position curPos = pos; for(unsigned char c : string) { - const unsigned idx = getIndexForChar(c, fontsize, color); - if(idx >= global::bmpArray.size()) - continue; - - auto& tex = getBmpTexture(idx); - if(!tex.isValid()) - { - curPos.x += getCharWidth(c, fontsize, color); - continue; - } - - const auto& bmp = global::bmpArray[idx]; - tex.draw(Rect(curPos.x, curPos.y, bmp.w, bmp.h)); - curPos.x += bmp.w; + auto& tex = getBmpTexture(getIndexForChar(c, fontsize, color)); + tex.draw(Rect(curPos.x, curPos.y, tex.getWidth(), tex.getHeight())); + curPos.x += tex.getWidth(); } } From 1ded52907b891ce437bc828c1ba0c6fd7724f845 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sat, 4 Jul 2026 23:29:14 +0200 Subject: [PATCH 15/40] Texture.drawTiled --- CIO/CSelectBox.cpp | 2 +- CIO/CTextfield.cpp | 2 +- CIO/CWindow.cpp | 10 +++++----- Texture.cpp | 28 ++++++++++++++-------------- Texture.h | 6 +++--- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/CIO/CSelectBox.cpp b/CIO/CSelectBox.cpp index ff6618d..b437bb7 100644 --- a/CIO/CSelectBox.cpp +++ b/CIO/CSelectBox.cpp @@ -223,7 +223,7 @@ void CSelectBox::draw(Position parentOrigin) // Draw background if(pic_background >= 0 && pic_foreground >= 0) { - drawTiledBmp(pic_foreground, area); + getBmpTexture(pic_foreground).drawTiled(area); } else { // Fill with black diff --git a/CIO/CTextfield.cpp b/CIO/CTextfield.cpp index 544a9c9..3496a56 100644 --- a/CIO/CTextfield.cpp +++ b/CIO/CTextfield.cpp @@ -260,7 +260,7 @@ void CTextfield::draw(Position parentOrigin) if(button_style) drawButtonBox(area, active, pic_background, pic_foreground); else - drawTiledBmp(pic_foreground, area); + getBmpTexture(pic_foreground).drawTiled(area); } else { // Fill with black diff --git a/CIO/CWindow.cpp b/CIO/CWindow.cpp index 8001bfa..b246ad6 100644 --- a/CIO/CWindow.cpp +++ b/CIO/CWindow.cpp @@ -263,7 +263,7 @@ void CWindow::draw(Position /*parentOrigin*/) // 1. Background fill (tiled) if(getBackground() != WINDOW_NOTHING) - drawTiledBmp(getBackground(), winRect); + getBmpTexture(getBackground()).drawTiled(winRect); // 2. Content (if not minimized) — clipped to the area inside frames if(!minimized) @@ -295,7 +295,7 @@ void CWindow::draw(Position /*parentOrigin*/) // Draw upper frame tile across the top of the window { const Rect upperFrameRect(origin, Extent(size_.x, getBmpTexture(upperframe).getHeight())); - drawTiledBmp(upperframe, upperFrameRect); + getBmpTexture(upperframe).drawTiled(upperFrameRect); } // 4. Title text @@ -311,13 +311,13 @@ void CWindow::draw(Position /*parentOrigin*/) const int lowerH = getBmpTexture(WINDOW_LOWER_FRAME).getHeight(); const Rect lowerFrameRect(Position(origin.x, origin.y + static_cast(size_.y) - lowerH), Extent(size_.x, lowerH)); - drawTiledBmp(WINDOW_LOWER_FRAME, lowerFrameRect); + getBmpTexture(WINDOW_LOWER_FRAME).drawTiled(lowerFrameRect); } // 6. Left frame (tiled down left side) { const Rect leftFrameRect(origin, Extent(getBmpTexture(WINDOW_LEFT_FRAME).getWidth(), size_.y)); - drawTiledBmp(WINDOW_LEFT_FRAME, leftFrameRect); + getBmpTexture(WINDOW_LEFT_FRAME).drawTiled(leftFrameRect); } // 7. Right frame (tiled down right side) @@ -325,7 +325,7 @@ void CWindow::draw(Position /*parentOrigin*/) const int rightW = getBmpTexture(WINDOW_RIGHT_FRAME).getWidth(); const Rect rightFrameRect(Position(origin.x + static_cast(size_.x) - rightW, origin.y), Extent(rightW, size_.y)); - drawTiledBmp(WINDOW_RIGHT_FRAME, rightFrameRect); + getBmpTexture(WINDOW_RIGHT_FRAME).drawTiled(rightFrameRect); } // 8. Corners diff --git a/Texture.cpp b/Texture.cpp index b8354cd..c2bc128 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -244,27 +244,27 @@ void ensureBmpTex(int idx) getBmpTexture(idx); } -void drawTiledBmp(int bmpIdx, const Rect& destRect) +void Texture::drawTiled(const Rect& destRect) const { - auto& tex = getBmpTexture(bmpIdx); - if(!tex.isValid()) + if(!texture_) return; - const Position tileSize(tex.getSize()); - if(tileSize.x <= 0 || tileSize.y <= 0) + const int tileW = getWidth(); + const int tileH = getHeight(); + if(tileW <= 0 || tileH <= 0) return; glColor4f(1, 1, 1, 1); - glBindTexture(GL_TEXTURE_2D, tex.getHandle()); + glBindTexture(GL_TEXTURE_2D, texture_); glBegin(GL_QUADS); - for(int y = destRect.top; y < destRect.bottom; y += tileSize.y) + for(int y = destRect.top; y < destRect.bottom; y += tileH) { - const int rowH = std::min(tileSize.y, destRect.bottom - y); - const float v1 = float(rowH) / float(tileSize.y); - for(int x = destRect.left; x < destRect.right; x += tileSize.x) + const int rowH = std::min(tileH, destRect.bottom - y); + const float v1 = float(rowH) / float(tileH); + for(int x = destRect.left; x < destRect.right; x += tileW) { - const int colW = std::min(tileSize.x, destRect.right - x); - const float u1 = float(colW) / float(tileSize.x); + const int colW = std::min(tileW, destRect.right - x); + const float u1 = float(colW) / float(tileW); glTexCoord2f(0, 0); glVertex2i(x, y); @@ -281,7 +281,7 @@ void drawTiledBmp(int bmpIdx, const Rect& destRect) void drawButtonBox(const Rect& area, bool pressed, int baseTex, int faceTex) { - drawTiledBmp(baseTex, area); + getBmpTexture(baseTex).drawTiled(area); const int w = area.right - area.left; const int h = area.bottom - area.top; @@ -299,5 +299,5 @@ void drawButtonBox(const Rect& area, bool pressed, int baseTex, int faceTex) // Foreground inset by 2px const Rect fgRect(area.getOrigin() + Position(2, 2), Extent(w - 4, h - 4)); - drawTiledBmp(faceTex, fgRect); + getBmpTexture(faceTex).drawTiled(fgRect); } diff --git a/Texture.h b/Texture.h index 706d3a2..c698a12 100644 --- a/Texture.h +++ b/Texture.h @@ -42,6 +42,9 @@ class Texture /// srcRect is in texture-local coordinates (may be clipped). void draw(const Rect& destRect, const Rect& srcRect) const; + /// Tile the texture to fill the given rectangle. + void drawTiled(const Rect& destRect) const; + /// Returns the raw GL texture name (for use with glBindTexture). unsigned getHandle() const { return texture_; } @@ -82,9 +85,6 @@ void drawLine(Position p1, Position p2, unsigned char r, unsigned char g, unsign /// Ensure the OpenGL texture for a bitmap index is loaded from its SDL surface. void ensureBmpTex(int idx); -/// Draw a bitmap texture tiled to fill the given rectangle. -void drawTiledBmp(int bmpIdx, const Rect& destRect); - /// Draw a 3D-style button box: tiled background, 2px black frame (sunken if pressed, raised otherwise), /// and tiled foreground inset by 2px. void drawButtonBox(const Rect& area, bool pressed, int baseTex, int faceTex); From 33c9ee0631afb90d2ad31a5bcbf871d062524426 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sat, 4 Jul 2026 23:39:35 +0200 Subject: [PATCH 16/40] setText early return --- CIO/CFont.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CIO/CFont.cpp b/CIO/CFont.cpp index cbafd58..25471eb 100644 --- a/CIO/CFont.cpp +++ b/CIO/CFont.cpp @@ -34,6 +34,8 @@ void CFont::setColor(FontColor color) void CFont::setText(std::string text) { + if(text == string_) + return; this->string_ = std::move(text); size_ = Extent(getTextWidth(string_, fontsize_), getLineHeight(fontsize_)); } From e398e7ae3feec0bdf6a665237a739d81f1afd925 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sat, 4 Jul 2026 23:41:21 +0200 Subject: [PATCH 17/40] makePos simpler --- CIO/CWindow.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CIO/CWindow.cpp b/CIO/CWindow.cpp index b246ad6..62712b1 100644 --- a/CIO/CWindow.cpp +++ b/CIO/CWindow.cpp @@ -34,8 +34,7 @@ static Position makePos(WindowPos pos, Extent size) { if(pos == WindowPos::Center) { - const auto res = global::s2->getRes(); - return Position(res.x / 2, res.y / 2) - size / 2; + return (global::s2->getRes() - size) / 2; } else return {}; } From a64dda3938d49450c9fcc58d9bfc325b7354519f Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sat, 4 Jul 2026 23:43:02 +0200 Subject: [PATCH 18/40] num_x/y > scale --- CIO/CMinimapWindow.cpp | 10 +++++----- CMap.cpp | 19 +++++++++---------- CMap.h | 2 +- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/CIO/CMinimapWindow.cpp b/CIO/CMinimapWindow.cpp index f439b9d..4f5c26c 100644 --- a/CIO/CMinimapWindow.cpp +++ b/CIO/CMinimapWindow.cpp @@ -28,8 +28,8 @@ void CMinimapWindow::draw(Position /*parentOrigin*/) return; // Fill pixel buffer with minimap terrain - int num_x = 1, num_y = 1; - map->drawMinimap(pixels_, cw, ch, num_x, num_y); + int scale = 1; + map->drawMinimap(pixels_, cw, ch, scale); // Upload to texture and draw if(!minimapTex_.isValid() || minimapTex_.getWidth() != cw || minimapTex_.getHeight() != ch) @@ -46,7 +46,7 @@ void CMinimapWindow::draw(Position /*parentOrigin*/) continue; const int flagIdx = FLAG_BLUE_DARK + i % 7; - const Position hqPos(hqX / num_x, hqY / num_y); + const Position hqPos(hqX / scale, hqY / scale); getBmpTexture(flagIdx).draw( contentPos + hqPos - Position(static_cast(global::bmpArray[flagIdx].nx), static_cast(global::bmpArray[flagIdx].ny))); @@ -61,8 +61,8 @@ void CMinimapWindow::draw(Position /*parentOrigin*/) const auto& dispRect = map->getDisplayRect(); const Position arrowPos = contentPos - + Position((dispRect.left + static_cast(dispRect.getSize().x) / 2) / triangleWidth / num_x, - (dispRect.top + static_cast(dispRect.getSize().y) / 2) / triangleHeight / num_y) + + Position((dispRect.left + static_cast(dispRect.getSize().x) / 2) / triangleWidth / scale, + (dispRect.top + static_cast(dispRect.getSize().y) / 2) / triangleHeight / scale) - Position(static_cast(global::bmpArray[arrowIdx].nx), static_cast(global::bmpArray[arrowIdx].ny)); getBmpTexture(arrowIdx).draw(arrowPos); } diff --git a/CMap.cpp b/CMap.cpp index c1a07b6..1865da5 100644 --- a/CMap.cpp +++ b/CMap.cpp @@ -1328,34 +1328,33 @@ static void getTriangleColor(const bobMAP& map, Uint8 rawTextureId, Sint16& r, S b = 128; } -void CMap::drawMinimap(std::vector& pixels, int w, int h, int& num_x, int& num_y) +void CMap::drawMinimap(std::vector& pixels, int w, int h, int& scale) { - // Scale factors to keep minimap within a reasonable size - num_x = (map->width > 256 ? map->width / 256 : 1); - num_y = (map->height > 256 ? map->height / 256 : 1); + // Scale factor to keep minimap within a reasonable size + int sx = (map->width > 256 ? map->width / 256 : 1); + int sy = (map->height > 256 ? map->height / 256 : 1); // Keep aspect ratio uniform - num_x = (num_x > num_y ? num_x : num_y); - num_y = num_x; + scale = (sx > sy ? sx : sy); // Ensure pixel buffer is the right size pixels.assign(static_cast(w) * h, 0); for(int y = 0; y < map->height; y++) { - if(y % num_y != 0) + if(y % scale != 0) continue; for(int x = 0; x < map->width; x++) { - if(x % num_x != 0) + if(x % scale != 0) continue; Sint16 r, g, b; getTriangleColor(*map, map->getVertex(x, y).rsuTexture, r, g, b); - const int py = y / num_y; - const int px = x / num_x; + const int py = y / scale; + const int px = x / scale; if(py >= h || px >= w) continue; diff --git a/CMap.h b/CMap.h index ab6341b..311cb49 100644 --- a/CMap.h +++ b/CMap.h @@ -165,7 +165,7 @@ class CMap /// @param pixels BGRA pixel buffer (w * h entries, 0xAARRGGBB layout). /// @param w,h Dimensions of the pixel buffer. /// @param num_x,num_y Output: scaling factors (map coords → pixel coords). - void drawMinimap(std::vector& pixels, int w, int h, int& num_x, int& num_y); + void drawMinimap(std::vector& pixels, int w, int h, int& scale); void render(); // get and set some variables necessary for cursor behavior void setHexagonMode(bool HexagonMode) From 00cc538e0fd71752a0005b2242a8e49061e8210e Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sat, 4 Jul 2026 23:51:49 +0200 Subject: [PATCH 19/40] std::vector --- Texture.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Texture.cpp b/Texture.cpp index c2bc128..b064f9f 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -7,7 +7,6 @@ #include "globals.h" #include #include -#include #include #include @@ -213,7 +212,7 @@ void drawLine(Position p1, Position p2, unsigned char r, unsigned char g, unsign Texture& getBmpTexture(int idx, bool filterLinear) { - static std::vector> cache; + static std::vector cache; static std::vector linearFlags; if(static_cast(idx) >= global::bmpArray.size()) { @@ -225,16 +224,14 @@ Texture& getBmpTexture(int idx, bool filterLinear) cache.resize(static_cast(idx) + 1); linearFlags.resize(static_cast(idx) + 1, false); } - if(!cache[idx] || linearFlags[idx] != filterLinear) + if(!cache[idx].isValid() || linearFlags[idx] != filterLinear) { - if(!cache[idx]) - cache[idx] = std::make_unique(); linearFlags[idx] = filterLinear; auto& bmp = global::bmpArray[idx]; if(bmp.surface) - cache[idx]->load(bmp.surface.get(), filterLinear); + cache[idx].load(bmp.surface.get(), filterLinear); } - return *cache[idx]; + return cache[idx]; } void ensureBmpTex(int idx) From c1c7b98f0a25d6ef2a471458dd0dccdab1bbe612 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sun, 5 Jul 2026 00:42:15 +0200 Subject: [PATCH 20/40] Fix text in load&save --- CIO/CTextfield.cpp | 2 +- Texture.cpp | 1 + callbacks.cpp | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CIO/CTextfield.cpp b/CIO/CTextfield.cpp index 3496a56..d7e3300 100644 --- a/CIO/CTextfield.cpp +++ b/CIO/CTextfield.cpp @@ -280,7 +280,7 @@ void CTextfield::draw(Position parentOrigin) if(!displayText.empty()) { textObj->setText(displayText); - textObj->draw(Position(area.left + 2, area.top + 2)); + textObj->draw(Position(parentOrigin.x + 2, parentOrigin.y + 4)); } rendered = true; diff --git a/Texture.cpp b/Texture.cpp index b064f9f..c39bcfd 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -197,6 +197,7 @@ void drawRect(const Rect& rect, unsigned color) glVertex2i(rect.left, rect.bottom); glEnd(); glEnable(GL_TEXTURE_2D); + glColor4f(1, 1, 1, 1); } void drawLine(Position p1, Position p2, unsigned char r, unsigned char g, unsigned char b, unsigned char a) diff --git a/callbacks.cpp b/callbacks.cpp index d05f979..338891e 100644 --- a/callbacks.cpp +++ b/callbacks.cpp @@ -931,10 +931,10 @@ void callback::EditorSaveMenu(int Param) TXTF_Filename = WNDSave->addTextfield(Position(10, 13), 21, 1); const bfs::path filePath = MapObj->getFilepath().empty() ? "MyMap" : MapObj->getFilepath(); TXTF_Filename->setText(filePath.filename().string()); - WNDSave->addText("Mapname", Position(98, 38), FontSize::Small); + WNDSave->addText("Mapname", Position(100, 38), FontSize::Small); TXTF_Mapname = WNDSave->addTextfield(Position(10, 50), 21, 1); TXTF_Mapname->setText(MapObj->getMapname()); - WNDSave->addText("Author", Position(110, 75), FontSize::Medium); + WNDSave->addText("Author", Position(100, 75), FontSize::Small); TXTF_Author = WNDSave->addTextfield(Position(10, 87), 21, 1); TXTF_Author->setText(MapObj->getAuthor()); WNDSave->addButton(EditorSaveMenu, SAVEMAP, Position(170, 120), Extent(90, 20), BUTTON_GREY, "Save"); From 5feba0d15546c31697fc4d26719e039dd0b19d11 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sun, 5 Jul 2026 00:57:58 +0200 Subject: [PATCH 21/40] Extent textSize --- CIO/CButton.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/CIO/CButton.cpp b/CIO/CButton.cpp index dfe210f..39ec50e 100644 --- a/CIO/CButton.cpp +++ b/CIO/CButton.cpp @@ -144,10 +144,8 @@ void CButton::draw(Position parentOrigin) const } else if(button_text) { // Draw text centered (using native-size texture drawing for each character) - const unsigned textW = CFont::getTextWidth(button_text, FontSize::Medium); - const unsigned textH = static_cast(FontSize::Medium); - const Position textPos = - absPos + Position(static_cast(size_.x / 2 - textW / 2), static_cast((size_.y - textH) / 2)); + const Extent textSize(CFont::getTextWidth(button_text, FontSize::Medium), static_cast(FontSize::Medium)); + const Position textPos = absPos + (Position(size_) - textSize) / 2; CFont::draw(button_text, textPos, FontSize::Medium, button_text_color, FontAlign::Left); } } From 599428d814c35c63dbd976edf973ad36991bf09c Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sun, 5 Jul 2026 15:30:55 +0200 Subject: [PATCH 22/40] Cleanup and dead code --- CIO/CButton.cpp | 1 - CIO/CControlContainer.cpp | 8 ++--- CIO/CControlContainer.h | 12 +++----- CIO/CFont.cpp | 20 ++----------- CIO/CFont.h | 3 -- CIO/CMinimapWindow.cpp | 4 +-- CIO/CSelectBox.cpp | 11 ------- CIO/CSelectBox.h | 2 -- CIO/CTextfield.cpp | 15 ---------- CIO/CTextfield.h | 3 -- CIO/CWindow.cpp | 24 +++++++-------- CIO/CWindow.h | 2 +- CMap.h | 4 --- Texture.cpp | 61 +++++++-------------------------------- Texture.h | 40 ------------------------- 15 files changed, 31 insertions(+), 179 deletions(-) diff --git a/CIO/CButton.cpp b/CIO/CButton.cpp index 39ec50e..9037681 100644 --- a/CIO/CButton.cpp +++ b/CIO/CButton.cpp @@ -8,7 +8,6 @@ #include "../globals.h" #include "CFont.h" #include "CollisionDetection.h" -#include CButton::CButton(void callback(int), int clickedParam, Position pos, Extent size, int color, const char* text, int button_picture) diff --git a/CIO/CControlContainer.cpp b/CIO/CControlContainer.cpp index 26fd05b..4f46370 100644 --- a/CIO/CControlContainer.cpp +++ b/CIO/CControlContainer.cpp @@ -13,8 +13,8 @@ #include "CTextfield.h" #include "helpers/containerUtils.h" -CControlContainer::CControlContainer(int pic_background) : CControlContainer(pic_background, FrameInsets{}) {} -CControlContainer::CControlContainer(int pic_background, FrameInsets border) +CControlContainer::CControlContainer(int pic_background) : CControlContainer(pic_background, BorderSizes{}) {} +CControlContainer::CControlContainer(int pic_background, BorderSizes border) : border(border), pic_background(pic_background) {} @@ -175,10 +175,6 @@ bool CControlContainer::delSelectBox(CSelectBox* SelectBoxToDelete) return eraseElement(selectboxes, SelectBoxToDelete); } -// --------------------------------------------------------------------------- -// Draw & DrawChildren -// --------------------------------------------------------------------------- - void CControlContainer::draw(Position parentOrigin) { drawChildren(parentOrigin); diff --git a/CIO/CControlContainer.h b/CIO/CControlContainer.h index 6367a05..948fd41 100644 --- a/CIO/CControlContainer.h +++ b/CIO/CControlContainer.h @@ -15,8 +15,7 @@ class CPicture; class CTextfield; class CSelectBox; -/// Pixel thickness of a window's frame border on each edge. -struct FrameInsets +struct BorderSizes { int left = 0; int top = 0; @@ -37,7 +36,7 @@ class CControlContainer }; // if waste is true, the menu will be delete within the game loop - FrameInsets border; + BorderSizes border; bool waste = false; int pic_background; std::vector> buttons; @@ -51,10 +50,7 @@ class CControlContainer bool eraseElement(T& collection, const U* element); protected: - /// Draw the container's background and child elements using OpenGL. - /// @param parentOrigin Absolute position of the parent container. virtual void draw(Position parentOrigin); - /// Draw children at the given origin (calls each child's Draw). void drawChildren(Position origin); auto& getTextFields() { return textfields; } @@ -63,10 +59,10 @@ class CControlContainer public: CControlContainer(int pic_background); - CControlContainer(int pic_background, FrameInsets border); + CControlContainer(int pic_background, BorderSizes border); virtual ~CControlContainer() noexcept; // Access - const FrameInsets& getBorder() const { return border; } + const BorderSizes& getBorderSizes() const { return border; } Extent getBorderSize() const { return {static_cast(border.left + border.right), static_cast(border.top + border.bottom)}; diff --git a/CIO/CFont.cpp b/CIO/CFont.cpp index 25471eb..3fac602 100644 --- a/CIO/CFont.cpp +++ b/CIO/CFont.cpp @@ -64,10 +64,6 @@ void CFont::setMouseData(SDL_MouseButtonEvent button) } } -// --------------------------------------------------------------------------- -// Character-index helpers (shared by SDL and GL paths) -// --------------------------------------------------------------------------- - namespace { unsigned getIndexForChar(uint8_t c) { @@ -194,10 +190,6 @@ unsigned getCharWidth(uint8_t c, FontSize fontsize, FontColor color) } } // namespace -// --------------------------------------------------------------------------- -// OpenGL Draw methods -// --------------------------------------------------------------------------- - void CFont::draw(Position parentOrigin) const { if(string_.empty()) @@ -228,15 +220,11 @@ void CFont::draw(const std::string& string, Position pos, FontSize fontsize, Fon for(unsigned char c : string) { auto& tex = getBmpTexture(getIndexForChar(c, fontsize, color)); - tex.draw(Rect(curPos.x, curPos.y, tex.getWidth(), tex.getHeight())); - curPos.x += tex.getWidth(); + tex.draw(Rect(curPos, tex.getSize())); + curPos.x += tex.getSize().x; } } -// --------------------------------------------------------------------------- -// SDL surface writeText (for terrain / minimap rendering) -// --------------------------------------------------------------------------- - bool CFont::writeText(SDL_Surface* Surf_Dest, const std::string& string, unsigned x, unsigned y, FontSize fontsize, FontColor color, FontAlign align) { @@ -309,10 +297,6 @@ bool CFont::writeText(SDL_Surface* Surf_Dest, const std::string& string, unsigne return true; } -// --------------------------------------------------------------------------- -// getTextWidth -// --------------------------------------------------------------------------- - unsigned CFont::getTextWidth(const std::string& string, FontSize fontsize) { unsigned w = 0; diff --git a/CIO/CFont.h b/CIO/CFont.h index 230fc59..3a467e3 100644 --- a/CIO/CFont.h +++ b/CIO/CFont.h @@ -47,11 +47,8 @@ class CFont } void setMouseData(SDL_MouseButtonEvent button); - /// Draw this font's text at the given absolute position using OpenGL. void draw(Position parentOrigin) const; - /// Static helpers for drawing text with OpenGL directly. - /// @param pos Absolute position (top-left of the text, adjusted for alignment). static void draw(const std::string& string, Position pos, FontSize fontsize = FontSize::Small, FontColor color = FontColor::Yellow, FontAlign align = FontAlign::Left); diff --git a/CIO/CMinimapWindow.cpp b/CIO/CMinimapWindow.cpp index 4f5c26c..bf96725 100644 --- a/CIO/CMinimapWindow.cpp +++ b/CIO/CMinimapWindow.cpp @@ -15,7 +15,7 @@ void CMinimapWindow::draw(Position /*parentOrigin*/) CWindow::draw(pos_); // Compute content area (inside the frames) - const auto& b = getBorder(); + const auto& b = getBorderSizes(); const Position contentPos(pos_.x + b.left, pos_.y + b.top); const int cw = static_cast(size_.x) - b.left - b.right; const int ch = static_cast(size_.y) - b.top - b.bottom; @@ -32,7 +32,7 @@ void CMinimapWindow::draw(Position /*parentOrigin*/) map->drawMinimap(pixels_, cw, ch, scale); // Upload to texture and draw - if(!minimapTex_.isValid() || minimapTex_.getWidth() != cw || minimapTex_.getHeight() != ch) + if(!minimapTex_.isValid() || minimapTex_.getSize() != contentSize) minimapTex_.createEmpty(contentSize); minimapTex_.upload(pixels_.data()); minimapTex_.draw(Rect(contentPos, contentSize)); diff --git a/CIO/CSelectBox.cpp b/CIO/CSelectBox.cpp index b437bb7..735ad09 100644 --- a/CIO/CSelectBox.cpp +++ b/CIO/CSelectBox.cpp @@ -35,16 +35,6 @@ void CSelectBox::addOption(const std::string& string, std::function c last_text_pos_y += row_height; } -bool CSelectBox::hasRendered() -{ - if(rendered) - { - rendered = false; - return true; - } else - return false; -} - void CSelectBox::setColor(int color) { switch(color) @@ -248,5 +238,4 @@ void CSelectBox::draw(Position parentOrigin) ScrollUpButton->draw(absPos); ScrollDownButton->draw(absPos); - rendered = true; } diff --git a/CIO/CSelectBox.h b/CIO/CSelectBox.h index 4257cc1..7917860 100644 --- a/CIO/CSelectBox.h +++ b/CIO/CSelectBox.h @@ -28,14 +28,12 @@ class CSelectBox std::unique_ptr ScrollUpButton; std::unique_ptr ScrollDownButton; Uint16 last_text_pos_y = 10; - bool rendered = false; public: CSelectBox(Position pos, Extent size, FontSize fontsize = FontSize::Large, FontColor text_color = FontColor::Yellow, int bg_color = -1); const Position& getPos() const { return pos_; } const Extent& getSize() const { return size_; } - bool hasRendered(); void setMouseData(SDL_MouseButtonEvent button); void setMouseData(SDL_MouseMotionEvent motion); void draw(Position parentOrigin); diff --git a/CIO/CTextfield.cpp b/CIO/CTextfield.cpp index d7e3300..1ad793f 100644 --- a/CIO/CTextfield.cpp +++ b/CIO/CTextfield.cpp @@ -26,7 +26,6 @@ CTextfield::CTextfield(Position pos, Uint16 cols, Uint16 rows, FontSize fontsize // allocate memory for the text: chiffres (cols) + '\n' for each line * rows + blinking chiffre + '\0' text_.resize((this->cols + 1) * this->rows + 2); - rendered = false; this->button_style = button_style; textObj = std::make_unique("", pos, fontsize, text_color); } @@ -41,16 +40,6 @@ void CTextfield::setPos(Position pos) textObj->setPos(pos); } -bool CTextfield::hasRendered() -{ - if(rendered) - { - rendered = false; - return true; - } else - return false; -} - void CTextfield::setColor(int color) { switch(color) @@ -251,9 +240,6 @@ void CTextfield::draw(Position parentOrigin) blinking_chiffre = false; } - // Ensure rendered flag is cleared each frame - rendered = false; - // Draw the background / foreground if(pic_background >= 0 && pic_foreground >= 0) { @@ -283,5 +269,4 @@ void CTextfield::draw(Position parentOrigin) textObj->draw(Position(parentOrigin.x + 2, parentOrigin.y + 4)); } - rendered = true; } diff --git a/CIO/CTextfield.h b/CIO/CTextfield.h index e0234fa..d0f72b3 100644 --- a/CIO/CTextfield.h +++ b/CIO/CTextfield.h @@ -26,8 +26,6 @@ class CTextfield std::vector text_; // if active, keyboard data will be delivered and the cursor is blinking bool active; - // we need this to say the window if it needs to render, otherwise no blinking cursor and no chiffres are shown - bool rendered; // if true, the textfield looks like a button bool button_style; // Cursor blink state @@ -47,7 +45,6 @@ class CTextfield void setActive() { active = true; } void setInactive() { active = false; } bool isActive() const { return active; } - bool hasRendered(); void setMouseData(SDL_MouseButtonEvent button); void setKeyboardData(const SDL_KeyboardEvent& key); void draw(Position parentOrigin); diff --git a/CIO/CWindow.cpp b/CIO/CWindow.cpp index 62712b1..f628ebb 100644 --- a/CIO/CWindow.cpp +++ b/CIO/CWindow.cpp @@ -251,10 +251,6 @@ void CWindow::setMouseData(SDL_MouseButtonEvent button) callback_(WINDOW_CLICKED_CALL); } -// --------------------------------------------------------------------------- -// Draw — OpenGL version of the old render() -// --------------------------------------------------------------------------- - void CWindow::draw(Position /*parentOrigin*/) { const Position origin = pos_; @@ -268,7 +264,7 @@ void CWindow::draw(Position /*parentOrigin*/) if(!minimized) { const auto viewH = global::s2->getRes().y; - const auto& b = getBorder(); + const auto& b = getBorderSizes(); const auto contentX = origin.x + b.left; const auto contentY = origin.y + b.top; const auto contentW = static_cast(size_.x) - b.left - b.right; @@ -293,21 +289,21 @@ void CWindow::draw(Position /*parentOrigin*/) // Draw upper frame tile across the top of the window { - const Rect upperFrameRect(origin, Extent(size_.x, getBmpTexture(upperframe).getHeight())); + const Rect upperFrameRect(origin, Extent(size_.x, getBmpTexture(upperframe).getSize().y)); getBmpTexture(upperframe).drawTiled(upperFrameRect); } // 4. Title text if(title) { - const int titleY = origin.y + (getBmpTexture(WINDOW_UPPER_FRAME).getHeight() - 9) / 2; + const int titleY = origin.y + (getBmpTexture(WINDOW_UPPER_FRAME).getSize().y - 9) / 2; CFont::draw(title, Position(origin.x + static_cast(size_.x) / 2, titleY), FontSize::Small, FontColor::Yellow, FontAlign::Middle); } // 5. Lower frame (tiled across bottom) { - const int lowerH = getBmpTexture(WINDOW_LOWER_FRAME).getHeight(); + const int lowerH = getBmpTexture(WINDOW_LOWER_FRAME).getSize().y; const Rect lowerFrameRect(Position(origin.x, origin.y + static_cast(size_.y) - lowerH), Extent(size_.x, lowerH)); getBmpTexture(WINDOW_LOWER_FRAME).drawTiled(lowerFrameRect); @@ -315,13 +311,13 @@ void CWindow::draw(Position /*parentOrigin*/) // 6. Left frame (tiled down left side) { - const Rect leftFrameRect(origin, Extent(getBmpTexture(WINDOW_LEFT_FRAME).getWidth(), size_.y)); + const Rect leftFrameRect(origin, Extent(getBmpTexture(WINDOW_LEFT_FRAME).getSize().x, size_.y)); getBmpTexture(WINDOW_LEFT_FRAME).drawTiled(leftFrameRect); } // 7. Right frame (tiled down right side) { - const int rightW = getBmpTexture(WINDOW_RIGHT_FRAME).getWidth(); + const int rightW = getBmpTexture(WINDOW_RIGHT_FRAME).getSize().x; const Rect rightFrameRect(Position(origin.x + static_cast(size_.x) - rightW, origin.y), Extent(rightW, size_.y)); getBmpTexture(WINDOW_RIGHT_FRAME).drawTiled(rightFrameRect); @@ -331,11 +327,11 @@ void CWindow::draw(Position /*parentOrigin*/) { getBmpTexture(WINDOW_LEFT_UPPER_CORNER).draw(origin); - const int ruW = getBmpTexture(WINDOW_RIGHT_UPPER_CORNER).getWidth(); + const int ruW = getBmpTexture(WINDOW_RIGHT_UPPER_CORNER).getSize().x; getBmpTexture(WINDOW_RIGHT_UPPER_CORNER).draw(Position(origin.x + static_cast(size_.x) - ruW, origin.y)); - const int crW = getBmpTexture(WINDOW_CORNER_RECTANGLE).getWidth(); - const int crH = getBmpTexture(WINDOW_CORNER_RECTANGLE).getHeight(); + const int crW = getBmpTexture(WINDOW_CORNER_RECTANGLE).getSize().x; + const int crH = getBmpTexture(WINDOW_CORNER_RECTANGLE).getSize().y; getBmpTexture(WINDOW_CORNER_RECTANGLE).draw(Position(origin.x, origin.y + static_cast(size_.y) - crH)); getBmpTexture(WINDOW_CORNER_RECTANGLE) .draw(Position(origin.x + static_cast(size_.x) - crW, origin.y + static_cast(size_.y) - crH)); @@ -365,7 +361,7 @@ void CWindow::draw(Position /*parentOrigin*/) else minimizebutton = WINDOW_BUTTON_MINIMIZE; getBmpTexture(minimizebutton) - .draw(Position(origin.x + static_cast(size_.x) - getBmpTexture(minimizebutton).getWidth(), origin.y)); + .draw(Position(origin.x + static_cast(size_.x) - getBmpTexture(minimizebutton).getSize().x, origin.y)); } // 11. Resize button diff --git a/CIO/CWindow.h b/CIO/CWindow.h index a0e7c77..54f636b 100644 --- a/CIO/CWindow.h +++ b/CIO/CWindow.h @@ -45,7 +45,7 @@ class CWindow : public CControlContainer int callbackQuitMessage; public: - /// Draw the window using OpenGL (frame and children). + /// Draw the window (frame and children). void draw(Position parentOrigin) override; CWindow(void callback(int), int callbackQuitMessage, Position pos, Extent size, const char* title = nullptr, diff --git a/CMap.h b/CMap.h index 311cb49..fbb3352 100644 --- a/CMap.h +++ b/CMap.h @@ -161,10 +161,6 @@ class CMap std::string getAuthor() const { return map->getAuthor(); } void setAuthor(const std::string& author) { map->setAuthor(author); } - /// Fill a pixel buffer with the minimap terrain view. - /// @param pixels BGRA pixel buffer (w * h entries, 0xAARRGGBB layout). - /// @param w,h Dimensions of the pixel buffer. - /// @param num_x,num_y Output: scaling factors (map coords → pixel coords). void drawMinimap(std::vector& pixels, int w, int h, int& scale); void render(); // get and set some variables necessary for cursor behavior diff --git a/Texture.cpp b/Texture.cpp index c39bcfd..ad4f197 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -101,12 +101,12 @@ bool Texture::load(SDL_Surface* surface, bool filterLinear) return true; } - // 32-bit surface: convert to destination format (BGRA), preserving colorkey transparency + // 32-bit surface: convert to destination format (BGRA), force full opacity SDL_Surface* converted = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ARGB8888, 0); if(!converted) return false; - // Force alpha to opaque (some source images may have wrong alpha=0) + // Force alpha to opaque (LBM palette entries often have alpha=0) SDL_LockSurface(converted); for(int y = 0; y < converted->h; y++) { @@ -157,35 +157,6 @@ void Texture::draw(Position pos) const glEnd(); } -void Texture::draw(const Rect& destRect, const Rect& srcRect) const -{ - if(!texture_) - return; - - // Clamp source rect to texture bounds - const Position clampedOrigin(std::max(0, srcRect.left), std::max(0, srcRect.top)); - const Position clampedEnd(std::min(static_cast(size_.x), srcRect.right), - std::min(static_cast(size_.y), srcRect.bottom)); - if(clampedOrigin.x >= clampedEnd.x || clampedOrigin.y >= clampedEnd.y) - return; - - const auto texSize = Position(getSize()); - const Point uv0 = Point(clampedOrigin) / Point(texSize); - const Point uv1 = Point(clampedEnd) / Point(texSize); - - glBindTexture(GL_TEXTURE_2D, texture_); - glBegin(GL_QUADS); - glTexCoord2f(uv0.x, uv0.y); - glVertex2i(destRect.left, destRect.top); - glTexCoord2f(uv1.x, uv0.y); - glVertex2i(destRect.right, destRect.top); - glTexCoord2f(uv1.x, uv1.y); - glVertex2i(destRect.right, destRect.bottom); - glTexCoord2f(uv0.x, uv1.y); - glVertex2i(destRect.left, destRect.bottom); - glEnd(); -} - void drawRect(const Rect& rect, unsigned color) { glDisable(GL_TEXTURE_2D); @@ -200,17 +171,6 @@ void drawRect(const Rect& rect, unsigned color) glColor4f(1, 1, 1, 1); } -void drawLine(Position p1, Position p2, unsigned char r, unsigned char g, unsigned char b, unsigned char a) -{ - glDisable(GL_TEXTURE_2D); - glColor4ub(r, g, b, a); - glBegin(GL_LINES); - glVertex2i(p1.x, p1.y); - glVertex2i(p2.x, p2.y); - glEnd(); - glEnable(GL_TEXTURE_2D); -} - Texture& getBmpTexture(int idx, bool filterLinear) { static std::vector cache; @@ -247,22 +207,21 @@ void Texture::drawTiled(const Rect& destRect) const if(!texture_) return; - const int tileW = getWidth(); - const int tileH = getHeight(); - if(tileW <= 0 || tileH <= 0) + const Extent tileSize = getSize(); + if(static_cast(tileSize.x) <= 0 || static_cast(tileSize.y) <= 0) return; glColor4f(1, 1, 1, 1); glBindTexture(GL_TEXTURE_2D, texture_); glBegin(GL_QUADS); - for(int y = destRect.top; y < destRect.bottom; y += tileH) + for(int y = destRect.top; y < destRect.bottom; y += static_cast(tileSize.y)) { - const int rowH = std::min(tileH, destRect.bottom - y); - const float v1 = float(rowH) / float(tileH); - for(int x = destRect.left; x < destRect.right; x += tileW) + const int rowH = std::min(static_cast(tileSize.y), destRect.bottom - y); + const float v1 = float(rowH) / float(tileSize.y); + for(int x = destRect.left; x < destRect.right; x += static_cast(tileSize.x)) { - const int colW = std::min(tileW, destRect.right - x); - const float u1 = float(colW) / float(tileW); + const int colW = std::min(static_cast(tileSize.x), destRect.right - x); + const float u1 = float(colW) / float(tileSize.x); glTexCoord2f(0, 0); glVertex2i(x, y); diff --git a/Texture.h b/Texture.h index c698a12..b634aae 100644 --- a/Texture.h +++ b/Texture.h @@ -8,7 +8,6 @@ #include #include -/// Wraps a texture with RAII and provides draw methods. class Texture { public: @@ -22,74 +21,35 @@ class Texture Texture(const Texture&) = delete; Texture& operator=(const Texture&) = delete; - /// Load from a 32-bit or 8-bit paletted SDL surface. - /// For 8-bit surfaces, optional colorkey is respected (keyed pixels become transparent). bool load(SDL_Surface* surface, bool filterLinear = false); - /// Create an empty texture of the given size (for use as a render-target). void createEmpty(Extent size, bool filterLinear = false); - /// Upload new pixel data to an existing texture (glTexSubImage2D). void upload(const void* bgraPixels); - /// Draw the texture stretched to fill the given rect. void draw(const Rect& destRect) const; - /// Draw the texture at native size at the given position. void draw(Position pos) const; - /// Draw a sub-rectangle of the texture to fill the given destination rect. - /// srcRect is in texture-local coordinates (may be clipped). - void draw(const Rect& destRect, const Rect& srcRect) const; - - /// Tile the texture to fill the given rectangle. void drawTiled(const Rect& destRect) const; - /// Returns the raw GL texture name (for use with glBindTexture). unsigned getHandle() const { return texture_; } - /// Size in pixels. Extent getSize() const { return size_; } - /// Width in pixels. - int getWidth() const { return size_.x; } - - /// Height in pixels. - int getHeight() const { return size_.y; } - - /// Returns true if the texture has been created. bool isValid() const { return texture_ != 0; } private: unsigned int texture_ = 0; Extent size_; - /// Internal: create or recreate texture from raw BGRA pixel data. void load(const void* bgraPixels, Extent size, bool filterLinear); }; -// --------------------------------------------------------------------------- -// Free functions for simple GL drawing (rect, line) used by UI components. -// --------------------------------------------------------------------------- - -/// Draw a filled rectangle with a 32-bit ARGB colour. void drawRect(const Rect& rect, unsigned color); -/// Draw a 1-pixel-wide line. -void drawLine(Position p1, Position p2, unsigned char r, unsigned char g, unsigned char b, unsigned char a = 255); - -// --------------------------------------------------------------------------- -// Texture-drawing helpers for UI components -// --------------------------------------------------------------------------- - -/// Ensure the OpenGL texture for a bitmap index is loaded from its SDL surface. void ensureBmpTex(int idx); -/// Draw a 3D-style button box: tiled background, 2px black frame (sunken if pressed, raised otherwise), -/// and tiled foreground inset by 2px. void drawButtonBox(const Rect& area, bool pressed, int baseTex, int faceTex); -/// Get or create the cached OpenGL texture for a bitmap index. -/// The texture is loaded from the SDL surface on first access. -/// @param filterLinear Whether to use linear filtering (for scaled backgrounds). Texture& getBmpTexture(int idx, bool filterLinear = false); From 8b749da8ce8dff1fac50592281600b5a36b7c8d5 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sun, 5 Jul 2026 15:33:32 +0200 Subject: [PATCH 23/40] drawButtonBox --- Texture.cpp | 81 ++++++++++++++++++++++++++--------------------------- 1 file changed, 40 insertions(+), 41 deletions(-) diff --git a/Texture.cpp b/Texture.cpp index ad4f197..de60ee8 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -157,6 +157,40 @@ void Texture::draw(Position pos) const glEnd(); } +void Texture::drawTiled(const Rect& destRect) const +{ + if(!texture_) + return; + + const Extent tileSize = getSize(); + if(static_cast(tileSize.x) <= 0 || static_cast(tileSize.y) <= 0) + return; + + glColor4f(1, 1, 1, 1); + glBindTexture(GL_TEXTURE_2D, texture_); + glBegin(GL_QUADS); + for(int y = destRect.top; y < destRect.bottom; y += static_cast(tileSize.y)) + { + const int rowH = std::min(static_cast(tileSize.y), destRect.bottom - y); + const float v1 = float(rowH) / float(tileSize.y); + for(int x = destRect.left; x < destRect.right; x += static_cast(tileSize.x)) + { + const int colW = std::min(static_cast(tileSize.x), destRect.right - x); + const float u1 = float(colW) / float(tileSize.x); + + glTexCoord2f(0, 0); + glVertex2i(x, y); + glTexCoord2f(u1, 0); + glVertex2i(x + colW, y); + glTexCoord2f(u1, v1); + glVertex2i(x + colW, y + rowH); + glTexCoord2f(0, v1); + glVertex2i(x, y + rowH); + } + } + glEnd(); +} + void drawRect(const Rect& rect, unsigned color) { glDisable(GL_TEXTURE_2D); @@ -202,59 +236,24 @@ void ensureBmpTex(int idx) getBmpTexture(idx); } -void Texture::drawTiled(const Rect& destRect) const -{ - if(!texture_) - return; - - const Extent tileSize = getSize(); - if(static_cast(tileSize.x) <= 0 || static_cast(tileSize.y) <= 0) - return; - - glColor4f(1, 1, 1, 1); - glBindTexture(GL_TEXTURE_2D, texture_); - glBegin(GL_QUADS); - for(int y = destRect.top; y < destRect.bottom; y += static_cast(tileSize.y)) - { - const int rowH = std::min(static_cast(tileSize.y), destRect.bottom - y); - const float v1 = float(rowH) / float(tileSize.y); - for(int x = destRect.left; x < destRect.right; x += static_cast(tileSize.x)) - { - const int colW = std::min(static_cast(tileSize.x), destRect.right - x); - const float u1 = float(colW) / float(tileSize.x); - - glTexCoord2f(0, 0); - glVertex2i(x, y); - glTexCoord2f(u1, 0); - glVertex2i(x + colW, y); - glTexCoord2f(u1, v1); - glVertex2i(x + colW, y + rowH); - glTexCoord2f(0, v1); - glVertex2i(x, y + rowH); - } - } - glEnd(); -} - void drawButtonBox(const Rect& area, bool pressed, int baseTex, int faceTex) { getBmpTexture(baseTex).drawTiled(area); - const int w = area.right - area.left; - const int h = area.bottom - area.top; + const auto sz = area.getSize(); // 2px black frame: left+top if pressed, right+bottom otherwise if(pressed) { - drawRect(Rect(area.left, area.top, 2, h), 0xFF000000); - drawRect(Rect(area.left, area.top, w, 2), 0xFF000000); + drawRect(Rect(area.getOrigin(), 2, sz.y), 0xFF000000); + drawRect(Rect(area.getOrigin(), sz.x, 2), 0xFF000000); } else { - drawRect(Rect(area.right - 2, area.top, 2, h), 0xFF000000); - drawRect(Rect(area.left, area.bottom - 2, w, 2), 0xFF000000); + drawRect(Rect(area.right - 2, area.top, 2, sz.y), 0xFF000000); + drawRect(Rect(area.left, area.bottom - 2, sz.x, 2), 0xFF000000); } // Foreground inset by 2px - const Rect fgRect(area.getOrigin() + Position(2, 2), Extent(w - 4, h - 4)); + const Rect fgRect(area.getOrigin() + Position(2, 2), sz - Extent(4, 4)); getBmpTexture(faceTex).drawTiled(fgRect); } From 9f1f347825542c92d4ce7fceb2716f04229019b6 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sun, 5 Jul 2026 15:37:21 +0200 Subject: [PATCH 24/40] Position/Extent --- CGame_Render.cpp | 2 -- CIO/CControlContainer.cpp | 5 ----- CIO/CControlContainer.h | 2 +- CIO/CFont.h | 4 ++-- CIO/CMenu.cpp | 13 ++----------- CIO/CMinimapWindow.cpp | 16 +++++++--------- CIO/CWindow.cpp | 13 ++++++------- 7 files changed, 18 insertions(+), 37 deletions(-) diff --git a/CGame_Render.cpp b/CGame_Render.cpp index 657dca4..3fb5b4b 100644 --- a/CGame_Render.cpp +++ b/CGame_Render.cpp @@ -117,10 +117,8 @@ void CGame::Render() framesPassedSinceLastFps = 0; lastFpsTick = curTicks; } - // Draw FPS counter lastFps.draw(Position(0, 0)); - // Cursor on top of everything const auto& cursorImg = Cursor.clicked ? (Cursor.button.right ? cross_ : cursorClicked_) : cursor_; cursorImg.draw(Cursor.pos); diff --git a/CIO/CControlContainer.cpp b/CIO/CControlContainer.cpp index 4f46370..a2a563d 100644 --- a/CIO/CControlContainer.cpp +++ b/CIO/CControlContainer.cpp @@ -175,11 +175,6 @@ bool CControlContainer::delSelectBox(CSelectBox* SelectBoxToDelete) return eraseElement(selectboxes, SelectBoxToDelete); } -void CControlContainer::draw(Position parentOrigin) -{ - drawChildren(parentOrigin); -} - void CControlContainer::drawChildren(Position origin) { for(const auto& picture : pictures) diff --git a/CIO/CControlContainer.h b/CIO/CControlContainer.h index 948fd41..59d73da 100644 --- a/CIO/CControlContainer.h +++ b/CIO/CControlContainer.h @@ -50,7 +50,7 @@ class CControlContainer bool eraseElement(T& collection, const U* element); protected: - virtual void draw(Position parentOrigin); + virtual void draw(Position parentOrigin) = 0; void drawChildren(Position origin); auto& getTextFields() { return textfields; } diff --git a/CIO/CFont.h b/CIO/CFont.h index 3a467e3..b44602f 100644 --- a/CIO/CFont.h +++ b/CIO/CFont.h @@ -28,8 +28,8 @@ class CFont CFont(std::string text, Position pos = {0, 0}, FontSize fontsize = FontSize::Small, FontColor color = FontColor::Yellow); // Access - const Position& getPos() const { return pos_; } - const Extent& getSize() const { return size_; } + Position getPos() const { return pos_; } + Extent getSize() const { return size_; } void setPos(Position pos); void setFontsize(FontSize fontsize); void setColor(FontColor color); diff --git a/CIO/CMenu.cpp b/CIO/CMenu.cpp index 96f53f4..fe1d3fb 100644 --- a/CIO/CMenu.cpp +++ b/CIO/CMenu.cpp @@ -13,17 +13,8 @@ CMenu::CMenu(int pic_background) : CControlContainer(pic_background) {} void CMenu::draw(Position /*parentOrigin*/) { // Draw full-screen background texture - const int picIdx = getBackground(); - if(picIdx >= 0 && picIdx < static_cast(global::bmpArray.size())) - { - auto& tex = getBmpTexture(picIdx, true); - if(tex.isValid()) - { - const auto res = global::s2->getRes(); - tex.draw(Rect(0, 0, res.x, res.y)); - } - } + const auto res = global::s2->getRes(); + getBmpTexture(getBackground(), true).draw(Rect(0, 0, res.x, res.y)); - // Draw children drawChildren(Position(0, 0)); } diff --git a/CIO/CMinimapWindow.cpp b/CIO/CMinimapWindow.cpp index bf96725..58a2db5 100644 --- a/CIO/CMinimapWindow.cpp +++ b/CIO/CMinimapWindow.cpp @@ -16,7 +16,7 @@ void CMinimapWindow::draw(Position /*parentOrigin*/) // Compute content area (inside the frames) const auto& b = getBorderSizes(); - const Position contentPos(pos_.x + b.left, pos_.y + b.top); + const Position contentPos = pos_ + Position(b.left, b.top); const int cw = static_cast(size_.x) - b.left - b.right; const int ch = static_cast(size_.y) - b.top - b.bottom; if(cw <= 0 || ch <= 0) @@ -46,10 +46,10 @@ void CMinimapWindow::draw(Position /*parentOrigin*/) continue; const int flagIdx = FLAG_BLUE_DARK + i % 7; - const Position hqPos(hqX / scale, hqY / scale); - getBmpTexture(flagIdx).draw( - contentPos + hqPos - - Position(static_cast(global::bmpArray[flagIdx].nx), static_cast(global::bmpArray[flagIdx].ny))); + const Position hqPos = Position(hqX, hqY) / scale; + const Position flagOffset(static_cast(global::bmpArray[flagIdx].nx), + static_cast(global::bmpArray[flagIdx].ny)); + getBmpTexture(flagIdx).draw(contentPos + hqPos - flagOffset); // Player number CFont::draw(std::to_string(i + 1), contentPos + hqPos, FontSize::Small, FontColor::MintGreen); @@ -59,10 +59,8 @@ void CMinimapWindow::draw(Position /*parentOrigin*/) { const int arrowIdx = MAPPIC_ARROWCROSS_ORANGE; const auto& dispRect = map->getDisplayRect(); - const Position arrowPos = - contentPos - + Position((dispRect.left + static_cast(dispRect.getSize().x) / 2) / triangleWidth / scale, - (dispRect.top + static_cast(dispRect.getSize().y) / 2) / triangleHeight / scale) + const Position arrowCenter = dispRect.getOrigin() + Position(dispRect.getSize().x / 2, dispRect.getSize().y / 2); + const Position arrowPos = contentPos + arrowCenter / Position(triangleWidth, triangleHeight) / scale - Position(static_cast(global::bmpArray[arrowIdx].nx), static_cast(global::bmpArray[arrowIdx].ny)); getBmpTexture(arrowIdx).draw(arrowPos); } diff --git a/CIO/CWindow.cpp b/CIO/CWindow.cpp index f628ebb..35f54e6 100644 --- a/CIO/CWindow.cpp +++ b/CIO/CWindow.cpp @@ -265,14 +265,13 @@ void CWindow::draw(Position /*parentOrigin*/) { const auto viewH = global::s2->getRes().y; const auto& b = getBorderSizes(); - const auto contentX = origin.x + b.left; - const auto contentY = origin.y + b.top; + const auto contentOrigin = origin + Position(b.left, b.top); const auto contentW = static_cast(size_.x) - b.left - b.right; const auto contentH = static_cast(size_.y) - b.top - b.bottom; if(contentW > 0 && contentH > 0) { glEnable(GL_SCISSOR_TEST); - glScissor(contentX, viewH - (contentY + contentH), contentW, contentH); + glScissor(contentOrigin.x, viewH - (contentOrigin.y + contentH), contentW, contentH); drawChildren(origin); glDisable(GL_SCISSOR_TEST); } @@ -328,13 +327,13 @@ void CWindow::draw(Position /*parentOrigin*/) getBmpTexture(WINDOW_LEFT_UPPER_CORNER).draw(origin); const int ruW = getBmpTexture(WINDOW_RIGHT_UPPER_CORNER).getSize().x; - getBmpTexture(WINDOW_RIGHT_UPPER_CORNER).draw(Position(origin.x + static_cast(size_.x) - ruW, origin.y)); + getBmpTexture(WINDOW_RIGHT_UPPER_CORNER).draw(origin + Position(static_cast(size_.x) - ruW, 0)); const int crW = getBmpTexture(WINDOW_CORNER_RECTANGLE).getSize().x; const int crH = getBmpTexture(WINDOW_CORNER_RECTANGLE).getSize().y; - getBmpTexture(WINDOW_CORNER_RECTANGLE).draw(Position(origin.x, origin.y + static_cast(size_.y) - crH)); + getBmpTexture(WINDOW_CORNER_RECTANGLE).draw(origin + Position(0, static_cast(size_.y) - crH)); getBmpTexture(WINDOW_CORNER_RECTANGLE) - .draw(Position(origin.x + static_cast(size_.x) - crW, origin.y + static_cast(size_.y) - crH)); + .draw(origin + Position(static_cast(size_.x) - crW, static_cast(size_.y) - crH)); } // 9. Close button @@ -361,7 +360,7 @@ void CWindow::draw(Position /*parentOrigin*/) else minimizebutton = WINDOW_BUTTON_MINIMIZE; getBmpTexture(minimizebutton) - .draw(Position(origin.x + static_cast(size_.x) - getBmpTexture(minimizebutton).getSize().x, origin.y)); + .draw(origin + Position(static_cast(size_.x) - getBmpTexture(minimizebutton).getSize().x, 0)); } // 11. Resize button From 506e0a39b0d802a013e0f7962ec0a01736d202d1 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sun, 5 Jul 2026 15:50:26 +0200 Subject: [PATCH 25/40] clamp --- CIO/CWindow.cpp | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/CIO/CWindow.cpp b/CIO/CWindow.cpp index 35f54e6..53a09d1 100644 --- a/CIO/CWindow.cpp +++ b/CIO/CWindow.cpp @@ -80,18 +80,12 @@ void CWindow::setMouseData(SDL_MouseMotionEvent motion) { pos_.x += motion.xrel; pos_.y += motion.yrel; - // make sure to not move the window outside the display surface - if(pos_.x < 0) - pos_.x = 0; - { - const auto res = global::s2->getRes(); - const int resX = static_cast(res.x); - const int resY = static_cast(res.y); - if(pos_.x + static_cast(size_.x) >= resX) //-V807 - pos_.x = resX - static_cast(size_.x) - 1; - if(pos_.y + static_cast(size_.y) >= resY) - pos_.y = resY - static_cast(size_.y) - 1; - } + // Clamp window position to screen bounds + const auto res = global::s2->getRes(); + const int maxX = static_cast(res.x - size_.x) - 1; + const int maxY = static_cast(res.y - size_.y) - 1; + pos_.x = std::clamp(pos_.x, 0, maxX); + pos_.y = std::clamp(pos_.y, 0, maxY); } // check whats happen to the close button @@ -374,7 +368,7 @@ void CWindow::draw(Position /*parentOrigin*/) else resizebutton = WINDOW_BUTTON_RESIZE; getBmpTexture(resizebutton) - .draw(Position(origin + Position(static_cast(size_.x), static_cast(size_.y))) + .draw(origin + Position(static_cast(size_.x), static_cast(size_.y)) - Position(getBmpTexture(resizebutton).getSize())); } } From c165b70d87055c0b41075e8dc2a0eb37ab6d1687 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sun, 5 Jul 2026 16:05:13 +0200 Subject: [PATCH 26/40] getBmpTexture().draw() --- CIO/CButton.cpp | 7 ++----- CIO/CControlContainer.cpp | 4 +--- CIO/CPicture.cpp | 5 +---- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/CIO/CButton.cpp b/CIO/CButton.cpp index 9037681..ce6e12f 100644 --- a/CIO/CButton.cpp +++ b/CIO/CButton.cpp @@ -135,11 +135,8 @@ void CButton::draw(Position parentOrigin) const if(button_picture >= 0) { auto& picTex = getBmpTexture(button_picture); - if(picTex.isValid()) - { - const Position picPos = absPos + size_ / 2 - Position(picTex.getSize()) / 2; - picTex.draw(picPos); - } + const Position picPos = absPos + size_ / 2 - Position(picTex.getSize()) / 2; + picTex.draw(picPos); } else if(button_text) { // Draw text centered (using native-size texture drawing for each character) diff --git a/CIO/CControlContainer.cpp b/CIO/CControlContainer.cpp index a2a563d..df98926 100644 --- a/CIO/CControlContainer.cpp +++ b/CIO/CControlContainer.cpp @@ -189,8 +189,6 @@ void CControlContainer::drawChildren(Position origin) button->draw(origin); for(const auto& static_picture : static_pictures) { - auto& tex = getBmpTexture(static_picture.pic); - if(tex.isValid()) - tex.draw(origin + static_picture.pos); + getBmpTexture(static_picture.pic).draw(origin + static_picture.pos); } } diff --git a/CIO/CPicture.cpp b/CIO/CPicture.cpp index a4d5975..abe2f41 100644 --- a/CIO/CPicture.cpp +++ b/CIO/CPicture.cpp @@ -66,8 +66,5 @@ void CPicture::setMouseData(const SDL_MouseButtonEvent& button) void CPicture::draw(Position parentOrigin) const { - auto& tex = getBmpTexture(picture_); - if(!tex.isValid()) - return; - tex.draw(parentOrigin + pos_); + getBmpTexture(picture_).draw(parentOrigin + pos_); } From b37716b5c79f4b4b27943e8242f2d5e57fcdbb0f Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sun, 5 Jul 2026 16:12:37 +0200 Subject: [PATCH 27/40] clang-format --- CIO/CButton.cpp | 3 ++- CIO/CButton.h | 4 ++-- CIO/CControlContainer.h | 2 +- CIO/CMinimapWindow.cpp | 14 +++++++------- CIO/CPicture.h | 4 ++-- CIO/CSelectBox.cpp | 1 - CIO/CSelectBox.h | 4 ++-- CIO/CTextfield.cpp | 1 - CIO/CTextfield.h | 2 +- CIO/CWindow.cpp | 8 ++++---- CIO/CWindow.h | 4 ++-- 11 files changed, 23 insertions(+), 24 deletions(-) diff --git a/CIO/CButton.cpp b/CIO/CButton.cpp index ce6e12f..cb25536 100644 --- a/CIO/CButton.cpp +++ b/CIO/CButton.cpp @@ -140,7 +140,8 @@ void CButton::draw(Position parentOrigin) const } else if(button_text) { // Draw text centered (using native-size texture drawing for each character) - const Extent textSize(CFont::getTextWidth(button_text, FontSize::Medium), static_cast(FontSize::Medium)); + const Extent textSize(CFont::getTextWidth(button_text, FontSize::Medium), + static_cast(FontSize::Medium)); const Position textPos = absPos + (Position(size_) - textSize) / 2; CFont::draw(button_text, textPos, FontSize::Medium, button_text_color, FontAlign::Left); } diff --git a/CIO/CButton.h b/CIO/CButton.h index 531a728..27fe79d 100644 --- a/CIO/CButton.h +++ b/CIO/CButton.h @@ -33,8 +33,8 @@ class CButton // Access int getX() const { return pos_.x; }; int getY() const { return pos_.y; }; - const Position& getPos() const { return pos_; } - const Extent& getSize() const { return size_; }; + Position getPos() const { return pos_; } + Extent getSize() const { return size_; }; void setX(int x) { pos_.x = x; }; void setY(int y) { pos_.y = y; }; void setButtonPicture(int picture); diff --git a/CIO/CControlContainer.h b/CIO/CControlContainer.h index 59d73da..bcf4ee8 100644 --- a/CIO/CControlContainer.h +++ b/CIO/CControlContainer.h @@ -62,7 +62,7 @@ class CControlContainer CControlContainer(int pic_background, BorderSizes border); virtual ~CControlContainer() noexcept; // Access - const BorderSizes& getBorderSizes() const { return border; } + BorderSizes getBorderSizes() const { return border; } Extent getBorderSize() const { return {static_cast(border.left + border.right), static_cast(border.top + border.bottom)}; diff --git a/CIO/CMinimapWindow.cpp b/CIO/CMinimapWindow.cpp index 58a2db5..d599566 100644 --- a/CIO/CMinimapWindow.cpp +++ b/CIO/CMinimapWindow.cpp @@ -17,11 +17,9 @@ void CMinimapWindow::draw(Position /*parentOrigin*/) // Compute content area (inside the frames) const auto& b = getBorderSizes(); const Position contentPos = pos_ + Position(b.left, b.top); - const int cw = static_cast(size_.x) - b.left - b.right; - const int ch = static_cast(size_.y) - b.top - b.bottom; - if(cw <= 0 || ch <= 0) + const auto contentSize = getSize() - getBorderSize(); + if(static_cast(contentSize.x) <= 0 || static_cast(contentSize.y) <= 0) return; - const Extent contentSize(cw, ch); auto* map = global::s2->getMapObj(); if(!map) @@ -29,7 +27,7 @@ void CMinimapWindow::draw(Position /*parentOrigin*/) // Fill pixel buffer with minimap terrain int scale = 1; - map->drawMinimap(pixels_, cw, ch, scale); + map->drawMinimap(pixels_, static_cast(contentSize.x), static_cast(contentSize.y), scale); // Upload to texture and draw if(!minimapTex_.isValid() || minimapTex_.getSize() != contentSize) @@ -59,8 +57,10 @@ void CMinimapWindow::draw(Position /*parentOrigin*/) { const int arrowIdx = MAPPIC_ARROWCROSS_ORANGE; const auto& dispRect = map->getDisplayRect(); - const Position arrowCenter = dispRect.getOrigin() + Position(dispRect.getSize().x / 2, dispRect.getSize().y / 2); - const Position arrowPos = contentPos + arrowCenter / Position(triangleWidth, triangleHeight) / scale + const Position arrowCenter = + dispRect.getOrigin() + Position(dispRect.getSize().x / 2, dispRect.getSize().y / 2); + const Position arrowPos = + contentPos + arrowCenter / Position(triangleWidth, triangleHeight) / scale - Position(static_cast(global::bmpArray[arrowIdx].nx), static_cast(global::bmpArray[arrowIdx].ny)); getBmpTexture(arrowIdx).draw(arrowPos); } diff --git a/CIO/CPicture.h b/CIO/CPicture.h index 758bd48..5a88a57 100644 --- a/CIO/CPicture.h +++ b/CIO/CPicture.h @@ -28,8 +28,8 @@ class CPicture // Access int getX() const { return pos_.x; }; int getY() const { return pos_.y; }; - const Position& getPos() const { return pos_; } - const Extent& getSize() const { return size_; }; + Position getPos() const { return pos_; } + Extent getSize() const { return size_; }; void setX(int x) { pos_.x = x; }; void setY(int y) { pos_.y = y; }; void setMouseData(const SDL_MouseMotionEvent& motion); diff --git a/CIO/CSelectBox.cpp b/CIO/CSelectBox.cpp index 735ad09..a8cc946 100644 --- a/CIO/CSelectBox.cpp +++ b/CIO/CSelectBox.cpp @@ -237,5 +237,4 @@ void CSelectBox::draw(Position parentOrigin) // Draw scroll buttons (on top, within the select box) ScrollUpButton->draw(absPos); ScrollDownButton->draw(absPos); - } diff --git a/CIO/CSelectBox.h b/CIO/CSelectBox.h index 7917860..7b149d5 100644 --- a/CIO/CSelectBox.h +++ b/CIO/CSelectBox.h @@ -32,8 +32,8 @@ class CSelectBox public: CSelectBox(Position pos, Extent size, FontSize fontsize = FontSize::Large, FontColor text_color = FontColor::Yellow, int bg_color = -1); - const Position& getPos() const { return pos_; } - const Extent& getSize() const { return size_; } + Position getPos() const { return pos_; } + Extent getSize() const { return size_; } void setMouseData(SDL_MouseButtonEvent button); void setMouseData(SDL_MouseMotionEvent motion); void draw(Position parentOrigin); diff --git a/CIO/CTextfield.cpp b/CIO/CTextfield.cpp index 1ad793f..365ab56 100644 --- a/CIO/CTextfield.cpp +++ b/CIO/CTextfield.cpp @@ -268,5 +268,4 @@ void CTextfield::draw(Position parentOrigin) textObj->setText(displayText); textObj->draw(Position(parentOrigin.x + 2, parentOrigin.y + 4)); } - } diff --git a/CIO/CTextfield.h b/CIO/CTextfield.h index d0f72b3..1b10415 100644 --- a/CIO/CTextfield.h +++ b/CIO/CTextfield.h @@ -38,7 +38,7 @@ class CTextfield // Access Position getPos() const; void setPos(Position pos); - const Extent& getSize() const { return size_; }; + Extent getSize() const { return size_; }; int getCols() const { return cols; } int getRows() const { return rows; } void setText(const std::string& text); diff --git a/CIO/CWindow.cpp b/CIO/CWindow.cpp index 53a09d1..6129c4a 100644 --- a/CIO/CWindow.cpp +++ b/CIO/CWindow.cpp @@ -260,12 +260,12 @@ void CWindow::draw(Position /*parentOrigin*/) const auto viewH = global::s2->getRes().y; const auto& b = getBorderSizes(); const auto contentOrigin = origin + Position(b.left, b.top); - const auto contentW = static_cast(size_.x) - b.left - b.right; - const auto contentH = static_cast(size_.y) - b.top - b.bottom; - if(contentW > 0 && contentH > 0) + const auto contentSize = getSize() - getBorderSize(); + if(static_cast(contentSize.x) > 0 && static_cast(contentSize.y) > 0) { glEnable(GL_SCISSOR_TEST); - glScissor(contentOrigin.x, viewH - (contentOrigin.y + contentH), contentW, contentH); + glScissor(contentOrigin.x, viewH - (contentOrigin.y + static_cast(contentSize.y)), + static_cast(contentSize.x), static_cast(contentSize.y)); drawChildren(origin); glDisable(GL_SCISSOR_TEST); } diff --git a/CIO/CWindow.h b/CIO/CWindow.h index 54f636b..eb0ed8b 100644 --- a/CIO/CWindow.h +++ b/CIO/CWindow.h @@ -53,8 +53,8 @@ class CWindow : public CControlContainer CWindow(void callback(int), int callbackQuitMessage, WindowPos pos, Extent size, const char* title = nullptr, int color = WINDOW_GREEN1, Uint8 flags = 0); // Access - const Position& getPos() const { return pos_; } - const Extent& getSize() const { return size_; } + Position getPos() const { return pos_; } + Extent getSize() const { return size_; } Rect getRect() const { return Rect(pos_, size_); } int getPriority() const { return priority; } void setPriority(int priority) { this->priority = priority; } From 345ddc6ad1112b04a0f3e5c30fc24d12d310efba Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sun, 5 Jul 2026 16:23:58 +0200 Subject: [PATCH 28/40] unused forward declaration --- include/defines.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/defines.h b/include/defines.h index 11bc44a..5adf11c 100644 --- a/include/defines.h +++ b/include/defines.h @@ -85,8 +85,6 @@ struct bobBMP SdlSurface surface; }; -class Texture; - // Structure for Bobtype 5 (Palette) struct bobPAL { From e9610ce85e0d7f0692098130d25144e3bab6ea42 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sun, 5 Jul 2026 19:36:29 +0200 Subject: [PATCH 29/40] clamp window --- CIO/CWindow.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/CIO/CWindow.cpp b/CIO/CWindow.cpp index 6129c4a..fb348cc 100644 --- a/CIO/CWindow.cpp +++ b/CIO/CWindow.cpp @@ -78,14 +78,11 @@ void CWindow::setMouseData(SDL_MouseMotionEvent motion) moving = false; if(moving && canMove) { - pos_.x += motion.xrel; - pos_.y += motion.yrel; - // Clamp window position to screen bounds + pos_ += Position(motion.xrel, motion.yrel); + // Clamp window position so it stays on screen const auto res = global::s2->getRes(); - const int maxX = static_cast(res.x - size_.x) - 1; - const int maxY = static_cast(res.y - size_.y) - 1; - pos_.x = std::clamp(pos_.x, 0, maxX); - pos_.y = std::clamp(pos_.y, 0, maxY); + const auto maxPos = res - elMin(size_, res); + pos_ = elMin(elMax(pos_, Position(0, 0)), Position(maxPos)); } // check whats happen to the close button From a85ffeab0978e533660c29e1a3c6108c4974d960 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sun, 5 Jul 2026 20:13:54 +0200 Subject: [PATCH 30/40] Positioning fixes, window size clamped to on screen --- CIO/CMinimapWindow.cpp | 3 +-- CIO/CWindow.cpp | 15 ++++++--------- Texture.cpp | 2 +- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/CIO/CMinimapWindow.cpp b/CIO/CMinimapWindow.cpp index d599566..f326fb3 100644 --- a/CIO/CMinimapWindow.cpp +++ b/CIO/CMinimapWindow.cpp @@ -57,8 +57,7 @@ void CMinimapWindow::draw(Position /*parentOrigin*/) { const int arrowIdx = MAPPIC_ARROWCROSS_ORANGE; const auto& dispRect = map->getDisplayRect(); - const Position arrowCenter = - dispRect.getOrigin() + Position(dispRect.getSize().x / 2, dispRect.getSize().y / 2); + const Position arrowCenter = dispRect.getOrigin() + dispRect.getSize() / 2u; const Position arrowPos = contentPos + arrowCenter / Position(triangleWidth, triangleHeight) / scale - Position(static_cast(global::bmpArray[arrowIdx].nx), static_cast(global::bmpArray[arrowIdx].ny)); diff --git a/CIO/CWindow.cpp b/CIO/CWindow.cpp index fb348cc..7c3b02c 100644 --- a/CIO/CWindow.cpp +++ b/CIO/CWindow.cpp @@ -33,9 +33,8 @@ CWindow::CWindow(void callback(int), int callbackQuitMessage, Position pos, Exte static Position makePos(WindowPos pos, Extent size) { if(pos == WindowPos::Center) - { return (global::s2->getRes() - size) / 2; - } else + else return {}; } @@ -126,10 +125,9 @@ void CWindow::setMouseData(SDL_MouseMotionEvent motion) if(!minimized) { size_ = Extent(static_cast(size_.x) + motion.xrel, static_cast(size_.y) + motion.yrel); - - // MISSING: we have to test if window size is under minimum - - // notify the callback that the window has been resized + const auto res = global::s2->getRes(); + const auto maxSize = Extent(elMax(Position(res) - pos_, Position(1, 1))); + size_ = elMin(elMax(size_, Extent::all(1u)), maxSize); callback_(WINDOW_RESIZED_CALL); } } @@ -324,7 +322,7 @@ void CWindow::draw(Position /*parentOrigin*/) const int crH = getBmpTexture(WINDOW_CORNER_RECTANGLE).getSize().y; getBmpTexture(WINDOW_CORNER_RECTANGLE).draw(origin + Position(0, static_cast(size_.y) - crH)); getBmpTexture(WINDOW_CORNER_RECTANGLE) - .draw(origin + Position(static_cast(size_.x) - crW, static_cast(size_.y) - crH)); + .draw(origin + size_ - Position(crW, crH)); } // 9. Close button @@ -365,8 +363,7 @@ void CWindow::draw(Position /*parentOrigin*/) else resizebutton = WINDOW_BUTTON_RESIZE; getBmpTexture(resizebutton) - .draw(origin + Position(static_cast(size_.x), static_cast(size_.y)) - - Position(getBmpTexture(resizebutton).getSize())); + .draw(origin + size_ - getBmpTexture(resizebutton).getSize()); } } diff --git a/Texture.cpp b/Texture.cpp index de60ee8..b4ad199 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -163,7 +163,7 @@ void Texture::drawTiled(const Rect& destRect) const return; const Extent tileSize = getSize(); - if(static_cast(tileSize.x) <= 0 || static_cast(tileSize.y) <= 0) + if(tileSize.x == 0 || tileSize.y == 0) return; glColor4f(1, 1, 1, 1); From 09f9e1970d61cf9c8ca58ca55a28bba77af180c2 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sun, 5 Jul 2026 20:16:21 +0200 Subject: [PATCH 31/40] glColor is already reset where used --- Texture.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Texture.cpp b/Texture.cpp index b4ad199..2ecba97 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -166,7 +166,6 @@ void Texture::drawTiled(const Rect& destRect) const if(tileSize.x == 0 || tileSize.y == 0) return; - glColor4f(1, 1, 1, 1); glBindTexture(GL_TEXTURE_2D, texture_); glBegin(GL_QUADS); for(int y = destRect.top; y < destRect.bottom; y += static_cast(tileSize.y)) From dd1f30430204179d9f8dc45baf4efdaee23b9d71 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sun, 5 Jul 2026 20:22:06 +0200 Subject: [PATCH 32/40] dead code ensureBmpText() --- Texture.cpp | 7 ------- Texture.h | 2 -- 2 files changed, 9 deletions(-) diff --git a/Texture.cpp b/Texture.cpp index 2ecba97..8c9a63e 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -228,13 +228,6 @@ Texture& getBmpTexture(int idx, bool filterLinear) return cache[idx]; } -void ensureBmpTex(int idx) -{ - if(static_cast(idx) >= global::bmpArray.size()) - return; - getBmpTexture(idx); -} - void drawButtonBox(const Rect& area, bool pressed, int baseTex, int faceTex) { getBmpTexture(baseTex).drawTiled(area); diff --git a/Texture.h b/Texture.h index b634aae..cf3819a 100644 --- a/Texture.h +++ b/Texture.h @@ -48,8 +48,6 @@ class Texture void drawRect(const Rect& rect, unsigned color); -void ensureBmpTex(int idx); - void drawButtonBox(const Rect& area, bool pressed, int baseTex, int faceTex); Texture& getBmpTexture(int idx, bool filterLinear = false); From 8ab3cb2e9184e4004e5680cd2be9647032ea5ece Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sun, 5 Jul 2026 20:25:33 +0200 Subject: [PATCH 33/40] unsigned bmpArray idx --- Texture.cpp | 8 ++++---- Texture.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Texture.cpp b/Texture.cpp index 8c9a63e..bac0849 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -204,16 +204,16 @@ void drawRect(const Rect& rect, unsigned color) glColor4f(1, 1, 1, 1); } -Texture& getBmpTexture(int idx, bool filterLinear) +Texture& getBmpTexture(unsigned idx, bool filterLinear) { static std::vector cache; static std::vector linearFlags; - if(static_cast(idx) >= global::bmpArray.size()) + if(idx >= global::bmpArray.size()) { static Texture dummy; return dummy; } - if(static_cast(idx) >= cache.size()) + if(idx >= cache.size()) { cache.resize(static_cast(idx) + 1); linearFlags.resize(static_cast(idx) + 1, false); @@ -228,7 +228,7 @@ Texture& getBmpTexture(int idx, bool filterLinear) return cache[idx]; } -void drawButtonBox(const Rect& area, bool pressed, int baseTex, int faceTex) +void drawButtonBox(const Rect& area, bool pressed, unsigned baseTex, unsigned faceTex) { getBmpTexture(baseTex).drawTiled(area); diff --git a/Texture.h b/Texture.h index cf3819a..41ca247 100644 --- a/Texture.h +++ b/Texture.h @@ -48,6 +48,6 @@ class Texture void drawRect(const Rect& rect, unsigned color); -void drawButtonBox(const Rect& area, bool pressed, int baseTex, int faceTex); +void drawButtonBox(const Rect& area, bool pressed, unsigned baseTex, unsigned faceTex); -Texture& getBmpTexture(int idx, bool filterLinear = false); +Texture& getBmpTexture(unsigned idx, bool filterLinear = false); From 0d3f877aba47c36b1a7b20a4b8ffa3915915e308 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sun, 5 Jul 2026 20:52:23 +0200 Subject: [PATCH 34/40] inlined origin and winRect --- CIO/CWindow.cpp | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/CIO/CWindow.cpp b/CIO/CWindow.cpp index 7c3b02c..f5264ae 100644 --- a/CIO/CWindow.cpp +++ b/CIO/CWindow.cpp @@ -242,26 +242,23 @@ void CWindow::setMouseData(SDL_MouseButtonEvent button) void CWindow::draw(Position /*parentOrigin*/) { - const Position origin = pos_; - const Rect winRect(origin, size_); - // 1. Background fill (tiled) if(getBackground() != WINDOW_NOTHING) - getBmpTexture(getBackground()).drawTiled(winRect); + getBmpTexture(getBackground()).drawTiled(Rect(pos_, size_)); // 2. Content (if not minimized) — clipped to the area inside frames if(!minimized) { const auto viewH = global::s2->getRes().y; const auto& b = getBorderSizes(); - const auto contentOrigin = origin + Position(b.left, b.top); + const auto contentOrigin = pos_ + Position(b.left, b.top); const auto contentSize = getSize() - getBorderSize(); if(static_cast(contentSize.x) > 0 && static_cast(contentSize.y) > 0) { glEnable(GL_SCISSOR_TEST); glScissor(contentOrigin.x, viewH - (contentOrigin.y + static_cast(contentSize.y)), static_cast(contentSize.x), static_cast(contentSize.y)); - drawChildren(origin); + drawChildren(pos_); glDisable(GL_SCISSOR_TEST); } } @@ -277,52 +274,52 @@ void CWindow::draw(Position /*parentOrigin*/) // Draw upper frame tile across the top of the window { - const Rect upperFrameRect(origin, Extent(size_.x, getBmpTexture(upperframe).getSize().y)); + const Rect upperFrameRect(pos_, Extent(size_.x, getBmpTexture(upperframe).getSize().y)); getBmpTexture(upperframe).drawTiled(upperFrameRect); } // 4. Title text if(title) { - const int titleY = origin.y + (getBmpTexture(WINDOW_UPPER_FRAME).getSize().y - 9) / 2; - CFont::draw(title, Position(origin.x + static_cast(size_.x) / 2, titleY), FontSize::Small, + const int titleY = pos_.y + (getBmpTexture(WINDOW_UPPER_FRAME).getSize().y - 9) / 2; + CFont::draw(title, Position(pos_.x + static_cast(size_.x) / 2, titleY), FontSize::Small, FontColor::Yellow, FontAlign::Middle); } // 5. Lower frame (tiled across bottom) { const int lowerH = getBmpTexture(WINDOW_LOWER_FRAME).getSize().y; - const Rect lowerFrameRect(Position(origin.x, origin.y + static_cast(size_.y) - lowerH), + const Rect lowerFrameRect(Position(pos_.x, pos_.y + static_cast(size_.y) - lowerH), Extent(size_.x, lowerH)); getBmpTexture(WINDOW_LOWER_FRAME).drawTiled(lowerFrameRect); } // 6. Left frame (tiled down left side) { - const Rect leftFrameRect(origin, Extent(getBmpTexture(WINDOW_LEFT_FRAME).getSize().x, size_.y)); + const Rect leftFrameRect(pos_, Extent(getBmpTexture(WINDOW_LEFT_FRAME).getSize().x, size_.y)); getBmpTexture(WINDOW_LEFT_FRAME).drawTiled(leftFrameRect); } // 7. Right frame (tiled down right side) { const int rightW = getBmpTexture(WINDOW_RIGHT_FRAME).getSize().x; - const Rect rightFrameRect(Position(origin.x + static_cast(size_.x) - rightW, origin.y), + const Rect rightFrameRect(Position(pos_.x + static_cast(size_.x) - rightW, pos_.y), Extent(rightW, size_.y)); getBmpTexture(WINDOW_RIGHT_FRAME).drawTiled(rightFrameRect); } // 8. Corners { - getBmpTexture(WINDOW_LEFT_UPPER_CORNER).draw(origin); + getBmpTexture(WINDOW_LEFT_UPPER_CORNER).draw(pos_); const int ruW = getBmpTexture(WINDOW_RIGHT_UPPER_CORNER).getSize().x; - getBmpTexture(WINDOW_RIGHT_UPPER_CORNER).draw(origin + Position(static_cast(size_.x) - ruW, 0)); + getBmpTexture(WINDOW_RIGHT_UPPER_CORNER).draw(pos_ + Position(static_cast(size_.x) - ruW, 0)); const int crW = getBmpTexture(WINDOW_CORNER_RECTANGLE).getSize().x; const int crH = getBmpTexture(WINDOW_CORNER_RECTANGLE).getSize().y; - getBmpTexture(WINDOW_CORNER_RECTANGLE).draw(origin + Position(0, static_cast(size_.y) - crH)); + getBmpTexture(WINDOW_CORNER_RECTANGLE).draw(pos_ + Position(0, static_cast(size_.y) - crH)); getBmpTexture(WINDOW_CORNER_RECTANGLE) - .draw(origin + size_ - Position(crW, crH)); + .draw(pos_ + size_ - Position(crW, crH)); } // 9. Close button @@ -335,7 +332,7 @@ void CWindow::draw(Position /*parentOrigin*/) closebutton = WINDOW_BUTTON_CLOSE_MARKED; else closebutton = WINDOW_BUTTON_CLOSE; - getBmpTexture(closebutton).draw(origin); + getBmpTexture(closebutton).draw(pos_); } // 10. Minimize button @@ -349,7 +346,7 @@ void CWindow::draw(Position /*parentOrigin*/) else minimizebutton = WINDOW_BUTTON_MINIMIZE; getBmpTexture(minimizebutton) - .draw(origin + Position(static_cast(size_.x) - getBmpTexture(minimizebutton).getSize().x, 0)); + .draw(pos_ + Position(static_cast(size_.x) - getBmpTexture(minimizebutton).getSize().x, 0)); } // 11. Resize button @@ -363,7 +360,7 @@ void CWindow::draw(Position /*parentOrigin*/) else resizebutton = WINDOW_BUTTON_RESIZE; getBmpTexture(resizebutton) - .draw(origin + size_ - getBmpTexture(resizebutton).getSize()); + .draw(pos_ + size_ - getBmpTexture(resizebutton).getSize()); } } From 84608ca08ae1d7e96ef8851659dd45148fbabb5a Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sun, 5 Jul 2026 20:54:31 +0200 Subject: [PATCH 35/40] tidy --- CIO/CMinimapWindow.cpp | 5 ++--- CIO/CWindow.cpp | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/CIO/CMinimapWindow.cpp b/CIO/CMinimapWindow.cpp index f326fb3..068a147 100644 --- a/CIO/CMinimapWindow.cpp +++ b/CIO/CMinimapWindow.cpp @@ -45,8 +45,7 @@ void CMinimapWindow::draw(Position /*parentOrigin*/) const int flagIdx = FLAG_BLUE_DARK + i % 7; const Position hqPos = Position(hqX, hqY) / scale; - const Position flagOffset(static_cast(global::bmpArray[flagIdx].nx), - static_cast(global::bmpArray[flagIdx].ny)); + const Position flagOffset(global::bmpArray[flagIdx].nx, global::bmpArray[flagIdx].ny); getBmpTexture(flagIdx).draw(contentPos + hqPos - flagOffset); // Player number @@ -60,7 +59,7 @@ void CMinimapWindow::draw(Position /*parentOrigin*/) const Position arrowCenter = dispRect.getOrigin() + dispRect.getSize() / 2u; const Position arrowPos = contentPos + arrowCenter / Position(triangleWidth, triangleHeight) / scale - - Position(static_cast(global::bmpArray[arrowIdx].nx), static_cast(global::bmpArray[arrowIdx].ny)); + - Position(global::bmpArray[arrowIdx].nx, global::bmpArray[arrowIdx].ny); getBmpTexture(arrowIdx).draw(arrowPos); } } diff --git a/CIO/CWindow.cpp b/CIO/CWindow.cpp index f5264ae..d4da83a 100644 --- a/CIO/CWindow.cpp +++ b/CIO/CWindow.cpp @@ -174,8 +174,7 @@ void CWindow::setMouseData(SDL_MouseButtonEvent button) clicked = true; } // pressed inside the window - if(button.state == SDL_PRESSED && (button.x >= pos_.x) && (button.x <= pos_.x + static_cast(size_.x)) - && (button.y >= pos_.y) && (button.y <= pos_.y + static_cast(size_.y))) + if(button.state == SDL_PRESSED && IsPointInRect(button.x, button.y, Rect(pos_, size_))) marked = true; // else pressed outside of the window else if(button.state == SDL_PRESSED) From 5b6284cd5cacb33866a01f0aecdb8b0c7b515e89 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Sun, 5 Jul 2026 20:54:55 +0200 Subject: [PATCH 36/40] clang-format --- CIO/CMinimapWindow.cpp | 5 ++--- CIO/CWindow.cpp | 10 ++++------ 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/CIO/CMinimapWindow.cpp b/CIO/CMinimapWindow.cpp index 068a147..6b7f4e5 100644 --- a/CIO/CMinimapWindow.cpp +++ b/CIO/CMinimapWindow.cpp @@ -57,9 +57,8 @@ void CMinimapWindow::draw(Position /*parentOrigin*/) const int arrowIdx = MAPPIC_ARROWCROSS_ORANGE; const auto& dispRect = map->getDisplayRect(); const Position arrowCenter = dispRect.getOrigin() + dispRect.getSize() / 2u; - const Position arrowPos = - contentPos + arrowCenter / Position(triangleWidth, triangleHeight) / scale - - Position(global::bmpArray[arrowIdx].nx, global::bmpArray[arrowIdx].ny); + const Position arrowPos = contentPos + arrowCenter / Position(triangleWidth, triangleHeight) / scale + - Position(global::bmpArray[arrowIdx].nx, global::bmpArray[arrowIdx].ny); getBmpTexture(arrowIdx).draw(arrowPos); } } diff --git a/CIO/CWindow.cpp b/CIO/CWindow.cpp index d4da83a..00be721 100644 --- a/CIO/CWindow.cpp +++ b/CIO/CWindow.cpp @@ -281,8 +281,8 @@ void CWindow::draw(Position /*parentOrigin*/) if(title) { const int titleY = pos_.y + (getBmpTexture(WINDOW_UPPER_FRAME).getSize().y - 9) / 2; - CFont::draw(title, Position(pos_.x + static_cast(size_.x) / 2, titleY), FontSize::Small, - FontColor::Yellow, FontAlign::Middle); + CFont::draw(title, Position(pos_.x + static_cast(size_.x) / 2, titleY), FontSize::Small, FontColor::Yellow, + FontAlign::Middle); } // 5. Lower frame (tiled across bottom) @@ -317,8 +317,7 @@ void CWindow::draw(Position /*parentOrigin*/) const int crW = getBmpTexture(WINDOW_CORNER_RECTANGLE).getSize().x; const int crH = getBmpTexture(WINDOW_CORNER_RECTANGLE).getSize().y; getBmpTexture(WINDOW_CORNER_RECTANGLE).draw(pos_ + Position(0, static_cast(size_.y) - crH)); - getBmpTexture(WINDOW_CORNER_RECTANGLE) - .draw(pos_ + size_ - Position(crW, crH)); + getBmpTexture(WINDOW_CORNER_RECTANGLE).draw(pos_ + size_ - Position(crW, crH)); } // 9. Close button @@ -358,8 +357,7 @@ void CWindow::draw(Position /*parentOrigin*/) resizebutton = WINDOW_BUTTON_RESIZE_MARKED; else resizebutton = WINDOW_BUTTON_RESIZE; - getBmpTexture(resizebutton) - .draw(pos_ + size_ - getBmpTexture(resizebutton).getSize()); + getBmpTexture(resizebutton).draw(pos_ + size_ - getBmpTexture(resizebutton).getSize()); } } From e364d69b59a6f75c761cd449399dfc8154ce1575 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Mon, 6 Jul 2026 19:18:15 +0200 Subject: [PATCH 37/40] Restore docstrings --- Texture.h | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/Texture.h b/Texture.h index 41ca247..b306c67 100644 --- a/Texture.h +++ b/Texture.h @@ -8,6 +8,7 @@ #include #include +/// Wraps a texture with RAII and provides draw methods. class Texture { public: @@ -21,33 +22,50 @@ class Texture Texture(const Texture&) = delete; Texture& operator=(const Texture&) = delete; + /// Load from a 32-bit or 8-bit paletted SDL surface. + /// For 8-bit surfaces, optional colorkey is respected (keyed pixels become transparent). bool load(SDL_Surface* surface, bool filterLinear = false); + /// Create an empty texture of the given size (for use as a render-target). void createEmpty(Extent size, bool filterLinear = false); + /// Upload new pixel data to an existing texture (glTexSubImage2D). void upload(const void* bgraPixels); + /// Draw the texture stretched to fill the given rect. void draw(const Rect& destRect) const; + /// Draw the texture at native size at the given position. void draw(Position pos) const; + /// Tile the texture to fill the given rectangle. void drawTiled(const Rect& destRect) const; + /// Returns the raw GL texture name (for use with glBindTexture). unsigned getHandle() const { return texture_; } + /// Size in pixels. Extent getSize() const { return size_; } + /// Returns true if the texture has been created. bool isValid() const { return texture_ != 0; } private: unsigned int texture_ = 0; Extent size_; + /// Internal: create or recreate texture from raw BGRA pixel data. void load(const void* bgraPixels, Extent size, bool filterLinear); }; +/// Draw a filled rectangle with a 32-bit ARGB colour. void drawRect(const Rect& rect, unsigned color); +/// Draw a 3D-style button box: tiled background, 2px black frame (sunken if pressed, raised otherwise), +/// and tiled foreground inset by 2px. void drawButtonBox(const Rect& area, bool pressed, unsigned baseTex, unsigned faceTex); -Texture& getBmpTexture(unsigned idx, bool filterLinear = false); +/// Get or create the cached OpenGL texture for a bitmap index. +/// The texture is loaded from the SDL surface on first access. +/// @param filterLinear Whether to use linear filtering (for scaled backgrounds). +Texture& getBmpTexture(int idx, bool filterLinear = false); From 66bb4be51e24e088584a7f1c5350e23df52ce190 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Mon, 6 Jul 2026 19:22:15 +0200 Subject: [PATCH 38/40] Restore docstrings --- CIO/CControlContainer.h | 4 ++++ CIO/CFont.h | 3 +++ 2 files changed, 7 insertions(+) diff --git a/CIO/CControlContainer.h b/CIO/CControlContainer.h index bcf4ee8..bebcfe8 100644 --- a/CIO/CControlContainer.h +++ b/CIO/CControlContainer.h @@ -15,6 +15,7 @@ class CPicture; class CTextfield; class CSelectBox; +/// Pixel thickness of a window's frame border on each edge. struct BorderSizes { int left = 0; @@ -50,7 +51,10 @@ class CControlContainer bool eraseElement(T& collection, const U* element); protected: + /// Draw the container's background and child elements using OpenGL. + /// @param parentOrigin Absolute position of the parent container. virtual void draw(Position parentOrigin) = 0; + /// Draw children at the given origin (calls each child's Draw). void drawChildren(Position origin); auto& getTextFields() { return textfields; } diff --git a/CIO/CFont.h b/CIO/CFont.h index b44602f..8d7f5e0 100644 --- a/CIO/CFont.h +++ b/CIO/CFont.h @@ -47,8 +47,11 @@ class CFont } void setMouseData(SDL_MouseButtonEvent button); + /// Draw this font's text at the given absolute position using OpenGL. void draw(Position parentOrigin) const; + /// Static helpers for drawing text with OpenGL directly. + /// @param pos Absolute position (top-left of the text, adjusted for alignment). static void draw(const std::string& string, Position pos, FontSize fontsize = FontSize::Small, FontColor color = FontColor::Yellow, FontAlign align = FontAlign::Left); From 4040fd9f5c3310f6deb25a7c58d74ca0290883b2 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Tue, 7 Jul 2026 16:17:10 +0200 Subject: [PATCH 39/40] Apply docstring suggestions Co-authored-by: Alexander Grund --- CIO/CControlContainer.h | 2 +- CIO/CFont.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CIO/CControlContainer.h b/CIO/CControlContainer.h index bebcfe8..2f945dd 100644 --- a/CIO/CControlContainer.h +++ b/CIO/CControlContainer.h @@ -51,7 +51,7 @@ class CControlContainer bool eraseElement(T& collection, const U* element); protected: - /// Draw the container's background and child elements using OpenGL. + /// Draw the container's background and child elements /// @param parentOrigin Absolute position of the parent container. virtual void draw(Position parentOrigin) = 0; /// Draw children at the given origin (calls each child's Draw). diff --git a/CIO/CFont.h b/CIO/CFont.h index 8d7f5e0..2448235 100644 --- a/CIO/CFont.h +++ b/CIO/CFont.h @@ -47,10 +47,10 @@ class CFont } void setMouseData(SDL_MouseButtonEvent button); - /// Draw this font's text at the given absolute position using OpenGL. + /// Draw this font's text at the given absolute position void draw(Position parentOrigin) const; - /// Static helpers for drawing text with OpenGL directly. + /// Draw text directly /// @param pos Absolute position (top-left of the text, adjusted for alignment). static void draw(const std::string& string, Position pos, FontSize fontsize = FontSize::Small, FontColor color = FontColor::Yellow, FontAlign align = FontAlign::Left); From 2a5ad4d8c005655f7626d6888e07fa916726fb96 Mon Sep 17 00:00:00 2001 From: Morgan Christiansson Date: Tue, 7 Jul 2026 16:18:04 +0200 Subject: [PATCH 40/40] getRect() Co-authored-by: Alexander Grund --- CIO/CWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIO/CWindow.cpp b/CIO/CWindow.cpp index 00be721..7696e9d 100644 --- a/CIO/CWindow.cpp +++ b/CIO/CWindow.cpp @@ -243,7 +243,7 @@ void CWindow::draw(Position /*parentOrigin*/) { // 1. Background fill (tiled) if(getBackground() != WINDOW_NOTHING) - getBmpTexture(getBackground()).drawTiled(Rect(pos_, size_)); + getBmpTexture(getBackground()).drawTiled(getRect()); // 2. Content (if not minimized) — clipped to the area inside frames if(!minimized)