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 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); }