DEADSOFTWARE

render: use TAnimationState for monsters
[d2df-sdl.git] / src / game / g_textures.pas
index d12a9a24e4ba74789cfbe74fbaa0713e4b0c376f..aaa91b793fe590d5e3bec09c6f432b148141b148 100644 (file)
@@ -33,6 +33,50 @@ type
 
   TLevelTextureArray = array of TLevelTexture;
 
+  TAnimationState = class{$IFDEF USE_MEMPOOL}(TPoolObject){$ENDIF}
+  private
+    mAlpha: Byte;
+    mBlending: Boolean;
+    mCounter: Byte; // Ñ÷åò÷èê îæèäàíèÿ ìåæäó êàäðàìè
+    mSpeed: Byte; // Âðåìÿ îæèäàíèÿ ìåæäó êàäðàìè
+    mCurrentFrame: Integer; // Òåêóùèé êàäð (íà÷èíàÿ ñ 0)
+    mLoop: Boolean; // Ïåðåõîäèòü íà ïåðâûé êàäð ïîñëå ïîñëåäíåãî?
+    mEnabled: Boolean; // Ðàáîòà ðàçðåøåíà?
+    mPlayed: Boolean; // Ïðîèãðàíà âñÿ õîòÿ áû ðàç?
+    mMinLength: Byte; // Îæèäàíèå ïîñëå ïðîèãðûâàíèÿ
+    mRevert: Boolean; // Ñìåíà êàäðîâ îáðàòíàÿ?
+
+    mLength: Integer;
+
+  public
+    constructor Create (aloop: Boolean; aspeed: Byte; len: Integer);
+    destructor  Destroy (); override;
+
+    procedure reset ();
+    procedure update ();
+    procedure enable ();
+    procedure disable ();
+    procedure revert (r: Boolean);
+
+    procedure saveState (st: TStream);
+    procedure loadState (st: TStream);
+
+    function totalFrames (): Integer; inline;
+
+  public
+    property played: Boolean read mPlayed;
+    property enabled: Boolean read mEnabled;
+    property isReverse: Boolean read mRevert;
+    property loop: Boolean read mLoop write mLoop;
+    property speed: Byte read mSpeed write mSpeed;
+    property minLength: Byte read mMinLength write mMinLength;
+    property currentFrame: Integer read mCurrentFrame write mCurrentFrame;
+    property currentCounter: Byte read mCounter write mCounter;
+    property counter: Byte read mCounter;
+    property blending: Boolean read mBlending write mBlending;
+    property alpha: Byte read mAlpha write mAlpha;
+  end;
+
   TAnimation = class{$IFDEF USE_MEMPOOL}(TPoolObject){$ENDIF}
   private
     mId: LongWord;
@@ -89,6 +133,176 @@ uses
   g_game, e_log, g_basic, g_console, wadreader, r_animations,
   g_language, utils, xstreams;
 
