DEADSOFTWARE

build: move dependency check to modules where they used
[d2df-sdl.git] / src / flexui / sdlstandalone.pas
1 (* Copyright (C) Doom 2D: Forever Developers
2 *
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, version 3 of the License ONLY.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 *)
15 {$INCLUDE ../shared/a_modes.inc}
16 unit sdlstandalone;
18 {$IFNDEF USE_SDL2}
19 {$FATAL SDL2 required for flexui sdlstandalone}
20 {$ENDIF}
22 interface
24 uses
25 SDL2,
26 sdlcarcass;
29 // ////////////////////////////////////////////////////////////////////////// //
30 // initialize OpenGL; set `gScreenWidth` and `gScreenHeight` before calling this
31 function glInit (const winTitle: AnsiString='SDL TEST'): Boolean;
32 procedure glDeinit ();
33 // call this to show built frame
34 procedure glSwap ();
35 // call this to push "quit" event into queue
36 procedure pushQuitEvent ();
37 // call this to process queued messages; result is `true` if quit event was received
38 function processMessages (): Boolean;
40 // run main loop, call `buildFrameCB()` and `renderFrameCB()`, maintain the given FPS
41 procedure mainLoop ();
44 implementation
46 uses
47 SysUtils;
50 var
51 gWinH: PSDL_Window = nil;
52 gGLContext: TSDL_GLContext = nil;
53 lastFrameTime: UInt64 = 0;
56 // ////////////////////////////////////////////////////////////////////////// //
57 procedure onExposeFrame ();
58 begin
59 glSwap();
60 end;
63 // ////////////////////////////////////////////////////////////////////////// //
64 function sdlInit (): Boolean;
65 var
66 sdlflags: LongWord;
67 begin
68 result := false;
70 sdlflags := SDL_INIT_TIMER or SDL_INIT_VIDEO;
71 if SDL_Init(sdlflags) < 0 then exit; //raise Exception.Create('SDL: Init failed: ' + SDL_GetError());
73 //SDL_Quit();
74 result := true;
75 fuiWinActive := fuiWinActive;
76 SDL_StartTextInput();
77 end;
80 procedure glSwap ();
81 begin
82 if (gWinH = nil) then exit;
83 SDL_GL_SwapWindow(gWinH);
84 end;
87 procedure killGLWindow ();
88 begin
89 if (gWinH <> nil) then SDL_DestroyWindow(gWinH);
90 if (gGLContext <> nil) then SDL_GL_DeleteContext(gGLContext);
91 gWinH := nil;
92 gGLContext := nil;
93 end;
96 procedure pushQuitEvent ();
97 var
98 ev: TSDL_Event;
99 begin
100 ev.type_ := SDL_QUITEV;
101 SDL_PushEvent(@ev);
102 end;
105 // ////////////////////////////////////////////////////////////////////////// //
106 // true: quit
107 function processMessages (): Boolean;
108 var
109 ev: TSDL_Event;
110 begin
111 result := false;
112 FillChar(ev, sizeof(ev), 0);
113 while (SDL_PollEvent(@ev) > 0) do
114 begin
115 fuiOnSDLEvent(ev);
116 //if (ev.type_ = SDL_QUITEV) then exit;
117 end;
118 if fuiQuitReceived then result := true;
119 end;
122 // ////////////////////////////////////////////////////////////////////////// //
123 procedure glDeinit ();
124 begin
125 if (gWinH <> nil) and assigned(oglDeinitCB) then oglDeinitCB();
126 killGLWindow();
127 end;
130 function glInit (const winTitle: AnsiString='SDL TEST'): Boolean;
131 var
132 wFlags: LongWord = 0;
133 v: Byte = 0;
134 begin
135 result := false;
137 wFlags := SDL_WINDOW_OPENGL or SDL_WINDOW_RESIZABLE;
138 //if gFullscreen then wFlags := wFlags or SDL_WINDOW_FULLSCREEN;
139 //if gWinMaximized then wFlags := wFlags or SDL_WINDOW_MAXIMIZED;
141 glDeinit();
143 //if VSync then v := 1 else v := 0;
144 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
145 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
146 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
147 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
148 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
149 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
150 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
151 SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 1); // lights; it is enough to have 1-bit stencil buffer for lighting
152 SDL_GL_SetSwapInterval(v);
155 if gFullscreen then
156 begin
157 mode.w := gScreenWidth;
158 mode.h := gScreenHeight;
159 mode.format := 0;
160 mode.refresh_rate := 0;
161 mode.driverdata := nil;
162 if SDL_GetClosestDisplayMode(0, @mode, @cmode) = nil then
163 begin
164 gScreenWidth := 800;
165 gScreenHeight := 600;
166 end
167 else
168 begin
169 gScreenWidth := cmode.w;
170 gScreenHeight := cmode.h;
171 end;
172 end;
175 gWinH := SDL_CreateWindow(PAnsiChar(winTitle), -1, -1, fuiScrWdt, fuiScrHgt, wFlags);
176 if (gWinH = nil) then exit;
178 gGLContext := SDL_GL_CreateContext(gWinH);
179 if (gGLContext = nil) then begin SDL_DestroyWindow(gWinH); gWinH := nil; exit; end;
181 SDL_GL_MakeCurrent(gWinH, gGLContext);
182 SDL_ShowCursor(SDL_DISABLE);
184 if assigned(oglInitCB) then oglInitCB();
186 result := true;
187 end;
190 // run main loop, call `buildFrameCB()` and `renderFrameCB()`, maintain the given FPS
191 procedure mainLoop ();
192 var
193 nft, ctt: UInt64;
194 wt: Integer;
195 begin
196 if assigned(buildFrameCB) then buildFrameCB();
197 if assigned(prerenderFrameCB) then prerenderFrameCB();
198 if assigned(renderFrameCB) then renderFrameCB();
199 if assigned(postrenderFrameCB) then postrenderFrameCB();
200 glSwap();
201 lastFrameTime := fuiTimeMilli();
202 while true do
203 begin
204 // calculate time to build and render next frame
205 nft := lastFrameTime+(1000 div fuiFPS);
206 ctt := fuiTimeMilli();
207 if (ctt >= nft) then
208 begin
209 // time to build next frame
210 if assigned(buildFrameCB) then buildFrameCB();
211 if assigned(prerenderFrameCB) then prerenderFrameCB();
212 if assigned(renderFrameCB) then renderFrameCB();
213 if assigned(postrenderFrameCB) then postrenderFrameCB();
214 glSwap();
215 lastFrameTime := ctt; // ignore frame processing time
216 end
217 else
218 begin
219 // has to wait for some time
220 if (nft-ctt > 1000) then wt := 1000 else wt := Integer(nft-ctt);
221 SDL_WaitEventTimeout(nil, wt);
222 end;
223 if processMessages() then break; // just in case
224 end;
225 end;
228 initialization
229 exposeFrameCB := onExposeFrame();
231 if not sdlInit() then raise Exception.Create('cannot initialize SDL');
232 finalization
233 glDeinit();
234 SDL_Quit();
235 end.