DEADSOFTWARE

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