DEADSOFTWARE

render: separate player model logic and drawing
authorDeaDDooMER <deaddoomer@deadsoftware.ru>
Tue, 8 Jun 2021 07:20:05 +0000 (10:20 +0300)
committerDeaDDooMER <deaddoomer@deadsoftware.ru>
Fri, 9 Jun 2023 07:42:16 +0000 (10:42 +0300)
src/game/Doom2DF.lpr
src/game/g_game.pas
src/game/g_gui.pas
src/game/g_playermodel.pas
src/game/opengl/r_player.pas
src/game/opengl/r_playermodel.pas [new file with mode: 0644]

index 5e81dcd199cfd14f9a23f2c88c4cb0b5b1f58450..b02f8f96e0173079b99bca9cb14ca3085a2ff5e3 100644 (file)
@@ -162,6 +162,7 @@ uses
   r_netmaster in 'opengl/r_netmaster.pas',
   r_panel in 'opengl/r_panel.pas',
   r_player in 'opengl/r_player.pas',
+  r_playermodel in 'opengl/r_playermodel.pas',
   r_weapons in 'opengl/r_weapons.pas',
 
 {$IFDEF USE_FMOD}
index 9226201986178582c9a617bc8e8889d065848d23..62628e7ce7b34a010a3c60fc5ff4020bfd3d0fc1 100644 (file)
@@ -452,7 +452,7 @@ uses
   g_triggers, g_monsters, e_sound, CONFIG,
   g_language, g_net, g_main, g_phys,
   ENet, e_msg, g_netmsg, g_netmaster,
-  sfs, wadreader, g_system;
+  sfs, wadreader, g_system, r_playermodel;
 
 
 // ////////////////////////////////////////////////////////////////////////// //
@@ -1149,7 +1149,7 @@ begin
     g_Console_Init();
 
     g_Game_SetLoadingText(_lc[I_LOAD_MODELS], 0, False);
-    g_PlayerModel_LoadData();
+    r_PlayerModel_Initialize;
 
     // load models from all possible wad types, in all known directories
     // this does a loosy job (linear search, ooph!), but meh
@@ -2329,6 +2329,7 @@ begin
   g_Game_StopAllSounds(True);
   gMusic.Free();
   g_Game_FreeData();
+  r_PlayerModel_Finalize;
   g_PlayerModel_FreeData();
   g_Texture_DeleteAll();
   g_Frames_DeleteAll();
index 2200703437db6be9fc693d2bdfbd83dc76a55b31..fb461784f5468c4b9b2447229a21d7515b26071d 100644 (file)
@@ -552,7 +552,7 @@ implementation
 uses
   {$INCLUDE ../nogl/noGLuses.inc}
   g_textures, g_sound, SysUtils, e_res,
-  g_game, Math, StrUtils, g_player, g_options, g_console,
+  g_game, Math, StrUtils, g_player, g_options, g_console, r_playermodel,
   g_map, g_weapons, xdynrec, wadreader;
 
 
@@ -2656,7 +2656,8 @@ begin
 
   DrawBox(FX, FY, 4, 4);
 
-  if FModel <> nil then FModel.Draw(FX+4, FY+4);
+  if FModel <> nil then
+    r_PlayerModel_Draw(FModel, FX+4, FY+4);
 end;
 
 procedure TGUIModelView.NextAnim();
index 6ffea1fbc3fc094fb714fb25df4ef20623235c4a..f91620eac842e0b6a9d1c4a9857015fad79f27f1 100644 (file)
@@ -56,6 +56,15 @@ const
   MODELSOUND_PAIN = 0;
   MODELSOUND_DIE  = 1;
 
+  W_POS_NORMAL = 0;
+  W_POS_UP     = 1;
+  W_POS_DOWN   = 2;
+
+  W_ACT_NORMAL = 0;
+  W_ACT_FIRE   = 1;
+
+  FLAG_BASEPOINT: TDFPoint = (X:16; Y:43);
+
 type
   TModelInfo = record
     Name:        String;
