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