DEADSOFTWARE

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