Skip to content

Commit

Permalink
Merge pull request #98 from MilchRatchet/dev-branch
Browse files Browse the repository at this point in the history
Mobyload Models
  • Loading branch information
MilchRatchet authored Nov 12, 2023
2 parents c942f22 + 415c78c commit 46cd7c6
Show file tree
Hide file tree
Showing 15 changed files with 476 additions and 40 deletions.
66 changes: 66 additions & 0 deletions LibReplanetizer/Headers/MobyloadHeader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// 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;

namespace LibReplanetizer.Headers
{
public class MobyloadHeader
{
public int mobyCount;
public int textureCount;
public int texturePointer;
public int textureDataPointer;
public List<Tuple<int, int>> modelData = new List<Tuple<int, int>>();

public MobyloadHeader(FileStream mobyloadFile)
{
byte[] headerBytes = ReadBlock(mobyloadFile, 0x00, 0x10);

mobyCount = ReadInt(headerBytes, 0x00);
textureCount = ReadInt(headerBytes, 0x04);
texturePointer = ReadInt(headerBytes, 0x08);
textureDataPointer = ReadInt(headerBytes, 0x0C);

byte[] pointerBlock = ReadBlock(mobyloadFile, 0x10, mobyCount * 0x0C);

for (int i = 0; i < mobyCount; i++)
{
int modelPointer = ReadInt(pointerBlock, 0x00 + i * 0x0C);
int modelID = ReadInt(pointerBlock, 0x04 + i * 0x0C);

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

public static string? FindMobyloadFile(GameType game, string enginePath, int id)
{
string? folder = Path.GetDirectoryName(enginePath);

switch (game.num)
{
case 3:
case 4:
string? path = Path.Join(folder, "mobyload" + id + ".ps3");
if (File.Exists(path)) return path;
break;
}

return null;
}

public byte[] Serialize()
{
byte[] bytes = new byte[0x10];

return bytes;
}
}
}
25 changes: 24 additions & 1 deletion LibReplanetizer/Level.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ public class Level
public List<Terrain> terrainChunks;
public List<int> textureConfigMenus;
public List<Mission> missions;
public List<List<MobyModel>> mobyloadModels;
public List<List<Texture>> mobyloadTextures;

public LevelVariables levelVariables;
public OcclusionData? occlusionData;
Expand Down Expand Up @@ -268,7 +270,7 @@ public Level(string enginePath)

for (int i = 0; i < 5; i++)
{
var chunkPath = Path.Join(path, @"chunk" + i + ".ps3");
string? chunkPath = Path.Join(path, @"chunk" + i + ".ps3");
if (!File.Exists(chunkPath)) continue;

using (ChunkParser chunkParser = new ChunkParser(chunkPath, game))
Expand Down Expand Up @@ -371,6 +373,27 @@ public Level(string enginePath)
missions.Add(mission);
}

mobyloadModels = new List<List<MobyModel>>();
mobyloadTextures = new List<List<Texture>>();

for (int mobyloadFileID = 0; mobyloadFileID < 32; mobyloadFileID++)
{
string? mobyloadFilePath = MobyloadHeader.FindMobyloadFile(game, enginePath, mobyloadFileID);
if (mobyloadFilePath != null)
{
using (MobyloadParser parser = new MobyloadParser(game, mobyloadFilePath))
{
mobyloadModels.Add(parser.GetMobyModels());
mobyloadTextures.Add(parser.GetTextures());
}
}
else
{
mobyloadModels.Add(new List<MobyModel>());
mobyloadTextures.Add(new List<Texture>());
}
}

using (VramParser vramParser = new VramParser(path + @"/vram.ps3"))
{
vramParser.GetTextures(textures);
Expand Down
7 changes: 4 additions & 3 deletions LibReplanetizer/LibReplanetizer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="NLog" Version="5.2.0" />
<PackageReference Include="OpenTK.Mathematics" Version="4.7.7" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.0.1" />
<PackageReference Include="ImGui.NET" Version="1.89.9.3" />
<PackageReference Include="NLog" Version="5.2.5" />
<PackageReference Include="OpenTK.Mathematics" Version="4.8.1" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.0.2" />
<PackageReference Include="System.Resources.Extensions" Version="7.0.0" />
</ItemGroup>

Expand Down
18 changes: 9 additions & 9 deletions LibReplanetizer/Models/Model.cs
Original file line number Diff line number Diff line change
Expand Up @@ -270,15 +270,15 @@ public static float[] GetVertices(FileStream fs, int vertexPointer, int uvPointe
byte[] uvBlock = ReadBlock(fs, uvPointer, vertexCount * uvElemSize);
for (int i = 0; i < vertexCount; i++)
{
vertexBuffer[(i * 8) + 0] = (ReadFloat(vertBlock, (i * vertexElemSize) + 0x00)); //VertexX
vertexBuffer[(i * 8) + 1] = (ReadFloat(vertBlock, (i * vertexElemSize) + 0x04)); //VertexY
vertexBuffer[(i * 8) + 2] = (ReadFloat(vertBlock, (i * vertexElemSize) + 0x08)); //VertexZ
vertexBuffer[(i * 8) + 3] = (ReadFloat(vertBlock, (i * vertexElemSize) + 0x0C)); //NormX
vertexBuffer[(i * 8) + 4] = (ReadFloat(vertBlock, (i * vertexElemSize) + 0x10)); //NormY
vertexBuffer[(i * 8) + 5] = (ReadFloat(vertBlock, (i * vertexElemSize) + 0x14)); //NormZ

vertexBuffer[(i * 8) + 6] = (ReadFloat(uvBlock, (i * uvElemSize) + 0x00)); //UVu
vertexBuffer[(i * 8) + 7] = (ReadFloat(uvBlock, (i * uvElemSize) + 0x04)); //UVv
vertexBuffer[(i * 8) + 0] = ReadFloat(vertBlock, (i * vertexElemSize) + 0x00); //VertexX
vertexBuffer[(i * 8) + 1] = ReadFloat(vertBlock, (i * vertexElemSize) + 0x04); //VertexY
vertexBuffer[(i * 8) + 2] = ReadFloat(vertBlock, (i * vertexElemSize) + 0x08); //VertexZ
vertexBuffer[(i * 8) + 3] = ReadFloat(vertBlock, (i * vertexElemSize) + 0x0C); //NormX
vertexBuffer[(i * 8) + 4] = ReadFloat(vertBlock, (i * vertexElemSize) + 0x10); //NormY
vertexBuffer[(i * 8) + 5] = ReadFloat(vertBlock, (i * vertexElemSize) + 0x14); //NormZ

vertexBuffer[(i * 8) + 6] = ReadFloat(uvBlock, (i * uvElemSize) + 0x00); //UVu
vertexBuffer[(i * 8) + 7] = ReadFloat(uvBlock, (i * uvElemSize) + 0x04); //UVv
}
return vertexBuffer;
}
Expand Down
24 changes: 12 additions & 12 deletions LibReplanetizer/Models/TextureConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ public WrapMode wrapModeS
{
if ((mode & 0b01) > 0)
{
return (((mode & 0b10) > 0)) ? WrapMode.ClampEdge : WrapMode.Repeat;
return ((mode & 0b10) > 0) ? WrapMode.ClampEdge : WrapMode.Repeat;
}

if (((mode >> 24) & 0b01) > 0)
{
return ((((mode >> 24) & 0b10) > 0)) ? WrapMode.ClampEdge : WrapMode.Repeat;
return (((mode >> 24) & 0b10) > 0) ? WrapMode.ClampEdge : WrapMode.Repeat;
}

return WrapMode.Repeat;
Expand All @@ -55,10 +55,10 @@ public WrapMode wrapModeS
switch (value)
{
case WrapMode.Repeat:
mode = mode & (~0b10);
mode &= (~0b10);
break;
case WrapMode.ClampEdge:
mode = mode | 0b10;
mode |= 0b10;
break;
default:
break;
Expand All @@ -71,10 +71,10 @@ public WrapMode wrapModeS
switch (value)
{
case WrapMode.Repeat:
mode = mode & ~(0b10 << 24);
mode &= ~(0b10 << 24);
break;
case WrapMode.ClampEdge:
mode = mode | (0b10 << 24);
mode |= (0b10 << 24);
break;
default:
break;
Expand All @@ -91,12 +91,12 @@ public WrapMode wrapModeT
{
if (((mode >> 2) & 0b01) > 0)
{
return ((((mode >> 2) & 0b10) > 0)) ? WrapMode.ClampEdge : WrapMode.Repeat;
return (((mode >> 2) & 0b10) > 0) ? WrapMode.ClampEdge : WrapMode.Repeat;
}

if (((mode >> 26) & 0b01) > 0)
{
return ((((mode >> 26) & 0b10) > 0)) ? WrapMode.ClampEdge : WrapMode.Repeat;
return (((mode >> 26) & 0b10) > 0) ? WrapMode.ClampEdge : WrapMode.Repeat;
}

return WrapMode.Repeat;
Expand All @@ -108,10 +108,10 @@ public WrapMode wrapModeT
switch (value)
{
case WrapMode.Repeat:
mode = mode & ~(0b10 << 2);
mode &= ~(0b10 << 2);
break;
case WrapMode.ClampEdge:
mode = mode | (0b10 << 2);
mode |= (0b10 << 2);
break;
default:
break;
Expand All @@ -124,10 +124,10 @@ public WrapMode wrapModeT
switch (value)
{
case WrapMode.Repeat:
mode = mode & ~(0b10 << 26);
mode &= ~(0b10 << 26);
break;
case WrapMode.ClampEdge:
mode = mode | (0b10 << 26);
mode |= (0b10 << 26);
break;
default:
break;
Expand Down
53 changes: 53 additions & 0 deletions LibReplanetizer/Parsers/MobyloadParser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// 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 LibReplanetizer.Headers;
using LibReplanetizer.Models;
using System;
using System.Collections.Generic;

namespace LibReplanetizer.Parsers
{
public class MobyloadParser : RatchetFileParser, IDisposable
{
MobyloadHeader mobyloadHead;
GameType game;

public MobyloadParser(GameType game, string mobyloadFile) : base(mobyloadFile)
{
this.game = game;
mobyloadHead = new MobyloadHeader(fileStream);
}

public List<Texture> GetTextures()
{
return GetTexturesMobyload(mobyloadHead.texturePointer, mobyloadHead.textureDataPointer, mobyloadHead.textureCount);
}

public List<MobyModel> GetMobyModels()
{
List<MobyModel> models = new List<MobyModel>();

foreach (Tuple<int, int> model in mobyloadHead.modelData)
{
// ID of zero implies that something wrong and this model is to be ignored.
if (model.Item2 != 0)
{
models.Add(new MobyModel(fileStream, game, (short) model.Item2, model.Item1));
}
}

return models;

}

public void Dispose()
{
fileStream.Close();
}
}
}
29 changes: 29 additions & 0 deletions LibReplanetizer/Parsers/RatchetFileParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,35 @@ protected List<Texture> GetTextures(int texturePointer, int textureCount)
return textureList;
}

protected List<Texture> GetTexturesMobyload(int texturePointer, int textureDataPointer, int textureCount)
{
List<Texture> textureList = new List<Texture>(textureCount);

//Read the whole texture header block, and add textures based on the count
byte[] textureBlock = ReadBlock(fileStream, texturePointer, textureCount * Texture.TEXTUREELEMSIZE);
for (int i = 0; i < textureCount; i++)
{
textureList.Add(new Texture(textureBlock, i));
}

for (int i = 0; i < textureList.Count; i++)
{
textureList[i].mipMapCount = 0;
int length;
if (i < textureList.Count - 1)
{
length = (int) (textureList[i + 1].vramPointer - textureList[i].vramPointer);
}
else
{
length = (int) (fileStream.Length - textureList[i].vramPointer);
}
textureList[i].data = ReadBlock(fileStream, textureDataPointer + textureList[i].vramPointer, length);
}

return textureList;
}

protected List<Tie> GetTies(List<Model> tieModels, int tiePointer, int tieCount)
{
List<Tie> ties = new List<Tie>(tieCount);
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ You can move around the world with keyboard and mouse:
- Left click items to select them
- Rotate the camera by holding the right mouse button down and moving your mouse

> **&#9432;** If your computer has both a dedicated and an onboard GPU, make sure to use the dedicated GPU. On Windows with a dedicated Nvidia GPU, you can do this by right clicking on Replanetizer.exe and selecting "Run with graphics processor" -> "High performance NVIDIA processor".
# Building

Dependencies:
Expand Down
8 changes: 8 additions & 0 deletions Replanetizer/Frames/LevelFrame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,14 @@ void LoadLevelTextures()
textureIds.Add(t, new GLTexture(t));
}
}

foreach (List<Texture> textures in level.mobyloadTextures)
{
foreach (Texture t in textures)
{
textureIds.Add(t, new GLTexture(t));
}
}
}

private void LoadLevel(Level level)
Expand Down
Loading

0 comments on commit 46cd7c6

Please sign in to comment.