DEADSOFTWARE

gl: fix fluid textures
[d2df-sdl.git] / src / game / g_panel.pas
index abdb26d803ce88559ed170b957973e73aa703977..2681f1d43ec1e40e7b50712e0f3f7a5183c3c0ed 100644 (file)
@@ -20,19 +20,22 @@ interface
 
 uses
   SysUtils, Classes,
-  MAPDEF, g_textures, xdynrec;
+  MAPDEF, g_animations, xdynrec;
 
 type
+  TLevelTexture = record
+    TextureName: AnsiString; // as stored in wad
+    FullName: AnsiString; // full path to texture // !!! merge it with TextureName
+  end;
+
+  TLevelTextureArray = array of TLevelTexture;
+
   TAddTextureArray = array of record
     Texture: Cardinal; // Textures[Texture]
-    Anim: Boolean;
   end;
 
   ATextureID = array of record
     Texture: Cardinal; // Textures[Texture]
-    case Anim: Boolean of
-      False: ();
-      True:  (AnTex: TAnimationState);
   end;
 
   PPanel = ^TPanel;
@@ -44,6 +47,8 @@ type
     FAlpha:           Byte;
     FBlending:        Boolean;
     FTextureIDs:      ATextureID;
+    FAnimTime:        LongWord;
+    FAnimLoop:        Boolean;
     mMovingSpeed: TDFPoint;
     mMovingStart: TDFPoint;
     mMovingEnd: TDFPoint;
@@ -91,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;
@@ -118,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;
@@ -191,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;
@@ -223,15 +227,46 @@ var
 
 implementation
 
-uses
-  g_basic, g_map, g_game, g_gfx, g_weapons, g_triggers, g_items,
-  g_console, g_language, g_monsters, g_player, g_grid, e_log, geom, utils, xstreams;
+  uses
+    {$IFDEF ENABLE_GFX}
+      g_gfx,
+    {$ENDIF}
+    {$IFDEF ENABLE_GIBS}
+      g_gibs,
+    {$ENDIF}
+    {$IFDEF ENABLE_CORPSES}
+      g_corpses,
+    {$ENDIF}
+    g_basic, g_map, g_game, g_weapons, g_triggers, g_items,
+    g_console, g_language, g_monsters, g_player, g_grid, e_log, geom, utils, xstreams
+  ;
 
 const
   PANEL_SIGNATURE = $4C4E4150; // 'PANL'
 
 { T P a n e l : }
 
+  function GetSpecialTexture (const name: String): Integer;
+    (* HACK: get texture id, if not present -> insert it into list *)
+    (* required for older maps *)
+    var i, len: Integer;
+  begin
+    i := 0; len := 0;
+    if Textures <> nil then
+    begin
+      len := Length(Textures);
+      while (i < len) and (Textures[i].TextureName <> name) do
+        Inc(i);
+    end;
+    if i >= len then
+    begin
+      i := len;
+      SetLength(Textures, len + 1);
+      Textures[i].TextureName := name;
+    end;
+    result := i;
+  end;
+
 constructor TPanel.Create(PanelRec: TDynRecord;
                           AddTextures: TAddTextureArray;
                           CurTex: Integer;
@@ -250,8 +285,6 @@ begin
   FOldH := Height;
   FAlpha := 0;
   FBlending := False;
-  FCurFrame := 0;
-  FCurFrameCount := 0;
   LastAnimLoop := 0;
 
   mapId := PanelRec.id;
@@ -272,7 +305,7 @@ begin
 
   mNeedSend := false;
 
-// Òèï ïàíåëè:
+// Тип панели:
   PanelType := PanelRec.PanelType;
   Enabled := True;
   Door := False;
@@ -288,14 +321,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
@@ -308,25 +341,16 @@ 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
     SetLength(FTextureIDs, 1);
-    FTextureIDs[0].Anim := False;
-
-{
-    // !!! set this
     case PanelRec.PanelType of
-      PANEL_WATER:
-        FTextureIDs[0].Tex := LongWord(TEXTURE_SPECIAL_WATER);
-      PANEL_ACID1:
-        FTextureIDs[0].Tex := LongWord(TEXTURE_SPECIAL_ACID1);
-      PANEL_ACID2:
-        FTextureIDs[0].Tex := LongWord(TEXTURE_SPECIAL_ACID2);
+      PANEL_WATER: FTextureIDs[0].Texture := GetSpecialTexture(TEXTURE_NAME_WATER);
+      PANEL_ACID1: FTextureIDs[0].Texture := GetSpecialTexture(TEXTURE_NAME_ACID1);
+      PANEL_ACID2: FTextureIDs[0].Texture := GetSpecialTexture(TEXTURE_NAME_ACID2);
     end;
-}
-
     FCurTexture := 0;
     Exit;
   end;
@@ -341,25 +365,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;
-    FTextureIDs[i].Anim := AddTextures[i].Anim;
-    if FTextureIDs[i].Anim then
-    begin // Àíèìèðîâàííàÿ òåêñòóðà
-      FTextureIDs[i].AnTex := TAnimationState.Create(True, Textures[AddTextures[i].Texture].Speed, Textures[AddTextures[i].Texture].FramesCount);
-      FTextureIDs[i].AnTex.Blending := ByteBool(PanelRec.Flags and PANEL_FLAG_BLENDING);
-      FTextureIDs[i].AnTex.Alpha := PanelRec.Alpha;
-    end
-  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);
@@ -374,14 +392,8 @@ begin
 end;
 
 destructor TPanel.Destroy();
