Ejemplo n.º 1
0
        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;
         }
 }