Skip to content

Commit

Permalink
Added texcoord precision level to weighted meshes
Browse files Browse the repository at this point in the history
  • Loading branch information
Justin113D committed Dec 4, 2023
1 parent 3065a61 commit 1458a25
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 8 deletions.
14 changes: 9 additions & 5 deletions src/SA3D.Modeling/Mesh/Converters/ChunkConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ private static ChunkResult ConvertWeightedBinaryColored(WeightedMesh wba)
corners[j].Index = (ushort)sortedVertMap[index];
}

polyChunks.AddRange(CreateStripChunk(corners, wba.Materials[i], wba.WriteSpecular));
polyChunks.AddRange(CreateStripChunk(corners, wba.Materials[i], wba.WriteSpecular, wba.TexcoordPrecisionLevel));
}

// assemble the attaches
Expand Down Expand Up @@ -392,7 +392,7 @@ private static ChunkResult ConvertWeighted(WeightedMesh wba)
corners[j].Texcoord = bc.Texcoord;
}

polyChunks.AddRange(CreateStripChunk(corners, wba.Materials[i], wba.WriteSpecular));
polyChunks.AddRange(CreateStripChunk(corners, wba.Materials[i], wba.WriteSpecular, wba.TexcoordPrecisionLevel));
}

// assemble the attaches
Expand Down Expand Up @@ -518,7 +518,7 @@ protected override ChunkResult ConvertWeightless(WeightedMesh wba, bool optimize
List<PolyChunk> polyChunks = new();
for(int i = 0; i < cornerSets.Length; i++)
{
polyChunks.AddRange(CreateStripChunk(cornerSets[i], wba.Materials[i], wba.WriteSpecular));
polyChunks.AddRange(CreateStripChunk(cornerSets[i], wba.Materials[i], wba.WriteSpecular, wba.TexcoordPrecisionLevel));
}

return new(
Expand All @@ -533,7 +533,7 @@ protected override ChunkResult ConvertWeightless(WeightedMesh wba, bool optimize
});
}

private static PolyChunk[] CreateStripChunk(ChunkCorner[] corners, BufferMaterial material, bool writeSpecular)
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];
Expand All @@ -544,7 +544,11 @@ private static PolyChunk[] CreateStripChunk(ChunkCorner[] corners, BufferMateria
}

bool hasUV = material.UseTexture && !material.NormalMapping;
PolyChunkType stripType = hasUV ? PolyChunkType.Strip_Tex : PolyChunkType.Strip_Blank;
PolyChunkType stripType = !hasUV
? PolyChunkType.Strip_Blank
: texcoordPrecision >= 2
? PolyChunkType.Strip_HDTex
: PolyChunkType.Strip_Tex;

