X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Fg_playermodel.pas;h=b2f57e6c95997ff2835acc80f58380b4ec6827ca;hb=d0936017ccb8a078d1b03f55478af284bb015bbc;hp=ebb3915efedfbc09ab7379729f7fa9bcd4dcfd78;hpb=56ec1dee6d63a32353f94eac7e87d6a42b801a25;p=d2df-sdl.git diff --git a/src/game/g_playermodel.pas b/src/game/g_playermodel.pas index ebb3915..b2f57e6 100644 --- a/src/game/g_playermodel.pas +++ b/src/game/g_playermodel.pas @@ -1,9 +1,8 @@ -(* Copyright (C) DooM 2D:Forever Developers +(* 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, either version 3 of the License, or - * (at your option) any later version. + * 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 @@ -20,8 +19,8 @@ unit g_playermodel; interface uses - {$IFDEF USE_MEMPOOL}mempool,{$ENDIF} - MAPDEF, g_textures, g_basic, g_weapons, e_graphics, utils; + MAPDEF, g_textures, g_base, g_basic, g_weapons, r_graphics, utils, g_gfx, + ImagingTypes, Imaging, ImagingUtility; const A_STAND = 0; @@ -56,6 +55,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; @@ -64,6 +72,10 @@ type HaveWeapon: Boolean; end; + TModelBlood = record + R, G, B, Kind: Byte; + end; + TModelSound = record ID: DWORD; Level: Byte; @@ -81,15 +93,17 @@ 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 FName: String; FDirection: TDirection; 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; @@ -114,7 +128,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; @@ -125,13 +138,27 @@ 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; function g_PlayerModel_GetInfo(ModelName: String): TModelInfo; +function g_PlayerModel_GetBlood(ModelName: String): TModelBlood; function g_PlayerModel_Get(ModelName: String): TPlayerModel; function g_PlayerModel_GetAnim(ModelName: String; Anim: Byte; var _Anim, _Mask: TAnimation): Boolean; function g_PlayerModel_GetGibs(ModelName: String; var Gibs: TGibsArray): Boolean; @@ -140,8 +167,8 @@ function g_PlayerModel_GetGibs(ModelName: String; var Gibs: TGibsArray): Boolea implementation uses - g_main, g_sound, g_console, SysUtils, g_player, CONFIG, - GL, GLExt, e_sound, g_options, g_map, Math, e_log, wadreader; + g_sound, g_console, SysUtils, g_player, CONFIG, + e_sound, g_options, g_map, Math, e_log, wadreader; type TPlayerModelInfo = record @@ -154,17 +181,10 @@ type PainSounds: TModelSoundArray; DieSounds: TModelSoundArray; SlopSound: Byte; + Blood: TModelBlood; 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 = @@ -184,26 +204,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; @@ -317,6 +319,65 @@ begin end; end; +function g_PlayerModel_CalcGibSize (pData: Pointer; dataSize, x, y, w, h: Integer): TRectWH; + var i, j: Integer; done: Boolean; img: TImageData; + + function IsVoid (i, j: Integer): Boolean; + begin + result := Byte((PByte(img.bits) + (y+j)*img.width*4 + (x+i)*4 + 3)^) = 0 + end; + +begin + InitImage(img); + assert(LoadImageFromMemory(pData, dataSize, img)); + + (* trace x from right to left *) + done := false; i := 0; + while not done and (i < w) do + begin + j := 0; + while (j < h) and IsVoid(i, j) do inc(j); + done := (j < h) and (IsVoid(i, j) = false); + result.x := i; + inc(i); + end; + + (* trace y from up to down *) + done := false; j := 0; + while not done and (j < h) do + begin + i := 0; + while (i < w) and IsVoid(i, j) do inc(i); + done := (i < w) and (IsVoid(i, j) = false); + result.y := j; + inc(j); + end; + + (* trace x from right to left *) + done := false; i := w - 1; + while not done and (i >= 0) do + begin + j := 0; + while (j < h) and IsVoid(i, j) do inc(j); + done := (j < h) and (IsVoid(i, j) = false); + result.width := i - result.x + 1; + dec(i); + end; + + (* trace y from down to up *) + done := false; j := h - 1; + while not done and (j >= 0) do + begin + i := 0; + while (i < w) and IsVoid(i, j) do inc(i); + done := (i < w) and (IsVoid(i, j) = false); + result.height := j - result.y + 1; + dec(j); + end; + + FreeImage(img); +end; + function g_PlayerModel_Load(FileName: string): Boolean; var ID: DWORD; @@ -329,7 +390,7 @@ var prefix: string; ok, chk: Boolean; begin - e_WriteLog(Format('Loading player model: %s', [ExtractFileName(FileName)]), TMsgType.Notify); + e_WriteLog(Format('Loading player model "%s"...', [FileName]), TMsgType.Notify); Result := False; @@ -371,6 +432,20 @@ begin Description := config.ReadStr('Model', 'description', ''); end; + with PlayerModelsArray[ID] do + begin + Blood.R := MAX(0, MIN(255, config.ReadInt('Blood', 'R', 150))); + Blood.G := MAX(0, MIN(255, config.ReadInt('Blood', 'G', 0))); + Blood.B := MAX(0, MIN(255, config.ReadInt('Blood', 'B', 0))); + case config.ReadStr('Blood', 'Kind', 'NORMAL') of + 'NORMAL': Blood.Kind := BLOOD_NORMAL; + 'SPARKS': Blood.Kind := BLOOD_CSPARKS; + 'COMBINE': Blood.Kind := BLOOD_COMBINE; + else + Blood.Kind := BLOOD_NORMAL + end + end; + for b := A_STAND to A_LAST do begin aname := s+'_RIGHTANIM'+IntToStr(b); @@ -465,7 +540,8 @@ begin if e_CreateTextureMemEx(pData, lenpd, Gibs[a].ID, a*32, 0, 32, 32) and e_CreateTextureMemEx(pData2, lenpd2, Gibs[a].MaskID, a*32, 0, 32, 32) then begin - Gibs[a].Rect := e_GetTextureSize2(Gibs[a].ID); + //Gibs[a].Rect := e_GetTextureSize2(Gibs[a].ID); + Gibs[a].Rect := g_PlayerModel_CalcGibSize(pData, lenpd, a*32, 0, 32, 32); with Gibs[a].Rect do if Height > 3 then Height := Height-1-Random(2); Gibs[a].OnlyOne := config.ReadInt('Gibs', 'once', -1) = a+1; @@ -581,6 +657,7 @@ begin with PlayerModelsArray[a] do begin Result.FName := Info.Name; + Result.FBlood := Blood; for b := A_STAND to A_LAST do begin @@ -723,16 +800,29 @@ begin end; end; +function g_PlayerModel_GetBlood(ModelName: string): TModelBlood; +var + a: Integer; +begin + Result.R := 150; + Result.G := 0; + Result.B := 0; + Result.Kind := BLOOD_NORMAL; + if PlayerModelsArray = nil then Exit; + + for a := 0 to High(PlayerModelsArray) do + if PlayerModelsArray[a].Info.Name = ModelName then + begin + Result := PlayerModelsArray[a].Blood; + Break; + end; +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; @@ -804,97 +894,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