Guide Draw Skeleton on Delphi 10.1

DREDD

Administrator
Administrator
Administrator
Administrator
Status
Offline
Joined
Apr 18, 2019
Messages
202
Reaction score
326
I think this code will need a very small number of coders, because using Delphi is rare in itself, but still.

Hope that at least someone will need it.

Code:
type
  FVector = packed record
  X, Y, Z: Single;
  class function Create(const x, y, z: Single): FVector; inline; static;
  class operator Negative(const a: FVector): FVector; inline;
  class operator Positive(const a: FVector): FVector; inline;
  class operator Equal(const Left, Right: FVector): Boolean; inline;
  class operator NotEqual(const Left, Right: FVector): Boolean; inline;
  class operator Add(const Left, Right: FVector): FVector; inline;
  class operator Subtract(const Left, Right: FVector): FVector; inline;
  class operator Multiply(const Left, Right: FVector): FVector; inline;
  class operator Divide(const Left, Right: FVector): FVector; inline;
  function Size: Single;
  function Size2D: Single;
  function SizeSquared: Single;
  function SizeSquared2D: Single;
  function Dot(const v: FVector): Single;
  function Normalize: FVector;
  function Distance(const v: FVector): Single;
end;
 
type Vector3 = FVector;
 
type FMinimalViewInfo = packed record
  Location: Vector3;
  Rotation: Vector3;
  FOV: Single;
  OrthoWidth: Single;
  OrthoNearClipPlane: Single;
  OrthoFarClipPlane: Single;
  AspectRatio: Single;
end;
 
type FCameraCacheEntry = packed record
  TimeStamp: Single;
  UnknownData00: array[1..$C]of Byte;
  POV: FMinimalViewInfo;
end;
 