+
+
+
+constructor TAnimationState.Create (aloop: Boolean; aspeed: Byte; len: Integer);
+begin
+  assert(len >= 0);
+  mLength := len;
+
+  mMinLength := 0;
+  mLoop := aloop;
+  mSpeed := aspeed;
+  mEnabled := true;
+  mCurrentFrame := 0;
+  mAlpha := 0;
+  mPlayed := false;
+end;
+
+destructor TAnimationState.Destroy;
+begin
+  inherited;
+end;
+
+procedure TAnimationState.update;
+begin
+  if (not mEnabled) then exit;
+
+  mCounter += 1;
+
+  if (mCounter >= mSpeed) then
+  begin
+    // Îæèäàíèå ìåæäó êàäðàìè çàêîí÷èëîñü
+    // Îáðàòíûé ïîðÿäîê êàäðîâ?
+    if mRevert then
+    begin
+      // Äîøëè äî êîíöà àíèìàöèè. Âîçìîæíî, æäåì åùå
+      if (mCurrentFrame = 0) then
+      begin
+        if (mLength * mSpeed + mCounter < mMinLength) then exit;
+      end;
+
+      mCurrentFrame -= 1;
+      mPlayed := (mCurrentFrame < 0);
+
+      // Ïîâòîðÿòü ëè àíèìàöèþ ïî êðóãó?
+      if mPlayed then
+      begin
+        if mLoop then
+          mCurrentFrame := mLength - 1
+        else
+          mCurrentFrame += 1
+      end;
+
+      mCounter := 0;
+    end
+    else
+    begin
+      // Ïðÿìîé ïîðÿäîê êàäðîâ
+      // Äîøëè äî êîíöà àíèìàöèè. Âîçìîæíî, æäåì åùå
+      if (mCurrentFrame = mLength - 1) then
+      begin
+        if (mLength * mSpeed + mCounter < mMinLength) then exit;
+      end;
+
+      mCurrentFrame += 1;
+      mPlayed := (mCurrentFrame > mLength - 1);
+
+      // Ïîâòîðÿòü ëè àíèìàöèþ ïî êðóãó?
+      if mPlayed then
+      begin
+        if mLoop then mCurrentFrame := 0 else mCurrentFrame -= 1;
+      end;
+
+      mCounter := 0;
+    end;
+  end;
+end;
+
+procedure TAnimationState.reset;
+begin
+  if mRevert then
+    mCurrentFrame := mLength - 1
+  else
+    mCurrentFrame := 0;
+  mCounter := 0;
+  mPlayed := false
+end;
+
+procedure TAnimationState.disable;
+begin
+  mEnabled := false
+end;
+
+procedure TAnimationState.enable;
+begin
+  mEnabled := true
+end;
+
+procedure TAnimationState.revert (r: Boolean);
+begin
+  mRevert := r;
+  reset
+end;
+
+function TAnimationState.totalFrames (): Integer; inline;
+begin
+  result := mLength
+end;
+
+procedure TAnimationState.saveState (st: TStream);
+begin
+  if (st = nil) then exit;
+
+  utils.writeSign(st, 'ANIM');
+  utils.writeInt(st, Byte(0)); // version
+  // Ñ÷åò÷èê îæèäàíèÿ ìåæäó êàäðàìè
+  utils.writeInt(st, Byte(mCounter));
+  // Òåêóùèé êàäð
+  utils.writeInt(st, LongInt(mCurrentFrame));
+  // Ïðîèãðàíà ëè àíèìàöèÿ öåëèêîì
+  utils.writeBool(st, mPlayed);
+  // Alpha-êàíàë âñåé òåêñòóðû
+  utils.writeInt(st, Byte(mAlpha));
+  // Ðàçìûòèå òåêñòóðû
+  utils.writeInt(st, Byte(mBlending));
+  // Âðåìÿ îæèäàíèÿ ìåæäó êàäðàìè
+  utils.writeInt(st, Byte(mSpeed));
+  // Çàöèêëåíà ëè àíèìàöèÿ
+  utils.writeBool(st, mLoop);
+  // Âêëþ÷åíà ëè
+  utils.writeBool(st, mEnabled);
+  // Îæèäàíèå ïîñëå ïðîèãðûâàíèÿ
+  utils.writeInt(st, Byte(mMinLength));
+  // Îáðàòíûé ëè ïîðÿäîê êàäðîâ
+  utils.writeBool(st, mRevert);
+end;
+
+
+procedure TAnimationState.loadState (st: TStream);
+begin
+  if (st = nil) then exit;
+
+  if not utils.checkSign(st, 'ANIM') then raise XStreamError.Create('animation chunk expected');
+  if (utils.readByte(st) <> 0) then raise XStreamError.Create('invalid animation chunk version');
+  // Ñ÷åò÷èê îæèäàíèÿ ìåæäó êàäðàìè
+  mCounter := utils.readByte(st);
+  // Òåêóùèé êàäð
+  mCurrentFrame := utils.readLongInt(st);
+  // Ïðîèãðàíà ëè àíèìàöèÿ öåëèêîì
+  mPlayed := utils.readBool(st);
+  // Alpha-êàíàë âñåé òåêñòóðû
+  mAlpha := utils.readByte(st);
+  // Ðàçìûòèå òåêñòóðû
+  mBlending := utils.readBool(st);
+  // Âðåìÿ îæèäàíèÿ ìåæäó êàäðàìè
+  mSpeed := utils.readByte(st);
+  // Çàöèêëåíà ëè àíèìàöèÿ
+  mLoop := utils.readBool(st);
+  // Âêëþ÷åíà ëè
+  mEnabled := utils.readBool(st);
+  // Îæèäàíèå ïîñëå ïðîèãðûâàíèÿ
+  mMinLength := utils.readByte(st);
+  // Îáðàòíûé ëè ïîðÿäîê êàäðîâ
+  mRevert := utils.readBool(st);
+end;
+
+
+
+
+
+
 constructor TAnimation.Create (aframesID: LongWord; aloop: Boolean; aspeed: Byte);
 begin
   if (aframesID >= Length(framesArray)) then