DEADSOFTWARE

gl: draw shells
[d2df-sdl.git] / src / game / renders / opengl / r_map.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_map;
18 interface
20 uses g_base; // TRectWH
22 procedure r_Map_Initialize;
23 procedure r_Map_Finalize;
25 procedure r_Map_Load;
26 procedure r_Map_Free;
28 procedure r_Map_LoadTextures;
29 procedure r_Map_FreeTextures;
31 {$IFDEF ENABLE_GFX}
32 procedure r_Map_NewGFX (typ, x, y: Integer);
33 {$ENDIF}
34 {$IFDEF ENABLE_GIBS}
35 function r_Map_GetGibSize (m, i: Integer): TRectWH;
36 {$ENDIF}
38 procedure r_Map_Update;
40 procedure r_Map_Draw (x, y, w, h, camx, camy: Integer);
42 implementation
44 uses
45 Math,
46 {$IFDEF USE_GLES1}
47 GLES11,
48 {$ELSE}
49 GL, GLEXT,
50 {$ENDIF}
51 e_log,
52 binheap, MAPDEF, utils,
53 g_options, g_textures, g_basic, g_phys,
54 g_game, g_map, g_panel, g_items, g_monsters, g_playermodel, g_player, g_weapons,
55 {$IFDEF ENABLE_CORPSES}
56 g_corpses,
57 {$ENDIF}
58 {$IFDEF ENABLE_SHELLS}
59 g_shells,
60 {$ENDIF}
61 {$IFDEF ENABLE_GIBS}
62 g_gibs,
63 {$ENDIF}
64 {$IFDEF ENABLE_GFX}
65 g_gfx,
66 {$ENDIF}
67 r_textures, r_draw
68 ;
70 const
71 MTABLE: array [0..MONSTER_MAN] of record
72 w, h: Integer;
73 end = (
74 (w: 64; h: 64), // NONE
75 (w: 64; h: 64), // DEMON
76 (w: 64; h: 64), // IMP
77 (w: 64; h: 64), // ZOMBY
78 (w: 64; h: 64), // SERG
79 (w: 128; h: 128), // CYBER
80 (w: 64; h: 64), // CGUN
81 (w: 128; h: 128), // BARON
82 (w: 128; h: 128), // KNIGHT
83 (w: 128; h: 128), // CACO
84 (w: 64; h: 64), // SOUL (DIE is 128x128, see load code)
85 (w: 128; h: 128), // PAIN
86 (w: 256; h: 128), // SPIDER
87 (w: 128; h: 64), // BSP
88 (w: 128; h: 128), // MANCUB
89 (w: 128; h: 128), // SKEL
90 (w: 128; h: 128), // VILE
91 (w: 32; h: 32), // FISH
92 (w: 64; h: 64), // BARREL
93 (w: 128; h: 128), // ROBO
94 (w: 64; h: 64) // MAN
95 );
96 VILEFIRE_DX = 32;
97 VILEFIRE_DY = 128;
99 {$IFDEF ENABLE_GFX}
100 GFXAnim: array [0..R_GFX_LAST] of record
101 name: AnsiString;
102 w, h: Integer;
103 count: Integer;
104 back: Boolean;
105 speed: Integer;
106 rspeed: Integer;
107 alpha: Integer;
108 end = (
109 (name: ''; w: 0; h: 0; count: 0; back: false; speed: 0; rspeed: 0; alpha: 0),
110 (name: 'TELEPORT'; w: 64; h: 64; count: 10; back: false; speed: 6; rspeed: 0; alpha: 0),
111 (name: 'FLAME'; w: 32; h: 32; count: 11; back: false; speed: 3; rspeed: 0; alpha: 0),
112 (name: 'EROCKET'; w: 128; h: 128; count: 6; back: false; speed: 6; rspeed: 0; alpha: 0),
113 (name: 'EBFG'; w: 128; h: 128; count: 6; back: false; speed: 6; rspeed: 0; alpha: 0),
114 (name: 'BFGHIT'; w: 64; h: 64; count: 4; back: false; speed: 4; rspeed: 0; alpha: 0),
115 (name: 'FIRE'; w: 64; h: 128; count: 8; back: false; speed: 4; rspeed: 2; alpha: 0),
116 (name: 'ITEMRESPAWN'; w: 32; h: 32; count: 5; back: true; speed: 4; rspeed: 0; alpha: 0),
117 (name: 'SMOKE'; w: 32; h: 32; count: 10; back: false; speed: 3; rspeed: 0; alpha: 0),
118 (name: 'ESKELFIRE'; w: 64; h: 64; count: 3; back: false; speed: 8; rspeed: 0; alpha: 0),
119 (name: 'EPLASMA'; w: 32; h: 32; count: 4; back: true; speed: 3; rspeed: 0; alpha: 0),
120 (name: 'EBSPFIRE'; w: 32; h: 32; count: 5; back: false; speed: 3; rspeed: 0; alpha: 0),
121 (name: 'EIMPFIRE'; w: 64; h: 64; count: 3; back: false; speed: 6; rspeed: 0; alpha: 0),
122 (name: 'ECACOFIRE'; w: 64; h: 64; count: 3; back: false; speed: 6; rspeed: 0; alpha: 0),
123 (name: 'EBARONFIRE'; w: 64; h: 64; count: 3; back: false; speed: 6; rspeed: 0; alpha: 0),
124 (name: 'TELEPORT'; w: 64; h: 64; count: 10; back: false; speed: 3; rspeed: 0; alpha: 0), // fast
125 (name: 'SMOKE'; w: 32; h: 32; count: 10; back: false; speed: 3; rspeed: 0; alpha: 150), // transparent
126 (name: 'FLAME'; w: 32; h: 32; count: 11; back: false; speed: 3; rspeed: 2; alpha: 0) // random
127 );
128 {$ENDIF}
130 ShotAnim: array [0..WEAPON_LAST] of record
131 name: AnsiString;
132 w, h: Integer;
133 count: Integer;
134 end = (
135 (name: ''; w: 0; h: 0; count: 0), // 0 KASTET
136 (name: ''; w: 0; h: 0; count: 0), // 1 SAW
137 (name: ''; w: 0; h: 0; count: 0), // 2 PISTOL
138 (name: ''; w: 0; h: 0; count: 0), // 3 SHOTGUN1
139 (name: ''; w: 0; h: 0; count: 0), // 4 SHOTGUN2
140 (name: ''; w: 0; h: 0; count: 0), // 5 CHAINGUN
141 (name: 'BROCKET'; w: 64; h: 32; count: 1), // 6 ROCKETLAUNCHER
142 (name: 'BPLASMA'; w: 16; h: 16; count: 2), // 7 PLASMA
143 (name: 'BBFG'; w: 64; h: 64; count: 2), // 8 BFG
144 (name: ''; w: 0; h: 0; count: 0), // 9 SUPERPULEMET
145 (name: 'FLAME'; w: 32; h: 32; count: 0{11}), // 10 FLAMETHROWER
146 (name: ''; w: 0; h: 0; count: 0), // 11
147 (name: ''; w: 0; h: 0; count: 0), // 12
148 (name: ''; w: 0; h: 0; count: 0), // 13
149 (name: ''; w: 0; h: 0; count: 0), // 14
150 (name: ''; w: 0; h: 0; count: 0), // 15
151 (name: ''; w: 0; h: 0; count: 0), // 16
152 (name: ''; w: 0; h: 0; count: 0), // 17
153 (name: ''; w: 0; h: 0; count: 0), // 18
154 (name: ''; w: 0; h: 0; count: 0), // 19
155 (name: ''; w: 0; h: 0; count: 0), // 20 ZOMPY_PISTOL
156 (name: 'BIMPFIRE'; w: 16; h: 16; count: 2), // 21 IMP_FIRE
157 (name: 'BBSPFIRE'; w: 16; h: 16; count: 2), // 22 BSP_FIRE
158 (name: 'BCACOFIRE'; w: 16; h: 16; count: 2), // 23 CACO_FIRE
159 (name: 'BBARONFIRE'; w: 64; h: 16; count: 2), // 24 BARON_FIRE
160 (name: 'BMANCUBFIRE'; w: 64; h: 32; count: 2), // 25 MANCUB_FIRE
161 (name: 'BSKELFIRE'; w: 64; h: 64; count: 2) // 26 SKEL_FIRE
162 );
164 {$IFDEF ENABLE_SHELLS}
165 ShellAnim: array [0..SHELL_LAST] of record
166 name: AnsiString;
167 dx, dy: Integer;
168 end = (
169 (name: 'EBULLET'; dx: 2; dy: 1), // 0 SHELL_BULLET
170 (name: 'ESHELL'; dx: 4; dy: 2), // 1 SHELL_SHELL
171 (name: 'ESHELL'; dx: 4; dy: 2) // 2 SHELL_DBLSHELL
172 );
173 {$ENDIF}
175 type
176 TBinHeapPanelDrawCmp = class
177 public
178 class function less (const a, b: TPanel): Boolean; inline;
179 end;
181 TBinHeapPanelDraw = specialize TBinaryHeapBase<TPanel, TBinHeapPanelDrawCmp>;
183 TMonsterAnims = array [0..ANIM_LAST, TDirection] of TGLMultiTexture;
185 var
186 SkyTexture: TGLTexture;
187 RenTextures: array of record
188 spec: LongInt;
189 tex: TGLMultiTexture;
190 end;
191 Items: array [0..ITEM_MAX] of record
192 tex: TGLMultiTexture;
193 anim: TAnimState;
194 end;
195 MonTextures: array [0..MONSTER_MAN] of TMonsterAnims;
196 WeapTextures: array [0..WP_LAST, 0..W_POS_LAST, 0..W_ACT_LAST] of TGLTexture;
197 ShotTextures: array [0..WEAPON_LAST] of TGLMultiTexture;
198 FlagTextures: array [0..FLAG_LAST] of TGLMultiTexture;
199 VileFire: TGLMultiTexture;
200 Models: array of record
201 anim: array [TDirection, 0..A_LAST] of record
202 base, mask: TGLMultiTexture;
203 end;
204 {$IFDEF ENABLE_GIBS}
205 gibs: record
206 base, mask: TGLTextureArray;
207 rect: TRectArray;
208 end;
209 {$ENDIF}
210 end;
212 StubShotAnim: TAnimState;
213 FlagAnim: TAnimState;
215 {$IFDEF ENABLE_SHELLS}
216 ShellTextures: array [0..SHELL_LAST] of TGLTexture;
217 {$ENDIF}
218 {$IFDEF ENABLE_GFX}
219 GFXTextures: array [0..R_GFX_LAST] of TGLMultiTexture;
220 gfxlist: array of record
221 typ: Byte;
222 alpha: Byte;
223 x, y: Integer;
224 oldX, oldY: Integer;
225 anim: TAnimState;
226 end = nil;
227 {$ENDIF}
229 plist: TBinHeapPanelDraw = nil;
231 class function TBinHeapPanelDrawCmp.less (const a, b: TPanel): Boolean; inline;
232 begin
233 if a.tag < b.tag then begin result := true; exit; end;
234 if a.tag > b.tag then begin result := false; exit; end;
235 result := a.arrIdx < b.arrIdx;
236 end;
238 procedure r_Map_Initialize;
239 begin
240 StubShotAnim := TAnimState.Create(true, 1, 1);
241 FlagAnim := TAnimState.Create(true, 8, 5);
242 plist := TBinHeapPanelDraw.Create();
243 end;
245 procedure r_Map_Finalize;
246 begin
247 plist.Free;
248 StubShotAnim.Invalidate;
249 end;
251 procedure r_Map_LoadModel (i: Integer);
252 var prefix: AnsiString; a: Integer; d: TDirection; m: ^TPlayerModelInfo;
253 begin
254 ASSERT(i < Length(Models));
255 ASSERT(i < Length(PlayerModelsArray));
256 m := @PlayerModelsArray[i];
257 prefix := m.FileName + ':TEXTURES/';
258 for d := TDirection.D_LEFT to TDirection.D_RIGHT do
259 begin
260 for a := A_STAND to A_LAST do
261 begin
262 Models[i].anim[d, a].base := nil;
263 Models[i].anim[d, a].mask := nil;
264 if m.anim[d, a].resource <> '' then
265 Models[i].anim[d, a].base := r_Textures_LoadMultiFromFileAndInfo(prefix + m.anim[d, a].resource, 64, 64, m.anim[d, a].frames, m.anim[d, a].back, true);
266 if m.anim[d, a].mask <> '' then
267 Models[i].anim[d, a].mask := r_Textures_LoadMultiFromFileAndInfo(prefix + m.anim[d, a].mask, 64, 64, m.anim[d, a].frames, m.anim[d, a].back, true);
268 end
269 end;
270 {$IFDEF ENABLE_GIBS}
271 Models[i].gibs.base := nil;
272 Models[i].gibs.mask := nil;
273 Models[i].gibs.rect := nil;
274 if m.GibsCount > 0 then
275 begin
276 SetLength(Models[i].gibs.base, m.GibsCount);
277 SetLength(Models[i].gibs.mask, m.GibsCount);
278 SetLength(Models[i].gibs.rect, m.GibsCount);
279 for a := 0 to m.GibsCount - 1 do
280 Models[i].gibs.rect[a] := DefaultGibSize;
281 if r_Textures_LoadStreamFromFile(prefix + m.GibsResource, 32, 32, m.GibsCount, Models[i].gibs.base, Models[i].gibs.rect) then
282 begin
283 if r_Textures_LoadStreamFromFile(prefix + m.GibsMask, 32, 32, m.GibsCount, Models[i].gibs.mask, nil) then
284 begin
285 // ok
286 end;
287 end;
288 for a := 0 to m.GibsCount - 1 do
289 e_logwritefln('model %s gib %s: %sx%s:%sx%s', [i, a, Models[i].gibs.rect[a].x, Models[i].gibs.rect[a].y, Models[i].gibs.rect[a].width, Models[i].gibs.rect[a].height]);
290 end;
291 {$ENDIF}
292 end;
294 procedure r_Map_Load;
295 const
296 WeapName: array [0..WP_LAST] of AnsiString = ('', 'CSAW', 'HGUN', 'SG', 'SSG', 'MGUN', 'RKT', 'PLZ', 'BFG', 'SPL', 'FLM');
297 WeapPos: array [0..W_POS_LAST] of AnsiString = ('', '_UP', '_DN');
298 WeapAct: array [0..W_ACT_LAST] of AnsiString = ('', '_FIRE');
299 var
300 i, j, k: Integer; d: TDirection;
302 procedure LoadItem (i: Integer; const name: AnsiString; w, h, delay, count: Integer; backanim: Boolean);
303 begin
304 ASSERT(i >= 0);
305 ASSERT(i <= ITEM_MAX);
306 Items[i].tex := r_Textures_LoadMultiFromFileAndInfo(GameWAD + ':TEXTURES/' + name, w, h, count, backanim, false);
307 if backanim then count := count * 2 - 2;
308 Items[i].anim := TAnimState.Create(True, delay, count);
309 ASSERT(Items[i].tex <> NIL);
310 end;
312 procedure LoadMonster (m, a: Integer; d: TDirection);
313 const
314 dir: array [TDirection] of AnsiString = ('_L', '');
315 var
316 w, h, count: Integer;
317 begin
318 count := MONSTER_ANIMTABLE[m].AnimCount[a];
319 if count > 0 then
320 begin
321 w := MTABLE[m].w;
322 h := MTABLE[m].h;
323 if (m = MONSTER_SOUL) and (a = ANIM_DIE) then
324 begin
325 // special case
326 w := 128;
327 h := 128;
328 end;
329 MonTextures[m, a, d] := r_Textures_LoadMultiFromFileAndInfo(
330 GameWAD + ':MTEXTURES/' + MONSTERTABLE[m].name + '_' + ANIMTABLE[a].name + dir[d],
331 w,
332 h,
333 count,
334 False,
335 False
337 end
338 else
339 MonTextures[m, a, d] := nil
340 end;
342 begin
343 // --------- items --------- //
344 // i name w h d n backanim
345 LoadItem(ITEM_NONE, 'NOTEXTURE', 16, 16, 0, 1, False);
346 LoadItem(ITEM_MEDKIT_SMALL, 'MED1', 16, 16, 0, 1, False);
347 LoadItem(ITEM_MEDKIT_LARGE, 'MED2', 32, 32, 0, 1, False);
348 LoadItem(ITEM_MEDKIT_BLACK, 'BMED', 32, 32, 0, 1, False);
349 LoadItem(ITEM_ARMOR_GREEN, 'ARMORGREEN', 32, 16, 20, 3, True);
350 LoadItem(ITEM_ARMOR_BLUE, 'ARMORBLUE', 32, 16, 20, 3, True);
351 LoadItem(ITEM_SPHERE_BLUE, 'SBLUE', 32, 32, 15, 4, True);
352 LoadItem(ITEM_SPHERE_WHITE, 'SWHITE', 32, 32, 20, 4, True);
353 LoadItem(ITEM_SUIT, 'SUIT', 32, 64, 0, 1, False);
354 LoadItem(ITEM_OXYGEN, 'OXYGEN', 16, 32, 0, 1, False);
355 LoadItem(ITEM_INVUL, 'INVUL', 32, 32, 20, 4, True);
356 LoadItem(ITEM_WEAPON_SAW, 'SAW', 64, 32, 0, 1, False);
357 LoadItem(ITEM_WEAPON_SHOTGUN1, 'SHOTGUN1', 64, 16, 0, 1, False);
358 LoadItem(ITEM_WEAPON_SHOTGUN2, 'SHOTGUN2', 64, 16, 0, 1, False);
359 LoadItem(ITEM_WEAPON_CHAINGUN, 'MGUN', 64, 16, 0, 1, False);
360 LoadItem(ITEM_WEAPON_ROCKETLAUNCHER, 'RLAUNCHER', 64, 16, 0, 1, False);
361 LoadItem(ITEM_WEAPON_PLASMA, 'PGUN', 64, 16, 0, 1, False);
362 LoadItem(ITEM_WEAPON_BFG, 'BFG', 64, 64, 0, 1, False);
363 LoadItem(ITEM_WEAPON_SUPERPULEMET, 'SPULEMET', 64, 16, 0, 1, False);
364 LoadItem(ITEM_AMMO_BULLETS, 'CLIP', 16, 16, 0, 1, False);
365 LoadItem(ITEM_AMMO_BULLETS_BOX, 'AMMO', 32, 16, 0, 1, False);
366 LoadItem(ITEM_AMMO_SHELLS, 'SHELL1', 16, 8, 0, 1, False);
367 LoadItem(ITEM_AMMO_SHELLS_BOX, 'SHELL2', 32, 16, 0, 1, False);
368 LoadItem(ITEM_AMMO_ROCKET, 'ROCKET', 16, 32, 0, 1, False);
369 LoadItem(ITEM_AMMO_ROCKET_BOX, 'ROCKETS', 64, 32, 0, 1, False);
370 LoadItem(ITEM_AMMO_CELL, 'CELL', 16, 16, 0, 1, False);
371 LoadItem(ITEM_AMMO_CELL_BIG, 'CELL2', 32, 32, 0, 1, False);
372 LoadItem(ITEM_AMMO_BACKPACK, 'BPACK', 32, 32, 0, 1, False);
373 LoadItem(ITEM_KEY_RED, 'KEYR', 16, 16, 0, 1, False);
374 LoadItem(ITEM_KEY_GREEN, 'KEYG', 16, 16, 0, 1, False);
375 LoadItem(ITEM_KEY_BLUE, 'KEYB', 16, 16, 0, 1, False);
376 LoadItem(ITEM_WEAPON_KASTET, 'KASTET', 64, 32, 0, 1, False);
377 LoadItem(ITEM_WEAPON_PISTOL, 'PISTOL', 64, 16, 0, 1, False);
378 LoadItem(ITEM_BOTTLE, 'BOTTLE', 16, 32, 20, 4, True);
379 LoadItem(ITEM_HELMET, 'HELMET', 16, 16, 20, 4, True);
380 LoadItem(ITEM_JETPACK, 'JETPACK', 32, 32, 15, 3, True);
381 LoadItem(ITEM_INVIS, 'INVIS', 32, 32, 20, 4, True);
382 LoadItem(ITEM_WEAPON_FLAMETHROWER, 'FLAMETHROWER', 64, 32, 0, 1, False);
383 LoadItem(ITEM_AMMO_FUELCAN, 'FUELCAN', 16, 32, 0, 1, False);
384 // fill with NOTEXURE forgotten item
385 for i := ITEM_AMMO_FUELCAN + 1 to ITEM_MAX do
386 LoadItem(i,'NOTEXTURE', 16, 16, 0, 1, False);
387 // --------- monsters --------- //
388 for i := MONSTER_DEMON to MONSTER_MAN do
389 for j := 0 to ANIM_LAST do
390 for d := TDirection.D_LEFT to TDirection.D_RIGHT do
391 LoadMonster(i, j, d);
392 VileFire := r_Textures_LoadMultiFromFileAndInfo(GameWAD + ':TEXTURES/FIRE', 64, 128, 8, False, False);
393 // --------- player models --------- //
394 if PlayerModelsArray <> nil then
395 begin
396 SetLength(Models, Length(PlayerModelsArray));
397 for i := 0 to High(PlayerModelsArray) do
398 r_Map_LoadModel(i);
399 end;
400 // --------- player weapons --------- //
401 for i := 1 to WP_LAST do
402 for j := 0 to W_POS_LAST do
403 for k := 0 to W_ACT_LAST do
404 WeapTextures[i, j, k] := r_Textures_LoadFromFile(GameWAD + ':WEAPONS\' + WeapName[i] + WeapPos[j] + WeapAct[k]);
405 // --------- gfx animations --------- //
406 {$IFDEF ENABLE_GFX}
407 for i := 1 to R_GFX_LAST do
408 if GFXAnim[i].count > 0 then
409 GFXTextures[i] := r_Textures_LoadMultiFromFileAndInfo(GameWad + ':TEXTURES/' + GFXAnim[i].name, GFXAnim[i].w, GFXAnim[i].h, GFXAnim[i].count, GFXAnim[i].back);
410 {$ENDIF}
411 // --------- shots --------- //
412 for i := 0 to WEAPON_LAST do
413 if ShotAnim[i].count > 0 then
414 ShotTextures[i] := r_Textures_LoadMultiFromFileAndInfo(GameWad + ':TEXTURES/' + ShotAnim[i].name, ShotAnim[i].w, ShotAnim[i].h, ShotAnim[i].count, false);
415 // --------- flags --------- //
416 FlagTextures[FLAG_NONE] := nil;
417 FlagTextures[FLAG_RED] := r_Textures_LoadMultiFromFileAndInfo(GameWad + ':TEXTURES/FLAGRED', 64, 64, 5, false);
418 FlagTextures[FLAG_BLUE] := r_Textures_LoadMultiFromFileAndInfo(GameWad + ':TEXTURES/FLAGBLUE', 64, 64, 5, false);
419 // FlagTextures[FLAG_DOM] := r_Textures_LoadMultiFromFileAndInfo(GameWad + ':TEXTURES/FLAGDOM', 64, 64, 8, false);
420 // --------- shells --------- //
421 {$IFDEF ENABLE_SHELLS}
422 for i := 0 to SHELL_LAST do
423 ShellTextures[i] := r_Textures_LoadFromFile(GameWad + ':TEXTURES/' + ShellAnim[i].name);
424 {$ENDIF}
425 end;
427 procedure r_Map_Free;
428 var i, j, k, a: Integer; d: TDirection;
429 begin
430 {$IFDEF ENABLE_SHELLS}
431 for i := 0 to SHELL_LAST do
432 begin
433 if ShellTextures[i] <> nil then
434 ShellTextures[i].Free;
435 ShellTextures[i] := nil;
436 end;
437 {$ENDIF}
438 for i := 0 to FLAG_LAST do
439 begin
440 if FlagTextures[i] <> nil then
441 FlagTextures[i].Free;
442 FlagTextures[i] := nil;
443 end;
444 for i := 0 to WEAPON_LAST do
445 begin
446 if ShotTextures[i] <> nil then
447 ShotTextures[i].Free;
448 ShotTextures[i] := nil;
449 end;
450 {$IFDEF ENABLE_GFX}
451 gfxlist := nil;
452 for i := 0 to R_GFX_LAST do
453 begin
454 if GFXTextures[i] <> nil then
455 GFXTextures[i].Free;
456 GFXTextures[i] := nil;
457 end;
458 {$ENDIF}
459 for i := 1 to WP_LAST do
460 begin
461 for j := 0 to W_POS_LAST do
462 begin
463 for k := 0 to W_ACT_LAST do
464 begin
465 if WeapTextures[i, j, k] <> nil then
466 WeapTextures[i, j, k].Free;
467 WeapTextures[i, j, k] := nil;
468 end;
469 end;
470 end;
471 for d := TDirection.D_LEFT to TDirection.D_RIGHT do
472 begin
473 for a := A_STAND to A_LAST do
474 begin
475 if Models[i].anim[d, a].base <> nil then
476 Models[i].anim[d, a].base.Free;
477 if Models[i].anim[d, a].mask <> nil then
478 Models[i].anim[d, a].mask.Free;
479 Models[i].anim[d, a].base := nil;
480 Models[i].anim[d, a].mask := nil;
481 end;
482 end;
483 for i := MONSTER_DEMON to MONSTER_MAN do
484 begin
485 for j := 0 to ANIM_LAST do
486 begin
487 for d := TDirection.D_LEFT to TDirection.D_RIGHT do
488 begin
489 if MonTextures[i, j, d] <> nil then
490 MonTextures[i, j, d].Free;
491 MonTextures[i, j, d] := nil;
492 end;
493 end;
494 end;
495 for i := 0 to ITEM_MAX do
496 begin
497 if Items[i].tex <> nil then
498 begin
499 Items[i].tex.Free;
500 Items[i].tex := nil;
501 end;
502 Items[i].anim.Invalidate;
503 end;
504 end;
506 procedure r_Map_LoadTextures;
507 var i, n: Integer;
508 begin
509 if Textures <> nil then
510 begin
511 n := Length(Textures);
512 SetLength(RenTextures, n);
513 for i := 0 to n - 1 do
514 begin
515 RenTextures[i].tex := nil;
516 case Textures[i].TextureName of
517 TEXTURE_NAME_WATER: RenTextures[i].spec := TEXTURE_SPECIAL_WATER;
518 TEXTURE_NAME_ACID1: RenTextures[i].spec := TEXTURE_SPECIAL_ACID1;
519 TEXTURE_NAME_ACID2: RenTextures[i].spec := TEXTURE_SPECIAL_ACID2;
520 else
521 RenTextures[i].spec := 0;
522 RenTextures[i].tex := r_Textures_LoadMultiFromFile(Textures[i].FullName);
523 if RenTextures[i].tex = nil then
524 e_LogWritefln('r_Map_LoadTextures: failed to load texture: %s', [Textures[i].FullName]);
525 end;
526 end;
527 end;
528 if gMapInfo.SkyFullName <> '' then
529 SkyTexture := r_Textures_LoadFromFile(gMapInfo.SkyFullName);
530 plist.Clear;
531 end;
533 procedure r_Map_FreeTextures;
534 var i: Integer;
535 begin
536 plist.Clear;
537 if SkyTexture <> nil then
538 SkyTexture.Free;
539 SkyTexture := nil;
540 if RenTextures <> nil then
541 for i := 0 to High(RenTextures) do
542 if RenTextures[i].tex <> nil then
543 RenTextures[i].tex.Free;
544 RenTextures := nil;
545 end;
547 procedure r_Map_DrawPanel (p: TPanel);
548 var Texture: Integer; t: TGLMultiTexture;
549 begin
550 ASSERT(p <> nil);
551 if p.FCurTexture >= 0 then
552 begin
553 Texture := p.TextureIDs[p.FCurTexture].Texture;
554 t := RenTextures[Texture].tex;
556 if (RenTextures[Texture].spec = 0) or (t <> nil) then
557 begin
558 if t = nil then
559 r_Draw_TextureRepeat(nil, p.x, p.y, p.width, p.height, false, 255, 255, 255, 255 - p.alpha, p.blending)
560 else if p.TextureIDs[p.FCurTexture].AnTex.IsValid() then
561 r_Draw_MultiTextureRepeat(t, p.TextureIDs[p.FCurTexture].AnTex, p.x, p.y, p.width, p.height, false, 255, 255, 255, 255 - p.alpha, p.blending)
562 else
563 r_Draw_TextureRepeat(t.GetTexture(0), p.x, p.y, p.width, p.height, false, 255, 255, 255, 255 - p.alpha, p.blending)
564 end;
566 if t = nil then
567 begin
568 case RenTextures[Texture].spec of
569 TEXTURE_SPECIAL_WATER: r_Draw_Filter(p.x, p.y, p.x + p.width, p.y + p.height, 0, 0, 255, 255);
570 TEXTURE_SPECIAL_ACID1: r_Draw_Filter(p.x, p.y, p.x + p.width, p.y + p.height, 0, 230, 0, 255);
571 TEXTURE_SPECIAL_ACID2: r_Draw_Filter(p.x, p.y, p.x + p.width, p.y + p.height, 230, 0, 0, 255);
572 end
573 end
574 end
575 end;
577 procedure r_Map_DrawPanelType (panelTyp: DWORD);
578 var tagMask, i: Integer; p: TPanel;
579 begin
580 i := 0;
581 tagMask := PanelTypeToTag(panelTyp);
582 while plist.count > 0 do
583 begin
584 p := TPanel(plist.Front());
585 if (p.tag and tagMask) = 0 then
586 break;
587 r_Map_DrawPanel(p);
588 Inc(i);
589 plist.PopFront
590 end;
591 end;
593 procedure r_Map_DrawItems (x, y, w, h: Integer; drop: Boolean);
594 var i, fX, fY: Integer; it: PItem; t: TGLMultiTexture;
595 begin
596 if ggItems <> nil then
597 begin
598 for i := 0 to High(ggItems) do
599 begin
600 it := @ggItems[i];
601 if it.used and it.alive and (it.dropped = drop) and (it.ItemType <> ITEM_NONE) then
602 begin
603 t := Items[it.ItemType].tex;
604 if g_Collide(it.obj.x, it.obj.y, t.width, t.height, x, y, w, h) then
605 begin
606 it.obj.Lerp(gLerpFactor, fX, fY);
607 r_Draw_MultiTextureRepeat(t, Items[it.ItemType].anim, fX, fY, t.width, t.height, false, 255, 255, 255, 255, false);
608 // if g_debug_frames then // TODO draw collision frame
609 end;
610 end;
611 end;
612 end;
613 end;
615 function r_Map_GetMonsterTexture (m, a: Integer; d: TDirection; out t: TGLMultiTexture; out dx, dy: Integer; out flip: Boolean): Boolean;
616 // var c: Integer;
617 begin
618 t := nil; dx := 0; dy := 0; flip := false;
619 result := MonTextures[m, a, d] <> nil;
620 if result = false then
621 begin
622 flip := true;
623 if d = TDirection.D_RIGHT then d := TDirection.D_LEFT else d := TDirection.D_RIGHT;
624 result := MonTextures[m, a, d] <> nil;
625 end;
626 if result = true then
627 begin
628 t := MonTextures[m, a, d];
629 if d = TDirection.D_LEFT then
630 begin
631 dx := MONSTER_ANIMTABLE[m].AnimDeltaLeft[a].X;
632 dy := MONSTER_ANIMTABLE[m].AnimDeltaLeft[a].Y;
633 end
634 else
635 begin
636 dx := MONSTER_ANIMTABLE[m].AnimDeltaRight[a].X;
637 dy := MONSTER_ANIMTABLE[m].AnimDeltaRight[a].Y;
638 end;
639 if flip then
640 begin
641 // c := (MONSTERTABLE[MonsterType].Rect.X - dx) + MONSTERTABLE[MonsterType].Rect.Width;
642 // dx := MTABLE[m].width - c - MONSTERTABLE[MonsterType].Rect.X;
643 dx := -dx;
644 end;
645 end;
646 end;
648 procedure r_Map_DrawMonsterAttack (constref mon: TMonster);
649 var o: TObj;
650 begin
651 if VileFire <> nil then
652 if (mon.MonsterType = MONSTER_VILE) and (mon.MonsterState = MONSTATE_SHOOT) then
653 if mon.VileFireAnim.IsValid() and GetPos(mon.MonsterTargetUID, @o) then
654 r_Draw_MultiTextureRepeat(VileFire, mon.VileFireAnim, o.x + o.rect.x + (o.rect.width div 2) - VILEFIRE_DX, o.y + o.rect.y + o.rect.height - VILEFIRE_DY, VileFire.width, VileFire.height, False, 255, 255, 255, 255, false);
655 end;
657 procedure r_Map_DrawMonster (constref mon: TMonster);
658 var m, a, fX, fY, dx, dy: Integer; d: TDirection; flip: Boolean; t: TGLMultiTexture;
659 begin
660 m := mon.MonsterType;
661 a := mon.MonsterAnim;
662 d := mon.GameDirection;
664 mon.obj.Lerp(gLerpFactor, fX, fY);
666 if r_Map_GetMonsterTexture(m, a, d, t, dx, dy, flip) then
667 r_Draw_MultiTextureRepeat(t, mon.DirAnim[a, d], fX + dx, fY + dy, t.width, t.height, flip, 255, 255, 255, 255, false);
670 if g_debug_frames
671 // TODO draw frame
673 end;
675 procedure r_Map_DrawMonsters (x, y, w, h: Integer);
676 var i: Integer; m: TMonster;
677 begin
678 if gMonsters <> nil then
679 begin
680 for i := 0 to High(gMonsters) do
681 begin
682 m := gMonsters[i];
683 if m <> nil then
684 begin
685 r_Map_DrawMonsterAttack(m);
686 // TODO select from grid
687 if g_Collide(m.obj.x + m.obj.rect.x, m.obj.y + m.obj.rect.y, m.obj.rect.width, m.obj.rect.height, x, y, w, h) then
688 r_Map_DrawMonster(m);
689 end;
690 end;
691 end;
692 end;
694 function r_Map_GetPlayerModelTex (i: Integer; var a: Integer; var d: TDirection; out flip: Boolean): Boolean;
695 begin
696 flip := false;
697 result := Models[i].anim[d, a].base <> nil;
698 if result = false then
699 begin
700 flip := true;
701 if d = TDirection.D_LEFT then d := TDirection.D_RIGHT else d := TDirection.D_LEFT;
702 result := Models[i].anim[d, a].base <> nil;
703 end;
704 end;
706 procedure r_Map_DrawPlayerModel (pm: TPlayerModel; x, y: Integer);
707 var a, pos, act, xx, yy, angle: Integer; d: TDirection; flip: Boolean; t: TGLMultiTexture; tex: TGLTexture; c: TRGB;
708 begin
709 a := pm.CurrentAnimation;
710 d := pm.Direction;
712 (* draw flag*)
713 t := FlagTextures[pm.Flag];
714 if (t <> nil) and not (a in [A_DIE1, A_DIE2]) then
715 begin
716 flip := d = TDirection.D_RIGHT;
717 angle := PlayerModelsArray[pm.id].FlagAngle;
718 xx := PlayerModelsArray[pm.id].FlagPoint.X;
719 yy := PlayerModelsArray[pm.id].FlagPoint.Y;
720 r_Draw_MultiTextureRepeatRotate(
721 t,
722 FlagAnim,
723 x + IfThen(flip, 2 * FLAG_BASEPOINT.X - xx + 1, xx - 1) - FLAG_BASEPOINT.X,
724 y + yy - FLAG_BASEPOINT.Y + 1,
725 t.width,
726 t.height,
727 flip,
728 255, 255, 255, 255, false,
729 IfThen(flip, 64 - FLAG_BASEPOINT.X, FLAG_BASEPOINT.X),
730 FLAG_BASEPOINT.Y,
731 IfThen(flip, angle, -angle)
732 );
733 end;
735 (* draw weapon *)
736 if PlayerModelsArray[pm.id].HaveWeapon and not (a in [A_DIE1, A_DIE2, A_PAIN]) then
737 begin
738 case a of
739 A_SEEUP, A_ATTACKUP: pos := W_POS_UP;
740 A_SEEDOWN, A_ATTACKDOWN: pos := W_POS_DOWN;
741 else pos := W_POS_NORMAL;
742 end;
743 if (a in [A_ATTACK, A_ATTACKUP, A_ATTACKDOWN]) or pm.GetFire() then
744 act := W_ACT_FIRE
745 else
746 act := W_ACT_NORMAL;
747 tex := WeapTextures[pm.CurrentWeapon, pos, act];
748 if tex <> nil then
749 begin
750 xx := PlayerModelsArray[pm.id].WeaponPoints[pm.CurrentWeapon, a, d, pm.AnimState.CurrentFrame].X;
751 yy := PlayerModelsArray[pm.id].WeaponPoints[pm.CurrentWeapon, a, d, pm.AnimState.CurrentFrame].Y;
752 r_Draw_Texture(
753 tex,
754 x + xx,
755 y + yy,
756 tex.width,
757 tex.height,
758 d = TDirection.D_LEFT,
759 255, 255, 255, 255, false
760 );
761 end;
762 end;
764 (* draw body *)
765 if r_Map_GetPlayerModelTex(pm.id, a, d, flip) then
766 begin
767 t := Models[pm.id].anim[d, a].base;
768 r_Draw_MultiTextureRepeat(t, pm.AnimState, x, y, t.width, t.height, flip, 255, 255, 255, 255, false);
769 t := Models[pm.id].anim[d, a].mask;
770 if t <> nil then
771 begin
772 c := pm.Color;
773 r_Draw_MultiTextureRepeat(t, pm.AnimState, x, y, t.width, t.height, flip, c.r, c.g, c.b, 255, false);
774 end;
775 end;
776 end;
778 procedure r_Map_DrawPlayer (p: TPlayer);
779 var fX, fY, fSlope: Integer;
780 begin
781 if p.alive then
782 begin
783 fX := p.obj.x; fY := p.obj.y;
784 // TODO fix lerp
785 //p.obj.Lerp(gLerpFactor, fX, fY);
786 fSlope := nlerp(p.SlopeOld, p.obj.slopeUpLeft, gLerpFactor);
787 // TODO draw punch
788 // TODO invul pentagram
789 // TODO draw it with transparency
790 r_Map_DrawPlayerModel(p.Model, fX, fY + fSlope);
791 end;
792 // TODO draw g_debug_frames
793 // TODO draw chat bubble
794 // TODO draw aim
795 end;
797 procedure r_Map_DrawPlayers (x, y, w, h: Integer);
798 var i: Integer;
799 begin
800 // TODO draw only visible
801 if gPlayers <> nil then
802 for i := 0 to High(gPlayers) do
803 if gPlayers[i] <> nil then
804 r_Map_DrawPlayer(gPlayers[i]);
805 end;
807 {$IFDEF ENABLE_GIBS}
808 function r_Map_GetGibSize (m, i: Integer): TRectWH;
809 begin
810 result := Models[m].gibs.rect[i];
811 end;
813 procedure r_Map_DrawGibs (x, y, w, h: Integer);
814 var i, fx, fy, m, id, rx, ry, ra: Integer; p: PObj; t: TGLTexture;
815 begin
816 if gGibs <> nil then
817 begin
818 for i := 0 to High(gGibs) do
819 begin
820 if gGibs[i].alive then
821 begin
822 p := @gGibs[i].Obj;
823 if g_Obj_Collide(x, y, w, h, p) then
824 begin
825 p.Lerp(gLerpFactor, fx, fy);
826 id := gGibs[i].GibID;
827 m := gGibs[i].ModelID;
828 t := Models[m].gibs.base[id];
829 if t <> nil then
830 begin
831 rx := p.Rect.X + p.Rect.Width div 2;
832 ry := p.Rect.Y + p.Rect.Height div 2;
833 ra := gGibs[i].RAngle;
834 r_Draw_TextureRepeatRotate(t, fx, fy, t.width, t.height, false, 255, 255, 255, 255, false, rx, ry, ra);
835 t := Models[m].gibs.mask[id];
836 if t <> nil then
837 r_Draw_TextureRepeatRotate(t, fx, fy, t.width, t.height, false, gGibs[i].Color.R, gGibs[i].Color.G, gGibs[i].Color.B, 255, false, rx, ry, ra);
838 // r_Draw_TextureRepeatRotate(nil, fx + p.Rect.X, fy + p.Rect.Y, p.Rect.Width, p.Rect.Height, false, 255, 255, 255, 255, false, p.Rect.Width div 2, p.Rect.Height div 2, ra);
839 end;
840 end;
841 end;
842 end;
843 end;
844 end;
845 {$ENDIF}
847 {$IFDEF ENABLE_CORPSES}
848 procedure r_Map_DrawCorpses (x, y, w, h: Integer);
849 var i, fX, fY: Integer; p: TCorpse;
850 begin
851 if gCorpses <> nil then
852 begin
853 for i := 0 to High(gCorpses) do
854 begin
855 p := gCorpses[i];
856 if (p <> nil) and (p.state <> CORPSE_STATE_REMOVEME) and (p.model <> nil) then
857 begin
858 p.obj.Lerp(gLerpFactor, fX, fY);
859 r_Map_DrawPlayerModel(p.model, fX, fY);
860 end;
861 end;
862 end;
863 end;
864 {$ENDIF}
866 {$IFDEF ENABLE_GFX}
867 function r_Map_GetGFXID (): Integer;
868 var i: Integer;
869 begin
870 i := 0;
871 if gfxlist <> nil then
872 begin
873 while (i < Length(gfxlist)) and gfxlist[i].anim.IsValid() do
874 Inc(i);
875 if i >= Length(gfxlist) then
876 SetLength(gfxlist, Length(gfxlist) + 1)
877 end
878 else
879 SetLength(gfxlist, 1);
880 gfxlist[i].typ := R_GFX_NONE;
881 gfxlist[i].anim.Invalidate;
882 result := i
883 end;
885 procedure r_Map_NewGFX (typ, x, y: Integer);
886 var i: Integer;
887 begin
888 if gpart_dbg_enabled and (typ > 0) and (typ <= R_GFX_LAST) then
889 begin
890 i := r_Map_GetGFXID();
891 if i >= 0 then
892 begin
893 gfxlist[i].typ := typ;
894 gfxlist[i].x := x;
895 gfxlist[i].y := y;
896 gfxlist[i].oldX := x;
897 gfxlist[i].oldY := y;
898 gfxlist[i].anim := TAnimState.Create(false, GFXAnim[typ].speed + Random(GFXAnim[typ].rspeed), GFXAnim[typ].count);
899 gfxlist[i].anim.Reset();
900 gfxlist[i].anim.Enable();
901 end;
902 end;
903 end;
905 procedure r_Map_UpdateGFX;
906 var i: Integer;
907 begin
908 if gfxlist <> nil then
909 begin
910 for i := 0 to High(gfxlist) do
911 begin
912 if gfxlist[i].anim.IsValid() then
913 begin
914 gfxlist[i].oldX := gfxlist[i].x;
915 gfxlist[i].oldY := gfxlist[i].y;
916 case gfxlist[i].typ of
917 R_GFX_FLAME, R_GFX_SMOKE:
918 begin
919 if Random(3) = 0 then
920 gfxlist[i].x := gfxlist[i].x - 1 + Random(3);
921 if Random(2) = 0 then
922 gfxlist[i].y := gfxlist[i].y - Random(2);
923 end;
924 end;
925 if gfxlist[i].anim.played then
926 gfxlist[i].anim.Invalidate
927 else
928 gfxlist[i].anim.Update
929 end;
930 end;
931 end;
932 end;
934 procedure r_Map_DrawParticles (x, y, w, h: Integer);
935 var i, fx, fy: Integer;
936 begin
937 if gpart_dbg_enabled and (Particles <> nil) then
938 begin
939 glDisable(GL_TEXTURE_2D);
940 if (g_dbg_scale < 0.6) then
941 glPointSize(1)
942 else if (g_dbg_scale > 1.3) then
943 glPointSize(g_dbg_scale + 1)
944 else
945 glPointSize(2);
946 glDisable(GL_POINT_SMOOTH);
947 glEnable(GL_BLEND);
948 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
950 glBegin(GL_POINTS);
951 for i := 0 to High(Particles) do
952 begin
953 if Particles[i].alive then
954 begin
955 fx := nlerp(Particles[i].oldX, Particles[i].x, gLerpFactor);
956 fy := nlerp(Particles[i].oldY, Particles[i].y, gLerpFactor);
957 glColor4ub(Particles[i].red, Particles[i].green, Particles[i].blue, Particles[i].alpha);
958 glVertex2f(fx, fy);
959 end;
960 end;
961 glEnd;
963 glDisable(GL_BLEND);
964 end;
965 end;
967 procedure r_Map_DrawGFX (x, y, w, h: Integer);
968 var i, fx, fy, typ: Integer; tex: TGLMultiTexture;
969 begin
970 if gfxlist <> nil then
971 begin
972 for i := 0 to High(gfxlist) do
973 begin
974 if gfxlist[i].anim.IsValid() then
975 begin
976 typ := gfxlist[i].typ;
977 tex := GFXTextures[typ];
978 if tex <> nil then
979 begin
980 fx := nlerp(gfxlist[i].oldX, gfxlist[i].x, gLerpFactor);
981 fy := nlerp(gfxlist[i].oldY, gfxlist[i].y, gLerpFactor);
982 r_Draw_MultiTextureRepeat(tex, gfxlist[i].anim, fx, fy, tex.width, tex.height, false, 255, 255, 255, 255 - GFXAnim[typ].alpha, false);
983 end;
984 end;
985 end;
986 end;
987 end;
988 {$ENDIF}
990 procedure r_Map_DrawShots (x, y, w, h: Integer);
991 var i, a, fX, fY, pX, pY, typ: Integer; tex: TGLMultiTexture; anim: ^TAnimState;
992 begin
993 if Shots <> nil then
994 begin
995 for i := 0 to High(Shots) do
996 begin
997 typ := Shots[i].ShotType;
998 if typ <> 0 then
999 begin
1000 tex := ShotTextures[typ];
1001 if tex <> nil then
1002 begin
1003 a := 0;
1004 case typ of
1005 WEAPON_ROCKETLAUNCHER, WEAPON_BARON_FIRE, WEAPON_MANCUB_FIRE, WEAPON_SKEL_FIRE:
1006 a := -GetAngle2(Shots[i].Obj.Vel.X, Shots[i].Obj.Vel.Y)
1007 end;
1008 Shots[i].Obj.Lerp(gLerpFactor, fX, fY);
1009 pX := Shots[i].Obj.Rect.Width div 2;
1010 pY := Shots[i].Obj.Rect.Height div 2;
1011 // TODO fix this hack
1012 if Shots[i].Animation.IsValid() then anim := @Shots[i].Animation else anim := @StubShotAnim;
1013 r_Draw_MultiTextureRepeatRotate(tex, anim^, fX, fY, tex.width, tex.height, false, 255, 255, 255, 255, false, pX, pY, a);
1014 end;
1015 end;
1016 end;
1017 end;
1018 end;
1020 procedure r_Map_DrawFlags (x, y, w, h: Integer);
1021 var i, dx, fx, fy: Integer; flip: Boolean; tex: TGLMultiTexture;
1022 begin
1023 if gGameSettings.GameMode = GM_CTF then
1024 begin
1025 for i := FLAG_RED to FLAG_BLUE do
1026 begin
1027 if not (gFlags[i].state in [FLAG_STATE_NONE, FLAG_STATE_CAPTURED]) then
1028 begin
1029 gFlags[i].Obj.Lerp(gLerpFactor, fx, fy);
1030 flip := gFlags[i].Direction = TDirection.D_LEFT;
1031 if flip then dx := -1 else dx := +1;
1032 tex := FlagTextures[i];
1033 r_Draw_MultiTextureRepeat(tex, FlagAnim, fx + dx, fy + 1, tex.width, tex.height, flip, 255, 255, 255, 255, false)
1034 // TODO g_debug_frames
1035 end;
1036 end;
1037 end;
1038 end;
1040 {$IFDEF ENABLE_SHELLS}
1041 procedure r_Map_DrawShells (x, y, w, h: Integer);
1042 var i, fx, fy, typ: Integer; t: TGLTexture; p: PObj;
1043 begin
1044 if gShells <> nil then
1045 begin
1046 for i := 0 to High(gShells) do
1047 begin
1048 if gShells[i].alive then
1049 begin
1050 typ := gShells[i].SType;
1051 if typ <= SHELL_LAST then
1052 begin
1053 p := @gShells[i].Obj;
1054 if g_Obj_Collide(x, y, w, h, p) then
1055 begin
1056 t := ShellTextures[typ];
1057 if t <> nil then
1058 begin
1059 p.Lerp(gLerpFactor, fx, fy);
1060 r_Draw_TextureRepeatRotate(t, fx, fy, t.width, t.height, false, 255, 255, 255, 255, false, ShellAnim[typ].dx, ShellAnim[typ].dy, gShells[i].RAngle);
1061 end;
1062 end;
1063 end;
1064 end;
1065 end;
1066 end;
1067 end;
1068 {$ENDIF}
1070 procedure r_Map_Draw (x, y, w, h, camx, camy: Integer);
1071 var iter: TPanelGrid.Iter; p: PPanel; cx, cy, xx, yy, ww, hh: Integer;
1072 begin
1073 cx := camx - w div 2;
1074 cy := camy - h div 2;
1075 xx := x + cx;
1076 yy := y + cy;
1077 ww := w;
1078 hh := h;
1080 if SkyTexture <> nil then
1081 r_Draw_Texture(SkyTexture, x, y, w, h, false, 255, 255, 255, 255, false);
1083 plist.Clear;
1084 iter := mapGrid.ForEachInAABB(xx, yy, ww, hh, GridDrawableMask);
1085 for p in iter do
1086 if ((p^.tag and GridTagDoor) <> 0) = p^.door then
1087 plist.Insert(p^);
1088 iter.Release;
1090 glPushMatrix;
1091 glTranslatef(-cx, -cy, 0);
1092 r_Map_DrawPanelType(PANEL_BACK);
1093 r_Map_DrawPanelType(PANEL_STEP);
1094 r_Map_DrawItems(xx, yy, ww, hh, false);
1095 r_Map_DrawShots(xx, yy, ww, hh);
1096 {$IFDEF ENABLE_SHELLS}
1097 r_Map_DrawShells(xx, yy, ww, hh);
1098 {$ENDIF}
1099 r_Map_DrawPlayers(xx, yy, ww, hh);
1100 {$IFDEF ENABLE_GIBS}
1101 r_Map_DrawGibs(xx, yy, ww, hh);
1102 {$ENDIF}
1103 {$IFDEF ENABLE_CORPSES}
1104 r_Map_DrawCorpses(xx, yy, ww, hh);
1105 {$ENDIF}
1106 r_Map_DrawPanelType(PANEL_WALL);
1107 r_Map_DrawMonsters(xx, yy, ww, hh);
1108 r_Map_DrawItems(xx, yy, ww, hh, true);
1109 r_Map_DrawPanelType(PANEL_CLOSEDOOR);
1110 {$IFDEF ENABLE_GFX}
1111 r_Map_DrawParticles(xx, yy, ww, hh);
1112 r_Map_DrawGFX(xx, yy, ww, hh);
1113 {$ENDIF}
1114 r_Map_DrawFlags(xx, yy, ww, hh);
1115 r_Map_DrawPanelType(PANEL_ACID1);
1116 r_Map_DrawPanelType(PANEL_ACID2);
1117 r_Map_DrawPanelType(PANEL_WATER);
1118 r_Map_DrawPanelType(PANEL_FORE);
1119 glPopMatrix;
1120 end;
1122 procedure r_Map_Update;
1123 var i: Integer;
1124 begin
1125 for i := 0 to ITEM_MAX do
1126 Items[i].anim.Update;
1127 r_Map_UpdateGFX;
1128 FlagAnim.Update;
1129 end;
1131 end.