-var
-  i: Integer;
 begin
-  for i := 0 to High(FTextureIDs) do
-    if FTextureIDs[i].Anim then
-      FTextureIDs[i].AnTex.Free();
   SetLength(FTextureIDs, 0);
-
   Inherited;
 end;
 
@@ -440,7 +452,9 @@ begin
       e_LogWritefln('panel moved: arridx=%s; guid=%s; proxyid=%s; old:(%s,%s)-(%sx%s); new:(%s,%s)-(%sx%s)',
         [arrIdx, mGUID, proxyId, px, py, pw, ph, x, y, width, height]);
       }
-      g_Mark(px, py, pw, ph, MARK_WALL, false);
+      {$IFDEF ENABLE_GFX}
+        g_Mark(px, py, pw, ph, MARK_WALL, false);
+      {$ENDIF}
       if (Width < 1) or (Height < 1) then
       begin
         mapGrid.proxyEnabled[proxyId] := false;
@@ -457,7 +471,9 @@ begin
         begin
           mapGrid.moveBody(proxyId, X, Y);
         end;
-        g_Mark(X, Y, Width, Height, MARK_WALL);
+        {$IFDEF ENABLE_GFX}
+          g_Mark(X, Y, Width, Height, MARK_WALL);
+        {$ENDIF}
       end;
     end;
   end;
@@ -571,28 +587,22 @@ var
   px, py, pw, ph, pdx, pdy: Integer;
   squash: Boolean;
   plr: TPlayer;
-  gib: PGib;
-  cor: TCorpse;
+  {$IFDEF ENABLE_GIBS}
+    gib: PGib;
+  {$ENDIF}
+  {$IFDEF ENABLE_CORPSES}
+    cor: TCorpse;
+  {$ENDIF}
+  ontop: Boolean;
   mon: TMonster;
   flg: PFlag;
   itm: PItem;
   mpfrid: LongWord;
-  ontop: Boolean;
   actMoveTrig: Boolean;
   actSizeTrig: Boolean;
 begin
   if (not Enabled) or (Width < 1) or (Height < 1) then exit;
 
-  if (FCurTexture >= 0) and
-    (FTextureIDs[FCurTexture].Anim) and
-    (FTextureIDs[FCurTexture].AnTex <> nil) 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;
@@ -691,33 +701,37 @@ begin
           if not g_Game_IsClient and squash then plr.Damage(15000, 0, 0, 0, HIT_TRAP);
         end;
 
-        // process gibs
-        for f := 0 to High(gGibs) do
-        begin
-          gib := @gGibs[f];
-          if not gib.alive then continue;
-          gib.getMapBox(px, py, pw, ph);
-          if not g_Collide(px, py, pw, ph, cx0, cy0, cw, ch) then continue;
-          if tryMPlatMove(px, py, pw, ph, pdx, pdy, squash, @ontop) then
+        {$IFDEF ENABLE_GIBS}
+          // process gibs
+          for f := 0 to High(gGibs) do
           begin
