DEADSOFTWARE

render: move player model texture loading into render
[d2df-sdl.git] / src / game / opengl / r_playermodel.pas
index c15a713800114833cd4fe50d89af4b2705410d05..1602f23e0d2b346d9c4f10e77665ca249486657d 100644 (file)
@@ -19,15 +19,16 @@ interface
 
   uses g_playermodel; // TPlayerModel
 
-  procedure r_PlayerModel_Initialize;
-  procedure r_PlayerModel_Finalize;
+  procedure r_PlayerModel_Load;
+  procedure r_PlayerModel_Free;
   procedure r_PlayerModel_Draw (pm: TPlayerModel; X, Y: Integer; Alpha: Byte = 0);
 
 implementation
 
   uses
     SysUtils, Classes, Math,
-    MAPDEF,
+    MAPDEF, utils,
+    ImagingTypes, Imaging, ImagingUtility,
     r_graphics, g_options, r_animations, r_textures,
     g_base, g_basic, g_map, g_weapons
   ;
@@ -35,27 +36,128 @@ implementation
   const
     WeapNames: Array [WP_FIRST + 1..WP_LAST] of String = ('csaw', 'hgun', 'sg', 'ssg', 'mgun', 'rkt', 'plz', 'bfg', 'spl', 'flm');
 
+  type
+    TDirIdx = TDirection.D_LEFT..TDirection.D_RIGHT;
+    TAnimIdx = A_STAND..A_LAST;
+
   var
     WeaponID: Array [WP_FIRST + 1..WP_LAST, W_POS_NORMAL..W_POS_DOWN, W_ACT_NORMAL..W_ACT_FIRE] of DWORD;
+    Models: Array of record
+      Frames: Array [TDirIdx, TAnimIdx] of record
+        base: DWORD;
+        mask: DWORD;
+      end;
+    end;
 
-procedure r_PlayerModel_Initialize;
-var
-  a: Integer;
-begin
-  for a := WP_FIRST + 1 to WP_LAST do
+  procedure ExtAnimFromBaseAnim(MName: String; AIdx: Integer);
+    const
+      CopyAnim: array [A_LASTBASE+1..A_LASTEXT] of Integer = (
+        A_WALK, A_WALK, A_WALK, A_WALK, A_WALK,
+        A_STAND, A_WALK, A_ATTACK, A_WALK, A_SEEUP, A_SEEDOWN,
+        A_ATTACKUP, A_ATTACKDOWN
+      );
+    var
+      OIdx: Integer;
+      AName, OName: String;
+  begin
+    // HACK: shitty workaround to duplicate base animations
+    //       in place of extended, replace with something better later
+
+    Assert((AIdx > A_LASTBASE) and (AIdx <= A_LASTEXT));
+    OIdx := CopyAnim[AIdx];
+
+    AName := MName + '_RIGHTANIM' + IntToStr(AIdx);
+    OName := MName + '_RIGHTANIM' + IntToStr(OIdx);
+    Assert(g_Frames_Dup(AName, OName));
+    Assert(g_Frames_Dup(AName + '_MASK', OName + '_MASK'));
+    AName := MName + '_LEFTANIM' + IntToStr(AIdx);
+    OName := MName + '_LEFTANIM' + IntToStr(OIdx);
+    if g_Frames_Exists(AName) then
+    begin
+      g_Frames_Dup(AName, OName);
+      g_Frames_Dup(AName + '_MASK', OName + '_MASK');
+    end;
+  end;
+
+  procedure r_PlayerModel_Load;
+    var ID1, ID2: DWORD; i, a, b: Integer; prefix, aname: String;
   begin
