DEADSOFTWARE

moved to SDL2
[d2df-sdl.git] / src / game / g_window.pas
1 unit g_window;
3 interface
5 uses
6 WADEDITOR;
8 function SDLMain(): Integer;
9 function GetTimer(): Int64;
10 procedure ResetTimer();
11 function CreateGLWindow(Title: PChar): Boolean;
12 procedure KillGLWindow();
13 procedure PushExitEvent();
14 function ProcessMessage(): Boolean;
15 procedure ProcessLoading();
16 procedure ReDrawWindow();
17 procedure SwapBuffers();
18 procedure Sleep(ms: LongWord);
19 function GetDisplayModes(dBPP: DWORD; var SelRes: DWORD): SArray;
20 function g_Window_SetDisplay(PreserveGL: Boolean = False): Boolean;
21 function g_Window_SetSize(W, H: Word; FScreen: Boolean): Boolean;
23 implementation
25 uses
26 SDL2, GL, GLExt, e_graphics, e_log, g_main,
27 g_console, SysUtils, e_input, g_options, g_game,
28 g_basic, g_textures, e_sound, g_sound, g_menu, ENet, g_net;
30 var
31 h_Wnd: PSDL_Window;
32 h_GL: TSDL_GLContext;
33 wFlags: LongWord = 0;
34 Time, Time_Delta, Time_Old: Int64;
35 flag: Boolean;
36 wTitle: PChar = nil;
37 wNeedTimeReset: Boolean = False;
38 wWindowCreated: Boolean = False;
39 //wCursorShown: Boolean = False;
40 wMinimized: Boolean = False;
41 //wNeedFree: Boolean = True;
42 wLoadingProgress: Boolean = False;
43 wLoadingQuit: Boolean = False;
44 {wWinPause: Byte = 0;}
46 const
47 // TODO: move this to a separate file
48 CP1251: array [0..127] of Word = (
49 $0402,$0403,$201A,$0453,$201E,$2026,$2020,$2021,$20AC,$2030,$0409,$2039,$040A,$040C,$040B,$040F,
50 $0452,$2018,$2019,$201C,$201D,$2022,$2013,$2014,$003F,$2122,$0459,$203A,$045A,$045C,$045B,$045F,
51 $00A0,$040E,$045E,$0408,$00A4,$0490,$00A6,$00A7,$0401,$00A9,$0404,$00AB,$00AC,$00AD,$00AE,$0407,
52 $00B0,$00B1,$0406,$0456,$0491,$00B5,$00B6,$00B7,$0451,$2116,$0454,$00BB,$0458,$0405,$0455,$0457,
53 $0410,$0411,$0412,$0413,$0414,$0415,$0416,$0417,$0418,$0419,$041A,$041B,$041C,$041D,$041E,$041F,
54 $0420,$0421,$0422,$0423,$0424,$0425,$0426,$0427,$0428,$0429,$042A,$042B,$042C,$042D,$042E,$042F,
55 $0430,$0431,$0432,$0433,$0434,$0435,$0436,$0437,$0438,$0439,$043A,$043B,$043C,$043D,$043E,$043F,
56 $0440,$0441,$0442,$0443,$0444,$0445,$0446,$0447,$0448,$0449,$044A,$044B,$044C,$044D,$044E,$044F
57 );
59 // TODO: make a transition table or something
60 function WCharToCP1251(wc: Word): Word;
61 var
62 n: Word;
63 begin
64 Result := 0;
65 for n := 0 to 127 do
66 if CP1251[n] = wc then begin Result := n; break end;
67 Result := Result + 128;
68 end;
70 function g_Window_SetDisplay(PreserveGL: Boolean = False): Boolean;
71 begin
72 Result := False;
74 e_WriteLog('Setting display mode...', MSG_NOTIFY);
76 // if wWindowCreated and PreserveGL then
77 // e_SaveGLContext(); // we need this and restore because of a bug in SDL1.2, apparently
79 wFlags := SDL_WINDOW_OPENGL or SDL_WINDOW_RESIZABLE;
80 if gFullscreen then wFlags := wFlags or SDL_WINDOW_FULLSCREEN;
81 if gWinMaximized then wFlags := wFlags or SDL_WINDOW_MAXIMIZED;
83 if h_Wnd <> nil then
84 begin
85 SDL_DestroyWindow(h_Wnd);
86 h_Wnd := nil;
87 end;
89 h_Wnd := SDL_CreateWindow(PChar(wTitle), gWinRealPosX, gWinRealPosY, gScreenWidth, gScreenHeight, wFlags);
90 if h_Wnd = nil then Exit;
92 SDL_GL_MakeCurrent(h_Wnd, h_GL);
93 SDL_ShowCursor(SDL_DISABLE);
95 // if wWindowCreated and PreserveGL then
96 // e_RestoreGLContext();
98 Result := True;
99 end;
101 procedure ReShowCursor();
102 begin
103 // TODO: what was this for?
104 end;
106 function GetDisplayModes(dBPP: DWORD; var SelRes: DWORD): SArray;
107 var
108 mode: TSDL_DisplayMode;
109 res, i, k: Integer;
110 begin
111 SetLength(Result, 0);
113 k := 0;
114 for i := 0 to SDL_GetNumDisplayModes(0) do
115 begin
116 res := SDL_GetDisplayMode(0, i, @mode);
117 if res < 0 then continue;
118 if (mode.w = gScreenWidth) and (mode.h = gScreenHeight) then
119 SelRes := k;
120 Inc(k);
121 SetLength(Result, k);
122 Result[k-1] := IntToStr(mode.w) + 'x' + IntToStr(mode.h);
123 end;
125 e_WriteLog('SDL: Got ' + IntToStr(k) + ' resolutions.', MSG_NOTIFY);
126 end;
128 procedure Sleep(ms: LongWord);
129 begin
130 SDL_Delay(ms);
131 end;
133 procedure ChangeWindowSize();
134 begin
135 gWinSizeX := gScreenWidth;
136 gWinSizeY := gScreenHeight;
137 e_ResizeWindow(gScreenWidth, gScreenHeight);
138 g_Game_SetupScreenSize();
139 g_Menu_Reset();
140 g_Game_ClearLoading();
141 end;
143 function g_Window_SetSize(W, H: Word; FScreen: Boolean): Boolean;
144 var
145 Preserve: Boolean;
146 begin
147 Result := False;
148 Preserve := False;
150 if (gScreenWidth <> W) or (gScreenHeight <> H) then
151 begin
152 Result := True;
153 gScreenWidth := W;
154 gScreenHeight := H;
155 end;
157 if gFullscreen <> FScreen then
158 begin
159 Result := True;
160 gFullscreen := FScreen;
161 Preserve := True;
162 end;
164 if Result then
165 begin
166 g_Window_SetDisplay(Preserve);
167 ChangeWindowSize();
168 end;
169 end;
171 function WindowEventHandler(ev: TSDL_WindowEvent): Boolean;
172 var
173 wActivate, wDeactivate: Boolean;
174 begin
175 Result := False;
176 wActivate := False;
177 wDeactivate := False;
179 case ev.event of
180 SDL_WINDOWEVENT_MOVED:
181 begin
182 if not (gFullscreen or gWinMaximized) then
183 begin
184 gWinRealPosX := ev.data1;
185 gWinRealPosY := ev.data2;
186 end;
187 end;
189 SDL_WINDOWEVENT_MINIMIZED:
190 begin
191 if not wMinimized then
192 begin
193 e_ResizeWindow(0, 0);
194 wMinimized := True;
196 if g_debug_WinMsgs then
197 begin
198 g_Console_Add('Now minimized');
199 e_WriteLog('[DEBUG] WinMsgs: Now minimized', MSG_NOTIFY);
200 end;
201 wDeactivate := True;
202 end;
203 end;
205 SDL_WINDOWEVENT_RESIZED:
206 begin
207 gScreenWidth := ev.data1;
208 gScreenHeight := ev.data2;
209 ChangeWindowSize();
210 SwapBuffers();
211 if g_debug_WinMsgs then
212 begin
213 g_Console_Add('Resized to ' + IntToStr(ev.data1) + 'x' + IntToStr(ev.data2));
214 e_WriteLog('[DEBUG] WinMsgs: Resized to ' + IntToStr(ev.data1) + 'x' + IntToStr(ev.data2), MSG_NOTIFY);
215 end;
216 end;
218 SDL_WINDOWEVENT_EXPOSED:
219 SwapBuffers();
221 SDL_WINDOWEVENT_MAXIMIZED:
222 begin
223 if wMinimized then
224 begin
225 e_ResizeWindow(gScreenWidth, gScreenHeight);
226 wMinimized := False;
227 wActivate := True;
228 end;
229 if not gWinMaximized then
230 begin
231 gWinMaximized := True;
232 if g_debug_WinMsgs then
233 begin
234 g_Console_Add('Now maximized');
235 e_WriteLog('[DEBUG] WinMsgs: Now maximized', MSG_NOTIFY);
236 end;
237 end;
238 end;
240 SDL_WINDOWEVENT_RESTORED:
241 begin
242 if wMinimized then
243 begin
244 e_ResizeWindow(gScreenWidth, gScreenHeight);
245 wMinimized := False;
246 wActivate := True;
247 end;
248 if gWinMaximized then
249 gWinMaximized := False;
250 if g_debug_WinMsgs then
251 begin
252 g_Console_Add('Now restored');
253 e_WriteLog('[DEBUG] WinMsgs: Now restored', MSG_NOTIFY);
254 end;
255 end;
257 SDL_WINDOWEVENT_FOCUS_GAINED:
258 wActivate := True;
260 SDL_WINDOWEVENT_FOCUS_LOST:
261 wDeactivate := True;
262 end;
264 if wDeactivate then
265 begin
266 if gWinActive then
267 begin
268 e_EnableInput := False;
269 e_ClearInputBuffer();
271 if gMuteWhenInactive then
272 e_MuteChannels(True);
274 if g_debug_WinMsgs then
275 begin
276 g_Console_Add('Now inactive');
277 e_WriteLog('[DEBUG] WinMsgs: Now inactive', MSG_NOTIFY);
278 end;
280 gWinActive := False;
281 end;
282 end
283 else if wActivate then
284 begin
285 if not gWinActive then
286 begin
287 e_EnableInput := True;
289 if gMuteWhenInactive then
290 e_MuteChannels(False);
292 if g_debug_WinMsgs then
293 begin
294 g_Console_Add('Now active');
295 e_WriteLog('[DEBUG] WinMsgs: Now active', MSG_NOTIFY);
296 end;
298 gWinActive := True;
299 end;
300 end;
301 end;
303 function EventHandler(ev: TSDL_Event): Boolean;
304 var
305 key, keychr: Word;
306 uc: UnicodeChar;
307 //joy: Integer;
308 begin
309 Result := False;
310 case ev.type_ of
311 SDL_WINDOWEVENT:
312 Result := WindowEventHandler(ev.window);
314 SDL_QUITEV:
315 begin
316 if gExit <> EXIT_QUIT then
317 begin
318 if not wLoadingProgress then
319 begin
320 g_Game_Free();
321 g_Game_Quit();
322 end
323 else
324 wLoadingQuit := True;
325 end;
326 Result := True;
327 end;
329 SDL_KEYDOWN:
330 begin
331 key := ev.key.keysym.scancode;
332 KeyPress(key);
333 end;
335 SDL_TEXTINPUT:
336 begin
337 Utf8ToUnicode(@uc, PChar(ev.text.text), 1);
338 keychr := Word(uc);
339 if (keychr > 127) then
340 keychr := WCharToCP1251(keychr);
341 CharPress(Chr(keychr));
342 end;
344 // other key presses and joysticks are handled in e_input
345 end;
346 end;
348 procedure SwapBuffers();
349 begin
350 SDL_GL_SwapWindow(h_Wnd);
351 end;
353 procedure KillGLWindow();
354 begin
355 if h_Wnd <> nil then SDL_DestroyWindow(h_Wnd);
356 if h_GL <> nil then SDL_GL_DeleteContext(h_GL);
357 h_Wnd := nil;
358 h_GL := nil;
359 wWindowCreated := False;
360 end;
362 function CreateGLWindow(Title: PChar): Boolean;
363 //var
364 // flags: LongWord;
365 begin
366 Result := False;
368 gWinSizeX := gScreenWidth;
369 gWinSizeY := gScreenHeight;
371 wTitle := Title;
372 e_WriteLog('Creating window', MSG_NOTIFY);
374 if not g_Window_SetDisplay() then
375 begin
376 KillGLWindow();
377 e_WriteLog('Window creation error (resolution not supported?)', MSG_FATALERROR);
378 exit;
379 end;
381 h_Gl := SDL_GL_CreateContext(h_Wnd);
382 if h_Gl = nil then Exit;
384 wWindowCreated := True;
386 e_ResizeWindow(gScreenWidth, gScreenHeight);
387 e_InitGL();
389 Result := True;
390 end;
392 function GetTimer(): Int64;
393 begin
394 Result := SDL_GetTicks() * 1000; // TODO: do we really need microseconds here?
395 end;
397 procedure ResetTimer();
398 begin
399 wNeedTimeReset := True;
400 end;
402 procedure PushExitEvent();
403 var
404 ev: TSDL_Event;
405 begin
406 ev.type_ := SDL_QUITEV;
407 SDL_PushEvent(@ev);
408 end;
410 procedure ProcessLoading();
411 var
412 ev: TSDL_Event;
413 ID: DWORD;
414 begin
415 FillChar(ev, SizeOf(ev), 0);
416 //wNeedFree := False;
417 wLoadingProgress := True;
418 while SDL_PollEvent(@ev) > 0 do
419 begin
420 if (ev.type_ = SDL_QUITEV) then
421 break;
422 end;
423 //wNeedFree := True;
425 if (ev.type_ = SDL_QUITEV) or (gExit = EXIT_QUIT) then
426 begin
427 wLoadingProgress := False;
428 exit;
429 end;
431 if not wMinimized then
432 begin
433 if g_Texture_Get('INTER', ID) then
434 e_DrawSize(ID, 0, 0, 0, False, False, gScreenWidth, gScreenHeight)
435 else
436 e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
438 DrawLoadingStat();
439 SwapBuffers();
441 ReShowCursor();
442 end;
444 e_SoundUpdate();
446 if NetMode = NET_SERVER then
447 g_Net_Host_Update
448 else
449 if (NetMode = NET_CLIENT) and (NetState <> NET_STATE_AUTH) then
450 g_Net_Client_UpdateWhileLoading;
451 wLoadingProgress := False;
452 end;
454 function ProcessMessage(): Boolean;
455 var
456 i, t: Integer;
457 ev: TSDL_Event;
458 begin
459 Result := False;
460 FillChar(ev, SizeOf(ev), 0);
462 while SDL_PollEvent(@ev) > 0 do
463 begin
464 Result := EventHandler(ev);
465 if ev.type_ = SDL_QUITEV then exit;
466 end;
468 Time := GetTimer();
469 Time_Delta := Time - Time_Old;
471 flag := False;
473 if wNeedTimeReset then
474 begin
475 Time_Delta := 27777;
476 wNeedTimeReset := False;
477 end;
479 t := Time_Delta div 27777;
480 if t > 0 then
481 begin
482 flag := True;
483 for i := 1 to t do
484 begin
485 if NetMode = NET_SERVER then g_Net_Host_Update()
486 else if NetMode = NET_CLIENT then g_Net_Client_Update();
487 Update();
488 end;
489 end
490 else
491 begin
492 if NetMode = NET_SERVER then g_Net_Host_Update()
493 else if NetMode = NET_CLIENT then g_Net_Client_Update();
494 end;
496 if wLoadingQuit then
497 begin
498 g_Game_Free();
499 g_Game_Quit();
500 end;
502 if gExit = EXIT_QUIT then
503 begin
504 Result := True;
505 Exit;
506 end;
508 // Âðåìÿ ïðåäûäóùåãî îáíîâëåíèÿ:
509 if flag then
510 begin
511 Time_Old := Time - (Time_Delta mod 27777);
512 if (not wMinimized) then
513 begin
514 Draw();
515 SwapBuffers();
516 ReShowCursor();
517 end;
518 end
519 else
520 Sleep(1);
522 e_SoundUpdate();
523 end;
525 procedure ReDrawWindow;
526 begin
527 SwapBuffers();
528 ReShowCursor();
529 end;
531 procedure InitOpenGL(VSync: Boolean);
532 var
533 v: Byte;
534 begin
535 if VSync then v := 1 else v := 0;
536 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
537 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
538 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
539 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
540 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
541 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
542 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
543 SDL_GL_SetSwapInterval(v);
544 end;
546 function SDLMain(): Integer;
547 begin
548 e_WriteLog('Creating GL window', MSG_NOTIFY);
549 if not CreateGLWindow(PChar(Format('Doom 2D: Forever %s', [GAME_VERSION]))) then
550 begin
551 Result := 0;
552 exit;
553 end;
555 e_WriteLog('Initializing OpenGL', MSG_NOTIFY);
556 InitOpenGL(gVSync);
558 {EnumDisplayModes();}
560 Init();
561 Time_Old := GetTimer();
563 // Êîìàíäíàÿ ñòðîêà:
564 if ParamCount > 0 then
565 g_Game_Process_Params();
567 // Çàïðîñ ÿçûêà:
568 if (not gGameOn) and gAskLanguage then
569 g_Menu_AskLanguage();
571 e_WriteLog('Entering the main loop', MSG_NOTIFY);
573 while not ProcessMessage() do
574 { Main Loop } ;
576 Release();
577 KillGLWindow();
579 Result := 0;
580 end;
582 end.