@@ -85,6 +94,7 @@ type
   TWeaponPoints = Array [WP_FIRST + 1..WP_LAST] of
                   Array [A_STAND..A_LAST] of
                   Array [TDirection.D_LEFT..TDirection.D_RIGHT] of Array of TDFPoint;
+  TModelMatrix = Array [TDirection.D_LEFT..TDirection.D_RIGHT] of Array [A_STAND..A_LAST] of TAnimation;
 
   TPlayerModel = class{$IFDEF USE_MEMPOOL}(TPoolObject){$ENDIF}
   private
@@ -93,8 +103,8 @@ type
     FColor:            TRGB;
     FBlood:            TModelBlood;
     FCurrentAnimation: Byte;
-    FAnim:             Array [TDirection.D_LEFT..TDirection.D_RIGHT] of Array [A_STAND..A_LAST] of TAnimation;
-    FMaskAnim:         Array [TDirection.D_LEFT..TDirection.D_RIGHT] of Array [A_STAND..A_LAST] of TAnimation;
+    FAnim:             TModelMatrix;
+    FMaskAnim:         TModelMatrix;
     FWeaponPoints:     TWeaponPoints;
     FPainSounds:       TModelSoundArray;
     FDieSounds:        TModelSoundArray;
@@ -119,7 +129,6 @@ type
     procedure   SetFire(Fire: Boolean);
     function    PlaySound(SoundType, Level: Byte; X, Y: Integer): Boolean;
     procedure   Update();
-    procedure   Draw(X, Y: Integer; Alpha: Byte = 0);
 
   published
     property    Fire: Boolean read FFire;
@@ -131,9 +140,21 @@ type
   public
     property    Color: TRGB read FColor write FColor;
     property    Blood: TModelBlood read FBlood;
+
+    property    Anim: TModelMatrix read FAnim;
+    property    MaskAnim: TModelMatrix read FMaskAnim;
+    property    CurrentAnimation: Byte read FCurrentAnimation;
+
+    property    CurrentWeapon: Byte read FCurrentWeapon;
+    property    DrawWeapon: Boolean read FDrawWeapon;
+    property    WeaponPoints: TWeaponPoints read FWeaponPoints;
+
+    property    Flag: Byte read FFlag;
+    property    FlagAnim: TAnimation read FFlagAnim;
+    property    FlagAngle: SmallInt read FFlagAngle;
+    property    FlagPoint: TDFPoint read FFlagPoint;
   end;
 
-procedure g_PlayerModel_LoadData();
 procedure g_PlayerModel_FreeData();
 function  g_PlayerModel_Load(FileName: String): Boolean;
 function  g_PlayerModel_GetNames(): SSArray;
@@ -166,14 +187,6 @@ type
   end;
 
 const
-  W_POS_NORMAL = 0;
-  W_POS_UP     = 1;
-  W_POS_DOWN   = 2;
-
-  W_ACT_NORMAL = 0;
-  W_ACT_FIRE   = 1;
-
-  FLAG_BASEPOINT: TDFPoint = (X:16; Y:43);
   FLAG_DEFPOINT:  TDFPoint = (X:32; Y:16);
   FLAG_DEFANGLE = -20;
   WEAPONBASE: Array [WP_FIRST + 1..WP_LAST] of TDFPoint =
@@ -193,26 +206,8 @@ const
              ('csaw', 'hgun', 'sg', 'ssg', 'mgun', 'rkt', 'plz', 'bfg', 'spl', 'flm');
 
 var
-  WeaponID: Array [WP_FIRST + 1..WP_LAST] of
-            Array [W_POS_NORMAL..W_POS_DOWN] of
-            Array [W_ACT_NORMAL..W_ACT_FIRE] of DWORD;
   PlayerModelsArray: Array of TPlayerModelInfo;
 
-procedure g_PlayerModel_LoadData();
-var
-  a: Integer;
-begin
-  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;
-end;
-
 function GetPoint(var str: String; var point: TDFPoint): Boolean;
 var
   a, x, y: Integer;
