DEADSOFTWARE

render: draw flag animation using TAnimationState
[d2df-sdl.git] / src / game / 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_panel, MAPDEF; // TPanel, TDFColor
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 // TODO procedure r_Map_FreeTextures
31 procedure r_Map_Update;
33 procedure r_Map_DrawBack (dx, dy: Integer);
34 procedure r_Map_DrawPanels (PanelType: Word; hasAmbient: Boolean; constref ambColor: TDFColor); // unaccelerated
35 procedure r_Map_CollectDrawPanels (x0, y0, wdt, hgt: Integer);
36 procedure r_Map_DrawPanelShadowVolumes (lightX: Integer; lightY: Integer; radius: Integer);
37 procedure r_Map_DrawFlags;
39 procedure r_Panel_Draw (constref p: TPanel; hasAmbient: Boolean; constref ambColor: TDFColor);
40 procedure r_Panel_DrawShadowVolume (constref p: TPanel; lightX, lightY: Integer; radius: Integer);
42 implementation
44 uses
45 {$INCLUDE ../nogl/noGLuses.inc}
46 SysUtils, Classes, Math, e_log, wadreader, CONFIG, utils,
47 r_graphics, r_animations, r_textures, g_textures,
48 g_base, g_basic, g_game, g_options,
49 g_map
50 ;
52 var
53 RenTextures: array of record
54 ID: DWORD;
55 Width, Height: WORD;
56 Anim: Boolean;
57 end;
58 FlagFrames: array [FLAG_RED..FLAG_BLUE] of DWORD;
59 FlagAnim: TAnimationState;
61 procedure r_Map_Initialize;
62 begin
63 FlagAnim := TAnimationState.Create(True, 8, 5);
64 end;
66 procedure r_Map_Finalize;
67 begin
68 FlagAnim.Free;
69 FlagAnim := nil;
70 end;
72 procedure r_Map_Load;
73 begin
74 g_Frames_CreateWAD(@FlagFrames[FLAG_RED], 'FRAMES_FLAG_RED', GameWAD + ':TEXTURES\FLAGRED', 64, 64, 5, False);
75 g_Frames_CreateWAD(@FlagFrames[FLAG_BLUE], 'FRAMES_FLAG_BLUE', GameWAD + ':TEXTURES\FLAGBLUE', 64, 64, 5, False);
76 end;
78 procedure r_Map_Free;
79 begin
80 g_Frames_DeleteByName('FRAMES_FLAG_RED');
81 g_Frames_DeleteByName('FRAMES_FLAG_BLUE');
82 end;
84 procedure r_Map_LoadTextures;
85 const
86 log = True;
87 var
88 i, n: Integer;
89 WadName, ResName: String;
90 WAD, WADZ: TWADFile;
91 ResData, ReszData: Pointer;
92 ResLen, ReszLen: Integer;
93 cfg: TConfig;
94 TextureResource: String;
95 Width, Height: Integer;
96 FramesCount: Integer;
97 BackAnim: Boolean;
98 begin
99 if Textures <> nil then
100 begin
101 n := Length(Textures);
102 SetLength(RenTextures, n);
103 for i := 0 to n - 1 do
104 begin
105 // e_LogWritefln('r_Map_LoadTextures: -> [%s] :: [%s]', [Textures[i].FullName, Textures[i].TextureName]);
106 RenTextures[i].ID := LongWord(TEXTURE_NONE);
107 RenTextures[i].Width := 0;
108 RenTextures[i].Height := 0;
109 RenTextures[i].Anim := False;
110 case Textures[i].TextureName of
111 TEXTURE_NAME_WATER: RenTextures[i].ID := LongWord(TEXTURE_SPECIAL_WATER);
112 TEXTURE_NAME_ACID1: RenTextures[i].ID := LongWord(TEXTURE_SPECIAL_ACID1);
113 TEXTURE_NAME_ACID2: RenTextures[i].ID := LongWord(TEXTURE_SPECIAL_ACID2);
114 else
115 WadName := g_ExtractWadName(Textures[i].FullName);
116 ResName := g_ExtractFilePathName(Textures[i].FullName);
117 WAD := TWADFile.Create();
118 if WAD.ReadFile(WadName) then
119 begin
120 if WAD.GetResource(ResName, ResData, ResLen, log) then
121 begin
122 if IsWadData(ResData, ResLen) then
123 begin
124 WADz := TWADFile.Create();
125 if WADz.ReadMemory(ResData, ResLen) then
126 begin
127 if WADz.GetResource('TEXT/ANIM', ReszData, ReszLen) then
128 begin
129 cfg := TConfig.CreateMem(ReszData, ReszLen);
130 FreeMem(ReszData);
131 if cfg <> nil then
132 begin
133 TextureResource := cfg.ReadStr('', 'resource', '');
134 Width := cfg.ReadInt('', 'framewidth', 0);
135 Height := cfg.ReadInt('', 'frameheight', 0);
136 FramesCount := cfg.ReadInt('', 'framecount', 0);
137 // Speed := cfg.ReadInt('', 'waitcount', 0);
138 BackAnim := cfg.ReadBool('', 'backanimation', False);
139 RenTextures[i].Width := Width;
140 RenTextures[i].Height := Height;
141 if TextureResource <> '' then
142 begin
143 if WADz.GetResource('TEXTURES/' + TextureResource, ReszData, ReszLen) then
144 begin
145 if g_Frames_CreateMemory(@RenTextures[i].ID, '', ReszData, ReszLen, Width, Height, FramesCount, BackAnim) then
146 RenTextures[i].Anim := True
147 else
148 e_LogWritefln('r_Map_LoadTextures: failed to create frames object (%s)', [Textures[i].FullName]);
149 FreeMem(ReszData)
150 end
151 else
152 e_LogWritefln('r_Map_LoadTextures: failed to open animation resources (%s)', [Textures[i].FullName])
153 end
154 else
155 e_LogWritefln('r_Map_LoadTextures: failed to animation has no texture resource string (%s)', [Textures[i].FullName]);
156 cfg.Free
157 end
158 else
159 e_LogWritefln('r_Map_LoadTextures: failed to parse animation description (%s)', [Textures[i].FullName])
160 end
161 else
162 e_LogWritefln('r_Map_LoadTextures: failed to open animation description (%s)', [Textures[i].FullName])
163 end
164 else
165 e_LogWritefln('r_Map_LoadTextures: failed to open animation (%s)', [Textures[i].FullName]);
166 WADz.Free
167 end
168 else
169 begin
170 if e_CreateTextureMem(ResData, ResLen, RenTextures[i].ID) then
171 e_GetTextureSize(RenTextures[i].ID, @RenTextures[i].Width, @RenTextures[i].Height)
172 else
173 e_LogWritefln('r_Map_LoadTextures: failed to create texture (%s)', [Textures[i].FullName])
174 end;
175 FreeMem(ResData);
176 end
177 else
178 e_LogWritefln('r_Map_LoadTextures: failed to open (%s)', [Textures[i].FullName])
179 end
180 else
181 e_LogWritefln('r_Map_LoadTextures: failed to open %s', [WadName]);
182 WAD.Free;
183 end
184 end
185 end
186 end;
188 procedure dplClear ();
189 begin
190 if (gDrawPanelList = nil) then gDrawPanelList := TBinHeapPanelDraw.Create() else gDrawPanelList.clear();
191 end;
193 // old algo
194 procedure r_Map_DrawPanels (PanelType: Word; hasAmbient: Boolean; constref ambColor: TDFColor);
196 procedure DrawPanels (constref panels: TPanelArray; drawDoors: Boolean=False);
197 var
198 idx: Integer;
199 begin
200 if (panels <> nil) then
201 begin
202 // alas, no visible set
203 for idx := 0 to High(panels) do
204 begin
205 if not (drawDoors xor panels[idx].Door) then
206 r_Panel_Draw(panels[idx], hasAmbient, ambColor);
207 end;
208 end;
209 end;
211 begin
212 case PanelType of
213 PANEL_WALL: DrawPanels(gWalls);
214 PANEL_CLOSEDOOR: DrawPanels(gWalls, True);
215 PANEL_BACK: DrawPanels(gRenderBackgrounds);
216 PANEL_FORE: DrawPanels(gRenderForegrounds);
217 PANEL_WATER: DrawPanels(gWater);
218 PANEL_ACID1: DrawPanels(gAcid1);
219 PANEL_ACID2: DrawPanels(gAcid2);
220 PANEL_STEP: DrawPanels(gSteps);
221 end;
222 end;
224 // new algo
225 procedure r_Map_CollectDrawPanels (x0, y0, wdt, hgt: Integer);
226 var
227 mwit: PPanel;
228 it: TPanelGrid.Iter;
229 begin
230 dplClear();
231 it := mapGrid.forEachInAABB(x0, y0, wdt, hgt, GridDrawableMask);
232 for mwit in it do if (((mwit^.tag and GridTagDoor) <> 0) = mwit^.Door) then gDrawPanelList.insert(mwit^);
233 it.release();
234 // list will be rendered in `g_game.DrawPlayer()`
235 end;
237 procedure r_Map_DrawPanelShadowVolumes (lightX: Integer; lightY: Integer; radius: Integer);
238 var
239 mwit: PPanel;
240 it: TPanelGrid.Iter;
241 begin
242 it := mapGrid.forEachInAABB(lightX-radius, lightY-radius, radius*2, radius*2, (GridTagWall or GridTagDoor));
243 for mwit in it do r_Panel_DrawShadowVolume(mwit^, lightX, lightY, radius);
244 it.release();
245 end;
247 procedure r_Map_DrawBack(dx, dy: Integer);
248 begin
249 if gDrawBackGround and (BackID <> DWORD(-1)) then
250 e_DrawSize(BackID, dx, dy, 0, False, False, gBackSize.X, gBackSize.Y)
251 else
252 e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
253 end;
255 procedure r_Map_DrawFlags;
256 var i, dx, tx, ty: Integer; Mirror: TMirrorType; f: PFlag;
257 begin
258 if gGameSettings.GameMode = GM_CTF then
259 begin
260 for i := FLAG_RED to FLAG_BLUE do
261 begin
262 f := @gFlags[i];
263 if not (f.State in [FLAG_STATE_NONE, FLAG_STATE_CAPTURED]) then
264 begin
265 f.Obj.lerp(gLerpFactor, tx, ty);
266 if f.Direction = TDirection.D_LEFT then
267 Mirror := TMirrorType.Horizontal
268 else
269 Mirror := TMirrorType.None;
270 dx := IfThen(f.Direction = TDirection.D_LEFT, -1, +1);
271 r_AnimationState_Draw(FlagFrames[i], FlagAnim, tx + dx, ty + 1, Mirror);
272 if g_debug_Frames then
273 e_DrawQuad(tx + f.Obj.Rect.X, ty + f.Obj.Rect.Y, tx + f.Obj.Rect.X + f.Obj.Rect.Width - 1, ty + f.Obj.Rect.Y + f.Obj.Rect.Height - 1, 0, 255, 0)
274 end
275 end
276 end
277 end;
279 procedure Panel_Lerp (p: TPanel; t: Single; out tX, tY, tW, tH: Integer);
280 begin
281 if p.movingActive then
282 begin
283 tX := nlerp(p.OldX, p.X, t);
284 tY := nlerp(p.OldY, p.Y, t);
285 tW := nlerp(p.OldWidth, p.Width, t);
286 tH := nlerp(p.OldHeight, p.Height, t);
287 end
288 else
289 begin
290 tX := p.X;
291 tY := p.Y;
292 tW := p.Width;
293 tH := p.Height;
294 end;
295 end;
297 procedure r_Panel_Draw (constref p: TPanel; hasAmbient: Boolean; constref ambColor: TDFColor);
298 var tx, ty, tw, th, xx, yy: Integer; NoTextureID, TextureID, FramesID: DWORD; NW, NH: Word; Texture: Cardinal; IsAnim: Boolean; w, h: Integer;
299 begin
300 if {p.Enabled and} (p.FCurTexture >= 0) and (p.Width > 0) and (p.Height > 0) and (p.Alpha < 255) {and g_Collide(X, Y, Width, Height, sX, sY, sWidth, sHeight)} then
301 begin
302 Panel_Lerp(p, gLerpFactor, tx, ty, tw, th);
303 Texture := p.TextureIDs[p.FCurTexture].Texture;
304 IsAnim := RenTextures[Texture].Anim;
305 if IsAnim then
306 begin
307 if p.TextureIDs[p.FCurTexture].AnTex <> nil then
308 begin
309 FramesID := RenTextures[Texture].ID;
310 w := RenTextures[Texture].Width;
311 h := RenTextures[Texture].Height;
312 for xx := 0 to tw div w - 1 do
313 for yy := 0 to th div h - 1 do
314 r_AnimationState_Draw(FramesID, p.TextureIDs[p.FCurTexture].AnTex, tx + xx * w, ty + yy * h, TMirrorType.None);
315 end
316 end
317 else
318 begin
319 TextureID := RenTextures[Texture].ID;
320 w := RenTextures[Texture].Width;
321 h := RenTextures[Texture].Height;
322 case TextureID of
323 LongWord(TEXTURE_SPECIAL_WATER): e_DrawFillQuad(tx, ty, tx + tw - 1, ty + th - 1, 0, 0, 255, 0, TBlending.Filter);
324 LongWord(TEXTURE_SPECIAL_ACID1): e_DrawFillQuad(tx, ty, tx + tw - 1, ty + th - 1, 0, 230, 0, 0, TBlending.Filter);
325 LongWord(TEXTURE_SPECIAL_ACID2): e_DrawFillQuad(tx, ty, tx + tw - 1, ty + th - 1, 230, 0, 0, 0, TBlending.Filter);
326 LongWord(TEXTURE_NONE):
327 if g_Texture_Get('NOTEXTURE', NoTextureID) then
328 begin
329 e_GetTextureSize(NoTextureID, @NW, @NH);
330 e_DrawFill(NoTextureID, tx, ty, tw div NW, th div NH, 0, False, False);
331 end
332 else
333 begin
334 xx := tx + (tw div 2);
335 yy := ty + (th div 2);
336 e_DrawFillQuad(tx, ty, xx, yy, 255, 0, 255, 0);
337 e_DrawFillQuad(xx, ty, tx + tw - 1, yy, 255, 255, 0, 0);
338 e_DrawFillQuad(tx, yy, xx, ty + th - 1, 255, 255, 0, 0);
339 e_DrawFillQuad(xx, yy, tx + tw - 1, ty + th - 1, 255, 0, 255, 0);
340 end;
341 else
342 if not p.movingActive then
343 e_DrawFill(TextureID, tx, ty, tw div w, th div h, p.Alpha, True, p.Blending, hasAmbient)
344 else
345 e_DrawFillX(TextureID, tx, ty, tw, th, p.Alpha, True, p.Blending, g_dbg_scale, hasAmbient);
346 if hasAmbient then
347 e_AmbientQuad(tx, ty, tw, th, ambColor.r, ambColor.g, ambColor.b, ambColor.a);
348 end
349 end
350 end
351 end;
353 procedure r_Panel_DrawShadowVolume (constref p: TPanel; lightX, lightY: Integer; radius: Integer);
354 var tx, ty, tw, th: Integer; Texture: Cardinal;
356 procedure extrude (x: Integer; y: Integer);
357 begin
358 glVertex2i(x + (x - lightX) * 500, y + (y - lightY) * 500);
359 //e_WriteLog(Format(' : (%d,%d)', [x + (x - lightX) * 300, y + (y - lightY) * 300]), MSG_WARNING);
360 end;
362 procedure drawLine (x0: Integer; y0: Integer; x1: Integer; y1: Integer);
363 begin
364 // does this side facing the light?
365 if ((x1 - x0) * (lightY - y0) - (lightX - x0) * (y1 - y0) >= 0) then exit;
366 //e_WriteLog(Format('lightpan: (%d,%d)-(%d,%d)', [x0, y0, x1, y1]), MSG_WARNING);
367 // this edge is facing the light, extrude and draw it
368 glVertex2i(x0, y0);
369 glVertex2i(x1, y1);
370 extrude(x1, y1);
371 extrude(x0, y0);
372 end;
374 begin
375 if radius < 4 then exit;
376 if p.Enabled and (p.FCurTexture >= 0) and (p.Width > 0) and (p.Height > 0) and (p.Alpha < 255) {and g_Collide(X, Y, tw, th, sX, sY, sWidth, sHeight)} then
377 begin
378 Panel_Lerp(p, gLerpFactor, tx, ty, tw, th);
379 Texture := p.TextureIDs[p.FCurTexture].Texture;
380 if not RenTextures[Texture].Anim then
381 begin
382 case RenTextures[Texture].ID of
383 LongWord(TEXTURE_SPECIAL_WATER): exit;
384 LongWord(TEXTURE_SPECIAL_ACID1): exit;
385 LongWord(TEXTURE_SPECIAL_ACID2): exit;
386 LongWord(TEXTURE_NONE): exit;
387 end;
388 end;
389 if (tx + tw < lightX - radius) then exit;
390 if (ty + th < lightY - radius) then exit;
391 if (tx > lightX + radius) then exit;
392 if (ty > lightY + radius) then exit;
393 //e_DrawFill(TextureIDs[FCurTexture].Tex, X, Y, tw div TextureWidth, th div TextureHeight, Alpha, True, Blending);
394 glBegin(GL_QUADS);
395 drawLine(tx, ty, tx + tw, ty); // top
396 drawLine(tx + tw, ty, tx + tw, ty + th); // right
397 drawLine(tx + tw, ty + th, tx, ty + th); // bottom
398 drawLine(tx, ty + th, tx, ty); // left
399 glEnd;
400 end
401 end;
403 procedure r_Map_Update;
404 begin
405 FlagAnim.Update
406 end;
408 end.