public ElementDescriptor(MDL0Object* polygon) { byte* pData = (byte*)polygon->DefList; byte* pCom; ElementDef* pDef; CPElementSpec UVATGroups; int format; //0 for direct, 1 for byte, 2 for short //Create remap table for vertex weights RemapTable = new int[polygon->_numVertices]; RemapSize = 0; Stride = 0; HasData = new bool[12]; Nodes = new ushort[16]; Commands = new byte[31]; Defs = new int[12]; _points = new List<List<Facepoint>>(); //Read element descriptor from polygon display list MDL0PolygonDefs* Definitons = (MDL0PolygonDefs*)polygon->DefList; int fmtLo = (int)Definitons->VtxFmtLo; int fmtHi = (int)Definitons->VtxFmtHi; UVATGroups = new CPElementSpec( (uint)Definitons->UVATA, (uint)Definitons->UVATB, (uint)Definitons->UVATC); //Build extract script. //What we're doing is assigning extract commands for elements in the polygon, in true order. //This allows us to process the polygon blindly, assuming that the definition is accurate. //Theoretically, this should offer a significant speed bonus. fixed (int* pDefData = Defs) fixed (byte* pComData = Commands) { pCom = pComData; pDef = (ElementDef*)pDefData; //Pos/Norm weight if (Weighted = (fmtLo & 1) != 0) { //Set the first command as the weight *pCom++ = (byte)DecodeOp.PosWeight; Stride++; //Increment stride by a byte (the length of the facepoints) } //Tex matrix for (int i = 0; i < 8; i++) if (((fmtLo >> (i + 1)) & 1) != 0) { //Set the command for each texture matrix *pCom++ = (byte)(DecodeOp.TexMtx0 + i); Stride++; //Increment stride by a byte (the length of the facepoints) } //Positions format = ((fmtLo >> 9) & 3) - 1; if (format >= 0) { HasData[0] = true; //Set the definitions input pDef->Format = (byte)format; //Set the type to Positions pDef->Type = 0; if (format == 0) { int f = (int)UVATGroups.PositionDef.DataFormat; //Clamp format to even value and add length to stride Stride += f.RoundDownToEven().Clamp(1, 4) * (!UVATGroups.PositionDef.IsSpecial ? 2 : 3); pDef->Scale = (byte)UVATGroups.PositionDef.Scale; pDef->Output = (byte)((!UVATGroups.PositionDef.IsSpecial ? (int)ElementCodec.CodecType.XY : (int)ElementCodec.CodecType.XYZ) + (byte)UVATGroups.PositionDef.DataFormat); *pCom++ = (byte)DecodeOp.ElementDirect; } else { Stride += format; //Add to stride (the length of the facepoints) pDef->Output = 12; //Set the output *pCom++ = (byte)DecodeOp.ElementIndexed; } pDef++; } //Normals format = ((fmtLo >> 11) & 3) - 1; if (format >= 0) { HasData[1] = true; //Set the definitions input pDef->Format = (byte)format; //Set the type to Normals pDef->Type = 1; if (format == 0) { int f = (int)UVATGroups.NormalDef.DataFormat; Stride += f.RoundDownToEven().Clamp(1, 4) * 3; pDef->Scale = (byte)UVATGroups.NormalDef.Scale; pDef->Output = (byte)(((int)ElementCodec.CodecType.XYZ) + (byte)UVATGroups.NormalDef.DataFormat); *pCom++ = (byte)DecodeOp.ElementDirect; } else { Stride += format; //Add to stride (the length of the facepoints) pDef->Output = 12; //Set the output *pCom++ = (byte)DecodeOp.ElementIndexed; } pDef++; } //Colors for (int i = 0; i < 2; i++) { format = ((fmtLo >> (i * 2 + 13)) & 3) - 1; if (format >= 0) { HasData[i + 2] = true; //Set the definitions input pDef->Format = (byte)format; //Set the type to Colors pDef->Type = (byte)(i + 2); if (format == 0) { //pDef->Output = pDef->Scale = 0; *pCom++ = (byte)DecodeOp.ElementDirect; } else { Stride += format; //Add to stride (the length of the facepoints) pDef->Output = 4; //Set the output *pCom++ = (byte)DecodeOp.ElementIndexed; } pDef++; } } //UVs for (int i = 0; i < 8; i++) { format = ((fmtHi >> (i * 2)) & 3) - 1; if (format >= 0) { HasData[i + 4] = true; //Set the definitions input pDef->Format = (byte)format; //Set the type to UVs pDef->Type = (byte)(i + 4); if (format == 0) { int f = (int)UVATGroups.GetUVDef(i).DataFormat; Stride += f.RoundDownToEven().Clamp(1, 4); pDef->Output = (byte)((!UVATGroups.GetUVDef(i).IsSpecial ? (int)ElementCodec.CodecType.S : (int)ElementCodec.CodecType.ST) + (byte)UVATGroups.GetUVDef(i).DataFormat); pDef->Scale = (byte)UVATGroups.GetUVDef(i).Scale; *pCom++ = (byte)DecodeOp.ElementDirect; } else { Stride += format; //Add to stride (the length of the facepoints) pDef->Output = 8; //Set the output *pCom++ = (byte)DecodeOp.ElementIndexed; } pDef++; } } *pCom = 0; } }
internal void ExtractPrimitives(MDL0Object* header, ref ElementDescriptor desc, byte** pOut, byte** pAssets) { int count; uint index = 0, temp; byte* pData = (byte*)header->PrimitiveData; byte* pTemp = (byte*)pData; ushort* indices = (ushort*)_indices.Address; IMatrixNode[] cache = _polygon.Model._linker.NodeCache; //Get element count for each primitive type int d3 = 0, d2 = 0, d1 = 0; uint p3 = 0, p2 = 0, p1 = 0; uint[] p1arr = null, p2arr = null, p3arr = null; bool newGroup = true; PrimitiveGroup group = new PrimitiveGroup(); ushort id; //Get counts for each primitive type, and assign face points NextPrimitive: byte cmd = *pTemp++; if (cmd <= 0x38 && cmd >= 0x20) { if (newGroup == false) { _polygon._primGroups.Add(group); group = new PrimitiveGroup() { _offset = (uint)((pTemp - 1) - pData) }; newGroup = true; } if (!group._nodes.Contains(id = *(bushort*)pTemp) && id != ushort.MaxValue) group._nodes.Add(id); } //Switch by primitive type and increment as well so we can read the count. switch ((GXListCommand)cmd) { //Fill weight cache case GXListCommand.LoadIndexA: //Positions group._nodeOffsets.Add(new NodeOffset((uint)(pTemp - pData) - group._offset, cache[*(bushort*)pTemp])); //Set weight node for facepoint extraction desc.SetNode(ref pTemp, (byte*)pData); goto NextPrimitive; case GXListCommand.LoadIndexB: //Normals case GXListCommand.LoadIndexC: //UVs group._nodeOffsets.Add(new NodeOffset((uint)(pTemp - pData) - group._offset, cache[*(bushort*)pTemp])); pTemp += 4; //Skip goto NextPrimitive; case GXListCommand.LoadIndexD: //Lights Console.WriteLine("There are lights in here!"); pTemp += 4; //Skip goto NextPrimitive; case GXListCommand.DrawQuads: if (newGroup == true) newGroup = false; d3 += (count = *(bushort*)pTemp) / 2 * 3; group._headers.Add(new PrimitiveHeader() { Type = WiiPrimitiveType.Quads, Entries = (ushort)count }); break; case GXListCommand.DrawTriangles: if (newGroup == true) newGroup = false; d3 += (count = *(bushort*)pTemp); group._headers.Add(new PrimitiveHeader() { Type = WiiPrimitiveType.TriangleList, Entries = (ushort)count }); break; case GXListCommand.DrawTriangleFan: if (newGroup == true) newGroup = false; d3 += ((count = *(bushort*)pTemp) - 2) * 3; group._headers.Add(new PrimitiveHeader() { Type = WiiPrimitiveType.TriangleFan, Entries = (ushort)count }); break; case GXListCommand.DrawTriangleStrip: if (newGroup == true) newGroup = false; d3 += ((count = *(bushort*)pTemp) - 2) * 3; group._headers.Add(new PrimitiveHeader() { Type = WiiPrimitiveType.TriangleStrip, Entries = (ushort)count }); break; case GXListCommand.DrawLines: if (newGroup == true) newGroup = false; d2 += (count = *(bushort*)pTemp); group._headers.Add(new PrimitiveHeader() { Type = WiiPrimitiveType.Lines, Entries = (ushort)count }); break; case GXListCommand.DrawLineStrip: if (newGroup == true) newGroup = false; d2 += ((count = *(bushort*)pTemp) - 1) * 2; group._headers.Add(new PrimitiveHeader() { Type = WiiPrimitiveType.LineStrip, Entries = (ushort)count }); break; case GXListCommand.DrawPoints: if (newGroup == true) newGroup = false; d1 += (count = *(bushort*)pTemp); group._headers.Add(new PrimitiveHeader() { Type = WiiPrimitiveType.Points, Entries = (ushort)count }); break; default: _polygon._primGroups.Add(group); goto Next; //No more primitives. } pTemp += 2; //Extract facepoints here! desc.Run(ref pTemp, pAssets, pOut, count, group, ref indices, _polygon.Model._linker.NodeCache); goto NextPrimitive; Next: //Create primitives if (d3 > 0) { _triangles = new NewPrimitive(d3, BeginMode.Triangles); p3arr = _triangles._indices; } else _triangles = null; if (d2 > 0) { _lines = new NewPrimitive(d2, BeginMode.Lines); p2arr = _lines._indices; } else _lines = null; if (d1 > 0) { _points = new NewPrimitive(d1, BeginMode.Points); p1arr = _points._indices; } else _points = null; //Extract indices in reverse order, this way we get CCW winding. Top: switch ((GXListCommand)(*pData++)) { case GXListCommand.LoadIndexA: case GXListCommand.LoadIndexB: case GXListCommand.LoadIndexC: case GXListCommand.LoadIndexD: pData += 4; //Skip goto Top; case GXListCommand.DrawQuads: count = *(bushort*)pData; for (int i = 0; i < count; i += 4) { p3arr[p3++] = index; p3arr[p3++] = (uint)(index + 2); p3arr[p3++] = (uint)(index + 1); p3arr[p3++] = index; p3arr[p3++] = (uint)(index + 3); p3arr[p3++] = (uint)(index + 2); index += 4; } break; case GXListCommand.DrawTriangles: count = *(bushort*)pData; for (int i = 0; i < count; i += 3) { p3arr[p3++] = (uint)(index + 2); p3arr[p3++] = (uint)(index + 1); p3arr[p3++] = index; index += 3; } break; case GXListCommand.DrawTriangleFan: count = *(bushort*)pData; temp = index++; for (int i = 2; i < count; i++) { p3arr[p3++] = temp; p3arr[p3++] = (uint)(index + 1); p3arr[p3++] = index++; } index++; break; case GXListCommand.DrawTriangleStrip: count = *(bushort*)pData; index += 2; for (int i = 2; i < count; i++) { p3arr[p3++] = index; p3arr[p3++] = (uint)(index - 1 - (i & 1)); p3arr[p3++] = (uint)((index++) - 2 + (i & 1)); } break; case GXListCommand.DrawLines: count = *(bushort*)pData; for (int i = 0; i < count; i++) p2arr[p2++] = index++; break; case GXListCommand.DrawLineStrip: count = *(bushort*)pData; for (int i = 1; i < count; i++) { p2arr[p2++] = index++; p2arr[p2++] = index; } index++; break; case GXListCommand.DrawPoints: count = *(bushort*)pData; for (int i = 0; i < count; i++) p1arr[p1++] = index++; break; default: return; } pData += 2 + count * desc.Stride; goto Top; }
public void WriteVertexFormat(VertexAttributeFormat[] fmtList, MDL0Object* polygon) { //These are default values. uint posCnt = (int)GXCompCnt.PosXYZ; uint posType = (int)GXCompType.Float; uint posFrac = 0; uint nrmCnt = (int)GXCompCnt.NrmXYZ; uint nrmType = (int)GXCompType.Float; uint nrmId3 = 0; uint c0Cnt = (int)GXCompCnt.ClrRGBA; uint c0Type = (int)GXCompType.RGBA8; uint c1Cnt = (int)GXCompCnt.ClrRGBA; uint c1Type = (int)GXCompType.RGBA8; uint tx0Cnt = (int)GXCompCnt.TexST; uint tx0Type = (int)GXCompType.Float; uint tx0Frac = 0; uint tx1Cnt = (int)GXCompCnt.TexST; uint tx1Type = (int)GXCompType.Float; uint tx1Frac = 0; uint tx2Cnt = (int)GXCompCnt.TexST; uint tx2Type = (int)GXCompType.Float; uint tx2Frac = 0; uint tx3Cnt = (int)GXCompCnt.TexST; uint tx3Type = (int)GXCompType.Float; uint tx3Frac = 0; uint tx4Cnt = (int)GXCompCnt.TexST; uint tx4Type = (int)GXCompType.Float; uint tx4Frac = 0; uint tx5Cnt = (int)GXCompCnt.TexST; uint tx5Type = (int)GXCompType.Float; uint tx5Frac = 0; uint tx6Cnt = (int)GXCompCnt.TexST; uint tx6Type = (int)GXCompType.Float; uint tx6Frac = 0; uint tx7Cnt = (int)GXCompCnt.TexST; uint tx7Type = (int)GXCompType.Float; uint tx7Frac = 0; foreach (VertexAttributeFormat list in fmtList) switch (list._attr) { case GXAttribute.Position: posCnt = (uint)list._cnt; posType = (uint)list._type; posFrac = list._frac; break; case GXAttribute.Normal: case GXAttribute.NBT: nrmType = (uint)list._type; if (list._cnt == GXCompCnt.NrmNBT3) { nrmCnt = (uint)GXCompCnt.NrmNBT; nrmId3 = 1; } else { nrmCnt = (uint)list._cnt; nrmId3 = 0; } break; case GXAttribute.Color0: c0Cnt = (uint)list._cnt; c0Type = (uint)list._type; break; case GXAttribute.Color1: c1Cnt = (uint)list._cnt; c1Type = (uint)list._type; break; case GXAttribute.Tex0: tx0Cnt = (uint)list._cnt; tx0Type = (uint)list._type; tx0Frac = list._frac; break; case GXAttribute.Tex1: tx1Cnt = (uint)list._cnt; tx1Type = (uint)list._type; tx1Frac = list._frac; break; case GXAttribute.Tex2: tx2Cnt = (uint)list._cnt; tx2Type = (uint)list._type; tx2Frac = list._frac; break; case GXAttribute.Tex3: tx3Cnt = (uint)list._cnt; tx3Type = (uint)list._type; tx3Frac = list._frac; break; case GXAttribute.Tex4: tx4Cnt = (uint)list._cnt; tx4Type = (uint)list._type; tx4Frac = list._frac; break; case GXAttribute.Tex5: tx5Cnt = (uint)list._cnt; tx5Type = (uint)list._type; tx5Frac = list._frac; break; case GXAttribute.Tex6: tx6Cnt = (uint)list._cnt; tx6Type = (uint)list._type; tx6Frac = list._frac; break; case GXAttribute.Tex7: tx7Cnt = (uint)list._cnt; tx7Type = (uint)list._type; tx7Frac = list._frac; break; } MDL0PolygonDefs* Defs = (MDL0PolygonDefs*)polygon->DefList; Defs->UVATA = (uint)ShiftUVATA(posCnt, posType, posFrac, nrmCnt, nrmType, c0Cnt, c0Type, c1Cnt, c1Type, tx0Cnt, tx0Type, tx0Frac, nrmId3); Defs->UVATB = (uint)ShiftUVATB(tx1Cnt, tx1Type, tx1Frac, tx2Cnt, tx2Type, tx2Frac, tx3Cnt, tx3Type, tx3Frac, tx4Cnt, tx4Type); Defs->UVATC = (uint)ShiftUVATC(tx4Frac, tx5Cnt, tx5Type, tx5Frac, tx6Cnt, tx6Type, tx6Frac, tx7Cnt, tx7Type, tx7Frac); }
internal void WritePrimitives(MDL0ObjectNode poly, MDL0Object* header) { _polygon = poly; VoidPtr start = header->PrimitiveData; VoidPtr address = header->PrimitiveData; FacepointAttribute[] desc = poly._descList; IMatrixNode[] cache = poly.Model._linker.NodeCache; foreach (PrimitiveGroup g in poly._primGroups) { if (!poly.Model._isImport && !poly._reOptimized) g.RegroupNodes(); g._nodes.Sort(); g._offset = (uint)address - (uint)start; g._nodeOffsets.Clear(); //Write matrix headers for linking weighted influences to points if (poly.Weighted) { int index = 0; //Texture Matrices if (poly.HasTexMtx) for (int i = 0; i < g._nodes.Count; i++) { *(byte*)address++ = 0x30; g._nodeOffsets.Add(new NodeOffset((uint)(address - start) - g._offset, cache[g._nodes[i]])); *(bushort*)address = g._nodes[i]; address += 2; *(byte*)address++ = 0xB0; *(byte*)address++ = (byte)(0x78 + (12 * index++)); } index = 0; //Position Matrices for (int i = 0; i < g._nodes.Count; i++) { *(byte*)address++ = 0x20; g._nodeOffsets.Add(new NodeOffset((uint)(address - start) - g._offset, cache[g._nodes[i]])); *(bushort*)address = g._nodes[i]; address += 2; *(byte*)address++ = 0xB0; *(byte*)address++ = (byte)(12 * index++); } index = 0; //Normal Matrices for (int i = 0; i < g._nodes.Count; i++) { *(byte*)address++ = 0x28; g._nodeOffsets.Add(new NodeOffset((uint)(address - start) - g._offset, cache[g._nodes[i]])); *(bushort*)address = g._nodes[i]; address += 2; *(byte*)address++ = 0x84; *(byte*)address++ = (byte)(9 * index++); } } if (poly.Model._isImport || poly._reOptimized) { //Write strips first if (g._tristrips.Count != 0) foreach (PointTriangleStrip strip in g._tristrips) { *(PrimitiveHeader*)address = strip.Header; address += 3; foreach (Facepoint f in strip._points) WriteFacepoint(f, g, desc, ref address, poly); } //Write remaining triangles under a single list header if (g._triangles.Count != 0) { *(PrimitiveHeader*)address = g.TriangleHeader; address += 3; foreach (PointTriangle tri in g._triangles) { WriteFacepoint(tri._x, g, desc, ref address, poly); WriteFacepoint(tri._y, g, desc, ref address, poly); WriteFacepoint(tri._z, g, desc, ref address, poly); } } } else //Write the original primitives read from the model for (int i = 0; i < g._headers.Count; i++) { *(PrimitiveHeader*)address = g._headers[i]; address += 3; foreach (Facepoint point in g._points[i]) WriteFacepoint(point, g, desc, ref address, poly); } } }
public PrimitiveManager(MDL0Object* polygon, AssetStorage assets, IMatrixNode[] nodes, MDL0ObjectNode p) { _polygon = p; byte*[] pAssetList = new byte*[12]; byte*[] pOutList = new byte*[12]; int id; //This relies on the header being accurate! _indices = new UnsafeBuffer(2 * (_pointCount = polygon->_numVertices)); _faceCount = polygon->_numFaces; //Compile decode script by reading the polygon def list //This sets how to read the facepoints ElementDescriptor desc = new ElementDescriptor(polygon); //Grab asset lists in sequential order. if ((id = polygon->_vertexId) >= 0 && desc.HasData[0] && assets.Assets[0] != null) { pOutList[0] = (byte*)(_faceData[0] = new UnsafeBuffer(12 * _pointCount)).Address; pAssetList[0] = (byte*)assets.Assets[0][id].Address; } if ((id = polygon->_normalId) >= 0 && desc.HasData[1] && assets.Assets[1] != null) { pOutList[1] = (byte*)(_faceData[1] = new UnsafeBuffer(12 * _pointCount)).Address; pAssetList[1] = (byte*)assets.Assets[1][id].Address; } for (int i = 0, x = 2; i < 2; i++, x++) if ((id = ((bshort*)polygon->_colorIds)[i]) >= 0 && desc.HasData[x] && assets.Assets[2] != null) { pOutList[x] = (byte*)(_faceData[x] = new UnsafeBuffer(4 * _pointCount)).Address; pAssetList[x] = (byte*)assets.Assets[2][id].Address; } for (int i = 0, x = 4; i < 8; i++, x++) if ((id = ((bshort*)polygon->_uids)[i]) >= 0 && desc.HasData[x] && assets.Assets[3] != null) { pOutList[x] = (byte*)(_faceData[x] = new UnsafeBuffer(8 * _pointCount)).Address; pAssetList[x] = (byte*)assets.Assets[3][id].Address; } //Extract primitives, using our descriptor and asset lists fixed (byte** pOut = pOutList) fixed (byte** pAssets = pAssetList) ExtractPrimitives(polygon, ref desc, pOut, pAssets); //Compile merged vertex list _vertices = desc.Finish((Vector3*)pAssetList[0], nodes); ushort* pIndex = (ushort*)_indices.Address; for (int x = 0; x < _pointCount; x++) if (pIndex[x] >= 0 && pIndex[x] < _vertices.Count) _vertices[pIndex[x]]._faceDataIndices.Add(x); }
private void CorrectNodeIds(MDL0Object* header) { WriteWeightTable(header->WeightIndices(Model._version)); if (_matrixNode != null) header->_nodeId = _nodeId = (ushort)_matrixNode.NodeIndex; else { header->_nodeId = _nodeId = -1; VoidPtr primAddr = header->PrimitiveData; foreach (PrimitiveGroup p in _primGroups) p.SetNodeIds(primAddr); } }