public bool tryMerge(PrimitiveGroup g2) { HashSet <int> tempIds = new HashSet <int>(); foreach (int i in nodeIds) { tempIds.Add(i); } foreach (int i in g2.nodeIds) { tempIds.Add(i); } if (tempIds.Count <= 10) { for (int i = 0; i < g2.Triangles.Count; i++) { AddTriangle(g2.Triangles[i]); } for (int i = 0; i < g2.Tristrips.Count; i++) { AddTristrip(g2.Tristrips[i]); } return(true); } return(false); }
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; }
//Decode a single primitive using command list public void Run(ref byte* pIn, byte** pAssets, byte** pOut, int count, PrimitiveGroup group, ref ushort* indices, IMatrixNode[] nodeTable) { //pIn is the address in the primitives //pOut is address of the face data buffers //pAssets is the address of the raw asset buffers int weight = 0; int index = 0, outSize; DecodeOp o; ElementDef* pDef; byte* p; byte[] pTexMtx = new byte[8]; byte* tIn, tOut; group._points.Add(new List<Facepoint>()); //Iterate commands in list fixed (ushort* pNode = Nodes) fixed (int* pDefData = Defs) fixed (byte* pCmd = Commands) { for (int i = 0; i < count; i++) { pDef = (ElementDef*)pDefData; p = pCmd; Facepoint f = new Facepoint(); Continue: o = (DecodeOp)(*p++); switch (o) { //Process weight using cache case DecodeOp.PosWeight: weight = pNode[*pIn++ / 3]; goto Continue; case DecodeOp.TexMtx0: case DecodeOp.TexMtx1: case DecodeOp.TexMtx2: case DecodeOp.TexMtx3: case DecodeOp.TexMtx4: case DecodeOp.TexMtx5: case DecodeOp.TexMtx6: case DecodeOp.TexMtx7: index = (int)o - (int)DecodeOp.TexMtx0; //if (*pIn++ == 0x60) //Identity matrix... // Console.WriteLine(); pTexMtx[index] = (byte)(*pIn++ / 3); goto Continue; case DecodeOp.ElementDirect: ElementCodec.Decoders[pDef->Output](ref pIn, ref pOut[pDef->Type], VQuant.DeQuantTable[pDef->Scale]); goto Continue; case DecodeOp.ElementIndexed: //Get asset index if (pDef->Format == 2) { index = *(bushort*)pIn; pIn += 2; } else index = *pIn++; switch (pDef->Type) { case 0: f._vertexIndex = index; break; case 1: f._normalIndex = index; break; case 2: case 3: f._colorIndices[pDef->Type - 2] = index; break; default: f._UVIndices[pDef->Type - 4] = index; break; } if (pDef->Type == 0) //Special processing for vertices { //Match weight and index with remap table int mapEntry = (weight << 16) | index; //Find matching index, starting at end of list //Lower index until a match is found at that index or index is less than 0 index = RemapSize; while ((--index >= 0) && (RemapTable[index] != mapEntry)) ; //No match, create new entry //Will be processed into vertices at the end! if (index < 0) { RemapTable[index = RemapSize++] = mapEntry; _points.Add(new List<Facepoint>()); } //Write index *indices++ = (ushort)index; _points[index].Add(f); } else { //Copy data from buffer outSize = pDef->Output; //Input data from asset cache tIn = pAssets[pDef->Type] + (index * outSize); tOut = pOut[pDef->Type]; if (tIn != null && tOut != null) { //Copy data to output while (outSize-- > 0) *tOut++ = *tIn++; //Increment element output pointer pOut[pDef->Type] = tOut; } } pDef++; goto Continue; default: break; //End } group._points[group._points.Count - 1].Add(f); } } }
internal void WriteFacepoint(Facepoint f, PrimitiveGroup g, FacepointAttribute[] desc, ref VoidPtr address, MDL0ObjectNode node) { foreach (FacepointAttribute d in desc) switch (d._attr) { case GXAttribute.PosNrmMtxId: if (d._type == XFDataFormat.Direct) *(byte*)address++ = (byte)(3 * g._nodes.IndexOf(f.NodeID)); break; case GXAttribute.Tex0MtxId: case GXAttribute.Tex1MtxId: case GXAttribute.Tex2MtxId: case GXAttribute.Tex3MtxId: case GXAttribute.Tex4MtxId: case GXAttribute.Tex5MtxId: case GXAttribute.Tex6MtxId: case GXAttribute.Tex7MtxId: if (d._type == XFDataFormat.Direct) *(byte*)address++ = (byte)(30 + (3 * g._nodes.IndexOf(f.NodeID))); break; case GXAttribute.Position: switch (d._type) { case XFDataFormat.Direct: byte* addr = (byte*)address; node.Model._linker._vertices[node._elementIndices[0]].Write(ref addr, f._vertexIndex); address = addr; break; case XFDataFormat.Index8: *(byte*)address++ = (byte)f._vertexIndex; break; case XFDataFormat.Index16: *(bushort*)address = (ushort)f._vertexIndex; address += 2; break; } break; case GXAttribute.Normal: switch (d._type) { case XFDataFormat.Direct: byte* addr = (byte*)address; node.Model._linker._normals[node._elementIndices[1]].Write(ref addr, f._normalIndex); address = addr; break; case XFDataFormat.Index8: *(byte*)address++ = (byte)f._normalIndex; break; case XFDataFormat.Index16: *(bushort*)address = (ushort)f._normalIndex; address += 2; break; } break; case GXAttribute.Color0: case GXAttribute.Color1: switch (d._type) { case XFDataFormat.Direct: int index = (int)d._attr - 11; byte* addr = (byte*)address; node.Model._linker._colors[node._elementIndices[index + 2]].Write(ref addr, f._colorIndices[index]); address = addr; break; case XFDataFormat.Index8: if (_polygon._colorChanged[(int)d._attr - (int)GXAttribute.Color0] && _polygon._colorSet[(int)d._attr - (int)GXAttribute.Color0] != null) *(byte*)address++ = 0; else *(byte*)address++ = (byte)f._colorIndices[(int)d._attr - 11]; break; case XFDataFormat.Index16: if (_polygon._colorChanged[(int)d._attr - (int)GXAttribute.Color0] && _polygon._colorSet[(int)d._attr - (int)GXAttribute.Color0] != null) *(bushort*)address = 0; else *(bushort*)address = (ushort)f._colorIndices[(int)d._attr - 11]; address += 2; break; } break; case GXAttribute.Tex0: case GXAttribute.Tex1: case GXAttribute.Tex2: case GXAttribute.Tex3: case GXAttribute.Tex4: case GXAttribute.Tex5: case GXAttribute.Tex6: case GXAttribute.Tex7: switch (d._type) { case XFDataFormat.Direct: int index = (int)d._attr - 13; byte* addr = (byte*)address; node.Model._linker._uvs[node._elementIndices[index + 4]].Write(ref addr, f._UVIndices[index]); address = addr; break; case XFDataFormat.Index8: *(byte*)address++ = (byte)f._UVIndices[(int)d._attr - 13]; break; case XFDataFormat.Index16: *(bushort*)address = (ushort)f._UVIndices[(int)d._attr - 13]; address += 2; break; } break; } }