Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[UE1][Skeletal Mesh][Animations] #251

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Unreal/GameDatabase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ const GameInfo GListOfGames[] = {
#if UNDYING
G("Undying", undying, GAME_Undying),
#endif
#if HP2
G("Harry Potter and the Chamber of Secrets", hp2, GAME_HarryPotter2),
#endif
#endif // UNREAL1

// Unreal Engine 2
Expand Down
1 change: 1 addition & 0 deletions Unreal/GameDefines.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#define DEUS_EX 1
#define RUNE 1
#define UNDYING 1
#define HP2 1
#endif

// requires UNREAL25
Expand Down
13 changes: 13 additions & 0 deletions Unreal/UnCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ enum EGame

GAME_UE1 = 0x0100000,
GAME_Undying,
GAME_HarryPotter2,

GAME_UE2 = 0x0200000,
GAME_UT2,
Expand Down Expand Up @@ -1118,6 +1119,17 @@ struct FVector
{
float X, Y, Z;

// Constructors.
FVector() {}

FVector(float InX, float InY, float InZ)
: X(InX), Y(InY), Z(InZ)
{}

explicit FVector(float In)
: X(In), Y(In), Z(In)
{}

void Set(float _X, float _Y, float _Z)
{
X = _X; Y = _Y; Z = _Z;
Expand Down Expand Up @@ -1149,6 +1161,7 @@ struct FVector
X *= value; Y *= value; Z *= value;
}


friend FArchive& operator<<(FArchive &Ar, FVector &V)
{
Ar << V.X << V.Y << V.Z;
Expand Down
3 changes: 3 additions & 0 deletions Unreal/UnCoreSerialize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,8 @@ FArchive& FArray::SerializeSimple(FArchive &Ar, int NumFields, int FieldSize)
//?? be done using generic serializer, or SerializeSimple should be
//?? extended for this

const bool bIsStatic = IsStatic();

// serialize data count
int Count = DataCount;
if (GameUsesFCompactIndex(Ar))
Expand All @@ -234,6 +236,7 @@ FArchive& FArray::SerializeSimple(FArchive &Ar, int NumFields, int FieldSize)
DataCount = Count;
}
if (!Count) return Ar;
if (bIsStatic) return Ar;

// perform serialization itself
Ar.Serialize(DataPtr, elementSize * Count);
Expand Down
4 changes: 2 additions & 2 deletions Unreal/UnrealMesh/UnAnim2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ UMeshAnimation::~UMeshAnimation()
}


void UMeshAnimation::ConvertAnims()
void UMeshAnimation::ConvertAnims(bool bShouldAdjustTime /* = true */)
{
guard(UMeshAnimation::ConvertAnims);

Expand Down Expand Up @@ -62,7 +62,7 @@ void UMeshAnimation::ConvertAnims()
CopyArray(T->KeyTime, A.KeyTime);
// usually MotionChunk.TrackTime is identical to NumFrames, but some packages exists where
// time channel should be adjusted
if (M.TrackTime > 0)
if (bShouldAdjustTime && M.TrackTime > 0)
{
float TimeScale = Src.NumFrames / M.TrackTime;
for (int k = 0; k < T->KeyTime.Num(); k++)
Expand Down
221 changes: 221 additions & 0 deletions Unreal/UnrealMesh/UnMesh1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,27 @@ void USkeletalMesh::SerializeSkelMesh1(FArchive &Ar)
}
unguard;

#if HP2
if (Ar.Game == GAME_HarryPotter2)
{
int i;
for (i = 0; i < Points.Num(); i++)
Points[i].Y *= -1;
for (i = 0; i < Triangles.Num(); i++)
Exchange(Triangles[i].WedgeIndex[0], Triangles[i].WedgeIndex[1]);
for (i = 0; i < RefSkeleton.Num(); i++)
{
FMeshBone &S = RefSkeleton[i];
S.BonePos.Position.Y *= -1;
S.BonePos.Orientation.Y *= -1;
S.BonePos.Orientation.W *= -1;
}

ConvertMesh();
return;
}
#endif // HP2

// mirror model: points, faces and skeleton
int i;
for (i = 0; i < Points.Num(); i++)
Expand All @@ -412,4 +433,204 @@ void USkeletalMesh::SerializeSkelMesh1(FArchive &Ar)
unguard;
}

#if HP2

struct FAnimVec
{
int16 X = 0, Y = 0, Z = 0;

// Convert back to Vector, with additional scale.
FVector Vector( float Scale ) const
{
FVector OutVector;
Scale /= BASE_SCALE;
OutVector.Set(X * Scale, Y * Scale, Z * Scale);
return OutVector;
}

enum { BASE_SCALE = (1<<15)-1 };

FQuat Quat() const
{
static float Scale = 1.57079633 / BASE_SCALE;

const float _X = sin(X * Scale);
const float _Y = sin(Y * Scale);
const float _Z = sin(Z * Scale);

const float W = sqrt(max(0.0f, 1.f - _X * _X - _Y * _Y - _Z * _Z));

FQuat OutQuat;
OutQuat.Set(_X, _Y, _Z, W);
return OutQuat;
}

friend FArchive& operator<<(FArchive &Ar, FAnimVec &A)
{
return Ar << A.X << A.Y << A.Z;
}
};

SIMPLE_TYPE(FAnimVec, int16)

struct AnalogTrack_HP2
{
unsigned Flags = 0; // reserved
TStaticArray<FAnimVec, 1> KeyQuat; // Orientation key track (count = 1 or KeyTime.Count)
TStaticArray<FAnimVec, 1> KeyPos; // Position key track (count = 1 or KeyTime.Count)
TStaticArray<byte, 1> KeyDelta; // For each key, time when next key takes effect (measured from start of track)
float PosScale = 0.0f; // Scale for position track.
float TimeScale = 0.0f; // Scale for time track.

inline FVector GetKeyPos(int i) const
{
return KeyPos[i].Vector( PosScale );
}

friend FArchive& operator<<(FArchive &Ar, AnalogTrack_HP2 &A)
{
guard(AnalogTrack_HP2<<);
return Ar << A.Flags << A.KeyQuat << A.KeyPos << A.KeyDelta << A.PosScale << A.TimeScale;
unguard;
}
};

struct MotionChunk_HP2
{
FVector RootSpeed3D; // Net 3d speed.
float TrackTime; // Total time (Same for each track.)
int StartBone; // If we're a partial-hierarchy-movement, this is the lowest bone.
unsigned Flags; // Reserved; equals to UMeshAnimation.Version in UE2.5

TArray<int> BoneIndices; // Refbones number of Bone indices (-1 or valid one) to fast-find tracks for a particular bone.
// Frame-less, compressed animation tracks. NumBones times NumAnims tracks in total
TArray<AnalogTrack_HP2> AnimTracks; // Compressed key tracks (one for each bone)
// AnalogTrack RootTrack; // May or may not be used; actual traverse-a-scene root tracks for use
// with cutscenes / special physics modes, in addition to the regular skeletal root track.

friend FArchive& operator<<(FArchive &Ar, MotionChunk_HP2 &M)
{
guard(MotionChunk<<);
return Ar << M.RootSpeed3D << M.TrackTime << M.StartBone << M.Flags << M.BoneIndices << M.AnimTracks;
unguard;
}
};

struct FMasterTrack
{
TArray<FAnimVec> KeyQuat;
TArray<FAnimVec> KeyPos;
TArray<byte> KeyDelta;

friend FArchive& operator<<(FArchive &Ar, FMasterTrack &M)
{
guard(FMasterTrack<<);
return Ar << M.KeyQuat << M.KeyPos << M.KeyDelta;
unguard;
}
};

#include "Mesh/SkeletalMesh.h"

void UMeshAnimation::SerializeHP2Moves(FArchive &Ar)
{
guard(SerializeHP2Moves);

TArray<MotionChunk_HP2> HPMoves;
FMasterTrack MasterTrack;
Ar << HPMoves << AnimSeqs << MasterTrack;

int Q = 0, P = 0, T = 0;

for (MotionChunk_HP2& Move : HPMoves)
{
for (AnalogTrack_HP2& Track : Move.AnimTracks)
{
const int CurrentKeyQuatNum = Track.KeyQuat.Num();
const int CurrentKeyPosNum = Track.KeyPos.Num();
const int CurrentKeyDeltaNum = Track.KeyDelta.Num();

for (int QuatIndex = 0; QuatIndex < CurrentKeyQuatNum; ++QuatIndex)
{
const int TargetIndex = (Q + QuatIndex);
Track.KeyQuat[QuatIndex] = MasterTrack.KeyQuat[TargetIndex];
}
for (int PosIndex = 0; PosIndex < CurrentKeyPosNum; ++PosIndex)
{
const int TargetIndex = (P + PosIndex);
Track.KeyPos[PosIndex] = MasterTrack.KeyPos[TargetIndex];
}
for (int DeltaIndex = 0; DeltaIndex < CurrentKeyDeltaNum; ++DeltaIndex)
{
const int TargetIndex = (T + DeltaIndex);
Track.KeyDelta[DeltaIndex] = MasterTrack.KeyDelta[TargetIndex];
}

Q += CurrentKeyQuatNum;
P += CurrentKeyPosNum;
T += CurrentKeyDeltaNum;
}
}

Moves.SetNum(HPMoves.Num());

for (int MoveIndex = 0; MoveIndex < HPMoves.Num(); MoveIndex++)
{
FMeshAnimSeq& AnimSeq = AnimSeqs[MoveIndex];

MotionChunk_HP2& SourceMove = HPMoves[MoveIndex];
MotionChunk& TargetMove = Moves[MoveIndex];

TargetMove.RootSpeed3D = SourceMove.RootSpeed3D;
TargetMove.TrackTime = SourceMove.TrackTime;
TargetMove.StartBone = SourceMove.StartBone;
TargetMove.Flags = SourceMove.Flags;

CopyArray(TargetMove.BoneIndices, SourceMove.BoneIndices);

// For every bone
TargetMove.AnimTracks.SetNum(SourceMove.AnimTracks.Num());

for (int BoneIndex = 0; BoneIndex < TargetMove.AnimTracks.Num(); BoneIndex++)
{
AnalogTrack& TargetAnalogTrack = TargetMove.AnimTracks[BoneIndex];
AnalogTrack_HP2& SourceAnalogTrack = SourceMove.AnimTracks[BoneIndex];

TargetAnalogTrack.Flags = SourceAnalogTrack.Flags;
TargetAnalogTrack.KeyQuat.SetNum(SourceAnalogTrack.KeyQuat.Num());
TargetAnalogTrack.KeyPos.SetNum(SourceAnalogTrack.KeyPos.Num());
TargetAnalogTrack.KeyTime.SetNum(SourceAnalogTrack.KeyDelta.Num());

for (int KeyQuatIndex = 0; KeyQuatIndex < TargetAnalogTrack.KeyQuat.Num(); KeyQuatIndex++)
{
FQuat TargetQuat = SourceAnalogTrack.KeyQuat[KeyQuatIndex].Quat();
TargetQuat.Y *= -1.0f;

// "Due to historical idiosyncrasy, root orientation is negated. !" From UE1
if (BoneIndex != 0)
{
TargetQuat.W *= -1.0f;
}

TargetAnalogTrack.KeyQuat[KeyQuatIndex] = TargetQuat;
}
for (int KeyPosIndex = 0; KeyPosIndex < TargetAnalogTrack.KeyPos.Num(); KeyPosIndex++)
{
TargetAnalogTrack.KeyPos[KeyPosIndex] = SourceAnalogTrack.GetKeyPos(KeyPosIndex);
TargetAnalogTrack.KeyPos[KeyPosIndex].Y *= -1.0f;
}

int CurrentTime = 0;
for (int KeyTimeIndex = 0; KeyTimeIndex < TargetAnalogTrack.KeyTime.Num(); KeyTimeIndex++)
{
TargetAnalogTrack.KeyTime[KeyTimeIndex] = CurrentTime + SourceAnalogTrack.KeyDelta[KeyTimeIndex];
CurrentTime += SourceAnalogTrack.KeyDelta[KeyTimeIndex];
}
}
}

unguard;
}
#endif // HP2

#endif // UNREAL1
15 changes: 14 additions & 1 deletion Unreal/UnrealMesh/UnMesh2.h
Original file line number Diff line number Diff line change
Expand Up @@ -1393,6 +1393,9 @@ class UMeshAnimation : public UObject
void SerializeSCell(FArchive &Ar);
#endif
#if UNREAL1
#if HP2
void SerializeHP2Moves(FArchive &Ar);
#endif
void Upgrade();
#endif

Expand Down Expand Up @@ -1422,6 +1425,16 @@ class UMeshAnimation : public UObject
return;
}
#endif // SWRC
#if UNREAL1
#if HP2
if (Ar.Game == GAME_HarryPotter2)
{
SerializeHP2Moves(Ar);
ConvertAnims(false);
return;
}
#endif // HP2
#endif // UNREAL1
#if UC2
if (Ar.Engine() == GAME_UE2X)
{
Expand Down Expand Up @@ -1454,7 +1467,7 @@ class UMeshAnimation : public UObject
unguard;
}

void ConvertAnims();
void ConvertAnims(bool bShouldAdjustTime = true);
};


Expand Down