DEADSOFTWARE

show map loading update once per 300 msec; it nearly halves loading times for huge...
[d2df-sdl.git] / src / game / g_window.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, either version 3 of the License, or
6 * (at your option) any later version.
7 *
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.
12 *
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/>.
15 *)
16 {$INCLUDE ../shared/a_modes.inc}
17 unit g_window;
19 interface
21 uses
22 wadreader;
24 function SDLMain(): Integer;
25 function GetTimer(): Int64;
26 procedure ResetTimer();
27 function CreateGLWindow(Title: PChar): Boolean;
28 procedure KillGLWindow();
29 procedure PushExitEvent();
30 function ProcessMessage(): Boolean;
31 procedure ProcessLoading (forceUpdate: Boolean=false);
32 procedure ReDrawWindow();
33 procedure SwapBuffers();
34 procedure Sleep(ms: LongWord);
35 function GetDisplayModes(dBPP: DWORD; var SelRes: DWORD): SArray;
36 function g_Window_SetDisplay(PreserveGL: Boolean = False): Boolean;
37 function g_Window_SetSize(W, H: Word; FScreen: Boolean): Boolean;
39 var
40 gwin_dump_extensions: Boolean = false;
41 gwin_has_stencil: Boolean = false;
42 gwin_k8_enable_light_experiments: Boolean = false;
45 implementation
47 uses
48 {$IFDEF WINDOWS}Windows,{$ENDIF}
49 SDL2, GL, GLExt, e_graphics, e_log, g_main,
50 g_console, SysUtils, e_input, g_options, g_game,
51 g_basic, g_textures, e_sound, g_sound, g_menu, ENet, g_net,
52 g_map, g_gfx, g_monsters, g_holmes, xprofiler;
54 var
55 h_Wnd: PSDL_Window;
56 h_GL: TSDL_GLContext;
57 wFlags: LongWord = 0;
58 Time, Time_Delta, Time_Old: Int64;
59 flag: Boolean;
60 wTitle: PChar = nil;
61 wNeedTimeReset: Boolean = False;
62 //wWindowCreated: Boolean = False;
63 //wCursorShown: Boolean = False;
64 wMinimized: Boolean = False;
65 //wNeedFree: Boolean = True;
66 wLoadingProgress: Boolean = False;
67 wLoadingQuit: Boolean = False;
68 {wWinPause: Byte = 0;}
69 {$IFNDEF WINDOWS}
70 ticksOverflow: Int64 = -1;
71 lastTicks: Uint32 = 0; // to detect overflow
72 {$ENDIF}
73 curMsButState: Word = 0;
74 curKbState: Word = 0;
75 curMsX: Integer = 0;
76 curMsY: Integer = 0;
78 const
79 // TODO: move this to a separate file
80 CP1251: array [0..127] of Word = (
81 $0402,$0403,$201A,$0453,$201E,$2026,$2020,$2021,$20AC,$2030,$0409,$2039,$040A,$040C,$040B,$040F,
82 $0452,$2018,$2019,$201C,$201D,$2022,$2013,$2014,$003F,$2122,$0459,$203A,$045A,$045C,$045B,$045F,
83 $00A0,$040E,$045E,$0408,$00A4,$0490,$00A6,$00A7,$0401,$00A9,$0404,$00AB,$00AC,$00AD,$00AE,$0407,
84 $00B0,$00B1,$0406,$0456,$0491,$00B5,$00B6,$00B7,$0451,$2116,$0454,$00BB,$0458,$0405,$0455,$0457,
85 $0410,$0411,$0412,$0413,$0414,$0415,$0416,$0417,$0418,$0419,$041A,$041B,$041C,$041D,$041E,$041F,
86 $0420,$0421,$0422,$0423,$0424,$0425,$0426,$0427,$0428,$0429,$042A,$042B,$042C,$042D,$042E,$042F,
87 $0430,$0431,$0432,$0433,$0434,$0435,$0436,$0437,$0438,$0439,$043A,$043B,$043C,$043D,$043E,$043F,
88 $0440,$0441,$0442,$0443,$0444,$0445,$0446,$0447,$0448,$0449,$044A,$044B,$044C,$044D,$044E,$044F
89 );
91 // TODO: make a transition table or something
92 function WCharToCP1251(wc: Word): Word;
93 var
94 n: Word;
95 begin
96 Result := 0;
97 for n := 0 to 127 do
98 if CP1251[n] = wc then begin Result := n; break end;
99 Result := Result + 128;
100 end;
102 function g_Window_SetDisplay(PreserveGL: Boolean = False): Boolean;
103 var
104 mode, cmode: TSDL_DisplayMode;
105 begin
106 {$IFDEF HEADLESS}
107 Result := True;
108 Exit;
109 {$ENDIF}
111 Result := False;
113 e_WriteLog('Setting display mode...', MSG_NOTIFY);
115 wFlags := SDL_WINDOW_OPENGL or SDL_WINDOW_RESIZABLE;
116 if gFullscreen then wFlags := wFlags or SDL_WINDOW_FULLSCREEN;
117 if gWinMaximized then wFlags := wFlags or SDL_WINDOW_MAXIMIZED;
119 if h_Wnd <> nil then
120 begin
121 SDL_DestroyWindow(h_Wnd);
122 h_Wnd := nil;
123 end;
125 if gFullscreen then
126 begin
127 mode.w := gScreenWidth;
128 mode.h := gScreenHeight;
129 mode.format := 0;
130 mode.refresh_rate := 0;
131 mode.driverdata := nil;
132 if SDL_GetClosestDisplayMode(0, @mode, @cmode) = nil then
133 begin
134 gScreenWidth := 800;
135 gScreenHeight := 600;
136 end
137 else
138 begin
139 gScreenWidth := cmode.w;
140 gScreenHeight := cmode.h;
141 end;
142 end;
144 h_Wnd := SDL_CreateWindow(PChar(wTitle), gWinRealPosX, gWinRealPosY, gScreenWidth, gScreenHeight, wFlags);
145 if h_Wnd = nil then Exit;
147 SDL_GL_MakeCurrent(h_Wnd, h_GL);
148 SDL_ShowCursor(SDL_DISABLE);
150 Result := True;
151 end;
153 procedure ReShowCursor();
154 begin
155 // TODO: what was this for?
156 end;
158 function GetDisplayModes(dBPP: DWORD; var SelRes: DWORD): SArray;
159 var
160 mode: TSDL_DisplayMode;
161 res, i, k, n, pw, ph: Integer;
162 begin
163 SetLength(Result, 0);
164 {$IFDEF HEADLESS}Exit;{$ENDIF}
165 k := 0; SelRes := 0;
166 n := SDL_GetNumDisplayModes(0);
167 pw := 0; ph := 0;
168 for i := 0 to n do
169 begin
170 res := SDL_GetDisplayMode(0, i, @mode);
171 if res < 0 then continue;
172 if SDL_BITSPERPIXEL(mode.format) = gBPP then continue;
173 if (mode.w = pw) and (mode.h = ph) then continue;
174 if (mode.w = gScreenWidth) and (mode.h = gScreenHeight) then
175 SelRes := k;
176 Inc(k);
177 SetLength(Result, k);
178 Result[k-1] := IntToStr(mode.w) + 'x' + IntToStr(mode.h);
179 pw := mode.w; ph := mode.h
180 end;
182 e_WriteLog('SDL: Got ' + IntToStr(k) + ' resolutions.', MSG_NOTIFY);
183 end;
185 procedure Sleep(ms: LongWord);
186 begin
187 SDL_Delay(ms);
188 end;
190 procedure ChangeWindowSize();
191 begin
192 gWinSizeX := gScreenWidth;
193 gWinSizeY := gScreenHeight;
194 {$IFDEF HEADLESS}Exit;{$ENDIF}
195 e_ResizeWindow(gScreenWidth, gScreenHeight);
196 g_Game_SetupScreenSize();
197 g_Menu_Reset();
198 g_Game_ClearLoading();
199 g_Holmes_VidModeChanged();
200 end;
202 function g_Window_SetSize(W, H: Word; FScreen: Boolean): Boolean;
203 var
204 Preserve: Boolean;
205 begin
206 Result := False;
207 {$IFDEF HEADLESS}Exit;{$ENDIF}
208 Preserve := False;
210 if (gScreenWidth <> W) or (gScreenHeight <> H) then
211 begin
212 Result := True;
213 gScreenWidth := W;
214 gScreenHeight := H;
215 end;
217 if gFullscreen <> FScreen then
218 begin
219 Result := True;
220 gFullscreen := FScreen;
221 Preserve := True;
222 end;
224 if Result then
225 begin
226 g_Window_SetDisplay(Preserve);
227 ChangeWindowSize();
228 end;
229 end;
231 function WindowEventHandler(ev: TSDL_WindowEvent): Boolean;
232 var
233 wActivate, wDeactivate: Boolean;
234 begin
235 Result := False;
236 wActivate := False;
237 wDeactivate := False;
239 case ev.event of
240 SDL_WINDOWEVENT_MOVED:
241 begin
242 if not (gFullscreen or gWinMaximized) then
243 begin
244 gWinRealPosX := ev.data1;
245 gWinRealPosY := ev.data2;
246 end;
247 end;
249 SDL_WINDOWEVENT_MINIMIZED:
250 begin
251 curMsButState := 0;
252 curKbState := 0;
253 e_UnpressAllKeys();
254 if not wMinimized then
255 begin
256 e_ResizeWindow(0, 0);
257 wMinimized := True;
259 if g_debug_WinMsgs then
260 begin
261 g_Console_Add('Now minimized');
262 e_WriteLog('[DEBUG] WinMsgs: Now minimized', MSG_NOTIFY);
263 end;
264 wDeactivate := True;
265 end;
266 end;
268 SDL_WINDOWEVENT_RESIZED:
269 begin
270 curMsButState := 0;
271 curKbState := 0;
272 gScreenWidth := ev.data1;
273 gScreenHeight := ev.data2;
274 ChangeWindowSize();
275 SwapBuffers();
276 if g_debug_WinMsgs then
277 begin
278 g_Console_Add('Resized to ' + IntToStr(ev.data1) + 'x' + IntToStr(ev.data2));
279 e_WriteLog('[DEBUG] WinMsgs: Resized to ' + IntToStr(ev.data1) + 'x' + IntToStr(ev.data2), MSG_NOTIFY);
280 end;
281 end;
283 SDL_WINDOWEVENT_EXPOSED:
284 SwapBuffers();
286 SDL_WINDOWEVENT_MAXIMIZED:
287 begin
288 curMsButState := 0;
289 curKbState := 0;
290 if wMinimized then
291 begin
292 e_ResizeWindow(gScreenWidth, gScreenHeight);
293 wMinimized := False;
294 wActivate := True;
295 end;
296 if not gWinMaximized then
297 begin
298 gWinMaximized := True;
299 if g_debug_WinMsgs then
300 begin
301 g_Console_Add('Now maximized');
302 e_WriteLog('[DEBUG] WinMsgs: Now maximized', MSG_NOTIFY);
303 end;
304 end;
305 end;
307 SDL_WINDOWEVENT_RESTORED:
308 begin
309 curMsButState := 0;
310 curKbState := 0;
311 if wMinimized then
312 begin
313 e_ResizeWindow(gScreenWidth, gScreenHeight);
314 wMinimized := False;
315 wActivate := True;
316 end;
317 if gWinMaximized then
318 gWinMaximized := False;
319 if g_debug_WinMsgs then
320 begin
321 g_Console_Add('Now restored');
322 e_WriteLog('[DEBUG] WinMsgs: Now restored', MSG_NOTIFY);
323 end;
324 end;
326 SDL_WINDOWEVENT_FOCUS_GAINED:
327 begin
328 curMsButState := 0;
329 curKbState := 0;
330 wActivate := True;
331 //e_WriteLog('window gained focus!', MSG_NOTIFY);
332 g_Holmes_WindowFocused();
333 end;
335 SDL_WINDOWEVENT_FOCUS_LOST:
336 begin
337 curMsButState := 0;
338 curKbState := 0;
339 wDeactivate := True;
340 e_UnpressAllKeys();
341 //e_WriteLog('window lost focus!', MSG_NOTIFY);
342 g_Holmes_WindowBlured();
343 end;
344 end;
346 if wDeactivate then
347 begin
348 if gWinActive then
349 begin
350 e_WriteLog('deactivating window', MSG_NOTIFY);
351 e_EnableInput := False;
352 e_ClearInputBuffer();
354 if gMuteWhenInactive then
355 begin
356 //e_WriteLog('deactivating sounds', MSG_NOTIFY);
357 e_MuteChannels(True);
358 end;
360 if g_debug_WinMsgs then
361 begin
362 g_Console_Add('Now inactive');
363 e_WriteLog('[DEBUG] WinMsgs: Now inactive', MSG_NOTIFY);
364 end;
366 gWinActive := False;
367 end;
368 end
369 else if wActivate then
370 begin
371 if not gWinActive then
372 begin
373 //e_WriteLog('activating window', MSG_NOTIFY);
374 e_EnableInput := True;
376 if gMuteWhenInactive then
377 begin
378 //e_WriteLog('activating sounds', MSG_NOTIFY);
379 e_MuteChannels(False);
380 end;
382 if g_debug_WinMsgs then
383 begin
384 g_Console_Add('Now active');
385 e_WriteLog('[DEBUG] WinMsgs: Now active', MSG_NOTIFY);
386 end;
388 gWinActive := True;
389 end;
390 end;
391 end;
393 function EventHandler(ev: TSDL_Event): Boolean;
394 var
395 key, keychr: Word;
396 uc: UnicodeChar;
397 //joy: Integer;
398 msev: THMouseEvent;
399 kbev: THKeyEvent;
401 function buildBut (b: Byte): Word;
402 begin
403 result := 0;
404 case b of
405 SDL_BUTTON_LEFT: result := result or THMouseEvent.Left;
406 SDL_BUTTON_MIDDLE: result := result or THMouseEvent.Middle;
407 SDL_BUTTON_RIGHT: result := result or THMouseEvent.Right;
408 end;
409 end;
411 procedure updateKBState ();
412 var
413 kbstate: PUint8;
414 begin
415 curKbState := 0;
416 kbstate := SDL_GetKeyboardState(nil);
417 if (kbstate[SDL_SCANCODE_LCTRL] <> 0) or (kbstate[SDL_SCANCODE_RCTRL] <> 0) then curKbState := curKbState or THKeyEvent.ModCtrl;
418 if (kbstate[SDL_SCANCODE_LALT] <> 0) or (kbstate[SDL_SCANCODE_RALT] <> 0) then curKbState := curKbState or THKeyEvent.ModAlt;
419 if (kbstate[SDL_SCANCODE_LSHIFT] <> 0) or (kbstate[SDL_SCANCODE_RSHIFT] <> 0) then curKbState := curKbState or THKeyEvent.ModShift;
420 end;
422 begin
423 Result := False;
424 updateKBState();
426 case ev.type_ of
427 SDL_WINDOWEVENT:
428 Result := WindowEventHandler(ev.window);
430 SDL_QUITEV:
431 begin
432 if gExit <> EXIT_QUIT then
433 begin
434 if not wLoadingProgress then
435 begin
436 g_Game_Free();
437 g_Game_Quit();
438 end
439 else
440 wLoadingQuit := True;
441 end;
442 Result := True;
443 end;
445 SDL_KEYDOWN, SDL_KEYUP:
446 begin
447 key := ev.key.keysym.scancode;
448 if (g_holmes_enabled) then
449 begin
450 if (ev.type_ = SDL_KEYDOWN) then kbev.kind := THKeyEvent.Press else kbev.kind := THKeyEvent.Release;
451 kbev.scan := ev.key.keysym.scancode;
452 kbev.sym := ev.key.keysym.sym;
453 kbev.bstate := curMsButState;
454 kbev.kstate := curKbState;
455 {$IF not DEFINED(HEADLESS)}
456 if g_Holmes_keyEvent(kbev) then
457 begin
458 if (ev.type_ <> SDL_KEYDOWN) then e_KeyUpDown(ev.key.keysym.scancode, false);
459 exit;
460 end;
461 {$ENDIF}
462 end;
463 if (ev.type_ = SDL_KEYDOWN) then KeyPress(key);
464 e_KeyUpDown(ev.key.keysym.scancode, (ev.type_ = SDL_KEYDOWN));
465 end;
467 {$IF not DEFINED(HEADLESS)}
468 SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONUP:
469 begin
470 msev.dx := ev.button.x-curMsX;
471 msev.dy := ev.button.y-curMsY;
472 curMsX := ev.button.x;
473 curMsY := ev.button.y;
474 if (ev.type_ = SDL_MOUSEBUTTONDOWN) then msev.kind := THMouseEvent.Press else msev.kind := THMouseEvent.Release;
475 msev.but := buildBut(ev.button.button);
476 msev.x := curMsX;
477 msev.y := curMsY;
478 if (msev.but <> 0) then
479 begin
480 // ev.button.clicks: Byte
481 if (ev.type_ = SDL_MOUSEBUTTONDOWN) then curMsButState := curMsButState or msev.but else curMsButState := curMsButState and (not msev.but);
482 msev.bstate := curMsButState;
483 msev.kstate := curKbState;
484 if (g_holmes_enabled) then g_Holmes_mouseEvent(msev);
485 end;
486 end;
487 SDL_MOUSEWHEEL:
488 begin
489 if (ev.wheel.y <> 0) then
490 begin
491 msev.dx := 0;
492 msev.dy := ev.wheel.y;
493 msev.kind := THMouseEvent.Press;
494 if (ev.wheel.y < 0) then msev.but := THMouseEvent.WheelUp else msev.but := THMouseEvent.WheelDown;
495 msev.x := curMsX;
496 msev.y := curMsY;
497 msev.bstate := curMsButState;
498 msev.kstate := curKbState;
499 if (g_holmes_enabled) then g_Holmes_mouseEvent(msev);
500 end;
501 end;
502 SDL_MOUSEMOTION:
503 begin
504 msev.dx := ev.button.x-curMsX;
505 msev.dy := ev.button.y-curMsY;
506 curMsX := ev.button.x;
507 curMsY := ev.button.y;
508 msev.kind := THMouseEvent.Motion;
509 msev.but := 0;
510 msev.x := curMsX;
511 msev.y := curMsY;
512 msev.bstate := curMsButState;
513 msev.kstate := curKbState;
514 if (g_holmes_enabled) then g_Holmes_mouseEvent(msev);
515 end;
516 {$ENDIF}
518 SDL_TEXTINPUT:
519 begin
520 Utf8ToUnicode(@uc, PChar(ev.text.text), 1);
521 keychr := Word(uc);
522 if (keychr > 127) then keychr := WCharToCP1251(keychr);
523 CharPress(Chr(keychr));
524 end;
526 // other key presses and joysticks are handled in e_input
527 end;
528 end;
530 procedure SwapBuffers();
531 begin
532 {$IFDEF HEADLESS}Exit;{$ENDIF}
533 SDL_GL_SwapWindow(h_Wnd);
534 end;
536 procedure KillGLWindow();
537 begin
538 if h_Wnd <> nil then SDL_DestroyWindow(h_Wnd);
539 if h_GL <> nil then SDL_GL_DeleteContext(h_GL);
540 h_Wnd := nil;
541 h_GL := nil;
542 //wWindowCreated := False;
543 end;
545 function CreateGLWindow(Title: PChar): Boolean;
546 //var
547 // flags: LongWord;
548 begin
549 Result := False;
551 gWinSizeX := gScreenWidth;
552 gWinSizeY := gScreenHeight;
554 wTitle := Title;
555 e_WriteLog('Creating window', MSG_NOTIFY);
557 if not g_Window_SetDisplay() then
558 begin
559 KillGLWindow();
560 e_WriteLog('Window creation error (resolution not supported?)', MSG_FATALERROR);
561 exit;
562 end;
564 {$IFNDEF HEADLESS}
565 h_Gl := SDL_GL_CreateContext(h_Wnd);
566 if h_Gl = nil then Exit;
567 {$ENDIF}
568 //wWindowCreated := True;
570 e_ResizeWindow(gScreenWidth, gScreenHeight);
571 e_InitGL();
573 Result := True;
574 end;
576 {$IFDEF WINDOWS}
577 // windoze sux; in headless mode `GetTickCount()` (and SDL) returns shit
578 function GetTimer(): Int64;
579 var
580 F, C: Int64;
581 begin
582 QueryPerformanceFrequency(F);
583 QueryPerformanceCounter(C);
584 Result := Round(C/F*1000{000});
585 end;
586 {$ELSE}
587 function GetTimer(): Int64;
588 var
589 t: Uint32;
590 tt: Int64;
591 begin
592 t := SDL_GetTicks() {* 1000}; // TODO: do we really need microseconds here? k8: NOPE!
593 if ticksOverflow = -1 then
594 begin
595 ticksOverflow := 0;
596 lastTicks := t;
597 end
598 else
599 begin
600 if lastTicks > t then
601 begin
602 // overflow, increment overflow ;-)
603 ticksOverflow := ticksOverflow+(Int64($ffffffff)+Int64(1));
604 tt := (Int64($ffffffff)+Int64(1))+Int64(t);
605 t := Uint32(tt-lastTicks);
606 end;
607 end;
608 lastTicks := t;
609 result := ticksOverflow+Int64(t);
610 end;
611 {$ENDIF}
613 procedure ResetTimer();
614 begin
615 wNeedTimeReset := True;
616 end;
618 procedure PushExitEvent();
619 var
620 ev: TSDL_Event;
621 begin
622 ev.type_ := SDL_QUITEV;
623 SDL_PushEvent(@ev);
624 end;
627 var
628 prevLoadingUpdateTime: UInt64 = 0;
630 procedure ProcessLoading (forceUpdate: Boolean=false);
631 var
632 ev: TSDL_Event;
633 ID: DWORD;
634 stt: UInt64;
635 begin
636 FillChar(ev, SizeOf(ev), 0);
637 //wNeedFree := False;
638 wLoadingProgress := True;
639 while SDL_PollEvent(@ev) > 0 do
640 begin
641 if (ev.type_ = SDL_QUITEV) then
642 break;
643 end;
644 //wNeedFree := True;
646 if (ev.type_ = SDL_QUITEV) or (gExit = EXIT_QUIT) then
647 begin
648 wLoadingProgress := False;
649 exit;
650 end;
652 if not wMinimized then
653 begin
654 if forceUpdate then
655 begin
656 prevLoadingUpdateTime := curTimeMilli();
657 end
658 else
659 begin
660 stt := curTimeMilli();
661 if (stt < prevLoadingUpdateTime) or (stt-prevLoadingUpdateTime >= 400) then
662 begin
663 prevLoadingUpdateTime := stt;
664 forceUpdate := true;
665 end;
666 end;
668 if forceUpdate then
669 begin
670 if g_Texture_Get('INTER', ID) then
671 begin
672 e_DrawSize(ID, 0, 0, 0, False, False, gScreenWidth, gScreenHeight)
673 end
674 else
675 begin
676 e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
677 end;
679 DrawLoadingStat();
680 SwapBuffers();
682 ReShowCursor();
683 end;
684 end;
686 e_SoundUpdate();
688 if NetMode = NET_SERVER then
689 begin
690 g_Net_Host_Update();
691 end
692 else
693 begin
694 if (NetMode = NET_CLIENT) and (NetState <> NET_STATE_AUTH) then g_Net_Client_UpdateWhileLoading();
695 end;
696 wLoadingProgress := False;
697 end;
699 function ProcessMessage(): Boolean;
700 var
701 i, t: Integer;
702 ev: TSDL_Event;
703 begin
704 Result := False;
705 FillChar(ev, SizeOf(ev), 0);
707 while SDL_PollEvent(@ev) > 0 do
708 begin
709 Result := EventHandler(ev);
710 if ev.type_ = SDL_QUITEV then exit;
711 end;
713 Time := GetTimer();
714 Time_Delta := Time - Time_Old;
716 flag := False;
718 if wNeedTimeReset then
719 begin
720 Time_Delta := 28{(27777 div 1000)};
721 wNeedTimeReset := False;
722 end;
724 g_Map_ProfilersBegin();
725 g_Mons_ProfilersBegin();
727 t := Time_Delta div 28{(27777 div 1000)};
728 if t > 0 then
729 begin
730 flag := True;
731 for i := 1 to t do
732 begin
733 if NetMode = NET_SERVER then g_Net_Host_Update()
734 else if NetMode = NET_CLIENT then g_Net_Client_Update();
735 Update();
736 end;
737 end
738 else
739 begin
740 if NetMode = NET_SERVER then g_Net_Host_Update()
741 else if NetMode = NET_CLIENT then g_Net_Client_Update();
742 end;
744 g_Map_ProfilersEnd();
745 g_Mons_ProfilersEnd();
747 if wLoadingQuit then
748 begin
749 g_Game_Free();
750 g_Game_Quit();
751 end;
753 if gExit = EXIT_QUIT then
754 begin
755 Result := True;
756 Exit;
757 end;
759 // Âðåìÿ ïðåäûäóùåãî îáíîâëåíèÿ:
760 if flag then
761 begin
762 Time_Old := Time - (Time_Delta mod 28{(27777 div 1000)});
763 if (not wMinimized) then
764 begin
765 Draw();
766 SwapBuffers();
767 ReShowCursor();
768 end;
769 end
770 else
771 Sleep(1);
773 e_SoundUpdate();
774 end;
776 procedure ReDrawWindow;
777 begin
778 SwapBuffers();
779 ReShowCursor();
780 end;
782 procedure InitOpenGL(VSync: Boolean);
783 var
784 v: Byte;
785 begin
786 {$IFDEF HEADLESS}Exit;{$ENDIF}
787 if VSync then v := 1 else v := 0;
788 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
789 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
790 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
791 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
792 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
793 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
794 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
795 if gwin_k8_enable_light_experiments then
796 begin
797 SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 1); // lights; it is enough to have 1-bit stencil buffer for lighting
798 end;
799 SDL_GL_SetSwapInterval(v);
800 end;
802 function glHasExtension (name: AnsiString): Boolean;
803 var
804 exts: PChar;
805 i: Integer;
806 found: Boolean;
807 extName: ShortString;
808 begin
809 result := false;
810 if length(name) = 0 then exit;
811 exts := glGetString(GL_EXTENSIONS);
812 if exts = nil then exit;
813 while (exts[0] <> #0) and (exts[0] = ' ') do Inc(exts);
814 while exts[0] <> #0 do
815 begin
816 if gwin_dump_extensions then
817 begin
818 i := 0;
819 while (exts[i] <> #0) and (exts[i] <> ' ') do Inc(i);
820 if i > 255 then
821 begin
822 e_WriteLog('FUUUUUUUUUUUUU', MSG_WARNING);
823 end
824 else
825 begin
826 Move(exts^, extName[1], i);
827 extName[0] := Char(i);
828 e_WriteLog(Format('EXT: %s', [extName]), MSG_NOTIFY);
829 end;
830 end;
831 found := true;
832 for i := 0 to length(name)-1 do
833 begin
834 if exts[i] = #0 then begin found := false; break; end;
835 if exts[i] <> name[i+1] then begin found := false; break; end;
836 end;
837 if found and ((exts[length(name)] = #0) or (exts[length(name)] = ' ')) then begin result := true; exit; end;
838 while (exts[0] <> #0) and (exts[0] <> ' ') do Inc(exts);
839 while (exts[0] <> #0) and (exts[0] = ' ') do Inc(exts);
840 end;
841 end;
843 function SDLMain(): Integer;
844 var
845 idx: Integer;
846 ltmp: Integer;
847 begin
848 {$IFDEF HEADLESS}
849 e_NoGraphics := True;
850 {$ENDIF}
852 for idx := 1 to ParamCount do
853 begin
854 if ParamStr(idx) = '--opengl-dump-exts' then gwin_dump_extensions := true;
855 if ParamStr(idx) = '--twinkletwinkle' then gwin_k8_enable_light_experiments := true;
856 if ParamStr(idx) = '--jah' then g_profile_history_size := 100;
857 if ParamStr(idx) = '--no-particles' then gpart_dbg_enabled := false;
858 if ParamStr(idx) = '--no-los' then gmon_dbg_los_enabled := false;
860 if ParamStr(idx) = '--profile-render' then g_profile_frame_draw := true;
861 if ParamStr(idx) = '--profile-coldet' then g_profile_collision := true;
862 if ParamStr(idx) = '--profile-los' then g_profile_los := true;
864 if ParamStr(idx) = '--no-part-phys' then gpart_dbg_phys_enabled := false;
865 if ParamStr(idx) = '--no-part-physics' then gpart_dbg_phys_enabled := false;
866 if ParamStr(idx) = '--no-particles-phys' then gpart_dbg_phys_enabled := false;
867 if ParamStr(idx) = '--no-particles-physics' then gpart_dbg_phys_enabled := false;
868 if ParamStr(idx) = '--no-particle-phys' then gpart_dbg_phys_enabled := false;
869 if ParamStr(idx) = '--no-particle-physics' then gpart_dbg_phys_enabled := false;
871 if ParamStr(idx) = '--holmes' then begin g_holmes_enabled := true; g_Game_SetDebugMode(); end;
872 end;
874 e_WriteLog('Initializing OpenGL', MSG_NOTIFY);
875 InitOpenGL(gVSync);
877 e_WriteLog('Creating GL window', MSG_NOTIFY);
878 if not CreateGLWindow(PChar(Format('Doom 2D: Forever %s', [GAME_VERSION]))) then
879 begin
880 Result := 0;
881 exit;
882 end;
884 {EnumDisplayModes();}
886 if gwin_k8_enable_light_experiments then
887 begin
888 SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, @ltmp);
889 e_WriteLog(Format('stencil buffer size: %d', [ltmp]), MSG_WARNING);
890 gwin_has_stencil := (ltmp > 0);
891 end
892 else
893 begin
894 gwin_has_stencil := false;
895 end;
897 if not glHasExtension('GL_ARB_texture_non_power_of_two') then
898 begin
899 e_WriteLog('Driver DID''T advertised NPOT textures support', MSG_WARNING);
900 glLegacyNPOT := true;
901 end
902 else
903 begin
904 e_WriteLog('Driver advertised NPOT textures support', MSG_NOTIFY);
905 glLegacyNPOT := false;
906 end;
907 gwin_dump_extensions := false;
909 Init();
910 Time_Old := GetTimer();
912 // Êîìàíäíàÿ ñòðîêà:
913 if ParamCount > 0 then
914 g_Game_Process_Params();
916 // Çàïðîñ ÿçûêà:
917 if (not gGameOn) and gAskLanguage then
918 g_Menu_AskLanguage();
920 e_WriteLog('Entering the main loop', MSG_NOTIFY);
922 while not ProcessMessage() do
923 { Main Loop } ;
925 Release();
926 KillGLWindow();
928 Result := 0;
929 end;
931 end.