DEADSOFTWARE

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