DEADSOFTWARE

render: move more texture load code into render
[d2df-sdl.git] / src / game / opengl / r_game.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, version 3 of the License ONLY.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 *)
15 {$INCLUDE ../../shared/a_modes.inc}
16 unit r_game;
18 interface
20 procedure r_Game_Load;
21 procedure r_Game_Free;
23 procedure r_Game_LoadTextures;
24 procedure r_Game_FreeTextures;
26 procedure r_Game_Draw;
27 procedure r_Game_DrawLoadingStat;
28 procedure r_Game_DrawMenuBackground (tex: AnsiString);
30 var
31 gStdFont: DWORD;
33 implementation
35 uses
36 {$INCLUDE ../nogl/noGLuses.inc}
37 {$IFDEF ENABLE_HOLMES}
38 g_holmes,
39 {$ENDIF}
40 SysUtils, Classes, Math,
41 g_base, r_graphics,
42 g_system, g_touch,
43 MAPDEF, xprofiler, utils, wadreader,
44 e_input, e_sound,
45 g_language, g_console, g_menu, g_triggers, g_player, g_options, g_monsters, g_map, g_panel,
46 g_items, g_weapons, g_gfx, g_phys, g_net, g_gui, g_netmaster,
47 g_game, r_console, r_gfx, r_items, r_map, r_monsters, r_weapons, r_netmaster, r_player, r_textures,
48 r_playermodel
49 ;
51 var
52 profileFrameDraw: TProfiler = nil;
54 FPS: Word;
55 FPSCounter: Word;
56 FPSTime: LongWord;
57 hasPBarGfx: Boolean;
59 procedure r_Game_Load;
60 var
61 wl, hl: Integer;
62 wr, hr: Integer;
63 wb, hb: Integer;
64 wm, hm: Integer;
65 begin
66 // early load
67 g_Texture_CreateWADEx('MENU_BACKGROUND', GameWAD + ':TEXTURES\TITLE', gTextureFilter);
68 g_Texture_CreateWADEx('INTER', GameWAD + ':TEXTURES\INTER', gTextureFilter);
69 g_Texture_CreateWADEx('ENDGAME_EN', GameWAD + ':TEXTURES\ENDGAME_EN', gTextureFilter);
70 g_Texture_CreateWADEx('ENDGAME_RU', GameWAD + ':TEXTURES\ENDGAME_RU', gTextureFilter);
71 LoadStdFont('STDTXT', 'STDFONT', gStdFont);
72 LoadFont('MENUTXT', 'MENUFONT', gMenuFont);
73 LoadFont('SMALLTXT', 'SMALLFONT', gMenuSmallFont);
74 // game data
75 g_Texture_CreateWADEx('NOTEXTURE', GameWAD + ':TEXTURES\NOTEXTURE');
76 g_Texture_CreateWADEx('TEXTURE_PLAYER_HUD', GameWAD + ':TEXTURES\HUD');
77 g_Texture_CreateWADEx('TEXTURE_PLAYER_HUDAIR', GameWAD + ':TEXTURES\AIRBAR');
78 g_Texture_CreateWADEx('TEXTURE_PLAYER_HUDJET', GameWAD + ':TEXTURES\JETBAR');
79 g_Texture_CreateWADEx('TEXTURE_PLAYER_HUDBG', GameWAD + ':TEXTURES\HUDBG');
80 g_Texture_CreateWADEx('TEXTURE_PLAYER_ARMORHUD', GameWAD + ':TEXTURES\ARMORHUD');
81 g_Texture_CreateWADEx('TEXTURE_PLAYER_REDFLAG', GameWAD + ':TEXTURES\FLAGHUD_R_BASE');
82 g_Texture_CreateWADEx('TEXTURE_PLAYER_REDFLAG_S', GameWAD + ':TEXTURES\FLAGHUD_R_STOLEN');
83 g_Texture_CreateWADEx('TEXTURE_PLAYER_REDFLAG_D', GameWAD + ':TEXTURES\FLAGHUD_R_DROP');
84 g_Texture_CreateWADEx('TEXTURE_PLAYER_BLUEFLAG', GameWAD + ':TEXTURES\FLAGHUD_B_BASE');
85 g_Texture_CreateWADEx('TEXTURE_PLAYER_BLUEFLAG_S', GameWAD + ':TEXTURES\FLAGHUD_B_STOLEN');
86 g_Texture_CreateWADEx('TEXTURE_PLAYER_BLUEFLAG_D', GameWAD + ':TEXTURES\FLAGHUD_B_DROP');
87 g_Texture_CreateWADEx('TEXTURE_PLAYER_TALKBUBBLE', GameWAD + ':TEXTURES\TALKBUBBLE');
88 g_Texture_CreateWADEx('TEXTURE_PLAYER_INVULPENTA', GameWAD + ':TEXTURES\PENTA');
89 g_Texture_CreateWADEx('TEXTURE_PLAYER_INDICATOR', GameWAD + ':TEXTURES\PLRIND');
90 // bar
91 hasPBarGfx := true;
92 if not g_Texture_CreateWADEx('UI_GFX_PBAR_LEFT', GameWAD+':TEXTURES\LLEFT') then hasPBarGfx := false;
93 if not g_Texture_CreateWADEx('UI_GFX_PBAR_MARKER', GameWAD+':TEXTURES\LMARKER') then hasPBarGfx := false;
94 if not g_Texture_CreateWADEx('UI_GFX_PBAR_MIDDLE', GameWAD+':TEXTURES\LMIDDLE') then hasPBarGfx := false;
95 if not g_Texture_CreateWADEx('UI_GFX_PBAR_RIGHT', GameWAD+':TEXTURES\LRIGHT') then hasPBarGfx := false;
96 if hasPBarGfx then
97 begin
98 g_Texture_GetSize('UI_GFX_PBAR_LEFT', wl, hl);
99 g_Texture_GetSize('UI_GFX_PBAR_RIGHT', wr, hr);
100 g_Texture_GetSize('UI_GFX_PBAR_MIDDLE', wb, hb);
101 g_Texture_GetSize('UI_GFX_PBAR_MARKER', wm, hm);
102 if (wl > 0) and (hl > 0) and (wr > 0) and (hr = hl) and (wb > 0) and (hb = hl) and (wm > 0) and (hm > 0) and (hm <= hl) then
103 begin
104 // yay!
105 end
106 else
107 hasPBarGfx := false;
108 end;
109 end;
111 procedure r_Game_Free;
112 begin
113 g_Texture_Delete('NOTEXTURE');
114 g_Texture_Delete('TEXTURE_PLAYER_HUD');
115 g_Texture_Delete('TEXTURE_PLAYER_HUDBG');
116 g_Texture_Delete('TEXTURE_PLAYER_ARMORHUD');
117 g_Texture_Delete('TEXTURE_PLAYER_REDFLAG');
118 g_Texture_Delete('TEXTURE_PLAYER_REDFLAG_S');
119 g_Texture_Delete('TEXTURE_PLAYER_REDFLAG_D');
120 g_Texture_Delete('TEXTURE_PLAYER_BLUEFLAG');
121 g_Texture_Delete('TEXTURE_PLAYER_BLUEFLAG_S');
122 g_Texture_Delete('TEXTURE_PLAYER_BLUEFLAG_D');
123 g_Texture_Delete('TEXTURE_PLAYER_TALKBUBBLE');
124 g_Texture_Delete('TEXTURE_PLAYER_INVULPENTA');
125 end;
127 procedure r_Game_LoadTextures;
128 begin
129 g_Texture_CreateWADEx('TEXTURE_endpic', EndPicPath, gTextureFilter);
130 end;
132 procedure r_Game_FreeTextures;
133 begin
134 g_Texture_Delete('TEXTURE_endpic')
135 end;
137 function GetActivePlayer_ByID(ID: Integer): TPlayer;
138 var
139 a: Integer;
140 begin
141 Result := nil;
142 if ID < 0 then
143 Exit;
144 if gPlayers = nil then
145 Exit;
146 for a := Low(gPlayers) to High(gPlayers) do
147 if IsActivePlayer(gPlayers[a]) then
148 begin
149 if gPlayers[a].UID <> ID then
150 continue;
151 Result := gPlayers[a];
152 break;
153 end;
154 end;
156 function calcProfilesHeight (prof: TProfiler): Integer;
157 begin
158 result := 0;
159 if (prof = nil) then exit;
160 if (length(prof.bars) = 0) then exit;
161 result := length(prof.bars)*(16+2);
162 end;
164 // returns width
165 function drawProfiles (x, y: Integer; prof: TProfiler): Integer;
166 var
167 wdt, hgt: Integer;
168 yy: Integer;
169 ii: Integer;
170 begin
171 result := 0;
172 if (prof = nil) then exit;
173 // gScreenWidth
174 if (length(prof.bars) = 0) then exit;
175 wdt := 192;
176 hgt := calcProfilesHeight(prof);
177 if (x < 0) then x := gScreenWidth-(wdt-1)+x;
178 if (y < 0) then y := gScreenHeight-(hgt-1)+y;
179 // background
180 //e_DrawFillQuad(x, y, x+wdt-1, y+hgt-1, 255, 255, 255, 200, B_BLEND);
181 //e_DrawFillQuad(x, y, x+wdt-1, y+hgt-1, 20, 20, 20, 0, B_NONE);
182 e_DarkenQuadWH(x, y, wdt, hgt, 150);
183 // title
184 yy := y+2;
185 for ii := 0 to High(prof.bars) do
186 begin
187 e_TextureFontPrintEx(x+2+4*prof.bars[ii].level, yy, Format('%s: %d', [prof.bars[ii].name, prof.bars[ii].value]), gStdFont, 255, 255, 0, 1, false);
188 Inc(yy, 16+2);
189 end;
190 result := wdt;
191 end;
193 procedure drawTime(X, Y: Integer); inline;
194 begin
195 e_TextureFontPrint(x, y, Format('%d:%.2d:%.2d', [gTime div 1000 div 3600, (gTime div 1000 div 60) mod 60, gTime div 1000 mod 60]), gStdFont);
196 end;
198 procedure DrawStat();
199 var
200 pc, x, y, w, h: Integer;
201 w1, w2, w3, w4: Integer;
202 a, aa: Integer;
203 cw, ch, r, g, b, rr, gg, bb: Byte;
204 s1, s2, s3: String;
205 _y: Integer;
206 stat: TPlayerStatArray;
207 wad, map: string;
208 mapstr: string;
209 namestr: string;
210 begin
211 s1 := '';
212 s2 := '';
213 s3 := '';
214 pc := g_Player_GetCount;
215 e_TextureFontGetSize(gStdFont, cw, ch);
217 w := gScreenWidth-(gScreenWidth div 5);
218 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
219 h := 32+ch*(11+pc)
220 else
221 h := 40+ch*5+(ch+8)*pc;
222 x := (gScreenWidth div 2)-(w div 2);
223 y := (gScreenHeight div 2)-(h div 2);
225 e_DrawFillQuad(x, y, x+w-1, y+h-1, 64, 64, 64, 32);
226 e_DrawQuad(x, y, x+w-1, y+h-1, 255, 127, 0);
228 drawTime(x+w-78, y+8);
230 wad := g_ExtractWadNameNoPath(gMapInfo.Map);
231 map := g_ExtractFileName(gMapInfo.Map);
232 mapstr := wad + ':\' + map + ' - ' + gMapInfo.Name;
234 case gGameSettings.GameMode of
235 GM_DM:
236 begin
237 if gGameSettings.MaxLives = 0 then
238 s1 := _lc[I_GAME_DM]
239 else
240 s1 := _lc[I_GAME_LMS];
241 s2 := Format(_lc[I_GAME_FRAG_LIMIT], [gGameSettings.GoalLimit]);
242 s3 := Format(_lc[I_GAME_TIME_LIMIT], [gGameSettings.TimeLimit div 3600, (gGameSettings.TimeLimit div 60) mod 60, gGameSettings.TimeLimit mod 60]);
243 end;
245 GM_TDM:
246 begin
247 if gGameSettings.MaxLives = 0 then
248 s1 := _lc[I_GAME_TDM]
249 else
250 s1 := _lc[I_GAME_TLMS];
251 s2 := Format(_lc[I_GAME_FRAG_LIMIT], [gGameSettings.GoalLimit]);
252 s3 := Format(_lc[I_GAME_TIME_LIMIT], [gGameSettings.TimeLimit div 3600, (gGameSettings.TimeLimit div 60) mod 60, gGameSettings.TimeLimit mod 60]);
253 end;
255 GM_CTF:
256 begin
257 s1 := _lc[I_GAME_CTF];
258 s2 := Format(_lc[I_GAME_SCORE_LIMIT], [gGameSettings.GoalLimit]);
259 s3 := Format(_lc[I_GAME_TIME_LIMIT], [gGameSettings.TimeLimit div 3600, (gGameSettings.TimeLimit div 60) mod 60, gGameSettings.TimeLimit mod 60]);
260 end;
262 GM_COOP:
263 begin
264 if gGameSettings.MaxLives = 0 then
265 s1 := _lc[I_GAME_COOP]
266 else
267 s1 := _lc[I_GAME_SURV];
268 s2 := _lc[I_GAME_MONSTERS] + ' ' + IntToStr(gCoopMonstersKilled) + '/' + IntToStr(gTotalMonsters);
269 s3 := _lc[I_GAME_SECRETS] + ' ' + IntToStr(gCoopSecretsFound) + '/' + IntToStr(gSecretsCount);
270 end;
272 else
273 begin
274 s1 := '';
275 s2 := '';
276 end;
277 end;
278 _y := y+8;
279 e_TextureFontPrintEx(x+(w div 2)-(Length(s1)*cw div 2), _y, s1, gStdFont, 255, 255, 255, 1);
280 _y := _y+ch+8;
281 e_TextureFontPrintEx(x+(w div 2)-(Length(mapstr)*cw div 2), _y, mapstr, gStdFont, 200, 200, 200, 1);
282 _y := _y+ch+8;
283 e_TextureFontPrintEx(x+16, _y, s2, gStdFont, 200, 200, 200, 1);
285 e_TextureFontPrintEx(x+w-16-(Length(s3))*cw, _y, s3,
286 gStdFont, 200, 200, 200, 1);
288 if NetMode = NET_SERVER then
289 e_TextureFontPrintEx(x+8, y + 8, _lc[I_NET_SERVER], gStdFont, 255, 255, 255, 1)
290 else
291 if NetMode = NET_CLIENT then
292 e_TextureFontPrintEx(x+8, y + 8,
293 NetClientIP + ':' + IntToStr(NetClientPort), gStdFont, 255, 255, 255, 1);
295 if pc = 0 then
296 Exit;
297 stat := g_Player_GetStats();
298 SortGameStat(stat);
300 w2 := (w-16) div 6 + 48; // ширина 2 столбца
301 w3 := (w-16) div 6; // ширина 3 и 4 столбцов
302 w4 := w3;
303 w1 := w-16-w2-w3-w4; // оставшееся пространство - для цвета и имени игрока
305 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
306 begin
307 _y := _y+ch+ch;
309 for a := TEAM_RED to TEAM_BLUE do
310 begin
311 if a = TEAM_RED then
312 begin
313 s1 := _lc[I_GAME_TEAM_RED];
314 r := 255;
315 g := 0;
316 b := 0;
317 end
318 else
319 begin
320 s1 := _lc[I_GAME_TEAM_BLUE];
321 r := 0;
322 g := 0;
323 b := 255;
324 end;
326 e_TextureFontPrintEx(x+16, _y, s1, gStdFont, r, g, b, 1);
327 e_TextureFontPrintEx(x+w1+16, _y, IntToStr(gTeamStat[a].Goals),
328 gStdFont, r, g, b, 1);
330 _y := _y+ch+(ch div 4);
331 e_DrawLine(1, x+16, _y, x+w-16, _y, r, g, b);
332 _y := _y+(ch div 4);
334 for aa := 0 to High(stat) do
335 if stat[aa].Team = a then
336 with stat[aa] do
337 begin
338 if Spectator then
339 begin
340 rr := r div 2;
341 gg := g div 2;
342 bb := b div 2;
343 end
344 else
345 begin
346 rr := r;
347 gg := g;
348 bb := b;
349 end;
350 if gShowPIDs then
351 namestr := Format('[%5d] %s', [UID, Name])
352 else
353 namestr := Name;
354 // Имя
355 e_TextureFontPrintEx(x+16, _y, namestr, gStdFont, rr, gg, bb, 1);
356 // Пинг/потери
357 e_TextureFontPrintEx(x+w1+16, _y, Format(_lc[I_GAME_PING_MS], [Ping, Loss]), gStdFont, rr, gg, bb, 1);
358 // Фраги
359 e_TextureFontPrintEx(x+w1+w2+16, _y, IntToStr(Frags), gStdFont, rr, gg, bb, 1);
360 // Смерти
361 e_TextureFontPrintEx(x+w1+w2+w3+16, _y, IntToStr(Deaths), gStdFont, rr, gg, bb, 1);
362 _y := _y+ch;
363 end;
365 _y := _y+ch;
366 end;
367 end
368 else if gGameSettings.GameMode in [GM_DM, GM_COOP] then
369 begin
370 _y := _y+ch+ch;
371 e_TextureFontPrintEx(x+16, _y, _lc[I_GAME_PLAYER_NAME], gStdFont, 255, 127, 0, 1);
372 e_TextureFontPrintEx(x+16+w1, _y, _lc[I_GAME_PING], gStdFont, 255, 127, 0, 1);
373 e_TextureFontPrintEx(x+16+w1+w2, _y, _lc[I_GAME_FRAGS], gStdFont, 255, 127, 0, 1);
374 e_TextureFontPrintEx(x+16+w1+w2+w3, _y, _lc[I_GAME_DEATHS], gStdFont, 255, 127, 0, 1);
376 _y := _y+ch+8;
377 for aa := 0 to High(stat) do
378 with stat[aa] do
379 begin
380 if Spectator then
381 begin
382 r := 127;
383 g := 64;
384 end
385 else
386 begin
387 r := 255;
388 g := 127;
389 end;
390 if gShowPIDs then
391 namestr := Format('[%5d] %s', [UID, Name])
392 else
393 namestr := Name;
394 // Цвет игрока
395 e_DrawFillQuad(x+16, _y+4, x+32-1, _y+16+4-1, Color.R, Color.G, Color.B, 0);
396 e_DrawQuad(x+16, _y+4, x+32-1, _y+16+4-1, 192, 192, 192);
397 // Имя
398 e_TextureFontPrintEx(x+16+16+8, _y+4, namestr, gStdFont, r, g, 0, 1);
399 // Пинг/потери
400 e_TextureFontPrintEx(x+w1+16, _y+4, Format(_lc[I_GAME_PING_MS], [Ping, Loss]), gStdFont, r, g, 0, 1);
401 // Фраги
402 e_TextureFontPrintEx(x+w1+w2+16, _y+4, IntToStr(Frags), gStdFont, r, g, 0, 1);
403 // Смерти
404 e_TextureFontPrintEx(x+w1+w2+w3+16, _y+4, IntToStr(Deaths), gStdFont, r, g, 0, 1);
405 _y := _y+ch+8;
406 end;
407 end
408 end;
410 procedure DrawCustomStat();
411 var
412 pc, x, y, w, _y,
413 w1, w2, w3,
414 t, p, m: Integer;
415 ww1, hh1: Word;
416 ww2, hh2, r, g, b, rr, gg, bb: Byte;
417 s1, s2, topstr: String;
418 begin
419 e_TextureFontGetSize(gStdFont, ww2, hh2);
421 sys_HandleInput;
423 if g_Console_Action(ACTION_SCORES) then
424 begin
425 if not gStatsPressed then
426 begin
427 gStatsOff := not gStatsOff;
428 gStatsPressed := True;
429 end;
430 end
431 else
432 gStatsPressed := False;
434 if gStatsOff then
435 begin
436 s1 := _lc[I_MENU_INTER_NOTICE_TAB];
437 w := (Length(s1) * ww2) div 2;
438 x := gScreenWidth div 2 - w;
439 y := 8;
440 e_TextureFontPrint(x, y, s1, gStdFont);
441 Exit;
442 end;
444 if (gGameSettings.GameMode = GM_COOP) then
445 begin
446 if gMissionFailed then
447 topstr := _lc[I_MENU_INTER_MISSION_FAIL]
448 else
449 topstr := _lc[I_MENU_INTER_LEVEL_COMPLETE];
450 end
451 else
452 topstr := _lc[I_MENU_INTER_ROUND_OVER];
454 e_CharFont_GetSize(gMenuFont, topstr, ww1, hh1);
455 e_CharFont_Print(gMenuFont, (gScreenWidth div 2)-(ww1 div 2), 16, topstr);
457 if g_Game_IsNet then
458 begin
459 topstr := Format(_lc[I_MENU_INTER_NOTICE_TIME], [gServInterTime]);
460 if not gChatShow then
461 e_TextureFontPrintEx((gScreenWidth div 2)-(Length(topstr)*ww2 div 2),
462 gScreenHeight-(hh2+4)*2, topstr, gStdFont, 255, 255, 255, 1);
463 end;
465 if g_Game_IsClient then
466 topstr := _lc[I_MENU_INTER_NOTICE_MAP]
467 else
468 topstr := _lc[I_MENU_INTER_NOTICE_SPACE];
469 if not gChatShow then
470 e_TextureFontPrintEx((gScreenWidth div 2)-(Length(topstr)*ww2 div 2),
471 gScreenHeight-(hh2+4), topstr, gStdFont, 255, 255, 255, 1);
473 x := 32;
474 y := 16+hh1+16;
476 w := gScreenWidth-x*2;
478 w2 := (w-16) div 6;
479 w3 := w2;
480 w1 := w-16-w2-w3;
482 e_DrawFillQuad(x, y, gScreenWidth-x-1, gScreenHeight-y-1, 64, 64, 64, 32);
483 e_DrawQuad(x, y, gScreenWidth-x-1, gScreenHeight-y-1, 255, 127, 0);
485 m := Max(Length(_lc[I_MENU_MAP])+1, Length(_lc[I_GAME_GAME_TIME])+1)*ww2;
487 case CustomStat.GameMode of
488 GM_DM:
489 begin
490 if gGameSettings.MaxLives = 0 then
491 s1 := _lc[I_GAME_DM]
492 else
493 s1 := _lc[I_GAME_LMS];
494 end;
495 GM_TDM:
496 begin
497 if gGameSettings.MaxLives = 0 then
498 s1 := _lc[I_GAME_TDM]
499 else
500 s1 := _lc[I_GAME_TLMS];
501 end;
502 GM_CTF: s1 := _lc[I_GAME_CTF];
503 GM_COOP:
504 begin
505 if gGameSettings.MaxLives = 0 then
506 s1 := _lc[I_GAME_COOP]
507 else
508 s1 := _lc[I_GAME_SURV];
509 end;
510 else s1 := '';
511 end;
513 _y := y+16;
514 e_TextureFontPrintEx(x+(w div 2)-(Length(s1)*ww2 div 2), _y, s1, gStdFont, 255, 255, 255, 1);
515 _y := _y+8;
517 _y := _y+16;
518 e_TextureFontPrintEx(x+8, _y, _lc[I_MENU_MAP], gStdFont, 255, 127, 0, 1);
519 e_TextureFontPrint(x+8+m, _y, Format('%s - %s', [CustomStat.Map, CustomStat.MapName]), gStdFont);
521 _y := _y+16;
522 e_TextureFontPrintEx(x+8, _y, _lc[I_GAME_GAME_TIME], gStdFont, 255, 127, 0, 1);
523 e_TextureFontPrint(x+8+m, _y, Format('%d:%.2d:%.2d', [CustomStat.GameTime div 1000 div 3600,
524 (CustomStat.GameTime div 1000 div 60) mod 60,
525 CustomStat.GameTime div 1000 mod 60]), gStdFont);
527 pc := Length(CustomStat.PlayerStat);
528 if pc = 0 then Exit;
530 if CustomStat.GameMode = GM_COOP then
531 begin
532 m := Max(Length(_lc[I_GAME_MONSTERS])+1, Length(_lc[I_GAME_SECRETS])+1)*ww2;
533 _y := _y+32;
534 s2 := _lc[I_GAME_MONSTERS];
535 e_TextureFontPrintEx(x+8, _y, s2, gStdFont, 255, 127, 0, 1);
536 e_TextureFontPrintEx(x+8+m, _y, IntToStr(gCoopMonstersKilled) + '/' + IntToStr(gTotalMonsters), gStdFont, 255, 255, 255, 1);
537 _y := _y+16;
538 s2 := _lc[I_GAME_SECRETS];
539 e_TextureFontPrintEx(x+8, _y, s2, gStdFont, 255, 127, 0, 1);
540 e_TextureFontPrintEx(x+8+m, _y, IntToStr(gCoopSecretsFound) + '/' + IntToStr(gSecretsCount), gStdFont, 255, 255, 255, 1);
541 if gLastMap then
542 begin
543 m := Max(Length(_lc[I_GAME_MONSTERS_TOTAL])+1, Length(_lc[I_GAME_SECRETS_TOTAL])+1)*ww2;
544 _y := _y-16;
545 s2 := _lc[I_GAME_MONSTERS_TOTAL];
546 e_TextureFontPrintEx(x+250, _y, s2, gStdFont, 255, 127, 0, 1);
547 e_TextureFontPrintEx(x+250+m, _y, IntToStr(gCoopTotalMonstersKilled) + '/' + IntToStr(gCoopTotalMonsters), gStdFont, 255, 255, 255, 1);
548 _y := _y+16;
549 s2 := _lc[I_GAME_SECRETS_TOTAL];
550 e_TextureFontPrintEx(x+250, _y, s2, gStdFont, 255, 127, 0, 1);
551 e_TextureFontPrintEx(x+250+m, _y, IntToStr(gCoopTotalSecretsFound) + '/' + IntToStr(gCoopTotalSecrets), gStdFont, 255, 255, 255, 1);
552 end;
553 end;
555 if CustomStat.GameMode in [GM_TDM, GM_CTF] then
556 begin
557 _y := _y+16+16;
559 with CustomStat do
560 if TeamStat[TEAM_RED].Goals > TeamStat[TEAM_BLUE].Goals then s1 := _lc[I_GAME_WIN_RED]
561 else if TeamStat[TEAM_BLUE].Goals > TeamStat[TEAM_RED].Goals then s1 := _lc[I_GAME_WIN_BLUE]
562 else s1 := _lc[I_GAME_WIN_DRAW];
564 e_TextureFontPrintEx(x+8+(w div 2)-(Length(s1)*ww2 div 2), _y, s1, gStdFont, 255, 255, 255, 1);
565 _y := _y+40;
567 for t := TEAM_RED to TEAM_BLUE do
568 begin
569 if t = TEAM_RED then
570 begin
571 e_TextureFontPrintEx(x+8, _y, _lc[I_GAME_TEAM_RED],
572 gStdFont, 255, 0, 0, 1);
573 e_TextureFontPrintEx(x+w1+8, _y, IntToStr(CustomStat.TeamStat[TEAM_RED].Goals),
574 gStdFont, 255, 0, 0, 1);
575 r := 255;
576 g := 0;
577 b := 0;
578 end
579 else
580 begin
581 e_TextureFontPrintEx(x+8, _y, _lc[I_GAME_TEAM_BLUE],
582 gStdFont, 0, 0, 255, 1);
583 e_TextureFontPrintEx(x+w1+8, _y, IntToStr(CustomStat.TeamStat[TEAM_BLUE].Goals),
584 gStdFont, 0, 0, 255, 1);
585 r := 0;
586 g := 0;
587 b := 255;
588 end;
590 e_DrawLine(1, x+8, _y+20, x-8+w, _y+20, r, g, b);
591 _y := _y+24;
593 for p := 0 to High(CustomStat.PlayerStat) do
594 if CustomStat.PlayerStat[p].Team = t then
595 with CustomStat.PlayerStat[p] do
596 begin
597 if Spectator then
598 begin
599 rr := r div 2;
600 gg := g div 2;
601 bb := b div 2;
602 end
603 else
604 begin
605 rr := r;
606 gg := g;
607 bb := b;
608 end;
609 if (gPlayers[Num] <> nil) and (gPlayers[Num].FReady) then
610 e_TextureFontPrintEx(x+16, _y, Name + ' *', gStdFont, rr, gg, bb, 1)
611 else
612 e_TextureFontPrintEx(x+16, _y, Name, gStdFont, rr, gg, bb, 1);
613 e_TextureFontPrintEx(x+w1+16, _y, IntToStr(Frags), gStdFont, rr, gg, bb, 1);
614 e_TextureFontPrintEx(x+w1+w2+16, _y, IntToStr(Deaths), gStdFont, rr, gg, bb, 1);
615 _y := _y+24;
616 end;
618 _y := _y+16+16;
619 end;
620 end
621 else if CustomStat.GameMode in [GM_DM, GM_COOP] then
622 begin
623 _y := _y+40;
624 e_TextureFontPrintEx(x+8, _y, _lc[I_GAME_PLAYER_NAME], gStdFont, 255, 127, 0, 1);
625 e_TextureFontPrintEx(x+8+w1, _y, _lc[I_GAME_FRAGS], gStdFont, 255, 127, 0, 1);
626 e_TextureFontPrintEx(x+8+w1+w2, _y, _lc[I_GAME_DEATHS], gStdFont, 255, 127, 0, 1);
628 _y := _y+24;
629 for p := 0 to High(CustomStat.PlayerStat) do
630 with CustomStat.PlayerStat[p] do
631 begin
632 e_DrawFillQuad(x+8, _y+4, x+24-1, _y+16+4-1, Color.R, Color.G, Color.B, 0);
634 if Spectator then
635 r := 127
636 else
637 r := 255;
639 if (gPlayers[Num] <> nil) and (gPlayers[Num].FReady) then
640 e_TextureFontPrintEx(x+8+16+8, _y+4, Name + ' *', gStdFont, r, r, r, 1, True)
641 else
642 e_TextureFontPrintEx(x+8+16+8, _y+4, Name, gStdFont, r, r, r, 1, True);
643 e_TextureFontPrintEx(x+w1+8+16+8, _y+4, IntToStr(Frags), gStdFont, r, r, r, 1, True);
644 e_TextureFontPrintEx(x+w1+w2+8+16+8, _y+4, IntToStr(Deaths), gStdFont, r, r, r, 1, True);
645 _y := _y+24;
646 end;
647 end;
649 // HACK: take stats screenshot immediately after the first frame of the stats showing
650 if gScreenshotStats and (not StatShotDone) and (Length(CustomStat.PlayerStat) > 1) then
651 begin
652 g_TakeScreenShot('stats/' + StatFilename);
653 StatShotDone := True;
654 end;
655 end;
657 procedure DrawSingleStat();
658 var
659 tm, key_x, val_x, y: Integer;
660 w1, w2, h: Word;
661 s1, s2: String;
663 procedure player_stat(n: Integer);
664 var
665 kpm: Real;
667 begin
668 // "Kills: # / #":
669 s1 := Format(' %d ', [SingleStat.PlayerStat[n].Kills]);
670 s2 := Format(' %d', [gTotalMonsters]);
672 e_CharFont_Print(gMenuFont, key_x, y, _lc[I_MENU_INTER_KILLS]);
673 e_CharFont_PrintEx(gMenuFont, val_x, y, s1, _RGB(255, 0, 0));
674 e_CharFont_GetSize(gMenuFont, s1, w1, h);
675 e_CharFont_Print(gMenuFont, val_x+w1, y, '/');
676 s1 := s1 + '/';
677 e_CharFont_GetSize(gMenuFont, s1, w1, h);
678 e_CharFont_PrintEx(gMenuFont, val_x+w1, y, s2, _RGB(255, 0, 0));
680 // "Kills-per-minute: ##.#":
681 s1 := _lc[I_MENU_INTER_KPM];
682 if tm > 0 then
683 kpm := (SingleStat.PlayerStat[n].Kills / tm) * 60
684 else
685 kpm := SingleStat.PlayerStat[n].Kills;
686 s2 := Format(' %.1f', [kpm]);
688 e_CharFont_Print(gMenuFont, key_x, y+32, s1);
689 e_CharFont_PrintEx(gMenuFont, val_x, y+32, s2, _RGB(255, 0, 0));
691 // "Secrets found: # / #":
692 s1 := Format(' %d ', [SingleStat.PlayerStat[n].Secrets]);
693 s2 := Format(' %d', [SingleStat.TotalSecrets]);
695 e_CharFont_Print(gMenuFont, key_x, y+64, _lc[I_MENU_INTER_SECRETS]);
696 e_CharFont_PrintEx(gMenuFont, val_x, y+64, s1, _RGB(255, 0, 0));
697 e_CharFont_GetSize(gMenuFont, s1, w1, h);
698 e_CharFont_Print(gMenuFont, val_x+w1, y+64, '/');
699 s1 := s1 + '/';
700 e_CharFont_GetSize(gMenuFont, s1, w1, h);
701 e_CharFont_PrintEx(gMenuFont, val_x+w1, y+64, s2, _RGB(255, 0, 0));
702 end;
704 begin
705 // "Level Complete":
706 e_CharFont_GetSize(gMenuFont, _lc[I_MENU_INTER_LEVEL_COMPLETE], w1, h);
707 e_CharFont_Print(gMenuFont, (gScreenWidth-w1) div 2, 32, _lc[I_MENU_INTER_LEVEL_COMPLETE]);
709 // Определяем координаты выравнивания по самой длинной строке:
710 s1 := _lc[I_MENU_INTER_KPM];
711 e_CharFont_GetSize(gMenuFont, s1, w1, h);
712 Inc(w1, 16);
713 s1 := ' 9999.9';
714 e_CharFont_GetSize(gMenuFont, s1, w2, h);
716 key_x := (gScreenWidth-w1-w2) div 2;
717 val_x := key_x + w1;
719 // "Time: #:##:##":
720 tm := SingleStat.GameTime div 1000;
721 s1 := _lc[I_MENU_INTER_TIME];
722 s2 := Format(' %d:%.2d:%.2d', [tm div (60*60), (tm mod (60*60)) div 60, tm mod 60]);
724 e_CharFont_Print(gMenuFont, key_x, 80, s1);
725 e_CharFont_PrintEx(gMenuFont, val_x, 80, s2, _RGB(255, 0, 0));
727 if SingleStat.TwoPlayers then
728 begin
729 // "Player 1":
730 s1 := _lc[I_MENU_PLAYER_1];
731 e_CharFont_GetSize(gMenuFont, s1, w1, h);
732 e_CharFont_Print(gMenuFont, (gScreenWidth-w1) div 2, 128, s1);
734 // Статистика первого игрока:
735 y := 176;
736 player_stat(0);
738 // "Player 2":
739 s1 := _lc[I_MENU_PLAYER_2];
740 e_CharFont_GetSize(gMenuFont, s1, w1, h);
741 e_CharFont_Print(gMenuFont, (gScreenWidth-w1) div 2, 288, s1);
743 // Статистика второго игрока:
744 y := 336;
745 player_stat(1);
746 end
747 else
748 begin
749 // Статистика первого игрока:
750 y := 128;
751 player_stat(0);
752 end;
753 end;
755 procedure r_Game_DrawLoadingStat;
756 procedure drawRect (x, y, w, h: Integer);
757 begin
758 if (w < 1) or (h < 1) then exit;
759 glBegin(GL_QUADS);
760 glVertex2f(x+0.375, y+0.375);
761 glVertex2f(x+w+0.375, y+0.375);
762 glVertex2f(x+w+0.375, y+h+0.375);
763 glVertex2f(x+0.375, y+h+0.375);
764 glEnd();
765 end;
767 function drawPBar (cur, total: Integer; washere: Boolean): Boolean;
768 var
769 rectW, rectH: Integer;
770 x0, y0: Integer;
771 wdt: Integer;
772 wl, hl: Integer;
773 wr, hr: Integer;
774 wb, hb: Integer;
775 wm, hm: Integer;
776 idl, idr, idb, idm: LongWord;
777 f, my: Integer;
778 begin
779 result := false;
780 if (total < 1) then exit;
781 if (cur < 1) then exit; // don't blink
782 if (not washere) and (cur >= total) then exit; // don't blink
783 //if (cur < 0) then cur := 0;
784 //if (cur > total) then cur := total;
785 result := true;
787 if (hasPBarGfx) then
788 begin
789 g_Texture_Get('UI_GFX_PBAR_LEFT', idl);
790 g_Texture_GetSize('UI_GFX_PBAR_LEFT', wl, hl);
791 g_Texture_Get('UI_GFX_PBAR_RIGHT', idr);
792 g_Texture_GetSize('UI_GFX_PBAR_RIGHT', wr, hr);
793 g_Texture_Get('UI_GFX_PBAR_MIDDLE', idb);
794 g_Texture_GetSize('UI_GFX_PBAR_MIDDLE', wb, hb);
795 g_Texture_Get('UI_GFX_PBAR_MARKER', idm);
796 g_Texture_GetSize('UI_GFX_PBAR_MARKER', wm, hm);
798 //rectW := gScreenWidth-360;
799 rectW := trunc(624.0*gScreenWidth/1024.0);
800 rectH := hl;
802 x0 := (gScreenWidth-rectW) div 2;
803 y0 := gScreenHeight-rectH-64;
804 if (y0 < 2) then y0 := 2;
806 glEnable(GL_SCISSOR_TEST);
808 // left and right
809 glScissor(x0, gScreenHeight-y0-rectH, rectW, rectH);
810 e_DrawSize(idl, x0, y0, 0, true, false, wl, hl);
811 e_DrawSize(idr, x0+rectW-wr, y0, 0, true, false, wr, hr);
813 // body
814 glScissor(x0+wl, gScreenHeight-y0-rectH, rectW-wl-wr, rectH);
815 f := x0+wl;
816 while (f < x0+rectW) do
817 begin
818 e_DrawSize(idb, f, y0, 0, true, false, wb, hb);
819 f += wb;
820 end;
822 // filled part
823 wdt := (rectW-wl-wr)*cur div total;
824 if (wdt > rectW-wl-wr) then wdt := rectW-wr-wr;
825 if (wdt > 0) then
826 begin
827 my := y0; // don't be so smart, ketmar: +(rectH-wm) div 2;
828 glScissor(x0+wl, gScreenHeight-my-rectH, wdt, hm);
829 f := x0+wl;
830 while (wdt > 0) do
831 begin
832 e_DrawSize(idm, f, y0, 0, true, false, wm, hm);
833 f += wm;
834 wdt -= wm;
835 end;
836 end;
838 glScissor(0, 0, gScreenWidth, gScreenHeight);
839 end
840 else
841 begin
842 rectW := gScreenWidth-64;
843 rectH := 16;
845 x0 := (gScreenWidth-rectW) div 2;
846 y0 := gScreenHeight-rectH-64;
847 if (y0 < 2) then y0 := 2;
849 glDisable(GL_BLEND);
850 glDisable(GL_TEXTURE_2D);
852 //glClearColor(0, 0, 0, 0);
853 //glClear(GL_COLOR_BUFFER_BIT);
855 glColor4ub(127, 127, 127, 255);
856 drawRect(x0-2, y0-2, rectW+4, rectH+4);
858 glColor4ub(0, 0, 0, 255);
859 drawRect(x0-1, y0-1, rectW+2, rectH+2);
861 glColor4ub(127, 127, 127, 255);
862 wdt := rectW*cur div total;
863 if (wdt > rectW) then wdt := rectW;
864 drawRect(x0, y0, wdt, rectH);
865 end;
866 end;
868 var
869 ww, hh: Word;
870 xx, yy, i: Integer;
871 s: String;
872 begin
873 if (Length(LoadingStat.Msgs) = 0) then exit;
875 e_CharFont_GetSize(gMenuFont, _lc[I_MENU_LOADING], ww, hh);
876 yy := (gScreenHeight div 3);
877 e_CharFont_Print(gMenuFont, (gScreenWidth div 2)-(ww div 2), yy-2*hh, _lc[I_MENU_LOADING]);
878 xx := (gScreenWidth div 3);
880 with LoadingStat do
881 begin
882 for i := 0 to NextMsg-1 do
883 begin
884 if (i = (NextMsg-1)) and (MaxValue > 0) then
885 s := Format('%s: %d/%d', [Msgs[i], CurValue, MaxValue])
886 else
887 s := Msgs[i];
889 e_CharFont_PrintEx(gMenuSmallFont, xx, yy, s, _RGB(255, 0, 0));
890 yy := yy + LOADING_INTERLINE;
891 PBarWasHere := drawPBar(CurValue, MaxValue, PBarWasHere);
892 end;
893 end;
894 end;
896 procedure r_Game_DrawMenuBackground (tex: AnsiString);
897 var
898 w, h: Word;
899 ID: DWord;
901 begin
902 if g_Texture_Get(tex, ID) then
903 begin
904 e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
905 e_GetTextureSize(ID, @w, @h);
906 if w = h then
907 w := round(w * 1.333 * (gScreenHeight / h))
908 else
909 w := trunc(w * (gScreenHeight / h));
910 e_DrawSize(ID, (gScreenWidth - w) div 2, 0, 0, False, False, w, gScreenHeight);
911 end
912 else e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
913 end;
915 procedure DrawMinimap(p: TPlayer; RenderRect: TRect);
916 var
917 a, aX, aY, aX2, aY2, Scale, ScaleSz: Integer;
919 function monDraw (mon: TMonster): Boolean;
920 begin
921 result := false; // don't stop
922 with mon do
923 begin
924 if alive then
925 begin
926 // Левый верхний угол
927 aX := Obj.X div ScaleSz + 1;
928 aY := Obj.Y div ScaleSz + 1;
929 // Размеры
930 aX2 := max(Obj.Rect.Width div ScaleSz, 1);
931 aY2 := max(Obj.Rect.Height div ScaleSz, 1);
932 // Правый нижний угол
933 aX2 := aX + aX2 - 1;
934 aY2 := aY + aY2 - 1;
935 e_DrawFillQuad(aX, aY, aX2, aY2, 255, 255, 0, 0);
936 end;
937 end;
938 end;
940 begin
941 if (gMapInfo.Width > RenderRect.Right - RenderRect.Left) or
942 (gMapInfo.Height > RenderRect.Bottom - RenderRect.Top) then
943 begin
944 Scale := 1;
945 // Сколько пикселов карты в 1 пикселе мини-карты:
946 ScaleSz := 16 div Scale;
947 // Размеры мини-карты:
948 aX := max(gMapInfo.Width div ScaleSz, 1);
949 aY := max(gMapInfo.Height div ScaleSz, 1);
950 // Рамка карты:
951 e_DrawFillQuad(0, 0, aX-1, aY-1, 0, 0, 0, 0);
953 if gWalls <> nil then
954 begin
955 // Рисуем стены:
956 for a := 0 to High(gWalls) do
957 with gWalls[a] do
958 if PanelType <> 0 then
959 begin
960 // Левый верхний угол:
961 aX := X div ScaleSz;
962 aY := Y div ScaleSz;
963 // Размеры:
964 aX2 := max(Width div ScaleSz, 1);
965 aY2 := max(Height div ScaleSz, 1);
966 // Правый нижний угол:
967 aX2 := aX + aX2 - 1;
968 aY2 := aY + aY2 - 1;
970 case PanelType of
971 PANEL_WALL: e_DrawFillQuad(aX, aY, aX2, aY2, 208, 208, 208, 0);
972 PANEL_OPENDOOR, PANEL_CLOSEDOOR:
973 if Enabled then e_DrawFillQuad(aX, aY, aX2, aY2, 160, 160, 160, 0);
974 end;
975 end;
976 end;
977 if gSteps <> nil then
978 begin
979 // Рисуем ступени:
980 for a := 0 to High(gSteps) do
981 with gSteps[a] do
982 if PanelType <> 0 then
983 begin
984 // Левый верхний угол:
985 aX := X div ScaleSz;
986 aY := Y div ScaleSz;
987 // Размеры:
988 aX2 := max(Width div ScaleSz, 1);
989 aY2 := max(Height div ScaleSz, 1);
990 // Правый нижний угол:
991 aX2 := aX + aX2 - 1;
992 aY2 := aY + aY2 - 1;
994 e_DrawFillQuad(aX, aY, aX2, aY2, 128, 128, 128, 0);
995 end;
996 end;
997 if gLifts <> nil then
998 begin
999 // Рисуем лифты:
1000 for a := 0 to High(gLifts) do
1001 with gLifts[a] do
1002 if PanelType <> 0 then
1003 begin
1004 // Левый верхний угол:
1005 aX := X div ScaleSz;
1006 aY := Y div ScaleSz;
1007 // Размеры:
1008 aX2 := max(Width div ScaleSz, 1);
1009 aY2 := max(Height div ScaleSz, 1);
1010 // Правый нижний угол:
1011 aX2 := aX + aX2 - 1;
1012 aY2 := aY + aY2 - 1;
1014 case LiftType of
1015 LIFTTYPE_UP: e_DrawFillQuad(aX, aY, aX2, aY2, 116, 72, 36, 0);
1016 LIFTTYPE_DOWN: e_DrawFillQuad(aX, aY, aX2, aY2, 116, 124, 96, 0);
1017 LIFTTYPE_LEFT: e_DrawFillQuad(aX, aY, aX2, aY2, 200, 80, 4, 0);
1018 LIFTTYPE_RIGHT: e_DrawFillQuad(aX, aY, aX2, aY2, 252, 140, 56, 0);
1019 end;
1020 end;
1021 end;
1022 if gWater <> nil then
1023 begin
1024 // Рисуем воду:
1025 for a := 0 to High(gWater) do
1026 with gWater[a] do
1027 if PanelType <> 0 then
1028 begin
1029 // Левый верхний угол:
1030 aX := X div ScaleSz;
1031 aY := Y div ScaleSz;
1032 // Размеры:
1033 aX2 := max(Width div ScaleSz, 1);
1034 aY2 := max(Height div ScaleSz, 1);
1035 // Правый нижний угол:
1036 aX2 := aX + aX2 - 1;
1037 aY2 := aY + aY2 - 1;
1039 e_DrawFillQuad(aX, aY, aX2, aY2, 0, 0, 192, 0);
1040 end;
1041 end;
1042 if gAcid1 <> nil then
1043 begin
1044 // Рисуем кислоту 1:
1045 for a := 0 to High(gAcid1) do
1046 with gAcid1[a] do
1047 if PanelType <> 0 then
1048 begin
1049 // Левый верхний угол:
1050 aX := X div ScaleSz;
1051 aY := Y div ScaleSz;
1052 // Размеры:
1053 aX2 := max(Width div ScaleSz, 1);
1054 aY2 := max(Height div ScaleSz, 1);
1055 // Правый нижний угол:
1056 aX2 := aX + aX2 - 1;
1057 aY2 := aY + aY2 - 1;
1059 e_DrawFillQuad(aX, aY, aX2, aY2, 0, 176, 0, 0);
1060 end;
1061 end;
1062 if gAcid2 <> nil then
1063 begin
1064 // Рисуем кислоту 2:
1065 for a := 0 to High(gAcid2) do
1066 with gAcid2[a] do
1067 if PanelType <> 0 then
1068 begin
1069 // Левый верхний угол:
1070 aX := X div ScaleSz;
1071 aY := Y div ScaleSz;
1072 // Размеры:
1073 aX2 := max(Width div ScaleSz, 1);
1074 aY2 := max(Height div ScaleSz, 1);
1075 // Правый нижний угол:
1076 aX2 := aX + aX2 - 1;
1077 aY2 := aY + aY2 - 1;
1079 e_DrawFillQuad(aX, aY, aX2, aY2, 176, 0, 0, 0);
1080 end;
1081 end;
1082 if gPlayers <> nil then
1083 begin
1084 // Рисуем игроков:
1085 for a := 0 to High(gPlayers) do
1086 if gPlayers[a] <> nil then with gPlayers[a] do
1087 if alive then begin
1088 // Левый верхний угол:
1089 aX := Obj.X div ScaleSz + 1;
1090 aY := Obj.Y div ScaleSz + 1;
1091 // Размеры:
1092 aX2 := max(Obj.Rect.Width div ScaleSz, 1);
1093 aY2 := max(Obj.Rect.Height div ScaleSz, 1);
1094 // Правый нижний угол:
1095 aX2 := aX + aX2 - 1;
1096 aY2 := aY + aY2 - 1;
1098 if gPlayers[a] = p then
1099 e_DrawFillQuad(aX, aY, aX2, aY2, 0, 255, 0, 0)
1100 else
1101 case Team of
1102 TEAM_RED: e_DrawFillQuad(aX, aY, aX2, aY2, 255, 0, 0, 0);
1103 TEAM_BLUE: e_DrawFillQuad(aX, aY, aX2, aY2, 0, 0, 255, 0);
1104 else e_DrawFillQuad(aX, aY, aX2, aY2, 255, 128, 0, 0);
1105 end;
1106 end;
1107 end;
1108 // Рисуем монстров
1109 g_Mons_ForEach(monDraw);
1110 end;
1111 end;
1114 procedure renderAmbientQuad (hasAmbient: Boolean; constref ambColor: TDFColor);
1115 begin
1116 if not hasAmbient then exit;
1117 e_AmbientQuad(sX, sY, sWidth, sHeight, ambColor.r, ambColor.g, ambColor.b, ambColor.a);
1118 end;
1120 // ////////////////////////////////////////////////////////////////////////// //
1121 var
1122 ltexid: GLuint = 0;
1124 function g_Texture_Light (): Integer;
1125 const
1126 Radius: Integer = 128;
1127 var
1128 tex, tpp: PByte;
1129 x, y, a: Integer;
1130 dist: Double;
1131 begin
1132 if ltexid = 0 then
1133 begin
1134 GetMem(tex, (Radius*2)*(Radius*2)*4);
1135 tpp := tex;
1136 for y := 0 to Radius*2-1 do
1137 begin
1138 for x := 0 to Radius*2-1 do
1139 begin
1140 dist := 1.0-sqrt((x-Radius)*(x-Radius)+(y-Radius)*(y-Radius))/Radius;
1141 if (dist < 0) then
1142 begin
1143 tpp^ := 0; Inc(tpp);
1144 tpp^ := 0; Inc(tpp);
1145 tpp^ := 0; Inc(tpp);
1146 tpp^ := 0; Inc(tpp);
1147 end
1148 else
1149 begin
1150 //tc.setPixel(x, y, Color(cast(int)(dist*255), cast(int)(dist*255), cast(int)(dist*255)));
1151 if (dist > 0.5) then dist := 0.5;
1152 a := round(dist*255);
1153 if (a < 0) then a := 0 else if (a > 255) then a := 255;
1154 tpp^ := 255; Inc(tpp);
1155 tpp^ := 255; Inc(tpp);
1156 tpp^ := 255; Inc(tpp);
1157 tpp^ := Byte(a); Inc(tpp);
1158 end;
1159 end;
1160 end;
1162 glGenTextures(1, @ltexid);
1163 //if (tid == 0) assert(0, "VGL: can't create screen texture");
1165 glBindTexture(GL_TEXTURE_2D, ltexid);
1166 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1167 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1168 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1169 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1171 //GLfloat[4] bclr = 0.0;
1172 //glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, bclr.ptr);
1174 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Radius*2, Radius*2, 0, GL_RGBA{gltt}, GL_UNSIGNED_BYTE, tex);
1175 end;
1177 result := ltexid;
1178 end;
1180 // setup sX, sY, sWidth, sHeight, and transformation matrix before calling this!
1181 //FIXME: broken for splitscreen mode
1182 procedure renderDynLightsInternal ();
1183 var
1184 //hasAmbient: Boolean;
1185 //ambColor: TDFColor;
1186 lln: Integer;
1187 lx, ly, lrad: Integer;
1188 scxywh: array[0..3] of GLint;
1189 wassc: Boolean;
1190 begin
1191 if e_NoGraphics then exit;
1193 //TODO: lights should be in separate grid, i think
1194 // but on the other side: grid may be slower for dynlights, as their lifetime is short
1195 if (not gwin_k8_enable_light_experiments) or (not gwin_has_stencil) or (g_dynLightCount < 1) then exit;
1197 // rendering mode
1198 //ambColor := gCurrentMap['light_ambient'].rgba;
1199 //hasAmbient := (not ambColor.isOpaque) or (not ambColor.isBlack);
1201 { // this will multiply incoming color to alpha from framebuffer
1202 glEnable(GL_BLEND);
1203 glBlendFunc(GL_DST_ALPHA, GL_ONE);
1206 (*
1207 * light rendering: (INVALID!)
1208 * glStencilFunc(GL_EQUAL, 0, $ff);
1209 * for each light:
1210 * glClear(GL_STENCIL_BUFFER_BIT);
1211 * glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
1212 * draw shadow volume into stencil buffer
1213 * glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); // modify color buffer
1214 * glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // don't modify stencil buffer
1215 * turn off blending
1216 * draw color-less quad with light alpha (WARNING! don't touch color!)
1217 * glEnable(GL_BLEND);
1218 * glBlendFunc(GL_DST_ALPHA, GL_ONE);
1219 * draw all geometry up to and including walls (with alpha-testing, probably) -- this does lighting
1220 *)
1221 wassc := (glIsEnabled(GL_SCISSOR_TEST) <> 0);
1222 if wassc then glGetIntegerv(GL_SCISSOR_BOX, @scxywh[0]) else glGetIntegerv(GL_VIEWPORT, @scxywh[0]);
1224 // setup OpenGL parameters
1225 glStencilMask($FFFFFFFF);
1226 glStencilFunc(GL_ALWAYS, 0, $FFFFFFFF);
1227 glEnable(GL_STENCIL_TEST);
1228 glEnable(GL_SCISSOR_TEST);
1229 glClear(GL_STENCIL_BUFFER_BIT);
1230 glStencilFunc(GL_EQUAL, 0, $ff);
1232 for lln := 0 to g_dynLightCount-1 do
1233 begin
1234 lx := g_dynLights[lln].x;
1235 ly := g_dynLights[lln].y;
1236 lrad := g_dynLights[lln].radius;
1237 if (lrad < 3) then continue;
1239 if (lx-sX+lrad < 0) then continue;
1240 if (ly-sY+lrad < 0) then continue;
1241 if (lx-sX-lrad >= gPlayerScreenSize.X) then continue;
1242 if (ly-sY-lrad >= gPlayerScreenSize.Y) then continue;
1244 // set scissor to optimize drawing
1245 if (g_dbg_scale = 1.0) then
1246 begin
1247 glScissor((lx-sX)-lrad+2, gPlayerScreenSize.Y-(ly-sY)-lrad-1+2, lrad*2-4, lrad*2-4);
1248 end
1249 else
1250 begin
1251 glScissor(0, 0, gScreenWidth, gScreenHeight);
1252 end;
1253 // no need to clear stencil buffer, light blitting will do it for us... but only for normal scale
1254 if (g_dbg_scale <> 1.0) then glClear(GL_STENCIL_BUFFER_BIT);
1255 glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
1256 // draw extruded panels
1257 glDisable(GL_TEXTURE_2D);
1258 glDisable(GL_BLEND);
1259 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // no need to modify color buffer
1260 if (lrad > 4) then r_Map_DrawPanelShadowVolumes(lx, ly, lrad);
1261 // render light texture
1262 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); // modify color buffer
1263 glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); // draw light, and clear stencil buffer
1264 // blend it
1265 glEnable(GL_BLEND);
1266 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1267 glEnable(GL_TEXTURE_2D);
1268 // color and opacity
1269 glColor4f(g_dynLights[lln].r, g_dynLights[lln].g, g_dynLights[lln].b, g_dynLights[lln].a);
1270 glBindTexture(GL_TEXTURE_2D, g_Texture_Light());
1271 glBegin(GL_QUADS);
1272 glTexCoord2f(0.0, 0.0); glVertex2i(lx-lrad, ly-lrad); // top-left
1273 glTexCoord2f(1.0, 0.0); glVertex2i(lx+lrad, ly-lrad); // top-right
1274 glTexCoord2f(1.0, 1.0); glVertex2i(lx+lrad, ly+lrad); // bottom-right
1275 glTexCoord2f(0.0, 1.0); glVertex2i(lx-lrad, ly+lrad); // bottom-left
1276 glEnd();
1277 end;
1279 // done
1280 glDisable(GL_STENCIL_TEST);
1281 glDisable(GL_BLEND);
1282 glDisable(GL_SCISSOR_TEST);
1283 //glScissor(0, 0, sWidth, sHeight);
1285 glScissor(scxywh[0], scxywh[1], scxywh[2], scxywh[3]);
1286 if wassc then glEnable(GL_SCISSOR_TEST) else glDisable(GL_SCISSOR_TEST);
1287 end;
1290 function fixViewportForScale (): Boolean;
1291 var
1292 nx0, ny0, nw, nh: Integer;
1293 begin
1294 result := false;
1295 if (g_dbg_scale <> 1.0) then
1296 begin
1297 result := true;
1298 nx0 := round(sX-(gPlayerScreenSize.X-(sWidth*g_dbg_scale))/2/g_dbg_scale);
1299 ny0 := round(sY-(gPlayerScreenSize.Y-(sHeight*g_dbg_scale))/2/g_dbg_scale);
1300 nw := round(sWidth/g_dbg_scale);
1301 nh := round(sHeight/g_dbg_scale);
1302 sX := nx0;
1303 sY := ny0;
1304 sWidth := nw;
1305 sHeight := nh;
1306 end;
1307 end;
1310 // setup sX, sY, sWidth, sHeight, and transformation matrix before calling this!
1311 // WARNING! this WILL CALL `glTranslatef()`, but won't restore matrices!
1312 procedure renderMapInternal (backXOfs, backYOfs: Integer; setTransMatrix: Boolean);
1313 type
1314 TDrawCB = procedure ();
1316 var
1317 hasAmbient: Boolean;
1318 ambColor: TDFColor;
1319 doAmbient: Boolean = false;
1321 procedure drawPanelType (profname: AnsiString; panType: DWord; doDraw: Boolean);
1322 var
1323 tagmask: Integer;
1324 pan: TPanel;
1325 begin
1326 if (profileFrameDraw <> nil) then profileFrameDraw.sectionBegin(profname);
1327 if gdbg_map_use_accel_render then
1328 begin
1329 tagmask := panelTypeToTag(panType);
1330 while (gDrawPanelList.count > 0) do
1331 begin
1332 pan := TPanel(gDrawPanelList.front());
1333 if ((pan.tag and tagmask) = 0) then break;
1334 if doDraw then r_Panel_Draw(pan, doAmbient, ambColor);
1335 gDrawPanelList.popFront();
1336 end;
1337 end
1338 else
1339 begin
1340 if doDraw then r_Map_DrawPanels(panType, hasAmbient, ambColor);
1341 end;
1342 if (profileFrameDraw <> nil) then profileFrameDraw.sectionEnd();
1343 end;
1345 procedure drawOther (profname: AnsiString; cb: TDrawCB);
1346 begin
1347 if (profileFrameDraw <> nil) then profileFrameDraw.sectionBegin(profname);
1348 if assigned(cb) then cb();
1349 if (profileFrameDraw <> nil) then profileFrameDraw.sectionEnd();
1350 end;
1352 begin
1353 if (profileFrameDraw <> nil) then profileFrameDraw.sectionBegin('total');
1355 // our accelerated renderer will collect all panels to gDrawPanelList
1356 // we can use panel tag to render level parts (see GridTagXXX in g_map.pas)
1357 if (profileFrameDraw <> nil) then profileFrameDraw.sectionBegin('collect');
1358 if gdbg_map_use_accel_render then
1359 begin
1360 r_Map_CollectDrawPanels(sX, sY, sWidth, sHeight);
1361 end;
1362 if (profileFrameDraw <> nil) then profileFrameDraw.sectionEnd();
1364 if (profileFrameDraw <> nil) then profileFrameDraw.sectionBegin('skyback');
1365 r_Map_DrawBack(backXOfs, backYOfs);
1366 if (profileFrameDraw <> nil) then profileFrameDraw.sectionEnd();
1368 if setTransMatrix then
1369 begin
1370 //if (g_dbg_scale <> 1.0) then glTranslatef(0.0, -0.375/2, 0);
1371 glScalef(g_dbg_scale, g_dbg_scale, 1.0);
1372 glTranslatef(-sX, -sY, 0);
1373 end;
1375 // rendering mode
1376 ambColor := gCurrentMap['light_ambient'].rgba;
1377 hasAmbient := (not ambColor.isOpaque) or (not ambColor.isBlack);
1380 if hasAmbient then
1381 begin
1382 //writeln('color: (', ambColor.r, ',', ambColor.g, ',', ambColor.b, ',', ambColor.a, ')');
1383 glColor4ub(ambColor.r, ambColor.g, ambColor.b, ambColor.a);
1384 glClear(GL_COLOR_BUFFER_BIT);
1385 end;
1387 //writeln('color: (', ambColor.r, ',', ambColor.g, ',', ambColor.b, ',', ambColor.a, ')');
1390 drawPanelType('*back', PANEL_BACK, g_rlayer_back);
1391 drawPanelType('*step', PANEL_STEP, g_rlayer_step);
1392 drawOther('items', @r_Items_Draw);
1393 drawOther('weapons', @r_Weapon_Draw);
1394 drawOther('shells', @r_Player_DrawShells);
1395 drawOther('drawall', @r_Player_DrawAll);
1396 drawOther('gibs', @r_PlayerModel_DrawGibs);
1397 drawOther('corpses', @r_Player_DrawCorpses);
1398 drawPanelType('*wall', PANEL_WALL, g_rlayer_wall);
1399 drawOther('monsters', @r_Monsters_Draw);
1400 drawOther('itemdrop', @r_Items_DrawDrop);
1401 drawPanelType('*door', PANEL_CLOSEDOOR, g_rlayer_door);
1402 drawOther('gfx', @r_GFX_Draw);
1403 drawOther('flags', @r_Map_DrawFlags);
1404 drawPanelType('*acid1', PANEL_ACID1, g_rlayer_acid1);
1405 drawPanelType('*acid2', PANEL_ACID2, g_rlayer_acid2);
1406 drawPanelType('*water', PANEL_WATER, g_rlayer_water);
1407 drawOther('dynlights', @renderDynLightsInternal);
1409 if hasAmbient {and ((not g_playerLight) or (not gwin_has_stencil) or (g_dynLightCount < 1))} then
1410 begin
1411 renderAmbientQuad(hasAmbient, ambColor);
1412 end;
1414 doAmbient := true;
1415 drawPanelType('*fore', PANEL_FORE, g_rlayer_fore);
1418 if g_debug_HealthBar then
1419 begin
1420 r_Monsters_DrawHealth();
1421 r_Player_DrawHealth();
1422 end;
1424 if (profileFrameDraw <> nil) then profileFrameDraw.mainEnd(); // map rendering
1425 end;
1428 procedure DrawMapView(x, y, w, h: Integer);
1430 var
1431 bx, by: Integer;
1432 begin
1433 glPushMatrix();
1435 bx := Round(x/(gMapInfo.Width - w)*(gBackSize.X - w));
1436 by := Round(y/(gMapInfo.Height - h)*(gBackSize.Y - h));
1438 sX := x;
1439 sY := y;
1440 sWidth := w;
1441 sHeight := h;
1443 fixViewportForScale();
1444 renderMapInternal(-bx, -by, true);
1446 glPopMatrix();
1447 end;
1450 procedure DrawPlayer(p: TPlayer);
1451 var
1452 px, py, a, b, c, d, i, fX, fY: Integer;
1453 camObj: TObj;
1454 //R: TRect;
1455 begin
1456 if (p = nil) or (p.FDummy) then
1457 begin
1458 glPushMatrix();
1459 r_Map_DrawBack(0, 0);
1460 glPopMatrix();
1461 Exit;
1462 end;
1464 if (profileFrameDraw = nil) then profileFrameDraw := TProfiler.Create('RENDER', g_profile_history_size);
1465 if (profileFrameDraw <> nil) then profileFrameDraw.mainBegin(g_profile_frame_draw);
1467 gPlayerDrawn := p;
1469 glPushMatrix();
1471 camObj := p.getCameraObj();
1472 camObj.lerp(gLerpFactor, fX, fY);
1473 px := fX + PLAYER_RECT_CX;
1474 py := fY + PLAYER_RECT_CY+nlerp(p.SlopeOld, camObj.slopeUpLeft, gLerpFactor);
1476 if (g_dbg_scale = 1.0) and (not g_dbg_ignore_bounds) then
1477 begin
1478 if (px > (gPlayerScreenSize.X div 2)) then a := -px+(gPlayerScreenSize.X div 2) else a := 0;
1479 if (py > (gPlayerScreenSize.Y div 2)) then b := -py+(gPlayerScreenSize.Y div 2) else b := 0;
1481 if (px > gMapInfo.Width-(gPlayerScreenSize.X div 2)) then a := -gMapInfo.Width+gPlayerScreenSize.X;
1482 if (py > gMapInfo.Height-(gPlayerScreenSize.Y div 2)) then b := -gMapInfo.Height+gPlayerScreenSize.Y;
1484 if (gMapInfo.Width = gPlayerScreenSize.X) then a := 0
1485 else if (gMapInfo.Width < gPlayerScreenSize.X) then
1486 begin
1487 // hcenter
1488 a := (gPlayerScreenSize.X-gMapInfo.Width) div 2;
1489 end;
1491 if (gMapInfo.Height = gPlayerScreenSize.Y) then b := 0
1492 else if (gMapInfo.Height < gPlayerScreenSize.Y) then
1493 begin
1494 // vcenter
1495 b := (gPlayerScreenSize.Y-gMapInfo.Height) div 2;
1496 end;
1497 end
1498 else
1499 begin
1500 // scaled, ignore level bounds
1501 a := -px+(gPlayerScreenSize.X div 2);
1502 b := -py+(gPlayerScreenSize.Y div 2);
1503 end;
1505 sX := -a;
1506 sY := -b;
1507 sWidth := gPlayerScreenSize.X;
1508 sHeight := gPlayerScreenSize.Y;
1509 fixViewportForScale();
1511 i := py - (sY + sHeight div 2);
1512 if (p.IncCam > 0) then
1513 begin
1514 // clamp to level bounds
1515 if (sY - p.IncCam < 0) then
1516 p.IncCam := nclamp(sY, 0, 120);
1517 // clamp around player position
1518 if (i > 0) then
1519 p.IncCam := nclamp(p.IncCam, 0, max(0, 120 - i));
1520 end
1521 else if (p.IncCam < 0) then
1522 begin
1523 // clamp to level bounds
1524 if (sY + sHeight - p.IncCam > gMapInfo.Height) then
1525 p.IncCam := nclamp(sY + sHeight - gMapInfo.Height, -120, 0);
1526 // clamp around player position
1527 if (i < 0) then
1528 p.IncCam := nclamp(p.IncCam, min(0, -120 - i), 0);
1529 end;
1531 sY := sY - nlerp(p.IncCamOld, p.IncCam, gLerpFactor);
1533 if (not g_dbg_ignore_bounds) then
1534 begin
1535 if (sX+sWidth > gMapInfo.Width) then sX := gMapInfo.Width-sWidth;
1536 if (sY+sHeight > gMapInfo.Height) then sY := gMapInfo.Height-sHeight;
1537 if (sX < 0) then sX := 0;
1538 if (sY < 0) then sY := 0;
1539 end;
1541 if (gBackSize.X <= gPlayerScreenSize.X) or (gMapInfo.Width <= sWidth) then c := 0 else c := trunc((gBackSize.X-gPlayerScreenSize.X)*sX/(gMapInfo.Width-sWidth));
1542 if (gBackSize.Y <= gPlayerScreenSize.Y) or (gMapInfo.Height <= sHeight) then d := 0 else d := trunc((gBackSize.Y-gPlayerScreenSize.Y)*sY/(gMapInfo.Height-sHeight));
1544 //r_smallmap_h: 0: left; 1: center; 2: right
1545 //r_smallmap_v: 0: top; 1: center; 2: bottom
1546 // horiz small map?
1547 if (gMapInfo.Width = sWidth) then
1548 begin
1549 sX := 0;
1550 end
1551 else if (gMapInfo.Width < sWidth) then
1552 begin
1553 case r_smallmap_h of
1554 1: sX := -((sWidth-gMapInfo.Width) div 2); // center
1555 2: sX := -(sWidth-gMapInfo.Width); // right
1556 else sX := 0; // left
1557 end;
1558 end;
1559 // vert small map?
1560 if (gMapInfo.Height = sHeight) then
1561 begin
1562 sY := 0;
1563 end
1564 else if (gMapInfo.Height < sHeight) then
1565 begin
1566 case r_smallmap_v of
1567 1: sY := -((sHeight-gMapInfo.Height) div 2); // center
1568 2: sY := -(sHeight-gMapInfo.Height); // bottom
1569 else sY := 0; // top
1570 end;
1571 end;
1573 p.viewPortX := sX;
1574 p.viewPortY := sY;
1575 p.viewPortW := sWidth;
1576 p.viewPortH := sHeight;
1578 {$IFDEF ENABLE_HOLMES}
1579 if (p = gPlayer1) then
1580 begin
1581 g_Holmes_plrViewPos(sX, sY);
1582 g_Holmes_plrViewSize(sWidth, sHeight);
1583 end;
1584 {$ENDIF}
1586 renderMapInternal(-c, -d, true);
1588 if (gGameSettings.GameMode <> GM_SINGLE) and (gPlayerIndicator > 0) then
1589 case gPlayerIndicator of
1590 1:
1591 r_Player_DrawIndicator(p, _RGB(255, 255, 255));
1593 2:
1594 for i := 0 to High(gPlayers) do
1595 if gPlayers[i] <> nil then
1596 if gPlayers[i] = p then
1597 r_Player_DrawIndicator(p, _RGB(255, 255, 255))
1598 else if (gPlayers[i].Team = p.Team) and (gPlayers[i].Team <> TEAM_NONE) then
1599 if gPlayerIndicatorStyle = 1 then
1600 r_Player_DrawIndicator(gPlayers[i], _RGB(192, 192, 192))
1601 else
1602 r_Player_DrawIndicator(gPlayers[i], gPlayers[i].GetColor);
1603 end;
1606 for a := 0 to High(gCollideMap) do
1607 for b := 0 to High(gCollideMap[a]) do
1608 begin
1609 d := 0;
1610 if ByteBool(gCollideMap[a, b] and MARK_WALL) then
1611 d := d + 1;
1612 if ByteBool(gCollideMap[a, b] and MARK_DOOR) then
1613 d := d + 2;
1615 case d of
1616 1: e_DrawPoint(1, b, a, 200, 200, 200);
1617 2: e_DrawPoint(1, b, a, 64, 64, 255);
1618 3: e_DrawPoint(1, b, a, 255, 0, 255);
1619 end;
1620 end;
1623 glPopMatrix();
1625 r_Player_DrawPain(p);
1626 r_Player_DrawPickup(p);
1627 r_Player_DrawRulez(p);
1628 if gShowMap then DrawMinimap(p, _TRect(0, 0, 128, 128));
1629 if g_Debug_Player then
1630 r_Player_DrawDebug(p);
1631 r_Player_DrawGUI(p);
1632 end;
1634 procedure drawProfilers ();
1635 var
1636 px: Integer = -1;
1637 py: Integer = -1;
1638 begin
1639 if g_profile_frame_draw and (profileFrameDraw <> nil) then px := px-drawProfiles(px, py, profileFrameDraw);
1640 if g_profile_collision and (profMapCollision <> nil) then begin px := px-drawProfiles(px, py, profMapCollision); py -= calcProfilesHeight(profMonsLOS); end;
1641 if g_profile_los and (profMonsLOS <> nil) then begin px := px-drawProfiles(px, py, profMonsLOS); py -= calcProfilesHeight(profMonsLOS); end;
1642 end;
1644 procedure r_Game_Draw();
1645 var
1646 ID: DWORD;
1647 w, h: Word;
1648 ww, hh: Byte;
1649 Time: Int64;
1650 back: string;
1651 plView1, plView2: TPlayer;
1652 Split: Boolean;
1653 begin
1654 if gExit = EXIT_QUIT then Exit;
1656 Time := GetTickCount64() {div 1000};
1657 FPSCounter := FPSCounter+1;
1658 if Time - FPSTime >= 1000 then
1659 begin
1660 FPS := FPSCounter;
1661 FPSCounter := 0;
1662 FPSTime := Time;
1663 end;
1665 e_SetRendertarget(True);
1666 e_SetViewPort(0, 0, gScreenWidth, gScreenHeight);
1668 if gGameOn or (gState = STATE_FOLD) then
1669 begin
1670 if (gPlayer1 <> nil) and (gPlayer2 <> nil) then
1671 begin
1672 gSpectMode := SPECT_NONE;
1673 if not gRevertPlayers then
1674 begin
1675 plView1 := gPlayer1;
1676 plView2 := gPlayer2;
1677 end
1678 else
1679 begin
1680 plView1 := gPlayer2;
1681 plView2 := gPlayer1;
1682 end;
1683 end
1684 else
1685 if (gPlayer1 <> nil) or (gPlayer2 <> nil) then
1686 begin
1687 gSpectMode := SPECT_NONE;
1688 if gPlayer2 = nil then
1689 plView1 := gPlayer1
1690 else
1691 plView1 := gPlayer2;
1692 plView2 := nil;
1693 end
1694 else
1695 begin
1696 plView1 := nil;
1697 plView2 := nil;
1698 end;
1700 if (plView1 = nil) and (plView2 = nil) and (gSpectMode = SPECT_NONE) then
1701 gSpectMode := SPECT_STATS;
1703 if gSpectMode = SPECT_PLAYERS then
1704 if gPlayers <> nil then
1705 begin
1706 plView1 := GetActivePlayer_ByID(gSpectPID1);
1707 if plView1 = nil then
1708 begin
1709 gSpectPID1 := GetActivePlayerID_Next();
1710 plView1 := GetActivePlayer_ByID(gSpectPID1);
1711 end;
1712 if gSpectViewTwo then
1713 begin
1714 plView2 := GetActivePlayer_ByID(gSpectPID2);
1715 if plView2 = nil then
1716 begin
1717 gSpectPID2 := GetActivePlayerID_Next();
1718 plView2 := GetActivePlayer_ByID(gSpectPID2);
1719 end;
1720 end;
1721 end;
1723 if gSpectMode = SPECT_MAPVIEW then
1724 begin
1725 // Режим просмотра карты
1726 Split := False;
1727 e_SetViewPort(0, 0, gScreenWidth, gScreenHeight);
1728 DrawMapView(gSpectX, gSpectY, gScreenWidth, gScreenHeight);
1729 gHearPoint1.Active := True;
1730 gHearPoint1.Coords.X := gScreenWidth div 2 + gSpectX;
1731 gHearPoint1.Coords.Y := gScreenHeight div 2 + gSpectY;
1732 gHearPoint2.Active := False;
1733 end
1734 else
1735 begin
1736 Split := (plView1 <> nil) and (plView2 <> nil);
1738 // Точки слуха игроков
1739 if plView1 <> nil then
1740 begin
1741 gHearPoint1.Active := True;
1742 gHearPoint1.Coords.X := plView1.GameX + PLAYER_RECT.Width;
1743 gHearPoint1.Coords.Y := plView1.GameY + PLAYER_RECT.Height DIV 2;
1744 end else
1745 gHearPoint1.Active := False;
1746 if plView2 <> nil then
1747 begin
1748 gHearPoint2.Active := True;
1749 gHearPoint2.Coords.X := plView2.GameX + PLAYER_RECT.Width;
1750 gHearPoint2.Coords.Y := plView2.GameY + PLAYER_RECT.Height DIV 2;
1751 end else
1752 gHearPoint2.Active := False;
1754 // Размер экранов игроков:
1755 gPlayerScreenSize.X := gScreenWidth-196;
1756 if Split then
1757 begin
1758 gPlayerScreenSize.Y := gScreenHeight div 2;
1759 if gScreenHeight mod 2 = 0 then
1760 Dec(gPlayerScreenSize.Y);
1761 end
1762 else
1763 gPlayerScreenSize.Y := gScreenHeight;
1765 if Split then
1766 if gScreenHeight mod 2 = 0 then
1767 e_SetViewPort(0, gPlayerScreenSize.Y+2, gPlayerScreenSize.X+196, gPlayerScreenSize.Y)
1768 else
1769 e_SetViewPort(0, gPlayerScreenSize.Y+1, gPlayerScreenSize.X+196, gPlayerScreenSize.Y);
1771 DrawPlayer(plView1);
1772 gPlayer1ScreenCoord.X := sX;
1773 gPlayer1ScreenCoord.Y := sY;
1775 if Split then
1776 begin
1777 e_SetViewPort(0, 0, gPlayerScreenSize.X+196, gPlayerScreenSize.Y);
1779 DrawPlayer(plView2);
1780 gPlayer2ScreenCoord.X := sX;
1781 gPlayer2ScreenCoord.Y := sY;
1782 end;
1784 e_SetViewPort(0, 0, gScreenWidth, gScreenHeight);
1786 if Split then
1787 e_DrawLine(2, 0, gScreenHeight div 2, gScreenWidth, gScreenHeight div 2, 0, 0, 0);
1788 end;
1790 {$IFDEF ENABLE_HOLMES}
1791 // draw inspector
1792 if (g_holmes_enabled) then g_Holmes_Draw();
1793 {$ENDIF}
1795 if MessageText <> '' then
1796 begin
1797 w := 0;
1798 h := 0;
1799 e_CharFont_GetSizeFmt(gMenuFont, MessageText, w, h);
1800 if Split then
1801 e_CharFont_PrintFmt(gMenuFont, (gScreenWidth div 2)-(w div 2),
1802 (gScreenHeight div 2)-(h div 2), MessageText)
1803 else
1804 e_CharFont_PrintFmt(gMenuFont, (gScreenWidth div 2)-(w div 2),
1805 Round(gScreenHeight / 2.75)-(h div 2), MessageText);
1806 end;
1808 if IsDrawStat or (gSpectMode = SPECT_STATS) then
1809 DrawStat();
1811 if gSpectHUD and (not gChatShow) and (gSpectMode <> SPECT_NONE) and (not gSpectAuto) then
1812 begin
1813 // Draw spectator GUI
1814 ww := 0;
1815 hh := 0;
1816 e_TextureFontGetSize(gStdFont, ww, hh);
1817 case gSpectMode of
1818 SPECT_STATS:
1819 e_TextureFontPrintEx(0, gScreenHeight - (hh+2)*2, 'MODE: Stats', gStdFont, 255, 255, 255, 1);
1820 SPECT_MAPVIEW:
1821 e_TextureFontPrintEx(0, gScreenHeight - (hh+2)*2, 'MODE: Observe Map', gStdFont, 255, 255, 255, 1);
1822 SPECT_PLAYERS:
1823 e_TextureFontPrintEx(0, gScreenHeight - (hh+2)*2, 'MODE: Watch Players', gStdFont, 255, 255, 255, 1);
1824 end;
1825 e_TextureFontPrintEx(2*ww, gScreenHeight - (hh+2), '< jump >', gStdFont, 255, 255, 255, 1);
1826 if gSpectMode = SPECT_STATS then
1827 begin
1828 e_TextureFontPrintEx(16*ww, gScreenHeight - (hh+2)*2, 'Autoview', gStdFont, 255, 255, 255, 1);
1829 e_TextureFontPrintEx(16*ww, gScreenHeight - (hh+2), '< fire >', gStdFont, 255, 255, 255, 1);
1830 end;
1831 if gSpectMode = SPECT_MAPVIEW then
1832 begin
1833 e_TextureFontPrintEx(22*ww, gScreenHeight - (hh+2)*2, '[-]', gStdFont, 255, 255, 255, 1);
1834 e_TextureFontPrintEx(26*ww, gScreenHeight - (hh+2)*2, 'Step ' + IntToStr(gSpectStep), gStdFont, 255, 255, 255, 1);
1835 e_TextureFontPrintEx(34*ww, gScreenHeight - (hh+2)*2, '[+]', gStdFont, 255, 255, 255, 1);
1836 e_TextureFontPrintEx(18*ww, gScreenHeight - (hh+2), '<prev weap>', gStdFont, 255, 255, 255, 1);
1837 e_TextureFontPrintEx(30*ww, gScreenHeight - (hh+2), '<next weap>', gStdFont, 255, 255, 255, 1);
1838 end;
1839 if gSpectMode = SPECT_PLAYERS then
1840 begin
1841 e_TextureFontPrintEx(22*ww, gScreenHeight - (hh+2)*2, 'Player 1', gStdFont, 255, 255, 255, 1);
1842 e_TextureFontPrintEx(20*ww, gScreenHeight - (hh+2), '<left/right>', gStdFont, 255, 255, 255, 1);
1843 if gSpectViewTwo then
1844 begin
1845 e_TextureFontPrintEx(37*ww, gScreenHeight - (hh+2)*2, 'Player 2', gStdFont, 255, 255, 255, 1);
1846 e_TextureFontPrintEx(34*ww, gScreenHeight - (hh+2), '<prev w/next w>', gStdFont, 255, 255, 255, 1);
1847 e_TextureFontPrintEx(52*ww, gScreenHeight - (hh+2)*2, '2x View', gStdFont, 255, 255, 255, 1);
1848 e_TextureFontPrintEx(51*ww, gScreenHeight - (hh+2), '<up/down>', gStdFont, 255, 255, 255, 1);
1849 end
1850 else
1851 begin
1852 e_TextureFontPrintEx(35*ww, gScreenHeight - (hh+2)*2, '2x View', gStdFont, 255, 255, 255, 1);
1853 e_TextureFontPrintEx(34*ww, gScreenHeight - (hh+2), '<up/down>', gStdFont, 255, 255, 255, 1);
1854 end;
1855 end;
1856 end;
1857 end;
1859 if gPauseMain and gGameOn and (g_ActiveWindow = nil) then
1860 begin
1861 //e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
1862 e_DarkenQuadWH(0, 0, gScreenWidth, gScreenHeight, 150);
1864 e_CharFont_GetSize(gMenuFont, _lc[I_MENU_PAUSE], w, h);
1865 e_CharFont_Print(gMenuFont, (gScreenWidth div 2)-(w div 2),
1866 (gScreenHeight div 2)-(h div 2), _lc[I_MENU_PAUSE]);
1867 end;
1869 if not gGameOn then
1870 begin
1871 if (gState = STATE_MENU) then
1872 begin
1873 if (g_ActiveWindow = nil) or (g_ActiveWindow.BackTexture = '') then r_Game_DrawMenuBackground('MENU_BACKGROUND');
1874 // F3 at menu will show game loading dialog
1875 if e_KeyPressed(IK_F3) then g_Menu_Show_LoadMenu(true);
1876 if (g_ActiveWindow <> nil) then
1877 begin
1878 //e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
1879 e_DarkenQuadWH(0, 0, gScreenWidth, gScreenHeight, 150);
1880 end
1881 else
1882 begin
1883 // F3 at titlepic will show game loading dialog
1884 if e_KeyPressed(IK_F3) then
1885 begin
1886 g_Menu_Show_LoadMenu(true);
1887 if (g_ActiveWindow <> nil) then e_DarkenQuadWH(0, 0, gScreenWidth, gScreenHeight, 150);
1888 end;
1889 end;
1890 end;
1892 if gState = STATE_FOLD then
1893 begin
1894 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 0, 0, 0, EndingGameCounter);
1895 end;
1897 if gState = STATE_INTERCUSTOM then
1898 begin
1899 if gLastMap and (gGameSettings.GameMode = GM_COOP) then
1900 begin
1901 back := 'TEXTURE_endpic';
1902 if not g_Texture_Get(back, ID) then
1903 back := _lc[I_TEXTURE_ENDPIC];
1904 end
1905 else
1906 back := 'INTER';
1908 r_Game_DrawMenuBackground(back);
1910 DrawCustomStat();
1912 if g_ActiveWindow <> nil then
1913 begin
1914 //e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
1915 e_DarkenQuadWH(0, 0, gScreenWidth, gScreenHeight, 150);
1916 end;
1917 end;
1919 if gState = STATE_INTERSINGLE then
1920 begin
1921 if EndingGameCounter > 0 then
1922 begin
1923 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 0, 0, 0, EndingGameCounter);
1924 end
1925 else
1926 begin
1927 back := 'INTER';
1929 r_Game_DrawMenuBackground(back);
1931 DrawSingleStat();
1933 if g_ActiveWindow <> nil then
1934 begin
1935 //e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
1936 e_DarkenQuadWH(0, 0, gScreenWidth, gScreenHeight, 150);
1937 end;
1938 end;
1939 end;
1941 if gState = STATE_ENDPIC then
1942 begin
1943 ID := DWORD(-1);
1944 if g_Texture_Get('TEXTURE_endpic', ID) then r_Game_DrawMenuBackground('TEXTURE_endpic')
1945 else r_Game_DrawMenuBackground(_lc[I_TEXTURE_ENDPIC]);
1947 if g_ActiveWindow <> nil then
1948 begin
1949 //e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
1950 e_DarkenQuadWH(0, 0, gScreenWidth, gScreenHeight, 150);
1951 end;
1952 end;
1954 if gState = STATE_SLIST then
1955 begin
1956 // if g_Texture_Get('MENU_BACKGROUND', ID) then
1957 // begin
1958 // e_DrawSize(ID, 0, 0, 0, False, False, gScreenWidth, gScreenHeight);
1959 // //e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
1960 // end;
1961 r_Game_DrawMenuBackground('MENU_BACKGROUND');
1962 e_DarkenQuadWH(0, 0, gScreenWidth, gScreenHeight, 150);
1963 r_Serverlist_Draw(slCurrent, slTable);
1964 end;
1965 end;
1967 if g_ActiveWindow <> nil then
1968 begin
1969 if gGameOn then
1970 begin
1971 //e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
1972 e_DarkenQuadWH(0, 0, gScreenWidth, gScreenHeight, 150);
1973 end;
1974 g_ActiveWindow.Draw();
1975 end;
1977 {$IFNDEF HEADLESS}
1978 r_Console_Draw();
1979 {$ENDIF}
1981 if g_debug_Sounds and gGameOn then
1982 begin
1983 for w := 0 to High(e_SoundsArray) do
1984 for h := 0 to e_SoundsArray[w].nRefs do
1985 e_DrawPoint(1, w+100, h+100, 255, 0, 0);
1986 end;
1988 if gShowFPS then
1989 begin
1990 e_TextureFontPrint(0, 0, Format('FPS: %d', [FPS]), gStdFont);
1991 e_TextureFontPrint(0, 16, Format('UPS: %d', [UPS]), gStdFont);
1992 end;
1994 if gGameOn and gShowTime then
1995 drawTime(gScreenWidth-72, gScreenHeight-16);
1997 if gGameOn then drawProfilers();
1999 // TODO: draw this after the FBO and remap mouse click coordinates
2001 {$IFDEF ENABLE_HOLMES}
2002 g_Holmes_DrawUI();
2003 {$ENDIF}
2005 // blit framebuffer to screen
2007 e_SetRendertarget(False);
2008 e_SetViewPort(0, 0, gWinSizeX, gWinSizeY);
2009 e_BlitFramebuffer(gWinSizeX, gWinSizeY);
2011 // draw the overlay stuff on top of it
2013 g_Touch_Draw;
2014 end;
2016 end.