Skip to content

Commit

Permalink
Merge pull request #96 from MilchRatchet/dev-branch
Browse files Browse the repository at this point in the history
RaC 2 and 3 Hook and Gadgets, DL Skeletons and proper Wireframes.
  • Loading branch information
MilchRatchet authored Jul 25, 2023
2 parents e115d18 + 6ef556d commit c22356d
Show file tree
Hide file tree
Showing 36 changed files with 816 additions and 186 deletions.
29 changes: 12 additions & 17 deletions LibReplanetizer/Headers/GadgetHeader.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
// Copyright (C) 2018-2021, The Replanetizer Contributors.
// Copyright (C) 2018-2023, The Replanetizer Contributors.
// Replanetizer 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.
// Please see the LICENSE.md file for more details.

using System;
using System.Collections.Generic;
using System.IO;
using static LibReplanetizer.DataFunctions;
Expand All @@ -13,25 +14,22 @@ namespace LibReplanetizer.Headers
{
public class GadgetHeader
{
public List<int> modelPointers = new List<int>();
public List<Tuple<int, int>> modelData = new List<Tuple<int, int>>();
public int texturePointer;
public int textureCount;

// Are they always 47? If not I would expect the count somewhere
private const int GADGET_COUNT = 47;

public GadgetHeader() { }


public GadgetHeader(FileStream gadgetFile)
{
byte[] gadgetHeaderBytes = ReadBlock(gadgetFile, 0x00, GADGET_COUNT * 0x04);
int gadgetCount = ReadInt(ReadBlock(gadgetFile, 0x3C0, 0x04), 0x00);

modelPointers = new List<int>();
byte[] gadgetHeaderBytes = ReadBlock(gadgetFile, 0x00, 0x3D0);

for (int i = 0; i < GADGET_COUNT; i++)
for (int i = 0; i < gadgetCount; i++)
{
modelPointers.Add(ReadInt(gadgetHeaderBytes, i * 0x04));
int modelPointer = ReadInt(gadgetHeaderBytes, 0x00 + i * 0x04);
int modelID = ReadInt(gadgetHeaderBytes, 0x240 + i * 0x04);

modelData.Add(new Tuple<int, int>(modelPointer, modelID));
}

texturePointer = ReadInt(ReadBlock(gadgetFile, 0x3C4, 0x04), 0x00);
Expand All @@ -58,12 +56,9 @@ public static string FindGadgetFile(GameType game, string enginePath)
switch (game.num)
{
case 2:
var rac2Path = Path.Join(superFolder, "global", "gadgets", "gadgets.ps3");
if (File.Exists(rac2Path)) return rac2Path;
break;
case 3:
var rac3Path = Path.Join(superFolder, "global", "gadgets.ps3");
if (File.Exists(rac3Path)) return rac3Path;
var path = Path.Join(superFolder, "global", "gadgets.ps3");
if (File.Exists(path)) return path;
break;
}

Expand Down
70 changes: 68 additions & 2 deletions LibReplanetizer/Level Objects/Gameplay/Moby.cs
Original file line number Diff line number Diff line change
Expand Up @@ -734,7 +734,7 @@ public void SetDead()
state |= 0x80;
}

public void Update(byte[] memory, int offset)
public void UpdateRC1(byte[] memory, int offset)
{
float collX = ReadFloat(memory, offset + 0x00);
float collY = ReadFloat(memory, offset + 0x04);
Expand Down Expand Up @@ -793,6 +793,61 @@ public void Update(byte[] memory, int offset)
position = new Vector4(X, Y, Z, W);
rotation = new Vector4(rotX, rotY, rotZ, rotW);
color = Color.FromRgb((byte) red, (byte) green, (byte) blue).ToPixel<Rgb24>();

// TODO: Understand this better, this is just a hack for now.
if (oClass == 71 || oClass == 190 || oClass == 192 || oClass == 208 || oClass == 229)
{
rotation = rotation + new Vector4(1.5707964f, 0.0f, 0.0f, 0.0f);
}
}

public void UpdateRC23(byte[] memory, int offset)
{
float collX = ReadFloat(memory, offset + 0x00);
float collY = ReadFloat(memory, offset + 0x04);
float collZ = ReadFloat(memory, offset + 0x08);
float collW = ReadFloat(memory, offset + 0x0C);

float X = ReadFloat(memory, offset + 0x10);
float Y = ReadFloat(memory, offset + 0x14);
float Z = ReadFloat(memory, offset + 0x18);
float W = ReadFloat(memory, offset + 0x1C);

state = memory[offset + 0x20];
group = memory[offset + 0x21];
mClass = memory[offset + 0x22];
alpha = memory[offset + 0x23];
scale = ReadFloat(memory, offset + 0x2C);

updateDistance = memory[offset + 0x30];
visible = memory[offset + 0x31];
drawDistance = ReadShort(memory, offset + 0x32);
modeBits = ReadUshort(memory, offset + 0x34);
unk36 = ReadUshort(memory, offset + 0x36);
byte colorPadding = memory[offset + 0x38];
byte blue = memory[offset + 0x39];
byte green = memory[offset + 0x3A];
byte red = memory[offset + 0x3B];
light = ReadInt(memory, offset + 0x3C);

animationFrame = memory[offset + 0x41];
updateID = memory[offset + 0x42];
animationID = memory[offset + 0x43];
unk54 = ReadFloat(memory, offset + 0x44);
unk58 = ReadFloat(memory, offset + 0x48);
framerate = ReadFloat(memory, offset + 0x4C);

oClass = ReadUshort(memory, offset + 0xAA);

float rotX = ReadFloat(memory, offset + 0xF0);
float rotY = ReadFloat(memory, offset + 0xF4);
float rotZ = ReadFloat(memory, offset + 0xF8);
float rotW = ReadFloat(memory, offset + 0xFC);

collPos = new Vector4(collX, collY, -collZ, collW);
position = new Vector4(X, Y, Z, W);
rotation = new Vector4(rotX, rotY, rotZ, rotW);
color = Color.FromRgb((byte) red, (byte) green, (byte) blue).ToPixel<Rgb24>();
}
}

Expand All @@ -813,7 +868,18 @@ public void UpdateFromMemory(byte[] mobyMemory, int offset, List<Model> models)
memory = new IngameMobyMemory();
}