@@ -828,13 +823,8 @@ end;
 procedure g_PlayerModel_FreeData();
 var
   i: DWORD;
-  a, b, c: Integer;
+  a, b: Integer;
 begin
-  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
-        e_DeleteTexture(WeaponID[a][b][c]);
-
   e_WriteLog('Releasing models...', TMsgType.Notify);
 
   if PlayerModelsArray = nil then Exit;
@@ -906,97 +896,6 @@ begin
   inherited;
 end;
 
-procedure TPlayerModel.Draw(X, Y: Integer; Alpha: Byte = 0);
-var
-  Mirror: TMirrorType;
-  pos, act: Byte;
-  p: TDFPoint;
-begin
-// Ôëàãè:
-  if Direction = TDirection.D_LEFT then
-    Mirror := TMirrorType.None
-  else
-    Mirror := TMirrorType.Horizontal;
-
-  if (FFlag <> FLAG_NONE) and (FFlagAnim <> nil) and
-     (not (FCurrentAnimation in [A_DIE1, A_DIE2])) then
-  begin
-    p.X := IfThen(Direction = TDirection.D_LEFT,
-                  FLAG_BASEPOINT.X,
-                  64-FLAG_BASEPOINT.X);
-    p.Y := FLAG_BASEPOINT.Y;
-
-    FFlagAnim.DrawEx(X+IfThen(Direction = TDirection.D_LEFT, FFlagPoint.X-1, 2*FLAG_BASEPOINT.X-FFlagPoint.X+1)-FLAG_BASEPOINT.X,
-                     Y+FFlagPoint.Y-FLAG_BASEPOINT.Y+1, Mirror, p,
-                     IfThen(FDirection = TDirection.D_RIGHT, FFlagAngle, -FFlagAngle));
-  end;
-
-// Îðóæèå:
-  if Direction = TDirection.D_RIGHT then
-    Mirror := TMirrorType.None
-  else
-    Mirror := TMirrorType.Horizontal;
-
-  if FDrawWeapon and
-    (not (FCurrentAnimation in [A_DIE1, A_DIE2, A_PAIN])) and
-    (FCurrentWeapon in [WP_FIRST + 1..WP_LAST]) then
-  begin
-    if FCurrentAnimation in [A_SEEUP, A_ATTACKUP] then
-      pos := W_POS_UP
-    else
-      if FCurrentAnimation in [A_SEEDOWN, A_ATTACKDOWN] then
-        pos := W_POS_DOWN
-      else
-        pos := W_POS_NORMAL;
-
-    if (FCurrentAnimation in [A_ATTACK, A_ATTACKUP, A_ATTACKDOWN]) or
-       FFire then
-      act := W_ACT_FIRE
-    else
-      act := W_ACT_NORMAL;
-
-    if Alpha < 201 then
-      e_Draw(WeaponID[FCurrentWeapon][pos][act],
-             X+FWeaponPoints[FCurrentWeapon, FCurrentAnimation, FDirection,
-                             FAnim[TDirection.D_RIGHT][FCurrentAnimation].CurrentFrame].X,
-             Y+FWeaponPoints[FCurrentWeapon, FCurrentAnimation, FDirection,
-                             FAnim[TDirection.D_RIGHT][FCurrentAnimation].CurrentFrame].Y,
-             0, True, False, Mirror);
-  end;
-
-// Ìîäåëü:
-  if (FDirection = TDirection.D_LEFT) and
-     (FAnim[TDirection.D_LEFT][FCurrentAnimation] <> nil) then
-  begin
-    FAnim[TDirection.D_LEFT][FCurrentAnimation].Alpha := Alpha;
-    FAnim[TDirection.D_LEFT][FCurrentAnimation].Draw(X, Y, TMirrorType.None);
-  end
-  else
-  begin
-    FAnim[TDirection.D_RIGHT][FCurrentAnimation].Alpha := Alpha;
-    FAnim[TDirection.D_RIGHT][FCurrentAnimation].Draw(X, Y, Mirror);
-  end;
-
-// Ìàñêà ìîäåëè:
-  e_Colors := FColor;
-
-  if (FDirection = TDirection.D_LEFT) and
-     (FMaskAnim[TDirection.D_LEFT][FCurrentAnimation] <> nil) then
-  begin
-    FMaskAnim[TDirection.D_LEFT][FCurrentAnimation].Alpha := Alpha;
-    FMaskAnim[TDirection.D_LEFT][FCurrentAnimation].Draw(X, Y, TMirrorType.None);
-  end
-  else
-  begin
-    FMaskAnim[TDirection.D_RIGHT][FCurrentAnimation].Alpha := Alpha;
-    FMaskAnim[TDirection.D_RIGHT][FCurrentAnimation].Draw(X, Y, Mirror);
-  end;
-
-  e_Colors.R := 255;
-  e_Colors.G := 255;
-  e_Colors.B := 255;
-end;
-
 function TPlayerModel.GetCurrentAnimation: TAnimation;
 begin
   if (FDirection = TDirection.D_LEFT) and (FAnim[TDirection.D_LEFT][FCurrentAnimation] <> nil) then
