Updated Dec3N XML conversion. Ported BoundGeometry.VerticesShrunk code from rageAm. Added Track2AnimUV shader param name

This commit is contained in:
dexy 2024-07-24 13:31:04 +10:00
parent b62162cf21
commit d0cdb1bd76
8 changed files with 394 additions and 80 deletions

View File

@ -4144,7 +4144,9 @@ namespace CodeWalker.GameFiles
} }
public void TestYfts() public void TestYfts()
{ {
bool xmltest = true;
bool savetest = false; bool savetest = false;
bool glasstest = false;
var errorfiles = new List<RpfEntry>(); var errorfiles = new List<RpfEntry>();
var sb = new StringBuilder(); var sb = new StringBuilder();
var flagdict = new Dictionary<uint, int>(); var flagdict = new Dictionary<uint, int>();
@ -4167,6 +4169,14 @@ namespace CodeWalker.GameFiles
UpdateStatus("Error! " + ex.ToString()); UpdateStatus("Error! " + ex.ToString());
errorfiles.Add(entry); errorfiles.Add(entry);
} }
if (xmltest && (yft != null) && (yft.Fragment != null))
{
var xml = YftXml.GetXml(yft);
var yft2 = XmlYft.GetYft(xml);//can't do full roundtrip here due to embedded textures
var xml2 = YftXml.GetXml(yft2);
if (xml != xml2)
{ }
}
if (savetest && (yft != null) && (yft.Fragment != null)) if (savetest && (yft != null) && (yft.Fragment != null))
{ {
var fentry = entry as RpfFileEntry; var fentry = entry as RpfFileEntry;
@ -4189,7 +4199,7 @@ namespace CodeWalker.GameFiles
} }
if (yft?.Fragment?.GlassWindows?.data_items != null) if (glasstest && (yft?.Fragment?.GlassWindows?.data_items != null))
{ {
var lastf = -1; var lastf = -1;
for (int i = 0; i < yft.Fragment.GlassWindows.data_items.Length; i++) for (int i = 0; i < yft.Fragment.GlassWindows.data_items.Length; i++)

View File

@ -3182,6 +3182,7 @@ namespace CodeWalker.GameFiles
topcloudthreshold = 1907493970, topcloudthreshold = 1907493970,
toplum = 2532426199, toplum = 2532426199,
totalelapsedtime = 3838297418, totalelapsedtime = 3838297418,
track2animuv = 3640659359,
trackanimuv = 3759799674, trackanimuv = 3759799674,
transcolor = 2460231751, transcolor = 2460231751,
transparentdstmapsampler = 2450925918, transparentdstmapsampler = 2450925918,

View File

@ -1248,13 +1248,13 @@ namespace CodeWalker.GameFiles
} }
} }
CalculateVertsShrunkByMargin();
CalculateOctants();
BuildMaterials(); BuildMaterials();
CalculateQuantum(); CalculateQuantum();
UpdateEdgeIndices(); UpdateEdgeIndices();
UpdateTriangleAreas(); UpdateTriangleAreas();
CalculateVertsShrunk();
//CalculateVertsShrunkByNormals();
CalculateOctants();
FileVFT = 1080226408; FileVFT = 1080226408;
} }
@ -1327,7 +1327,17 @@ namespace CodeWalker.GameFiles
} }
if (Materials != null) if (Materials != null)
{ {
MaterialsBlock = new ResourceSystemStructBlock<BoundMaterial_s>(Materials); var mats = Materials;
if (mats.Length < 4) //add padding to the array for writing if necessary
{
mats = new BoundMaterial_s[4];
for (int i = 0; i < Materials.Length; i++)
{
mats[i] = Materials[i];
}
}
MaterialsBlock = new ResourceSystemStructBlock<BoundMaterial_s>(mats);
list.Add(MaterialsBlock); list.Add(MaterialsBlock);
} }
if (MaterialColours != null) if (MaterialColours != null)
@ -1781,7 +1791,230 @@ namespace CodeWalker.GameFiles
} }
} }
public void CalculateVertsShrunkByMargin() public void CalculateVertsShrunk()
{
//this will also adjust the Margin if it can't successfully shrink!
//thanks to ranstar74
//https://github.com/ranstar74/rageAm/blob/master/projects/app/src/rage/physics/bounds/boundgeometry.cpp
if (Vertices == null) return;//must have existing vertices for this!
VerticesShrunk = null;
var size = Vector3.Abs(BoxMax - BoxMin) * 0.5f;
var margin = Math.Min(Math.Min(Math.Min(Margin, size.X), size.Y), size.Z);
while (margin > 1e-6f)
{
var verts = ShrinkPolysByMargin(margin); //try shrink by this margin, if successful, break out
var check = CheckShrunkPolys(verts);
if (check)
{
VerticesShrunk = verts;
break;
}
margin *= 0.5f;
}
if (VerticesShrunk == null)
{
CalculateVertsShrunkByNormals();//fallback case, just shrink by normals
return;
}
margin = Math.Max(margin, 0.025f);
//Margin = margin;//should we actually update this here?
var shrunkMin = BoxMin + margin - CenterGeom;
var shrunkMax = BoxMax - margin - CenterGeom;
for (int i = 0; i < VerticesShrunk.Length; i++)//make sure the shrunk vertices fit in the box. (usually shouldn't do anything)
{
var vertex = VerticesShrunk[i];
vertex = Vector3.Min(vertex, shrunkMax);
vertex = Vector3.Max(vertex, shrunkMin);
if (VerticesShrunk[i] != vertex)
{
VerticesShrunk[i] = vertex;
}
}
}
private Vector3[] ShrinkPolysByMargin(float margin)
{
var verts = new Vector3[Vertices.Length];
Array.Copy(Vertices, verts, Vertices.Length);
var vc = verts.Length;
var polyNormals = new Vector3[Polygons.Length];//precompute all the poly normals.
for (int polyIndex = 0; polyIndex < Polygons.Length; polyIndex++)
{
var tri = Polygons[polyIndex] as BoundPolygonTriangle;
if (tri == null) { continue; }//can only compute poly normals for triangles!
var vi1 = tri.vertIndex1;
var vi2 = tri.vertIndex2;
var vi3 = tri.vertIndex3;
if ((vi1 >= vc) || (vi2 >= vc) || (vi3 >= vc)) continue;//vertex index out of range!?
var v1 = Vertices[vi1];//test against non-shrunk triangle
var v2 = Vertices[vi2];
var v3 = Vertices[vi3];
polyNormals[polyIndex] = Vector3.Normalize(Vector3.Cross(v3 - v2, v1 - v2));
}
var normals = new Vector3[64];//first is current poly normal, and remaining are neighbours (assumes 63 neighbours is enough!)
var processedVertices = new uint[2048];//2048*32 = 65536 vertices max
var negMargin = -margin;
for (int polyIndex = 0; polyIndex < Polygons.Length; polyIndex++)
{
var tri = Polygons[polyIndex] as BoundPolygonTriangle;
if (tri == null) { continue; }
for (int polyVertexIndex = 0; polyVertexIndex < 3; polyVertexIndex++)
{
var vertexIndex = tri.GetVertexIndex(polyVertexIndex);
var bucket = vertexIndex >> 5;
var mask = 1u << (vertexIndex & 0x1F);
if ((processedVertices[bucket] & mask) != 0) continue;//already processed this vertex
processedVertices[bucket] |= mask;
var vertex = verts[vertexIndex];
var normal = polyNormals[polyIndex];
normals[0] = normal;//used for weighted normal computation
var averageNormal = normal;//compute average normal from surrounding polygons
var prevNeighbour = polyIndex;
var normalCount = 1;
var neighbourCount = 0;
var polyNeighbourIndex = (polyVertexIndex + 2) % 3;//find starting neighbour index
var neighbour = tri.GetEdgeIndex(polyNeighbourIndex);
if (neighbour < 0)
{
neighbour = tri.GetEdgeIndex(polyVertexIndex);
polyNeighbourIndex = polyVertexIndex;//is this needed?
}
while (neighbour >= 0)
{
var neighbourPoly = Polygons[neighbour] as BoundPolygonTriangle;
var neighbourNormal = polyNormals[neighbour];
averageNormal += neighbourNormal;
normals[neighbourCount + 1] = neighbourNormal;
normalCount++;
neighbourCount++;
var newNeighbour = -1;
if (neighbourPoly != null)
{
for (var j = 0; j < 3; j++)
{
var nextIndex = (j + 1) % 3;
var n = neighbourPoly.GetVertexIndex(nextIndex);
if (n == vertexIndex)
{
newNeighbour = neighbourPoly.GetEdgeIndex(j);
if (newNeighbour == prevNeighbour)
{
newNeighbour = neighbourPoly.GetEdgeIndex(nextIndex);
}
prevNeighbour = neighbour;
neighbour = newNeighbour;
break;
}
}
}
if (newNeighbour == polyIndex) break; //check the circle is closed and iterated all neighbours
if (neighbourCount >= 63) break;//too many neighbours! possibly a mesh error
}
averageNormal = Vector3.Normalize(averageNormal);
if (normalCount == 1)
{
verts[vertexIndex] = vertex + (normal * negMargin);
}
else if (normalCount == 2)
{
var cross = Vector3.Cross(normal, normals[1]);
var crossMagSq = cross.LengthSquared();
if (crossMagSq < 0.1f)//small angle between normals, just shrink by base normal
{
verts[vertexIndex] = vertex + (normal * negMargin);
continue;
}
var lengthInv = 1.0f / (float)Math.Sqrt(crossMagSq);//insert new normal to weighted set
normals[2] = cross * lengthInv;
normalCount = 3;
}
if (normalCount < 3) continue;
var neighbourNormalCount = normalCount - 1;
var shrunk = vertex + (averageNormal * negMargin);
for (var i = 0; i < neighbourNormalCount - 1; i++)//traverse and compute weighted normals
{
for (var j = 0; j < neighbourNormalCount - i - 1; j++)
{
for (var k = 0; k < neighbourNormalCount - j - i - 1; k++)
{
var normal1 = normals[i];
var normal2 = normals[i + j + 1];
var normal3 = normals[i + j + k + 2];
var cross23 = Vector3.Cross(normal2, normal3);
var dot = Vector3.Dot(normal1, cross23);
if (Math.Abs(dot) > 0.25f)//check only neighbours with large angle between neighbour normals and poly normal
{
var dotinv = 1.0f / dot;//normals with angle closer to 0.25 will contribute more to weighted normal
var cross31 = Vector3.Cross(normal3, normal1);
var cross12 = Vector3.Cross(normal1, normal2);
var newNormal = (cross23 + cross31 + cross12) * dotinv;//compute weighted normal
var newShrink = vertex + (newNormal * negMargin);
var toOld = shrunk - vertex;//choose shrunk vertex that is furthest from original vertex
var toNew = newShrink - vertex;
if (toNew.LengthSquared() > toOld.LengthSquared())
{
shrunk = newShrink;
}
}
}
}
}
verts[vertexIndex] = shrunk;
}
}
return verts;
}
private bool CheckShrunkPolys(Vector3[] verts)
{
bool rayIntersects(in Ray ray, ref Vector3 v1, ref Vector3 v2, ref Vector3 v3, float maxDist)
{
var hit = ray.Intersects(ref v1, ref v2, ref v3, out float dist);
return hit && (dist <= maxDist);
}
var vc = verts.Length;
if (vc != Vertices.Length) return false;//vertex count mismatch!?
for (var i = 0; i < vc; i++)
{
var vertex = Vertices[i];
var shrunkVertex = verts[i];
var segmentPos = shrunkVertex;
var segmentDir = vertex - shrunkVertex;
var segmentLength = segmentDir.Length();
if (segmentLength == 0) continue;//vertex wasn't shrunk!?
segmentDir *= (1.0f / segmentLength);
var segmentRay = new Ray(segmentPos, segmentDir);
for (int p = 0; p < Polygons.Length; p++)
{
var tri = Polygons[p] as BoundPolygonTriangle;
if (tri == null) { continue; }
var vi1 = tri.vertIndex1;
var vi2 = tri.vertIndex2;
var vi3 = tri.vertIndex3;
if ((vi1 >= vc) || (vi2 >= vc) || (vi3 >= vc)) return false;//vertex index out of range!?
if ((vi1 == i) || (vi2 == i) || (vi3 == i)) continue;//only test polys not using this vertex
var v1 = Vertices[vi1];//test against non-shrunk triangle
var v2 = Vertices[vi2];
var v3 = Vertices[vi3];
if (rayIntersects(segmentRay, ref v1, ref v2, ref v3, segmentLength)) return false;
var vs1 = verts[vi1];//test against shrunk triangle
var vs2 = verts[vi2];
var vs3 = verts[vi3];
if (rayIntersects(segmentRay, ref vs1, ref vs2, ref vs3, segmentLength)) return false;
}
}
return true;
}
public void CalculateVertsShrunkByNormals()
{ {
Vector3[] vertNormals = CalculateVertNormals(); Vector3[] vertNormals = CalculateVertNormals();
VerticesShrunk = new Vector3[Vertices.Length]; VerticesShrunk = new Vector3[Vertices.Length];
@ -1792,7 +2025,6 @@ namespace CodeWalker.GameFiles
VerticesShrunk[i] = Vertices[i] + normalShrunk; VerticesShrunk[i] = Vertices[i] + normalShrunk;
} }
} }
public Vector3[] CalculateVertNormals() public Vector3[] CalculateVertNormals()
{ {
Vector3[] vertNormals = new Vector3[Vertices.Length]; Vector3[] vertNormals = new Vector3[Vertices.Length];
@ -1825,7 +2057,8 @@ namespace CodeWalker.GameFiles
return vertNormals; return vertNormals;
} }
public void CalculateQuantum()
public void CalculateMinMax()
{ {
var min = new Vector3(float.MaxValue); var min = new Vector3(float.MaxValue);
var max = new Vector3(float.MinValue); var max = new Vector3(float.MinValue);
@ -1837,7 +2070,7 @@ namespace CodeWalker.GameFiles
max = Vector3.Max(max, v); max = Vector3.Max(max, v);
} }
} }
if (VerticesShrunk != null) if (VerticesShrunk != null)//this shouldn't be needed
{ {
foreach (var v in VerticesShrunk) foreach (var v in VerticesShrunk)
{ {
@ -1845,9 +2078,38 @@ namespace CodeWalker.GameFiles
max = Vector3.Max(max, v); max = Vector3.Max(max, v);
} }
} }
var maxsiz = Vector3.Max(min.Abs(), max.Abs()); if (min.X == float.MaxValue) min = Vector3.Zero;
var q = (maxsiz+Margin) / 32767.0f; if (max.X == float.MinValue) max = Vector3.Zero;
Quantum = q; BoxMin = min - Margin;
BoxMax = max + Margin;
}
public void CalculateQuantum()
{
Quantum = (BoxMax - BoxMin) * 0.5f / 32767.0f;
//var min = new Vector3(float.MaxValue);
//var max = new Vector3(float.MinValue);
//if (Vertices != null)
//{
// foreach (var v in Vertices)
// {
// min = Vector3.Min(min, v);
// max = Vector3.Max(max, v);
// }
//}
//if (VerticesShrunk != null)
//{
// foreach (var v in VerticesShrunk)
// {
// min = Vector3.Min(min, v);
// max = Vector3.Max(max, v);
// }
//}
//var maxsiz = Vector3.Max(min.Abs(), max.Abs());
//var q = (maxsiz+Margin) / 32767.0f;
//Quantum = q;
} }
public void BuildMaterials() public void BuildMaterials()
@ -1878,13 +2140,6 @@ namespace CodeWalker.GameFiles
} }
MaterialsCount = (byte)matlist.Count; MaterialsCount = (byte)matlist.Count;
//add padding to the array for writing
for (int i = matlist.Count; i < 4; i++)
{
matlist.Add(new BoundMaterial_s());
}
Materials = matlist.ToArray(); Materials = matlist.ToArray();
PolygonMaterialIndices = polymats.ToArray(); PolygonMaterialIndices = polymats.ToArray();
} }
@ -1918,49 +2173,49 @@ namespace CodeWalker.GameFiles
{ {
if (edge1.Triangle2 != null) if (edge1.Triangle2 != null)
{ {
btri.SetEdgeIndex(1, (short)edge1.Triangle1.Index); btri.SetEdgeIndex(0, edge1.Triangle1.Index);
} }
else else
{ {
edge1.Triangle2 = btri; edge1.Triangle2 = btri;
edge1.EdgeID2 = 1; edge1.EdgeID2 = 0;
} }
} }
else else
{ {
edgedict[e1] = new BoundEdge(btri, 1); edgedict[e1] = new BoundEdge(btri, 0);
} }
if (edgedict.TryGetValue(e2, out BoundEdge edge2)) if (edgedict.TryGetValue(e2, out BoundEdge edge2))
{ {
if (edge2.Triangle2 != null) if (edge2.Triangle2 != null)
{ {
btri.SetEdgeIndex(2, (short)edge2.Triangle1.Index); btri.SetEdgeIndex(1, edge2.Triangle1.Index);
} }
else else
{ {
edge2.Triangle2 = btri; edge2.Triangle2 = btri;
edge2.EdgeID2 = 2; edge2.EdgeID2 = 1;
} }
} }
else else
{ {
edgedict[e2] = new BoundEdge(btri, 2); edgedict[e2] = new BoundEdge(btri, 1);
} }
if (edgedict.TryGetValue(e3, out BoundEdge edge3)) if (edgedict.TryGetValue(e3, out BoundEdge edge3))
{ {
if (edge3.Triangle2 != null) if (edge3.Triangle2 != null)
{ {
btri.SetEdgeIndex(3, (short)edge3.Triangle1.Index); btri.SetEdgeIndex(2, edge3.Triangle1.Index);
} }
else else
{ {
edge3.Triangle2 = btri; edge3.Triangle2 = btri;
edge3.EdgeID2 = 3; edge3.EdgeID2 = 2;
} }
} }
else else
{ {
edgedict[e3] = new BoundEdge(btri, 3); edgedict[e3] = new BoundEdge(btri, 2);
} }
} }
@ -1981,8 +2236,8 @@ namespace CodeWalker.GameFiles
} }
else else
{ {
edge.Triangle1.SetEdgeIndex(edge.EdgeID1, (short)edge.Triangle2.Index); edge.Triangle1.SetEdgeIndex(edge.EdgeID1, edge.Triangle2.Index);
edge.Triangle2.SetEdgeIndex(edge.EdgeID2, (short)edge.Triangle1.Index); edge.Triangle2.SetEdgeIndex(edge.EdgeID2, edge.Triangle1.Index);
} }
} }
@ -2045,12 +2300,12 @@ namespace CodeWalker.GameFiles
var poly = Polygons[i]; var poly = Polygons[i];
if (poly is BoundPolygonTriangle btri) if (poly is BoundPolygonTriangle btri)
{ {
if (btri.edgeIndex1 == idx) btri.edgeIndex1 = -1; if (btri.edgeIndex1 == idx) btri.edgeIndex1 = 0xFFFF;
if (btri.edgeIndex1 > idx) btri.edgeIndex1--; if ((btri.edgeIndex1 > idx) && (btri.edgeIndex1 != 0xFFFF)) btri.edgeIndex1--;
if (btri.edgeIndex2 == idx) btri.edgeIndex2 = -1; if (btri.edgeIndex2 == idx) btri.edgeIndex2 = 0xFFFF;
if (btri.edgeIndex2 > idx) btri.edgeIndex2--; if ((btri.edgeIndex2 > idx) && (btri.edgeIndex2 != 0xFFFF)) btri.edgeIndex2--;
if (btri.edgeIndex3 == idx) btri.edgeIndex3 = -1; if (btri.edgeIndex3 == idx) btri.edgeIndex3 = 0xFFFF;
if (btri.edgeIndex3 > idx) btri.edgeIndex3--; if ((btri.edgeIndex3 > idx) && (btri.edgeIndex3 != 0xFFFF)) btri.edgeIndex3--;
} }
poly.Index = i; poly.Index = i;
} }
@ -2363,7 +2618,7 @@ namespace CodeWalker.GameFiles
var newpolys = new BoundPolygon[items.Count]; var newpolys = new BoundPolygon[items.Count];
var newpolymats = new byte[items.Count]; var newpolymats = new byte[items.Count];
var itemlookup = new short[items.Count]; var itemlookup = new int[items.Count];
for (int i = 0; i < items.Count; i++) for (int i = 0; i < items.Count; i++)
{ {
var poly = items[i]?.Polygon; var poly = items[i]?.Polygon;
@ -2371,7 +2626,7 @@ namespace CodeWalker.GameFiles
{ {
if (poly.Index < itemlookup.Length) if (poly.Index < itemlookup.Length)
{ {
itemlookup[poly.Index] = (short)i; itemlookup[poly.Index] = i;
} }
else else
{ }//shouldn't happen { }//shouldn't happen
@ -2389,9 +2644,12 @@ namespace CodeWalker.GameFiles
poly.Index = i; poly.Index = i;
if (poly is BoundPolygonTriangle ptri) if (poly is BoundPolygonTriangle ptri)
{ {
ptri.edgeIndex1 = ((ptri.edgeIndex1 >= 0) && (ptri.edgeIndex1 < itemlookup.Length)) ? itemlookup[ptri.edgeIndex1] : (short)-1; var edgeIndex1 = ((ptri.edgeIndex1 >= 0) && (ptri.edgeIndex1 < itemlookup.Length)) ? itemlookup[ptri.edgeIndex1] : -1;
ptri.edgeIndex2 = ((ptri.edgeIndex2 >= 0) && (ptri.edgeIndex2 < itemlookup.Length)) ? itemlookup[ptri.edgeIndex2] : (short)-1; var edgeIndex2 = ((ptri.edgeIndex2 >= 0) && (ptri.edgeIndex2 < itemlookup.Length)) ? itemlookup[ptri.edgeIndex2] : -1;
ptri.edgeIndex3 = ((ptri.edgeIndex3 >= 0) && (ptri.edgeIndex3 < itemlookup.Length)) ? itemlookup[ptri.edgeIndex3] : (short)-1; var edgeIndex3 = ((ptri.edgeIndex3 >= 0) && (ptri.edgeIndex3 < itemlookup.Length)) ? itemlookup[ptri.edgeIndex3] : -1;
ptri.SetEdgeIndex(1, edgeIndex1);
ptri.SetEdgeIndex(2, edgeIndex2);
ptri.SetEdgeIndex(3, edgeIndex3);
} }
} }
} }
@ -3214,9 +3472,9 @@ namespace CodeWalker.GameFiles
public ushort triIndex1 { get; set; } public ushort triIndex1 { get; set; }
public ushort triIndex2 { get; set; } public ushort triIndex2 { get; set; }
public ushort triIndex3 { get; set; } public ushort triIndex3 { get; set; }
public short edgeIndex1 { get; set; } public ushort edgeIndex1 { get; set; }
public short edgeIndex2 { get; set; } public ushort edgeIndex2 { get; set; }
public short edgeIndex3 { get; set; } public ushort edgeIndex3 { get; set; }
public int vertIndex1 { get { return (triIndex1 & 0x7FFF); } set { triIndex1 = (ushort)((value & 0x7FFF) + (vertFlag1 ? 0x8000 : 0)); } } public int vertIndex1 { get { return (triIndex1 & 0x7FFF); } set { triIndex1 = (ushort)((value & 0x7FFF) + (vertFlag1 ? 0x8000 : 0)); } }
public int vertIndex2 { get { return (triIndex2 & 0x7FFF); } set { triIndex2 = (ushort)((value & 0x7FFF) + (vertFlag2 ? 0x8000 : 0)); } } public int vertIndex2 { get { return (triIndex2 & 0x7FFF); } set { triIndex2 = (ushort)((value & 0x7FFF) + (vertFlag2 ? 0x8000 : 0)); } }
@ -3358,29 +3616,61 @@ namespace CodeWalker.GameFiles
} }
} }
public void SetEdgeIndex(int edgeid, short polyindex) public int GetVertexIndex(int i)
{ {
switch (edgeid) switch (i)
{ {
case 1: default:
if (edgeIndex1 != polyindex) case 0: return vertIndex1;
case 1: return vertIndex2;
case 2: return vertIndex3;
}
}
public int GetEdgeIndex(int i)
{
switch (i)
{
default:
case 0: return UnpackEdgeIndex(edgeIndex1);
case 1: return UnpackEdgeIndex(edgeIndex2);
case 2: return UnpackEdgeIndex(edgeIndex3);
}
}
public void SetEdgeIndex(int i, int polyindex)
{
var e = PackEdgeIndex(polyindex);
switch (i)
{
case 0:
if (edgeIndex1 != e)
{ } { }
edgeIndex1 = polyindex; edgeIndex1 = e;
break;
case 1:
if (edgeIndex2 != e)
{ }
edgeIndex2 = e;
break; break;
case 2: case 2:
if (edgeIndex2 != polyindex) if (edgeIndex3 != e)
{ } { }
edgeIndex2 = polyindex; edgeIndex3 = e;
break;
case 3:
if (edgeIndex3 != polyindex)
{ }
edgeIndex3 = polyindex;
break; break;
default: default:
break; break;
} }
} }
public static ushort PackEdgeIndex(int polyIndex)
{
if (polyIndex < 0) return 0xFFFF;
if (polyIndex > 0xFFFF) return 0xFFFF;
return (ushort)polyIndex;
}
public static int UnpackEdgeIndex(ushort edgeIndex)
{
if (edgeIndex == 0xFFFF) return -1;
return (int)edgeIndex;
}
public BoundPolygonTriangle() public BoundPolygonTriangle()
{ {
@ -3392,9 +3682,9 @@ namespace CodeWalker.GameFiles
triIndex1 = BitConverter.ToUInt16(bytes, offset + 4); triIndex1 = BitConverter.ToUInt16(bytes, offset + 4);
triIndex2 = BitConverter.ToUInt16(bytes, offset + 6); triIndex2 = BitConverter.ToUInt16(bytes, offset + 6);
triIndex3 = BitConverter.ToUInt16(bytes, offset + 8); triIndex3 = BitConverter.ToUInt16(bytes, offset + 8);
edgeIndex1 = BitConverter.ToInt16(bytes, offset + 10); edgeIndex1 = BitConverter.ToUInt16(bytes, offset + 10);
edgeIndex2 = BitConverter.ToInt16(bytes, offset + 12); edgeIndex2 = BitConverter.ToUInt16(bytes, offset + 12);
edgeIndex3 = BitConverter.ToInt16(bytes, offset + 14); edgeIndex3 = BitConverter.ToUInt16(bytes, offset + 14);
} }
public override void Write(BinaryWriter bw) public override void Write(BinaryWriter bw)
{ {

View File

@ -3779,7 +3779,7 @@ namespace CodeWalker.GameFiles
case VertexComponentType.Float2: SetVector2(v, c, new Vector2(f(0), f(1))); break; case VertexComponentType.Float2: SetVector2(v, c, new Vector2(f(0), f(1))); break;
case VertexComponentType.Float3: SetVector3(v, c, new Vector3(f(0), f(1), f(2))); break; case VertexComponentType.Float3: SetVector3(v, c, new Vector3(f(0), f(1), f(2))); break;
case VertexComponentType.Float4: SetVector4(v, c, new Vector4(f(0), f(1), f(2), f(3))); break; case VertexComponentType.Float4: SetVector4(v, c, new Vector4(f(0), f(1), f(2), f(3))); break;
case VertexComponentType.Dec3N: SetDec3N(v, c, new Vector3(f(0), f(1), f(2))); break; case VertexComponentType.Dec3N: SetDec3N(v, c, new Vector4(f(0), f(1), f(2), f(3))); break;
case VertexComponentType.Half2: SetHalf2(v, c, new Half2(f(0), f(1))); break; case VertexComponentType.Half2: SetHalf2(v, c, new Half2(f(0), f(1))); break;
case VertexComponentType.Half4: SetHalf4(v, c, new Half4(f(0), f(1), f(2), f(3))); break; case VertexComponentType.Half4: SetHalf4(v, c, new Half4(f(0), f(1), f(2), f(3))); break;
case VertexComponentType.Colour: SetColour(v, c, new Color(b(0), b(1), b(2), b(3))); break; case VertexComponentType.Colour: SetColour(v, c, new Color(b(0), b(1), b(2), b(3))); break;
@ -3862,7 +3862,7 @@ namespace CodeWalker.GameFiles
} }
} }
} }
public void SetDec3N(int v, int c, Vector3 val) public void SetDec3N(int v, int c, Vector4 val)
{ {
//see https://docs.microsoft.com/en-us/previous-versions/windows/desktop/bb322868(v%3Dvs.85) //see https://docs.microsoft.com/en-us/previous-versions/windows/desktop/bb322868(v%3Dvs.85)
if ((Info != null) && (VertexBytes != null)) if ((Info != null) && (VertexBytes != null))
@ -3873,16 +3873,18 @@ namespace CodeWalker.GameFiles
var e = o + 4;//sizeof(Dec3N) var e = o + 4;//sizeof(Dec3N)
if (e <= VertexBytes.Length) if (e <= VertexBytes.Length)
{ {
var sx = (val.X < 0.0f); var sx = (val.X >= 0.0f);
var sy = (val.X < 0.0f); var sy = (val.Y >= 0.0f);
var sz = (val.X < 0.0f); var sz = (val.Z >= 0.0f);
var sw = (val.W >= 0.0f);
var x = Math.Min((uint)(Math.Abs(val.X) * 511.0f), 511); var x = Math.Min((uint)(Math.Abs(val.X) * 511.0f), 511);
var y = Math.Min((uint)(Math.Abs(val.Y) * 511.0f), 511); var y = Math.Min((uint)(Math.Abs(val.Y) * 511.0f), 511);
var z = Math.Min((uint)(Math.Abs(val.Z) * 511.0f), 511); var z = Math.Min((uint)(Math.Abs(val.Z) * 511.0f), 511);
var ux = ((sx ? ~x : x) & 0x1FF) + (sx ? 0x200 : 0); var w = Math.Min((uint)(val.W), 2);
var uy = ((sy ? ~y : y) & 0x1FF) + (sy ? 0x200 : 0); var ux = ((sx ? x : ~x) & 0x1FF) + (sx ? 0x200 : 0);
var uz = ((sz ? ~z : z) & 0x1FF) + (sz ? 0x200 : 0); var uy = ((sy ? y : ~y) & 0x1FF) + (sy ? 0x200 : 0);
var uw = 0u; var uz = ((sz ? z : ~z) & 0x1FF) + (sz ? 0x200 : 0);
var uw = sw ? w : 3;//(0,1,2)=>(0,1,2); (-1)=>(3)
var u = ux + (uy << 10) + (uz << 20) + (uw << 30); var u = ux + (uy << 10) + (uz << 20) + (uw << 30);
var b = BitConverter.GetBytes(u); var b = BitConverter.GetBytes(u);
Buffer.BlockCopy(b, 0, VertexBytes, o, 4); Buffer.BlockCopy(b, 0, VertexBytes, o, 4);
@ -3971,7 +3973,7 @@ namespace CodeWalker.GameFiles
case VertexComponentType.Float2: return FloatUtil.GetVector2String(GetVector2(v, c), d); case VertexComponentType.Float2: return FloatUtil.GetVector2String(GetVector2(v, c), d);
case VertexComponentType.Float3: return FloatUtil.GetVector3String(GetVector3(v, c), d); case VertexComponentType.Float3: return FloatUtil.GetVector3String(GetVector3(v, c), d);
case VertexComponentType.Float4: return FloatUtil.GetVector4String(GetVector4(v, c), d); case VertexComponentType.Float4: return FloatUtil.GetVector4String(GetVector4(v, c), d);
case VertexComponentType.Dec3N: return FloatUtil.GetVector3String(GetDec3N(v, c), d); case VertexComponentType.Dec3N: return FloatUtil.GetVector4String(GetDec3N(v, c), d);
case VertexComponentType.Half2: return FloatUtil.GetHalf2String(GetHalf2(v, c), d); case VertexComponentType.Half2: return FloatUtil.GetHalf2String(GetHalf2(v, c), d);
case VertexComponentType.Half4: return FloatUtil.GetHalf4String(GetHalf4(v, c), d); case VertexComponentType.Half4: return FloatUtil.GetHalf4String(GetHalf4(v, c), d);
case VertexComponentType.Colour: return FloatUtil.GetColourString(GetColour(v, c), d); case VertexComponentType.Colour: return FloatUtil.GetColourString(GetColour(v, c), d);
@ -4052,7 +4054,7 @@ namespace CodeWalker.GameFiles
} }
return Vector4.Zero; return Vector4.Zero;
} }
public Vector3 GetDec3N(int v, int c) public Vector4 GetDec3N(int v, int c)
{ {
//see https://docs.microsoft.com/en-us/previous-versions/windows/desktop/bb322868(v%3Dvs.85) //see https://docs.microsoft.com/en-us/previous-versions/windows/desktop/bb322868(v%3Dvs.85)
if ((Info != null) && (VertexBytes != null)) if ((Info != null) && (VertexBytes != null))
@ -4067,17 +4069,18 @@ namespace CodeWalker.GameFiles
var ux = (u >> 0) & 0x3FF; var ux = (u >> 0) & 0x3FF;
var uy = (u >> 10) & 0x3FF; var uy = (u >> 10) & 0x3FF;
var uz = (u >> 20) & 0x3FF; var uz = (u >> 20) & 0x3FF;
var uw = (u >> 30); var uw = (u >> 30) & 0x3;
var sx = (ux & 0x200) > 0; var sx = (ux & 0x200) > 0;
var sy = (uy & 0x200) > 0; var sy = (uy & 0x200) > 0;
var sz = (uz & 0x200) > 0; var sz = (uz & 0x200) > 0;
var x = ((sx ? ~ux : ux) & 0x1FF) / (sx ? -511.0f : 511.0f); var x = ((sx ? ux : ~ux) & 0x1FF) / (sx ? 511.0f : -511.0f);
var y = ((sy ? ~uy : uy) & 0x1FF) / (sy ? -511.0f : 511.0f); var y = ((sy ? uy : ~uy) & 0x1FF) / (sy ? 511.0f : -511.0f);
var z = ((sz ? ~uz : uz) & 0x1FF) / (sz ? -511.0f : 511.0f); var z = ((sz ? uz : ~uz) & 0x1FF) / (sz ? 511.0f : -511.0f);
return new Vector3(x, y, z); var w = (uw == 3) ? -1.0f : uw;//(0,1,2)=>(0,1,2); (3)=>(-1)
return new Vector4(x, y, z, w);
} }
} }
return Vector3.Zero; return Vector4.Zero;
} }
public Half2 GetHalf2(int v, int c) public Half2 GetHalf2(int v, int c)
{ {

View File

@ -512,6 +512,10 @@ namespace CodeWalker.GameFiles
} }
LightAttributes = new ResourceSimpleList64<LightAttributes>(); LightAttributes = new ResourceSimpleList64<LightAttributes>();
LightAttributes.data_items = XmlMeta.ReadItemArray<LightAttributes>(node, "Lights"); LightAttributes.data_items = XmlMeta.ReadItemArray<LightAttributes>(node, "Lights");
if (LightAttributes.data_items == null)
{
LightAttributes.data_items = new LightAttributes[0];
}
Cloths = new ResourcePointerList64<EnvironmentCloth>(); Cloths = new ResourcePointerList64<EnvironmentCloth>();
var cnode = node.SelectSingleNode("Cloths"); var cnode = node.SelectSingleNode("Cloths");
if (cnode != null) if (cnode != null)
@ -526,6 +530,10 @@ namespace CodeWalker.GameFiles
v.ReadXml(inode, ddsfolder); v.ReadXml(inode, ddsfolder);
vlist.Add(v); vlist.Add(v);
if (v.Drawable != null)
{
v.Drawable.OwnerCloth = v;
}
if (Drawable == null) if (Drawable == null)
{ {
Drawable = v.Drawable; Drawable = v.Drawable;
@ -2898,6 +2906,7 @@ namespace CodeWalker.GameFiles
{ {
var type = Xml.GetEnumValue<FragJointType>(Xml.GetStringAttribute(jnode, "type")); var type = Xml.GetEnumValue<FragJointType>(Xml.GetStringAttribute(jnode, "type"));
var j = FragPhysJointType.Create(type); var j = FragPhysJointType.Create(type);
j.Type = type;
j?.ReadXml(jnode); j?.ReadXml(jnode);
jlist.Add(j); jlist.Add(j);
} }

View File

@ -1315,6 +1315,7 @@ namespace CodeWalker.GameFiles
topLum = 2532426199, topLum = 2532426199,
TotalElapsedTime = 3838297418, TotalElapsedTime = 3838297418,
TrackAnimUV = 3759799674, TrackAnimUV = 3759799674,
Track2AnimUV = 3640659359,
TransColor = 2460231751, TransColor = 2460231751,
TransparentDstMapSampler = 2450925918, TransparentDstMapSampler = 2450925918,
TransparentSrcMap = 2768420156, TransparentSrcMap = 2768420156,

View File

@ -62,7 +62,7 @@ namespace CodeWalker.GameFiles
case VertexComponentType.Float4: return 4; case VertexComponentType.Float4: return 4;
case VertexComponentType.UByte4: return 4; case VertexComponentType.UByte4: return 4;
case VertexComponentType.Colour: return 4; case VertexComponentType.Colour: return 4;
case VertexComponentType.Dec3N: return 3; case VertexComponentType.Dec3N: return 4;
default: return 0; default: return 0;
} }
} }

View File

@ -4346,9 +4346,9 @@ namespace CodeWalker.Project
if (ptri != null) if (ptri != null)
{ {
ptri.edgeIndex1 = -1; ptri.edgeIndex1 = 0xFFFF;
ptri.edgeIndex2 = -1; ptri.edgeIndex2 = 0xFFFF;
ptri.edgeIndex3 = -1; ptri.edgeIndex3 = 0xFFFF;
} }
if (copy != null) if (copy != null)