DEADSOFTWARE

panels: handle panel animation in render (bump protocol)
authorDeaDDooMER <deaddoomer@deadsoftware.ru>
Mon, 13 Jun 2022 21:40:31 +0000 (00:40 +0300)
committerDeaDDooMER <deaddoomer@deadsoftware.ru>
Fri, 9 Jun 2023 08:53:20 +0000 (11:53 +0300)
src/game/g_map.pas
src/game/g_net.pas
src/game/g_netmsg.pas
src/game/g_panel.pas
src/game/renders/opengl/r_map.pas
src/game/renders/opengl/r_textures.pas

index 03c029f6404dad7c884a4647d9752216b9ab6482..54d22a183ba4a224133de8c67d6dbf2b8120bdca 100644 (file)
@@ -959,11 +959,10 @@ end;
   function CreateTexture (RecName: AnsiString; Map: String; log: Boolean): Integer;
     var
       HName: AnsiString;
-      WAD, WADz: TWADFile;
+      WAD: TWADFile;
       WADName, ResName: String;
-      ResData, ReszData: Pointer;
-      ResLen, ReszLen: Integer;
-      cfg: TConfig;
+      ResData: Pointer;
+      ResLen: Integer;
       id: Integer;
   begin
     Result := -1;
@@ -1000,40 +999,13 @@ end;
           begin
             if WAD.GetResource(ResName, ResData, ResLen, log) then
             begin
-              if IsWadData(ResData, ResLen) then
-              begin
-                WADz := TWADFile.Create();
-                if WADz.ReadMemory(ResData, ResLen) then
-                begin
-                  if WADz.GetResource('TEXT/ANIM', ReszData, ReszLen) then
-                  begin
-                    cfg := TConfig.CreateMem(ReszData, ReszLen);
-                    if cfg <> nil then
-                    begin
-                      SetLength(Textures, Length(Textures) + 1);
-                      Textures[High(Textures)].TextureName := RecName;
-                      Textures[High(Textures)].FullName := WadName + ':' + ResName;
-                      Textures[High(Textures)].FramesCount := cfg.ReadInt('', 'framecount', 0);
-                      Textures[High(Textures)].Speed := cfg.ReadInt('', 'waitcount', 0);
-                      Result := High(Textures);
-                      TextNameHash.put(HName, result);
-                      cfg.Free;
-                    end;
-                    FreeMem(ReszData);
-                  end
-                end;
-                WADz.Free;
-              end
-              else
-              begin
-                SetLength(Textures, Length(Textures) + 1);
-                Textures[High(Textures)].FullName := WADName + ':' + ResName;
-                Textures[High(Textures)].TextureName := RecName;
-                Result := High(Textures);
-                TextNameHash.put(HName, result);
-              end;
-              FreeMem(ResData);
-            end
+              SetLength(Textures, Length(Textures) + 1);
+              Textures[High(Textures)].FullName := WADName + ':' + ResName;
+              Textures[High(Textures)].TextureName := RecName;
+              Result := High(Textures);
+              TextNameHash.put(HName, result);
+            end;
+            FreeMem(ResData);
           end;
           WAD.Free;
         end
@@ -2601,7 +2573,7 @@ begin
   tp := g_Map_PanelByGUID(pguid);
   if (tp = nil) then exit;
   tp.NextTexture(AnimLoop);
-  if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelTexture(pguid, AnimLoop);
+  if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelTexture(pguid);
 end;
 
 
index ab13a28c238117ce4ac28d930a91ec515caa51a1..417be8b7c6a568ad6a1742af54ef5f86adab7f00 100644 (file)
@@ -21,7 +21,7 @@ uses
   e_log, e_msg, utils, ENet, Classes, md5, MAPDEF{$IFDEF USE_MINIUPNPC}, miniupnpc;{$ELSE};{$ENDIF}
 
 const
-  NET_PROTOCOL_VER = 188;
+  NET_PROTOCOL_VER = 189;
 
   NET_MAXCLIENTS = 24;
   NET_CHANS = 12;