memory.Update(mobyMemory, offset);
switch (game.num)
{
case 1:
memory.UpdateRC1(mobyMemory, offset);
break;
case 2:
case 3:
memory.UpdateRC23(mobyMemory, offset);
break;
default:
return;
}

pVarMemoryAddress = 0x300000000 + memory.pVars;

Expand Down
28 changes: 27 additions & 1 deletion LibReplanetizer/Level.cs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ public Level(string enginePath)
LOGGER.Debug("Added {0} terrain elements", terrainEngine.fragments.Count);

LOGGER.Debug("Parsing player animations...");
playerAnimations = engineParser.GetPlayerAnimations((MobyModel) mobyModels[0]);
playerAnimations = (mobyModels.Count > 0) ? engineParser.GetPlayerAnimations((MobyModel) mobyModels[0]) : new List<Animation>();
LOGGER.Debug("Added {0} player animations", playerAnimations.Count);

uiElements = engineParser.GetUiElements();
Expand Down Expand Up @@ -402,6 +402,32 @@ public void EmplaceCommonData()

mobyModels.AddRange(gadgetModels);

if (armorModels.Count > 0)
{
// Replace the empty ratchet model with the first armor model.
// This can be changed once we know where the game stores which armor model to use.

int armorTextureOffset = textures.Count;
textures.AddRange(armorTextures[0]);

Model defaultRatchetModel = armorModels[0];

foreach (TextureConfig conf in defaultRatchetModel.textureConfig)
{
conf.id += armorTextureOffset;
}

mobyModels.RemoveAll(x => x.id == 0);
mobyModels.Add(defaultRatchetModel);
mobs.ForEach(x =>
{
if (x.modelID == 0)
{
x.model = defaultRatchetModel;
}
});
}

