diff --git a/src/SA3D.Modeling/Mesh/Chunk/ChunkTypeExtensions.cs b/src/SA3D.Modeling/Mesh/Chunk/ChunkTypeExtensions.cs index 2427a1f..bfdf95e 100644 --- a/src/SA3D.Modeling/Mesh/Chunk/ChunkTypeExtensions.cs +++ b/src/SA3D.Modeling/Mesh/Chunk/ChunkTypeExtensions.cs @@ -115,18 +115,6 @@ public static bool CheckHasWeights(this VertexChunkType type) or VertexChunkType.NormalAttributes; } - /// - /// Checks whether a vertex chunktype has diffuse colors - /// - /// The type to check. - /// - public static bool CheckStripHasColor(this PolyChunkType type) - { - return type is PolyChunkType.Strip_Color - or PolyChunkType.Strip_TexColor - or PolyChunkType.Strip_HDTexColor; - } - /// /// Returns the number of 4-byte values a chunk vertex has. /// @@ -167,5 +155,89 @@ public static ushort GetIntegerSize(this VertexChunkType type) throw new ArgumentException($"Invalid vertex chunk type: {type}", nameof(type)); } } + + + /// + /// Checks whether a polychunk type is a type of strip chunk. + /// + /// The type to check. + public static bool CheckIsStrip(this PolyChunkType type) + { + return (int)type >= _strip && type <= PolyChunkType.Strip_HDTexDouble; + } + + /// + /// Returns the number of texture coordinate sets by strip chunk type. + ///
Throws an error if is not a strip chunk type. + ///
+ /// Type to get the strip chunk texture coordinate set count of. + public static int GetStripTexCoordCount(this PolyChunkType type) + { + if(!type.CheckIsStrip()) + { + throw new ArgumentException($"Polychunk type \"{type}\" is not a strip chunk type!", nameof(type)); + } + else if(type is PolyChunkType.Strip_Tex + or PolyChunkType.Strip_HDTex + or PolyChunkType.Strip_TexNormal + or PolyChunkType.Strip_HDTexNormal + or PolyChunkType.Strip_TexColor + or PolyChunkType.Strip_HDTexColor) + { + return 1; + } + else if(type is PolyChunkType.Strip_TexDouble + or PolyChunkType.Strip_HDTexDouble) + { + return 2; + } + else + { + return 0; + } + } + + /// + /// Checks whether a strip chunk type contains HD texture coordinates. + ///
Throws an error if is not a strip chunk type. + ///
+ /// Type to check + public static bool CheckStripHasHDTexcoords(this PolyChunkType type) + { + return !type.CheckIsStrip() + ? throw new ArgumentException($"Polychunk type \"{type}\" is not a strip chunk type!", nameof(type)) + : type is PolyChunkType.Strip_HDTex + or PolyChunkType.Strip_HDTexColor + or PolyChunkType.Strip_HDTexNormal + or PolyChunkType.Strip_HDTexDouble; + } + + /// + /// Checks whether a strip chunk type contains colors. + ///
Throws an error if is not a strip chunk type. + ///
+ /// Type to check + public static bool CheckStripHasColors(this PolyChunkType type) + { + return !type.CheckIsStrip() + ? throw new ArgumentException($"Polychunk type \"{type}\" is not a strip chunk type!", nameof(type)) + : type is PolyChunkType.Strip_Color + or PolyChunkType.Strip_TexColor + or PolyChunkType.Strip_HDTexColor; + } + + /// + /// Checks whether a strip chunk type contains normals. + ///
Throws an error if is not a strip chunk type. + ///
+ /// Type to check + public static bool CheckStripHasNormals(this PolyChunkType type) + { + return !type.CheckIsStrip() + ? throw new ArgumentException($"Polychunk type \"{type}\" is not a strip chunk type!", nameof(type)) + : type is PolyChunkType.Strip_Normal + or PolyChunkType.Strip_TexNormal + or PolyChunkType.Strip_HDTexNormal; + } } } diff --git a/src/SA3D.Modeling/Mesh/Chunk/PolyChunks/StripChunk.cs b/src/SA3D.Modeling/Mesh/Chunk/PolyChunks/StripChunk.cs index 5e07f5e..f87cbf4 100644 --- a/src/SA3D.Modeling/Mesh/Chunk/PolyChunks/StripChunk.cs +++ b/src/SA3D.Modeling/Mesh/Chunk/PolyChunks/StripChunk.cs @@ -17,55 +17,22 @@ public class StripChunk : SizedChunk /// /// The number of texture coordinate sets the polygons utilize. /// - public int TexcoordCount - { - get - { - if(Type is PolyChunkType.Strip_Tex - or PolyChunkType.Strip_HDTex - or PolyChunkType.Strip_TexNormal - or PolyChunkType.Strip_HDTexNormal - or PolyChunkType.Strip_TexColor - or PolyChunkType.Strip_HDTexColor) - { - return 1; - } - else if(Type is PolyChunkType.Strip_TexDouble - or PolyChunkType.Strip_HDTexDouble) - { - return 2; - } - else - { - return 0; - } - } - } + public int TexcoordCount => Type.GetStripTexCoordCount(); /// /// Whether texture coordinates are in the 0-1023 range, instead of 0-255. /// - public bool HasHDTexcoords => - Type is PolyChunkType.Strip_HDTex - or PolyChunkType.Strip_HDTexColor - or PolyChunkType.Strip_HDTexNormal - or PolyChunkType.Strip_HDTexDouble; + public bool HasHDTexcoords => Type.CheckStripHasHDTexcoords(); /// /// Whether polygons utilize normals. /// - public bool HasNormals => - Type is PolyChunkType.Strip_Normal - or PolyChunkType.Strip_TexNormal - or PolyChunkType.Strip_HDTexNormal; + public bool HasNormals => Type.CheckStripHasNormals(); /// /// Whether polygons utilize colors. /// - public bool HasColors => - Type is PolyChunkType.Strip_Color - or PolyChunkType.Strip_TexColor - or PolyChunkType.Strip_HDTexColor; + public bool HasColors => Type.CheckStripHasColors(); #endregion @@ -222,7 +189,7 @@ public override ushort Size { uint result = RawSize; - if(result > ushort.MaxValue) + if(result * 2 > ushort.MaxValue) { throw new InvalidOperationException($"Strip chunk size ({result}) exceeds maximum size ({ushort.MaxValue})."); } diff --git a/src/SA3D.Modeling/Mesh/Chunk/Structs/ChunkStrip.cs b/src/SA3D.Modeling/Mesh/Chunk/Structs/ChunkStrip.cs index d82223d..16535ba 100644 --- a/src/SA3D.Modeling/Mesh/Chunk/Structs/ChunkStrip.cs +++ b/src/SA3D.Modeling/Mesh/Chunk/Structs/ChunkStrip.cs @@ -9,6 +9,11 @@ namespace SA3D.Modeling.Mesh.Chunk.Structs /// public struct ChunkStrip : ICloneable { + /// + /// Maximum allowed size of a (collection of) strip chunk(s) + /// + public const uint MaxByteSize = ushort.MaxValue - 4; + /// /// Triangle corners. ///
The first two corners are only used for their index. diff --git a/src/SA3D.Modeling/Mesh/Converters/ChunkConverter.cs b/src/SA3D.Modeling/Mesh/Converters/ChunkConverter.cs index dacf9f0..d6f6018 100644 --- a/src/SA3D.Modeling/Mesh/Converters/ChunkConverter.cs +++ b/src/SA3D.Modeling/Mesh/Converters/ChunkConverter.cs @@ -548,14 +548,6 @@ protected override ChunkResult ConvertWeightless(WeightedMesh wba, bool optimize private static PolyChunk[] CreateStripChunk(ChunkCorner[] corners, BufferMaterial material, bool writeSpecular, byte texcoordPrecision) { - ChunkCorner[][] stripCorners = TriangleStrippifier.Global.StrippifyNoDegen(corners, out bool[] reversed); - ChunkStrip[] strips = new ChunkStrip[stripCorners.Length]; - - for(int i = 0; i < strips.Length; i++) - { - strips[i] = new(stripCorners[i], reversed[i]); - } - bool hasUV = material.UseTexture && !material.NormalMapping; PolyChunkType stripType = !hasUV ? PolyChunkType.Strip_Blank @@ -563,16 +555,47 @@ private static PolyChunk[] CreateStripChunk(ChunkCorner[] corners, BufferMateria ? PolyChunkType.Strip_HDTex : PolyChunkType.Strip_Tex; - StripChunk stripchunk = new(stripType, strips, 0) + ChunkCorner[][] stripCorners = TriangleStrippifier.Global.StrippifyNoDegen(corners, out bool[] reversed); + List stripCollections = []; + List currentStrips = []; + uint currentStripsSize = 0; + + int stripTexcoordCount = stripType.GetStripTexCoordCount(); + bool stripHasNormals = stripType.CheckStripHasNormals(); + bool stripHasColors = stripType.CheckStripHasColors(); + + for(int i = 0; i < stripCorners.Length; i++) { - FlatShading = material.Flat, - IgnoreAmbient = material.NoAmbient, - IgnoreLight = material.NoLighting, - IgnoreSpecular = material.NoSpecular, - EnvironmentMapping = material.NormalMapping, - UseAlpha = material.UseAlpha, - DoubleSide = !material.BackfaceCulling - }; + ChunkStrip strip = new(stripCorners[i], reversed[i]); + + uint stripSize = strip.Size(stripTexcoordCount, stripHasNormals, stripHasColors, 0); + if(currentStripsSize + stripSize > ChunkStrip.MaxByteSize) + { + currentStripsSize = 0; + stripCollections.Add([.. currentStrips]); + currentStrips.Clear(); + } + + currentStripsSize += stripSize; + currentStrips.Add(strip); + } + + stripCollections.Add([.. currentStrips]); + + StripChunk[] stripchunks = new StripChunk[stripCollections.Count]; + for(int i = 0; i < stripchunks.Length; i++) + { + stripchunks[i] = new(stripType, stripCollections[i], 0) + { + FlatShading = material.Flat, + IgnoreAmbient = material.NoAmbient, + IgnoreLight = material.NoLighting, + IgnoreSpecular = material.NoSpecular, + EnvironmentMapping = material.NormalMapping, + UseAlpha = material.UseAlpha, + DoubleSide = !material.BackfaceCulling + }; + } TextureChunk textureChunk = new() { @@ -599,7 +622,7 @@ private static PolyChunk[] CreateStripChunk(ChunkCorner[] corners, BufferMateria materialChunk.SpecularExponent = (byte)material.SpecularExponent; } - return new PolyChunk[] { materialChunk, textureChunk, stripchunk }; + return [materialChunk, textureChunk, .. stripchunks]; } protected override void CorrectSpace(Attach attach, Matrix4x4 vertexMatrix, Matrix4x4 normalMatrix) diff --git a/src/SA3D.Modeling/PublicAPI/net8.0/PublicAPI.Shipped.txt b/src/SA3D.Modeling/PublicAPI/net8.0/PublicAPI.Shipped.txt index 8a65d26..dac5358 100644 --- a/src/SA3D.Modeling/PublicAPI/net8.0/PublicAPI.Shipped.txt +++ b/src/SA3D.Modeling/PublicAPI/net8.0/PublicAPI.Shipped.txt @@ -1846,7 +1846,6 @@ static SA3D.Modeling.Mesh.Chunk.ChunkTypeExtensions.CheckHasSpecularColor(this S static SA3D.Modeling.Mesh.Chunk.ChunkTypeExtensions.CheckHasWeights(this SA3D.Modeling.Mesh.Chunk.VertexChunkType type) -> bool static SA3D.Modeling.Mesh.Chunk.ChunkTypeExtensions.CheckIsNormal32(this SA3D.Modeling.Mesh.Chunk.VertexChunkType type) -> bool static SA3D.Modeling.Mesh.Chunk.ChunkTypeExtensions.CheckIsVec4(this SA3D.Modeling.Mesh.Chunk.VertexChunkType type) -> bool -static SA3D.Modeling.Mesh.Chunk.ChunkTypeExtensions.CheckStripHasColor(this SA3D.Modeling.Mesh.Chunk.PolyChunkType type) -> bool static SA3D.Modeling.Mesh.Chunk.ChunkTypeExtensions.GetIntegerSize(this SA3D.Modeling.Mesh.Chunk.VertexChunkType type) -> ushort static SA3D.Modeling.Mesh.Chunk.PolyChunk.Read(SA3D.Common.IO.EndianStackReader! reader, ref uint address, SA3D.Modeling.Structs.PointerLUT! lut) -> SA3D.Modeling.Mesh.Chunk.PolyChunk! static SA3D.Modeling.Mesh.Chunk.PolyChunk.ReadArray(SA3D.Common.IO.EndianStackReader! reader, uint address, SA3D.Modeling.Structs.PointerLUT! lut) -> SA3D.Modeling.Mesh.Chunk.PolyChunk?[]! diff --git a/src/SA3D.Modeling/PublicAPI/net8.0/PublicAPI.Unshipped.txt b/src/SA3D.Modeling/PublicAPI/net8.0/PublicAPI.Unshipped.txt index 6ca9704..02a07a0 100644 --- a/src/SA3D.Modeling/PublicAPI/net8.0/PublicAPI.Unshipped.txt +++ b/src/SA3D.Modeling/PublicAPI/net8.0/PublicAPI.Unshipped.txt @@ -1,2 +1,8 @@ -SA3D.Modeling.Mesh.Weighted.WeightedMesh.ToAttach(SA3D.Modeling.Mesh.AttachFormat format, bool optimize, out int[]?[]! vertexMapping) -> SA3D.Modeling.Mesh.Attach! +const SA3D.Modeling.Mesh.Chunk.Structs.ChunkStrip.MaxByteSize = 65531 -> uint +SA3D.Modeling.Mesh.Weighted.WeightedMesh.ToAttach(SA3D.Modeling.Mesh.AttachFormat format, bool optimize, out int[]?[]! vertexMapping) -> SA3D.Modeling.Mesh.Attach! +static SA3D.Modeling.Mesh.Chunk.ChunkTypeExtensions.CheckIsStrip(this SA3D.Modeling.Mesh.Chunk.PolyChunkType type) -> bool +static SA3D.Modeling.Mesh.Chunk.ChunkTypeExtensions.CheckStripHasColors(this SA3D.Modeling.Mesh.Chunk.PolyChunkType type) -> bool +static SA3D.Modeling.Mesh.Chunk.ChunkTypeExtensions.CheckStripHasHDTexcoords(this SA3D.Modeling.Mesh.Chunk.PolyChunkType type) -> bool +static SA3D.Modeling.Mesh.Chunk.ChunkTypeExtensions.CheckStripHasNormals(this SA3D.Modeling.Mesh.Chunk.PolyChunkType type) -> bool +static SA3D.Modeling.Mesh.Chunk.ChunkTypeExtensions.GetStripTexCoordCount(this SA3D.Modeling.Mesh.Chunk.PolyChunkType type) -> int static SA3D.Modeling.Mesh.Weighted.WeightedMesh.ToModel(SA3D.Modeling.ObjectData.Node! model, SA3D.Modeling.Mesh.Weighted.WeightedMesh![]! meshes, SA3D.Modeling.Mesh.AttachFormat format, bool optimize, out int[]?[]! vertexMapping) -> void \ No newline at end of file