Skip to content

Commit 6dd57e4

Browse files
Morgan Christianssonmorganchristiansson
authored andcommitted
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
1 parent 517ffa5 commit 6dd57e4

9 files changed

Lines changed: 111 additions & 68 deletions

File tree

CGame.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,6 @@ int CGame::Execute()
7777

7878
void CGame::RenderPresent()
7979
{
80-
displayTexture_.upload(Surf_Display->pixels);
81-
displayTexture_.Draw(Rect(0, 0, GameResolution.x, GameResolution.y));
82-
8380
const auto& cursorImg = Cursor.clicked ? (Cursor.button.right ? cross_ : cursorClicked_) : cursor_;
8481
cursorImg.Draw(Cursor.pos);
8582

CGame.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
#pragma once
77

88
#include "CIO/CFont.h"
9-
#include "SdlSurface.h"
109
#include "Texture.h"
1110
#include <boost/filesystem/path.hpp>
1211
#include <Point.h>
@@ -27,8 +26,6 @@ class CGame
2726

2827
bool Running;
2928
bool showLoadScreen;
30-
SdlSurface Surf_Display;
31-
Texture displayTexture_;
3229
SDL_GLContext glContext_ = nullptr;
3330
SdlWindow window_;
3431

@@ -52,6 +49,8 @@ class CGame
5249
Texture cursor_;
5350
Texture cursorClicked_;
5451
Texture cross_;
52+
Texture fpsTex_; ///< Texture for the FPS counter
53+
Texture mapTex_; ///< Texture for the map/terrain (Surf_Map may be 8-bit)
5554

5655
// structure for mouse cursor
5756
struct
@@ -111,6 +110,5 @@ class CGame
111110
CMap* getMapObj();
112111
void delMapObj();
113112
void enterEditor(const boost::filesystem::path& filepath);
114-
SDL_Surface* getDisplaySurface() const { return Surf_Display.get(); };
115113
auto getRes() const { return GameResolution; }
116114
};

CGame_Init.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@ bool CGame::CreateWindow()
3838
SDL_ShowWindow(window_.get());
3939

4040
ApplyWindowChanges();
41-
if(!displayTexture_.isValid() || !Surf_Display)
42-
return false;
4341

4442
SetAppIcon();
4543

@@ -125,9 +123,6 @@ void CGame::UpdateDisplaySize(const Extent& newSize)
125123
appliedResolution_ = GameResolution;
126124
appliedFullscreen_ = fullscreen;
127125