mobyModels.ForEach(x =>
{
if (x.id == 0 && x is MobyModel mobyModel)
Expand Down
63 changes: 61 additions & 2 deletions LibReplanetizer/Models/Animation/Animation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public Animation()
{

}
public Animation(FileStream fs, int modelOffset, int animationOffset, int boneCount, bool force = false)
public Animation(FileStream fs, GameType game, int modelOffset, int animationOffset, int boneCount, bool force = false)
{
//Only try to parse if the offset is non-zero
if (animationOffset == 0 && !force)
Expand All @@ -42,6 +42,22 @@ public Animation(FileStream fs, int modelOffset, int animationOffset, int boneCo
if (modelOffset <= 0)
return;

switch (game.num)
{
case 4:
GetDLVals(fs, game, modelOffset, animationOffset, boneCount);
break;
case 1:
case 2:
case 3:
default:
GetRC123Vals(fs, game, modelOffset, animationOffset, boneCount);
break;
}
}

private void GetRC123Vals(FileStream fs, GameType game, int modelOffset, int animationOffset, int boneCount)
{
// Header
byte[] header = ReadBlock(fs, modelOffset + animationOffset, 0x1C);
unk1 = ReadFloat(header, 0x00);
Expand All @@ -67,7 +83,7 @@ public Animation(FileStream fs, int modelOffset, int animationOffset, int boneCo
byte[] animationPointerBlock = ReadBlock(fs, modelOffset + animationOffset + 0x1C, frameCount * 0x04);
for (int i = 0; i < frameCount; i++)
{
frames.Add(new Frame(fs, modelOffset + ReadInt(animationPointerBlock, i * 0x04), boneCount));
frames.Add(new Frame(fs, game, modelOffset + ReadInt(animationPointerBlock, i * 0x04), boneCount));
}

// Sound configs
Expand All @@ -78,6 +94,49 @@ public Animation(FileStream fs, int modelOffset, int animationOffset, int boneCo
}
}

private void GetDLVals(FileStream fs, GameType game, int modelOffset, int animationOffset, int boneCount)
{
// Header
byte[] header = ReadBlock(fs, modelOffset + animationOffset, 0x20);
unk1 = ReadFloat(header, 0x00);
unk2 = ReadFloat(header, 0x04);
unk3 = ReadFloat(header, 0x08);
unk4 = ReadFloat(header, 0x0C);

byte frameCount = header[0x10];
unk5 = header[0x11];
byte soundsCount = header[0x12];
unk7 = header[0x13];

int offsetSound = ReadInt(header, 0x14);
int offsetUnk = ReadInt(header, 0x18);
int offsetFrameHeader = ReadInt(header, 0x1C);

byte[] unkBytes = ReadBlock(fs, modelOffset + animationOffset + offsetUnk, offsetFrameHeader - offsetUnk);

byte[] frameHeaderBlock = ReadBlock(fs, modelOffset + animationOffset + offsetFrameHeader, 0x10);

byte numFrames = frameHeaderBlock[1];
byte numRotations = frameHeaderBlock[2];
byte numScalings = frameHeaderBlock[3];
byte numTranslations = frameHeaderBlock[4];

// Frames
int frameSize = (numRotations + numScalings + numTranslations) * 0x08;
byte[] frameDataBlock = ReadBlock(fs, modelOffset + animationOffset + offsetFrameHeader + 0x10, numFrames * frameSize);
for (int i = 0; i < frameCount; i++)
{
frames.Add(new Frame(frameDataBlock, i * frameSize, numRotations, numScalings, numTranslations));
}

// Sound configs
byte[] extrasBlock = ReadBlock(fs, modelOffset + animationOffset + offsetSound, soundsCount * 4);
for (int i = 0; i < soundsCount; i++)
{
sounds.Add(ReadInt(extrasBlock, i * 4));
}
}

public byte[] Serialize(int baseOffset = 0, int fileOffset = 0)
{
// Head
Expand Down
41 changes: 39 additions & 2 deletions LibReplanetizer/Models/Animation/BoneData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,26 @@ namespace LibReplanetizer.Models.Animations
{
public class BoneData
{
public Vector3 translation;
public Vector3 translation; // This is not the same as the cumulative offset in the bonematrix
public short unk0x0C;
public short parent;

//The first 12 bytes are 3 floats which are exactly the translation from the BoneMatrix
//Last 4 bytes are equal to the last 4 bytes in the corresponding BoneMatrix

public BoneData(byte[] boneDataBlock, int num)
public BoneData(GameType game, byte[] boneDataBlock, int num)
{
if (game == GameType.DL)
{
GetDLVals(boneDataBlock, num);
}
else
{
GetRC123Vals(boneDataBlock, num);
}
}

private void GetRC123Vals(byte[] boneDataBlock, int num)
{
int offset = num * 0x10;
float translationX = ReadFloat(boneDataBlock, offset + 0x00);
Expand All @@ -33,6 +45,31 @@ public BoneData(byte[] boneDataBlock, int num)
parent = (short) (ReadShort(boneDataBlock, offset + 0x0E) / 0x40);
}

private void GetDLVals(byte[] boneDataBlock, int num)
{
int offset = num * 0x10;
float translationX = ReadFloat(boneDataBlock, offset + 0x00);
float translationY = ReadFloat(boneDataBlock, offset + 0x04);
float translationZ = ReadFloat(boneDataBlock, offset + 0x08);

translation = new Vector3(translationX / 1024.0f, translationY / 1024.0f, translationZ / 1024.0f);

//0 for root and some constant else (0b0111000000000000 = 0x7000 = 28672)
unk0x0C = ReadShort(boneDataBlock, offset + 0x0C);
parent = ReadShort(boneDataBlock, offset + 0x0E);

if (parent == 0xFF)
{
// The root node is always marked with 0xFF.
parent = 0;
}
else
{
// Parent is only 8 bits and the sign bit is set for some reason.
parent &= 0x7F;
}
}

public byte[] Serialize()
{
byte[] outBytes = new byte[0x10];
Expand Down
Loading

0 comments on commit c22356d

Please sign in to comment.