DEADSOFTWARE

acac0c61d3b8a87cc78bc9598d65d834ef6817c2
[d2df-sdl.git] / src / game / g_textures.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 g_textures;
18 interface
20 uses
21 SysUtils, Classes,
22 {$IFDEF USE_MEMPOOL}mempool,{$ENDIF}
23 g_base, r_graphics, MAPDEF, ImagingTypes, Imaging, ImagingUtility;
25 type
26 TLevelTexture = record
27 textureName: AnsiString;
28 width, height: Word;
29 case anim: Boolean of
30 false: (textureID: LongWord);
31 true: (framesID: LongWord; framesCount: Byte; speed: Byte);
32 end;
34 TLevelTextureArray = array of TLevelTexture;
36 TAnimationState = class{$IFDEF USE_MEMPOOL}(TPoolObject){$ENDIF}
37 private
38 mAlpha: Byte;
39 mBlending: Boolean;
40 mCounter: Byte; // Ñ÷åò÷èê îæèäàíèÿ ìåæäó êàäðàìè
41 mSpeed: Byte; // Âðåìÿ îæèäàíèÿ ìåæäó êàäðàìè
42 mCurrentFrame: Integer; // Òåêóùèé êàäð (íà÷èíàÿ ñ 0)
43 mLoop: Boolean; // Ïåðåõîäèòü íà ïåðâûé êàäð ïîñëå ïîñëåäíåãî?
44 mEnabled: Boolean; // Ðàáîòà ðàçðåøåíà?
45 mPlayed: Boolean; // Ïðîèãðàíà âñÿ õîòÿ áû ðàç?
46 mMinLength: Byte; // Îæèäàíèå ïîñëå ïðîèãðûâàíèÿ
47 mRevert: Boolean; // Ñìåíà êàäðîâ îáðàòíàÿ?
49 mLength: Integer;
51 public
52 constructor Create (aloop: Boolean; aspeed: Byte; len: Integer);
53 destructor Destroy (); override;
55 procedure reset ();
56 procedure update ();
57 procedure enable ();
58 procedure disable ();
59 procedure revert (r: Boolean);
61 procedure saveState (st: TStream);
62 procedure loadState (st: TStream);
64 // function totalFrames (): Integer; inline;
66 public
67 property played: Boolean read mPlayed;
68 property enabled: Boolean read mEnabled;
69 property isReverse: Boolean read mRevert;
70 property loop: Boolean read mLoop write mLoop;
71 property speed: Byte read mSpeed write mSpeed;
72 property minLength: Byte read mMinLength write mMinLength;
73 property currentFrame: Integer read mCurrentFrame write mCurrentFrame;
74 property currentCounter: Byte read mCounter write mCounter;
75 property counter: Byte read mCounter;
76 property blending: Boolean read mBlending write mBlending;
77 property alpha: Byte read mAlpha write mAlpha;
78 end;
80 TAnimation = class{$IFDEF USE_MEMPOOL}(TPoolObject){$ENDIF}
81 private
82 mId: LongWord;
83 mAlpha: Byte;
84 mBlending: Boolean;
85 mCounter: Byte; // Ñ÷åò÷èê îæèäàíèÿ ìåæäó êàäðàìè
86 mSpeed: Byte; // Âðåìÿ îæèäàíèÿ ìåæäó êàäðàìè
87 mCurrentFrame: Integer; // Òåêóùèé êàäð (íà÷èíàÿ ñ 0)
88 mLoop: Boolean; // Ïåðåõîäèòü íà ïåðâûé êàäð ïîñëå ïîñëåäíåãî?
89 mEnabled: Boolean; // Ðàáîòà ðàçðåøåíà?
90 mPlayed: Boolean; // Ïðîèãðàíà âñÿ õîòÿ áû ðàç?
91 mHeight: Word;
92 mWidth: Word;
93 mMinLength: Byte; // Îæèäàíèå ïîñëå ïðîèãðûâàíèÿ
94 mRevert: Boolean; // Ñìåíà êàäðîâ îáðàòíàÿ?
96 public
97 constructor Create (aframesID: LongWord; aloop: Boolean; aspeed: Byte);
98 destructor Destroy (); override;
100 procedure reset ();
101 procedure update ();
102 procedure enable ();
103 procedure disable ();
104 procedure revert (r: Boolean);
106 procedure saveState (st: TStream);
107 procedure loadState (st: TStream);
109 function totalFrames (): Integer; inline;
111 public
112 property played: Boolean read mPlayed;
113 property enabled: Boolean read mEnabled;
114 property isReverse: Boolean read mRevert;
115 property loop: Boolean read mLoop write mLoop;
116 property speed: Byte read mSpeed write mSpeed;
117 property minLength: Byte read mMinLength write mMinLength;
118 property currentFrame: Integer read mCurrentFrame write mCurrentFrame;
119 property currentCounter: Byte read mCounter write mCounter;
120 property counter: Byte read mCounter;
121 property blending: Boolean read mBlending write mBlending;
122 property alpha: Byte read mAlpha write mAlpha;
123 property framesId: LongWord read mId;
124 property width: Word read mWidth;
125 property height: Word read mHeight;
127 property id: LongWord read mId;
128 end;
130 implementation
132 uses
133 g_game, e_log, g_basic, g_console, wadreader, r_animations,
134 g_language, utils, xstreams;
139 constructor TAnimationState.Create (aloop: Boolean; aspeed: Byte; len: Integer);
140 begin
141 assert(len >= 0);
142 mLength := len;
144 mMinLength := 0;
145 mLoop := aloop;
146 mSpeed := aspeed;
147 mEnabled := true;
148 mCurrentFrame := 0;
149 mAlpha := 0;
150 mPlayed := false;
151 end;
153 destructor TAnimationState.Destroy;
154 begin
155 inherited;
156 end;
158 procedure TAnimationState.update;
159 begin
160 if (not mEnabled) then exit;
162 mCounter += 1;
164 if (mCounter >= mSpeed) then
165 begin
166 // Îæèäàíèå ìåæäó êàäðàìè çàêîí÷èëîñü
167 // Îáðàòíûé ïîðÿäîê êàäðîâ?
168 if mRevert then
169 begin
170 // Äîøëè äî êîíöà àíèìàöèè. Âîçìîæíî, æäåì åùå
171 if (mCurrentFrame = 0) then
172 begin
173 if (mLength * mSpeed + mCounter < mMinLength) then exit;
174 end;
176 mCurrentFrame -= 1;
177 mPlayed := (mCurrentFrame < 0);
179 // Ïîâòîðÿòü ëè àíèìàöèþ ïî êðóãó?
180 if mPlayed then
181 begin
182 if mLoop then
183 mCurrentFrame := mLength - 1
184 else
185 mCurrentFrame += 1
186 end;
188 mCounter := 0;
189 end
190 else
191 begin
192 // Ïðÿìîé ïîðÿäîê êàäðîâ
193 // Äîøëè äî êîíöà àíèìàöèè. Âîçìîæíî, æäåì åùå
194 if (mCurrentFrame = mLength - 1) then
195 begin
196 if (mLength * mSpeed + mCounter < mMinLength) then exit;
197 end;
199 mCurrentFrame += 1;
200 mPlayed := (mCurrentFrame > mLength - 1);
202 // Ïîâòîðÿòü ëè àíèìàöèþ ïî êðóãó?
203 if mPlayed then
204 begin
205 if mLoop then mCurrentFrame := 0 else mCurrentFrame -= 1;
206 end;
208 mCounter := 0;
209 end;
210 end;
211 end;
213 procedure TAnimationState.reset;
214 begin
215 if mRevert then
216 mCurrentFrame := mLength - 1
217 else
218 mCurrentFrame := 0;
219 mCounter := 0;
220 mPlayed := false
221 end;
223 procedure TAnimationState.disable;
224 begin
225 mEnabled := false
226 end;
228 procedure TAnimationState.enable;
229 begin
230 mEnabled := true
231 end;
233 procedure TAnimationState.revert (r: Boolean);
234 begin
235 mRevert := r;
236 reset
237 end;
239 procedure TAnimationState.saveState (st: TStream);
240 begin
241 if (st = nil) then exit;
243 utils.writeSign(st, 'ANIM');
244 utils.writeInt(st, Byte(0)); // version
245 // Ñ÷åò÷èê îæèäàíèÿ ìåæäó êàäðàìè
246 utils.writeInt(st, Byte(mCounter));
247 // Òåêóùèé êàäð
248 utils.writeInt(st, LongInt(mCurrentFrame));
249 // Ïðîèãðàíà ëè àíèìàöèÿ öåëèêîì
250 utils.writeBool(st, mPlayed);
251 // Alpha-êàíàë âñåé òåêñòóðû
252 utils.writeInt(st, Byte(mAlpha));
253 // Ðàçìûòèå òåêñòóðû
254 utils.writeInt(st, Byte(mBlending));
255 // Âðåìÿ îæèäàíèÿ ìåæäó êàäðàìè
256 utils.writeInt(st, Byte(mSpeed));
257 // Çàöèêëåíà ëè àíèìàöèÿ
258 utils.writeBool(st, mLoop);
259 // Âêëþ÷åíà ëè
260 utils.writeBool(st, mEnabled);
261 // Îæèäàíèå ïîñëå ïðîèãðûâàíèÿ
262 utils.writeInt(st, Byte(mMinLength));
263 // Îáðàòíûé ëè ïîðÿäîê êàäðîâ
264 utils.writeBool(st, mRevert);
265 end;
268 procedure TAnimationState.loadState (st: TStream);
269 begin
270 if (st = nil) then exit;
272 if not utils.checkSign(st, 'ANIM') then raise XStreamError.Create('animation chunk expected');
273 if (utils.readByte(st) <> 0) then raise XStreamError.Create('invalid animation chunk version');
274 // Ñ÷åò÷èê îæèäàíèÿ ìåæäó êàäðàìè
275 mCounter := utils.readByte(st);
276 // Òåêóùèé êàäð
277 mCurrentFrame := utils.readLongInt(st);
278 // Ïðîèãðàíà ëè àíèìàöèÿ öåëèêîì
279 mPlayed := utils.readBool(st);
280 // Alpha-êàíàë âñåé òåêñòóðû
281 mAlpha := utils.readByte(st);
282 // Ðàçìûòèå òåêñòóðû
283 mBlending := utils.readBool(st);
284 // Âðåìÿ îæèäàíèÿ ìåæäó êàäðàìè
285 mSpeed := utils.readByte(st);
286 // Çàöèêëåíà ëè àíèìàöèÿ
287 mLoop := utils.readBool(st);
288 // Âêëþ÷åíà ëè
289 mEnabled := utils.readBool(st);
290 // Îæèäàíèå ïîñëå ïðîèãðûâàíèÿ
291 mMinLength := utils.readByte(st);
292 // Îáðàòíûé ëè ïîðÿäîê êàäðîâ
293 mRevert := utils.readBool(st);
294 end;
301 constructor TAnimation.Create (aframesID: LongWord; aloop: Boolean; aspeed: Byte);
302 begin
303 if (aframesID >= Length(framesArray)) then
304 begin
305 //raise Exception.Create('trying to create inexisting frame: something is very wrong here');
306 e_LogWritefln('trying to create inexisting frame %u of %u: something is very wrong here', [aframesID, LongWord(Length(framesArray))], TMsgType.Warning);
307 aframesID := 0;
308 if (Length(framesArray) = 0) then raise Exception.Create('trying to create inexisting frame: something is very wrong here');
309 end;
310 mId := aframesID;
311 mMinLength := 0;
312 mLoop := aloop;
313 mSpeed := aspeed;
314 mEnabled := true;
315 mCurrentFrame := 0;
316 mPlayed := false;
317 mAlpha := 0;
318 mWidth := framesArray[mId].FrameWidth;
319 mHeight := framesArray[mId].FrameHeight;
320 end;
323 destructor TAnimation.Destroy ();
324 begin
325 inherited;
326 end;
329 procedure TAnimation.update ();
330 begin
331 if (not mEnabled) then exit;
333 mCounter += 1;
335 if (mCounter >= mSpeed) then
336 begin
337 // Îæèäàíèå ìåæäó êàäðàìè çàêîí÷èëîñü
338 // Îáðàòíûé ïîðÿäîê êàäðîâ?
339 if mRevert then
340 begin
341 // Äîøëè äî êîíöà àíèìàöèè. Âîçìîæíî, æäåì åùå
342 if (mCurrentFrame = 0) then
343 begin
344 if (Length(framesArray[mId].TexturesID)*mSpeed+mCounter < mMinLength) then exit;
345 end;
347 mCurrentFrame -= 1;
348 mPlayed := (mCurrentFrame < 0);
350 // Ïîâòîðÿòü ëè àíèìàöèþ ïî êðóãó?
351 if mPlayed then
352 begin
353 if mLoop then mCurrentFrame := High(framesArray[mId].TexturesID) else mCurrentFrame += 1;
354 end;
356 mCounter := 0;
357 end
358 else
359 begin
360 // Ïðÿìîé ïîðÿäîê êàäðîâ
361 // Äîøëè äî êîíöà àíèìàöèè. Âîçìîæíî, æäåì åùå
362 if (mCurrentFrame = High(framesArray[mId].TexturesID)) then
363 begin
364 if (Length(framesArray[mId].TexturesID)*mSpeed+mCounter < mMinLength) then exit;
365 end;
367 mCurrentFrame += 1;
368 mPlayed := (mCurrentFrame > High(framesArray[mId].TexturesID));
370 // Ïîâòîðÿòü ëè àíèìàöèþ ïî êðóãó?
371 if mPlayed then
372 begin
373 if mLoop then mCurrentFrame := 0 else mCurrentFrame -= 1;
374 end;
376 mCounter := 0;
377 end;
378 end;
379 end;
382 procedure TAnimation.reset ();
383 begin
384 if mRevert then mCurrentFrame := High(framesArray[mId].TexturesID) else mCurrentFrame := 0;
385 mCounter := 0;
386 mPlayed := false;
387 end;
390 procedure TAnimation.disable (); begin mEnabled := false; end;
391 procedure TAnimation.enable (); begin mEnabled := true; end;
394 function TAnimation.totalFrames (): Integer; inline; begin result := Length(framesArray[mId].TexturesID); end;
397 procedure TAnimation.revert (r: Boolean);
398 begin
399 mRevert := r;
400 reset();
401 end;
404 procedure TAnimation.saveState (st: TStream);
405 begin
406 if (st = nil) then exit;
408 utils.writeSign(st, 'ANIM');
409 utils.writeInt(st, Byte(0)); // version
410 // Ñ÷åò÷èê îæèäàíèÿ ìåæäó êàäðàìè
411 utils.writeInt(st, Byte(mCounter));
412 // Òåêóùèé êàäð
413 utils.writeInt(st, LongInt(mCurrentFrame));
414 // Ïðîèãðàíà ëè àíèìàöèÿ öåëèêîì
415 utils.writeBool(st, mPlayed);
416 // Alpha-êàíàë âñåé òåêñòóðû
417 utils.writeInt(st, Byte(mAlpha));
418 // Ðàçìûòèå òåêñòóðû
419 utils.writeInt(st, Byte(mBlending));
420 // Âðåìÿ îæèäàíèÿ ìåæäó êàäðàìè
421 utils.writeInt(st, Byte(mSpeed));
422 // Çàöèêëåíà ëè àíèìàöèÿ
423 utils.writeBool(st, mLoop);
424 // Âêëþ÷åíà ëè
425 utils.writeBool(st, mEnabled);
426 // Îæèäàíèå ïîñëå ïðîèãðûâàíèÿ
427 utils.writeInt(st, Byte(mMinLength));
428 // Îáðàòíûé ëè ïîðÿäîê êàäðîâ
429 utils.writeBool(st, mRevert);
430 end;
433 procedure TAnimation.loadState (st: TStream);
434 begin
435 if (st = nil) then exit;
437 if not utils.checkSign(st, 'ANIM') then raise XStreamError.Create('animation chunk expected');
438 if (utils.readByte(st) <> 0) then raise XStreamError.Create('invalid animation chunk version');
439 // Ñ÷åò÷èê îæèäàíèÿ ìåæäó êàäðàìè
440 mCounter := utils.readByte(st);
441 // Òåêóùèé êàäð
442 mCurrentFrame := utils.readLongInt(st);
443 // Ïðîèãðàíà ëè àíèìàöèÿ öåëèêîì
444 mPlayed := utils.readBool(st);
445 // Alpha-êàíàë âñåé òåêñòóðû
446 mAlpha := utils.readByte(st);
447 // Ðàçìûòèå òåêñòóðû
448 mBlending := utils.readBool(st);
449 // Âðåìÿ îæèäàíèÿ ìåæäó êàäðàìè
450 mSpeed := utils.readByte(st);
451 // Çàöèêëåíà ëè àíèìàöèÿ
452 mLoop := utils.readBool(st);
453 // Âêëþ÷åíà ëè
454 mEnabled := utils.readBool(st);
455 // Îæèäàíèå ïîñëå ïðîèãðûâàíèÿ
456 mMinLength := utils.readByte(st);
457 // Îáðàòíûé ëè ïîðÿäîê êàäðîâ
458 mRevert := utils.readBool(st);
459 end;
461 end.