128-
Surf_Display = makeRGBSurface(GameResolution.x, GameResolution.y, true);
129-
displayTexture_.createEmpty(GameResolution);
130-
131126
setGLViewport();
132127
for(auto& menu : Menus)
133128
{

CGame_Render.cpp

Lines changed: 61 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ void CGame::SetAppIcon()
4040
void CGame::Render()
4141
{
4242
glClear(GL_COLOR_BUFFER_BIT);
43-
SDL_FillRect(Surf_Display.get(), nullptr, SDL_MapRGBA(Surf_Display->format, 0, 0, 0, 0));
4443

4544
// if the S2 loading screen is shown, render only this until user clicks a mouse button
4645
if(showLoadScreen)
@@ -50,53 +49,58 @@ void CGame::Render()
5049
return;
5150
}
5251

53-
// render the map if active
52+
// ---- 1. Menu backgrounds are drawn via getTexture() ----
53+
54+
// ---- 2. Render map (software) and draw via GL ----
55+
// Map renders directly to its own Surf_Map; we upload that to GL.
56+
// Text overlays are written onto Surf_Map before upload.
5457
if(MapObj && MapObj->isActive())
5558
{
56-
CSurface::Draw(Surf_Display, MapObj->getSurface(), 0, 0);
57-
std::array<char, 100> textBuffer;
58-
// text for x and y of vertex (shown in upper left corner)
59-
std::snprintf(textBuffer.data(), textBuffer.size(), "%d %d", MapObj->getVertexX(), MapObj->getVertexY());
60-
CFont::writeText(Surf_Display, textBuffer.data(), Position(20, 20));
61-
// text for MinReduceHeight and MaxRaiseHeight
62-
std::snprintf(textBuffer.data(), textBuffer.size(),
63-
"min. height: %#04x/0x3C max. height: %#04x/0x3C NormalNull: 0x0A",
64-
MapObj->getMinReduceHeight(), MapObj->getMaxRaiseHeight());
65-
CFont::writeText(Surf_Display, textBuffer.data(), Position(100, 20));
66-
// text for MovementLocked
67-
if(MapObj->isHorizontalMovementLocked() && MapObj->isVerticalMovementLocked())
68-
CFont::writeText(Surf_Display, "Movement locked (F9 or F10 to unlock)", Position(20, 40), FontSize::Large,
69-
FontColor::Orange);
70-
else if(MapObj->isHorizontalMovementLocked())
71-
CFont::writeText(Surf_Display, "Horizontal movement locked (F9 to unlock)", Position(20, 40),
72-
FontSize::Large, FontColor::Orange);
73-
else if(MapObj->isVerticalMovementLocked())
74-
CFont::writeText(Surf_Display, "Vertical movement locked (F10 to unlock)", Position(20, 40),
75-
FontSize::Large, FontColor::Orange);
59+
auto* mapSurf = MapObj->getSurface();
60+
if(mapSurf)
61+
{
62+
std::array<char, 100> textBuffer;
63+
std::snprintf(textBuffer.data(), textBuffer.size(), "%d %d", MapObj->getVertexX(), MapObj->getVertexY());
64+
CFont::writeText(mapSurf, textBuffer.data(), 20, 20);
65+
std::snprintf(textBuffer.data(), textBuffer.size(),
66+
"min. height: %#04x/0x3C max. height: %#04x/0x3C NormalNull: 0x0A",
67+
MapObj->getMinReduceHeight(), MapObj->getMaxRaiseHeight());
68+
CFont::writeText(mapSurf, textBuffer.data(), 100, 20);
69+
if(MapObj->isHorizontalMovementLocked() && MapObj->isVerticalMovementLocked())
70+
CFont::writeText(mapSurf, "Movement locked (F9 or F10 to unlock)", 20, 40, FontSize::Large,
71+
FontColor::Orange);
72+
else if(MapObj->isHorizontalMovementLocked())
73+
CFont::writeText(mapSurf, "Horizontal movement locked (F9 to unlock)", 20, 40, FontSize::Large,
74+
FontColor::Orange);
75+
else if(MapObj->isVerticalMovementLocked())
76+
CFont::writeText(mapSurf, "Vertical movement locked (F10 to unlock)", 20, 40, FontSize::Large,
77+
FontColor::Orange);
78+
79+
mapTex_.load(mapSurf);
80+
mapTex_.Draw(Rect(0, 0, GameResolution.x, GameResolution.y));
81+
}
7682
}
7783

78-
// render active menus
84+
// ---- 3. Draw UI controls via OpenGL ----
7985
for(auto& Menu : Menus)
8086
{
8187
if(Menu->isActive())
82-
CSurface::Draw(Surf_Display, Menu->getSurface(), 0, 0);
88+
Menu->getTexture().Draw(Rect(0, 0, GameResolution.x, GameResolution.y));
8389
}
8490

85-
// render windows ordered by priority
91+
// render windows ordered by priority, lowest first
8692
int highestPriority = 0;
87-
// first find the highest priority
8893
for(auto& Window : Windows)
8994
{
9095
if(Window->getPriority() > highestPriority)
9196
highestPriority = Window->getPriority();
9297
}
93-
// render from lowest priority to highest
9498
for(int actualPriority = 0; actualPriority <= highestPriority; actualPriority++)
9599
{
96100
for(auto& Window : Windows)
97101
{
98102
if(Window->getPriority() == actualPriority)
99-
CSurface::Draw(Surf_Display, Window->getSurface(), Window->getX(), Window->getY());
103+
Window->getTexture().Draw(Position(Window->getX(), Window->getY()));
100104
}
101105
}
102106

@@ -105,7 +109,6 @@ void CGame::Render()
105109
#endif
106110

107111
++framesPassedSinceLastFps;
108-
109112
const auto curTicks = SDL_GetTicks();
110113
const auto diffTicks = curTicks - lastFpsTick;
111114
if(diffTicks > 1000)
@@ -114,9 +117,36 @@ void CGame::Render()
114117
framesPassedSinceLastFps = 0;
115118
lastFpsTick = curTicks;
116119
}
117-
CSurface::Draw(Surf_Display, lastFps.getSurface(), 0, 0);
120+
{
121+
auto* fpsSurf = lastFps.getSurface();
122+
if(fpsSurf)
123+
{
124+
fpsTex_.load(fpsSurf);
125+
glBindTexture(GL_TEXTURE_2D, fpsTex_.getHandle());
126+
glBegin(GL_QUADS);
127+
glTexCoord2f(0, 0);
128+
glVertex2i(0, 0);
129+
glTexCoord2f(1, 0);
130+
glVertex2i(fpsSurf->w, 0);
131+
glTexCoord2f(1, 1);
132+
glVertex2i(fpsSurf->w, fpsSurf->h);
133+
glTexCoord2f(0, 1);
134+
glVertex2i(0, fpsSurf->h);
135+
glEnd();
136+
}
137+
}
138+
139+
// ---- 5. Cursor on top of everything ----
140+
{
141+
const auto& cursorImg = Cursor.clicked ? (Cursor.button.right ? cross_ : cursorClicked_) : cursor_;
142+
cursorImg.Draw(Cursor.pos);
143+
}
118144

