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}
25 // ////////////////////////////////////////////////////////////////////////// //
26 // call this with SDL2 event; returns `true` if event was eaten
27 function fuiOnSDLEvent (var ev
: TSDL_Event
): Boolean;
30 // ////////////////////////////////////////////////////////////////////////// //
33 winFocusCB
: procedure () = nil; // this will be called when window got focus; `fuiWinActive` already set
34 winBlurCB
: procedure () = nil; // this will be called when window lost focus; `fuiWinActive` already set
36 buildFrameCB
: procedure () = nil; // don't do any rendering here, do it in `renderFrameCB()`
37 renderFrameCB
: procedure () = nil; // no need to call `glSwap()` here
38 exposeFrameCB
: procedure () = nil; // call `glSwap()` here instead; automatically set by standalone
40 prerenderFrameCB
: procedure () = nil;
41 postrenderFrameCB
: procedure () = nil;
42 fuiResizeCB
: procedure () = nil; // `fuiScrWdt` and `fuiScrHgt` are already set
43 oglInitCB
: procedure () = nil; // `fuiScrWdt` and `fuiScrHgt` are already set
44 oglDeinitCB
: procedure () = nil;
49 fuiScrWdt
: Integer = 1024;
50 fuiScrHgt
: Integer = 768;
51 fuiWinActive
: Boolean = false;
52 fuiQuitReceived
: Boolean = false;
55 // ////////////////////////////////////////////////////////////////////////// //
56 function fuiTimeMicro (): UInt64; inline;
57 function fuiTimeMilli (): UInt64; inline;
60 // ////////////////////////////////////////////////////////////////////////// //
61 // only for standalone mode
62 function getFUIFPS (): Integer; inline;
63 procedure setFUIFPS (v
: Integer); inline;
65 property fuiFPS
: Integer read getFUIFPS write setFUIFPS
; // default: 30
75 {$ELSEIF DEFINED(WINDOWS)}
83 // ////////////////////////////////////////////////////////////////////////// //
85 gEffFPS
: Integer = 30;
87 function getFUIFPS (): Integer; inline; begin result
:= gEffFPS
; end;
88 procedure setFUIFPS (v
: Integer); inline; begin if (v
< 1) then v
:= 1 else if (v
> 60*4) then v
:= 60*4; gEffFPS
:= v
; end;
91 // ////////////////////////////////////////////////////////////////////////// //
93 type THPTimeType
= TTimeSpec
;
95 type THPTimeType
= Int64;
99 mFrequency
: Int64 = 0;
100 mHasHPTimer
: Boolean = false;
102 procedure initTimerIntr ();
106 if (mFrequency
= 0) then
109 if (clock_getres(CLOCK_MONOTONIC
, @r
) <> 0) then raise Exception
.Create('profiler error: cannot get timer resolution');
110 mHasHPTimer
:= (r
.tv_nsec
<> 0);
111 if not mHasHPTimer
then raise Exception
.Create('profiler error: hires timer is not available');
112 mFrequency
:= 1; // just a flag
113 if (r
.tv_nsec
<> 0) then mFrequency
:= 1000000000000000000 div r
.tv_nsec
;
115 mHasHPTimer
:= QueryPerformanceFrequency(r
);
116 if not mHasHPTimer
then raise Exception
.Create('profiler error: hires timer is not available');
123 function fuiTimeMicro (): UInt64; inline;
127 //if (mFrequency = 0) then initTimerIntr();
129 clock_gettime(CLOCK_MONOTONIC
, @r
);
130 result
:= UInt64(r
.tv_sec
)*1000000+UInt64(r
.tv_nsec
) div 1000; // microseconds
132 QueryPerformanceCounter(r
);
133 result
:= UInt64(r
)*1000000 div mFrequency
;
138 function fuiTimeMilli (): UInt64; inline;
140 result
:= fuiTimeMicro() div 1000;
144 // ////////////////////////////////////////////////////////////////////////// //
145 function fuiOnSDLEvent (var ev
: TSDL_Event
): Boolean;
150 function buildBut (b
: Byte): Word;
154 SDL_BUTTON_LEFT
: result
:= result
or THMouseEvent
.Left
;
155 SDL_BUTTON_MIDDLE
: result
:= result
or THMouseEvent
.Middle
;
156 SDL_BUTTON_RIGHT
: result
:= result
or THMouseEvent
.Right
;
160 procedure windowEventHandler (constref ev
: TSDL_WindowEvent
);
163 SDL_WINDOWEVENT_MINIMIZED
: if fuiWinActive
then begin fuiResetKMState(true); fuiWinActive
:= false; if assigned(winBlurCB
) then winBlurCB(); end;
164 SDL_WINDOWEVENT_RESIZED
, SDL_WINDOWEVENT_SIZE_CHANGED
:
166 if (ev
.data1
<> fuiScrWdt
) or (ev
.data2
<> fuiScrHgt
) then
168 fuiScrWdt
:= ev
.data1
;
169 fuiScrHgt
:= ev
.data2
;
170 if assigned(fuiResizeCB
) then fuiResizeCB();
173 SDL_WINDOWEVENT_EXPOSED
: if assigned(exposeFrameCB
) then exposeFrameCB();
174 SDL_WINDOWEVENT_FOCUS_GAINED
: if not fuiWinActive
then begin fuiWinActive
:= true; if assigned(winFocusCB
) then winFocusCB(); end;
175 SDL_WINDOWEVENT_FOCUS_LOST
: if fuiWinActive
then begin fuiResetKMState(true); fuiWinActive
:= false; if assigned(winBlurCB
) then winBlurCB(); end;
183 SDL_WINDOWEVENT
: windowEventHandler(ev
.window
);
184 SDL_QUITEV
: fuiQuitReceived
:= true;
186 SDL_KEYDOWN
, SDL_KEYUP
:
188 // fix left/right modifiers
189 FillChar(kev
, sizeof(kev
), 0);
191 if (ev
.type_
= SDL_KEYDOWN
) then kev
.kind
:= THKeyEvent
.TKind
.Press
else kev
.kind
:= THKeyEvent
.TKind
.Release
;
192 kev
.scan
:= ev
.key
.keysym
.scancode
;
193 //kev.sym := ev.key.keysym.sym;
195 if (kev
.scan
= SDL_SCANCODE_RCTRL
) then kev
.scan
:= SDL_SCANCODE_LCTRL
;
196 if (kev
.scan
= SDL_SCANCODE_RALT
) then kev
.scan
:= SDL_SCANCODE_LALT
;
197 if (kev
.scan
= SDL_SCANCODE_RSHIFT
) then kev
.scan
:= SDL_SCANCODE_LSHIFT
;
198 if (kev
.scan
= SDL_SCANCODE_RGUI
) then kev
.scan
:= SDL_SCANCODE_LGUI
;
201 if (kev.sym = SDLK_RCTRL) then kev.sym := SDLK_LCTRL;
202 if (kev.sym = SDLK_RALT) then kev.sym := SDLK_LALT;
203 if (kev.sym = SDLK_RSHIFT) then kev.sym := SDLK_LSHIFT;
204 if (kev.sym = SDLK_RGUI) then kev.sym := SDLK_LGUI;
209 kev
.bstate
:= fuiButState
;
210 kev
.kstate
:= fuiModState
;
213 SDL_SCANCODE_LCTRL
: if (kev
.press
) then fuiSetModState(fuiModState
or THKeyEvent
.ModCtrl
) else fuiSetModState(fuiModState
and (not THKeyEvent
.ModCtrl
));
214 SDL_SCANCODE_LALT
: if (kev
.press
) then fuiSetModState(fuiModState
or THKeyEvent
.ModAlt
) else fuiSetModState(fuiModState
and (not THKeyEvent
.ModAlt
));
215 SDL_SCANCODE_LSHIFT
: if (kev
.press
) then fuiSetModState(fuiModState
or THKeyEvent
.ModShift
) else fuiSetModState(fuiModState
and (not THKeyEvent
.ModShift
));
218 if assigned(evKeyCB
) then
225 SDL_MOUSEBUTTONDOWN
, SDL_MOUSEBUTTONUP
:
227 FillChar(mev
, sizeof(mev
), 0);
229 if (ev
.type_
= SDL_MOUSEBUTTONDOWN
) then mev
.kind
:= THMouseEvent
.TKind
.Press
else mev
.kind
:= THMouseEvent
.TKind
.Release
;
230 mev
.dx
:= ev
.button
.x
-fuiMouseX
;
231 mev
.dy
:= ev
.button
.y
-fuiMouseY
;
232 fuiSetMouseX(ev
.button
.x
);
233 fuiSetMouseY(ev
.button
.y
);
234 mev
.but
:= buildBut(ev
.button
.button
);
237 mev
.bstate
:= fuiButState
;
238 mev
.kstate
:= fuiModState
;
239 if (mev
.but
<> 0) then
241 // ev.button.clicks: Byte
242 if (ev
.type_
= SDL_MOUSEBUTTONDOWN
) then fuiSetButState(fuiButState
or mev
.but
) else fuiSetButState(fuiButState
and (not mev
.but
));
243 if assigned(evMouseCB
) then
252 if (ev
.wheel
.y
<> 0) then
254 FillChar(mev
, sizeof(mev
), 0);
256 mev
.kind
:= THMouseEvent
.TKind
.Press
;
258 mev
.dy
:= ev
.wheel
.y
;
259 if (ev
.wheel
.y
< 0) then mev
.but
:= THMouseEvent
.WheelUp
else mev
.but
:= THMouseEvent
.WheelDown
;
262 mev
.bstate
:= fuiButState
;
263 mev
.kstate
:= fuiModState
;
264 if assigned(evMouseCB
) then
273 FillChar(mev
, sizeof(mev
), 0);
275 mev
.kind
:= THMouseEvent
.TKind
.Motion
;
276 mev
.dx
:= ev
.button
.x
-fuiMouseX
;
277 mev
.dy
:= ev
.button
.y
-fuiMouseY
;
278 fuiSetMouseX(ev
.button
.x
);
279 fuiSetMouseY(ev
.button
.y
);
283 mev
.bstate
:= fuiButState
;
284 mev
.kstate
:= fuiModState
;
285 if assigned(evMouseCB
) then
295 Utf8ToUnicode(@uc, PChar(ev.text.text), 1);
297 if (keychr > 127) then keychr := Word(wchar2win(WideChar(keychr)));
298 CharPress(AnsiChar(keychr));
307 fuiWinActive
:= fuiWinActive
;
308 fuiScrWdt
:= fuiScrWdt
;
309 fuiScrHgt
:= fuiScrHgt
;