-    g_Texture_CreateWAD(WeaponID[a][W_POS_NORMAL][W_ACT_NORMAL], GameWAD+':WEAPONS\'+UpperCase(WeapNames[a]));
-    g_Texture_CreateWAD(WeaponID[a][W_POS_NORMAL][W_ACT_FIRE], GameWAD+':WEAPONS\'+UpperCase(WeapNames[a])+'_FIRE');
-    g_Texture_CreateWAD(WeaponID[a][W_POS_UP][W_ACT_NORMAL], GameWAD+':WEAPONS\'+UpperCase(WeapNames[a])+'_UP');
-    g_Texture_CreateWAD(WeaponID[a][W_POS_UP][W_ACT_FIRE], GameWAD+':WEAPONS\'+UpperCase(WeapNames[a])+'_UP_FIRE');
-    g_Texture_CreateWAD(WeaponID[a][W_POS_DOWN][W_ACT_NORMAL], GameWAD+':WEAPONS\'+UpperCase(WeapNames[a])+'_DN');
-    g_Texture_CreateWAD(WeaponID[a][W_POS_DOWN][W_ACT_FIRE], GameWAD+':WEAPONS\'+UpperCase(WeapNames[a])+'_DN_FIRE');
+    for a := WP_FIRST + 1 to WP_LAST do
+    begin
+      g_Texture_CreateWAD(WeaponID[a][W_POS_NORMAL][W_ACT_NORMAL], GameWAD+':WEAPONS\'+UpperCase(WeapNames[a]));
+      g_Texture_CreateWAD(WeaponID[a][W_POS_NORMAL][W_ACT_FIRE], GameWAD+':WEAPONS\'+UpperCase(WeapNames[a])+'_FIRE');
+      g_Texture_CreateWAD(WeaponID[a][W_POS_UP][W_ACT_NORMAL], GameWAD+':WEAPONS\'+UpperCase(WeapNames[a])+'_UP');
+      g_Texture_CreateWAD(WeaponID[a][W_POS_UP][W_ACT_FIRE], GameWAD+':WEAPONS\'+UpperCase(WeapNames[a])+'_UP_FIRE');
+      g_Texture_CreateWAD(WeaponID[a][W_POS_DOWN][W_ACT_NORMAL], GameWAD+':WEAPONS\'+UpperCase(WeapNames[a])+'_DN');
+      g_Texture_CreateWAD(WeaponID[a][W_POS_DOWN][W_ACT_FIRE], GameWAD+':WEAPONS\'+UpperCase(WeapNames[a])+'_DN_FIRE');
+    end;
+    Models := nil;
+    if PlayerModelsArray <> nil then
+    begin
+      SetLength(Models, Length(PlayerModelsArray));
+      for i := 0 to High(PlayerModelsArray) do
+      begin
+        prefix := PlayerModelsArray[i].FileName + ':TEXTURES\';
+        for b := A_STAND to A_LAST do
+        begin
+          aname := PlayerModelsArray[i].Info.Name + '_RIGHTANIM' + IntToStr(b);
+          with PlayerModelsArray[i].Anim[TDirection.D_RIGHT, b] do
+          begin
+            if not (g_Frames_CreateWAD(@ID1, aname, prefix + Resource, 64, 64, Frames, Back) and
+                    g_Frames_CreateWAD(@ID2, aname + '_MASK', prefix + Mask, 64, 64, Frames, Back)) then
+            begin
+              if b > A_LASTBASE then
+              begin
+                ExtAnimFromBaseAnim(PlayerModelsArray[i].Info.Name, b);
+                continue
+              end
+            end;
+            Models[i].Frames[TDirection.D_RIGHT, b].base := ID1;
+            Models[i].Frames[TDirection.D_RIGHT, b].mask := ID2;
+          end;
+          with PlayerModelsArray[i].Anim[TDirection.D_LEFT, b] do
+          begin
+            if (Resource <> '') and (Mask <> '') then
+            begin
+              aname := PlayerModelsArray[i].Info.Name + '_LEFTANIM' + IntToStr(b);
+              g_Frames_CreateWAD(@ID1, aname, prefix + Resource, 64, 64, Frames, Back);
+              g_Frames_CreateWAD(@ID2, aname + '_MASK', prefix + Mask, 64, 64, Frames, Back);
+              Models[i].Frames[TDirection.D_LEFT, b].base := ID1;
+              Models[i].Frames[TDirection.D_LEFT, b].mask := ID2;
+            end
+          end
+        end
+      end
+    end
   end;
-end;
 
-  procedure r_PlayerModel_Finalize;
-    var a, b, c: Integer;
+  procedure r_PlayerModel_Free;
+    var i, a, b, c: Integer;
   begin
+    if PlayerModelsArray = nil then Exit;
+    for i := 0 to High(PlayerModelsArray) do
+    begin
+      with PlayerModelsArray[i] do
+      begin
+        for a := A_STAND to A_LAST do
+        begin
+          g_Frames_DeleteByName(Info.Name+'_LEFTANIM'+IntToStr(a));
+          g_Frames_DeleteByName(Info.Name+'_LEFTANIM'+IntToStr(a)+'_MASK');
+          g_Frames_DeleteByName(Info.Name+'_RIGHTANIM'+IntToStr(a));
+          g_Frames_DeleteByName(Info.Name+'_RIGHTANIM'+IntToStr(a)+'_MASK');
+        end;
+        if Gibs <> nil then
+        begin
+          for a := 0 to High(Gibs) do
+          begin
+            e_DeleteTexture(Gibs[a].ID);
+            e_DeleteTexture(Gibs[a].MaskID);
+            Gibs[a].ID := DWORD(-1);
+            Gibs[a].MaskID := DWORD(-1);
+          end
+        end
+      end
+    end;
     for a := WP_FIRST + 1 to WP_LAST do
       for b := W_POS_NORMAL to W_POS_DOWN do
         for c := W_ACT_NORMAL to W_ACT_FIRE do
@@ -67,6 +169,7 @@ var
   Mirror: TMirrorType;
   pos, act: Byte;
   p: TDFPoint;
+  FramesID: DWORD;
 begin
 // Флаги:
   if pm.Direction = TDirection.D_LEFT then
@@ -90,7 +193,7 @@ begin
   else
     Mirror := TMirrorType.Horizontal;
 
-  if pm.DrawWeapon and (not (pm.CurrentAnimation in [A_DIE1, A_DIE2, A_PAIN])) and  (pm.CurrentWeapon in [WP_FIRST + 1..WP_LAST]) then
+  if PlayerModelsArray[pm.id].Info.HaveWeapon and (not (pm.CurrentAnimation in [A_DIE1, A_DIE2, A_PAIN])) and  (pm.CurrentWeapon in [WP_FIRST + 1..WP_LAST]) then
   begin
     if pm.CurrentAnimation in [A_SEEUP, A_ATTACKUP] then
       pos := W_POS_UP
@@ -106,38 +209,45 @@ begin
       act := W_ACT_NORMAL;
 
     if Alpha < 201 then
-      e_Draw(WeaponID[pm.CurrentWeapon][pos][act],
-             X + pm.WeaponPoints[pm.CurrentWeapon, pm.CurrentAnimation, pm.Direction,
-             pm.Anim[TDirection.D_RIGHT][pm.CurrentAnimation].CurrentFrame].X,
-             Y + pm.WeaponPoints[pm.CurrentWeapon, pm.CurrentAnimation, pm.Direction,
-             pm.Anim[TDirection.D_RIGHT][pm.CurrentAnimation].CurrentFrame].Y,
-             0, True, False, Mirror);
+      e_Draw(
+        WeaponID[pm.CurrentWeapon][pos][act],
+        X + PlayerModelsArray[pm.id].WeaponPoints[pm.CurrentWeapon, pm.CurrentAnimation, pm.Direction, pm.AnimState.CurrentFrame].X,
+        Y + PlayerModelsArray[pm.id].WeaponPoints[pm.CurrentWeapon, pm.CurrentAnimation, pm.Direction, pm.AnimState.CurrentFrame].Y,
+        0,
+        True,
+        False,
+        Mirror
+      );
   end;
 
 // Модель:
-  if (pm.Direction = TDirection.D_LEFT) and (pm.Anim[TDirection.D_LEFT][pm.CurrentAnimation] <> nil) then
+  if (pm.Direction = TDirection.D_LEFT) and (Models[pm.id].Frames[TDirection.D_LEFT, pm.CurrentAnimation].base <> 0) then
   begin
-    pm.Anim[TDirection.D_LEFT][pm.CurrentAnimation].Alpha := Alpha;
-    r_Animation_Draw(pm.Anim[TDirection.D_LEFT][pm.CurrentAnimation], X, Y, TMirrorType.None);
+    pm.AnimState.Alpha := Alpha; // !!!
+    FramesID := Models[pm.id].Frames[TDirection.D_LEFT, pm.CurrentAnimation].base;
+    r_AnimationState_Draw(FramesID, pm.AnimState, X, Y, TMirrorType.None);
   end
   else
   begin
-    pm.Anim[TDirection.D_RIGHT][pm.CurrentAnimation].Alpha := Alpha;
-    r_Animation_Draw(pm.Anim[TDirection.D_RIGHT][pm.CurrentAnimation], X, Y, Mirror);
+    pm.AnimState.Alpha := Alpha; // !!!
+    FramesID := Models[pm.id].Frames[TDirection.D_RIGHT, pm.CurrentAnimation].base;
+    r_AnimationState_Draw(FramesID, pm.AnimState, X, Y, Mirror);
   end;
 
 // Маска модели:
   e_Colors := pm.Color;
 
-  if (pm.Direction = TDirection.D_LEFT) and (pm.MaskAnim[TDirection.D_LEFT][pm.CurrentAnimation] <> nil) then
+  if (pm.Direction = TDirection.D_LEFT) and (Models[pm.id].Frames[TDirection.D_LEFT, pm.CurrentAnimation].mask <> 0) then
   begin
-    pm.MaskAnim[TDirection.D_LEFT][pm.CurrentAnimation].Alpha := Alpha;
-    r_Animation_Draw(pm.MaskAnim[TDirection.D_LEFT][pm.CurrentAnimation], X, Y, TMirrorType.None);
+    pm.AnimState.Alpha := Alpha; // !!!
+    FramesID := Models[pm.id].Frames[TDirection.D_LEFT, pm.CurrentAnimation].mask;
+    r_AnimationState_Draw(FramesID, pm.AnimState, X, Y, TMirrorType.None);
   end
   else
   begin
-    pm.MaskAnim[TDirection.D_RIGHT][pm.CurrentAnimation].Alpha := Alpha;
-    r_Animation_Draw(pm.MaskAnim[TDirection.D_RIGHT][pm.CurrentAnimation], X, Y, Mirror);
+    pm.AnimState.Alpha := Alpha; // !!!
+    FramesID := Models[pm.id].Frames[TDirection.D_RIGHT, pm.CurrentAnimation].mask;
+    r_AnimationState_Draw(FramesID, pm.AnimState, X, Y, Mirror);
   end;
 
   e_Colors.R := 255;