119-
RenderPresent();
145+
SDL_GL_SwapWindow(window_.get());
146+
147+
#ifdef _ADMINMODE
148+
FrameCounter++;
149+
#endif
120150

121151
if(msWait)
122152
SDL_Delay(msWait);

CIO/CControlContainer.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#pragma once
77

8+
#include "../Texture.h"
89
#include "defines.h"
910
#include <memory>
1011
#include <vector>
@@ -45,6 +46,7 @@ class CControlContainer
4546
protected:
4647
SdlSurface surface;
4748
bool needRender = true;
49+
Texture surfaceTex_; ///< Texture for this container's surface (used by CWindow)
4850

4951
void renderElements();
5052
auto& getTextFields() { return textfields; }
@@ -54,13 +56,22 @@ class CControlContainer
5456
public:
5557
CControlContainer(int pic_background);
5658
CControlContainer(int pic_background, Extent borderBeginSize, Extent borderEndSize);
57-
~CControlContainer() noexcept;
59+
virtual ~CControlContainer() noexcept;
5860
// Access
5961
Extent getBorderSize() const { return borderBeginSize + borderEndSize; }
6062
void setBackgroundPicture(int pic_background);
6163
virtual void setMouseData(SDL_MouseMotionEvent motion);
6264
virtual void setMouseData(SDL_MouseButtonEvent button);
6365
void setKeyboardData(const SDL_KeyboardEvent& key);
66+
/// Get the texture for this container's rendered content.
67+
const Texture& getTexture()
68+
{
69+
render();
70+
if(surface)
71+
surfaceTex_.load(surface.get());
72+
return surfaceTex_;
73+
}
74+
/// Get the raw surface for direct pixel access (minimap overlay, etc.).
6475
SDL_Surface* getSurface()
6576
{
6677
render();

CIO/CWindow.cpp

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,10 @@ CWindow::CWindow(void callback(int), int callbackQuitMessage, Position pos, Exte
4242
static Position makePos(WindowPos pos, Extent size)
4343
{
4444
if(pos == WindowPos::Center)
45-
return Position(global::s2->getDisplaySurface()->w, global::s2->getDisplaySurface()->h) / 2 - size / 2;
46-
else
45+
{
46+
const auto res = global::s2->getRes();
47+
return Position(res.x / 2, res.y / 2) - size / 2;
48+
} else
4749
return {};
4850
}
4951

@@ -91,12 +93,14 @@ void CWindow::setMouseData(SDL_MouseMotionEvent motion)
9193
// make sure to not move the window outside the display surface
9294
if(x_ < 0)
9395
x_ = 0;
94-
if(x_ + w_ >= global::s2->getDisplaySurface()->w) //-V807
95-
x_ = global::s2->getDisplaySurface()->w - w_ - 1;
96-
if(y_ < 0)
97-
y_ = 0;
98-
if(y_ + h_ >= global::s2->getDisplaySurface()->h)
99-
y_ = global::s2->getDisplaySurface()->h - h_ - 1;
96+
{
97+
const auto res = global::s2->getRes();
98+
const int resW = res.x, resH = res.y;
99+
if(x_ + w_ >= resW) //-V807
100+
x_ = resW - w_ - 1;
101+
if(y_ + h_ >= resH)
102+
y_ = resH - h_ - 1;
103+
}
100104
}
101105

102106
// check whats happen to the close button

Texture.cpp

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -98,21 +98,13 @@ bool Texture::load(SDL_Surface* surface, bool filterLinear)
9898
return true;
9999
}
100100

