From 36fb40708726d6a0659f332a09c4c371473d0394 Mon Sep 17 00:00:00 2001 From: DeaDDooMER Date: Tue, 8 Jun 2021 10:20:05 +0300 Subject: [PATCH] render: separate player model logic and drawing --- src/game/Doom2DF.lpr | 1 + src/game/g_game.pas | 7 +- src/game/g_gui.pas | 5 +- src/game/g_playermodel.pas | 153 +++++------------------------- src/game/opengl/r_player.pas | 11 ++- src/game/opengl/r_playermodel.pas | 148 +++++++++++++++++++++++++++++ 6 files changed, 188 insertions(+), 137 deletions(-) create mode 100644 src/game/opengl/r_playermodel.pas diff --git a/src/game/Doom2DF.lpr b/src/game/Doom2DF.lpr index 660fcfc..a83b3cb 100644 --- a/src/game/Doom2DF.lpr +++ b/src/game/Doom2DF.lpr @@ -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} diff --git a/src/game/g_game.pas b/src/game/g_game.pas index e505f8b..d19ceb6 100644 --- a/src/game/g_game.pas +++ b/src/game/g_game.pas @@ -443,7 +443,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; // ////////////////////////////////////////////////////////////////////////// // @@ -1128,7 +1128,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 @@ -2285,6 +2285,7 @@ begin g_Game_StopAllSounds(True); gMusic.Free(); g_Game_FreeData(); + r_PlayerModel_Finalize; g_PlayerModel_FreeData(); g_Texture_DeleteAll(); g_Frames_DeleteAll(); @@ -6471,4 +6472,4 @@ begin conRegVar('r_showspect', @gSpectHUD, 'show spectator hud', 'show spectator hud'); conRegVar('r_showstat', @gShowStat, 'show stats', 'show stats'); conRegVar('r_showpids', @gShowPIDs, 'show PIDs', 'show PIDs'); -end. \ No newline at end of file +end. diff --git a/src/game/g_gui.pas b/src/game/g_gui.pas index 3181e69..7329f52 100644 --- a/src/game/g_gui.pas +++ b/src/game/g_gui.pas @@ -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_game, Math, StrUtils, g_player, g_options, r_playermodel, g_map, g_weapons, xdynrec, wadreader; @@ -2694,7 +2694,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(); diff --git a/src/game/g_playermodel.pas b/src/game/g_playermodel.pas index 6ffea1f..f91620e 100644 --- a/src/game/g_playermodel.pas +++ b/src/game/g_playermodel.pas @@ -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 diff --git a/src/game/opengl/r_player.pas b/src/game/opengl/r_player.pas index b9fae84..25a2dd7 100644 --- a/src/game/opengl/r_player.pas +++ b/src/game/opengl/r_player.pas @@ -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 index 0000000..a9447d5 --- /dev/null +++ b/src/game/opengl/r_playermodel.pas @@ -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 . + *) +{$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. -- 2.29.2