type Bones = (
  Root,
  pelvis,
  spine_01,
  spine_02,
  spine_03,
  neck_01,
  Head,
  face_root,
  eyebrows_pos_root,
  eyebrows_root,
  eyebrows_r,
  eyebrows_l,
  eyebrow_l,
  eyebrow_r,
  forehead_root,
  forehead,
  jaw_pos_root,
  jaw_root,
  jaw,
  mouth_down_pos_root,
  mouth_down_root,
  lip_bm_01,
  lip_bm_02,
  lip_br,
  lip_bl,
  jaw_01,
  jaw_02,
  cheek_pos_root,
  cheek_root,
  cheek_r,
  cheek_l,
  nose_side_root,
  nose_side_r_01,
  nose_side_r_02,
  nose_side_l_01,
  nose_side_l_02,
  eye_pos_r_root,
  eye_r_root,
  eye_rot_r_root,
  eye_lid_u_r,
  eye_r,
  eye_lid_b_r,
  eye_pos_l_root,
  eye_l_root,
  eye_rot_l_root,
  eye_lid_u_l,
  eye_l,
  eye_lid_b_l,
  nose_pos_root,
  nose,
  mouth_up_pos_root,
  mouth_up_root,
  lip_ul,
  lip_um_01,
  lip_um_02,
  lip_ur,
  lip_l,
  lip_r,
  hair_root,
  hair_b_01,
  hair_b_02,
  hair_l_01,
  hair_l_02,
  hair_r_01,
  hair_r_02,
  hair_f_02,
  hair_f_01,
  hair_b_pt_01,
  hair_b_pt_02,
  hair_b_pt_03,
  hair_b_pt_04,
  hair_b_pt_05,
  camera_fpp,
  GunReferencePoint,
  GunRef,
  breast_l,
  breast_r,
  clavicle_l,
  upperarm_l,
  lowerarm_l,
  hand_l,
  thumb_01_l,
  thumb_02_l,
  thumb_03_l,
  thumb_04_l_MBONLY,
  index_01_l,
  index_02_l,
  index_03_l,
  index_04_l_MBONLY,
  middle_01_l,
  middle_02_l,
  middle_03_l,
  middle_04_l_MBONLY,
  ring_01_l,
  ring_02_l,
  ring_03_l,
  ring_04_l_MBONLY,
  pinky_01_l,
  pinky_02_l,
  pinky_03_l,
  pinky_04_l_MBONLY,
  item_l,
  lowerarm_twist_01_l,
  upperarm_twist_01_l,
  clavicle_r,
  upperarm_r,
  lowerarm_r,
  hand_r,
  thumb_01_r,
  thumb_02_r,
  thumb_03_r,
  thumb_04_r_MBONLY,
  index_01_r,
  index_02_r,
  index_03_r,
  index_04_r_MBONLY,
  middle_01_r,
  middle_02_r,
  middle_03_r,
  middle_04_r_MBONLY,
  ring_01_r,
  ring_02_r,
  ring_03_r,
  ring_04_r_MBONLY,
  pinky_01_r,
  pinky_02_r,
  pinky_03_r,
  pinky_04_r_MBONLY,
  item_r,
  lowerarm_twist_01_r,
  upperarm_twist_01_r,
  BackPack,
  backpack_01,
  backpack_02,
  Slot_Primary,
  Slot_Secondary,
  Slot_Melee,
  slot_throwable,
  coat_l_01,
  coat_l_02,
  coat_l_03,
  coat_l_04,
  coat_fl_01,
  coat_fl_02,
  coat_fl_03,
  coat_fl_04,
  coat_b_01,
  coat_b_02,
  coat_b_03,
  coat_b_04,
  coat_r_01,
  coat_r_02,
  coat_r_03,
  coat_r_04,
  coat_fr_01,
  coat_fr_02,
  coat_fr_03,
  coat_fr_04,
  thigh_l,
  calf_l,
  foot_l,
  ball_l,
  calf_twist_01_l,
  thigh_twist_01_l,
  thigh_r,
  calf_r,
  foot_r,
  ball_r,
  calf_twist_01_r,
  thigh_twist_01_r,
  Slot_SideArm,
  skirt_l_01,
  skirt_l_02,
  skirt_l_03,
  skirt_f_01,
  skirt_f_02,
  skirt_f_03,
  skirt_b_01,
  skirt_b_02,
  skirt_b_03,
  skirt_r_01,
  skirt_r_02,
  skirt_r_03,
  ik_hand_root,
  ik_hand_gun,
  ik_hand_r,
  ik_hand_l,
  ik_aim_root,
  ik_aim_l,
  ik_aim_r,
  ik_foot_root,
  ik_foot_l,
  ik_foot_r,
  camera_tpp,
  ik_target_root,
  ik_target_l,
  ik_target_r,
  VB_spine_03_spine_03,
  VB_upperarm_r_lowerarm_r
  );
 
type FQuat = packed record
  x, y, z, w: Single;
end;
 
type FTransform = packed record
  rot: FQuat;
  translation: Vector3;
  pad: array[1..4]of Byte;
  scale: Vector3;
  pad1: array[1..4]of Byte;
  function ToMatrixWithScale: D3DXMATRIX;
end;
 
implementation
 
class function FVector.Create(const x, y, z: Single): FVector;
begin
  Result.X:= x;
  Result.Y:= y;
  Result.Z:= z;
end;
 
class operator FVector.Negative(const a: FVector): FVector;
begin
  Result.x:= -a.x;
  Result.y:= -a.y;
  Result.z:= -a.z;
end;
 
class operator FVector.Positive(const a: FVector): FVector;
begin
  Result:= a;
end;
 
class operator FVector.Equal(const Left, Right: FVector): Boolean;
begin
  Result:= (Left.x = Right.x) and (Left.y = Right.y) and (Left.z = Right.z);
end;
 
class operator FVector.NotEqual(const Left, Right: FVector): Boolean;
begin
  Result:= not((Left.x = Right.x) and (Left.y = Right.y) and (Left.z = Right.z));
end;
 
class operator FVector.Add(const Left, Right: FVector): FVector;
begin
  Result.x:= Left.x + Right.x;
  Result.y:= Left.y + Right.y;
  Result.z:= Left.z + Right.z;
end;
 
class operator FVector.Subtract(const Left, Right: FVector): FVector;
begin
  Result.x:= Left.x - Right.x;
  Result.y:= Left.y - Right.y;
  Result.z:= Left.z - Right.z;
end;
 
