1 (* Copyright (C) Doom 2D: Forever Developers
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.
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.
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/>.
15 {$INCLUDE ../../shared/a_modes.inc}
20 uses g_base
, g_textures
, MAPDEF
, Imaging
; // TMirrorType, TAnimation, TDFPoint, TDynImageDataArray
22 procedure r_Animation_Draw (t
: TAnimation
; x
, y
: Integer; mirror
: TMirrorType
);
23 procedure r_Animation_DrawEx (t
: TAnimation
; x
, y
: Integer; mirror
: TMirrorType
; rpoint
: TDFPoint
; angle
: SmallInt);
25 procedure r_AnimationState_Draw (TID
: DWORD
; t
: TAnimationState
; x
, y
: Integer; mirror
: TMirrorType
);
26 procedure r_AnimationState_DrawEx (FID
: DWORD
; t
: TAnimationState
; x
, y
: Integer; mirror
: TMirrorType
; rpoint
: TDFPoint
; angle
: SmallInt);
28 function g_CreateFramesImg (ia
: TDynImageDataArray
; ID
: PDWORD
; const Name
: AnsiString; BackAnimation
: Boolean = false): Boolean;
30 function g_Frames_CreateWAD (ID
: PDWORD
; const Name
, Resource
: AnsiString; mWidth
, mHeight
, mCount
: Word; BackAnimation
: Boolean=false): Boolean;
31 function g_Frames_CreateFile (ID
: PDWORD
; const Name
, FileName
: AnsiString; mWidth
, mHeight
, mCount
: Word; BackAnimation
: Boolean = false): Boolean;
32 function g_Frames_CreateMemory (ID
: PDWORD
; const Name
: AnsiString; pData
: Pointer; dataSize
: LongInt; mWidth
, mHeight
, mCount
: Word; BackAnimation
: Boolean=false): Boolean;
33 function g_Frames_Dup (const NewName
, OldName
: AnsiString): Boolean;
34 function g_Frames_Get (out ID
: LongWord; const FramesName
: AnsiString): Boolean;
35 function g_Frames_GetTexture (out ID
: LongWord; const FramesName
: AnsiString; Frame
: Word): Boolean;
36 function g_Frames_Exists (const FramesName
: AnsiString): Boolean;
37 procedure g_Frames_DeleteByName (const FramesName
: AnsiString);
38 procedure g_Frames_DeleteByID (ID
: LongWord);
39 procedure g_Frames_DeleteAll
;
43 texturesID
: array of LongWord;
45 frameWidth
, frameHeight
: Word;
50 framesArray
: array of TFrames
= nil;
55 SysUtils
, Classes
, Math
,
62 procedure r_Animation_Draw (t
: TAnimation
; x
, y
: Integer; mirror
: TMirrorType
);
65 e_DrawAdv(framesArray
[t
.id
].TexturesID
[t
.currentFrame
], x
, y
, t
.alpha
, true, t
.blending
, 0, nil, mirror
)
68 procedure r_Animation_DrawEx (t
: TAnimation
; x
, y
: Integer; mirror
: TMirrorType
; rpoint
: TDFPoint
; angle
: SmallInt);
71 e_DrawAdv(framesArray
[t
.id
].TexturesID
[t
.currentFrame
], x
, y
, t
.alpha
, true, t
.blending
, angle
, @rpoint
, mirror
)
74 procedure r_AnimationState_Draw (TID
: DWORD
; t
: TAnimationState
; x
, y
: Integer; mirror
: TMirrorType
);
77 e_DrawAdv(framesArray
[TID
].TexturesID
[t
.currentFrame
], x
, y
, t
.alpha
, true, t
.blending
, 0, nil, mirror
)
80 procedure r_AnimationState_DrawEx (FID
: DWORD
; t
: TAnimationState
; x
, y
: Integer; mirror
: TMirrorType
; rpoint
: TDFPoint
; angle
: SmallInt);
83 e_DrawAdv(framesArray
[FID
].TexturesID
[t
.currentFrame
], x
, y
, t
.alpha
, true, t
.blending
, angle
, @rpoint
, mirror
)
86 function allocFrameSlot (): LongWord;
90 for f
:= 0 to High(framesArray
) do
92 if (not framesArray
[f
].used
) then
99 result
:= Length(framesArray
);
100 SetLength(framesArray
, result
+64);
101 for f
:= result
to High(framesArray
) do
103 with framesArray
[f
] do
114 function g_Frames_CreateFile (ID
: PDWORD
; const Name
, FileName
: AnsiString;
115 mWidth
, mHeight
, mCount
: Word; BackAnimation
: Boolean = false): Boolean;
122 find_id
:= allocFrameSlot();
124 if (mCount
<= 2) then BackAnimation
:= false;
126 if BackAnimation
then SetLength(framesArray
[find_id
].TexturesID
, mCount
+mCount
-2)
127 else SetLength(framesArray
[find_id
].TexturesID
, mCount
);
129 for a
:= 0 to mCount
-1 do
131 if not e_CreateTextureEx(FileName
, framesArray
[find_id
].TexturesID
[a
], a
*mWidth
, 0, mWidth
, mHeight
) then exit
;
134 if BackAnimation
then
136 for a
:= 1 to mCount
-2 do framesArray
[find_id
].TexturesID
[mCount
+mCount
-2-a
] := framesArray
[find_id
].TexturesID
[a
];
139 framesArray
[find_id
].used
:= true;
140 framesArray
[find_id
].FrameWidth
:= mWidth
;
141 framesArray
[find_id
].FrameHeight
:= mHeight
;
142 if (Name
<> '') then framesArray
[find_id
].Name
:= Name
else framesArray
[find_id
].Name
:= '<noname>';
144 if (ID
<> nil) then ID
^ := find_id
;
149 function CreateFramesMem (pData
: Pointer; dataSize
: LongInt; ID
: PDWORD
; Name
: AnsiString;
150 mWidth
, mHeight
, mCount
: Word; BackAnimation
: Boolean = false): Boolean;
157 find_id
:= allocFrameSlot();
159 if (mCount
<= 2) then BackAnimation
:= false;
161 if BackAnimation
then SetLength(framesArray
[find_id
].TexturesID
, mCount
+mCount
-2)
162 else SetLength(framesArray
[find_id
].TexturesID
, mCount
);
164 for a
:= 0 to mCount
-1 do
165 if not e_CreateTextureMemEx(pData
, dataSize
, framesArray
[find_id
].TexturesID
[a
], a
*mWidth
, 0, mWidth
, mHeight
) then
171 if BackAnimation
then
173 for a
:= 1 to mCount
-2 do framesArray
[find_id
].TexturesID
[mCount
+mCount
-2-a
] := framesArray
[find_id
].TexturesID
[a
];
176 framesArray
[find_id
].used
:= true;
177 framesArray
[find_id
].FrameWidth
:= mWidth
;
178 framesArray
[find_id
].FrameHeight
:= mHeight
;
179 if (Name
<> '') then framesArray
[find_id
].Name
:= Name
else framesArray
[find_id
].Name
:= '<noname>';
181 if (ID
<> nil) then ID
^ := find_id
;
186 function g_CreateFramesImg (ia
: TDynImageDataArray
; ID
: PDWORD
; const Name
: AnsiString; BackAnimation
: Boolean = false): Boolean;
192 find_id
:= allocFrameSlot();
194 mCount
:= Length(ia
);
196 //e_WriteLog(Format('+++ creating %d frames [%s]', [FCount, Name]), MSG_NOTIFY);
198 if (mCount
< 1) then exit
;
199 if (mCount
<= 2) then BackAnimation
:= false;
201 if BackAnimation
then SetLength(framesArray
[find_id
].TexturesID
, mCount
+mCount
-2)
202 else SetLength(framesArray
[find_id
].TexturesID
, mCount
);
204 //e_WriteLog(Format('+++ creating %d frames, %dx%d', [FCount, ia[0].width, ia[0].height]), MSG_NOTIFY);
206 for a
:= 0 to mCount
-1 do
208 if not e_CreateTextureImg(ia
[a
], framesArray
[find_id
].TexturesID
[a
]) then exit
;
209 //e_WriteLog(Format('+++ frame %d, %dx%d', [a, ia[a].width, ia[a].height]), MSG_NOTIFY);
212 if BackAnimation
then
214 for a
:= 1 to mCount
-2 do framesArray
[find_id
].TexturesID
[mCount
+mCount
-2-a
] := framesArray
[find_id
].TexturesID
[a
];
217 framesArray
[find_id
].used
:= true;
218 framesArray
[find_id
].FrameWidth
:= ia
[0].width
;
219 framesArray
[find_id
].FrameHeight
:= ia
[0].height
;
220 if (Name
<> '') then framesArray
[find_id
].Name
:= Name
else framesArray
[find_id
].Name
:= '<noname>';
222 if (ID
<> nil) then ID
^ := find_id
;
227 function g_Frames_CreateWAD (ID
: PDWORD
; const Name
, Resource
: AnsiString;
228 mWidth
, mHeight
, mCount
: Word; BackAnimation
: Boolean=false): Boolean;
231 FileName
: AnsiString;
232 TextureData
: Pointer;
233 ResourceLength
: Integer;
237 // models without "advanced" animations asks for "nothing" like this; don't spam log
238 if (Length(Resource
) > 0) and ((Resource
[Length(Resource
)] = '/') or (Resource
[Length(Resource
)] = '\')) then exit
;
240 FileName
:= g_ExtractWadName(Resource
);
242 WAD
:= TWADFile
.Create();
243 WAD
.ReadFile(FileName
);
245 if not WAD
.GetResource(g_ExtractFilePathName(Resource
), TextureData
, ResourceLength
) then
248 e_WriteLog(Format('Error loading texture %s', [Resource
]), TMsgType
.Warning
);
249 //e_WriteLog(Format('WAD Reader error: %s', [WAD.GetLastErrorStr]), MSG_WARNING);
253 if not CreateFramesMem(TextureData
, ResourceLength
, ID
, Name
, mWidth
, mHeight
, mCount
, BackAnimation
) then
255 FreeMem(TextureData
);
260 FreeMem(TextureData
);
266 function g_Frames_CreateMemory (ID
: PDWORD
; const Name
: AnsiString; pData
: Pointer; dataSize
: LongInt;
267 mWidth
, mHeight
, mCount
: Word; BackAnimation
: Boolean = false): Boolean;
269 result
:= CreateFramesMem(pData
, dataSize
, ID
, Name
, mWidth
, mHeight
, mCount
, BackAnimation
);
272 function g_Frames_Dup (const NewName
, OldName
: AnsiString): Boolean;
274 find_id
, b
: LongWord;
279 if not g_Frames_Get(b
, OldName
) then exit
;
281 find_id
:= allocFrameSlot();
283 framesArray
[find_id
].used
:= true;
284 framesArray
[find_id
].Name
:= NewName
;
285 framesArray
[find_id
].FrameWidth
:= framesArray
[b
].FrameWidth
;
286 framesArray
[find_id
].FrameHeight
:= framesArray
[b
].FrameHeight
;
288 c
:= High(framesArray
[b
].TexturesID
);
289 SetLength(framesArray
[find_id
].TexturesID
, c
+1);
291 for a
:= 0 to c
do framesArray
[find_id
].TexturesID
[a
] := framesArray
[b
].TexturesID
[a
];
297 procedure g_Frames_DeleteByName (const FramesName
: AnsiString);
301 if (Length(framesArray
) = 0) then exit
;
302 for a
:= 0 to High(framesArray
) do
304 if (StrEquCI1251(framesArray
[a
].Name
, FramesName
)) then
306 if framesArray
[a
].TexturesID
<> nil then
308 for b
:= 0 to High(framesArray
[a
].TexturesID
) do e_DeleteTexture(framesArray
[a
].TexturesID
[b
]);
310 framesArray
[a
].used
:= false;
311 framesArray
[a
].TexturesID
:= nil;
312 framesArray
[a
].Name
:= '';
313 framesArray
[a
].FrameWidth
:= 0;
314 framesArray
[a
].FrameHeight
:= 0;
319 procedure g_Frames_DeleteByID (ID
: LongWord);
323 if (Length(framesArray
) = 0) then exit
;
324 if (framesArray
[ID
].TexturesID
<> nil) then
326 for b
:= 0 to High(framesArray
[ID
].TexturesID
) do e_DeleteTexture(framesArray
[ID
].TexturesID
[b
]);
328 framesArray
[ID
].used
:= false;
329 framesArray
[ID
].TexturesID
:= nil;
330 framesArray
[ID
].Name
:= '';
331 framesArray
[ID
].FrameWidth
:= 0;
332 framesArray
[ID
].FrameHeight
:= 0;
335 procedure g_Frames_DeleteAll ();
339 for a
:= 0 to High(framesArray
) do
341 if (framesArray
[a
].used
) then
343 for b
:= 0 to High(framesArray
[a
].TexturesID
) do e_DeleteTexture(framesArray
[a
].TexturesID
[b
]);
345 framesArray
[a
].used
:= false;
346 framesArray
[a
].TexturesID
:= nil;
347 framesArray
[a
].Name
:= '';
348 framesArray
[a
].FrameWidth
:= 0;
349 framesArray
[a
].FrameHeight
:= 0;
355 function g_Frames_Get (out ID
: LongWord; const FramesName
: AnsiString): Boolean;
360 if (Length(framesArray
) = 0) then exit
;
361 for a
:= 0 to High(framesArray
) do
363 if (StrEquCI1251(framesArray
[a
].Name
, FramesName
)) then
370 if not result
then g_FatalError(Format(_lc
[I_GAME_ERROR_FRAMES
], [FramesName
]));
373 function g_Frames_GetTexture (out ID
: LongWord; const FramesName
: AnsiString; Frame
: Word): Boolean;
378 if (Length(framesArray
) = 0) then exit
;
379 for a
:= 0 to High(framesArray
) do
381 if (StrEquCI1251(framesArray
[a
].Name
, FramesName
)) then
383 if (Frame
< Length(framesArray
[a
].TexturesID
)) then
385 ID
:= framesArray
[a
].TexturesID
[Frame
];
391 if not result
then g_FatalError(Format(_lc
[I_GAME_ERROR_FRAMES
], [FramesName
]));
394 function g_Frames_Exists (const FramesName
: AnsiString): Boolean;
399 if (Length(framesArray
) = 0) then exit
;
400 for a
:= 0 to High(framesArray
) do
402 if (StrEquCI1251(framesArray
[a
].Name
, FramesName
)) then