101-
// 32-bit surface: convert to destination format (BGRA), force full opacity
101+
// 32-bit surface: convert to destination format (BGRA).
102+
// SDL_ConvertSurfaceFormat preserves color keys and alpha, so
103+
// transparent pixels keep alpha=0 and text anti-aliasing is retained.
102104
SDL_Surface* converted = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ARGB8888, 0);
103105
if(!converted)
104106
return false;
105107

106-
// Force alpha to opaque (LBM palette entries often have alpha=0)
107-
SDL_LockSurface(converted);
108-
for(int y = 0; y < converted->h; y++)
109-
{
110-
auto* row = (Uint32*)((Uint8*)converted->pixels + y * converted->pitch);
111-
for(int x = 0; x < converted->w; x++)
112-
row[x] |= 0xFF000000u; // set alpha bits
113-
}
114-
SDL_UnlockSurface(converted);
115-
116108
load(converted->pixels, Extent(converted->w, converted->h), filterLinear);
117109
SDL_FreeSurface(converted);
118110
return true;

Texture.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,18 @@ class Texture
3838
/// Draw the texture at native size at the given position.
3939
void Draw(Position pos) const;
4040

41+
/// Convenience overload for callers using separate x/y.
42+
void Draw(int x, int y) const { Draw(Position(x, y)); }
43+
44+
/// Returns the raw GL texture name (for use with glBindTexture).
45+
unsigned getHandle() const { return texture_; }
46+
47+
/// Width in pixels.
48+
int getWidth() const { return size_.x; }
49+
50+
/// Height in pixels.
51+
int getHeight() const { return size_.y; }
52+
4153
/// Returns true if the texture has been created.
4254
bool isValid() const { return texture_ != 0; }
4355

callbacks.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "globals.h"
2020
#include "helpers/format.hpp"
2121
#include "s25util/strAlgos.h"
22+
#include <glad/glad.h>
2223
#include <boost/filesystem.hpp>
2324
#include <algorithm>
2425
#include <cctype>
@@ -51,9 +52,12 @@ void callback::PleaseWait(int Param)
5152
WNDWait->addText("Please wait ...", Position(10, 10), FontSize::Large);
5253
// we need to render this window NOW, cause the render loop will do it too late (when the operation
5354
// is done and we don't need the "Please wait"-window anymore)
54-
CSurface::Draw(global::s2->getDisplaySurface(), WNDWait->getSurface(),
55-
global::s2->getDisplaySurface()->w / 2 - 106, global::s2->getDisplaySurface()->h / 2 - 35);
56-
global::s2->RenderPresent();
55+
{
56+
const auto res = global::s2->getRes();
57+
glClear(GL_COLOR_BUFFER_BIT);
58+
WNDWait->getTexture().Draw(Position(res.x / 2 - 106, res.y / 2 - 35));
59+
global::s2->RenderPresent();
60+
}
5761
break;
5862

5963
case CALL_FROM_GAMELOOP: // This window gives a "Please Wait"-string, so it is shown while there is an intensive
@@ -2849,8 +2853,8 @@ void callback::MinimapMenu(int Param)
28492853
height = map->height / scaleNum;
28502854
//--> 12px is width of left and right window frame and 30px is height of the upper and lower window
28512855
// frame
2852-
if((global::s2->getDisplaySurface()->w - 12 < width)
2853-
|| (global::s2->getDisplaySurface()->h - 30 < height))
2856+
if((static_cast<int>(global::s2->getRes().x) - 12 < width)
2857+
|| (static_cast<int>(global::s2->getRes().y) - 30 < height))
28542858
break;
28552859
WNDMinimap = global::s2->RegisterWindow(
28562860
std::make_unique<CWindow>(MinimapMenu, WINDOWQUIT, WindowPos::Center, Extent(width + 12, height + 30),

0 commit comments

Comments
 (0)