-            // set new position
-            gib.moveBy(pdx, pdy); // this will call `positionChanged()` for us
+            gib := @gGibs[f];
+            if not gib.alive then continue;
+            gib.getMapBox(px, py, pw, ph);
+            if not g_Collide(px, py, pw, ph, cx0, cy0, cw, ch) then continue;
+            if tryMPlatMove(px, py, pw, ph, pdx, pdy, squash, @ontop) then
+            begin
+              // set new position
+              gib.moveBy(pdx, pdy); // this will call `positionChanged()` for us
+            end;
           end;
-        end;
+        {$ENDIF}
 
-        // move and push corpses
-        for f := 0 to High(gCorpses) do
-        begin
-          cor := gCorpses[f];
-          if (cor = nil) then continue;
-          cor.getMapBox(px, py, pw, ph);
-          if not g_Collide(px, py, pw, ph, cx0, cy0, cw, ch) then continue;
-          if tryMPlatMove(px, py, pw, ph, pdx, pdy, squash, @ontop) then
+        {$IFDEF ENABLE_CORPSES}
+          // move and push corpses
+          for f := 0 to High(gCorpses) do
           begin
-            // set new position
-            cor.moveBy(pdx, pdy); // this will call `positionChanged()` for us
+            cor := gCorpses[f];
+            if (cor = nil) then continue;
+            cor.getMapBox(px, py, pw, ph);
+            if not g_Collide(px, py, pw, ph, cx0, cy0, cw, ch) then continue;
+            if tryMPlatMove(px, py, pw, ph, pdx, pdy, squash, @ontop) then
+            begin
+              // set new position
+              cor.moveBy(pdx, pdy); // this will call `positionChanged()` for us
+            end;
           end;
-        end;
+        {$ENDIF}
 
         // move and push flags
         if gGameSettings.GameMode = GM_CTF then
@@ -844,37 +858,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].Anim) and
-    (FTextureIDs[FCurTexture].AnTex <> nil) 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
@@ -883,31 +881,22 @@ begin
           FCurTexture := 0;
       end
     else
-    // Áîëüøå îäíîé òåêñòóðû:
+    // Больше одной текстуры:
       begin
-      // Ñëåäóþùàÿ:
+      // Следующая:
         Inc(FCurTexture);
-      // Ñëåäóþùåé íåò - âîçâðàò ê íà÷àëó:
+      // Следующей нет - возврат к началу:
         if FCurTexture >= Length(FTextureIDs) then
           FCurTexture := 0;
       end;
 
-// Ïåðåêëþ÷èëèñü íà âèäèìóþ àíèì. òåêñòóðó:
-  if (FCurTexture >= 0) and FTextureIDs[FCurTexture].Anim then
+  if FCurTexture >= 0 then
   begin
-    if (FTextureIDs[FCurTexture].AnTex = nil) then
-    begin
-      g_FatalError(_lc[I_GAME_ERROR_SWITCH_TEXTURE]);
-      Exit;
+    case AnimLoop of
+      1: FAnimLoop := true;
+      2: FAnimLoop := false;
     end;
-
-    if AnimLoop = 1 then
-      FTextureIDs[FCurTexture].AnTex.Loop := True
-    else
-      if AnimLoop = 2 then
-        FTextureIDs[FCurTexture].AnTex.Loop := False;
-
-    FTextureIDs[FCurTexture].AnTex.Reset();
+    FAnimTime := gTime;
   end;
 
   LastAnimLoop := AnimLoop;
@@ -918,54 +907,41 @@ begin
   if (ID >= -1) and (ID < Length(FTextureIDs)) then
     FCurTexture := ID;
 
-// Ïåðåêëþ÷èëèñü íà âèäèìóþ àíèì. òåêñòóðó:
-  if (FCurTexture >= 0) and FTextureIDs[FCurTexture].Anim then
+  if FCurTexture >= 0 then
   begin
-    if (FTextureIDs[FCurTexture].AnTex = nil) then
-    begin
-      g_FatalError(_lc[I_GAME_ERROR_SWITCH_TEXTURE]);
-      Exit;
+    case AnimLoop of
+      1: FAnimLoop := true;
+      2: FAnimLoop := false;
     end;
