Skip to content

Commit

Permalink
Convert sprite storage to dictionaries (LostArtefacts#633)
Browse files Browse the repository at this point in the history
  • Loading branch information
lahm86 authored Apr 29, 2024
1 parent c025659 commit 5b45d14
Show file tree
Hide file tree
Showing 50 changed files with 529 additions and 558 deletions.
Binary file modified Deps/TRGE.Coord.dll
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -9,63 +9,35 @@ public class EMConvertSpriteSequenceFunction : BaseEMFunction

public override void ApplyToLevel(TR1Level level)
{
ConvertSpriteSequence(level.SpriteSequences);
UpdateSpriteEntities(level.Entities);
ConvertSpriteSequence(level.Sprites, level.Entities);
}

public override void ApplyToLevel(TR2Level level)
{
ConvertSpriteSequence(level.SpriteSequences);
UpdateSpriteEntities(level.Entities);
ConvertSpriteSequence(level.Sprites, level.Entities);
}

public override void ApplyToLevel(TR3Level level)
{
ConvertSpriteSequence(level.SpriteSequences);
UpdateSpriteEntities(level.Entities);
ConvertSpriteSequence(level.Sprites, level.Entities);
}

private void ConvertSpriteSequence(List<TRSpriteSequence> sequences)
private void ConvertSpriteSequence<T, E>(TRDictionary<T, TRSpriteSequence> sequences, List<E> entities)
where T : Enum
where E : TREntity<T>
{
if (sequences.Find(s => s.SpriteID == NewSpriteID) == null)
T oldID = (T)(object)OldSpriteID;
T newID = (T)(object)NewSpriteID;
if (!sequences.ChangeKey(oldID, newID))
{
TRSpriteSequence oldSequence = sequences.Find(s => s.SpriteID == OldSpriteID);
if (oldSequence != null)
{
oldSequence.SpriteID = NewSpriteID;
}
}
}

private void UpdateSpriteEntities(List<TR1Entity> entities)
{
foreach (TR1Entity entity in entities)
{
if (entity.TypeID == (TR1Type)OldSpriteID)
{
entity.TypeID = (TR1Type)NewSpriteID;
}
return;
}
}

private void UpdateSpriteEntities(IEnumerable<TR2Entity> entities)
{
foreach (TR2Entity entity in entities)
{
if (entity.TypeID == (TR2Type)OldSpriteID)
{
entity.TypeID = (TR2Type)NewSpriteID;
}
}
}

private void UpdateSpriteEntities(IEnumerable<TR3Entity> entities)
{
foreach (TR3Entity entity in entities)
foreach (E entity in entities)
{
if (entity.TypeID == (TR3Type)OldSpriteID)
if (EqualityComparer<T>.Default.Equals(entity.TypeID, oldID))
{
entity.TypeID = (TR3Type)NewSpriteID;
entity.TypeID = newID;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,29 @@ public class EMCopySpriteSequenceFunction : BaseEMFunction

public override void ApplyToLevel(TR1Level level)
{
CopySpriteSequence(level.SpriteSequences);
CopySpriteSequence(level.Sprites);
}

public override void ApplyToLevel(TR2Level level)
{
CopySpriteSequence(level.SpriteSequences);
CopySpriteSequence(level.Sprites);
}

public override void ApplyToLevel(TR3Level level)
{
CopySpriteSequence(level.SpriteSequences);
CopySpriteSequence(level.Sprites);
}

private void CopySpriteSequence(List<TRSpriteSequence> sequences)
private void CopySpriteSequence<T>(TRDictionary<T, TRSpriteSequence> sequences)
where T : Enum
{
TRSpriteSequence baseSequence = sequences.Find(s => s.SpriteID == BaseSpriteID);
TRSpriteSequence targetSequence = sequences.Find(s => s.SpriteID == TargetSpriteID);

if (baseSequence != null && targetSequence == null)
T baseID = (T)(object)BaseSpriteID;
T targetID = (T)(object)TargetSpriteID;
if (!sequences.ContainsKey(baseID) || sequences.ContainsKey(targetID))
{
sequences.Add(new()
{
NegativeLength = baseSequence.NegativeLength,
Offset = baseSequence.Offset,
SpriteID = TargetSpriteID
});
return;
}

sequences[targetID] = sequences[baseID];
}
}
8 changes: 8 additions & 0 deletions TRLevelControl/Build/ISpriteProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace TRLevelControl.Build;

public interface ISpriteProvider<T>
where T : Enum
{
public short GetSpriteOffset(T type);
public T FindSpriteType(short textureOffset);
}
111 changes: 111 additions & 0 deletions TRLevelControl/Build/TRSpriteBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
using System.Diagnostics;
using TRLevelControl.Model;

namespace TRLevelControl.Build;

public class TRSpriteBuilder<T> : ISpriteProvider<T>
where T : Enum
{
private static readonly string _sprMarker = "SPR";

private readonly TRGameVersion _version;
private Dictionary<T, short> _spriteOffsets;

public TRSpriteBuilder(TRGameVersion version)
{
_version = version;
}

public TRDictionary<T, TRSpriteSequence> ReadSprites(TRLevelReader reader)
{
if (_version >= TRGameVersion.TR4)
{
string sprMarker = new(reader.ReadChars(_sprMarker.Length));
Debug.Assert(sprMarker == _sprMarker);
Debug.Assert(_version != TRGameVersion.TR5 || reader.ReadByte() == 0);
}

uint numTextures = reader.ReadUInt32();
List<TRSpriteTexture> textures = reader.ReadSpriteTextures(numTextures, _version);

uint numSpriteSequences = reader.ReadUInt32();
TRDictionary<T, TRSpriteSequence> sprites = new();

for (int i = 0; i < numSpriteSequences; i++)
{
TRSpriteSequence sequence = new()
{
Textures = new()
};
sprites[(T)(object)(uint)reader.ReadInt32()] = sequence;

short negativeLength = reader.ReadInt16();
short offset = reader.ReadInt16();
for (int j = 0; j < -negativeLength; j++)
{
sequence.Textures.Add(textures[offset + j]);
}
}

CacheSpriteOffsets(sprites);
return sprites;
}

public void WriteSprites(TRLevelWriter writer, TRDictionary<T, TRSpriteSequence> sprites)
{
if (_version >= TRGameVersion.TR4)
{
writer.Write(_sprMarker.ToCharArray());
if (_version == TRGameVersion.TR5)
{
writer.Write((byte)0);
}
}

List<TRSpriteTexture> textures = sprites.Values
.SelectMany(s => s.Textures)
.ToList();

writer.Write((uint)textures.Count);
writer.Write(textures, _version);

writer.Write((uint)sprites.Count);
foreach (T spriteID in sprites.Keys)
{
TRSpriteSequence sequence = sprites[spriteID];
uint id = (uint)(object)spriteID;
writer.Write((int)id);
writer.Write((short)-sequence.Textures.Count);
writer.Write(GetSpriteOffset(spriteID));
}
}

public void CacheSpriteOffsets(TRDictionary<T, TRSpriteSequence> spriteSequences)
{
_spriteOffsets = new();
short offset = 0;
foreach (var (type, sequence) in spriteSequences)
{
_spriteOffsets[type] = offset;
offset += (short)sequence.Textures.Count;
}
}

public T FindSpriteType(short textureOffset)
{
foreach (var (type, offset) in _spriteOffsets)
{
if (offset == textureOffset)
{
return type;
}
}

throw new IndexOutOfRangeException();
}

public short GetSpriteOffset(T type)
{
return _spriteOffsets[type];
}
}
32 changes: 15 additions & 17 deletions TRLevelControl/Control/TR1LevelControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ namespace TRLevelControl;
public class TR1LevelControl : TRLevelControlBase<TR1Level>
{
private readonly TRObjectMeshBuilder _meshBuilder;
private readonly TRSpriteBuilder<TR1Type> _spriteBuilder;

public TR1LevelControl(ITRLevelObserver observer = null)
: base(observer)
{
_meshBuilder = new(TRGameVersion.TR1, _observer);
_spriteBuilder = new(TRGameVersion.TR1);
}

protected override TR1Level CreateLevel(TRFileVersion version)
Expand Down Expand Up @@ -120,19 +122,7 @@ protected override void Read(TRLevelReader reader)
_level.ObjectTextures.Add(TR2FileReadUtilities.ReadObjectTexture(reader));
}

uint numSpriteTextures = reader.ReadUInt32();
_level.SpriteTextures = new();
for (int i = 0; i < numSpriteTextures; i++)
{
_level.SpriteTextures.Add(TR2FileReadUtilities.ReadSpriteTexture(reader));
}

uint numSpriteSequences = reader.ReadUInt32();
_level.SpriteSequences = new();
for (int i = 0; i < numSpriteSequences; i++)
{
_level.SpriteSequences.Add(TR2FileReadUtilities.ReadSpriteSequence(reader));
}
ReadSprites(reader);

//Cameras
uint numCameras = reader.ReadUInt32();
Expand Down Expand Up @@ -200,6 +190,7 @@ protected override void Write(TRLevelWriter writer)

writer.Write(_level.Version.LevelNumber);

_spriteBuilder.CacheSpriteOffsets(_level.Sprites);
writer.Write((ushort)_level.Rooms.Count);
foreach (TR1Room room in _level.Rooms) { writer.Write(room.Serialize()); }

Expand All @@ -213,10 +204,7 @@ protected override void Write(TRLevelWriter writer)

writer.Write((uint)_level.ObjectTextures.Count);
foreach (TRObjectTexture tex in _level.ObjectTextures) { writer.Write(tex.Serialize()); }
writer.Write((uint)_level.SpriteTextures.Count);
foreach (TRSpriteTexture tex in _level.SpriteTextures) { writer.Write(tex.Serialize()); }
writer.Write((uint)_level.SpriteSequences.Count);
foreach (TRSpriteSequence sequence in _level.SpriteSequences) { writer.Write(sequence.Serialize()); }
WriteSprites(writer);

writer.Write((uint)_level.Cameras.Count);
foreach (TRCamera cam in _level.Cameras) { writer.Write(cam.Serialize()); }
Expand Down Expand Up @@ -284,6 +272,16 @@ private void WriteStaticMeshes(TRLevelWriter writer)
_meshBuilder.WriteStaticMeshes(writer, _level.StaticMeshes);
}

private void ReadSprites(TRLevelReader reader)
{
_level.Sprites = _spriteBuilder.ReadSprites(reader);
}

private void WriteSprites(TRLevelWriter writer)
{
_spriteBuilder.WriteSprites(writer, _level.Sprites);
}

private static TR1RoomData ConvertToRoomData(TR1Room room)
{
int RoomDataOffset = 0;
Expand Down
32 changes: 15 additions & 17 deletions TRLevelControl/Control/TR2LevelControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ namespace TRLevelControl;
public class TR2LevelControl : TRLevelControlBase<TR2Level>
{
private readonly TRObjectMeshBuilder _meshBuilder;
private readonly TRSpriteBuilder<TR2Type> _spriteBuilder;

public TR2LevelControl(ITRLevelObserver observer = null)
: base(observer)
{
_meshBuilder = new(TRGameVersion.TR2, _observer);
_spriteBuilder = new(TRGameVersion.TR2);
}

protected override TR2Level CreateLevel(TRFileVersion version)
Expand Down Expand Up @@ -128,19 +130,7 @@ protected override void Read(TRLevelReader reader)
_level.ObjectTextures.Add(TR2FileReadUtilities.ReadObjectTexture(reader));
}

uint numSpriteTextures = reader.ReadUInt32();
_level.SpriteTextures = new();
for (int i = 0; i < numSpriteTextures; i++)
{
_level.SpriteTextures.Add(TR2FileReadUtilities.ReadSpriteTexture(reader));
}

uint numSpriteSequences = reader.ReadUInt32();
_level.SpriteSequences = new();
for (int i = 0; i < numSpriteSequences; i++)
{
_level.SpriteSequences.Add(TR2FileReadUtilities.ReadSpriteSequence(reader));
}
ReadSprites(reader);

uint numCameras = reader.ReadUInt32();
_level.Cameras = new();
Expand Down Expand Up @@ -213,6 +203,7 @@ protected override void Write(TRLevelWriter writer)

writer.Write(_level.Version.LevelNumber);

_spriteBuilder.CacheSpriteOffsets(_level.Sprites);
writer.Write((ushort)_level.Rooms.Count);
foreach (TR2Room room in _level.Rooms) { writer.Write(room.Serialize()); }

Expand All @@ -226,10 +217,7 @@ protected override void Write(TRLevelWriter writer)

writer.Write((uint)_level.ObjectTextures.Count);
foreach (TRObjectTexture tex in _level.ObjectTextures) { writer.Write(tex.Serialize()); }
writer.Write((uint)_level.SpriteTextures.Count);
foreach (TRSpriteTexture tex in _level.SpriteTextures) { writer.Write(tex.Serialize()); }
writer.Write((uint)_level.SpriteSequences.Count);
foreach (TRSpriteSequence sequence in _level.SpriteSequences) { writer.Write(sequence.Serialize()); }
WriteSprites(writer);

writer.Write((uint)_level.Cameras.Count);
foreach (TRCamera cam in _level.Cameras) { writer.Write(cam.Serialize()); }
Expand Down Expand Up @@ -295,6 +283,16 @@ private void WriteStaticMeshes(TRLevelWriter writer)
_meshBuilder.WriteStaticMeshes(writer, _level.StaticMeshes);
}

private void ReadSprites(TRLevelReader reader)
{
_level.Sprites = _spriteBuilder.ReadSprites(reader);
}

private void WriteSprites(TRLevelWriter writer)
{
_spriteBuilder.WriteSprites(writer, _level.Sprites);
}

private static TR2RoomData ConvertToRoomData(TR2Room room)
{
int RoomDataOffset = 0;
Expand Down
Loading

0 comments on commit 5b45d14

Please sign in to comment.