StripChunk stripchunk = new(stripType, strips, 0)
{
Expand Down
14 changes: 11 additions & 3 deletions src/SA3D.Modeling/Mesh/Converters/GCConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public static void ConvertWeightedToGC(Node model, WeightedMesh[] meshData, bool
cornerCount += weightedMesh.TriangleSets[i].Length;
}

float uvFac = 1 << byte.Clamp(weightedMesh.TexcoordPrecisionLevel, 0, 7);
Vector2[] texcoordData = new Vector2[cornerCount];
Color[] colorData = new Color[cornerCount];
GCCorner[][] polygonData = new GCCorner[weightedMesh.TriangleSets.Length][];
Expand All @@ -59,7 +60,7 @@ public static void ConvertWeightedToGC(Node model, WeightedMesh[] meshData, bool
{
BufferCorner bcorner = bufferCorners[j];

texcoordData[cornerIndex] = bcorner.Texcoord;
texcoordData[cornerIndex] = bcorner.Texcoord * uvFac;
colorData[cornerIndex] = bcorner.Color;

meshCorners[j] = new GCCorner()
Expand Down Expand Up @@ -110,12 +111,19 @@ GCMesh ProcessBufferMesh(GCCorner[] corners, BufferMaterial material, ref Buffer

foreach(GCVertexSet set in vertexData)
{
parameters.Add(new GCVertexFormatParameter()
GCVertexFormatParameter param = new()
{
VertexType = set.Type,
VertexStructType = set.StructType,
VertexDataType = set.DataType
});
};

if(param.VertexType is >= GCVertexType.TexCoord0 and <= GCVertexType.TexCoord7)
{
param.Attributes = byte.Min(7, weightedMesh.TexcoordPrecisionLevel);
}

parameters.Add(param);

uint flag = 1u << ((int)set.Type * 2);

Expand Down
87 changes: 87 additions & 0 deletions src/SA3D.Modeling/Mesh/Weighted/WeightedMesh.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
using SA3D.Common.Lookup;
using SA3D.Modeling.Mesh.Buffer;
using SA3D.Modeling.Mesh.Converters;
using SA3D.Modeling.Mesh.Gamecube;
using SA3D.Modeling.Mesh.Gamecube.Enums;
using SA3D.Modeling.Mesh.Gamecube.Parameters;
using SA3D.Modeling.ObjectData;
using System;
using System.Collections.Generic;
Expand Down Expand Up @@ -66,6 +69,18 @@ public class WeightedMesh : ICloneable
/// </summary>
public bool WriteSpecular { get; set; }

/// <summary>
/// Texture coordinate precision level. Every level higher allows for double the previous precision, but also reduces range by half.
/// <br/> Supported:
/// <br/> - Basic: 0
/// <br/> - Chunk: 0 or 2
/// <br/> - Gamecube: 0-7
/// <br/> - Buffer: Unaffected
/// <br/>
/// <br/> When converting, the lowest supported precision is used.
/// </summary>
public byte TexcoordPrecisionLevel { get; set; }


internal WeightedMesh(
WeightedVertex[] vertices,
Expand Down Expand Up @@ -175,6 +190,11 @@ public static WeightedMesh FromAttach(Attach attach, BufferMode bufferMode)
public static WeightedMesh[] FromModel(Node model, BufferMode bufferMode)
{
AttachFormat? attachFormat = model.GetAttachFormat();
if(attachFormat == null)
{
return Array.Empty<WeightedMesh>();
}

bool hasWelding = model.GetTreeNodeEnumerable().Any(x => x.Welding != null);

WeightedMesh[] result;
Expand All @@ -200,12 +220,79 @@ public static WeightedMesh[] FromModel(Node model, BufferMode bufferMode)
}

result = ToWeightedConverter.ConvertToWeighted(model);
GetTexcoordPrecisionLevel(model, result, attachFormat.Value);
}

EnsurePolygonsValid(ref result);
return result;
}

private static void GetTexcoordPrecisionLevel(Node model, WeightedMesh[] meshes, AttachFormat format)
{
Node[] nodes = model.GetTreeNodes();

switch(format)
{
case AttachFormat.GC:
foreach(WeightedMesh mesh in meshes)
{
GCAttach atc = (GCAttach)nodes[mesh.RootIndices.First()].Attach!;

byte texcoordPrecision = 255;
if(atc.OpaqueMeshes.Length != 0)
{
GCVertexFormatParameter[] vtxParams = atc.OpaqueMeshes
.SelectMany(x => x.Parameters)
.Select(x => x)
.OfType<GCVertexFormatParameter>()
.Where(x => x.VertexType == GCVertexType.TexCoord0)
.ToArray();

if(vtxParams.Length != 1)
{
continue;
}

mesh.TexcoordPrecisionLevel = vtxParams[0].Attributes;
}

if(atc.TransparentMeshes.Length != 0)
{
GCVertexFormatParameter[] vtxParams = atc.TransparentMeshes
.SelectMany(x => x.Parameters)
.Select(x => x)
.OfType<GCVertexFormatParameter>()
.Where(x => x.VertexType == GCVertexType.TexCoord0)
.ToArray();

if(vtxParams.Length != 1)
{
continue;
}

byte newPrecision = vtxParams[0].Attributes;
if(texcoordPrecision == 255)
{
mesh.TexcoordPrecisionLevel = newPrecision;
}
else if(texcoordPrecision != newPrecision)
{
mesh.TexcoordPrecisionLevel = 0;
continue;
}
}
}

break;
case AttachFormat.CHUNK: // theoretically you can do it for chunk, but its very annoying
case AttachFormat.Buffer:
case AttachFormat.BASIC:
default:
break;
}

}

/// <summary>
/// Attempts to convert the weighted mesh to a standalone attach.
/// </summary>
Expand Down
2 changes: 2 additions & 0 deletions src/SA3D.Modeling/PublicAPI/net7.0/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ SA3D.Modeling.File.Structs.MetaWeightVertex.MetaWeightVertex() -> void
SA3D.Modeling.File.Structs.MetaWeightVertex.MetaWeightVertex(uint destinationVertexIndex, SA3D.Modeling.File.Structs.MetaWeight[]! weights) -> void
SA3D.Modeling.File.Structs.MetaWeightVertex.Weights.get -> SA3D.Modeling.File.Structs.MetaWeight[]!
SA3D.Modeling.File.Structs.MetaWeightVertex.Write(SA3D.Common.IO.EndianStackWriter! writer) -> void
SA3D.Modeling.Mesh.Weighted.WeightedMesh.TexcoordPrecisionLevel.get -> byte
SA3D.Modeling.Mesh.Weighted.WeightedMesh.TexcoordPrecisionLevel.set -> void
SA3D.Modeling.Mesh.Weighted.WeightedMesh.ToAttach(SA3D.Modeling.Mesh.AttachFormat format, bool optimize) -> SA3D.Modeling.Mesh.Attach!
SA3D.Modeling.ObjectData.Node.ClearWeldingsFromTree() -> void
SA3D.Modeling.ObjectData.Node.ConvertAttachFormat(SA3D.Modeling.Mesh.AttachFormat newAttachFormat, SA3D.Modeling.Mesh.Weighted.BufferMode bufferMode, bool optimize, bool forceUpdate = false, bool updateBuffer = false) -> void
Expand Down

0 comments on commit 1458a25

Please sign in to comment.