DEADSOFTWARE

initial commit:
[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 SDL, 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_Surface;
32 wFlags: LongWord = 0;
33 Time, Time_Delta, Time_Old: Int64;
34 flag: Boolean;
35 wNeedTimeReset: Boolean = False;
36 wWindowCreated: Boolean = False;
37 //wCursorShown: Boolean = False;
38 wMinimized: Boolean = False;
39 //wNeedFree: Boolean = True;
40 wLoadingProgress: Boolean = False;
41 wLoadingQuit: Boolean = False;
42 {wWinPause: Byte = 0;}
44 const
45 // TODO: move this to a separate file
46 CP1251: array [0..127] of Word = (
47 $0402,$0403,$201A,$0453,$201E,$2026,$2020,$2021,$20AC,$2030,$0409,$2039,$040A,$040C,$040B,$040F,
48 $0452,$2018,$2019,$201C,$201D,$2022,$2013,$2014,$003F,$2122,$0459,$203A,$045A,$045C,$045B,$045F,
49 $00A0,$040E,$045E,$0408,$00A4,$0490,$00A6,$00A7,$0401,$00A9,$0404,$00AB,$00AC,$00AD,$00AE,$0407,
50 $00B0,$00B1,$0406,$0456,$0491,$00B5,$00B6,$00B7,$0451,$2116,$0454,$00BB,$0458,$0405,$0455,$0457,
51 $0410,$0411,$0412,$0413,$0414,$0415,$0416,$0417,$0418,$0419,$041A,$041B,$041C,$041D,$041E,$041F,
52 $0420,$0421,$0422,$0423,$0424,$0425,$0426,$0427,$0428,$0429,$042A,$042B,$042C,$042D,$042E,$042F,
53 $0430,$0431,$0432,$0433,$0434,$0435,$0436,$0437,$0438,$0439,$043A,$043B,$043C,$043D,$043E,$043F,
54 $0440,$0441,$0442,$0443,$0444,$0445,$0446,$0447,$0448,$0449,$044A,$044B,$044C,$044D,$044E,$044F
55 );
57 // TODO: make a transition table or something
58 function WCharToCP1251(wc: Word): Word;
59 begin
60 for Result := 0 to 127 do
61 if CP1251[Result] = wc then
62 break;
63 Result := Result + 128;
64 end;
66 function g_Window_SetDisplay(PreserveGL: Boolean = False): Boolean;
67 begin
68 Result := False;
70 e_WriteLog('Setting display mode...', MSG_NOTIFY);
72 if wWindowCreated and PreserveGL then
73 e_SaveGLContext(); // we need this and restore because of a bug in SDL1.2, apparently
75 wFlags := SDL_RESIZABLE or SDL_OPENGL;
76 if gFullscreen then wFlags := wFlags or SDL_FULLSCREEN;
78 h_Wnd := SDL_SetVideoMode(gScreenWidth, gScreenHeight, gBPP, wFlags);
79 SDL_EnableUNICODE(SDL_ENABLE);
80 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
81 SDL_ShowCursor(SDL_DISABLE);
83 if wWindowCreated and PreserveGL then
84 e_RestoreGLContext();
86 Result := h_Wnd <> nil;
87 end;
89 procedure ReShowCursor();
90 begin
91 // TODO: what was this for?
92 end;
94 function GetDisplayModes(dBPP: DWORD; var SelRes: DWORD): SArray;
95 var
96 modesp: PPSDL_Rect;
97 tmpp: PSDL_Rect;
98 tmpr: SDL_Rect;
99 i: Integer;
100 begin
101 SetLength(Result, 0);
102 modesp := SDL_ListModes(nil, SDL_FULLSCREEN or SDL_HWSURFACE);
103 if modesp = nil then exit;
104 if Pointer(-1) = modesp then exit;
106 tmpp := modesp^;
107 i := 0;
108 while tmpp <> nil do
109 begin
110 tmpr := tmpp^;
111 if (tmpr.w = gScreenWidth) and (tmpr.h = gScreenHeight) then
112 SelRes := i;
113 SetLength(Result, Length(Result) + 1);
114 Result[i] := IntToStr(tmpr.w) + 'x' + IntToStr(tmpr.h);
116 modesp := Pointer(Cardinal(modesp) + SizeOf(PSDL_Rect));
117 tmpp := modesp^;
118 Inc(i);
119 end;
121 e_WriteLog('SDL: Got ' + IntToStr(Length(Result)) + ' resolutions.', MSG_NOTIFY);
122 end;
124 procedure Sleep(ms: LongWord);
125 begin
126 SDL_Delay(ms);
127 end;
129 procedure ChangeWindowSize();
130 begin
131 gWinSizeX := gScreenWidth;
132 gWinSizeY := gScreenHeight;
133 e_ResizeWindow(gScreenWidth, gScreenHeight);
134 g_Game_SetupScreenSize();
135 g_Menu_Reset();
136 g_Game_ClearLoading();
137 end;
139 function g_Window_SetSize(W, H: Word; FScreen: Boolean): Boolean;
140 var
141 Preserve: Boolean;
142 begin
143 Result := False;
144 Preserve := False;
146 if (gScreenWidth <> W) or (gScreenHeight <> H) then
147 begin
148 Result := True;
149 gScreenWidth := W;
150 gScreenHeight := H;
151 end;
153 if gFullscreen <> FScreen then
154 begin
155 Result := True;
156 gFullscreen := FScreen;
157 Preserve := True;
158 end;
160 if Result then
161 begin
162 g_Window_SetDisplay(Preserve);
163 ChangeWindowSize();
164 end;
165 end;
167 function EventHandler(ev: TSDL_Event): Boolean;
168 var
169 key, keychr: Word;
170 //joy: Integer;
171 begin
172 Result := False;
173 case ev.type_ of
174 SDL_VIDEORESIZE:
175 begin
176 g_Window_SetSize(ev.resize.w, ev.resize.h, gFullscreen);
177 e_Clear();
178 end;
180 SDL_ACTIVEEVENT:
181 begin
182 if (ev.active.gain = 0) then
183 begin
184 if g_debug_WinMsgs then
185 begin
186 g_Console_Add('Inactive');
187 e_WriteLog('[DEBUG] WinMsgs: Inactive', MSG_NOTIFY);
188 end;
190 if LongBool(ev.active.state and SDL_APPINPUTFOCUS) and gWinActive then
191 begin
192 e_EnableInput := False;
193 e_ClearInputBuffer();
195 if gMuteWhenInactive then
196 e_MuteChannels(True);
198 if g_debug_WinMsgs then
199 begin
200 g_Console_Add('Inactive indeed');
201 e_WriteLog('[DEBUG] WinMsgs: Inactive indeed', MSG_NOTIFY);
202 end;
204 gWinActive := False;
205 end;
207 if LongBool(ev.active.state and SDL_APPACTIVE) and (not wMinimized) then
208 begin
209 e_ResizeWindow(0, 0);
210 wMinimized := True;
212 if g_debug_WinMsgs then
213 begin
214 g_Console_Add('Minimized indeed');
215 e_WriteLog('[DEBUG] WinMsgs: Minimized indeed', MSG_NOTIFY);
216 end;
217 end;
218 end
219 else
220 begin
221 if g_debug_WinMsgs then
222 begin
223 g_Console_Add('Active');
224 e_WriteLog('[DEBUG] WinMsgs: Active', MSG_NOTIFY);
225 end;
227 // Åñëè îêíî áûëî íåàêòèâíûì:
228 if LongBool(ev.active.state and SDL_APPINPUTFOCUS) and (not gWinActive) then
229 begin
230 e_EnableInput := True;
232 if gMuteWhenInactive then
233 e_MuteChannels(False);
235 if g_debug_WinMsgs then
236 begin
237 g_Console_Add('Active indeed');
238 e_WriteLog('[DEBUG] WinMsgs: Active indeed', MSG_NOTIFY);
239 end;
241 gWinActive := True;
242 end;
244 if LongBool(ev.active.state and SDL_APPACTIVE) and wMinimized then
245 begin
246 e_ResizeWindow(gScreenWidth, gScreenHeight);
248 wMinimized := False;
250 if g_debug_WinMsgs then
251 begin
252 g_Console_Add('Restored indeed');
253 e_WriteLog('[DEBUG] WinMsgs: Restored indeed', MSG_NOTIFY);
254 end;
255 end;
256 end;
257 end;
259 SDL_VIDEOEXPOSE:
260 begin
261 // TODO: the fuck is this event?
262 // Draw();
263 end;
265 SDL_QUITEV:
266 begin
267 if gExit <> EXIT_QUIT then
268 begin
269 if not wLoadingProgress then
270 begin
271 g_Game_Free();
272 g_Game_Quit();
273 end
274 else
275 wLoadingQuit := True;
276 end;
277 Result := True;
278 end;
280 SDL_KEYDOWN:
281 begin
282 key := ev.key.keysym.sym;
283 keychr := ev.key.keysym.unicode;
284 KeyPress(key);
285 if (keychr > 7) and (key <> IK_BACKSPACE) then
286 begin
287 if (keychr >= 128) then
288 keychr := WCharToCP1251(keychr);
289 CharPress(Chr(keychr));
290 end;
291 end;
293 // key presses and joysticks are handled in e_input
294 end;
295 end;
297 procedure SwapBuffers();
298 begin
299 SDL_GL_SwapBuffers();
300 end;
302 procedure KillGLWindow();
303 begin
304 wWindowCreated := False;
305 end;
307 function CreateGLWindow(Title: PChar): Boolean;
308 //var
309 // flags: LongWord;
310 begin
311 Result := False;
313 gWinSizeX := gScreenWidth;
314 gWinSizeY := gScreenHeight;
316 e_WriteLog('Creating window', MSG_NOTIFY);
318 if not g_Window_SetDisplay() then
319 begin
320 KillGLWindow();
321 e_WriteLog('Window creation error (resolution not supported?)', MSG_FATALERROR);
322 exit;
323 end;
325 SDL_WM_SetCaption(Title, Title);
326 wWindowCreated := True;
328 e_ResizeWindow(gScreenWidth, gScreenHeight);
329 e_InitGL();
331 Result := True;
332 end;
334 function GetTimer(): Int64;
335 begin
336 Result := SDL_GetTicks() * 1000; // TODO: do we really need microseconds here?
337 end;
339 procedure ResetTimer();
340 begin
341 wNeedTimeReset := True;
342 end;
344 procedure PushExitEvent();
345 var
346 ev: TSDL_Event;
347 begin
348 ev.type_ := SDL_QUITEV;
349 SDL_PushEvent(@ev);
350 end;
352 procedure ProcessLoading();
353 var
354 ev: TSDL_Event;
355 ID: DWORD;
356 begin
357 //wNeedFree := False;
358 wLoadingProgress := True;
359 while SDL_PollEvent(@ev) > 0 do
360 begin
361 if (ev.type_ = SDL_QUITEV) then
362 break;
363 end;
364 //wNeedFree := True;
366 if (ev.type_ = SDL_QUITEV) or (gExit = EXIT_QUIT) then
367 begin
368 wLoadingProgress := False;
369 exit;
370 end;
372 if not wMinimized then
373 begin
374 if g_Texture_Get('INTER', ID) then
375 e_DrawSize(ID, 0, 0, 0, False, False, gScreenWidth, gScreenHeight)
376 else
377 e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
379 DrawLoadingStat();
380 SwapBuffers();
382 ReShowCursor();
383 end;
385 e_SoundUpdate();
387 if NetMode = NET_SERVER then
388 g_Net_Host_Update
389 else
390 if (NetMode = NET_CLIENT) and (NetState <> NET_STATE_AUTH) then
391 g_Net_Client_UpdateWhileLoading;
392 wLoadingProgress := False;
393 end;
395 function ProcessMessage(): Boolean;
396 var
397 i, t: Integer;
398 ev: TSDL_Event;
399 begin
400 Result := False;
402 while SDL_PollEvent(@ev) > 0 do
403 begin
404 Result := EventHandler(ev);
405 if ev.type_ = SDL_QUITEV then exit;
406 end;
408 Time := GetTimer();
409 Time_Delta := Time - Time_Old;
411 flag := False;
413 if wNeedTimeReset then
414 begin
415 Time_Delta := 27777;
416 wNeedTimeReset := False;
417 end;
419 t := Time_Delta div 27777;
420 if t > 0 then
421 begin
422 flag := True;
423 for i := 1 to t do
424 begin
425 if NetMode = NET_SERVER then g_Net_Host_Update()
426 else if NetMode = NET_CLIENT then g_Net_Client_Update();
427 Update();
428 end;
429 end
430 else
431 begin
432 if NetMode = NET_SERVER then g_Net_Host_Update()
433 else if NetMode = NET_CLIENT then g_Net_Client_Update();
434 end;
436 if wLoadingQuit then
437 begin
438 g_Game_Free();
439 g_Game_Quit();
440 end;
442 if gExit = EXIT_QUIT then
443 begin
444 Result := True;
445 Exit;
446 end;
448 // Âðåìÿ ïðåäûäóùåãî îáíîâëåíèÿ:
449 if flag then
450 begin
451 Time_Old := Time - (Time_Delta mod 27777);
452 if (not wMinimized) then
453 begin
454 Draw();
455 SwapBuffers();
456 ReShowCursor();
457 end;
458 end
459 else
460 Sleep(1);
462 e_SoundUpdate();
463 end;
465 procedure ReDrawWindow;
466 begin
467 SwapBuffers();
468 ReShowCursor();
469 end;
471 procedure InitOpenGL(VSync: Boolean);
472 var
473 v: Byte;
474 begin
475 if VSync then v := 1 else v := 0;
476 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
477 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
478 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
479 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
480 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
481 SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, v);
482 end;
484 function SDLMain(): Integer;
485 begin
486 e_WriteLog('Creating GL window', MSG_NOTIFY);
487 if not CreateGLWindow(PChar(Format('Doom 2D: Forever %s', [GAME_VERSION]))) then
488 begin
489 Result := 0;
490 exit;
491 end;
493 e_WriteLog('Initializing OpenGL', MSG_NOTIFY);
494 InitOpenGL(gVSync);
496 {EnumDisplayModes();}
498 Init();
499 Time_Old := GetTimer();
501 // Êîìàíäíàÿ ñòðîêà:
502 if ParamCount > 0 then
503 g_Game_Process_Params();
505 // Çàïðîñ ÿçûêà:
506 if (not gGameOn) and gAskLanguage then
507 g_Menu_AskLanguage();
509 e_WriteLog('Entering the main loop', MSG_NOTIFY);
511 while not ProcessMessage() do
512 { Main Loop } ;
514 Release();
515 KillGLWindow();
517 Result := 0;
518 end;
520 end.