DEADSOFTWARE

gl: implement touch screen controls
[d2df-sdl.git] / src / game / renders / opengl / r_render.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_render;
18 interface
20 uses
21 {$IFDEF ENABLE_MENU}
22 g_gui,
23 {$ENDIF}
24 g_base // TRectWH
25 ;
27 type
28 TProcedure = procedure;
30 (* render startup *)
31 procedure r_Render_Initialize;
32 procedure r_Render_Finalize;
34 (* load globally used textures *)
35 procedure r_Render_Load;
36 procedure r_Render_Free;
38 (* load map specific textures *)
39 procedure r_Render_LoadTextures;
40 procedure r_Render_FreeTextures;
42 procedure r_Render_Update;
43 procedure r_Render_Draw;
45 procedure r_Render_Resize (w, h: Integer);
46 procedure r_Render_Apply;
48 function r_Render_WriteScreenShot (filename: String): Boolean;
50 {$IFDEF ENABLE_GIBS}
51 function r_Render_GetGibRect (m, id: Integer): TRectWH;
52 {$ENDIF}
54 {$IFDEF ENABLE_GFX}
55 procedure r_Render_QueueEffect (AnimType, X, Y: Integer);
56 {$ENDIF}
58 {$IFDEF ENABLE_TOUCH}
59 // touch screen button location and size
60 procedure r_Render_GetKeyRect (key: Integer; out x, y, w, h: Integer; out founded: Boolean);
61 {$ENDIF}
63 {$IFDEF ENABLE_MENU}
64 procedure r_Render_GetControlSize (ctrl: TGUIControl; out w, h: Integer);
65 procedure r_Render_GetLogoSize (out w, h: Integer);
66 procedure r_Render_GetMaxFontSize (BigFont: Boolean; out w, h: Integer);
67 procedure r_Render_GetStringSize (BigFont: Boolean; str: String; out w, h: Integer);
68 {$ENDIF}
70 procedure r_Render_SetProcessLoadingCallback (p: TProcedure);
71 procedure r_Render_ClearLoading;
72 procedure r_Render_SetLoading (const text: String; maxval: Integer);
73 procedure r_Render_StepLoading (incval: Integer);
74 procedure r_Render_DrawLoading (force: Boolean);
76 {$IFDEF ENABLE_HOLMES}
77 function pmsCurMapX (): Integer;
78 function pmsCurMapY (): Integer;
79 function r_Render_HolmesViewIsSet (): Boolean;
80 {$ENDIF}
82 implementation
84 uses
85 {$IFDEF USE_GLES1}
86 GLES11,
87 {$ELSE}
88 GL, GLEXT,
89 {$ENDIF}
90 {$IFDEF ENABLE_MENU}
91 r_gui,
92 {$ENDIF}
93 {$IFDEF ENABLE_SYSTEM}
94 g_system,
95 {$ENDIF}
96 {$IFDEF ENABLE_TOUCH}
97 r_touch,
98 {$ENDIF}
99 {$IFDEF ENABLE_HOLMES}
100 r_holmes,
101 {$ENDIF}
102 SysUtils, Classes, Math,
103 g_basic,
104 e_log, utils, wadreader, mapdef,
105 g_game, g_map, g_panel, g_options, g_console, g_player, g_weapons, g_language, g_triggers, g_monsters,
106 g_net, g_netmaster,
107 r_draw, r_textures, r_fonts, r_common, r_console, r_map, r_loadscreen
110 var
111 hud, hudbg: TGLTexture;
112 hudhp: array [Boolean] of TGLTexture;
113 hudap: TGLTexture;
114 hudwp: array [0..WP_LAST] of TGLTexture;
115 hudkey: array [0..2] of TGLTexture;
116 hudair: TGLTexture;
117 hudjet: TGLTexture;
118 hudrflag, hudrflags, hudrflagd: TGLTexture;
119 hudbflag, hudbflags, hudbflagd: TGLTexture;
121 FPS, FPSCounter, FPSTime: LongWord;
123 procedure r_Render_LoadTextures;
124 begin
125 r_Map_LoadTextures;
126 end;
128 procedure r_Render_FreeTextures;
129 begin
130 r_Map_FreeTextures;
131 end;
133 procedure r_Render_Load;
134 const
135 WeapName: array [0..WP_LAST] of AnsiString = ('KASTET', 'SAW', 'PISTOL', 'SHOTGUN1', 'SHOTGUN2', 'MGUN', 'RLAUNCHER', 'PGUN', 'BFG', 'SPULEMET', 'FLAMETHROWER');
136 var
137 i: Integer;
138 begin
139 r_LoadScreen_Load;
140 r_Common_Load;
141 r_Common_SetLoading('HUD Textures', 5 + (WP_LAST + 1) + 11);
142 hud := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/HUD', [TGLHints.txNoRepeat]);
143 hudbg := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/HUDBG', []);
144 hudhp[false] := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/MED2', [TGLHints.txNoRepeat]);
145 hudhp[true] := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/BMED', [TGLHints.txNoRepeat]);
146 hudap := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/ARMORHUD', [TGLHints.txNoRepeat]);
147 for i := 0 to WP_LAST do
148 hudwp[i] := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/' + WeapName[i], [TGLHints.txNoRepeat]);
149 hudkey[0] := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/KEYR', [TGLHints.txNoRepeat]);
150 hudkey[1] := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/KEYG', [TGLHints.txNoRepeat]);
151 hudkey[2] := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/KEYB', [TGLHints.txNoRepeat]);
152 hudair := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/AIRBAR', [TGLHints.txNoRepeat]);
153 hudjet := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/JETBAR', [TGLHints.txNoRepeat]);
154 hudrflag := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/FLAGHUD_R_BASE', [TGLHints.txNoRepeat]);
155 hudrflags := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/FLAGHUD_R_STOLEN', [TGLHints.txNoRepeat]);
156 hudrflagd := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/FLAGHUD_R_DROP', [TGLHints.txNoRepeat]);
157 hudbflag := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/FLAGHUD_B_BASE', [TGLHints.txNoRepeat]);
158 hudbflags := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/FLAGHUD_B_STOLEN', [TGLHints.txNoRepeat]);
159 hudbflagd := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/FLAGHUD_B_DROP', [TGLHints.txNoRepeat]);
160 r_Console_Load;
161 r_Map_Load;
162 {$IFDEF ENABLE_MENU}
163 r_GUI_Load;
164 {$ENDIF}
165 end;
167 procedure r_Render_Free;
168 var i: Integer;
169 begin
170 {$IFDEF ENABLE_MENU}
171 r_GUI_Free;
172 {$ENDIF}
173 r_Map_Free;
174 r_Console_Free;
175 r_Common_FreeAndNil(hudbflagd);
176 r_Common_FreeAndNil(hudbflags);
177 r_Common_FreeAndNil(hudbflag);
178 r_Common_FreeAndNil(hudrflagd);
179 r_Common_FreeAndNil(hudrflags);
180 r_Common_FreeAndNil(hudrflag);
181 r_Common_FreeAndNil(hudjet);
182 r_Common_FreeAndNil(hudair);
183 r_Common_FreeAndNil(hudkey[0]);
184 r_Common_FreeAndNil(hudkey[1]);
185 r_Common_FreeAndNil(hudkey[2]);
186 for i := 0 to WP_LAST do
187 r_Common_FreeAndNil(hudwp[i]);
188 r_Common_FreeAndNil(hudap);
189 r_Common_FreeAndNil(hudhp[true]);
190 r_Common_FreeAndNil(hudhp[false]);
191 r_Common_FreeAndNil(hudbg);
192 r_Common_FreeAndNil(hud);
193 r_Common_Free;
194 end;
196 {$IFDEF ENABLE_SYSTEM}
197 function GetInfo (): TGLDisplayInfo;
198 var info: TGLDisplayInfo;
199 begin
200 info := Default(TGLDisplayInfo);
201 info.w := Max(1, gRC_Width);
202 info.h := Max(1, gRC_Height);
203 info.bpp := Max(1, gBPP);
204 info.fullscreen := gRC_FullScreen;
205 info.maximized := gRC_Maximized;
206 info.major := 1;
207 info.minor := 1;
208 info.profile := TGLProfile.Compat;
209 result := info;
210 end;
211 {$ENDIF}
213 procedure r_Render_Initialize;
214 begin
215 {$IFDEF ENABLE_SYSTEM}
216 if sys_SetDisplayModeGL(GetInfo()) = False then
217 raise Exception.Create('Failed to set videomode on startup.');
218 sys_EnableVSync(gVSync);
219 {$ENDIF}
220 r_LoadScreen_Initialize;
221 r_Textures_Initialize;
222 r_Console_Initialize;
223 r_Map_Initialize;
224 end;
226 procedure r_Render_Finalize;
227 begin
228 r_Map_Finalize;
229 r_Console_Finalize;
230 r_Textures_Finalize;
231 r_LoadScreen_Finalize;
232 end;
234 procedure r_Render_Update;
235 begin
236 r_Console_Update;
237 r_Map_Update;
238 end;
240 procedure r_Render_DrawHUD (x, y: Integer; p: TPlayer);
241 var t: TGLTexture; s: AnsiString;
242 begin
243 ASSERT(p <> nil);
245 // hud area is 196 x 240 pixels
246 r_Common_DrawTexture(hud, x, y, hud.width, hud.height, TBasePoint.BP_LEFTUP);
247 r_Common_DrawText(p.name, x + 98, y + 16, 255, 0, 0, 255, smallfont, TBasePoint.BP_CENTER);
249 t := hudhp[R_BERSERK in p.FRulez];
250 r_Common_DrawTexture(t, x + 51, y + 61, t.width, t.height, TBasePoint.BP_CENTER);
251 r_Common_DrawTexture(hudap, x + 50, y + 85, hudap.width, hudap.height, TBasePoint.BP_CENTER);
253 r_Common_DrawText(IntToStr(MAX(0, p.health)), x + 174, y + 56, 255, 0, 0, 255, menufont, TBasePoint.BP_RIGHT);
254 r_Common_DrawText(IntToStr(MAX(0, p.armor)), x + 174, y + 84, 255, 0, 0, 255, menufont, TBasePoint.BP_RIGHT);
256 case p.CurrWeap of
257 WEAPON_KASTET, WEAPON_SAW: s := '--';
258 else s := IntToStr(p.GetAmmoByWeapon(p.CurrWeap));
259 end;
260 r_Common_DrawText(s, x + 174, y + 174, 255, 0, 0, 255, menufont, TBasePoint.BP_RIGHT);
262 if p.CurrWeap <= WP_LAST then
263 begin
264 t := hudwp[p.CurrWeap];
265 r_Common_DrawTexture(t, x + 18, y + 160, t.width, t.height, TBasePoint.BP_LEFTUP);
266 end;
268 if R_KEY_RED in p.FRulez then
269 r_Common_DrawTexture(hudkey[0], x + 76, y + 214, 16, 16, TBasePoint.BP_LEFTUP);
270 if R_KEY_GREEN in p.FRulez then
271 r_Common_DrawTexture(hudkey[1], x + 93, y + 214, 16, 16, TBasePoint.BP_LEFTUP);
272 if R_KEY_BLUE in p.FRulez then
273 r_Common_DrawTexture(hudkey[2], x + 110, y + 214, 16, 16, TBasePoint.BP_LEFTUP);
275 if p.JetFuel > 0 then
276 begin
277 r_Common_DrawTexture(hudair, x, y + 116, hudair.width, hudair.height, TBasePoint.BP_LEFTUP);
278 if p.air > 0 then
279 r_Draw_FillRect(x + 14, y + 116 + 4, x + 14 + 168 * p.air div AIR_MAX, y + 116 + 4 + 4, 0, 0, 196, 255);
280 r_Common_DrawTexture(hudjet, x, y + 126, hudjet.width, hudjet.height, TBasePoint.BP_LEFTUP);
281 r_Draw_FillRect(x + 14, y + 126 + 4, x + 14 + 168 * p.JetFuel div JET_MAX, y + 126 + 4 + 4, 208, 0, 0, 255);
282 end
283 else
284 begin
285 r_Common_DrawTexture(hudair, x, y + 124, hudair.width, hudair.height, TBasePoint.BP_LEFTUP);
286 if p.air > 0 then
287 r_Draw_FillRect(x + 14, y + 124 + 4, x + 14 + 168 * p.air div AIR_MAX, y + 124 + 4 + 4, 0, 0, 196, 255);
288 end;
289 end;
291 procedure r_Render_DrawHUDArea (x, y, w, h: Integer; p: TPlayer);
292 var s: AnsiString; oldy: Integer;
293 begin
294 r_Common_DrawTexture(hudbg, x, y, w, h, TBasePoint.BP_LEFTUP);
296 if p <> nil then
297 begin
298 oldy := y;
299 if h < 239 then y := y - 32; (* hack: hide nickname on 640x400 *)
300 r_Render_DrawHUD(x + w - 196 + 2, y, p);
301 if p.Spectator then
302 begin
303 r_Common_DrawText(_lc[I_PLAYER_SPECT], x + 4, y + 242, 255, 255, 255, 255, stdfont, TBasePoint.BP_LEFTUP);
304 r_Common_DrawText(_lc[I_PLAYER_SPECT2], x + 4, y + 258, 255, 255, 255, 255, stdfont, TBasePoint.BP_LEFTUP);
305 r_Common_DrawText(_lc[I_PLAYER_SPECT1], x + 4, y + 274, 255, 255, 255, 255, stdfont, TBasePoint.BP_LEFTUP);
306 if p.NoRespawn then
307 r_Common_DrawText(_lc[I_PLAYER_SPECT1S], x + 4, y + 290, 255, 255, 255, 255, stdfont, TBasePoint.BP_LEFTUP);
308 end;
309 y := oldy;
310 end;
312 if gShowPing and g_Game_IsClient then
313 begin
314 s := _lc[I_GAME_PING_HUD] + IntToStr(NetPeer.lastRoundTripTime) + _lc[I_NET_SLIST_PING_MS];
315 r_Common_DrawText(s, x + 4, y + 242, 255, 255, 255, 255, stdfont, TBasePoint.BP_LEFTUP);
316 end;
317 end;
319 procedure r_Render_DrawStatsView (x, y, w, h: Integer; p: TPlayer);
320 var fw, i, maxFrags, top, totalPlayers: Integer; sign: Char; stat: TPlayerStatArray; f: TGLTexture;
321 begin
322 ASSERT(p <> nil);
324 if gShowScore and (gGameSettings.GameMode in [GM_TDM, GM_CTF]) then
325 begin
326 (* RED TEAM GOALS *)
327 fw := 0;
328 if gGameSettings.GameMode = GM_CTF then
329 begin
330 case gFlags[FLAG_RED].State of
331 FLAG_STATE_CAPTURED: f := hudrflags;
332 FLAG_STATE_DROPPED: f := hudrflagd;
333 otherwise f := hudrflag;
334 end;
335 if f <> nil then
336 begin
337 fw := f.width + 8; (* + space *)
338 r_Common_DrawTexture(f, x + w - 16, y + 240 - 72 - 4, f.width, f.height, TBasePoint.BP_RIGHTUP);
339 end;
340 end;
341 r_Common_DrawText(IntToStr(gTeamStat[TEAM_RED].Score), x + w - 16 - fw, y + 240 - 72 - 4, TEAMCOLOR[TEAM_RED].R, TEAMCOLOR[TEAM_RED].G, TEAMCOLOR[TEAM_RED].B, 255, menufont, TBasePoint.BP_RIGHTUP);
343 (* BLUE TEAM GOALS *)
344 fw := 0;
345 if gGameSettings.GameMode = GM_CTF then
346 begin
347 case gFlags[FLAG_BLUE].State of
348 FLAG_STATE_CAPTURED: f := hudbflags;
349 FLAG_STATE_DROPPED: f := hudbflagd;
350 otherwise f := hudbflag;
351 end;
352 if f <> nil then
353 begin
354 fw := f.width + 8; (* + space *)
355 r_Common_DrawTexture(f, x + w - 16, y + 240 - 32 - 4, f.width, f.height, TBasePoint.BP_RIGHTUP);
356 end;
357 end;
358 r_Common_DrawText(IntToStr(gTeamStat[TEAM_BLUE].Score), x + w - 16 - fw, y + 240 - 32 - 4, TEAMCOLOR[TEAM_BLUE].R, TEAMCOLOR[TEAM_BLUE].G, TEAMCOLOR[TEAM_BLUE].B, 255, menufont, TBasePoint.BP_RIGHTUP);
359 end;
361 if gGameSettings.GameType in [GT_CUSTOM, GT_SERVER, GT_CLIENT] then
362 begin
363 if gShowStat then
364 begin
365 r_Common_DrawText(IntToStr(p.Frags), x + w - 16, y, 255, 0, 0, 255, menufont, TBasePoint.BP_RIGHTUP);
367 top := 1;
368 maxFrags := 0;
369 totalPlayers := 0;
370 stat := g_Player_GetStats();
371 if stat <> nil then
372 begin
373 totalPlayers := Length(stat);
374 for i := 0 to High(stat) do
375 begin
376 if stat[i].Name <> p.Name then
377 begin
378 maxFrags := MAX(maxFrags, stat[i].Frags);
379 if stat[i].Frags > p.Frags then
380 top := top + 1;
381 end;
382 end;
383 end;
384 if p.Frags >= maxFrags then sign := '+' else sign := '-';
385 r_Common_DrawText(IntToStr(top) + ' / ' + IntToStr(totalPlayers) + ' ' + sign + IntToStr(ABS(p.Frags - maxFrags)), x + w - 16, y + 32, 255, 0, 0, 255, smallfont, TBasePoint.BP_RIGHTUP);
386 end;
388 if gLMSRespawn > LMS_RESPAWN_NONE then
389 begin
390 r_Common_DrawText(_lc[I_GAME_WARMUP], x + w - 16 - 64, y + h, 0, 255, 0, 255, menufont, TBasePoint.BP_RIGHTDOWN);
391 r_Common_DrawText(': ' + IntToStr((gLMSRespawnTime - gTime) div 1000), x + w - 16 - 64, y + h, 0, 255, 0, 255, menufont, TBasePoint.BP_LEFTDOWN);
392 end
393 else if gShowLives and (gGameSettings.MaxLives > 0) then
394 begin
395 r_Common_DrawText(IntToStr(p.Lives), x + w - 16, y + h, 0, 255, 0, 255, menufont, TBasePoint.BP_RIGHTDOWN);
396 end;
397 end;
398 end;
400 procedure r_Render_DrawView (x, y, w, h: Integer; p: TPlayer);
401 var l, t, r, b, xx, yy, cx, cy: Integer;
402 begin
403 r_Draw_GetRect(l, t, r, b);
404 r_Draw_SetRect(x, y, x + w, y + h);
406 r_Common_GetCameraPos(p, true, xx, yy);
407 if p <> nil then
408 begin
409 r_Map_Draw(x, y, w, h, xx, yy, p, cx, cy);
410 {$IFDEF ENABLE_HOLMES}
411 if p = gPlayer1 then
412 begin
413 r_Holmes_plrViewPos(cx, cy);
414 r_Holmes_plrViewSize(h, w);
415 end;
416 {$ENDIF}
417 r_Render_DrawStatsView(x, y, w, h, p);
418 if p.Spectator and p.NoRespawn then
419 r_Common_DrawText(_lc[I_PLAYER_SPECT4], x div 2 + w div 2, y div 2 + h div 2, 255, 255, 255, 255, stdfont, TBasePoint.BP_CENTER);
420 end
421 else
422 begin
423 r_Map_Draw(x, y, w, h, xx, yy, nil, cx, cy);
424 end;
426 r_Draw_SetRect(l, t, r, b);
427 end;
429 procedure r_Render_DrawMapView (x, y, w, h, camx, camy: Integer);
430 var l, t, r, b, cx, cy: Integer;
431 begin
432 r_Draw_GetRect(l, t, r, b);
433 r_Draw_SetRect(x, y, x + w, y + h);
434 r_Map_Draw(x, y, w, h, camx, camy, nil, cx, cy);
435 r_Draw_SetRect(l, t, r, b);
436 end;
438 procedure r_Render_DrawPlayerView (x, y, w, h: Integer; p: TPlayer);
439 var l, t, r, b: Integer;
440 begin
441 r_Draw_GetRect(l, t, r, b);
442 r_Draw_SetRect(x, y, x + w, y + h);
443 r_Render_DrawView(x, y, w - 196, h, p);
444 r_Render_DrawHUDArea(x + w - 196, y, 196, h, p);
445 r_Draw_SetRect(l, t, r, b);
446 end;
448 procedure r_Render_DrawServerList (var SL: TNetServerList; var ST: TNetServerTable);
449 var ip: AnsiString; ww, hh, cw, ch, mw, mh, motdh, scrx, scry, i, mx, y: Integer; msg: SSArray; Srv: TNetServer;
450 begin
451 scrx := gScreenWidth div 2;
452 scry := gScreenHeight div 2;
454 r_Draw_GetTextSize(_lc[I_NET_SLIST], menufont, ww, hh);
455 r_Common_DrawText(_lc[I_NET_SLIST], gScreenWidth div 2, 16, 255, 255, 255, 255, menufont, TBasePoint.BP_UP);
457 r_Draw_GetTextSize('W', stdfont, cw, ch);
458 motdh := gScreenHeight - 49 - ch * b_Text_LineCount(slMOTD);
460 r_Draw_FillRect(16, 64, gScreenWidth - 16, motdh, 64, 64, 64, 145);
461 r_Draw_Rect(16, 64, gScreenWidth - 16, motdh, 255, 127, 0, 255);
463 r_Common_DrawText(_lc[I_NET_SLIST_HELP], gScreenWidth div 2, gScreenHeight - 8, 255, 255, 255, 255, stdfont, TBasePoint.BP_DOWN);
465 if slMOTD <> '' then
466 begin
467 r_Draw_FillRect(16, motdh, gScreenWidth - 16, gScreenHeight - 44, 64, 64, 64, 110);
468 r_Draw_Rect(16, motdh, gScreenWidth - 16, gScreenHeight - 44, 255, 127, 0, 255);
469 r_Common_DrawFormatText(slMOTD, 20, motdh + 3, 255, stdfont, TBasePoint.BP_LEFTUP);
470 end;
472 if not slReadUrgent and (slUrgent <> '') then
473 begin
474 r_Draw_FillRect(17, 65, gScreenWidth - 17, motdh - 1, 64, 64, 64, 127);
475 r_Draw_FillRect(scrx - 256, scry - 60, scrx + 256, scry + 60, 64, 64, 64, 127);
476 r_Draw_Rect(scrx - 256, scry - 60, scrx + 256, scry + 60, 255, 127, 0, 255);
477 r_Draw_FillRect(scrx - 256, scry - 40, scrx + 256, scry - 40, 255, 127, 0, 255);
478 r_Common_DrawText(_lc[I_NET_SLIST_URGENT], scrx, scry - 58, 255, 255, 255, 255, stdfont, TBasePoint.BP_UP);
479 r_Common_DrawFormatText(slUrgent, scrx - 253, scry - 38, 255, stdfont, TBasePoint.BP_LEFTUP);
480 r_Common_DrawText(_lc[I_NET_SLIST_URGENT_CONT], scrx, scry + 41, 255, 255, 255, 255, stdfont, TBasePoint.BP_UP);
481 r_Draw_FillRect(scrx - 256, scry + 40, scrx + 256, scry + 40, 255, 127, 0, 255);
482 end
483 else if SL = nil then
484 begin
485 r_Draw_FillRect(17, 65, gScreenWidth - 17, motdh - 1, 64, 64, 64, 127);
486 r_Draw_Rect(scrx - 192, scry - 10, scrx + 192, scry + 11, 255, 127, 0, 255);
487 r_Common_DrawText(slWaitStr, scrx, scry, 255, 255, 255, 255, stdfont, TBasePoint.BP_CENTER);
488 end
489 else
490 begin
491 y := 90;
492 if slSelection < Length(ST) then
493 begin
494 sy := y + 42 * slSelection - 4;
495 Srv := GetServerFromTable(slSelection, SL, ST);
496 ip := _lc[I_NET_ADDRESS] + ' ' + Srv.IP + ':' + IntToStr(Srv.Port);
497 ip := ip + ' ' + _lc[I_NET_SERVER_PASSWORD] + ' ';
498 if Srv.Password then ip := ip + _lc[I_MENU_YES] else ip := ip +_lc[I_MENU_NO];
499 end;
501 mw := gScreenWidth - 188;
502 mx := 16 + mw;
504 r_Draw_FillRect(16 + 1, sy, gScreenWidth - 16 - 1, sy + 40, 64, 64, 64, 255);
505 r_Draw_FillRect(16 + 1, sy, gScreenWidth - 16 - 1, sy, 205, 205, 205, 255);
506 r_Draw_FillRect(16 + 1, sy + 41, gScreenWidth - 16 - 1, sy + 41, 255, 255, 255, 255);
508 r_Draw_FillRect(16, 85, gScreenWidth - 16, 85, 255, 127, 0, 255);
509 r_Draw_FillRect(16, motdh - 20, gScreenWidth - 16, motdh - 20, 255, 127, 0, 255);
511 r_Draw_FillRect(mx - 70, 64, mx - 70, motdh, 255, 127, 0, 255);
512 r_Draw_FillRect(mx, 64, mx, motdh - 20, 255, 127, 0, 255);
513 r_Draw_FillRect(mx + 52, 64, mx + 52, motdh - 20, 255, 127, 0, 255);
514 r_Draw_FillRect(mx + 104, 64, mx + 104, motdh - 20, 255, 127, 0, 255);
516 r_Common_DrawText('NAME/MAP', 18, 68, 255, 127, 0, 255, stdfont, TBasePoint.BP_LEFTUP);
517 r_Common_DrawText('PING', mx - 68, 68, 255, 127, 0, 255, stdfont, TBasePoint.BP_LEFTUP);
518 r_Common_DrawText('MODE', mx + 2, 68, 255, 127, 0, 255, stdfont, TBasePoint.BP_LEFTUP);
519 r_Common_DrawText('PLRS', mx + 54, 68, 255, 127, 0, 255, stdfont, TBasePoint.BP_LEFTUP);
520 r_Common_DrawText('VER', mx + 106, 68, 255, 127, 0, 255, stdfont, TBasePoint.BP_LEFTUP);
522 for i := 0 to High(ST) do
523 begin
524 Srv := GetServerFromTable(i, SL, ST);
525 r_Common_DrawText(Srv.Name, 18, y, 255, 255, 255, 255, stdfont, TBasePoint.BP_LEFTUP);
526 r_Common_DrawText(Srv.Map, 18, y + 16, 210, 210, 210, 255, stdfont, TBasePoint.BP_LEFTUP);
528 if Srv.Ping = 0 then
529 r_Common_DrawText('<1' + _lc[I_NET_SLIST_PING_MS], mx - 68, y, 255, 255, 255, 255, stdfont, TBasePoint.BP_LEFTUP)
530 else if (Srv.Ping >= 0) and (Srv.Ping <= 999) then
531 r_Common_DrawText(IntToStr(Srv.Ping) + _lc[I_NET_SLIST_PING_MS], mx - 68, y, 255, 255, 255, 255, stdfont, TBasePoint.BP_LEFTUP)
532 else
533 r_Common_DrawText(_lc[I_NET_SLIST_NO_ACCESS], mx - 68, y, 255, 0, 0, 255, stdfont, TBasePoint.BP_LEFTUP);
534 if Length(ST[I].Indices) > 1 then
535 r_Common_DrawText('<' + IntToStr(Length(ST[I].Indices)) + '>', mx - 68, y + 16, 210, 210, 210, 255, stdfont, TBasePoint.BP_LEFTUP);
537 r_Common_DrawText(g_Game_ModeToText(Srv.GameMode), mx + 2, y, 255, 255, 255, 255, stdfont, TBasePoint.BP_LEFTUP);
539 r_Common_DrawText(IntToStr(Srv.Players) + '/' + IntToStr(Srv.MaxPlayers), mx + 54, y, 255, 255, 255, 255, stdfont, TBasePoint.BP_LEFTUP);
540 r_Common_DrawText(IntToStr(Srv.LocalPl) + '+' + IntToStr(Srv.Bots), mx + 54, y + 16, 210, 210, 210, 255, stdfont, TBasePoint.BP_LEFTUP);
542 r_Common_DrawText(IntToStr(Srv.Protocol), mx + 106, y, 255, 255, 255, 255, stdfont, TBasePoint.BP_LEFTUP);
544 y := y + 42;
545 end;
547 r_Common_DrawText(ip, 20, motdh - 20 + 3, 205, 205, 205, 255, stdfont, TBasePoint.BP_LEFTUP);
548 r_Common_DrawText(IntToStr(Length(ST)) + _lc[I_NET_SLIST_SERVERS], gScreenWidth - 48, motdh - 20 + 3, 255, 255, 255, 255, stdfont, TBasePoint.BP_RIGHTUP);
549 end;
550 end;
552 procedure r_Render_DrawStatsColumns (constref cs: TEndCustomGameStat; x, y, w: Integer; endview: Boolean);
553 var i, cw, ch, yy, team, players, w1, w2, w3, w4, tw: Integer; r, g, b, rr, gg, bb: Byte; s: AnsiString;
554 begin
555 r_Draw_GetTextSize('W', stdfont, cw, ch);
556 w4 := cw * 6; (* deaths width *)
557 w3 := cw * 8; (* frags width *)
558 w2 := cw * 12; (* ping/loss width *)
559 w1 := w - w2 - w3 - w4; (* name width *)
560 tw := w1 - cw * 2 - w2; (* team goals *)
561 if cs.PlayerStat = nil then players := 0 else players := Length(cs.PlayerStat);
562 yy := y;
563 if cs.GameMode in [GM_TDM, GM_CTF] then
564 begin
565 for team := TEAM_RED to TEAM_BLUE do
566 begin
567 case team of
568 TEAM_RED:
569 begin
570 s := _lc[I_GAME_TEAM_RED];
571 r := 255; g := 0; b := 0;
572 end;
573 TEAM_BLUE:
574 begin
575 s := _lc[I_GAME_TEAM_BLUE];
576 r := 0; g := 0; b := 255;
577 end;
578 end;
579 r_Common_DrawText(s, x, yy, r, g, b, 255, stdfont, TBasePoint.BP_LEFTUP);
580 r_Common_DrawText(IntToStr(cs.TeamStat[team].Score), x + tw, yy, r, g, b, 255, stdfont, TBasePoint.BP_UP);
581 if endview = false then
582 r_Common_DrawText(_lc[I_GAME_PING], x + w1, yy, r, g, b, 255, stdfont, TBasePoint.BP_UP);
583 r_Common_DrawText(_lc[I_GAME_FRAGS], x + w1 + w2, yy, r, g, b, 255, stdfont, TBasePoint.BP_UP);
584 r_Common_DrawText(_lc[I_GAME_DEATHS], x + w1 + w2 + w3, yy, r, g, b, 255, stdfont, TBasePoint.BP_UP);
585 INC(yy, ch);
587 INC(yy, ch div 4);
588 r_Draw_FillRect(x, yy, x + w - 1, yy, r, g, b, 255);
589 INC(yy, ch div 4);
591 for i := 0 to players - 1 do
592 begin
593 if cs.PlayerStat[i].Team = team then
594 begin
595 rr := r; gg := g; bb := b;
596 if cs.PlayerStat[i].Spectator then
597 begin
598 rr := r div 2; gg := g div 2; bb := b div 2;
599 end;
601 // Player name
602 if gShowPIDs then s := Format('[%5d] %s', [cs.PlayerStat[i].UID, cs.PlayerStat[i].Name]) else s := cs.PlayerStat[i].Name;
603 if (gPlayers[cs.PlayerStat[i].Num] <> nil) and (gPlayers[cs.PlayerStat[i].Num].FReady) then s := s + ' *';
604 r_Common_DrawText(s, x, yy, rr, gg, bb, 255, stdfont, TBasePoint.BP_LEFTUP);
605 if endview = false then
606 begin
607 // Player ping/loss
608 s := Format(_lc[I_GAME_PING_MS], [cs.PlayerStat[i].Ping, cs.PlayerStat[i].Loss]);
609 r_Common_DrawText(s, x + w1, yy, rr, gg, bb, 255, stdfont, TBasePoint.BP_UP);
610 end;
611 // Player frags
612 s := IntToStr(cs.PlayerStat[i].Frags);
613 r_Common_DrawText(s, x + w1 + w2, yy, rr, gg, bb, 255, stdfont, TBasePoint.BP_UP);
614 // Player deaths
615 s := IntToStr(cs.PlayerStat[i].Deaths);
616 r_Common_DrawText(s, x + w1 + w2 + w3, yy, rr, gg, bb, 255, stdfont, TBasePoint.BP_UP);
618 INC(yy, ch);
619 end;
620 end;
621 INC(yy, ch);
622 end;
623 end
624 else if cs.GameMode in [GM_DM, GM_COOP] then
625 begin
626 r_Common_DrawText(_lc[I_GAME_PLAYER_NAME], x, yy, 255, 127, 0, 255, stdfont, TBasePoint.BP_LEFTUP);
627 if endview = false then
628 r_Common_DrawText(_lc[I_GAME_PING], x + w1, yy, 255, 127, 0, 255, stdfont, TBasePoint.BP_UP);
629 r_Common_DrawText(_lc[I_GAME_FRAGS], x + w1 + w2, yy, 255, 127, 0, 255, stdfont, TBasePoint.BP_UP);
630 r_Common_DrawText(_lc[I_GAME_DEATHS], x + w1 + w2 + w3, yy, 255, 127, 0, 255, stdfont, TBasePoint.BP_UP);
631 INC(yy, ch + ch div 2);
632 for i := 0 to players - 1 do
633 begin
634 // rr := 255; gg := 127; bb := 0;
635 rr := 255; gg := 255; bb := 255;
636 if cs.PlayerStat[i].Spectator then
637 begin
638 rr := rr div 2; gg := gg div 2; bb := bb div 2;
639 end;
641 // Player color
642 r_Draw_Rect(x, yy, x + 16 - 1, yy + 16 - 1, 192, 192, 192, 255);
643 r_Draw_FillRect(x + 1, yy + 1, x + 16 - 1, yy + 16 - 1, cs.PlayerStat[i].Color.R, cs.PlayerStat[i].Color.G, cs.PlayerStat[i].Color.B, 255);
644 // Player name
645 if gShowPIDs then s := Format('[%5d] %s', [cs.PlayerStat[i].UID, cs.PlayerStat[i].Name]) else s := cs.PlayerStat[i].Name;
646 if (gPlayers[cs.PlayerStat[i].Num] <> nil) and (gPlayers[cs.PlayerStat[i].Num].FReady) then s := s + ' *';
647 r_Common_DrawText(s, x + 16 + 8, yy, rr, gg, bb, 255, stdfont, TBasePoint.BP_LEFTUP);
648 if endview = false then
649 begin
650 // Player ping/loss
651 s := Format(_lc[I_GAME_PING_MS], [cs.PlayerStat[i].Ping, cs.PlayerStat[i].Loss]);
652 r_Common_DrawText(s, x + w1, yy, rr, gg, bb, 255, stdfont, TBasePoint.BP_UP);
653 end;
654 // Player frags
655 s := IntToStr(cs.PlayerStat[i].Frags);
656 r_Common_DrawText(s, x + w1 + w2, yy, rr, gg, bb, 255, stdfont, TBasePoint.BP_UP);
657 // Player deaths
658 s := IntToStr(cs.PlayerStat[i].Deaths);
659 r_Common_DrawText(s, x + w1 + w2 + w3, yy, rr, gg, bb, 255, stdfont, TBasePoint.BP_UP);
661 INC(yy, ch + ch div 2);
662 end;
663 end;
664 end;
666 procedure r_Render_DrawStatsWindow (x, y, w, h: Integer; cs: TEndCustomGameStat; endview: Boolean);
667 var xoff, yoff, cw, ch: Integer; s: AnsiString;
668 begin
669 xoff := 0; yoff := 8;
670 r_Draw_GetTextSize('W', stdfont, cw, ch);
671 r_Draw_FillRect(x, y, x + w - 1, y + h - 1, 64, 64, 64, 224);
672 r_Draw_Rect(x, y, x + w - 1, y + h - 1, 255, 127, 0, 255);
674 (* LINE 1 *)
676 if endview = false then
677 begin
678 case NetMode of
679 NET_SERVER: s := _lc[I_NET_SERVER];
680 NET_CLIENT: s := NetClientIP + ':' + IntToStr(NetClientPort);
681 otherwise s := '';
682 end;
683 r_Common_DrawText(s, x + 16, y + yoff, 255, 255, 255, 255, stdfont, TBasePoint.BP_LEFTUP);
684 end;
686 case cs.GameMode of
687 GM_DM: if gGameSettings.MaxLives = 0 then s := _lc[I_GAME_DM] else s := _lc[I_GAME_LMS];
688 GM_TDM: if gGameSettings.MaxLives = 0 then s := _lc[I_GAME_TDM] else s := _lc[I_GAME_TLMS];
689 GM_CTF: s := _lc[I_GAME_CTF];
690 GM_COOP: if gGameSettings.MaxLives = 0 then s := _lc[I_GAME_COOP] else s := _lc[I_GAME_SURV];
691 otherwise s := 'GAME MODE ' + IntToStr(gGameSettings.GameMode);
692 end;
693 r_Common_DrawText(s, x + w div 2, y + yoff, 255, 255, 255, 255, stdfont, TBasePoint.BP_UP);
695 if endview = false then
696 begin
697 s := r_Common_TimeToStr(cs.GameTime);
698 r_Common_DrawText(s, x + w - 16, y + yoff, 255, 255, 255, 255, stdfont, TBasePoint.BP_RIGHTUP);
699 end;
701 INC(yoff, ch + ch div 2);
703 (* LINE 2/3 *)
705 s := cs.Map;
706 if cs.MapName <> '' then
707 s := s + ' - ' + cs.MapName;
709 if endview = false then
710 begin
711 r_Common_DrawText(s, x + w div 2, y + yoff, 200, 200, 200, 255, stdfont, TBasePoint.BP_UP);
712 INC(yoff, ch + ch div 2);
713 case cs.GameMode of
714 GM_DM, GM_TDM: s := Format(_lc[I_GAME_FRAG_LIMIT], [gGameSettings.ScoreLimit]);
715 GM_CTF: s := Format(_lc[I_GAME_SCORE_LIMIT], [gGameSettings.ScoreLimit]);
716 GM_COOP: s := _lc[I_GAME_MONSTERS] + ' ' + IntToStr(gCoopMonstersKilled) + '/' + IntToStr(gTotalMonsters);
717 otherwise s := '';
718 end;
719 r_Common_DrawText(s, x + 16, y + yoff, 200, 200, 200, 255, stdfont, TBasePoint.BP_LEFTUP);
720 case cs.GameMode of
721 GM_DM, GM_TDM, GM_CTF: s := Format(_lc[I_GAME_TIME_LIMIT], [gGameSettings.TimeLimit div 3600, (gGameSettings.TimeLimit div 60) mod 60, gGameSettings.TimeLimit mod 60]);
722 GM_COOP: s := _lc[I_GAME_SECRETS] + ' ' + IntToStr(gCoopSecretsFound) + '/' + IntToStr(gSecretsCount);
723 otherwise s := '';
724 end;
725 r_Common_DrawText(s, x + w - 16, y + yoff, 200, 200, 200, 255, stdfont, TBasePoint.BP_RIGHTUP);
726 INC(yoff, ch);
727 end
728 else
729 begin
730 xoff := MAX(Length(_lc[I_MENU_MAP]) + 1, Length(_lc[I_GAME_GAME_TIME]) + 1) * cw;
731 r_Common_DrawText(_lc[I_MENU_MAP], x + 16, y + yoff, 255, 127, 0, 255, stdfont, TBasePoint.BP_LEFTUP);
732 r_Common_DrawText(s, x + 16 + xoff, y + yoff, 255, 255, 255, 255, stdfont, TBasePoint.BP_LEFTUP);
733 INC(yoff, ch);
734 r_Common_DrawText(_lc[I_GAME_GAME_TIME], x + 16, y + yoff, 255, 127, 0, 255, stdfont, TBasePoint.BP_LEFTUP);
735 r_Common_DrawText(r_Common_TimeToStr(cs.GameTime), x + 16 + xoff, y + yoff, 255, 255, 255, 255, stdfont, TBasePoint.BP_LEFTUP);
736 INC(yoff, ch);
737 end;
739 INC(yoff, ch);
741 (* LINE 4/5 *)
743 if endview and (cs.GameMode = GM_COOP) then
744 begin
745 xoff := MAX(Length(_lc[I_GAME_MONSTERS]) + 1, Length(_lc[I_GAME_SECRETS]) + 1) * cw;
746 r_Common_DrawText(_lc[I_GAME_MONSTERS], x + 16, y + yoff, 255, 127, 0, 255, stdfont, TBasePoint.BP_LEFTUP);
747 r_Common_DrawText(IntToStr(gCoopMonstersKilled) + '/' + IntToStr(gTotalMonsters), x + 16 + xoff, y + yoff, 255, 255, 255, 255, stdfont, TBasePoint.BP_LEFTUP);
748 INC(yoff, ch);
749 r_Common_DrawText(_lc[I_GAME_SECRETS], x + 16, y + yoff, 255, 127, 0, 255, stdfont, TBasePoint.BP_LEFTUP);
750 r_Common_DrawText(IntToStr(gCoopSecretsFound) + '/' + IntToStr(gSecretsCount), x + 16 + xoff, y + yoff, 255, 255, 255, 255, stdfont, TBasePoint.BP_LEFTUP);
751 INC(yoff, ch);
752 INC(yoff, ch);
753 end;
755 (* LINE 6/7 *)
757 if endview and (cs.GameMode = GM_COOP) and gLastMap then
758 begin
759 xoff := MAX(Length(_lc[I_GAME_MONSTERS_TOTAL]) + 1, Length(_lc[I_GAME_SECRETS_TOTAL]) + 1) * cw;
760 r_Common_DrawText(_lc[I_GAME_MONSTERS_TOTAL], x + 16, y + yoff, 255, 127, 0, 255, stdfont, TBasePoint.BP_LEFTUP);
761 r_Common_DrawText(IntToStr(gCoopTotalMonstersKilled) + '/' + IntToStr(gCoopTotalMonsters), x + 16 + xoff, y + yoff, 255, 255, 255, 255, stdfont, TBasePoint.BP_LEFTUP);
762 INC(yoff, ch);
763 r_Common_DrawText(_lc[I_GAME_SECRETS_TOTAL], x + 16, y + yoff, 255, 127, 0, 255, stdfont, TBasePoint.BP_LEFTUP);
764 r_Common_DrawText(IntToStr(gCoopTotalSecretsFound) + '/' + IntToStr(gCoopTotalSecrets), x + 16 + xoff, y + yoff, 255, 255, 255, 255, stdfont, TBasePoint.BP_LEFTUP);
765 INC(yoff, ch);
766 INC(yoff, ch);
767 end;
769 (* LINE *)
771 if endview and (cs.GameMode in [GM_TDM, GM_CTF]) then
772 begin
773 if cs.TeamStat[TEAM_RED].Score > cs.TeamStat[TEAM_BLUE].Score then s := _lc[I_GAME_WIN_RED]
774 else if cs.TeamStat[TEAM_BLUE].Score > cs.TeamStat[TEAM_RED].Score then s := _lc[I_GAME_WIN_BLUE]
775 else s := _lc[I_GAME_WIN_DRAW];
776 r_Common_DrawText(s, x + w div 2, y + yoff, 255, 255, 255, 255, stdfont, TBasePoint.BP_UP);
777 INC(yoff, ch);
778 INC(yoff, ch);
779 end;
781 (* LINE n *)
783 r_Render_DrawStatsColumns(cs, x + 16, y + yoff, w - 16 - 16, endview);
784 end;
786 function r_Render_StatsHeight (players: Integer): Integer;
787 var cw, ch: Integer;
788 begin
789 ASSERT(players >= 0);
790 r_Draw_GetTextSize('W', stdfont, cw, ch);
791 case gGameSettings.GameMode of
792 GM_TDM, GM_CTF: result := 32 + ch * (11 + players);
793 otherwise result := 40 + ch * 5 + (ch + 8) * players;
794 end;
795 end;
797 procedure r_Render_DrawStats;
798 var x, y, w, h, players: Integer; cs: TEndCustomGameStat;
799 begin
800 cs.PlayerStat := g_Player_GetStats();
801 SortGameStat(cs.PlayerStat);
802 cs.TeamStat := gTeamStat;
803 cs.GameTime := gTime;
804 cs.GameMode := gGameSettings.GameMode;
805 cs.Map := g_ExtractWadNameNoPath(gMapInfo.Map) + ':' + g_ExtractFileName(gMapInfo.Map);
806 cs.MapName := gMapInfo.Name;
807 if cs.PlayerStat = nil then players := 0 else players := Length(cs.PlayerStat);
808 w := gScreenWidth - (gScreenWidth div 5);
809 h := r_Render_StatsHeight(players);
810 x := (gScreenWidth div 2) - (w div 2);
811 y := (gScreenHeight div 2) - (h div 2);
812 r_Render_DrawStatsWindow(x, y, w, h, cs, false);
813 end;
815 procedure r_Render_DrawCustomStats;
816 var cw, ch, s: AnsiString;
817 begin
818 if gStatsOff then
819 begin
820 r_Common_DrawText(_lc[I_MENU_INTER_NOTICE_TAB], gScreenWidth div 2, 8, 255, 255, 255, 255, stdfont, TBasePoint.BP_UP);
821 end
822 else
823 begin
824 case gGameSettings.GameMode of
825 GM_COOP: if gMissionFailed then s := _lc[I_MENU_INTER_MISSION_FAIL] else s := _lc[I_MENU_INTER_LEVEL_COMPLETE];
826 otherwise s := _lc[I_MENU_INTER_ROUND_OVER];
827 end;
828 r_Common_DrawText(s, gScreenWidth div 2, 16, 255, 255, 255, 255, menufont, TBasePoint.BP_UP);
830 if gChatShow = false then
831 begin
832 if g_Game_IsClient then s := _lc[I_MENU_INTER_NOTICE_MAP] else s := _lc[I_MENU_INTER_NOTICE_SPACE];
833 r_Common_DrawText(s, gScreenWidth div 2, gScreenHeight - 4, 255, 255, 255, 255, stdfont, TBasePoint.BP_DOWN);
834 if g_Game_IsNet then
835 begin
836 s := Format(_lc[I_MENU_INTER_NOTICE_TIME], [gServInterTime]);
837 r_Common_DrawText(s, gScreenWidth div 2, gScreenHeight - 16 - 4, 255, 255, 255, 255, stdfont, TBasePoint.BP_DOWN);
838 end;
839 end;
841 r_Render_DrawStatsWindow(32, 64, gScreenWidth - 32 * 2, gScreenHeight - 64 * 2, CustomStat, true);
842 end;
843 end;
845 procedure r_Render_DrawValueOf (a, b, x, y: Integer; f: TGLFont);
846 var wa, wb, ch: Integer; sa, sb: AnsiString;
847 begin
848 sa := IntToStr(a);
849 sb := IntToStr(b);
850 r_Draw_GetTextSize(sa, f, wa, ch);
851 r_Draw_GetTextSize(sa + ' / ', f, wb, ch);
852 r_Common_DrawText(sa, x, y, 255, 0, 0, 255, f, TBasePoint.BP_LEFTUP);
853 r_Common_DrawText(' / ', x + wa, y, 255, 255, 255, 255, f, TBasePoint.BP_LEFTUP);
854 r_Common_DrawText(sb, x + wb, y, 255, 0, 0, 255, f, TBasePoint.BP_LEFTUP);
855 end;
857 procedure r_Render_DrawSinglStatsPlayer (player, x, y, w1: Integer);
858 var time, kpm: Single;
859 begin
860 r_Common_DrawText(_lc[I_MENU_INTER_KILLS], x, y, 255, 255, 255, 255, menufont, TBasePoint.BP_LEFTUP);
861 r_Render_DrawValueOf(SingleStat.PlayerStat[player].Kills, gTotalMonsters, x + w1, y, MenuFont);
862 r_Common_DrawText(_lc[I_MENU_INTER_KPM], x, y + 32, 255, 255, 255, 255, menufont, TBasePoint.BP_LEFTUP);
863 time := SingleStat.GameTime / 1000;
864 kpm := SingleStat.PlayerStat[player].Kills;
865 if time > 0 then kpm := kpm / time * 60;
866 r_Common_DrawText(Format('%.1f', [kpm]), x + w1, y + 32, 255, 0, 0, 255, menufont, TBasePoint.BP_LEFTUP);
867 r_Common_DrawText(_lc[I_MENU_INTER_SECRETS], x, y + 64, 255, 255, 255, 255, menufont, TBasePoint.BP_LEFTUP);
868 r_Render_DrawValueOf(SingleStat.PlayerStat[player].Secrets, SingleStat.TotalSecrets, x + w1, y + 64, MenuFont);
869 end;
871 procedure r_Render_DrawSingleStats;
872 var xx, wa, wb, ww, ch: Integer; s: AnsiString;
873 begin
874 r_Common_DrawText(_lc[I_MENU_INTER_LEVEL_COMPLETE], gScreenWidth div 2, 32, 255, 255, 255, 255, menufont, TBasePoint.BP_UP);
876 r_Draw_GetTextSize(_lc[I_MENU_INTER_KPM] + ' ', menufont, wa, ch);
877 r_Draw_GetTextSize(' 9999.9', menufont, wb, ch);
878 ww := wa + wb;
879 xx := gScreenWidth div 2 - ww div 2;
881 s := r_Common_TimeToStr(SingleStat.GameTime);
882 r_Common_DrawText(_lc[I_MENU_INTER_TIME], xx, 80, 255, 255, 255, 255, menufont, TBasePoint.BP_LEFTUP);
883 r_Common_DrawText(s, xx + wa, 80, 255, 0, 0, 255, menufont, TBasePoint.BP_LEFTUP);
885 if SingleStat.TwoPlayers then
886 begin
887 r_Common_DrawText(_lc[I_MENU_PLAYER_1], gScreenWidth div 2, 128, 255, 255, 255, 255, menufont, TBasePoint.BP_UP);
888 r_Render_DrawSinglStatsPlayer(0, xx, 176, wa);
889 r_Common_DrawText(_lc[I_MENU_PLAYER_2], gScreenWidth div 2, 288, 255, 255, 255, 255, menufont, TBasePoint.BP_UP);
890 r_Render_DrawSinglStatsPlayer(1, xx, 336, wa);
891 end
892 else
893 begin
894 r_Render_DrawSinglStatsPlayer(0, xx, 128, wa);
895 end;
896 end;
898 procedure r_Render_DrawSpectHud;
899 var xoff: Integer; s: AnsiString;
901 procedure AddText (s1, s2: AnsiString);
902 var w1, w2, ww, ch: Integer;
903 begin
904 r_Draw_GetTextSize(s1, stdfont, w1, ch);
905 r_Draw_GetTextSize(s2, stdfont, w2, ch);
906 ww := MAX(w1, w2);
907 r_Common_DrawText(s1, xoff + ww div 2, gScreenHeight - ch, 255, 255, 255, 255, stdfont, TBasePoint.BP_DOWN);
908 r_Common_DrawText(s2, xoff + ww div 2, gScreenHeight - ch, 255, 255, 255, 255, stdfont, TBasePoint.BP_UP);
909 xoff := xoff + ww + 16;
910 end;
912 begin
913 xoff := 0;
914 case gSpectMode of
915 SPECT_STATS: s := 'MODE: Stats';
916 SPECT_MAPVIEW: s := 'MODE: Observe Map';
917 SPECT_PLAYERS: s := 'MODE: Watch Players';
918 otherwise s := 'MODE: ' + IntToStr(gSpectMode);
919 end;
920 AddText(s, '< jump >');
921 if gSpectMode = SPECT_STATS then
922 AddText('Autoview', '< fire >');
923 if gSpectMode = SPECT_MAPVIEW then
924 AddText('[-] Step ' + IntToStr(gSpectStep) + ' [+]', '<prev weap> <next weap>');
925 if gSpectMode = SPECT_PLAYERS then
926 begin
927 AddText('Player 1', '<left/right>');
928 if gSpectViewTwo then
929 AddText('Player 2', '<prev w/next w>');
930 AddText('2x View', '<up/down>');
931 end;
932 end;
934 function GetActivePlayer_ByID (id: Integer): TPlayer;
935 var i, len: Integer; p: TPlayer;
936 begin
937 p := nil;
938 if (id >= 0) and (gPlayers <> nil) then
939 begin
940 i := 0; len := Length(gPlayers);
941 while (i < len) and ((IsActivePlayer(gPlayers[i]) = false) or (gPlayers[i].UID <> id)) do INC(i);
942 if i < len then p := gPlayers[i];
943 end;
944 result := p;
945 end;
947 procedure r_Render_DrawMinimap (x, y: Integer; alpha: Byte);
948 const scale = 16;
950 function IsMinimapPanel (const p: TPanel): Boolean;
951 begin
952 result := (p <> nil) and p.Enabled;
953 if result then
954 begin
955 case p.PanelType of
956 PANEL_WALL, PANEL_WATER, PANEL_ACID1, PANEL_ACID2,
957 PANEL_STEP, PANEL_OPENDOOR, PANEL_CLOSEDOOR,
958 PANEL_LIFTUP, PANEL_LIFTDOWN, PANEL_LIFTLEFT, PANEL_LIFTRIGHT:
959 result := true;
960 otherwise
961 result := false;
962 end;
963 end;
964 end;
966 procedure DrawObject (xx, yy, ww, hh: Integer; r, g, b: Byte);
967 var x0, y0, x1, y1: Integer;
968 begin
969 x0 := x + xx div scale;
970 y0 := y + yy div scale;
971 x1 := x + (xx + ww - 1) div scale;
972 y1 := y + (yy + hh - 1) div scale;
973 r_Draw_FillRect(x0, y0, x1, y1, r, g, b, alpha);
974 end;
976 procedure DrawPanels (const a: TPanelArray);
977 var i: Integer; p: TPanel; c: TRGB;
978 begin
979 if a <> nil then
980 begin
981 for i := 0 to HIGH(a) do
982 begin
983 p := a[i];
984 if IsMinimapPanel(p) then
985 begin
986 case p.PanelType of
987 PANEL_WALL: c := _RGB(208, 208, 208);
988 PANEL_OPENDOOR: c := _RGB(160, 160, 160);
989 PANEL_CLOSEDOOR: c := _RGB(160, 160, 160);
990 PANEL_STEP: c := _RGB(128, 128, 128);
991 PANEL_LIFTUP, PANEL_LIFTDOWN, PANEL_LIFTLEFT, PANEL_LIFTRIGHT:
992 case p.LiftType of
993 LIFTTYPE_UP: c := _RGB(116, 72, 36);
994 LIFTTYPE_DOWN: c := _RGB(116, 124, 96);
995 LIFTTYPE_LEFT: c := _RGB(116, 200, 80);
996 LIFTTYPE_RIGHT: c := _RGB(116, 252, 140);
997 otherwise c := _RGB(255, 0, 0);
998 end;
999 PANEL_WATER: c := _RGB(0, 0, 192);
1000 PANEL_ACID1: c := _RGB(0, 176, 0);
1001 PANEL_ACID2: c := _RGB(176, 0, 0);
1002 otherwise c := _RGB(255, 0, 0);
1003 end;
1004 DrawObject(p.x, p.y, p.width, p.height, c.r, c.g, c.b);
1005 end;
1006 end;
1007 end;
1008 end;
1010 procedure DrawPlayers;
1011 var i: Integer; p: TPlayer; c: TRGB;
1012 begin
1013 if gPlayers <> nil then
1014 begin
1015 for i := 0 to HIGH(gPlayers) do
1016 begin
1017 p := gPlayers[i];
1018 if p.Alive then
1019 begin
1020 case p.Team of
1021 TEAM_RED: c := _RGB(255, 0, 0);
1022 TEAM_BLUE: c := _RGB(0, 0, 255);
1023 otherwise c := _RGB(255, 128, 0);
1024 end;
1025 DrawObject(p.obj.x, p.obj.y, p.obj.rect.width, p.obj.rect.height, c.r, c.g, c.b);
1026 end;
1027 end;
1028 end;
1029 end;
1031 function DrawMonster (m: TMonster): Boolean;
1032 begin
1033 result := false; // don't stop
1034 if m.alive then
1035 DrawObject(m.obj.x, m.obj.y, m.obj.rect.width, m.obj.rect.height, 255, 255, 0);
1036 end;
1038 begin
1039 r_Draw_FillRect(x, y, (x + gMapInfo.Width - 1) div scale, (y + gMapInfo.Height - 1) div scale, 0, 0, 0, alpha);
1040 DrawPanels(gSteps);
1041 DrawPanels(gLifts);
1042 DrawPanels(gWater);
1043 DrawPanels(gAcid1);
1044 DrawPanels(gAcid2);
1045 DrawPanels(gWalls);
1046 g_Mons_ForEach(DrawMonster);
1047 DrawPlayers;
1048 end;
1050 procedure r_Render_Draw;
1051 var p1, p2: TPlayer; time: LongWord;
1052 begin
1053 if gExit = EXIT_QUIT then
1054 exit;
1056 INC(FPSCounter);
1057 time := GetTickCount64();
1058 if time - FPSTime >= 1000 then
1059 begin
1060 FPS := FPSCounter;
1061 FPSCounter := 0;
1062 FPSTime := time;
1063 end;
1065 r_Draw_Setup(gWinSizeX, gWinSizeY, gScreenWidth, gScreenHeight);
1067 glClearColor(0.0, 0.0, 0.0, 0.0);
1068 glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
1070 p1 := nil;
1071 p2 := nil;
1072 if gGameOn or (gState = STATE_FOLD) then
1073 begin
1074 if (gPlayer1 <> nil) and (gPlayer2 <> nil) then
1075 begin
1076 if gRevertPlayers then
1077 begin
1078 p1 := gPlayer2;
1079 p2 := gPlayer1;
1080 end
1081 else
1082 begin
1083 p1 := gPlayer1;
1084 p2 := gPlayer2;
1085 end;
1086 end
1087 else if gPlayer1 <> nil then
1088 begin
1089 p1 := gPlayer1;
1090 end
1091 else if gPlayer2 <> nil then
1092 begin
1093 p1 := gPlayer2;
1094 end;
1095 if (gSpectMode = SPECT_PLAYERS) and (gPlayers <> nil) then
1096 begin
1097 p1 := GetActivePlayer_ByID(gSpectPID1);
1098 if p1 = nil then
1099 p1 := GetActivePlayer_ByID(GetActivePlayerID_Next());
1100 if gSpectViewTwo then
1101 begin
1102 p2 := GetActivePlayer_ByID(gSpectPID2);
1103 if p2 = nil then
1104 p2 := GetActivePlayer_ByID(GetActivePlayerID_Next());
1105 end;
1106 end;
1107 end;
1109 if gGameOn or ((gState in [STATE_FOLD]) and (EndingGameCounter < 255)) then
1110 begin
1111 if gSpectMode = SPECT_MAPVIEW then
1112 begin
1113 r_Render_DrawMapView(0, 0, gScreenWidth, gScreenHeight, gSpectX + gScreenWidth div 2, gSpectY + gScreenHeight div 2);
1114 end
1115 else if (p1 <> nil) and (p2 <> nil) then
1116 begin
1117 r_Render_DrawPlayerView(0, 0, gScreenWidth, gScreenHeight div 2 - 2, p1);
1118 r_Render_DrawPlayerView(0, gScreenHeight div 2 + 2, gScreenWidth, gScreenHeight div 2, p2);
1119 end
1120 else if p1 <> nil then
1121 begin
1122 r_Render_DrawPlayerView(0, 0, gScreenWidth, gScreenHeight, p1);
1123 end
1124 else if p2 <> nil then
1125 begin
1126 r_Render_DrawPlayerView(0, 0, gScreenWidth, gScreenHeight, p2);
1127 end;
1129 if gShowMap then
1130 r_Render_DrawMiniMap(0, 0, 160);
1132 {$IFDEF ENABLE_HOLMES}
1133 r_Holmes_Draw;
1134 {$ENDIF}
1136 if MessageText <> '' then
1137 r_Common_DrawFormatText(MessageText, (gScreenWidth - 196) div 2, gScreenHeight div 2, 255, menufont, TBasePoint.BP_CENTER);
1139 if IsDrawStat or (gSpectMode = SPECT_STATS) then
1140 r_Render_DrawStats;
1142 if gSpectHUD and (gChatShow = false) and (gSpectMode <> SPECT_NONE) and (gSpectAuto = false) then
1143 r_Render_DrawSpectHud;
1144 end;
1146 if gPauseMain and gGameOn {$IFDEF ENABLE_MENU}and (g_ActiveWindow = nil){$ENDIF} then
1147 begin
1148 r_Draw_FillRect(0, 0, gScreenWidth - 1, gScreenHeight - 1, 0, 0, 0, 105);
1149 r_Common_DrawText(_lc[I_MENU_PAUSE], gScreenWidth div 2, gScreenHeight div 2, 255, 255, 255, 255, menufont, TBasePoint.BP_CENTER);
1150 end;
1152 if not gGameOn then
1153 begin
1154 // TODO F key handle
1155 case gState of
1156 STATE_NONE: (* do nothing *) ;
1157 STATE_MENU: r_Common_DrawBackground(GameWad + ':TEXTURES/TITLE');
1158 STATE_FOLD:
1159 begin
1160 if EndingGameCounter > 0 then
1161 r_Draw_FillRect(0, 0, gScreenWidth - 1, gScreenHeight - 1, 0, 0, 0, MIN(MAX(255 - EndingGameCounter, 0), 255));
1162 end;
1163 STATE_INTERCUSTOM:
1164 begin
1165 if gLastMap and (gGameSettings.GameMode = GM_COOP) then
1166 if EndPicPath <> '' then
1167 r_Common_DrawBackground(EndPicPath)
1168 else
1169 r_Common_DrawBackground(GameWad + ':TEXTURES/' + _lc[I_TEXTURE_ENDPIC])
1170 else
1171 r_Common_DrawBackground(GameWad + ':TEXTURES/INTER');
1173 r_Render_DrawCustomStats;
1175 {$IFDEF ENABLE_MENU}
1176 if g_ActiveWindow <> nil then
1177 r_Draw_FillRect(0, 0, gScreenWidth - 1, gScreenHeight - 1, 0, 0, 0, 105);
1178 {$ENDIF}
1179 end;
1180 STATE_INTERSINGLE, STATE_INTERTEXT, STATE_INTERPIC:
1181 begin
1182 if EndingGameCounter > 0 then
1183 begin
1184 r_Draw_FillRect(0, 0, gScreenWidth - 1, gScreenHeight - 1, 0, 0, 0, MIN(MAX(255 - EndingGameCounter, 0), 255));
1185 end
1186 else
1187 begin
1188 r_Common_DrawBackground(GameWad + ':TEXTURES/INTER');
1189 r_Render_DrawSingleStats;
1190 {$IFDEF ENABLE_MENU}
1191 if g_ActiveWindow <> nil then
1192 r_Draw_FillRect(0, 0, gScreenWidth - 1, gScreenHeight - 1, 0, 0, 0, 105);
1193 {$ENDIF}
1194 end;
1195 end;
1196 STATE_ENDPIC:
1197 begin
1198 if EndPicPath <> '' then
1199 r_Common_DrawBackground(EndPicPath)
1200 else
1201 r_Common_DrawBackground(GameWad + ':TEXTURES/' + _lc[I_TEXTURE_ENDPIC]);
1202 {$IFDEF ENABLE_MENU}
1203 if g_ActiveWindow <> nil then
1204 r_Draw_FillRect(0, 0, gScreenWidth - 1, gScreenHeight - 1, 0, 0, 0, 105);
1205 {$ENDIF}
1206 end;
1207 STATE_SLIST:
1208 begin
1209 r_Common_DrawBackground(GameWad + ':TEXTURES/TITLE');
1210 r_Draw_FillRect(0, 0, gScreenWidth - 1, gScreenHeight - 1, 0, 0, 0, 105);
1211 r_Render_DrawServerList(slCurrent, slTable);
1212 end;
1213 end;
1214 end;
1216 {$IFDEF ENABLE_MENU}
1217 if g_ActiveWindow <> nil then
1218 begin
1219 if gGameOn then
1220 r_Draw_FillRect(0, 0, gScreenWidth - 1, gScreenHeight - 1, 0, 0, 0, 105);
1221 r_GUI_Draw_Window(g_ActiveWindow);
1222 end;
1223 {$ENDIF}
1225 r_Console_Draw(false);
1227 // TODO g_debug_Sounds
1229 if gShowFPS then
1230 begin
1231 r_Common_DrawText('FPS: ' + IntToStr(FPS), 0, 0, 255, 255, 255, 255, stdfont, TBasePoint.BP_LEFTUP);
1232 r_Common_DrawText('UPS: ' + IntToStr(UPS), 0, 16, 255, 255, 255, 255, stdfont, TBasePoint.BP_LEFTUP);
1233 end;
1235 if gGameOn and gShowTime then
1236 begin
1237 r_Common_DrawText(r_Common_TimeToStr(gTime), gScreenWidth - 4, gScreenHeight - 1, 255, 255, 255, 255, stdfont, TBasePoint.BP_RIGHTDOWN);
1238 end;
1240 // TODO draw profilers
1242 {$IFDEF ENABLE_HOLMES}
1243 r_Holmes_DrawUI;
1244 {$ENDIF}
1246 {$IFDEF ENABLE_TOUCH}
1247 r_Touch_Draw;
1248 {$ENDIF}
1250 sys_Repaint;
1251 end;
1253 procedure r_Render_Resize (w, h: Integer);
1254 begin
1255 gWinSizeX := w;
1256 gWinSizeY := h;
1257 gRC_Width := w;
1258 gRC_Height := h;
1259 gScreenWidth := Round(w / r_pixel_scale);
1260 gScreenHeight := Round(h / r_pixel_scale);
1261 end;
1263 procedure r_Render_Apply;
1264 begin
1265 {$IFDEF ENABLE_SYSTEM}
1266 if sys_SetDisplayModeGL(GetInfo()) then
1267 e_LogWriteln('resolution changed')
1268 else
1269 e_LogWriteln('resolution not changed');
1270 sys_EnableVSync(gVSync)
1271 {$ENDIF}
1272 end;
1274 function r_Render_WriteScreenShot (filename: String): Boolean;
1275 begin
1276 // TODO write screenshot file
1277 Result := False;
1278 end;
1280 {$IFDEF ENABLE_GIBS}
1281 function r_Render_GetGibRect (m, id: Integer): TRectWH;
1282 begin
1283 result := r_Map_GetGibSize(m, id);
1284 end;
1285 {$ENDIF}
1287 {$IFDEF ENABLE_GFX}
1288 procedure r_Render_QueueEffect (AnimType, X, Y: Integer);
1289 begin
1290 r_Map_NewGFX(AnimType, X, Y);
1291 end;
1292 {$ENDIF}
1294 {$IFDEF ENABLE_TOUCH}
1295 procedure r_Render_GetKeyRect (key: Integer; out x, y, w, h: Integer; out founded: Boolean);
1296 begin
1297 r_Touch_GetKeyRect(key, x, y, w, h, founded)
1298 end;
1299 {$ENDIF}
1301 {$IFDEF ENABLE_MENU}
1302 procedure r_Render_GetControlSize (ctrl: TGUIControl; out w, h: Integer);
1303 begin
1304 r_GUI_GetSize(ctrl, w, h);
1305 end;
1307 procedure r_Render_GetLogoSize (out w, h: Integer);
1308 begin
1309 r_GUI_GetLogoSize(w, h);
1310 end;
1312 procedure r_Render_GetMaxFontSize (BigFont: Boolean; out w, h: Integer);
1313 begin
1314 r_GUI_GetMaxFontSize(BigFont, w, h);
1315 end;
1317 procedure r_Render_GetStringSize (BigFont: Boolean; str: String; out w, h: Integer);
1318 begin
1319 r_GUI_GetStringSize(BigFont, str, w, h);
1320 end;
1321 {$ENDIF}
1323 procedure r_Render_SetProcessLoadingCallback (p: TProcedure);
1324 begin
1325 r_Common_ProcessLoadingCallback := p;
1326 end;
1328 procedure r_Render_ClearLoading;
1329 begin
1330 r_Common_ClearLoading;
1331 end;
1333 procedure r_Render_SetLoading (const text: String; maxval: Integer);
1334 begin
1335 r_Common_SetLoading(text, maxval);
1336 end;
1338 procedure r_Render_StepLoading (incval: Integer);
1339 begin
1340 r_Common_StepLoading(incval);
1341 end;
1343 procedure r_Render_DrawLoading (force: Boolean);
1344 begin
1345 r_Common_DrawLoading(force);
1346 end;
1348 {$IFDEF ENABLE_HOLMES}
1349 function pmsCurMapX (): Integer;
1350 begin
1351 result := r_holmes.pmsCurMapX();
1352 end;
1354 function pmsCurMapY (): Integer;
1355 begin
1356 result := r_holmes.pmsCurMapY();
1357 end;
1359 function r_Render_HolmesViewIsSet (): Boolean;
1360 begin
1361 result := vpSet;
1362 end;
1363 {$ENDIF}
1365 end.