X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Fopengl%2Fr_playermodel.pas;h=c4fe391680359245ceb2fa49000a899ed6e60774;hb=f517a19e84dae6941cff317aaf6fbcc3a5c5bb6f;hp=9b0f244eed5d4ea446a524f161f5b1386125f1a4;hpb=c5684c0c980bb96fd4fd0efae4d48cdeb469c8ff;p=d2df-sdl.git diff --git a/src/game/opengl/r_playermodel.pas b/src/game/opengl/r_playermodel.pas index 9b0f244..c4fe391 100644 --- a/src/game/opengl/r_playermodel.pas +++ b/src/game/opengl/r_playermodel.pas @@ -17,56 +17,287 @@ unit r_playermodel; interface - uses g_playermodel; // TPlayerModel + uses g_playermodel, g_base; // TPlayerModel, TRectWH procedure r_PlayerModel_Initialize; procedure r_PlayerModel_Finalize; + procedure r_PlayerModel_Load; + procedure r_PlayerModel_Free; + procedure r_PlayerModel_Update; procedure r_PlayerModel_Draw (pm: TPlayerModel; X, Y: Integer; Alpha: Byte = 0); + procedure r_PlayerModel_DrawGibs; + + function r_PlayerModel_GetGibRect (m, id: Integer): TRectWH; implementation uses SysUtils, Classes, Math, - MAPDEF, - r_graphics, - g_base, g_basic, g_map, g_weapons, g_textures, g_main + MAPDEF, utils, e_log, wadreader, + ImagingTypes, Imaging, ImagingUtility, + r_graphics, g_options, r_animations, r_textures, + g_basic, g_map, g_weapons, g_textures, g_player, g_phys, g_game ; 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; + Gibs: Array of record + base: DWORD; + mask: DWORD; + rect: TRectWH; + end; + end; + RedFlagFrames: DWORD; + BlueFlagFrames: DWORD; + FlagAnimState: TAnimationState; -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'); + function r_PlayerModel_GetGibRect (m, id: Integer): TRectWH; + begin + Result := Models[m].Gibs[id].rect + end; + + procedure r_PlayerModel_Initialize; + begin + FlagAnimState := TAnimationState.Create(True, 8, 5); end; -end; procedure r_PlayerModel_Finalize; - var a, b, c: Integer; begin + FlagAnimState.Free; + FlagAnimState := nil; + end; + + 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_LoadResource (resource: AnsiString; var pData: Pointer; var len: Integer); + var WAD: TWADFile; + begin + pData := nil; + len := 0; + WAD := TWADFile.Create; + WAD.ReadFile(g_ExtractWadName(resource)); + WAD.GetResource(g_ExtractFilePathName(resource), pData, len); + WAD.Free; + 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; + + procedure r_PlayerModel_Load; + var + ID1, ID2: DWORD; + i, a, b: Integer; + prefix, aname: String; + base, mask: Pointer; + baseLen, maskLen: Integer; + begin + g_Frames_CreateWAD(@RedFlagFrames, 'FRAMES_FLAG_RED', GameWAD + ':TEXTURES\FLAGRED', 64, 64, 5, False); + g_Frames_CreateWAD(@BlueFlagFrames, 'FRAMES_FLAG_BLUE', GameWAD + ':TEXTURES\FLAGBLUE', 64, 64, 5, False); + 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].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].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].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; + SetLength(Models[i].Gibs, PlayerModelsArray[i].GibsCount); + if PlayerModelsArray[i].GibsCount > 0 then + begin + r_PlayerModel_LoadResource(prefix + PlayerModelsArray[i].GibsResource, base, baseLen); + r_PlayerModel_LoadResource(prefix + PlayerModelsArray[i].GibsMask, mask, maskLen); + if (base <> nil) and (mask <> nil) then + begin + for a := 0 to PlayerModelsArray[i].GibsCount - 1 do + begin + if e_CreateTextureMemEx(base, baseLen, Models[i].Gibs[a].base, a * 32, 0, 32, 32) and + e_CreateTextureMemEx(mask, maskLen, Models[i].Gibs[a].mask, a * 32, 0, 32, 32) then + begin + Models[i].Gibs[a].rect := g_PlayerModel_CalcGibSize(base, baseLen, a * 32, 0, 32, 32); + with Models[i].Gibs[a].Rect do + if Height > 3 then + Height := Height - 1 - Random(2); // ??? + end + end + end; + FreeMem(mask); + FreeMem(base); + end + end + end + end; + + procedure r_PlayerModel_Free; + var i, a, b, c: Integer; + begin + e_DeleteTexture(RedFlagFrames); + e_DeleteTexture(BlueFlagFrames); + 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(Name + '_LEFTANIM' + IntToStr(a)); + g_Frames_DeleteByName(Name + '_LEFTANIM' + IntToStr(a) + '_MASK'); + g_Frames_DeleteByName(Name + '_RIGHTANIM' + IntToStr(a)); + g_Frames_DeleteByName(Name + '_RIGHTANIM' + IntToStr(a) + '_MASK'); + end; + end + // !!! delete gibs textures here + 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 e_DeleteTexture(WeaponID[a][b][c]) end; + procedure r_PlayerModel_Update; + begin + FlagAnimState.Update + end; + procedure r_PlayerModel_Draw (pm: TPlayerModel; X, Y: Integer; Alpha: Byte = 0); var Mirror: TMirrorType; pos, act: Byte; - p: TDFPoint; + fp, p: TDFPoint; + FramesID: DWORD; + fa: Integer; begin // Флаги: if pm.Direction = TDirection.D_LEFT then @@ -74,14 +305,26 @@ begin else Mirror := TMirrorType.Horizontal; - if (pm.Flag <> FLAG_NONE) and (pm.FlagAnim <> nil) and (not (pm.CurrentAnimation in [A_DIE1, A_DIE2])) then + FramesID := 0; + case pm.Flag of + FLAG_RED: FramesID := RedFlagFrames; + FLAG_BLUE: FramesID := BlueFlagFrames; + end; + if (FramesID <> 0) and (not (pm.CurrentAnimation in [A_DIE1, A_DIE2])) then begin + fp := PlayerModelsArray[pm.id].FlagPoint; + fa := PlayerModelsArray[pm.id].FlagAngle; 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)); + r_AnimationState_DrawEx( + FramesID, + FlagAnimState, + X + IfThen(pm.Direction = TDirection.D_LEFT, fp.X - 1, 2 * FLAG_BASEPOINT.X - fp.X + 1) - FLAG_BASEPOINT.X, + Y + fp.Y - FLAG_BASEPOINT.Y + 1, + Mirror, + p, + IfThen(pm.Direction = TDirection.D_RIGHT, fa, -fa) + ); end; // Оружие: @@ -90,7 +333,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].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 @@ -100,44 +343,51 @@ begin else pos := W_POS_NORMAL; - if (pm.CurrentAnimation in [A_ATTACK, A_ATTACKUP, A_ATTACKDOWN]) or pm.Fire then + if (pm.CurrentAnimation in [A_ATTACK, A_ATTACKUP, A_ATTACKDOWN]) or pm.GetFire() 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); + 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; - pm.Anim[TDirection.D_LEFT][pm.CurrentAnimation].Draw(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; - pm.Anim[TDirection.D_RIGHT][pm.CurrentAnimation].Draw(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; - pm.MaskAnim[TDirection.D_LEFT][pm.CurrentAnimation].Draw(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; - pm.MaskAnim[TDirection.D_RIGHT][pm.CurrentAnimation].Draw(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; @@ -145,4 +395,32 @@ begin e_Colors.B := 255; end; + procedure r_PlayerModel_DrawGibs; + var i, fX, fY, m, id: Integer; a: TDFPoint; pobj: ^TObj; + begin + if gGibs <> nil then + begin + for i := 0 to High(gGibs) do + begin + if gGibs[i].alive then + begin + pobj := @gGibs[i].Obj; + if not g_Obj_Collide(sX, sY, sWidth, sHeight, pobj) then + Continue; + pobj.lerp(gLerpFactor, fX, fY); + a.X := pobj.Rect.X + (pobj.Rect.Width div 2); + a.y := pobj.Rect.Y + (pobj.Rect.Height div 2); + m := gGibs[i].ModelID; + id := gGibs[i].GibID; + e_DrawAdv(Models[m].Gibs[id].base, fX, fY, 0, True, False, gGibs[i].RAngle, @a, TMirrorType.None); + e_Colors := gGibs[i].Color; + e_DrawAdv(Models[m].Gibs[id].mask, fX, fY, 0, True, False, gGibs[i].RAngle, @a, TMirrorType.None); + e_Colors.R := 255; + e_Colors.G := 255; + e_Colors.B := 255; + end + end + end + end; + end.