class operator FVector.Multiply(const Left, Right: FVector): FVector;
begin
  Result.x:= Left.x * Right.x;
  Result.y:= Left.y * Right.y;
  Result.z:= Left.z * Right.z;
end;
 
class operator FVector.Divide(const Left, Right: FVector): FVector;
begin
  Result.x:= Left.x / Right.x;
  Result.y:= Left.y / Right.y;
  Result.z:= Left.z / Right.z;
end;
 
function FVector.Size;
begin
  Result:= sqrt(x*x + y*y + z*z);
end;
 
function FVector.Size2D;
begin
  Result:= sqrt(x*x + y*y);
end;
 
function FVector.SizeSquared;
begin
  Result:= x*x + y*y + z*z;
end;
 
function FVector.SizeSquared2D;
begin
  Result:= x*x + y*y;
end;
 
function FVector.Dot(const v: FVector): Single;
begin
  Result:= x * v.x + y * v.y + z * v.z;
end;
 
function FVector.Normalize;
var v: FVector;
len: Single;
begin
  len:= Self.Size;
  if (len <> 0) then
  begin
    v.X:= X / len;
    v.Y:= Y / len;
    v.Z:= Z / len;
  end
  else
  begin
    v.X:= 0;
    v.Y:= 0;
    v.Z:= 1;
  end;
  Result:= v;
end;
 
function FVector.Distance(const v: FVector): Single;
var v0: FVector;
begin
  v0:= Self - v;
  v0:= v0 * v0;
  Result:= sqrt(v0.X + v0.Y + v0.Z);
end;
 
function FTransform.ToMatrixWithScale: D3DXMATRIX;
var m: D3DXMATRIX;
x2, y2, z2, xx2, yy2, zz2, yz2, wx2, xy2, wz2, xz2, wy2: Single;
begin
  m._41:= translation.x;
  m._42:= translation.y;
  m._43:= translation.z;
 
  x2:= rot.x + rot.x;
  y2:= rot.y + rot.y;
  z2:= rot.z + rot.z;
 
  xx2:= rot.x * x2;
  yy2:= rot.y * y2;
  zz2:= rot.z * z2;
 
  m._11:= (1 - (yy2 + zz2)) * scale.X;
  m._22:= (1 - (xx2 + zz2)) * scale.Y;
  m._33:= (1 - (xx2 + yy2)) * scale.Z;
 
  yz2:= rot.y * z2;
  wx2:= rot.w * x2;
 
  m._32:= (yz2 - wx2) * scale.Z;
  m._23:= (yz2 + wx2) * scale.Y;
 
  xy2:= rot.x * y2;
  wz2:= rot.w * z2;
  m._21:= (xy2 - wz2) * scale.y;
  m._12:= (xy2 + wz2) * scale.x;
 
  xz2:= rot.x * z2;
  wy2:= rot.w * y2;
  m._31:= (xz2 + wy2) * scale.z;
  m._13:= (xz2 - wy2) * scale.x;
 
  m._14:= 0.0;
  m._24:= 0.0;
  m._34:= 0.0;
  m._44:= 1.0;
 
  Result:= m;
end;

Code:
const upper_part: array[0..2]of Bones = (Bones.neck_01, Bones.Head, Bones.forehead);
const right_arm: array[0..3]of Bones = (Bones.neck_01, Bones.upperarm_r, Bones.lowerarm_r, Bones.hand_r);
const left_arm: array[0..3]of Bones = (Bones.neck_01, Bones.upperarm_l, Bones.lowerarm_l, Bones.hand_l);
const spine: array[0..3]of Bones = (Bones.neck_01, Bones.spine_02, Bones.spine_01, Bones.pelvis);
 
const lower_right: array[0..3]of Bones = (Bones.pelvis, Bones.thigh_r, Bones.calf_r, Bones.foot_r);
const lower_left: array[0..3]of Bones = (Bones.pelvis, Bones.thigh_l, Bones.calf_l, Bones.foot_l);
 
var skeleton: array[0..5]of array of Bones;
 
