DEADSOFTWARE

5caa9c9e5788a94044266a26f7ea8e8d6b692d70
[d2df-sdl.git] / src / game / sdl / g_system.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 g_system;
18 interface
20 (* To fix:
21 * - Joystick support
22 *)
24 uses Utils;
26 (* --- Utils --- *)
27 function sys_GetTicks (): Int64;
28 procedure sys_Delay (ms: Integer);
30 (* --- Graphics --- *)
31 function sys_GetDispalyModes (bpp: Integer): SSArray;
32 function sys_SetDisplayMode (w, h, bpp: Integer; fullscreen: Boolean): Boolean;
33 procedure sys_EnableVSync (yes: Boolean);
34 procedure sys_Repaint;
36 (* --- Input --- *)
37 function sys_HandleInput (): Boolean;
38 procedure sys_RequestQuit;
40 (* --- Init --- *)
41 procedure sys_Init;
42 procedure sys_Final;
44 implementation
46 uses
47 SysUtils, SDL, GL,
48 e_log, e_graphics, e_input,
49 g_options, g_window, g_console, g_game, g_menu, g_gui, g_main;
51 var
52 userResize: Boolean;
53 modeResize: Integer;
54 screen: PSDL_Surface;
56 (* --------- Utils --------- *)
58 function sys_GetTicks (): Int64;
59 begin
60 Result := SDL_GetTicks()
61 end;
63 procedure sys_Delay (ms: Integer);
64 begin
65 SDL_Delay(ms)
66 end;
68 (* --------- Graphics --------- *)
70 procedure UpdateSize (w, h: Integer);
71 begin
72 gWinSizeX := w;
73 gWinSizeY := h;
74 gWinRealPosX := 0;
75 gWinRealPosY := 0;
76 gScreenWidth := w;
77 gScreenHeight := h;
78 {$IFDEF ENABLE_HOLMES}
79 fuiScrWdt := w;
80 fuiScrHgt := h;
81 {$ENDIF}
82 e_ResizeWindow(w, h);
83 e_InitGL;
84 g_Game_SetupScreenSize;
85 g_Menu_Reset;
86 g_Game_ClearLoading;
87 end;
89 function InitWindow (w, h, bpp: Integer; fullScreen: Boolean): Boolean;
90 var flags: Uint32;
91 begin
92 e_LogWritefln('InitWindow %s %s %s %s', [w, h, bpp, fullscreen]);
93 Result := False;
94 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
95 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
96 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
97 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
98 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
99 SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); // lights; it is enough to have 1-bit stencil buffer for lighting, but...
100 flags := SDL_OPENGL;
101 if fullScreen then flags := flags or SDL_FULLSCREEN;
102 if userResize then flags := flags or SDL_VIDEORESIZE;
103 if (screen = nil) or (SDL_VideoModeOk(w, h, bpp, flags) <> 0) then
104 begin
105 SDL_FreeSurface(screen);
106 screen := SDL_SetVideoMode(w, h, bpp, flags);
107 if screen <> nil then
108 begin
109 SDL_WM_SetCaption('Doom 2D: Forever (SDL 1.2)', nil);
110 UpdateSize(w, h);
111 Result := True
112 end
113 end
114 else
115 begin
116 e_LogWritefln('SDL: video mode not supported', [])
117 end
118 end;
120 procedure sys_Repaint;
121 begin
122 SDL_GL_SwapBuffers
123 end;
125 procedure sys_EnableVSync (yes: Boolean);
126 begin
127 (* ??? *)
128 end;
130 function sys_GetDispalyModes (bpp: Integer): SSArray;
131 var m: PPSDL_Rect; f: TSDL_PixelFormat; i, count: Integer;
132 begin
133 SetLength(result, 0);
134 FillChar(f, sizeof(f), 0);
135 f.palette := nil;
136 f.BitsPerPixel := bpp;
137 f.BytesPerPixel := (bpp + 7) div 8;
138 m := SDL_ListModes(@f, SDL_OPENGL or SDL_FULLSCREEN);
139 if (m <> NIL) and (IntPtr(m) <> -1) then
140 begin
141 count := 0;
142 while m[count] <> nil do inc(count);
143 SetLength(result, count);
144 for i := 0 to count - 1 do
145 result[i] := IntToStr(m[i].w) + 'x' + IntToStr(m[i].h);
146 end
147 end;
149 function sys_SetDisplayMode (w, h, bpp: Integer; fullscreen: Boolean): Boolean;
150 begin
151 result := InitWindow(w, h, bpp, fullscreen)
152 end;
154 (* --------- Input --------- *)
156 function Key2Stub (key: Integer): Integer;
157 var x: Integer;
158 begin
159 case key of
160 SDLK_ESCAPE: x := IK_ESCAPE;
161 SDLK_RETURN: x := IK_RETURN;
162 SDLK_KP_ENTER: x := IK_KPRETURN;
163 SDLK_KP0: x := IK_KPINSERT;
164 SDLK_UP: x := IK_UP;
165 SDLK_KP8: x := IK_KPUP;
166 SDLK_DOWN: x := IK_DOWN;
167 SDLK_KP2: x := IK_KPDOWN;
168 SDLK_LEFT: x := IK_LEFT;
169 SDLK_KP4: x := IK_KPLEFT;
170 SDLK_RIGHT: x := IK_RIGHT;
171 SDLK_KP6: x := IK_KPRIGHT;
172 SDLK_DELETE: x := IK_DELETE;
173 SDLK_HOME: x := IK_HOME;
174 SDLK_KP7: x := IK_KPHOME;
175 SDLK_INSERT: x := IK_INSERT;
176 SDLK_SPACE: x := IK_SPACE;
177 SDLK_LSHIFT: x := IK_SHIFT;
178 SDLK_LALT: x := IK_ALT;
179 SDLK_TAB: x := IK_TAB;
180 SDLK_PAGEUP: x := IK_PAGEUP;
181 SDLK_KP9: x := IK_KPPAGEUP;
182 SDLK_PAGEDOWN: x := IK_PAGEDN;
183 SDLK_KP3: x := IK_KPPAGEDN;
184 SDLK_KP5: x := IK_KP5;
185 SDLK_NUMLOCK: x := IK_NUMLOCK;
186 SDLK_KP_DIVIDE: x := IK_KPDIVIDE;
187 SDLK_KP_MULTIPLY: x := IK_KPMULTIPLE;
188 SDLK_KP_MINUS: x := IK_KPMINUS;
189 SDLK_KP_PLUS: x := IK_KPPLUS;
190 SDLK_KP_PERIOD: x := IK_KPDOT;
191 SDLK_CAPSLOCK: x := IK_CAPSLOCK;
192 SDLK_RSHIFT: x := IK_RSHIFT;
193 SDLK_LCTRL: x := IK_CTRL;
194 SDLK_RCTRL: x := IK_RCTRL;
195 SDLK_RALT: x := IK_RALT;
196 SDLK_LSUPER: x := IK_WIN;
197 SDLK_RSUPER: x := IK_RWIN;
198 SDLK_MENU: x := IK_MENU;
199 SDLK_PRINT: x := IK_PRINTSCR;
200 SDLK_SCROLLOCK: x := IK_SCROLLLOCK;
201 SDLK_LEFTBRACKET: x := IK_LBRACKET;
202 SDLK_RIGHTBRACKET: x := IK_RBRACKET;
203 SDLK_SEMICOLON: x := IK_SEMICOLON;
204 SDLK_QUOTE: x := IK_QUOTE;
205 SDLK_BACKSLASH: x := IK_BACKSLASH;
206 SDLK_SLASH: x := IK_SLASH;
207 SDLK_COMMA: x := IK_COMMA;
208 SDLK_PERIOD: x := IK_DOT;
209 SDLK_EQUALS: x := IK_EQUALS;
210 SDLK_0: x := IK_0;
211 SDLK_1: x := IK_1;
212 SDLK_2: x := IK_2;
213 SDLK_3: x := IK_3;
214 SDLK_4: x := IK_4;
215 SDLK_5: x := IK_5;
216 SDLK_6: x := IK_6;
217 SDLK_7: x := IK_7;
218 SDLK_8: x := IK_8;
219 SDLK_9: x := IK_9;
220 SDLK_F1: x := IK_F1;
221 SDLK_F2: x := IK_F2;
222 SDLK_F3: x := IK_F3;
223 SDLK_F4: x := IK_F4;
224 SDLK_F5: x := IK_F5;
225 SDLK_F6: x := IK_F6;
226 SDLK_F7: x := IK_F7;
227 SDLK_F8: x := IK_F8;
228 SDLK_F9: x := IK_F9;
229 SDLK_F10: x := IK_F10;
230 SDLK_F11: x := IK_F11;
231 SDLK_F12: x := IK_F12;
232 SDLK_END: x := IK_END;
233 SDLK_KP1: x := IK_KPEND;
234 SDLK_BACKSPACE: x := IK_BACKSPACE;
235 SDLK_BACKQUOTE: x := IK_BACKQUOTE;
236 SDLK_PAUSE: x := IK_PAUSE;
237 SDLK_A..SDLK_Z: x := IK_A + (key - SDLK_A);
238 SDLK_MINUS: x := IK_MINUS;
239 SDLK_RMETA: x := IK_RMETA;
240 SDLK_LMETA: x := IK_LMETA;
241 else
242 x := IK_INVALID
243 end;
244 result := x
245 end;
247 procedure HandleKeyboard (var ev: TSDL_KeyboardEvent);
248 var down, repeated: Boolean; key: Integer; ch: Char;
249 begin
250 key := Key2Stub(ev.keysym.sym);
251 down := (ev.type_ = SDL_KEYDOWN);
252 repeated := down and e_KeyPressed(key);
253 ch := wchar2win(WideChar(ev.keysym.unicode));
254 if g_dbg_input then
255 e_LogWritefln('Input Debug: keysym, down=%s, sym=%s, state=%s, unicode=%s, stubsym=%s, cp1251=%s', [down, ev.keysym.sym, ev.state, ev.keysym.unicode, key, Ord(ch)]);
256 if not repeated then
257 begin
258 e_KeyUpDown(key, down);
259 g_Console_ProcessBind(key, down);
260 end
261 else if gConsoleShow or gChatShow or (g_ActiveWindow <> nil) then
262 begin
263 KeyPress(key)
264 end;
265 if down and IsValid1251(ev.keysym.unicode) and IsPrintable1251(ch) then
266 CharPress(ch)
267 end;
269 function sys_HandleInput (): Boolean;
270 var ev: TSDL_Event;
271 begin
272 result := false;
273 while SDL_PollEvent(@ev) <> 0 do
274 begin
275 case ev.type_ of
276 SDL_QUITEV: result := true;
277 SDL_VIDEORESIZE:
278 begin
279 if g_dbg_input then
280 e_LogWritefln('Input Debug: SDL_VIDEORESIZE %s %s', [ev.resize.w, ev.resize.h]);
281 if modeResize = 1 then
282 UpdateSize(ev.resize.w, ev.resize.h)
283 else if modeResize > 1 then
284 InitWindow(ev.resize.w, ev.resize.h, gBPP, gFullscreen)
285 end;
286 SDL_KEYUP, SDL_KEYDOWN: HandleKeyboard(ev.key);
287 end
288 end
289 end;
291 procedure sys_RequestQuit;
292 var ev: TSDL_Event;
293 begin
294 ev.quit.type_ := SDL_QUITEV;
295 SDL_PushEvent(@ev)
296 end;
298 (* --------- Init --------- *)
300 procedure sys_Init;
301 var flags: Uint32; ok: Boolean;
302 begin
303 flags := SDL_INIT_VIDEO or SDL_INIT_AUDIO or
304 SDL_INIT_TIMER or SDL_INIT_JOYSTICK
305 (*or SDL_INIT_NOPARACHUTE*);
306 if SDL_Init(flags) <> 0 then
307 raise Exception.Create('SDL: Init failed: ' + SDL_GetError());
308 ok := InitWindow(gScreenWidth, gScreenHeight, gBPP, gFullScreen);
309 if not ok then
310 raise Exception.Create('SDL: failed to set videomode: ' + SDL_GetError);
311 SDL_EnableUNICODE(1);
312 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
313 end;
315 procedure sys_Final;
316 begin
317 e_WriteLog('Releasing SDL', TMsgType.Notify);
318 SDL_FreeSurface(screen);
319 SDL_Quit
320 end;
322 initialization
323 (* window resize are broken both on linux and osx, so disabled by default *)
324 conRegVar('sdl_allow_resize', @userResize, 'allow to resize window by user', 'allow to resize window by user');
325 conRegVar('sdl_resize_action', @modeResize, 'set window resize mode (0: ignore, 1: change, 2: reset)', '');
326 userResize := false;
327 modeResize := 0;
328 end.