DEADSOFTWARE

"--write-mapdef" cli arg to write "mapdef.txt" and exit
[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;
43 g_dbg_aimline_on: Boolean = false;
46 implementation
48 uses
49 {$IFDEF WINDOWS}Windows,{$ENDIF}
50 SysUtils, Classes, MAPDEF,
51 SDL2, GL, GLExt, e_graphics, e_log, g_main,
52 g_console, e_input, g_options, g_game,
53 g_basic, g_textures, e_sound, g_sound, g_menu, ENet, g_net,
54 g_map, g_gfx, g_monsters, g_holmes, xprofiler, utils;
56 var
57 h_Wnd: PSDL_Window;
58 h_GL: TSDL_GLContext;
59 wFlags: LongWord = 0;
60 Time, Time_Delta, Time_Old: Int64;
61 flag: Boolean;
62 wTitle: PChar = nil;
63 wNeedTimeReset: Boolean = False;
64 //wWindowCreated: Boolean = False;
65 //wCursorShown: Boolean = False;
66 wMinimized: Boolean = False;
67 //wNeedFree: Boolean = True;
68 wLoadingProgress: Boolean = False;
69 wLoadingQuit: Boolean = False;
70 {wWinPause: Byte = 0;}
71 {$IFNDEF WINDOWS}
72 ticksOverflow: Int64 = -1;
73 lastTicks: Uint32 = 0; // to detect overflow
74 {$ENDIF}
75 curMsButState: Word = 0;
76 curKbState: Word = 0;
77 curMsX: Integer = 0;
78 curMsY: Integer = 0;
80 function g_Window_SetDisplay(PreserveGL: Boolean = False): Boolean;
81 var
82 mode, cmode: TSDL_DisplayMode;
83 begin
84 {$IFDEF HEADLESS}
85 Result := True;
86 Exit;
87 {$ENDIF}
89 Result := False;
91 e_WriteLog('Setting display mode...', MSG_NOTIFY);
93 wFlags := SDL_WINDOW_OPENGL or SDL_WINDOW_RESIZABLE;
94 if gFullscreen then wFlags := wFlags or SDL_WINDOW_FULLSCREEN;
95 if gWinMaximized then wFlags := wFlags or SDL_WINDOW_MAXIMIZED;
97 if h_Wnd <> nil then
98 begin
99 SDL_DestroyWindow(h_Wnd);
100 h_Wnd := nil;
101 end;
103 if gFullscreen then
104 begin
105 mode.w := gScreenWidth;
106 mode.h := gScreenHeight;
107 mode.format := 0;
108 mode.refresh_rate := 0;
109 mode.driverdata := nil;
110 if SDL_GetClosestDisplayMode(0, @mode, @cmode) = nil then
111 begin
112 gScreenWidth := 800;
113 gScreenHeight := 600;
114 end
115 else
116 begin
117 gScreenWidth := cmode.w;
118 gScreenHeight := cmode.h;
119 end;
120 end;
122 h_Wnd := SDL_CreateWindow(PChar(wTitle), gWinRealPosX, gWinRealPosY, gScreenWidth, gScreenHeight, wFlags);
123 if h_Wnd = nil then Exit;
125 SDL_GL_MakeCurrent(h_Wnd, h_GL);
126 SDL_ShowCursor(SDL_DISABLE);
128 Result := True;
129 end;
131 procedure ReShowCursor();
132 begin
133 // TODO: what was this for?
134 end;
136 function GetDisplayModes(dBPP: DWORD; var SelRes: DWORD): SArray;
137 var
138 mode: TSDL_DisplayMode;
139 res, i, k, n, pw, ph: Integer;
140 begin
141 SetLength(Result, 0);
142 {$IFDEF HEADLESS}Exit;{$ENDIF}
143 k := 0; SelRes := 0;
144 n := SDL_GetNumDisplayModes(0);
145 pw := 0; ph := 0;
146 for i := 0 to n do
147 begin
148 res := SDL_GetDisplayMode(0, i, @mode);
149 if res < 0 then continue;
150 if SDL_BITSPERPIXEL(mode.format) = gBPP then continue;
151 if (mode.w = pw) and (mode.h = ph) then continue;
152 if (mode.w = gScreenWidth) and (mode.h = gScreenHeight) then
153 SelRes := k;
154 Inc(k);
155 SetLength(Result, k);
156 Result[k-1] := IntToStr(mode.w) + 'x' + IntToStr(mode.h);
157 pw := mode.w; ph := mode.h
158 end;
160 e_WriteLog('SDL: Got ' + IntToStr(k) + ' resolutions.', MSG_NOTIFY);
161 end;
163 procedure Sleep(ms: LongWord);
164 begin
165 SDL_Delay(ms);
166 end;
168 procedure ChangeWindowSize();
169 begin
170 gWinSizeX := gScreenWidth;
171 gWinSizeY := gScreenHeight;
172 {$IFDEF HEADLESS}Exit;{$ENDIF}
173 e_ResizeWindow(gScreenWidth, gScreenHeight);
174 g_Game_SetupScreenSize();
175 g_Menu_Reset();
176 g_Game_ClearLoading();
177 g_Holmes_VidModeChanged();
178 end;
180 function g_Window_SetSize(W, H: Word; FScreen: Boolean): Boolean;
181 var
182 Preserve: Boolean;
183 begin
184 Result := False;
185 {$IFDEF HEADLESS}Exit;{$ENDIF}
186 Preserve := False;
188 if (gScreenWidth <> W) or (gScreenHeight <> H) then
189 begin
190 Result := True;
191 gScreenWidth := W;
192 gScreenHeight := H;
193 end;
195 if gFullscreen <> FScreen then
196 begin
197 Result := True;
198 gFullscreen := FScreen;
199 Preserve := True;
200 end;
202 if Result then
203 begin
204 g_Window_SetDisplay(Preserve);
205 ChangeWindowSize();
206 end;
207 end;
209 function WindowEventHandler(ev: TSDL_WindowEvent): Boolean;
210 var
211 wActivate, wDeactivate: Boolean;
212 begin
213 Result := False;
214 wActivate := False;
215 wDeactivate := False;
217 case ev.event of
218 SDL_WINDOWEVENT_MOVED:
219 begin
220 if not (gFullscreen or gWinMaximized) then
221 begin
222 gWinRealPosX := ev.data1;
223 gWinRealPosY := ev.data2;
224 end;
225 end;
227 SDL_WINDOWEVENT_MINIMIZED:
228 begin
229 curMsButState := 0;
230 curKbState := 0;
231 e_UnpressAllKeys();
232 if not wMinimized then
233 begin
234 e_ResizeWindow(0, 0);
235 wMinimized := True;
237 if g_debug_WinMsgs then
238 begin
239 g_Console_Add('Now minimized');
240 e_WriteLog('[DEBUG] WinMsgs: Now minimized', MSG_NOTIFY);
241 end;
242 wDeactivate := True;
243 end;
244 end;
246 SDL_WINDOWEVENT_RESIZED:
247 begin
248 curMsButState := 0;
249 curKbState := 0;
250 gScreenWidth := ev.data1;
251 gScreenHeight := ev.data2;
252 ChangeWindowSize();
253 SwapBuffers();
254 if g_debug_WinMsgs then
255 begin
256 g_Console_Add('Resized to ' + IntToStr(ev.data1) + 'x' + IntToStr(ev.data2));
257 e_WriteLog('[DEBUG] WinMsgs: Resized to ' + IntToStr(ev.data1) + 'x' + IntToStr(ev.data2), MSG_NOTIFY);
258 end;
259 end;
261 SDL_WINDOWEVENT_EXPOSED:
262 SwapBuffers();
264 SDL_WINDOWEVENT_MAXIMIZED:
265 begin
266 curMsButState := 0;
267 curKbState := 0;
268 if wMinimized then
269 begin
270 e_ResizeWindow(gScreenWidth, gScreenHeight);
271 wMinimized := False;
272 wActivate := True;
273 end;
274 if not gWinMaximized then
275 begin
276 gWinMaximized := True;
277 if g_debug_WinMsgs then
278 begin
279 g_Console_Add('Now maximized');
280 e_WriteLog('[DEBUG] WinMsgs: Now maximized', MSG_NOTIFY);
281 end;
282 end;
283 end;
285 SDL_WINDOWEVENT_RESTORED:
286 begin
287 curMsButState := 0;
288 curKbState := 0;
289 if wMinimized then
290 begin
291 e_ResizeWindow(gScreenWidth, gScreenHeight);
292 wMinimized := False;
293 wActivate := True;
294 end;
295 if gWinMaximized then
296 gWinMaximized := False;
297 if g_debug_WinMsgs then
298 begin
299 g_Console_Add('Now restored');
300 e_WriteLog('[DEBUG] WinMsgs: Now restored', MSG_NOTIFY);
301 end;
302 end;
304 SDL_WINDOWEVENT_FOCUS_GAINED:
305 begin
306 curMsButState := 0;
307 curKbState := 0;
308 wActivate := True;
309 //e_WriteLog('window gained focus!', MSG_NOTIFY);
310 g_Holmes_WindowFocused();
311 end;
313 SDL_WINDOWEVENT_FOCUS_LOST:
314 begin
315 curMsButState := 0;
316 curKbState := 0;
317 wDeactivate := True;
318 e_UnpressAllKeys();
319 //e_WriteLog('window lost focus!', MSG_NOTIFY);
320 g_Holmes_WindowBlured();
321 end;
322 end;
324 if wDeactivate then
325 begin
326 if gWinActive then
327 begin
328 e_WriteLog('deactivating window', MSG_NOTIFY);
329 e_EnableInput := False;
330 e_ClearInputBuffer();
332 if gMuteWhenInactive then
333 begin
334 //e_WriteLog('deactivating sounds', MSG_NOTIFY);
335 e_MuteChannels(True);
336 end;
338 if g_debug_WinMsgs then
339 begin
340 g_Console_Add('Now inactive');
341 e_WriteLog('[DEBUG] WinMsgs: Now inactive', MSG_NOTIFY);
342 end;
344 gWinActive := False;
345 end;
346 end
347 else if wActivate then
348 begin
349 if not gWinActive then
350 begin
351 //e_WriteLog('activating window', MSG_NOTIFY);
352 e_EnableInput := True;
354 if gMuteWhenInactive then
355 begin
356 //e_WriteLog('activating sounds', MSG_NOTIFY);
357 e_MuteChannels(False);
358 end;
360 if g_debug_WinMsgs then
361 begin
362 g_Console_Add('Now active');
363 e_WriteLog('[DEBUG] WinMsgs: Now active', MSG_NOTIFY);
364 end;
366 gWinActive := True;
367 end;
368 end;
369 end;
371 function EventHandler(ev: TSDL_Event): Boolean;
372 var
373 key, keychr: Word;
374 uc: UnicodeChar;
375 //joy: Integer;
376 msev: THMouseEvent;
377 kbev: THKeyEvent;
379 function buildBut (b: Byte): Word;
380 begin
381 result := 0;
382 case b of
383 SDL_BUTTON_LEFT: result := result or THMouseEvent.Left;
384 SDL_BUTTON_MIDDLE: result := result or THMouseEvent.Middle;
385 SDL_BUTTON_RIGHT: result := result or THMouseEvent.Right;
386 end;
387 end;
389 procedure updateKBState ();
390 var
391 kbstate: PUint8;
392 begin
393 curKbState := 0;
394 kbstate := SDL_GetKeyboardState(nil);
395 if (kbstate[SDL_SCANCODE_LCTRL] <> 0) or (kbstate[SDL_SCANCODE_RCTRL] <> 0) then curKbState := curKbState or THKeyEvent.ModCtrl;
396 if (kbstate[SDL_SCANCODE_LALT] <> 0) or (kbstate[SDL_SCANCODE_RALT] <> 0) then curKbState := curKbState or THKeyEvent.ModAlt;
397 if (kbstate[SDL_SCANCODE_LSHIFT] <> 0) or (kbstate[SDL_SCANCODE_RSHIFT] <> 0) then curKbState := curKbState or THKeyEvent.ModShift;
398 end;
400 begin
401 Result := False;
402 updateKBState();
404 case ev.type_ of
405 SDL_WINDOWEVENT:
406 Result := WindowEventHandler(ev.window);
408 SDL_QUITEV:
409 begin
410 if gExit <> EXIT_QUIT then
411 begin
412 if not wLoadingProgress then
413 begin
414 g_Game_Free();
415 g_Game_Quit();
416 end
417 else
418 wLoadingQuit := True;
419 end;
420 Result := True;
421 end;
423 SDL_KEYDOWN, SDL_KEYUP:
424 begin
425 key := ev.key.keysym.scancode;
426 if (g_holmes_enabled) then
427 begin
428 if (ev.type_ = SDL_KEYDOWN) then kbev.kind := THKeyEvent.Press else kbev.kind := THKeyEvent.Release;
429 kbev.scan := ev.key.keysym.scancode;
430 kbev.sym := ev.key.keysym.sym;
431 kbev.bstate := curMsButState;
432 kbev.kstate := curKbState;
433 {$IF not DEFINED(HEADLESS)}
434 if g_Holmes_keyEvent(kbev) then
435 begin
436 if (ev.type_ <> SDL_KEYDOWN) then e_KeyUpDown(ev.key.keysym.scancode, false);
437 exit;
438 end;
439 {$ENDIF}
440 end;
441 if (ev.type_ = SDL_KEYDOWN) then KeyPress(key);
442 e_KeyUpDown(ev.key.keysym.scancode, (ev.type_ = SDL_KEYDOWN));
443 end;
445 {$IF not DEFINED(HEADLESS)}
446 SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONUP:
447 begin
448 msev.dx := ev.button.x-curMsX;
449 msev.dy := ev.button.y-curMsY;
450 curMsX := ev.button.x;
451 curMsY := ev.button.y;
452 if (ev.type_ = SDL_MOUSEBUTTONDOWN) then msev.kind := THMouseEvent.Press else msev.kind := THMouseEvent.Release;
453 msev.but := buildBut(ev.button.button);
454 msev.x := curMsX;
455 msev.y := curMsY;
456 if (msev.but <> 0) then
457 begin
458 // ev.button.clicks: Byte
459 if (ev.type_ = SDL_MOUSEBUTTONDOWN) then curMsButState := curMsButState or msev.but else curMsButState := curMsButState and (not msev.but);
460 msev.bstate := curMsButState;
461 msev.kstate := curKbState;
462 if (g_holmes_enabled) then g_Holmes_mouseEvent(msev);
463 end;
464 end;
465 SDL_MOUSEWHEEL:
466 begin
467 if (ev.wheel.y <> 0) then
468 begin
469 msev.dx := 0;
470 msev.dy := ev.wheel.y;
471 msev.kind := THMouseEvent.Press;
472 if (ev.wheel.y < 0) then msev.but := THMouseEvent.WheelUp else msev.but := THMouseEvent.WheelDown;
473 msev.x := curMsX;
474 msev.y := curMsY;
475 msev.bstate := curMsButState;
476 msev.kstate := curKbState;
477 if (g_holmes_enabled) then g_Holmes_mouseEvent(msev);
478 end;
479 end;
480 SDL_MOUSEMOTION:
481 begin
482 msev.dx := ev.button.x-curMsX;
483 msev.dy := ev.button.y-curMsY;
484 curMsX := ev.button.x;
485 curMsY := ev.button.y;
486 msev.kind := THMouseEvent.Motion;
487 msev.but := 0;
488 msev.x := curMsX;
489 msev.y := curMsY;
490 msev.bstate := curMsButState;
491 msev.kstate := curKbState;
492 if (g_holmes_enabled) then g_Holmes_mouseEvent(msev);
493 end;
494 {$ENDIF}
496 SDL_TEXTINPUT:
497 begin
498 Utf8ToUnicode(@uc, PChar(ev.text.text), 1);
499 keychr := Word(uc);
500 if (keychr > 127) then keychr := Word(wchar2win(WideChar(keychr)));
501 CharPress(AnsiChar(keychr));
502 end;
504 // other key presses and joysticks are handled in e_input
505 end;
506 end;
508 procedure SwapBuffers();
509 begin
510 {$IFDEF HEADLESS}Exit;{$ENDIF}
511 SDL_GL_SwapWindow(h_Wnd);
512 end;
514 procedure KillGLWindow();
515 begin
516 if h_Wnd <> nil then SDL_DestroyWindow(h_Wnd);
517 if h_GL <> nil then SDL_GL_DeleteContext(h_GL);
518 h_Wnd := nil;
519 h_GL := nil;
520 //wWindowCreated := False;
521 end;
523 function CreateGLWindow(Title: PChar): Boolean;
524 //var
525 // flags: LongWord;
526 begin
527 Result := False;
529 gWinSizeX := gScreenWidth;
530 gWinSizeY := gScreenHeight;
532 wTitle := Title;
533 e_WriteLog('Creating window', MSG_NOTIFY);
535 if not g_Window_SetDisplay() then
536 begin
537 KillGLWindow();
538 e_WriteLog('Window creation error (resolution not supported?)', MSG_FATALERROR);
539 exit;
540 end;
542 {$IFNDEF HEADLESS}
543 h_Gl := SDL_GL_CreateContext(h_Wnd);
544 if h_Gl = nil then Exit;
545 {$ENDIF}
546 //wWindowCreated := True;
548 e_ResizeWindow(gScreenWidth, gScreenHeight);
549 e_InitGL();
551 Result := True;
552 end;
554 {$IFDEF WINDOWS}
555 // windoze sux; in headless mode `GetTickCount()` (and SDL) returns shit
556 function GetTimer(): Int64;
557 var
558 F, C: Int64;
559 begin
560 QueryPerformanceFrequency(F);
561 QueryPerformanceCounter(C);
562 Result := Round(C/F*1000{000});
563 end;
564 {$ELSE}
565 function GetTimer(): Int64;
566 var
567 t: Uint32;
568 tt: Int64;
569 begin
570 t := SDL_GetTicks() {* 1000}; // TODO: do we really need microseconds here? k8: NOPE!
571 if ticksOverflow = -1 then
572 begin
573 ticksOverflow := 0;
574 lastTicks := t;
575 end
576 else
577 begin
578 if lastTicks > t then
579 begin
580 // overflow, increment overflow ;-)
581 ticksOverflow := ticksOverflow+(Int64($ffffffff)+Int64(1));
582 tt := (Int64($ffffffff)+Int64(1))+Int64(t);
583 t := Uint32(tt-lastTicks);
584 end;
585 end;
586 lastTicks := t;
587 result := ticksOverflow+Int64(t);
588 end;
589 {$ENDIF}
591 procedure ResetTimer();
592 begin
593 wNeedTimeReset := True;
594 end;
596 procedure PushExitEvent();
597 var
598 ev: TSDL_Event;
599 begin
600 ev.type_ := SDL_QUITEV;
601 SDL_PushEvent(@ev);
602 end;
605 var
606 prevLoadingUpdateTime: UInt64 = 0;
608 procedure ProcessLoading (forceUpdate: Boolean=false);
609 var
610 ev: TSDL_Event;
611 ID: DWORD;
612 stt: UInt64;
613 begin
614 FillChar(ev, SizeOf(ev), 0);
615 //wNeedFree := False;
616 wLoadingProgress := True;
617 while SDL_PollEvent(@ev) > 0 do
618 begin
619 if (ev.type_ = SDL_QUITEV) then
620 break;
621 end;
622 //wNeedFree := True;
624 if (ev.type_ = SDL_QUITEV) or (gExit = EXIT_QUIT) then
625 begin
626 wLoadingProgress := False;
627 exit;
628 end;
630 if not wMinimized then
631 begin
632 if forceUpdate then
633 begin
634 prevLoadingUpdateTime := curTimeMilli();
635 end
636 else
637 begin
638 stt := curTimeMilli();
639 if (stt < prevLoadingUpdateTime) or (stt-prevLoadingUpdateTime >= 400) then
640 begin
641 prevLoadingUpdateTime := stt;
642 forceUpdate := true;
643 end;
644 end;
646 if forceUpdate then
647 begin
648 if g_Texture_Get('INTER', ID) then
649 begin
650 e_DrawSize(ID, 0, 0, 0, False, False, gScreenWidth, gScreenHeight)
651 end
652 else
653 begin
654 e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
655 end;
657 DrawLoadingStat();
658 SwapBuffers();
660 ReShowCursor();
661 end;
662 end;
664 e_SoundUpdate();
666 if NetMode = NET_SERVER then
667 begin
668 g_Net_Host_Update();
669 end
670 else
671 begin
672 if (NetMode = NET_CLIENT) and (NetState <> NET_STATE_AUTH) then g_Net_Client_UpdateWhileLoading();
673 end;
674 wLoadingProgress := False;
675 end;
677 function ProcessMessage(): Boolean;
678 var
679 i, t: Integer;
680 ev: TSDL_Event;
681 begin
682 Result := False;
683 FillChar(ev, SizeOf(ev), 0);
685 while SDL_PollEvent(@ev) > 0 do
686 begin
687 Result := EventHandler(ev);
688 if ev.type_ = SDL_QUITEV then exit;
689 end;
691 Time := GetTimer();
692 Time_Delta := Time - Time_Old;
694 flag := False;
696 if wNeedTimeReset then
697 begin
698 Time_Delta := 28{(27777 div 1000)};
699 wNeedTimeReset := False;
700 end;
702 g_Map_ProfilersBegin();
703 g_Mons_ProfilersBegin();
705 t := Time_Delta div 28{(27777 div 1000)};
706 if t > 0 then
707 begin
708 flag := True;
709 for i := 1 to t do
710 begin
711 if NetMode = NET_SERVER then g_Net_Host_Update()
712 else if NetMode = NET_CLIENT then g_Net_Client_Update();
713 Update();
714 end;
715 end
716 else
717 begin
718 if NetMode = NET_SERVER then g_Net_Host_Update()
719 else if NetMode = NET_CLIENT then g_Net_Client_Update();
720 end;
722 g_Map_ProfilersEnd();
723 g_Mons_ProfilersEnd();
725 if wLoadingQuit then
726 begin
727 g_Game_Free();
728 g_Game_Quit();
729 end;
731 if gExit = EXIT_QUIT then
732 begin
733 Result := True;
734 Exit;
735 end;
737 // Âðåìÿ ïðåäûäóùåãî îáíîâëåíèÿ:
738 if flag then
739 begin
740 Time_Old := Time - (Time_Delta mod 28{(27777 div 1000)});
741 if (not wMinimized) then
742 begin
743 Draw();
744 SwapBuffers();
745 ReShowCursor();
746 end;
747 end
748 else
749 Sleep(1);
751 e_SoundUpdate();
752 end;
754 procedure ReDrawWindow;
755 begin
756 SwapBuffers();
757 ReShowCursor();
758 end;
760 procedure InitOpenGL(VSync: Boolean);
761 var
762 v: Byte;
763 begin
764 {$IFDEF HEADLESS}Exit;{$ENDIF}
765 if VSync then v := 1 else v := 0;
766 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
767 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
768 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
769 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
770 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
771 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
772 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
773 if gwin_k8_enable_light_experiments then
774 begin
775 SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 1); // lights; it is enough to have 1-bit stencil buffer for lighting
776 end;
777 SDL_GL_SetSwapInterval(v);
778 end;
780 function glHasExtension (name: AnsiString): Boolean;
781 var
782 exts: PChar;
783 i: Integer;
784 found: Boolean;
785 extName: ShortString;
786 begin
787 result := false;
788 if length(name) = 0 then exit;
789 exts := glGetString(GL_EXTENSIONS);
790 if exts = nil then exit;
791 while (exts[0] <> #0) and (exts[0] = ' ') do Inc(exts);
792 while exts[0] <> #0 do
793 begin
794 if gwin_dump_extensions then
795 begin
796 i := 0;
797 while (exts[i] <> #0) and (exts[i] <> ' ') do Inc(i);
798 if i > 255 then
799 begin
800 e_WriteLog('FUUUUUUUUUUUUU', MSG_WARNING);
801 end
802 else
803 begin
804 Move(exts^, extName[1], i);
805 extName[0] := Char(i);
806 e_WriteLog(Format('EXT: %s', [extName]), MSG_NOTIFY);
807 end;
808 end;
809 found := true;
810 for i := 0 to length(name)-1 do
811 begin
812 if exts[i] = #0 then begin found := false; break; end;
813 if exts[i] <> name[i+1] then begin found := false; break; end;
814 end;
815 if found and ((exts[length(name)] = #0) or (exts[length(name)] = ' ')) then begin result := true; exit; end;
816 while (exts[0] <> #0) and (exts[0] <> ' ') do Inc(exts);
817 while (exts[0] <> #0) and (exts[0] = ' ') do Inc(exts);
818 end;
819 end;
821 function SDLMain(): Integer;
822 var
823 idx: Integer;
824 ltmp: Integer;
825 arg: AnsiString;
826 mdfo: TStream;
827 begin
828 {$IFDEF HEADLESS}
829 e_NoGraphics := True;
830 {$ENDIF}
832 idx := 1;
833 while (idx <= ParamCount) do
834 begin
835 arg := ParamStr(idx);
836 Inc(idx);
837 if arg = '--opengl-dump-exts' then gwin_dump_extensions := true;
838 if arg = '--twinkletwinkle' then gwin_k8_enable_light_experiments := true;
839 if arg = '--jah' then g_profile_history_size := 100;
840 if arg = '--no-particles' then gpart_dbg_enabled := false;
841 if arg = '--no-los' then gmon_dbg_los_enabled := false;
843 if arg = '--profile-render' then g_profile_frame_draw := true;
844 if arg = '--profile-coldet' then g_profile_collision := true;
845 if arg = '--profile-los' then g_profile_los := true;
847 if arg = '--no-part-phys' then gpart_dbg_phys_enabled := false;
848 if arg = '--no-part-physics' then gpart_dbg_phys_enabled := false;
849 if arg = '--no-particles-phys' then gpart_dbg_phys_enabled := false;
850 if arg = '--no-particles-physics' then gpart_dbg_phys_enabled := false;
851 if arg = '--no-particle-phys' then gpart_dbg_phys_enabled := false;
852 if arg = '--no-particle-physics' then gpart_dbg_phys_enabled := false;
854 {$IF DEFINED(D2F_DEBUG)}
855 if arg = '--aimline' then g_dbg_aimline_on := false;
856 {$ENDIF}
858 if arg = '--holmes' then begin g_holmes_enabled := true; g_Game_SetDebugMode(); end;
859 if (arg = '--holmes-ui-scale') or (arg = '-holmes-ui-scale') then
860 begin
861 if (idx <= ParamCount) then
862 begin
863 if not conParseFloat(g_holmes_ui_scale, ParamStr(idx)) then g_holmes_ui_scale := 1.0;
864 Inc(idx);
865 end;
866 end;
868 {$IF DEFINED(D2F_DEBUG)}
869 if (arg = '--game-scale') or (arg = '-game-scale') then
870 begin
871 if (idx <= ParamCount) then
872 begin
873 if not conParseFloat(g_dbg_scale, ParamStr(idx)) then g_dbg_scale := 1.0;
874 Inc(idx);
875 end;
876 end;
877 {$ENDIF}
879 if (arg = '--write-mapdef') or (arg = '-write-mapdef') then
880 begin
881 mdfo := createDiskFile('mapdef.txt');
882 mdfo.WriteBuffer(defaultMapDef[1], Length(defaultMapDef));
883 mdfo.Free();
884 Halt(0);
885 end;
886 end;
888 e_WriteLog('Initializing OpenGL', MSG_NOTIFY);
889 InitOpenGL(gVSync);
891 e_WriteLog('Creating GL window', MSG_NOTIFY);
892 if not CreateGLWindow(PChar(Format('Doom 2D: Forever %s', [GAME_VERSION]))) then
893 begin
894 Result := 0;
895 exit;
896 end;
898 {EnumDisplayModes();}
900 if gwin_k8_enable_light_experiments then
901 begin
902 SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, @ltmp);
903 e_WriteLog(Format('stencil buffer size: %d', [ltmp]), MSG_WARNING);
904 gwin_has_stencil := (ltmp > 0);
905 end
906 else
907 begin
908 gwin_has_stencil := false;
909 end;
911 if not glHasExtension('GL_ARB_texture_non_power_of_two') then
912 begin
913 e_WriteLog('Driver DID''T advertised NPOT textures support', MSG_WARNING);
914 glLegacyNPOT := true;
915 end
916 else
917 begin
918 e_WriteLog('Driver advertised NPOT textures support', MSG_NOTIFY);
919 glLegacyNPOT := false;
920 end;
921 gwin_dump_extensions := false;
923 Init();
924 Time_Old := GetTimer();
926 // Êîìàíäíàÿ ñòðîêà:
927 if ParamCount > 0 then
928 g_Game_Process_Params();
930 // Çàïðîñ ÿçûêà:
931 if (not gGameOn) and gAskLanguage then
932 g_Menu_AskLanguage();
934 e_WriteLog('Entering the main loop', MSG_NOTIFY);
936 while not ProcessMessage() do
937 { Main Loop } ;
939 Release();
940 KillGLWindow();
942 Result := 0;
943 end;
945 end.