function Matrix(const rot, origin: Vector3): D3DXMATRIX;
var radPitch, radYaw, radRoll, SP, CP, SY, CY, SR, CR: Single;
begin
  radPitch:= rot.X * Pi / 180;
  radYaw:= rot.Y * Pi / 180;
  radRoll:= rot.Z * Pi/ 180;
 
  SP:= sin(radPitch);
  CP:= cos(radPitch);
  SY:= sin(radYaw);
  CY:= cos(radYaw);
  SR:= sin(radRoll);
  CR:= cos(radRoll);
 
  Result.m[0][0]:= CP * CY;
    Result.m[0][1]:= CP * SY;
    Result.m[0][2]:= SP;
    Result.m[0][3]:= 0;
 
    Result.m[1][0]:= SR * SP * CY - CR * SY;
    Result.m[1][1]:= SR * SP * SY + CR * CY;
    Result.m[1][2]:= -SR * CP;
    Result.m[1][3]:= 0;
 
    Result.m[2][0]:= -(CR * SP * CY + SR * SY);
    Result.m[2][1]:= CY * SR - CR * SP * SY;
    Result.m[2][2]:= CR * CP;
    Result.m[2][3]:= 0;
 
    Result.m[3][0]:= origin.x;
    Result.m[3][1]:= origin.y;
    Result.m[3][2]:= origin.z;
    Result.m[3][3]:= 1;
end;
 
function WorldToScreen(WorldLocation: Vector3; CameraCacheL: FCameraCacheEntry): Vector3;
var Screenlocation, Rotation, vDelta, vTransformed: Vector3;
POV: FMinimalViewInfo;
tempMatrix: D3DXMATRIX;
vAxisX, vAxisY, vAxisZ: Vector3;
ScreenCenterX, ScreenCenterY, FovAngle: Single;
begin
  try
    POV:= CameraCacheL.POV;
    Rotation:= POV.Rotation;
    tempMatrix:= Matrix(Rotation, Vector3.Create(0, 0, 0));
 
    vAxisX:= Vector3.Create(tempMatrix.m[0][0], tempMatrix.m[0][1], tempMatrix.m[0][2]);
    vAxisY:= Vector3.Create(tempMatrix.m[1][0], tempMatrix.m[1][1], tempMatrix.m[1][2]);
    vAxisZ:= Vector3.Create(tempMatrix.m[2][0], tempMatrix.m[2][1], tempMatrix.m[2][2]);
 
    vDelta:= WorldLocation - POV.Location;
    vTransformed:= Vector3.Create(vDelta.Dot(vAxisY), vDelta.Dot(vAxisZ), vDelta.Dot(vAxisX));
 
    if vTransformed.Z < 1 then
      vTransformed.Z:= 1;
 
    FovAngle:= POV.FOV;
    ScreenCenterX:= s_width / 2;
    ScreenCenterY:= s_height / 2;
 
    Screenlocation.X:= ScreenCenterX + vTransformed.x * (ScreenCenterX / tan(FovAngle * Pi / 360)) / vTransformed.z;
    Screenlocation.Y:= ScreenCenterY - vTransformed.y * (ScreenCenterX / tan(FovAngle * Pi / 360)) / vTransformed.z;
    Screenlocation.Z:= vTransformed.Z;
 
    Result:= Screenlocation;
  except
    Result:= Vector3.Create(0, 0, 0);
  end;
end;
 
