diff --git a/Directory.Packages.props b/Directory.Packages.props index 785906a..b81cd74 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -2,8 +2,8 @@ true false - 10.0.7 - 12.0.2 + 10.0.8 + 12.0.4 diff --git a/src/010 Templates/clm.bt b/src/010 Templates/clm.bt new file mode 100644 index 0000000..6c7ff6d --- /dev/null +++ b/src/010 Templates/clm.bt @@ -0,0 +1,35 @@ +//-------------------------------------- +//--- 010 Editor v15.0.1 Binary Template +// +// File: clm.bt +// Author: Petar Tasev +// Revision: 1 +// Purpose: Label Ego Engine clm files +//-------------------------------------- +LittleEndian(); +SetBackColor(cLtGray); +// Compressed Light Map +// Supports RD:G and D2 for now + +// MapHeader +float offsetX; +float offsetZ; +float scaleX; +float scaleZ; +uint32 mapSize; +uint32 tileWidth; + +struct MapCell { + uint32 subOffset; + int8 cellData[100]; + + local int32 i = 0; + local int32 val ; + for (i = 0; i < 100; ++i) { + val = cellData[i]; + if (val < 0) { + FSeek(~val * 0x68 + subOffset); + struct MapCell subCell; + } + } +} firstCell; diff --git a/src/010 Templates/ornaments.bt b/src/010 Templates/ornaments.bt index 0bbe993..bd01acd 100644 --- a/src/010 Templates/ornaments.bt +++ b/src/010 Templates/ornaments.bt @@ -10,12 +10,12 @@ // ID Bytes: // History: //------------------------------------------------ -local ubyte isDirt2 = 0; // D2, F1 2011 - 2014 +local ubyte isDirt2 = 1; // D2, F1 2011 - 2014 local ubyte isF12010 = 0; local ubyte isDirt3 = 0; local ubyte isDirtShowdown = 0; local ubyte isGrid2 = 0; -local ubyte isGridAutosport = 1; // GA, Dirt Rally +local ubyte isGridAutosport = 0; // GA, Dirt Rally SetBackColor(cLtGray); int32 version; diff --git a/src/010 Templates/pssg.bt b/src/010 Templates/pssg.bt index d169abd..2cf60a9 100644 --- a/src/010 Templates/pssg.bt +++ b/src/010 Templates/pssg.bt @@ -81,6 +81,7 @@ struct NODE { case "SHADERINPUT": case "TEXTUREIMAGEBLOCKDATA": case "TRANSFORM": + case "SHADERPROGRAMCODEBLOCK": char data[end - FTell()] ; break; default: diff --git a/src/010 Templates/trees.bt b/src/010 Templates/trees.bt new file mode 100644 index 0000000..2b7510d --- /dev/null +++ b/src/010 Templates/trees.bt @@ -0,0 +1,103 @@ +//------------------------------------------------ +//--- 010 Editor v12.0.1 Binary Template +// +// File: +// Authors: +// Version: +// Purpose: trees.bin in tracks +// Category: +// File Mask: +// ID Bytes: +// History: +//------------------------------------------------ +local ubyte isDirt2 = 0; // D2, F1 2010 - 2014 +local ubyte isDirt3 = 0; // D3, DShowdown, G2 +local ubyte isGridAutosport = 0; // GA, DRally +SetBackColor(cLtGray); + +if (isDirt3 || isGridAutosport) { + int32 version; + int32 instanceListOffset; + int32 numInstanceList; +} +else +{ + local int32 instanceListOffset = 0; + local int32 numInstanceList = 1; +} + +FSeek(instanceListOffset); +struct InstanceList { +float boundsMin[3]; +float boundsMax[3]; +if (isDirt3 || isGridAutosport) { + int32 referenceNum; +} +int32 totalInstances; // aka instanceNum +if (isDirt2 || isDirt3 || isGridAutosport) +{ + int32 totalLandmarks; // does not exist in RD: Grid +} +int32 instanceRefOffset; +int32 numInstanceRef; +if (isDirt3 || isGridAutosport) { + int32 instanceOffset; + int32 numInstance; +} + +FSeek(instanceRefOffset); +struct InstanceRef { + int32 fileNameOffset; + if (isDirt3 || isGridAutosport) { + int32 referenceId; + } + float boundsMin[3]; + float boundsMax[3]; + if (isDirt3 || isGridAutosport) { + int32 distant; + int32 maxInstances; + local int32 numInstances = 0; + } + else { + int32 maxInstances; + int32 offset; // index offset into total instance list + int32 instancesOffset; + int32 numInstances; + int32 distant; + } + + if (numInstances <= 0) { + return; + } + + local int64 pos = FTell(); + FSeek(instancesOffset); + struct Instance { + float transform[12]; + ubyte color[4]; + if (isDirt2) { + float shadowFactor; + int32 dynamic; + int32 landmark; + } + } instances[numInstances] ; + FSeek(pos); +} instanceRefs[numInstanceRef] ; + +if (isDirt3 || isGridAutosport) { +FSeek(instanceOffset); +struct Instance2 { + int32 referenceId; + int32 instanceId; + float transform[12]; + ubyte color[4]; + float shadowFactor; + int32 dynamic; + int32 landmark; + int32 instanceTag; + if (isGridAutosport) { + int32 todSpecificOffset; + } +} instances[numInstance] ; +} +} instanceLists[numInstanceList] ; diff --git a/src/EgoEngineLibrary/Formats/Pssg/RenderDataSourceReader.cs b/src/EgoEngineLibrary/Formats/Pssg/RenderDataSourceReader.cs index 94e5a07..63d34c2 100644 --- a/src/EgoEngineLibrary/Formats/Pssg/RenderDataSourceReader.cs +++ b/src/EgoEngineLibrary/Formats/Pssg/RenderDataSourceReader.cs @@ -231,6 +231,8 @@ public Vector3 GetNormal(uint index) return ReadVector3(data); case "half4": // just read Vec3, pretty sure 4th item is just 1.0 return ReadVectorHalf3(data); + case "hend3n": + return ReadHend3N(data); default: throw new NotImplementedException($"Support for {attribute.Name} data type {attribute.DataType} is not implemented."); } @@ -256,6 +258,8 @@ public Vector4 GetTangent(uint index) return ReadVectorHalf4(data); case "float3": return new Vector4(ReadVector3(data), 0); + case "hend3n": + return new Vector4(ReadHend3N(data), 0); default: throw new NotImplementedException($"Support for {attribute.Name} data type {attribute.DataType} is not implemented."); } @@ -281,6 +285,8 @@ public Vector4 GetBinormal(uint index) return ReadVectorHalf4(data); case "float3": return new Vector4(ReadVector3(data), 0); + case "hend3n": + return new Vector4(ReadHend3N(data), 0); default: throw new NotImplementedException($"Support for {attribute.Name} data type {attribute.DataType} is not implemented."); } @@ -339,6 +345,8 @@ public Vector4 GetColor(uint index) { case "uint_color_argb": return UnpackArgbColor(BinaryPrimitives.ReadUInt32BigEndian(data)); + case "uchar4": + return UnpackRgbaColor(BinaryPrimitives.ReadUInt32BigEndian(data)); default: throw new NotImplementedException($"Support for {attribute.Name} data type {attribute.DataType} is not implemented."); } @@ -356,6 +364,15 @@ static Vector4 UnpackArgbColor(uint color) ((color >> 24) & 0xFF) / (float)byte.MaxValue, ((color >> 0) & 0xFF) / (float)byte.MaxValue); } + + static Vector4 UnpackRgbaColor(uint color) + { + return new Vector4( + ((color >> 0) & 0xFF) / (float)byte.MaxValue, + ((color >> 8) & 0xFF) / (float)byte.MaxValue, + ((color >> 16) & 0xFF) / (float)byte.MaxValue, + ((color >> 24) & 0xFF) / (float)byte.MaxValue); + } } private static Vector3 ReadVector3(ReadOnlySpan data) @@ -378,37 +395,45 @@ private static Vector2 ReadVector2(ReadOnlySpan data) private static Vector4 ReadVectorHalf4(ReadOnlySpan data) { var vec = new Vector4(); - vec.X = (float)BigToHalf(data); - vec.Y = (float)BigToHalf(data.Slice(2)); - vec.Z = (float)BigToHalf(data.Slice(4)); - vec.W = (float)BigToHalf(data.Slice(6)); + vec.X = (float)BinaryPrimitives.ReadHalfBigEndian(data); + vec.Y = (float)BinaryPrimitives.ReadHalfBigEndian(data[2..]); + vec.Z = (float)BinaryPrimitives.ReadHalfBigEndian(data[4..]); + vec.W = (float)BinaryPrimitives.ReadHalfBigEndian(data[6..]); return vec; } private static Vector3 ReadVectorHalf3(ReadOnlySpan data) { var vec = new Vector3(); - vec.X = (float)BigToHalf(data); - vec.Y = (float)BigToHalf(data.Slice(2)); - vec.Z = (float)BigToHalf(data.Slice(4)); + vec.X = (float)BinaryPrimitives.ReadHalfBigEndian(data); + vec.Y = (float)BinaryPrimitives.ReadHalfBigEndian(data[2..]); + vec.Z = (float)BinaryPrimitives.ReadHalfBigEndian(data[4..]); return vec; } private static Vector2 ReadVectorHalf2(ReadOnlySpan data) { var vec = new Vector2(); - vec.X = (float)BigToHalf(data); - vec.Y = (float)BigToHalf(data.Slice(2)); + vec.X = (float)BinaryPrimitives.ReadHalfBigEndian(data); + vec.Y = (float)BinaryPrimitives.ReadHalfBigEndian(data[2..]); return vec; } - - static Half BigToHalf(ReadOnlySpan source) + + private static Vector3 ReadHend3N(ReadOnlySpan data) { - return Int16BitsToHalf(BinaryPrimitives.ReadInt16BigEndian(source)); - } - static unsafe Half Int16BitsToHalf(short value) - { - return *(Half*)&value; + // 11 11 10 bit signed values + var i = BinaryPrimitives.ReadUInt32BigEndian(data); + var y = i >> 11; + var z = i >> 22; + + // use shift to sign extend + var vec = new Vector3 + { + X = (((int)(i & 0x7FF)) << 21 >> 21) / (float)0x3FF, + Y = (((int)(y & 0x7FF)) << 21 >> 21) / (float)0x3FF, + Z = (((int)(z & 0x3FF)) << 22 >> 22) / (float)0x1FF + }; + return vec; } } } diff --git a/src/EgoEngineLibrary/Formats/Pssg/RenderDataSourceWriter.cs b/src/EgoEngineLibrary/Formats/Pssg/RenderDataSourceWriter.cs index cd1c85d..33010a5 100644 --- a/src/EgoEngineLibrary/Formats/Pssg/RenderDataSourceWriter.cs +++ b/src/EgoEngineLibrary/Formats/Pssg/RenderDataSourceWriter.cs @@ -245,6 +245,9 @@ private void WriteNormal(ShaderVertexInputInfo vi, uint elementIndex, Span case "half4": WriteVectorHalf4(destination, new Vector4(value, 1)); break; + case "hend3n": + WriteHend3N(destination, value); + break; default: throw new NotImplementedException($"Support for {vi.Name} data type {vi.DataType} is not implemented."); } @@ -262,6 +265,9 @@ private void WriteTangent(ShaderVertexInputInfo vi, uint elementIndex, Span case "uint_color_argb": BinaryPrimitives.WriteUInt32BigEndian(destination, PackArgbColor(value)); break; + case "uchar4": + BinaryPrimitives.WriteUInt32BigEndian(destination, PackRgbaColor(value)); + break; default: throw new NotImplementedException($"Support for {vi.Name} data type {vi.DataType} is not implemented."); } + return; + static uint PackArgbColor(Vector4 vector) { Vector4 MaxBytes = new Vector4(byte.MaxValue); @@ -346,6 +360,17 @@ static uint PackArgbColor(Vector4 vector) return (uint)((((byte)vector.W) << 0) | (((byte)vector.X) << 8) | (((byte)vector.Y) << 16) | (((byte)vector.Z) << 24)); } + + static uint PackRgbaColor(Vector4 vector) + { + Vector4 MaxBytes = new Vector4(byte.MaxValue); + Vector4 Half = new Vector4(0.5f); + vector *= MaxBytes; + vector += Half; + vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); + + return (uint)((((byte)vector.X) << 0) | (((byte)vector.Y) << 8) | (((byte)vector.Z) << 16) | (((byte)vector.W) << 24)); + } } private void WriteSkinIndex(ShaderVertexInputInfo vi, uint elementIndex, Span destination) @@ -377,25 +402,27 @@ private static void WriteVector2(Span destination, Vector2 value) private static void WriteVectorHalf2(Span destination, Vector2 value) { - WriteHalfBigEndian(destination, (Half)value.X); - WriteHalfBigEndian(destination.Slice(2), (Half)value.Y); + BinaryPrimitives.WriteHalfBigEndian(destination, (Half)value.X); + BinaryPrimitives.WriteHalfBigEndian(destination.Slice(2), (Half)value.Y); } private static void WriteVectorHalf4(Span destination, Vector4 value) { - WriteHalfBigEndian(destination, (Half)value.X); - WriteHalfBigEndian(destination.Slice(2), (Half)value.Y); - WriteHalfBigEndian(destination.Slice(4), (Half)value.Z); - WriteHalfBigEndian(destination.Slice(6), (Half)value.W); + BinaryPrimitives.WriteHalfBigEndian(destination, (Half)value.X); + BinaryPrimitives.WriteHalfBigEndian(destination.Slice(2), (Half)value.Y); + BinaryPrimitives.WriteHalfBigEndian(destination.Slice(4), (Half)value.Z); + BinaryPrimitives.WriteHalfBigEndian(destination.Slice(6), (Half)value.W); } - private static void WriteHalfBigEndian(Span destination, Half value) - { - BinaryPrimitives.WriteInt16BigEndian(destination, HalfToInt16Bits(value)); - } - private static unsafe short HalfToInt16Bits(Half value) + private static void WriteHend3N(Span destination, Vector3 value) { - return *(short*)&value; + // 11 11 10 bit signed values + // Shift up to capture sign bit, then unsigned shift back + var x = ((int)(float.Clamp(value.X, -1, 1) * 0x3FF)) << 21 >>> 21; + var y = ((int)(float.Clamp(value.Y, -1, 1) * 0x3FF)) << 21 >>> 21; + var z = ((int)(float.Clamp(value.Z, -1, 1) * 0x1FF)) << 22 >>> 22; + uint val = (uint)x | ((uint)y << 11) | ((uint)z << 22); + BinaryPrimitives.WriteUInt32BigEndian(destination, val); } } } diff --git a/src/EgoEngineLibrary/Graphics/Pssg/Elements/PssgShaderProgramCode.cs b/src/EgoEngineLibrary/Graphics/Pssg/Elements/PssgShaderProgramCode.cs index 5aa3bdf..3a42ea1 100644 --- a/src/EgoEngineLibrary/Graphics/Pssg/Elements/PssgShaderProgramCode.cs +++ b/src/EgoEngineLibrary/Graphics/Pssg/Elements/PssgShaderProgramCode.cs @@ -11,7 +11,7 @@ public class PssgShaderProgramCode : PssgElement new PssgSchemaAttribute("codeType", PssgAttributeType.String), new PssgSchemaAttribute("profileType", PssgAttributeType.Int), new PssgSchemaAttribute("profile", PssgAttributeType.Int), - new PssgSchemaAttribute("codeEntry", PssgAttributeType.Int), + new PssgSchemaAttribute("codeEntry", PssgAttributeType.String), new PssgSchemaAttribute("parameterCount", PssgAttributeType.Int), new PssgSchemaAttribute("streamCount", PssgAttributeType.Int), } @@ -41,9 +41,9 @@ public uint Profile set => AddAttribute(Schema.Attributes[3].Name, value); } - public byte CodeEntry + public string CodeEntry { - get => GetAttributeValue(Schema.Attributes[4].Name); + get => GetAttributeValue(Schema.Attributes[4].Name); set => AddAttribute(Schema.Attributes[4].Name, value); } diff --git a/src/EgoEngineLibrary/Graphics/Pssg/PssgBinaryReader.cs b/src/EgoEngineLibrary/Graphics/Pssg/PssgBinaryReader.cs index fc6e563..2eb6a57 100644 --- a/src/EgoEngineLibrary/Graphics/Pssg/PssgBinaryReader.cs +++ b/src/EgoEngineLibrary/Graphics/Pssg/PssgBinaryReader.cs @@ -1,6 +1,4 @@ using System.Numerics; -using System.Text; -using EgoEngineLibrary.Collections; using EgoEngineLibrary.Conversion; using EgoEngineLibrary.IO; @@ -8,8 +6,8 @@ namespace EgoEngineLibrary.Graphics.Pssg { public class PssgBinaryReader : EndianBinaryReader { - public OrderedSet ElementTable { get; set; } - public OrderedSet AttributeTable { get; set; } + public List ElementTable { get; set; } + public List AttributeTable { get; set; } internal bool UseDataElementCheck { get; set; } public PssgBinaryReader(EndianBitConverter bitConvertor, Stream stream, bool leaveOpen) diff --git a/src/EgoEngineLibrary/Graphics/Pssg/PssgFile.cs b/src/EgoEngineLibrary/Graphics/Pssg/PssgFile.cs index 8901bdb..95dae6d 100644 --- a/src/EgoEngineLibrary/Graphics/Pssg/PssgFile.cs +++ b/src/EgoEngineLibrary/Graphics/Pssg/PssgFile.cs @@ -132,8 +132,8 @@ public static PssgFile ReadPssg(Stream fileStream, PssgFileType fileType) } } - file._elementTable = reader.ElementTable; - file._attributeTable = reader.AttributeTable; + file._elementTable = new OrderedSet(reader.ElementTable); + file._attributeTable = new OrderedSet(reader.AttributeTable); } return file; diff --git a/src/EgoPssgEditor/App.axaml b/src/EgoPssgEditor/App.axaml index bcafe07..306222b 100644 --- a/src/EgoPssgEditor/App.axaml +++ b/src/EgoPssgEditor/App.axaml @@ -10,6 +10,13 @@ + +