@@ -44,14 +44,10 @@ void CGame::Render()
4444 // Ensure viewport and ortho projection match current window size (handles resize)
4545 setGLViewport ();
4646
47- // Clear the framebuffer and the software overlay surface.
48- // GL draws (backgrounds) and the final Surf_Display overlay are
49- // composited via blending.
47+ // Clear the framebuffer.
5048 glClear (GL_COLOR_BUFFER_BIT );
51- SDL_FillRect (Surf_Display.get (), nullptr , SDL_MapRGBA (Surf_Display->format , 0 , 0 , 0 , 0 ));
5249
53- if (Extent (Surf_Display->w , Surf_Display->h ) != GameResolution
54- || fullscreen != ((SDL_GetWindowFlags (window_.get ()) & SDL_WINDOW_FULLSCREEN ) != 0 ))
50+ if (fullscreen != ((SDL_GetWindowFlags (window_.get ()) & SDL_WINDOW_FULLSCREEN ) != 0 ))
5551 {
5652 ReCreateWindow ();
5753 }
@@ -64,71 +60,75 @@ void CGame::Render()
6460 return ;
6561 }
6662
67- // render the map if active
68- if (MapObj && MapObj->isActive ())
69- {
70- CSurface::Draw (Surf_Display, MapObj->getSurface (), 0 , 0 );
71- std::array<char , 100 > textBuffer;
72- // text for x and y of vertex (shown in upper left corner)
73- std::snprintf (textBuffer.data (), textBuffer.size (), " %d %d" , MapObj->getVertexX (), MapObj->getVertexY ());
74- CFont::writeText (Surf_Display, textBuffer.data (), Position (20 , 20 ));
75- // text for MinReduceHeight and MaxRaiseHeight
76- std::snprintf (textBuffer.data (), textBuffer.size (),
77- " min. height: %#04x/0x3C max. height: %#04x/0x3C NormalNull: 0x0A" ,
78- MapObj->getMinReduceHeight (), MapObj->getMaxRaiseHeight ());
79- CFont::writeText (Surf_Display, textBuffer.data (), Position (100 , 20 ));
80- // text for MovementLocked
81- if (MapObj->isHorizontalMovementLocked () && MapObj->isVerticalMovementLocked ())
82- CFont::writeText (Surf_Display, " Movement locked (F9 or F10 to unlock)" , Position (20 , 40 ), FontSize::Large,
83- FontColor::Orange);
84- else if (MapObj->isHorizontalMovementLocked ())
85- CFont::writeText (Surf_Display, " Horizontal movement locked (F9 to unlock)" , Position (20 , 40 ),
86- FontSize::Large, FontColor::Orange);
87- else if (MapObj->isVerticalMovementLocked ())
88- CFont::writeText (Surf_Display, " Vertical movement locked (F10 to unlock)" , Position (20 , 40 ),
89- FontSize::Large, FontColor::Orange);
90- }
91-
92- // render active menus
63+ // ---- 1. Draw menu backgrounds via OpenGL ----
9364 for (auto & Menu : Menus)
9465 {
9566 if (Menu->isActive ())
9667 {
97- // Draw menu background via OpenGL
9868 int bgIdx = Menu->getBackground ();
9969 (bgIdx == SPLASHSCREEN_MAINMENU ? menuBgMain_ : menuBgSub_)
10070 .DrawFull (Rect (0 , 0 , GameResolution.x , GameResolution.y ));
101- // Draw UI overlay on top
102- CSurface::Draw (Surf_Display, Menu->getSurface (), 0 , 0 );
10371 }
10472 }
10573
106- // render windows ordered by priority
74+ // ---- 2. Render map (software) and draw via GL ----
75+ // Map renders directly to its own Surf_Map; we upload that to GL.
76+ // Text overlays are written onto Surf_Map before upload.
77+ const bool mapActive = (MapObj && MapObj->isActive ());
78+ if (mapActive)
79+ {
80+ auto * mapSurf = MapObj->getSurface ();
81+ if (mapSurf)
82+ {
83+ // Write text overlays directly onto the map surface
84+ std::array<char , 100 > textBuffer;
85+ std::snprintf (textBuffer.data (), textBuffer.size (), " %d %d" , MapObj->getVertexX (), MapObj->getVertexY ());
86+ CFont::writeText (mapSurf, textBuffer.data (), 20 , 20 );
87+ std::snprintf (textBuffer.data (), textBuffer.size (),
88+ " min. height: %#04x/0x3C max. height: %#04x/0x3C NormalNull: 0x0A" ,
89+ MapObj->getMinReduceHeight (), MapObj->getMaxRaiseHeight ());
90+ CFont::writeText (mapSurf, textBuffer.data (), 100 , 20 );
91+ if (MapObj->isHorizontalMovementLocked () && MapObj->isVerticalMovementLocked ())
92+ CFont::writeText (mapSurf, " Movement locked (F9 or F10 to unlock)" , 20 , 40 , FontSize::Large,
93+ FontColor::Orange);
94+ else if (MapObj->isHorizontalMovementLocked ())
95+ CFont::writeText (mapSurf, " Horizontal movement locked (F9 to unlock)" , 20 , 40 , FontSize::Large,
96+ FontColor::Orange);
97+ else if (MapObj->isVerticalMovementLocked ())
98+ CFont::writeText (mapSurf, " Vertical movement locked (F10 to unlock)" , 20 , 40 , FontSize::Large,
99+ FontColor::Orange);
100+
101+ // Upload map surface — handles 8-bit paletted (classic) and 32-bit
102+ mapTex_.load (mapSurf);
103+ mapTex_.DrawFull (Rect (0 , 0 , GameResolution.x , GameResolution.y ));
104+ }
105+ }
106+
107+ // ---- 3. Draw UI controls via OpenGL ----
108+ for (auto & Menu : Menus)
109+ {
110+ if (Menu->isActive ())
111+ Menu->renderGL (0 , 0 );
112+ }
113+
114+ // render windows ordered by priority, lowest first
107115 int highestPriority = 0 ;
108- // first find the highest priority
109116 for (auto & Window : Windows)
110117 {
111118 if (Window->getPriority () > highestPriority)
112119 highestPriority = Window->getPriority ();
113120 }
114- // render from lowest priority to highest
115121 for (int actualPriority = 0 ; actualPriority <= highestPriority; actualPriority++)
116122 {
117123 for (auto & Window : Windows)
118124 {
119125 if (Window->getPriority () == actualPriority)
120- CSurface::Draw (Surf_Display, Window->getSurface (), Window->getX (), Window->getY ());
126+ Window->renderGL ( Window->getX (), Window->getY ());
121127 }
122128 }
123129
124- // Cursor is drawn in RenderPresent via GL (after the Surf_Display overlay)
125-
126- #ifdef _ADMINMODE
127- FrameCounter++;
128- #endif
129-
130+ // ---- 4. Draw FPS counter via GL ----
130131 ++framesPassedSinceLastFps;
131-
132132 const auto curTicks = SDL_GetTicks ();
133133 const auto diffTicks = curTicks - lastFpsTick;
134134 if (diffTicks > 1000 )
@@ -137,9 +137,36 @@ void CGame::Render()
137137 framesPassedSinceLastFps = 0 ;
138138 lastFpsTick = curTicks;
139139 }
140- CSurface::Draw (Surf_Display, lastFps.getSurface (), 0 , 0 );
140+ {
141+ auto * fpsSurf = lastFps.getSurface ();
142+ if (fpsSurf)
143+ {
144+ fpsTex_.load (fpsSurf);
145+ glBindTexture (GL_TEXTURE_2D , fpsTex_.getHandle ());
146+ glBegin (GL_QUADS );
147+ glTexCoord2f (0 , 0 );
148+ glVertex2i (0 , 0 );
149+ glTexCoord2f (1 , 0 );
150+ glVertex2i (fpsSurf->w , 0 );
151+ glTexCoord2f (1 , 1 );
152+ glVertex2i (fpsSurf->w , fpsSurf->h );
153+ glTexCoord2f (0 , 1 );
154+ glVertex2i (0 , fpsSurf->h );
155+ glEnd ();
156+ }
157+ }
141158
142- RenderPresent ();
159+ // ---- 5. Cursor on top of everything ----
160+ {
161+ const auto & cursorImg = Cursor.clicked ? (Cursor.button .right ? cross_ : cursorClicked_) : cursor_;
162+ cursorImg.Draw (Cursor.pos .x , Cursor.pos .y );
163+ }
164+
165+ SDL_GL_SwapWindow (window_.get ());
166+
167+ #ifdef _ADMINMODE
168+ FrameCounter++;
169+ #endif
143170
144171 if (msWait)
145172 SDL_Delay (msWait);
0 commit comments