index c054d06e5739f91ed50b37ba2e7d2bf7449245a7..0f6ec3531a96236f82f798e91e2e4db0417f5785 100644 (file)
@@ -42,7 +42,8 @@ implementation
   uses
     SysUtils, Classes, Math,
     MAPDEF, utils,
-    g_basic, g_game, g_phys, g_map, g_textures, g_menu, g_language, g_weapons, g_items, g_net, g_options
+    g_basic, g_game, g_phys, g_map, g_textures, g_menu, g_language, g_weapons, g_items, g_net, g_options,
+    r_playermodel
   ;
 
   procedure r_Player_DrawAll;
@@ -357,15 +358,15 @@ begin
         else
           dr := True;
         if dr then
-          p.Model.Draw(fX, fY + fSlope, 200)
+          r_PlayerModel_Draw(p.Model, fX, fY + fSlope, 200)
         else
-          p.Model.Draw(fX, fY + fSlope);
+          r_PlayerModel_Draw(p.Model, fX, fY + fSlope);
       end
       else
-        p.Model.Draw(fX, fY + fSlope, 254);
+        r_PlayerModel_Draw(p.Model, fX, fY + fSlope, 254);
     end
     else
-      p.Model.Draw(fX, fY + fSlope);
+      r_PlayerModel_Draw(p.Model, fX, fY + fSlope);
   end;
 
   if g_debug_Frames then