-
-    if AnimLoop = 1 then
-      FTextureIDs[FCurTexture].AnTex.Loop := True
-    else
-      if AnimLoop = 2 then
-        FTextureIDs[FCurTexture].AnTex.Loop := False;
-
-    FTextureIDs[FCurTexture].AnTex.Reset();
+    FAnimTime := gTime;
   end;
 
   LastAnimLoop := AnimLoop;
 end;
 
-function TPanel.GetTextureID(): DWORD;
-begin
-  Result := LongWord(TEXTURE_NONE);
-//  if (FCurTexture >= 0) then
-//  begin
-//    if FTextureIDs[FCurTexture].Anim then
-//      Result := Textures[FTextureIDs[FCurTexture].Texture].FramesID
-//    else
-//      Result := Textures[FTextureIDs[FCurTexture].Texture].TextureID
-{
-    // !!! old behavior
-    if FTextureIDs[FCurTexture].Anim then
-      Result := FTextureIDs[FCurTexture].AnTex.FramesID
-    else
-      Result := FTextureIDs[FCurTexture].Tex;
-}
-//  end
-end;
+  function TPanel.GetTextureID(): DWORD;
+    var Texture: Integer;
+  begin
+    Result := LongWord(TEXTURE_NONE);
+    if (FCurTexture >= 0) then
+    begin
+      Texture := FTextureIDs[FCurTexture].Texture;
+      if Texture >= 0 then
+      begin
+        case Textures[Texture].TextureName of (* TODO: optimize it *)
+          TEXTURE_NAME_WATER: Result := DWORD(TEXTURE_SPECIAL_WATER);
+          TEXTURE_NAME_ACID1: Result := DWORD(TEXTURE_SPECIAL_ACID1);
+          TEXTURE_NAME_ACID2: Result := DWORD(TEXTURE_SPECIAL_ACID2);
+        end
+      end
+    end
+  end;
 
 function TPanel.GetTextureCount(): Integer;
 begin
   Result := Length(FTextureIDs);
-  if Enabled and (FCurTexture >= 0) then
-     if (FTextureIDs[FCurTexture].Anim) and
-        (FTextureIDs[FCurTexture].AnTex <> nil) 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;
@@ -977,38 +953,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));
-  // Àíèìèðîâàíà ëè òåêóùàÿ òåêñòóðà
-  if (FCurTexture >= 0) and (FTextureIDs[FCurTexture].Anim) then
-  begin
-    assert(FTextureIDs[FCurTexture].AnTex <> nil, 'TPanel.SaveState: No animation object');
-    anim := true;
-  end
-  else
+  // Анимирована ли текущая текстура
+  anim := FCurTexture >= 0;
+  utils.writeBool(st, anim);
+  // Если да - сохраняем анимацию
+  if anim then
   begin
-    anim := false;
+    stub := TAnimState.Create(FAnimLoop, 1, 1);
+    stub.SaveState(st, FAlpha, FBlending);
+    stub.Invalidate;
   end;
-  utils.writeBool(st, anim);
-  // Åñëè äà - ñîõðàíÿåì àíèìàöèþ
-  if anim then FTextureIDs[FCurTexture].AnTex.SaveState(st);
 
   // moving platform state
   utils.writeInt(st, Integer(mMovingSpeed.X));
@@ -1032,19 +1004,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;
@@ -1053,15 +1026,14 @@ begin
   FHeight := utils.readWord(st);
   FOldW := FWidth;
   FOldH := FHeight;
-  // Àíèìèðîâàííàÿ ëè òåêóùàÿ òåêñòóðà
+  // Анимированная ли текущая текстура
   if utils.readBool(st) then
   begin
-    // Åñëè äà - çàãðóæàåì àíèìàöèþ
-    Assert((FCurTexture >= 0) and
-           (FTextureIDs[FCurTexture].Anim) and
-           (FTextureIDs[FCurTexture].AnTex <> nil),
-           'TPanel.LoadState: No animation object');
-    FTextureIDs[FCurTexture].AnTex.LoadState(st);
+    // Если да - загружаем анимацию
+    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