1 (* Copyright (C) Doom 2D: Forever Developers
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 {$INCLUDE ../shared/a_modes.inc}
26 // ////////////////////////////////////////////////////////////////////////// //
27 // initialize OpenGL; set `gScreenWidth` and `gScreenHeight` before calling this
28 function glInit (const winTitle
: AnsiString='SDL TEST'): Boolean;
29 procedure glDeinit ();
30 // call this to show built frame
32 // call this to push "quit" event into queue
33 procedure pushQuitEvent ();
34 // call this to process queued messages; result is `true` if quit event was received
35 function processMessages (): Boolean;
37 // run main loop, call `buildFrameCB()` and `renderFrameCB()`, maintain the given FPS
38 procedure mainLoop ();
48 gWinH
: PSDL_Window
= nil;
49 gGLContext
: TSDL_GLContext
= nil;
50 lastFrameTime
: UInt64 = 0;
53 // ////////////////////////////////////////////////////////////////////////// //
54 procedure onExposeFrame ();
60 // ////////////////////////////////////////////////////////////////////////// //
61 function sdlInit (): Boolean;
67 sdlflags
:= SDL_INIT_TIMER
or SDL_INIT_VIDEO
;
68 if SDL_Init(sdlflags
) < 0 then exit
; //raise Exception.Create('SDL: Init failed: ' + SDL_GetError());
72 fuiWinActive
:= fuiWinActive
;
79 if (gWinH
= nil) then exit
;
80 SDL_GL_SwapWindow(gWinH
);
84 procedure killGLWindow ();
86 if (gWinH
<> nil) then SDL_DestroyWindow(gWinH
);
87 if (gGLContext
<> nil) then SDL_GL_DeleteContext(gGLContext
);
93 procedure pushQuitEvent ();
97 ev
.type_
:= SDL_QUITEV
;
102 // ////////////////////////////////////////////////////////////////////////// //
104 function processMessages (): Boolean;
109 FillChar(ev
, sizeof(ev
), 0);
110 while (SDL_PollEvent(@ev
) > 0) do
113 //if (ev.type_ = SDL_QUITEV) then exit;
115 if fuiQuitReceived
then result
:= true;
119 // ////////////////////////////////////////////////////////////////////////// //
120 procedure glDeinit ();
122 if (gWinH
<> nil) and assigned(oglDeinitCB
) then oglDeinitCB();
127 function glInit (const winTitle
: AnsiString='SDL TEST'): Boolean;
129 wFlags
: LongWord = 0;
134 wFlags
:= SDL_WINDOW_OPENGL
or SDL_WINDOW_RESIZABLE
;
135 //if gFullscreen then wFlags := wFlags or SDL_WINDOW_FULLSCREEN;
136 //if gWinMaximized then wFlags := wFlags or SDL_WINDOW_MAXIMIZED;
140 //if VSync then v := 1 else v := 0;
141 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION
, 2);
142 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION
, 1);
143 SDL_GL_SetAttribute(SDL_GL_RED_SIZE
, 8);
144 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE
, 8);
145 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE
, 8);
146 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE
, 16);
147 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER
, 1);
148 SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE
, 1); // lights; it is enough to have 1-bit stencil buffer for lighting
149 SDL_GL_SetSwapInterval(v
);
154 mode.w := gScreenWidth;
155 mode.h := gScreenHeight;
157 mode.refresh_rate := 0;
158 mode.driverdata := nil;
159 if SDL_GetClosestDisplayMode(0, @mode, @cmode) = nil then
162 gScreenHeight := 600;
166 gScreenWidth := cmode.w;
167 gScreenHeight := cmode.h;
172 gWinH
:= SDL_CreateWindow(PAnsiChar(winTitle
), -1, -1, fuiScrWdt
, fuiScrHgt
, wFlags
);
173 if (gWinH
= nil) then exit
;
175 gGLContext
:= SDL_GL_CreateContext(gWinH
);
176 if (gGLContext
= nil) then begin SDL_DestroyWindow(gWinH
); gWinH
:= nil; exit
; end;
178 SDL_GL_MakeCurrent(gWinH
, gGLContext
);
179 SDL_ShowCursor(SDL_DISABLE
);
181 if assigned(oglInitCB
) then oglInitCB();
187 // run main loop, call `buildFrameCB()` and `renderFrameCB()`, maintain the given FPS
188 procedure mainLoop ();
193 if assigned(buildFrameCB
) then buildFrameCB();
194 if assigned(prerenderFrameCB
) then prerenderFrameCB();
195 if assigned(renderFrameCB
) then renderFrameCB();
196 if assigned(postrenderFrameCB
) then postrenderFrameCB();
198 lastFrameTime
:= fuiTimeMilli();
201 // calculate time to build and render next frame
202 nft
:= lastFrameTime
+(1000 div fuiFPS
);
203 ctt
:= fuiTimeMilli();
206 // time to build next frame
207 if assigned(buildFrameCB
) then buildFrameCB();
208 if assigned(prerenderFrameCB
) then prerenderFrameCB();
209 if assigned(renderFrameCB
) then renderFrameCB();
210 if assigned(postrenderFrameCB
) then postrenderFrameCB();
212 lastFrameTime
:= ctt
; // ignore frame processing time
216 // has to wait for some time
217 if (nft
-ctt
> 1000) then wt
:= 1000 else wt
:= Integer(nft
-ctt
);
218 SDL_WaitEventTimeout(nil, wt
);
220 if processMessages() then break
; // just in case
226 exposeFrameCB
:= onExposeFrame();
228 if not sdlInit() then raise Exception
.Create('cannot initialize SDL');