DEADSOFTWARE

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