function MatrixMultiplication(M1, M2: D3DMATRIX): D3DMATRIX;
begin
  Result._11:= M1._11 * M2._11 + M1._12 * M2._21 + M1._13 * M2._31 + M1._14 * M2._41;
  Result._12:= M1._11 * M2._12 + M1._12 * M2._22 + M1._13 * M2._32 + M1._14 * M2._42;
  Result._13:= M1._11 * M2._13 + M1._12 * M2._23 + M1._13 * M2._33 + M1._14 * M2._43;
  Result._14:= M1._11 * M2._14 + M1._12 * M2._24 + M1._13 * M2._34 + M1._14 * M2._44;
  Result._21:= M1._21 * M2._11 + M1._22 * M2._21 + M1._23 * M2._31 + M1._24 * M2._41;
  Result._22:= M1._21 * M2._12 + M1._22 * M2._22 + M1._23 * M2._32 + M1._24 * M2._42;
  Result._23:= M1._21 * M2._13 + M1._22 * M2._23 + M1._23 * M2._33 + M1._24 * M2._43;
  Result._24:= M1._21 * M2._14 + M1._22 * M2._24 + M1._23 * M2._34 + M1._24 * M2._44;
  Result._31:= M1._31 * M2._11 + M1._32 * M2._21 + M1._33 * M2._31 + M1._34 * M2._41;
  Result._32:= M1._31 * M2._12 + M1._32 * M2._22 + M1._33 * M2._32 + M1._34 * M2._42;
  Result._33:= M1._31 * M2._13 + M1._32 * M2._23 + M1._33 * M2._33 + M1._34 * M2._43;
  Result._34:= M1._31 * M2._14 + M1._32 * M2._24 + M1._33 * M2._34 + M1._34 * M2._44;
  Result._41:= M1._41 * M2._11 + M1._42 * M2._21 + M1._43 * M2._31 + M1._44 * M2._41;
  Result._42:= M1._41 * M2._12 + M1._42 * M2._22 + M1._43 * M2._32 + M1._44 * M2._42;
  Result._43:= M1._41 * M2._13 + M1._42 * M2._23 + M1._43 * M2._33 + M1._44 * M2._43;
  Result._44:= M1._41 * M2._14 + M1._42 * M2._24 + M1._43 * M2._34 + M1._44 * M2._44;
end;
 
function GetBoneIndex(mesh: UInt64; index: Integer): FTransform;
var bonearray: UInt64;
begin
  if Mem.Read(mesh + $960,  @BonEarray, 8) then
    Mem.Read(bonearray + index * $30,  @Result, SizeOf(Result));
end;
 
function GetBoneWithRotation(mesh: UInt64; id: Integer): Vector3;
var bone, ComponentToWorld: FTransform;
Matrix: D3DXMATRIX;
begin
  Result:= Vector3.Create(0, 0, 0);
  bone:= GetBoneIndex(mesh, id);
 
  if Mem.Read(mesh + $280,  @ComponentToWorld, SizeOf(ComponentToWorld)) then
  begin
    Matrix:= MatrixMultiplication(bone.ToMatrixWithScale, ComponentToWorld.ToMatrixWithScale);
    Result:= Vector3.Create(Matrix._41, Matrix._42, Matrix._43);
  end;
end;
 
procedure DrawSkeleton(mesh: UInt64; color: D3DCOLOR);
var neckpos, pelvispos, previous, current, p1, c1: Vector3;
i, j, bone: Integer;
begin
  for i := 0 to High(skeleton) do
  begin
    previous:= Vector3.Create(0, 0, 0);
    for j := 0 to High(skeleton[i]) do
    begin
      bone:= Integer(skeleton[i][j]);
      current:= GetBoneWithRotation(mesh, bone);
      if bone = Integer(Bones.neck_01) then
        neckpos:= current;
      if bone = Integer(Bones.pelvis) then
        pelvispos:= current;
      if previous.X = 0 then
        previous:= current;
      p1:= WorldToScreen(previous, G.cameracache);
      c1:= WorldToScreen(current, G.cameracache);
      DrawLine(p1.X, p1.Y, c1.X, c1.Y, color);
      previous:= current;
    end;
  end;
end;
 
begin
  SetLength(skeleton[0], Length(upper_part));
  SetLength(skeleton[1], Length(right_arm));
  SetLength(skeleton[2], Length(left_arm));
  SetLength(skeleton[3], Length(spine));
  SetLength(skeleton[4], Length(lower_right));
  SetLength(skeleton[5], Length(lower_left));
  CopyMemory(@skeleton[0][0],  @upper_part[0], SizeOf(upper_part));
  CopyMemory(@skeleton[1][0],  @right_arm[0], SizeOf(right_arm));
  CopyMemory(@skeleton[2][0],  @Left_arm[0], SizeOf(left_arm));
  CopyMemory(@skeleton[3][0],  @Spine[0], SizeOf(spine));
  CopyMemory(@skeleton[4][0],  @lower_right[0], SizeOf(lower_right));
  CopyMemory(@skeleton[5][0],  @lower_left[0], SizeOf(lower_left));
end.
 
Top