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, TAnimationState, TDFPoint, TDynImageDataArray
22 procedure r_AnimState_Draw (FID
: DWORD
; const t
: TAnimState
; x
, y
: Integer; alpha
: Byte; mirror
: TMirrorType
; blending
: Boolean);
23 procedure r_AnimState_DrawEx (FID
: DWORD
; const t
: TAnimState
; x
, y
: Integer; alpha
: Byte; mirror
: TMirrorType
; blending
: Boolean; rpoint
: TDFPoint
; angle
: SmallInt);
25 function g_CreateFramesImg (ia
: TDynImageDataArray
; ID
: PDWORD
; const Name
: AnsiString; BackAnimation
: Boolean = false): Boolean;
27 function g_Frames_CreateWAD (ID
: PDWORD
; const Name
, Resource
: AnsiString; mWidth
, mHeight
, mCount
: Word; BackAnimation
: Boolean=false): Boolean;
28 function g_Frames_CreateFile (ID
: PDWORD
; const Name
, FileName
: AnsiString; mWidth
, mHeight
, mCount
: Word; BackAnimation
: Boolean = false): Boolean;
29 function g_Frames_CreateMemory (ID
: PDWORD
; const Name
: AnsiString; pData
: Pointer; dataSize
: LongInt; mWidth
, mHeight
, mCount
: Word; BackAnimation
: Boolean=false): Boolean;
30 function g_Frames_Dup (const NewName
, OldName
: AnsiString): Boolean;
31 function g_Frames_Get (out ID
: LongWord; const FramesName
: AnsiString): Boolean;
32 function g_Frames_GetTexture (out ID
: LongWord; const FramesName
: AnsiString; Frame
: Word): Boolean;
33 procedure g_Frames_GetFrameSize (ID
: DWORD
; out w
, h
: Integer);
34 function g_Frames_Exists (const FramesName
: AnsiString): Boolean;
35 procedure g_Frames_DeleteByName (const FramesName
: AnsiString);
36 procedure g_Frames_DeleteByID (ID
: LongWord);
37 procedure g_Frames_DeleteAll
;
41 texturesID
: array of LongWord;
43 frameWidth
, frameHeight
: Word;
48 framesArray
: array of TFrames
= nil;
53 SysUtils
, Classes
, Math
,
60 procedure g_Frames_GetFrameSize (ID
: DWORD
; out w
, h
: Integer);
64 if framesArray
<> nil then
66 w
:= framesArray
[ID
].frameWidth
;
67 h
:= framesArray
[ID
].frameHeight
;
71 procedure r_AnimState_Draw (FID
: DWORD
; const t
: TAnimState
; x
, y
: Integer; alpha
: Byte; mirror
: TMirrorType
; blending
: Boolean);
74 e_DrawAdv(framesArray
[FID
].TexturesID
[t
.currentFrame
], x
, y
, alpha
, true, blending
, 0, nil, mirror
)
77 procedure r_AnimState_DrawEx (FID
: DWORD
; const t
: TAnimState
; x
, y
: Integer; alpha
: Byte; mirror
: TMirrorType
; blending
: Boolean; rpoint
: TDFPoint
; angle
: SmallInt);
80 e_DrawAdv(framesArray
[FID
].TexturesID
[t
.currentFrame
], x
, y
, alpha
, true, blending
, angle
, @rpoint
, mirror
)
83 function allocFrameSlot (): LongWord;
87 for f
:= 0 to High(framesArray
) do
89 if (not framesArray
[f
].used
) then
96 result
:= Length(framesArray
);
97 SetLength(framesArray
, result
+64);
98 for f
:= result
to High(framesArray
) do
100 with framesArray
[f
] do
111 function g_Frames_CreateFile (ID
: PDWORD
; const Name
, FileName
: AnsiString;
112 mWidth
, mHeight
, mCount
: Word; BackAnimation
: Boolean = false): Boolean;
119 find_id
:= allocFrameSlot();
121 if (mCount
<= 2) then BackAnimation
:= false;
123 if BackAnimation
then SetLength(framesArray
[find_id
].TexturesID
, mCount
+mCount
-2)
124 else SetLength(framesArray
[find_id
].TexturesID
, mCount
);
126 for a
:= 0 to mCount
-1 do
128 if not e_CreateTextureEx(FileName
, framesArray
[find_id
].TexturesID
[a
], a
*mWidth
, 0, mWidth
, mHeight
) then exit
;
131 if BackAnimation
then
133 for a
:= 1 to mCount
-2 do framesArray
[find_id
].TexturesID
[mCount
+mCount
-2-a
] := framesArray
[find_id
].TexturesID
[a
];
136 framesArray
[find_id
].used
:= true;
137 framesArray
[find_id
].FrameWidth
:= mWidth
;
138 framesArray
[find_id
].FrameHeight
:= mHeight
;
139 if (Name
<> '') then framesArray
[find_id
].Name
:= Name
else framesArray
[find_id
].Name
:= '<noname>';
141 if (ID
<> nil) then ID
^ := find_id
;
146 function CreateFramesMem (pData
: Pointer; dataSize
: LongInt; ID
: PDWORD
; Name
: AnsiString;
147 mWidth
, mHeight
, mCount
: Word; BackAnimation
: Boolean = false): Boolean;
154 find_id
:= allocFrameSlot();
156 if (mCount
<= 2) then BackAnimation
:= false;
158 if BackAnimation
then SetLength(framesArray
[find_id
].TexturesID
, mCount
+mCount
-2)
159 else SetLength(framesArray
[find_id
].TexturesID
, mCount
);
161 for a
:= 0 to mCount
-1 do
162 if not e_CreateTextureMemEx(pData
, dataSize
, framesArray
[find_id
].TexturesID
[a
], a
*mWidth
, 0, mWidth
, mHeight
) then
168 if BackAnimation
then
170 for a
:= 1 to mCount
-2 do framesArray
[find_id
].TexturesID
[mCount
+mCount
-2-a
] := framesArray
[find_id
].TexturesID
[a
];
173 framesArray
[find_id
].used
:= true;
174 framesArray
[find_id
].FrameWidth
:= mWidth
;
175 framesArray
[find_id
].FrameHeight
:= mHeight
;
176 if (Name
<> '') then framesArray
[find_id
].Name
:= Name
else framesArray
[find_id
].Name
:= '<noname>';
178 if (ID
<> nil) then ID
^ := find_id
;
183 function g_CreateFramesImg (ia
: TDynImageDataArray
; ID
: PDWORD
; const Name
: AnsiString; BackAnimation
: Boolean = false): Boolean;
189 find_id
:= allocFrameSlot();
191 mCount
:= Length(ia
);
193 //e_WriteLog(Format('+++ creating %d frames [%s]', [FCount, Name]), MSG_NOTIFY);
195 if (mCount
< 1) then exit
;
196 if (mCount
<= 2) then BackAnimation
:= false;
198 if BackAnimation
then SetLength(framesArray
[find_id
].TexturesID
, mCount
+mCount
-2)
199 else SetLength(framesArray
[find_id
].TexturesID
, mCount
);
201 //e_WriteLog(Format('+++ creating %d frames, %dx%d', [FCount, ia[0].width, ia[0].height]), MSG_NOTIFY);
203 for a
:= 0 to mCount
-1 do
205 if not e_CreateTextureImg(ia
[a
], framesArray
[find_id
].TexturesID
[a
]) then exit
;
206 //e_WriteLog(Format('+++ frame %d, %dx%d', [a, ia[a].width, ia[a].height]), MSG_NOTIFY);
209 if BackAnimation
then
211 for a
:= 1 to mCount
-2 do framesArray
[find_id
].TexturesID
[mCount
+mCount
-2-a
] := framesArray
[find_id
].TexturesID
[a
];
214 framesArray
[find_id
].used
:= true;
215 framesArray
[find_id
].FrameWidth
:= ia
[0].width
;
216 framesArray
[find_id
].FrameHeight
:= ia
[0].height
;
217 if (Name
<> '') then framesArray
[find_id
].Name
:= Name
else framesArray
[find_id
].Name
:= '<noname>';
219 if (ID
<> nil) then ID
^ := find_id
;
224 function g_Frames_CreateWAD (ID
: PDWORD
; const Name
, Resource
: AnsiString;
225 mWidth
, mHeight
, mCount
: Word; BackAnimation
: Boolean=false): Boolean;
228 FileName
: AnsiString;
229 TextureData
: Pointer;
230 ResourceLength
: Integer;
234 // models without "advanced" animations asks for "nothing" like this; don't spam log
235 if (Length(Resource
) > 0) and ((Resource
[Length(Resource
)] = '/') or (Resource
[Length(Resource
)] = '\')) then exit
;
237 FileName
:= g_ExtractWadName(Resource
);
239 WAD
:= TWADFile
.Create();
240 WAD
.ReadFile(FileName
);
242 if not WAD
.GetResource(g_ExtractFilePathName(Resource
), TextureData
, ResourceLength
) then
245 e_WriteLog(Format('Error loading texture %s', [Resource
]), TMsgType
.Warning
);
246 //e_WriteLog(Format('WAD Reader error: %s', [WAD.GetLastErrorStr]), MSG_WARNING);
250 if not CreateFramesMem(TextureData
, ResourceLength
, ID
, Name
, mWidth
, mHeight
, mCount
, BackAnimation
) then
252 FreeMem(TextureData
);
257 FreeMem(TextureData
);
263 function g_Frames_CreateMemory (ID
: PDWORD
; const Name
: AnsiString; pData
: Pointer; dataSize
: LongInt;
264 mWidth
, mHeight
, mCount
: Word; BackAnimation
: Boolean = false): Boolean;
266 result
:= CreateFramesMem(pData
, dataSize
, ID
, Name
, mWidth
, mHeight
, mCount
, BackAnimation
);
269 function g_Frames_Dup (const NewName
, OldName
: AnsiString): Boolean;
271 find_id
, b
: LongWord;
276 if not g_Frames_Get(b
, OldName
) then exit
;
278 find_id
:= allocFrameSlot();
280 framesArray
[find_id
].used
:= true;
281 framesArray
[find_id
].Name
:= NewName
;
282 framesArray
[find_id
].FrameWidth
:= framesArray
[b
].FrameWidth
;
283 framesArray
[find_id
].FrameHeight
:= framesArray
[b
].FrameHeight
;
285 c
:= High(framesArray
[b
].TexturesID
);
286 SetLength(framesArray
[find_id
].TexturesID
, c
+1);
288 for a
:= 0 to c
do framesArray
[find_id
].TexturesID
[a
] := framesArray
[b
].TexturesID
[a
];
294 procedure g_Frames_DeleteByName (const FramesName
: AnsiString);
298 if (Length(framesArray
) = 0) then exit
;
299 for a
:= 0 to High(framesArray
) do
301 if (StrEquCI1251(framesArray
[a
].Name
, FramesName
)) then
303 if framesArray
[a
].TexturesID
<> nil then
305 for b
:= 0 to High(framesArray
[a
].TexturesID
) do e_DeleteTexture(framesArray
[a
].TexturesID
[b
]);
307 framesArray
[a
].used
:= false;
308 framesArray
[a
].TexturesID
:= nil;
309 framesArray
[a
].Name
:= '';
310 framesArray
[a
].FrameWidth
:= 0;
311 framesArray
[a
].FrameHeight
:= 0;
316 procedure g_Frames_DeleteByID (ID
: LongWord);
320 if (Length(framesArray
) = 0) then exit
;
321 if (framesArray
[ID
].TexturesID
<> nil) then
323 for b
:= 0 to High(framesArray
[ID
].TexturesID
) do e_DeleteTexture(framesArray
[ID
].TexturesID
[b
]);
325 framesArray
[ID
].used
:= false;
326 framesArray
[ID
].TexturesID
:= nil;
327 framesArray
[ID
].Name
:= '';
328 framesArray
[ID
].FrameWidth
:= 0;
329 framesArray
[ID
].FrameHeight
:= 0;
332 procedure g_Frames_DeleteAll ();
336 for a
:= 0 to High(framesArray
) do
338 if (framesArray
[a
].used
) then
340 for b
:= 0 to High(framesArray
[a
].TexturesID
) do e_DeleteTexture(framesArray
[a
].TexturesID
[b
]);
342 framesArray
[a
].used
:= false;
343 framesArray
[a
].TexturesID
:= nil;
344 framesArray
[a
].Name
:= '';
345 framesArray
[a
].FrameWidth
:= 0;
346 framesArray
[a
].FrameHeight
:= 0;
352 function g_Frames_Get (out ID
: LongWord; const FramesName
: AnsiString): Boolean;
357 if (Length(framesArray
) = 0) then exit
;
358 for a
:= 0 to High(framesArray
) do
360 if (StrEquCI1251(framesArray
[a
].Name
, FramesName
)) then
367 if not result
then g_FatalError(Format(_lc
[I_GAME_ERROR_FRAMES
], [FramesName
]));
370 function g_Frames_GetTexture (out ID
: LongWord; const FramesName
: AnsiString; Frame
: Word): Boolean;
375 if (Length(framesArray
) = 0) then exit
;
376 for a
:= 0 to High(framesArray
) do
378 if (StrEquCI1251(framesArray
[a
].Name
, FramesName
)) then
380 if (Frame
< Length(framesArray
[a
].TexturesID
)) then
382 ID
:= framesArray
[a
].TexturesID
[Frame
];
388 if not result
then g_FatalError(Format(_lc
[I_GAME_ERROR_FRAMES
], [FramesName
]));
391 function g_Frames_Exists (const FramesName
: AnsiString): Boolean;
396 if (Length(framesArray
) = 0) then exit
;
397 for a
:= 0 to High(framesArray
) do
399 if (StrEquCI1251(framesArray
[a
].Name
, FramesName
)) then