DEADSOFTWARE

NPOT message typo
[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 utils;
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 ReDrawWindow ();
32 procedure SwapBuffers ();
33 procedure Sleep (ms: LongWord);
34 function GetDisplayModes (dbpp: LongWord; var selres: LongWord): SSArray;
35 function g_Window_SetDisplay (preserveGL: Boolean=false): Boolean;
36 function g_Window_SetSize (w, h: Word; fullscreen: Boolean): Boolean;
38 procedure ProcessLoading (forceUpdate: Boolean=false);
41 var
42 gwin_dump_extensions: Boolean = false;
43 gwin_has_stencil: Boolean = false;
44 gwin_k8_enable_light_experiments: Boolean = false;
45 g_dbg_aimline_on: Boolean = false;
48 implementation
50 uses
51 {$IFDEF WINDOWS}Windows,{$ENDIF}
52 SysUtils, Classes, MAPDEF,
53 SDL2, GL, GLExt, e_graphics, e_log, e_texture, g_main,
54 g_console, e_input, g_options, g_game,
55 g_basic, g_textures, e_sound, g_sound, g_menu, ENet, g_net,
56 g_map, g_gfx, g_monsters, g_holmes, xprofiler,
57 sdlcarcass, gh_ui;
60 const
61 ProgressUpdateMSecs = 100;
63 var
64 h_Wnd: PSDL_Window = nil;
65 h_GL: TSDL_GLContext = nil;
66 Time, Time_Delta, Time_Old: Int64;
67 flag: Boolean;
68 {$IF not DEFINED(HEADLESS)}
69 wTitle: PChar = nil;
70 {$ENDIF}
71 wNeedTimeReset: Boolean = false;
72 wMinimized: Boolean = false;
73 wLoadingProgress: Boolean = false;
74 wLoadingQuit: Boolean = false;
75 {$IFNDEF WINDOWS}
76 ticksOverflow: Int64 = -1;
77 lastTicks: Uint32 = 0; // to detect overflow
78 {$ENDIF}
81 procedure KillGLWindow ();
82 begin
83 if (h_Wnd <> nil) then
84 begin
85 if assigned(oglDeinitCB) then oglDeinitCB();
86 end;
87 if (h_Wnd <> nil) then SDL_DestroyWindow(h_Wnd);
88 if (h_GL <> nil) then SDL_GL_DeleteContext(h_GL);
89 h_Wnd := nil;
90 h_GL := nil;
91 end;
94 function g_Window_SetDisplay (preserveGL: Boolean = false): Boolean;
95 {$IF not DEFINED(HEADLESS)}
96 var
97 mode, cmode: TSDL_DisplayMode;
98 wFlags: LongWord = 0;
99 {$ENDIF}
100 begin
101 {$IF not DEFINED(HEADLESS)}
102 result := false;
104 e_WriteLog('Setting display mode...', TMsgType.Notify);
106 wFlags := SDL_WINDOW_OPENGL or SDL_WINDOW_RESIZABLE;
107 if gFullscreen then wFlags := wFlags or SDL_WINDOW_FULLSCREEN;
108 if gWinMaximized then wFlags := wFlags or SDL_WINDOW_MAXIMIZED;
110 KillGLWindow();
112 if gFullscreen then
113 begin
114 mode.w := gScreenWidth;
115 mode.h := gScreenHeight;
116 mode.format := 0;
117 mode.refresh_rate := 0;
118 mode.driverdata := nil;
119 if (SDL_GetClosestDisplayMode(0, @mode, @cmode) = nil) then
120 begin
121 gScreenWidth := 800;
122 gScreenHeight := 600;
123 end
124 else
125 begin
126 gScreenWidth := cmode.w;
127 gScreenHeight := cmode.h;
128 end;
129 end;
131 h_Wnd := SDL_CreateWindow(PChar(wTitle), gWinRealPosX, gWinRealPosY, gScreenWidth, gScreenHeight, wFlags);
132 if (h_Wnd = nil) then exit;
134 SDL_GL_MakeCurrent(h_Wnd, h_GL);
135 SDL_ShowCursor(SDL_DISABLE);
136 if (h_GL <> nil) then
137 begin
138 if assigned(oglInitCB) then oglInitCB();
139 end;
140 {$ENDIF}
142 result := true;
143 end;
146 function GetDisplayModes (dbpp: LongWord; var selres: LongWord): SSArray;
147 var
148 mode: TSDL_DisplayMode;
149 res, i, k, n, pw, ph: Integer;
150 begin
151 SetLength(result, 0);
152 {$IFDEF HEADLESS}exit;{$ENDIF}
153 k := 0; selres := 0;
154 n := SDL_GetNumDisplayModes(0);
155 pw := 0; ph := 0;
156 for i := 0 to n do
157 begin
158 res := SDL_GetDisplayMode(0, i, @mode);
159 if res < 0 then continue;
160 if SDL_BITSPERPIXEL(mode.format) = gBPP then continue;
161 if (mode.w = pw) and (mode.h = ph) then continue;
162 if (mode.w = gScreenWidth) and (mode.h = gScreenHeight) then
163 selres := k;
164 Inc(k);
165 SetLength(result, k);
166 result[k-1] := IntToStr(mode.w) + 'x' + IntToStr(mode.h);
167 pw := mode.w; ph := mode.h
168 end;
170 e_WriteLog('SDL: Got ' + IntToStr(k) + ' resolutions.', TMsgType.Notify);
171 end;
174 procedure Sleep (ms: LongWord);
175 begin
176 SDL_Delay(ms);
177 end;
180 procedure ChangeWindowSize ();
181 begin
182 gWinSizeX := gScreenWidth;
183 gWinSizeY := gScreenHeight;
184 {$IF not DEFINED(HEADLESS)}
185 e_ResizeWindow(gScreenWidth, gScreenHeight);
186 g_Game_SetupScreenSize();
187 g_Menu_Reset();
188 g_Game_ClearLoading();
189 {$ENDIF}
190 end;
193 function g_Window_SetSize (w, h: Word; fullscreen: Boolean): Boolean;
194 {$IF not DEFINED(HEADLESS)}
195 var
196 preserve: Boolean;
197 {$ENDIF}
198 begin
199 result := false;
200 {$IF not DEFINED(HEADLESS)}
201 preserve := false;
203 if (gScreenWidth <> w) or (gScreenHeight <> h) then
204 begin
205 result := true;
206 gScreenWidth := w;
207 gScreenHeight := h;
208 end;
210 if (gFullscreen <> fullscreen) then
211 begin
212 result := true;
213 gFullscreen := fullscreen;
214 preserve := true;
215 end;
217 if result then
218 begin
219 g_Window_SetDisplay(preserve);
220 ChangeWindowSize();
221 end;
222 {$ENDIF}
223 end;
226 function WindowEventHandler (constref ev: TSDL_WindowEvent): Boolean;
227 var
228 wActivate, wDeactivate: Boolean;
229 begin
230 result := false;
231 wActivate := false;
232 wDeactivate := false;
234 case ev.event of
235 SDL_WINDOWEVENT_MOVED:
236 begin
237 if not (gFullscreen or gWinMaximized) then
238 begin
239 gWinRealPosX := ev.data1;
240 gWinRealPosY := ev.data2;
241 end;
242 end;
244 SDL_WINDOWEVENT_MINIMIZED:
245 begin
246 e_UnpressAllKeys();
247 if not wMinimized then
248 begin
249 e_ResizeWindow(0, 0);
250 wMinimized := true;
251 if g_debug_WinMsgs then
252 begin
253 g_Console_Add('Now minimized');
254 e_WriteLog('[DEBUG] WinMsgs: Now minimized', TMsgType.Notify);
255 end;
256 wDeactivate := true;
257 end;
258 end;
260 SDL_WINDOWEVENT_RESIZED:
261 begin
262 gScreenWidth := ev.data1;
263 gScreenHeight := ev.data2;
264 ChangeWindowSize();
265 SwapBuffers();
266 if g_debug_WinMsgs then
267 begin
268 g_Console_Add('Resized to ' + IntToStr(ev.data1) + 'x' + IntToStr(ev.data2));
269 e_WriteLog('[DEBUG] WinMsgs: Resized to ' + IntToStr(ev.data1) + 'x' + IntToStr(ev.data2), TMsgType.Notify);
270 end;
271 end;
273 SDL_WINDOWEVENT_EXPOSED:
274 SwapBuffers();
276 SDL_WINDOWEVENT_MAXIMIZED:
277 begin
278 if wMinimized then
279 begin
280 e_ResizeWindow(gScreenWidth, gScreenHeight);
281 wMinimized := false;
282 wActivate := true;
283 end;
284 if not gWinMaximized then
285 begin
286 gWinMaximized := true;
287 if g_debug_WinMsgs then
288 begin
289 g_Console_Add('Now maximized');
290 e_WriteLog('[DEBUG] WinMsgs: Now maximized', TMsgType.Notify);
291 end;
292 end;
293 end;
295 SDL_WINDOWEVENT_RESTORED:
296 begin
297 if wMinimized then
298 begin
299 e_ResizeWindow(gScreenWidth, gScreenHeight);
300 wMinimized := false;
301 wActivate := true;
302 end;
303 if gWinMaximized then gWinMaximized := false;
304 if g_debug_WinMsgs then
305 begin
306 g_Console_Add('Now restored');
307 e_WriteLog('[DEBUG] WinMsgs: Now restored', TMsgType.Notify);
308 end;
309 end;
311 SDL_WINDOWEVENT_FOCUS_GAINED:
312 begin
313 wActivate := true;
314 //e_WriteLog('window gained focus!', MSG_NOTIFY);
315 end;
317 SDL_WINDOWEVENT_FOCUS_LOST:
318 begin
319 wDeactivate := true;
320 e_UnpressAllKeys();
321 //e_WriteLog('window lost focus!', MSG_NOTIFY);
322 end;
323 end;
325 if wDeactivate then
326 begin
327 if gWinActive then
328 begin
329 e_WriteLog('deactivating window', TMsgType.Notify);
330 e_EnableInput := false;
331 e_ClearInputBuffer();
333 if gMuteWhenInactive then
334 begin
335 //e_WriteLog('deactivating sounds', MSG_NOTIFY);
336 e_MuteChannels(true);
337 end;
339 if g_debug_WinMsgs then
340 begin
341 g_Console_Add('Now inactive');
342 e_WriteLog('[DEBUG] WinMsgs: Now inactive', TMsgType.Notify);
343 end;
345 gWinActive := false;
347 if assigned(winBlurCB) then winBlurCB();
348 end;
349 end
350 else if wActivate then
351 begin
352 if not gWinActive then
353 begin
354 //e_WriteLog('activating window', MSG_NOTIFY);
355 e_EnableInput := true;
357 if gMuteWhenInactive then
358 begin
359 //e_WriteLog('activating sounds', MSG_NOTIFY);
360 e_MuteChannels(false);
361 end;
363 if g_debug_WinMsgs then
364 begin
365 g_Console_Add('Now active');
366 e_WriteLog('[DEBUG] WinMsgs: Now active', TMsgType.Notify);
367 end;
369 gWinActive := true;
370 if assigned(winFocusCB) then winFocusCB();
371 end;
372 end;
373 end;
376 function EventHandler (var ev: TSDL_Event): Boolean;
377 var
378 key, keychr: Word;
379 uc: UnicodeChar;
380 down: Boolean;
381 begin
382 result := false;
384 case ev.type_ of
385 SDL_WINDOWEVENT:
386 result := WindowEventHandler(ev.window);
388 SDL_QUITEV:
389 begin
390 if (gExit <> EXIT_QUIT) then
391 begin
392 if not wLoadingProgress then
393 begin
394 g_Game_Free();
395 g_Game_Quit();
396 end
397 else
398 begin
399 wLoadingQuit := true;
400 end;
401 end;
402 result := true;
403 end;
405 SDL_KEYDOWN, SDL_KEYUP:
406 begin
407 key := ev.key.keysym.scancode;
408 down := (ev.type_ = SDL_KEYDOWN);
409 {$IF not DEFINED(HEADLESS)}
410 if evSDLCB(ev) then
411 begin
412 // event eaten, but...
413 if not down then e_KeyUpDown(key, false);
414 exit;
415 end;
416 {$ENDIF}
417 if down then KeyPress(key);
418 e_KeyUpDown(key, down);
419 end;
421 {$IF not DEFINED(HEADLESS)}
422 SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONUP, SDL_MOUSEWHEEL, SDL_MOUSEMOTION:
423 evSDLCB(ev);
424 {$ENDIF}
426 SDL_TEXTINPUT:
427 begin
428 Utf8ToUnicode(@uc, PChar(ev.text.text), 1);
429 keychr := Word(uc);
430 if (keychr > 127) then keychr := Word(wchar2win(WideChar(keychr)));
431 CharPress(AnsiChar(keychr));
432 end;
434 // other key presses and joysticks are handled in e_input
435 end;
436 end;
439 procedure SwapBuffers ();
440 begin
441 {$IF not DEFINED(HEADLESS)}
442 SDL_GL_SwapWindow(h_Wnd);
443 {$ENDIF}
444 end;
447 function CreateGLWindow (Title: PChar): Boolean;
448 begin
449 result := false;
451 gWinSizeX := gScreenWidth;
452 gWinSizeY := gScreenHeight;
454 {$IF not DEFINED(HEADLESS)}
455 wTitle := Title;
456 {$ENDIF}
457 e_WriteLog('Creating window', TMsgType.Notify);
459 if not g_Window_SetDisplay() then
460 begin
461 KillGLWindow();
462 e_WriteLog('Window creation error (resolution not supported?)', TMsgType.Fatal);
463 exit;
464 end;
466 {$IF not DEFINED(HEADLESS)}
467 h_Gl := SDL_GL_CreateContext(h_Wnd);
468 if (h_Gl = nil) then exit;
469 if assigned(oglInitCB) then oglInitCB();
470 {$ENDIF}
472 e_ResizeWindow(gScreenWidth, gScreenHeight);
473 e_InitGL();
475 result := true;
476 end;
479 {$IFDEF WINDOWS}
480 // windoze sux; in headless mode `GetTickCount()` (and SDL) returns shit
481 function GetTimer (): Int64;
482 var
483 F, C: Int64;
484 begin
485 QueryPerformanceFrequency(F);
486 QueryPerformanceCounter(C);
487 result := Round(C/F*1000{000});
488 end;
489 {$ELSE}
490 function GetTimer (): Int64;
491 var
492 t: Uint32;
493 tt: Int64;
494 begin
495 t := SDL_GetTicks();
496 if (ticksOverflow = -1) then
497 begin
498 ticksOverflow := 0;
499 lastTicks := t;
500 end
501 else
502 begin
503 if (lastTicks > t) then
504 begin
505 // overflow, increment overflow ;-)
506 ticksOverflow := ticksOverflow+(Int64($ffffffff)+Int64(1));
507 tt := (Int64($ffffffff)+Int64(1))+Int64(t);
508 t := Uint32(tt-lastTicks);
509 end;
510 end;
511 lastTicks := t;
512 result := ticksOverflow+Int64(t);
513 end;
514 {$ENDIF}
517 procedure ResetTimer ();
518 begin
519 wNeedTimeReset := true;
520 end;
523 procedure PushExitEvent ();
524 var
525 ev: TSDL_Event;
526 begin
527 ev.type_ := SDL_QUITEV;
528 SDL_PushEvent(@ev);
529 end;
532 var
533 prevLoadingUpdateTime: UInt64 = 0;
535 procedure ProcessLoading (forceUpdate: Boolean=false);
536 var
537 ev: TSDL_Event;
538 ID: LongWord;
539 stt: UInt64;
540 begin
541 FillChar(ev, sizeof(ev), 0);
542 wLoadingProgress := true;
544 while (SDL_PollEvent(@ev) > 0) do
545 begin
546 if (ev.type_ = SDL_QUITEV) then break;
547 end;
549 if (ev.type_ = SDL_QUITEV) or (gExit = EXIT_QUIT) then
550 begin
551 wLoadingProgress := false;
552 exit;
553 end;
555 if not wMinimized then
556 begin
557 if forceUpdate then
558 begin
559 prevLoadingUpdateTime := getTimeMilli();
560 end
561 else
562 begin
563 stt := getTimeMilli();
564 if (stt < prevLoadingUpdateTime) or (stt-prevLoadingUpdateTime >= ProgressUpdateMSecs) then
565 begin
566 prevLoadingUpdateTime := stt;
567 forceUpdate := true;
568 end;
569 end;
571 if forceUpdate then
572 begin
573 if g_Texture_Get('INTER', ID) then
574 begin
575 e_DrawSize(ID, 0, 0, 0, false, false, gScreenWidth, gScreenHeight)
576 end
577 else
578 begin
579 e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
580 end;
582 DrawLoadingStat();
583 SwapBuffers();
584 end;
585 end;
587 e_SoundUpdate();
589 if NetMode = NET_SERVER then
590 begin
591 g_Net_Host_Update();
592 end
593 else
594 begin
595 if (NetMode = NET_CLIENT) and (NetState <> NET_STATE_AUTH) then g_Net_Client_UpdateWhileLoading();
596 end;
598 wLoadingProgress := false;
599 end;
602 function ProcessMessage (): Boolean;
603 var
604 i, t: Integer;
605 ev: TSDL_Event;
606 begin
607 result := false;
608 FillChar(ev, SizeOf(ev), 0);
610 while (SDL_PollEvent(@ev) > 0) do
611 begin
612 result := EventHandler(ev);
613 if (ev.type_ = SDL_QUITEV) then exit;
614 end;
616 Time := GetTimer();
617 Time_Delta := Time-Time_Old;
619 flag := false;
621 if wNeedTimeReset then
622 begin
623 Time_Delta := 28;
624 wNeedTimeReset := false;
625 end;
627 g_Map_ProfilersBegin();
628 g_Mons_ProfilersBegin();
630 t := Time_Delta div 28;
631 if (t > 0) then
632 begin
633 flag := true;
634 for i := 1 to t do
635 begin
636 if (NetMode = NET_SERVER) then g_Net_Host_Update()
637 else if (NetMode = NET_CLIENT) then g_Net_Client_Update();
638 Update();
639 end;
640 end
641 else
642 begin
643 if (NetMode = NET_SERVER) then g_Net_Host_Update()
644 else if (NetMode = NET_CLIENT) then g_Net_Client_Update();
645 end;
647 g_Map_ProfilersEnd();
648 g_Mons_ProfilersEnd();
650 if wLoadingQuit then
651 begin
652 g_Game_Free();
653 g_Game_Quit();
654 end;
656 if (gExit = EXIT_QUIT) then
657 begin
658 result := true;
659 exit;
660 end;
662 // Âðåìÿ ïðåäûäóùåãî îáíîâëåíèÿ
663 if flag then
664 begin
665 Time_Old := Time-(Time_Delta mod 28);
666 if (not wMinimized) then
667 begin
668 Draw();
669 SwapBuffers();
670 end;
671 end
672 else
673 begin
674 Sleep(1); // release time slice, so we won't eat 100% CPU
675 end;
677 e_SoundUpdate();
678 end;
681 procedure ReDrawWindow ();
682 begin
683 SwapBuffers();
684 end;
687 procedure InitOpenGL (vsync: Boolean);
688 {$IF not DEFINED(HEADLESS)}
689 var
690 v: Byte;
691 {$ENDIF}
692 begin
693 {$IF not DEFINED(HEADLESS)}
694 if vsync then v := 1 else v := 0;
695 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
696 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
697 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
698 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
699 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
700 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
701 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
702 SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); // lights; it is enough to have 1-bit stencil buffer for lighting, but...
703 SDL_GL_SetSwapInterval(v);
704 {$ENDIF}
705 end;
708 function glHasExtension (const name: AnsiString): Boolean;
709 var
710 exts: PChar;
711 i: Integer;
712 found: Boolean;
713 extName: ShortString;
714 begin
715 result := false;
716 if (Length(name) = 0) then exit;
717 exts := glGetString(GL_EXTENSIONS);
718 if (exts = nil) then exit;
719 while (exts[0] <> #0) and (exts[0] = ' ') do Inc(exts);
720 while (exts[0] <> #0) do
721 begin
722 if gwin_dump_extensions then
723 begin
724 i := 0;
725 while (exts[i] <> #0) and (exts[i] <> ' ') do Inc(i);
726 if i > 255 then
727 begin
728 e_WriteLog('FUUUUUUUUUUUUU', TMsgType.Warning);
729 end
730 else
731 begin
732 Move(exts^, extName[1], i);
733 extName[0] := Char(i);
734 e_WriteLog(Format('EXT: %s', [extName]), TMsgType.Notify);
735 end;
736 end;
737 found := true;
738 for i := 0 to length(name)-1 do
739 begin
740 if (exts[i] = #0) then begin found := false; break; end;
741 if (exts[i] <> name[i+1]) then begin found := false; break; end;
742 end;
743 if found and ((exts[Length(name)] = #0) or (exts[Length(name)] = ' ')) then begin result := true; exit; end;
744 while (exts[0] <> #0) and (exts[0] <> ' ') do Inc(exts);
745 while (exts[0] <> #0) and (exts[0] = ' ') do Inc(exts);
746 end;
747 end;
750 function SDLMain (): Integer;
751 var
752 idx: Integer;
753 {$IF not DEFINED(HEADLESS)}
754 ltmp: Integer;
755 {$ENDIF}
756 arg: AnsiString;
757 mdfo: TStream;
758 begin
759 {$IFDEF HEADLESS}
760 e_NoGraphics := true;
761 {$ENDIF}
763 idx := 1;
764 while (idx <= ParamCount) do
765 begin
766 arg := ParamStr(idx);
767 Inc(idx);
768 if arg = '--opengl-dump-exts' then gwin_dump_extensions := true;
769 //if arg = '--twinkletwinkle' then gwin_k8_enable_light_experiments := true;
770 if arg = '--jah' then g_profile_history_size := 100;
771 if arg = '--no-particles' then gpart_dbg_enabled := false;
772 if arg = '--no-los' then gmon_dbg_los_enabled := false;
774 if arg = '--profile-render' then g_profile_frame_draw := true;
775 if arg = '--profile-coldet' then g_profile_collision := true;
776 if arg = '--profile-los' then g_profile_los := true;
778 if arg = '--no-part-phys' then gpart_dbg_phys_enabled := false;
779 if arg = '--no-part-physics' then gpart_dbg_phys_enabled := false;
780 if arg = '--no-particles-phys' then gpart_dbg_phys_enabled := false;
781 if arg = '--no-particles-physics' then gpart_dbg_phys_enabled := false;
782 if arg = '--no-particle-phys' then gpart_dbg_phys_enabled := false;
783 if arg = '--no-particle-physics' then gpart_dbg_phys_enabled := false;
785 {.$IF DEFINED(D2F_DEBUG)}
786 if arg = '--aimline' then g_dbg_aimline_on := true;
787 {.$ENDIF}
789 if arg = '--holmes' then begin g_holmes_enabled := true; g_Game_SetDebugMode(); end;
790 if (arg = '--holmes-ui-scale') or (arg = '-holmes-ui-scale') then
791 begin
792 if (idx <= ParamCount) then
793 begin
794 if not conParseFloat(gh_ui_scale, ParamStr(idx)) then gh_ui_scale := 1.0;
795 Inc(idx);
796 end;
797 end;
799 if (arg = '--game-scale') or (arg = '-game-scale') then
800 begin
801 if (idx <= ParamCount) then
802 begin
803 if not conParseFloat(g_dbg_scale, ParamStr(idx)) then g_dbg_scale := 1.0;
804 Inc(idx);
805 end;
806 end;
808 if (arg = '--write-mapdef') or (arg = '-write-mapdef') then
809 begin
810 mdfo := createDiskFile('mapdef.txt');
811 mdfo.WriteBuffer(defaultMapDef[1], Length(defaultMapDef));
812 mdfo.Free();
813 Halt(0);
814 end;
815 end;
817 e_WriteLog('Initializing OpenGL', TMsgType.Notify);
818 InitOpenGL(gVSync);
820 e_WriteLog('Creating GL window', TMsgType.Notify);
821 if not CreateGLWindow(PChar(Format('Doom 2D: Forever %s', [GAME_VERSION]))) then
822 begin
823 result := 0;
824 exit;
825 end;
827 {EnumDisplayModes();}
829 {$IFDEF HEADLESS}
830 //gwin_k8_enable_light_experiments := false;
831 gwin_has_stencil := false;
832 glLegacyNPOT := false;
833 gwin_dump_extensions := false;
834 {$ELSE}
835 SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, @ltmp);
836 e_LogWritefln('stencil buffer size: %s', [ltmp]);
837 gwin_has_stencil := (ltmp > 0);
839 if not glHasExtension('GL_ARB_texture_non_power_of_two') then
840 begin
841 e_WriteLog('NPOT textures: NO', TMsgType.Warning);
842 glLegacyNPOT := true;
843 end
844 else
845 begin
846 e_WriteLog('NPOT textures: YES', TMsgType.Notify);
847 glLegacyNPOT := false;
848 end;
849 gwin_dump_extensions := false;
850 {$ENDIF}
852 Init();
853 Time_Old := GetTimer();
855 // Êîìàíäíàÿ ñòðîêà
856 if (ParamCount > 0) then g_Game_Process_Params();
858 // Çàïðîñ ÿçûêà
859 if (not gGameOn) and gAskLanguage then g_Menu_AskLanguage();
861 e_WriteLog('Entering the main loop', TMsgType.Notify);
863 // main loop
864 while not ProcessMessage() do begin end;
866 Release();
867 KillGLWindow();
869 result := 0;
870 end;
873 end.