index 08fd9df69598dd87840cabd9fc700ec104c4b37b..4ada39477e8bf9ee37c7a738029786fce98211a4 100644 (file)
@@ -181,7 +181,7 @@ procedure MH_SEND_ItemSpawn(Quiet: Boolean; IID: Word; ID: Integer = NET_EVERYON
 procedure MH_SEND_ItemDestroy(Quiet: Boolean; IID: Word; ID: Integer = NET_EVERYONE);
 procedure MH_SEND_ItemPos(IID: Word; ID: Integer = NET_EVERYONE);
 // PANEL
-procedure MH_SEND_PanelTexture(PGUID: Integer; AnimLoop: Byte; ID: Integer = NET_EVERYONE);
+procedure MH_SEND_PanelTexture(PGUID: Integer; ID: Integer = NET_EVERYONE);
 procedure MH_SEND_PanelState(PGUID: Integer; ID: Integer = NET_EVERYONE);
 // MONSTER
 procedure MH_SEND_MonsterSpawn(UID: Word; ID: Integer = NET_EVERYONE);
@@ -916,7 +916,7 @@ procedure MH_SEND_Everything(CreatePlayers: Boolean {= False}; ID: Integer {= NE
   begin
     result := false; // don't stop
     MH_SEND_PanelState(pan.guid, ID); // anyway, to sync mplats
-    if (pan.CanChangeTexture) then MH_SEND_PanelTexture(pan.guid, pan.LastAnimLoop, ID);
+    if (pan.CanChangeTexture) then MH_SEND_PanelTexture(pan.guid, ID);
   end;
 
 var
@@ -1485,22 +1485,18 @@ end;
 
 // PANEL
 
-procedure MH_SEND_PanelTexture(PGUID: Integer; AnimLoop: Byte; ID: Integer = NET_EVERYONE);
+procedure MH_SEND_PanelTexture(PGUID: Integer; ID: Integer = NET_EVERYONE);
 var
   TP: TPanel;
 begin
   TP := g_Map_PanelByGUID(PGUID);
   if (TP = nil) then exit;
 
-  with TP do
-  begin
-    NetOut.Write(Byte(NET_MSG_PTEX));
-    NetOut.Write(LongWord(PGUID));
-    NetOut.Write(FCurTexture);
-    NetOut.Write(FCurFrame);
-    NetOut.Write(FCurFrameCount);
-    NetOut.Write(AnimLoop);
-  end;
+  NetOut.Write(Byte(NET_MSG_PTEX));
+  NetOut.Write(LongWord(PGUID));
+  NetOut.Write(TP.FCurTexture);
+  NetOut.Write(TP.AnimTime);
+  NetOut.Write(TP.LastAnimLoop);
 
   g_Net_Host_Send(ID, True, NET_CHAN_LARGEDATA);
 end;
@@ -2823,18 +2819,13 @@ end;
 // PANEL
 
 procedure MC_RECV_PanelTexture(var M: TMsg);
-var
-  TP: TPanel;
-  PGUID: Integer;
-  Tex, Fr: Integer;
-  Loop, Cnt: Byte;
+  var TP: TPanel; PGUID, Tex: Integer; AnimTime: LongWord; Loop: Byte;
 begin
   if not gGameOn then Exit;
 
   PGUID := Integer(M.ReadLongWord());
   Tex := M.ReadLongInt();
-  Fr := M.ReadLongInt();
-  Cnt := M.ReadByte();
+  AnimTime := M.ReadLongWord();
   Loop := M.ReadByte();
 
   TP := g_Map_PanelByGUID(PGUID);
@@ -2842,7 +2833,7 @@ begin
   begin
     // switch texture
     TP.SetTexture(Tex, Loop);
-    TP.SetFrame(Fr, Cnt);
+    TP.SetFrame(AnimTime);
   end;
 end;
 
index 58e7477c6f84d275e67384a718dd4e49a828dcf9..70d2cc15fd4ff5c1deaa801dae3e2d98aaab9e28 100644 (file)
@@ -26,7 +26,6 @@ type
   TLevelTexture = record
     TextureName: AnsiString; // as stored in wad
     FullName: AnsiString; // full path to texture // !!! merge it with TextureName
-    framesCount, speed: Byte;
   end;
 
   TLevelTextureArray = array of TLevelTexture;
@@ -37,7 +36,6 @@ type
 
   ATextureID = array of record
     Texture: Cardinal; // Textures[Texture]
-    AnTex: TAnimState;
   end;
 
   PPanel = ^TPanel;
@@ -49,6 +47,8 @@ type
     FAlpha:           Byte;
     FBlending:        Boolean;
     FTextureIDs:      ATextureID;
+    FAnimTime:        LongWord;
+    FAnimLoop:        Boolean;
     mMovingSpeed: TDFPoint;
     mMovingStart: TDFPoint;
     mMovingEnd: TDFPoint;
@@ -96,9 +96,7 @@ type
     procedure setSizeEndY (v: Integer); inline;
 
   public
-    FCurTexture:      Integer; // Íîìåð òåêóùåé òåêñòóðû
-    FCurFrame:        Integer;
-    FCurFrameCount:   Byte;
+    FCurTexture:      Integer; // Номер текущей текстуры
     FX, FY:           Integer;
     FOldX, FOldY:     Integer;
     FWidth, FHeight:  Word;
@@ -123,7 +121,7 @@ type
     destructor  Destroy(); override;
 
     procedure   Update();
-    procedure   SetFrame(Frame: Integer; Count: Byte);
+    procedure   SetFrame(StartTime: LongWord);
     procedure   NextTexture(AnimLoop: Byte = 0);
     procedure   SetTexture(ID: Integer; AnimLoop: Byte = 0);
     function    GetTextureID(): Cardinal;
@@ -196,10 +194,11 @@ type
     property isGLift: Boolean read getIsGLift;
     property isGBlockMon: Boolean read getIsGBlockMon;
 
-    (* private state *)
     property Alpha: Byte read FAlpha;
     property Blending: Boolean read FBlending;
     property TextureIDs: ATextureID read FTextureIDs;
+    property AnimTime: LongWord read FAnimTime;
+    property AnimLoop: Boolean read FAnimLoop;
 
   public
     property movingSpeed: TDFPoint read mMovingSpeed write mMovingSpeed;
@@ -282,8 +281,6 @@ begin
   FOldH := Height;
   FAlpha := 0;
   FBlending := False;
-  FCurFrame := 0;
-  FCurFrameCount := 0;
   LastAnimLoop := 0;
 
   mapId := PanelRec.id;
@@ -304,7 +301,7 @@ begin
 
   mNeedSend := false;
 
-// Òèï ïàíåëè:
+// Тип панели:
   PanelType := PanelRec.PanelType;
   Enabled := True;
   Door := False;
@@ -320,14 +317,14 @@ begin
     PANEL_LIFTRIGHT: LiftType := LIFTTYPE_RIGHT;
   end;
 
-// Íåâèäèìàÿ:
+// Невидимая:
   if ByteBool(PanelRec.Flags and PANEL_FLAG_HIDE) then
   begin
     SetLength(FTextureIDs, 0);
     FCurTexture := -1;
     Exit;
   end;
-// Ïàíåëè, íå èñïîëüçóþùèå òåêñòóðû:
+// Панели, не использующие текстуры:
   if ByteBool(PanelType and
     (PANEL_LIFTUP or
      PANEL_LIFTDOWN or
@@ -340,7 +337,7 @@ begin
     Exit;
   end;
 
-// Åñëè ýòî æèäêîñòü áåç òåêñòóðû - ñïåöòåêñòóðó:
+// Если это жидкость без текстуры - спецтекстуру:
   if WordBool(PanelType and (PANEL_WATER or PANEL_ACID1 or PANEL_ACID2)) and
      (not ByteBool(PanelRec.Flags and PANEL_FLAG_WATERTEXTURES)) then
   begin
@@ -364,22 +361,19 @@ begin
     else
       FCurTexture := CurTex;
 
-  for i := 0 to Length(FTextureIDs)-1 do
-  begin
+  for i := 0 to Length(FTextureIDs) - 1 do
     FTextureIDs[i].Texture := AddTextures[i].Texture;
-    if Textures[AddTextures[i].Texture].FramesCount > 0 then
-      FTextureIDs[i].AnTex := TAnimState.Create(True, Textures[AddTextures[i].Texture].Speed, Textures[AddTextures[i].Texture].FramesCount)
-    else
-      FTextureIDs[i].AnTex.Invalidate;
-  end;
 
-// Òåêñòóð íåñêîëüêî - íóæíî ñîõðàíÿòü òåêóùóþ:
+  FAnimTime := gTime;
+  FAnimLoop := true;
+
+// Текстур несколько - нужно сохранять текущую:
   //if Length(FTextureIDs) > 1 then SaveIt := True;
 
   if (PanelRec.TextureRec = nil) then tnum := -1 else tnum := PanelRec.tagInt;
   if (tnum < 0) then tnum := Length(Textures);
 
-// Åñëè íå ñïåöòåêñòóðà, òî çàäàåì ðàçìåðû:
+// Если не спецтекстура, то задаем размеры:
   if ({PanelRec.TextureNum}tnum > High(Textures)) then
   begin
     e_WriteLog(Format('WTF?! tnum is out of limits! (%d : %d)', [tnum, High(Textures)]), TMsgType.Warning);
@@ -605,13 +599,6 @@ var
 begin
   if (not Enabled) or (Width < 1) or (Height < 1) then exit;
 
-  if (FCurTexture >= 0) and (FTextureIDs[FCurTexture].AnTex.IsValid()) and (FAlpha < 255) then
-  begin
-    FTextureIDs[FCurTexture].AnTex.Update();
-    FCurFrame := FTextureIDs[FCurTexture].AnTex.CurrentFrame;
-    FCurFrameCount := FTextureIDs[FCurTexture].AnTex.CurrentCounter;
-  end;
-
   if not g_dbgpan_mplat_active then exit;
 
   if (mOldMovingActive <> mMovingActive) then mNeedSend := true;
@@ -867,34 +854,21 @@ begin
   end;
 end;
 
-
-procedure TPanel.SetFrame(Frame: Integer; Count: Byte);
-
-  function ClampInt(X, A, B: Integer): Integer;
+  procedure TPanel.SetFrame (StartTime: LongWord);
   begin
-    Result := X;
-    if X < A then Result := A else if X > B then Result := B;
+    if Enabled and (FCurTexture >= 0) and (Width > 0) and (Height > 0) and (FAlpha < 255) then
+      FAnimTime := StartTime;
   end;
 
-begin
-  if Enabled and (FCurTexture >= 0) and (FTextureIDs[FCurTexture].AnTex.IsValid()) and (Width > 0) and (Height > 0) and (FAlpha < 255) then
-  begin
-    FCurFrame := ClampInt(Frame, 0, FTextureIDs[FCurTexture].AnTex.TotalFrames - 1);
-    FCurFrameCount := Count;
-    FTextureIDs[FCurTexture].AnTex.CurrentFrame := FCurFrame;
-    FTextureIDs[FCurTexture].AnTex.CurrentCounter := FCurFrameCount;
-  end;
-end;
-
 procedure TPanel.NextTexture(AnimLoop: Byte = 0);
 begin
   Assert(FCurTexture >= -1, 'FCurTexture < -1');
 
-// Íåò òåêñòóð:
+// Нет текстур:
   if Length(FTextureIDs) = 0 then
     FCurTexture := -1
   else
-  // Òîëüêî îäíà òåêñòóðà:
+  // Только одна текстура:
     if Length(FTextureIDs) = 1 then
       begin
         if FCurTexture = 0 then
@@ -903,23 +877,22 @@ begin
           FCurTexture := 0;
       end
     else
-    // Áîëüøå îäíîé òåêñòóðû:
+    // Больше одной текстуры:
       begin
-      // Ñëåäóþùàÿ:
+      // Следующая:
         Inc(FCurTexture);
-      // Ñëåäóþùåé íåò - âîçâðàò ê íà÷àëó:
+      // Следующей нет - возврат к началу:
         if FCurTexture >= Length(FTextureIDs) then
           FCurTexture := 0;
       end;
 
-// Ïåðåêëþ÷èëèñü íà âèäèìóþ àíèì. òåêñòóðó:
-  if (FCurTexture >= 0) and FTextureIDs[FCurTexture].AnTex.IsValid() then
+  if FCurTexture >= 0 then
   begin
-    if AnimLoop = 1 then
-      FTextureIDs[FCurTexture].AnTex.Loop := True
-    else if AnimLoop = 2 then
-      FTextureIDs[FCurTexture].AnTex.Loop := False;
-    FTextureIDs[FCurTexture].AnTex.Reset();
+    case AnimLoop of
+      1: FAnimLoop := true;
+      2: FAnimLoop := false;
+    end;
+    FAnimTime := gTime;
   end;
 
   LastAnimLoop := AnimLoop;
@@ -930,14 +903,13 @@ begin
   if (ID >= -1) and (ID < Length(FTextureIDs)) then
     FCurTexture := ID;
 
-// Ïåðåêëþ÷èëèñü íà âèäèìóþ àíèì. òåêñòóðó:
-  if (FCurTexture >= 0) and FTextureIDs[FCurTexture].AnTex.IsValid() then
+  if FCurTexture >= 0 then
   begin
-    if AnimLoop = 1 then
-      FTextureIDs[FCurTexture].AnTex.Loop := True
-    else if AnimLoop = 2 then
-      FTextureIDs[FCurTexture].AnTex.Loop := False;
-    FTextureIDs[FCurTexture].AnTex.Reset();
+    case AnimLoop of
+      1: FAnimLoop := true;
+      2: FAnimLoop := false;
+    end;
+    FAnimTime := gTime;
   end;
 
   LastAnimLoop := AnimLoop;
@@ -961,9 +933,8 @@ end;
 function TPanel.GetTextureCount(): Integer;
 begin
   Result := Length(FTextureIDs);
-  if Enabled and (FCurTexture >= 0) then
-    if (FTextureIDs[FCurTexture].AnTex.IsValid()) and (Width > 0) and (Height > 0) and (FAlpha < 255) then
-      Result := Result + 100;
+  if Enabled and (FCurTexture >= 0) and (Width > 0) and (Height > 0) and (FAlpha < 255) then
+    Result := Result + 100; // ???
 end;
 
 function TPanel.CanChangeTexture(): Boolean;
@@ -975,30 +946,34 @@ const
   PAN_SAVE_VERSION = 1;
 
 procedure TPanel.SaveState (st: TStream);
-var
-  anim: Boolean;
+  var anim: Boolean; stub: TAnimState;
 begin
   if (st = nil) then exit;
 
-  // Ñèãíàòóðà ïàíåëè
+  // Сигнатура панели
   utils.writeSign(st, 'PANL');
   utils.writeInt(st, Byte(PAN_SAVE_VERSION));
-  // Îòêðûòà/çàêðûòà, åñëè äâåðü
+  // Открыта/закрыта, если дверь
   utils.writeBool(st, FEnabled);
-  // Íàïðàâëåíèå ëèôòà, åñëè ëèôò
+  // Направление лифта, если лифт
   utils.writeInt(st, Byte(FLiftType));
-  // Íîìåð òåêóùåé òåêñòóðû
+  // Номер текущей текстуры
   utils.writeInt(st, Integer(FCurTexture));
-  // Êîîðäèíàòû è ðàçìåð
+  // Координаты и размер
   utils.writeInt(st, Integer(FX));
   utils.writeInt(st, Integer(FY));
   utils.writeInt(st, Word(FWidth));
   utils.writeInt(st, Word(FHeight));
-  // Àíèìèðîâàíà ëè òåêóùàÿ òåêñòóðà
-  anim := (FCurTexture >= 0) and (FTextureIDs[FCurTexture].AnTex.IsValid());
+  // Анимирована ли текущая текстура
+  anim := FCurTexture >= 0;
   utils.writeBool(st, anim);
-  // Åñëè äà - ñîõðàíÿåì àíèìàöèþ
-  if anim then FTextureIDs[FCurTexture].AnTex.SaveState(st, FAlpha, FBlending);
+  // Если да - сохраняем анимацию
+  if anim then
+  begin
+    stub := TAnimState.Create(FAnimLoop, 1, 1);
+    stub.SaveState(st, FAlpha, FBlending);
+    stub.Invalidate;
+  end;
 
   // moving platform state
   utils.writeInt(st, Integer(mMovingSpeed.X));
@@ -1022,19 +997,20 @@ end;
 
 
 procedure TPanel.LoadState (st: TStream);
+  var stub: TAnimState;
 begin
   if (st = nil) then exit;
 
-  // Ñèãíàòóðà ïàíåëè
+  // Сигнатура панели
   if not utils.checkSign(st, 'PANL') then raise XStreamError.create('wrong panel signature');
   if (utils.readByte(st) <> PAN_SAVE_VERSION) then raise XStreamError.create('wrong panel version');
-  // Îòêðûòà/çàêðûòà, åñëè äâåðü
+  // Открыта/закрыта, если дверь
   FEnabled := utils.readBool(st);
-  // Íàïðàâëåíèå ëèôòà, åñëè ëèôò
+  // Направление лифта, если лифт
   FLiftType := utils.readByte(st);
-  // Íîìåð òåêóùåé òåêñòóðû
+  // Номер текущей текстуры
   FCurTexture := utils.readLongInt(st);
-  // Êîîðäèíàòû è ðàçìåð
+  // Координаты и размер
   FX := utils.readLongInt(st);
   FY := utils.readLongInt(st);
   FOldX := FX;
@@ -1043,12 +1019,14 @@ begin
   FHeight := utils.readWord(st);
   FOldW := FWidth;
   FOldH := FHeight;
-  // Àíèìèðîâàííàÿ ëè òåêóùàÿ òåêñòóðà
+  // Анимированная ли текущая текстура
   if utils.readBool(st) then
   begin
-    // Åñëè äà - çàãðóæàåì àíèìàöèþ
-    Assert((FCurTexture >= 0) and (FTextureIDs[FCurTexture].AnTex.IsValid()), 'TPanel.LoadState: No animation object');
-    FTextureIDs[FCurTexture].AnTex.LoadState(st, FAlpha, FBlending);
+    // Если да - загружаем анимацию
+    Assert(FCurTexture >= 0, 'TPanel.LoadState: No animation object');
+    stub := TAnimState.Create(FAnimLoop, 1, 1);
+    stub.LoadState(st, FAlpha, FBlending);
+    stub.Invalidate;
   end;
 
   // moving platform state
index 7e9482e6a3e7b43e82a94851c43d177756898e32..786bd5409728417dc9f342797999f857a85f94b7 100644 (file)
@@ -238,6 +238,7 @@ implementation
     RenTextures: array of record
       spec: LongInt;
       tex: TGLMultiTexture;
+      anim: TAnimInfo;
     end;
     Items: array [0..ITEM_LAST] of record
       tex: TGLMultiTexture;
@@ -547,7 +548,8 @@ implementation
   end;
 
   procedure r_Map_LoadTextures;
-    var i, n: Integer;
+    const DefaultAnimInfo: TAnimInfo = (loop: true; delay: 1; frames: 1; back: false);
+    var i, n: Integer; txt: TAnimTextInfo;
   begin
     if Textures <> nil then
     begin
@@ -555,6 +557,7 @@ implementation
       SetLength(RenTextures, n);
       for i := 0 to n - 1 do
       begin
+        txt.anim := DefaultAnimInfo;
         RenTextures[i].tex := nil;
         case Textures[i].TextureName of
           TEXTURE_NAME_WATER: RenTextures[i].spec := TEXTURE_SPECIAL_WATER;
@@ -562,10 +565,13 @@ implementation
           TEXTURE_NAME_ACID2: RenTextures[i].spec := TEXTURE_SPECIAL_ACID2;
           else
             RenTextures[i].spec := 0;
-            RenTextures[i].tex := r_Textures_LoadMultiFromFile(Textures[i].FullName);
+            e_LogWritefln('r_Map_LoadTextures: begin load texture: %s', [Textures[i].FullName]);
+            RenTextures[i].tex := r_Textures_LoadMultiTextFromFile(Textures[i].FullName, txt);
+            e_LogWritefln('r_Map_LoadTextures: end load texture: %s', [Textures[i].FullName]);
             if RenTextures[i].tex = nil then
               e_LogWritefln('r_Map_LoadTextures: failed to load texture: %s', [Textures[i].FullName]);
         end;
+        RenTextures[i].anim := txt.anim;
       end;
     end;
     if gMapInfo.SkyFullName <> '' then
@@ -588,22 +594,29 @@ implementation
   end;
 
   procedure r_Map_DrawPanel (p: TPanel);
-    var Texture: Integer; t: TGLMultiTexture;
+    var Texture: Integer; t: TGLMultiTexture; tex: TGLTexture; count, frame: LongInt; a: TAnimInfo;
   begin
     ASSERT(p <> nil);
     if p.FCurTexture >= 0 then
     begin
       Texture := p.TextureIDs[p.FCurTexture].Texture;
       t := RenTextures[Texture].tex;
-
       if (RenTextures[Texture].spec = 0) or (t <> nil) then
       begin
-        if t = nil then
-          r_Draw_TextureRepeat(nil, p.x, p.y, p.width, p.height, false, 255, 255, 255, 255 - p.alpha, p.blending)
-        else if p.TextureIDs[p.FCurTexture].AnTex.IsValid() then
-          r_Draw_MultiTextureRepeat(t, p.TextureIDs[p.FCurTexture].AnTex, p.x, p.y, p.width, p.height, false, 255, 255, 255, 255 - p.alpha, p.blending)
+        count := 0; frame := 0;
+        if p.AnimTime <= gTime then
+        begin
+          a := RenTextures[Texture].anim;
+          a.loop := p.AnimLoop;
+          g_Anim_GetFrameByTime(a, (gTime - p.AnimTime) DIV GAME_TICK, count, frame);
+        end;
+        if t <> nil then
+        begin
+          tex := t.GetTexture(frame);
+          r_Draw_TextureRepeat(tex, p.x, p.y, p.width, p.height, false, 255, 255, 255, 255 - p.alpha, p.blending);
+        end
         else
-          r_Draw_TextureRepeat(t.GetTexture(0), p.x, p.y, p.width, p.height, false, 255, 255, 255, 255 - p.alpha, p.blending)
+          r_Draw_TextureRepeat(nil, p.x, p.y, p.width, p.height, false, 255, 255, 255, 255, false);
       end;
 
       if t = nil then
index 64d4f533ab39c7fd89e4704d808258864489a51e..062f76bdcebe373f1ecc231c88ba127b7724d476 100644 (file)
@@ -23,7 +23,7 @@ interface
     {$ELSE}
       GL, GLEXT,
     {$ENDIF}
-    g_base,  // TRectHW
+    g_base, g_animations,  // TRectHW, TAnimInfo
     utils,
     r_atlas, r_fonts
   ;
@@ -116,12 +116,20 @@ interface
         function GetSpace (): Integer;
     end;
 
+    TAnimTextInfo = record
+      name: AnsiString;
+      w, h: Integer;
+      anim: TAnimInfo;
+    end;
+
   procedure r_Textures_Initialize;
   procedure r_Textures_Finalize;
 
   function r_Textures_LoadFromFile (const filename: AnsiString; log: Boolean = True): TGLTexture;
   function r_Textures_LoadMultiFromFile (const filename: AnsiString; log: Boolean = True): TGLMultiTexture;
   function r_Textures_LoadMultiFromFileAndInfo (const filename: AnsiString; w, h, count: Integer; backanim: Boolean; log: Boolean = True): TGLMultiTexture;
+  function r_Textures_LoadMultiTextFromFile (const filename: AnsiString; var txt: TAnimTextInfo; log: Boolean = True): TGLMultiTexture;
+
   function r_Textures_LoadStreamFromFile (const filename: AnsiString; w, h, count, cw: Integer; st: TGLTextureArray; rs: TRectArray; log: Boolean = True): Boolean;
 
   function r_Textures_LoadFontFromFile (const filename: AnsiString; constref f: TFontInfo; skipch: Integer; log: Boolean = true): TGLFont;
@@ -494,43 +502,57 @@ implementation
     end;
   end;
 
-  function r_Textures_LoadMultiFromWad (wad: TWADFile): TGLMultiTexture;
-    var data: Pointer; size: LongInt; TexRes: AnsiString; w, h, c: Integer; b: Boolean; cfg: TConfig; img: TImageData;
+  function r_Textures_LoadTextFromMemory (data: Pointer; size: LongInt; var txt: TAnimTextInfo): Boolean;
+    var cfg: TConfig;
+  begin
+    result := false;
+    if data <> nil then
+    begin
+      cfg := TConfig.CreateMem(data, size);
+      if cfg <> nil then
+      begin
+        txt.name := cfg.ReadStr('', 'resource', '');
+        txt.w := MAX(0, cfg.ReadInt('', 'framewidth', 0));
+        txt.h := MAX(0, cfg.ReadInt('', 'frameheight', 0));
+        txt.anim.loop := true;
+        txt.anim.delay := MAX(0, cfg.ReadInt('', 'waitcount', 0));
+        txt.anim.frames := MAX(0, cfg.ReadInt('', 'framecount', 0));
+        txt.anim.back := cfg.ReadBool('', 'backanim', false);
+        cfg.Free;
+        result := (txt.name <> '') and (txt.w > 0) and (txt.h > 0) and (txt.anim.delay > 0) and (txt.anim.frames > 0);
+      end;
+    end;
+  end;
+
+  function r_Textures_LoadMultiFromWad (wad: TWADFile; var txt: TAnimTextInfo): TGLMultiTexture;
+    var data: Pointer; size: LongInt; img: TImageData;
   begin
     ASSERT(wad <> nil);
     result := nil;
     if wad.GetResource('TEXT/ANIM', data, size) then
     begin
-      cfg := TConfig.CreateMem(data, size);
-      FreeMem(data);
-      if cfg <> nil then
+      if r_Textures_LoadTextFromMemory(data, size, txt) then
       begin
-        TexRes := cfg.ReadStr('', 'resource', '');
-        w := cfg.ReadInt('', 'framewidth', 0);
-        h := cfg.ReadInt('', 'frameheight', 0);
-        c := cfg.ReadInt('', 'framecount', 0);
-        b := cfg.ReadBool('', 'backanim', false);
-        if (TexRes <> '') and (w > 0) and (h > 0) and (c > 0) then
+        FreeMem(data);
+        if wad.GetResource('TEXTURES/' + txt.name, data, size) then
         begin
-          if wad.GetResource('TEXTURES/' + TexRes, data, size) then
-          begin
-            InitImage(img);
-            try
-              if LoadImageFromMemory(data, size, img) then
-                if r_Textures_FixImageData(img) then
-                  result := r_Textures_LoadMultiFromImageAndInfo(img, w, h, c, b)
-            finally
-              FreeMem(data);
-            end;
-            FreeImage(img);
-          end
+          InitImage(img);
+          try
+            if LoadImageFromMemory(data, size, img) then
+              if r_Textures_FixImageData(img) then
+                result := r_Textures_LoadMultiFromImageAndInfo(img, txt.w, txt.h, txt.anim.frames, txt.anim.back);
+          finally
+            FreeMem(data);
+          end;
+          FreeImage(img);
         end;
-        cfg.Free;
       end
+      else
+        FreeMem(data);
     end;
   end;
 
-  function r_Textures_LoadMultiFromMemory (data: Pointer; size: LongInt): TGLMultiTexture;
+  function r_Textures_LoadMultiFromMemory (data: Pointer; size: LongInt; var txt: TAnimTextInfo): TGLMultiTexture;
     var wad: TWADFile; t: TGLTexture; m: TGLMultiTexture;
   begin
     result := nil;
@@ -543,6 +565,13 @@ implementation
         SetLength(m.mTexture, 1);
         m.mTexture[0] := t;
         m.mBackanim := false;
+        txt.name := '';
+        txt.w := m.width;
+        txt.h := m.height;
+        txt.anim.loop := true;
+        txt.anim.delay := 1;
+        txt.anim.frames := 1;
+        txt.anim.back := false;
         result := m;
       end
       else if IsWadData(data, size) then
@@ -550,15 +579,15 @@ implementation
         wad := TWADFile.Create();
         if wad.ReadMemory(data, size) then
         begin
-          result := r_Textures_LoadMultiFromWad(wad);
+          result := r_Textures_LoadMultiFromWad(wad, txt);
           wad.Free;
         end
       end
     end
   end;
 
-  function r_Textures_LoadMultiFromFile (const filename: AnsiString; log: Boolean = True): TGLMultiTexture;
-    var wad: TWADFile; wadName, resName: AnsiString; data: Pointer; size: Integer; t: TGLTexture;
+  function r_Textures_LoadMultiTextFromFile (const filename: AnsiString; var txt: TAnimTextInfo; log: Boolean = True): TGLMultiTexture;
+    var wad: TWADFile; wadName, resName: AnsiString; data: Pointer; size: Integer;
   begin
     result := nil;
     wadName := g_ExtractWadName(filename);
@@ -568,13 +597,19 @@ implementation
       resName := g_ExtractFilePathName(filename);
       if wad.GetResource(resName, data, size, log) then
       begin
-        result := r_Textures_LoadMultiFromMemory(data, size);
+        result := r_Textures_LoadMultiFromMemory(data, size, txt);
         FreeMem(data);
       end;
       wad.Free
     end
   end;
 
+  function r_Textures_LoadMultiFromFile (const filename: AnsiString; log: Boolean = True): TGLMultiTexture;
+    var txt: TAnimTextInfo;
+  begin
+    result := r_Textures_LoadMultiTextFromFile(filename, txt, log);
+  end;
+
   function r_Textures_LoadMultiFromFileAndInfo (const filename: AnsiString; w, h, count: Integer; backanim: Boolean; log: Boolean = True): TGLMultiTexture;
     var wad: TWADFile; wadName, resName: AnsiString; data: Pointer; size: Integer;
   begin