diff --git a/src/game/opengl/r_playermodel.pas b/src/game/opengl/r_playermodel.pas
new file mode 100644 (file)
index 0000000..a9447d5
--- /dev/null
@@ -0,0 +1,148 @@
+(* Copyright (C)  Doom 2D: Forever Developers
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License ONLY.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *)
+{$INCLUDE ../../shared/a_modes.inc}
+unit r_playermodel;
+
+interface
+
+  uses g_playermodel; // TPlayerModel
+
+  procedure r_PlayerModel_Initialize;
+  procedure r_PlayerModel_Finalize;
+  procedure r_PlayerModel_Draw (pm: TPlayerModel; X, Y: Integer; Alpha: Byte = 0);
+
+implementation
+
+  uses
+    SysUtils, Classes, Math,
+    MAPDEF,
+    e_graphics,
+    g_basic, g_map, g_weapons, g_textures, g_main
+  ;
+
+  const
+    WeapNames: Array [WP_FIRST + 1..WP_LAST] of String = ('csaw', 'hgun', 'sg', 'ssg', 'mgun', 'rkt', 'plz', 'bfg', 'spl', 'flm');
+
+  var
+    WeaponID: Array [WP_FIRST + 1..WP_LAST, W_POS_NORMAL..W_POS_DOWN, W_ACT_NORMAL..W_ACT_FIRE] of DWORD;
+
+procedure r_PlayerModel_Initialize;
+var
+  a: Integer;
+begin
+  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;
+end;
+
+  procedure r_PlayerModel_Finalize;
+    var a, b, c: Integer;
+  begin
+    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
+          e_DeleteTexture(WeaponID[a][b][c])
+  end;
+
+procedure r_PlayerModel_Draw (pm: TPlayerModel; X, Y: Integer; Alpha: Byte = 0);
+var
+  Mirror: TMirrorType;
+  pos, act: Byte;
+  p: TDFPoint;
+begin
+// Флаги:
+  if pm.Direction = TDirection.D_LEFT then
+    Mirror := TMirrorType.None
+  else
+    Mirror := TMirrorType.Horizontal;
+
+  if (pm.Flag <> FLAG_NONE) and (pm.FlagAnim <> nil) and (not (pm.CurrentAnimation in [A_DIE1, A_DIE2])) then
+  begin
+    p.X := IfThen(pm.Direction = TDirection.D_LEFT, FLAG_BASEPOINT.X, 64 - FLAG_BASEPOINT.X);
+    p.Y := FLAG_BASEPOINT.Y;
+
+    pm.FlagAnim.DrawEx(X+IfThen(pm.Direction = TDirection.D_LEFT, pm.FlagPoint.X-1, 2*FLAG_BASEPOINT.X-pm.FlagPoint.X+1)-FLAG_BASEPOINT.X,
+                     Y+pm.FlagPoint.Y-FLAG_BASEPOINT.Y+1, Mirror, p,
+                     IfThen(pm.Direction = TDirection.D_RIGHT, pm.FlagAngle, -pm.FlagAngle));
+  end;
+
+// Оружие:
+  if pm.Direction = TDirection.D_RIGHT then
+    Mirror := TMirrorType.None
+  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
+  begin
+    if pm.CurrentAnimation in [A_SEEUP, A_ATTACKUP] then
+      pos := W_POS_UP
+    else
+      if pm.CurrentAnimation in [A_SEEDOWN, A_ATTACKDOWN] then
+        pos := W_POS_DOWN
+      else
+        pos := W_POS_NORMAL;
+
+    if (pm.CurrentAnimation in [A_ATTACK, A_ATTACKUP, A_ATTACKDOWN]) or pm.Fire then
+      act := W_ACT_FIRE
+    else
+      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);
+  end;
+
+// Модель:
+  if (pm.Direction = TDirection.D_LEFT) and (pm.Anim[TDirection.D_LEFT][pm.CurrentAnimation] <> nil) then
+  begin
+    pm.Anim[TDirection.D_LEFT][pm.CurrentAnimation].Alpha := Alpha;
+    pm.Anim[TDirection.D_LEFT][pm.CurrentAnimation].Draw(X, Y, TMirrorType.None);
+  end
+  else
+  begin
+    pm.Anim[TDirection.D_RIGHT][pm.CurrentAnimation].Alpha := Alpha;
+    pm.Anim[TDirection.D_RIGHT][pm.CurrentAnimation].Draw(X, Y, Mirror);
+  end;
+
+// Маска модели:
+  e_Colors := pm.Color;
+
+  if (pm.Direction = TDirection.D_LEFT) and (pm.MaskAnim[TDirection.D_LEFT][pm.CurrentAnimation] <> nil) then
+  begin
+    pm.MaskAnim[TDirection.D_LEFT][pm.CurrentAnimation].Alpha := Alpha;
+    pm.MaskAnim[TDirection.D_LEFT][pm.CurrentAnimation].Draw(X, Y, TMirrorType.None);
+  end
+  else
+  begin
+    pm.MaskAnim[TDirection.D_RIGHT][pm.CurrentAnimation].Alpha := Alpha;
+    pm.MaskAnim[TDirection.D_RIGHT][pm.CurrentAnimation].Draw(X, Y, Mirror);
+  end;
+
+  e_Colors.R := 255;
+  e_Colors.G := 255;
+  e_Colors.B := 255;
+end;
+
+end.