index be268e299d7d87f7e8aaef28d64b9b3a2a90c40b..b2f57e6c95997ff2835acc80f58380b4ec6827ca 100644 (file)
*
* 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
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;
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;
HaveWeapon: Boolean;
end;
+ TModelBlood = record
+ R, G, B, Kind: Byte;
+ end;
+
TModelSound = record
ID: DWORD;
Level: Byte;
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;
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;
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;
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
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 =
('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;
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;
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;
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);
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;
with PlayerModelsArray[a] do
begin
Result.FName := Info.Name;
+ Result.FBlood := Blood;
for b := A_STAND to A_LAST do
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;
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