public override void OnRebuild(VoidPtr address, int length, bool force)
        {
            MDL0Object* header = (MDL0Object*)address;

            MDL0Node model = Model;

            if (_uvSet[7] != null)
                _defSize = 224;
            else if (_uvSet[5] != null)
                _defSize = 192;
            else if (_uvSet[2] != null)
                _defSize = 160;
            else
                _defSize = 128;

            if (model._rebuildAllObj || model._isImport || _rebuild || _reOptimized)
            {
                //Set Header
                header->_totalLength = length;

                header->_numVertices = _numFacepoints;
                header->_numFaces = _numFaces;

                _primBufferSize = header->_primitives._bufferSize = _primitiveSize;
                _primSize = header->_primitives._size = _primitiveSize;
                _primOffset = header->_primitives._offset = _tableLen + 0xBC;

                _defOffset = _tableLen - 0x18;

                header->_defintions._bufferSize = _defBufferSize;
                header->_defintions._size = _defSize;
                header->_defintions._offset = _defOffset;

                header->_flag = _flag;
                header->_index = _entryIndex;

                if (model._version < 10)
                    header->_nodeTableOffset = 0x64;
                else
                {
                    *(bshort*)((byte*)header + 0x60) = _elementIndices[12];
                    *(bshort*)((byte*)header + 0x62) = _elementIndices[13];

                    //Table offset
                    *(byte*)((byte*)header + 0x67) = 0x68;
                }

                //Set the node id
                if (_matrixNode != null)
                    header->_nodeId = _nodeId = (ushort)_matrixNode.NodeIndex;
                else
                    header->_nodeId = _nodeId = -1;

                //Set asset ids
                header->_vertexId = model._isImport && model._linker._forceDirectAssets[0] ? (short)-1 : (short)(_elementIndices[0] >= 0 ? _elementIndices[0] : -1);
                header->_normalId = model._isImport && model._linker._forceDirectAssets[1] ? (short)-1 : (short)(_elementIndices[1] >= 0 ? _elementIndices[1] : -1);
                for (int i = 2; i < 4; i++)
                    *(bshort*)&header->_colorIds[i - 2] = model._isImport && model._linker._forceDirectAssets[i] ? (short)-1 : (short)(_elementIndices[i] >= 0 ? _elementIndices[i] : -1);
                for (int i = 4; i < 12; i++)
                    *(bshort*)&header->_uids[i - 4] = model._isImport && model._linker._forceDirectAssets[i] ? (short)-1 : (short)(_elementIndices[i] >= 0 ? _elementIndices[i] : -1);

                //Write def list
                MDL0PolygonDefs* Defs = (MDL0PolygonDefs*)header->DefList;
                *Defs = MDL0PolygonDefs.Default;

                //Array flags are already set
                header->_arrayFlags = _arrayFlags;

                //Set vertex flags using descriptor list (sets the flags to this object)
                _manager.WriteVertexDescriptor(_descList, this);

                //Set UVAT groups using format list (writes directly to header)
                _manager.WriteVertexFormat(_fmtList, header);

                //Write newly set flags
                header->_vertexFormat._lo = Defs->VtxFmtLo = _vertexFormat._lo;
                header->_vertexFormat._hi = Defs->VtxFmtHi = _vertexFormat._hi;
                header->_vertexSpecs = Defs->VtxSpecs = _vertexSpecs;

                //Display UVAT groups that were written
                UVATGroups = new CPElementSpec(
                    (uint)Defs->UVATA,
                    (uint)Defs->UVATB,
                    (uint)Defs->UVATC);

                //Write weight table only if the object is weighted
                if (_matrixNode == null)
                    WriteWeightTable(header->WeightIndices(Model._version));

                //Write primitives
                _manager.WritePrimitives(this, header);
            }
            else
            {
                //Move raw data over
                base.OnRebuild(address, length, force);

                CorrectNodeIds(header);

                header->_vertexId = _elementIndices[0];
                header->_normalId = _elementIndices[1];
                for (int i = 2; i < 4; i++)
                    *(bshort*)&header->_colorIds[i - 2] = (short)(_elementIndices[i] >= 0 ? _elementIndices[i] : -1);
                for (int i = 4; i < 12; i++)
                    *(bshort*)&header->_uids[i - 4] = (short)(_elementIndices[i] >= 0 ? _elementIndices[i] : -1);
                if (model._version >= 10)
                {
                    *(bshort*)((byte*)header + 0x60) = _elementIndices[12];
                    *(bshort*)((byte*)header + 0x62) = _elementIndices[13];
                }
                header->_defintions._size = _defSize;
            }
            _rebuild = _reOptimized = false;
        }
        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;
            }
        }
        public override bool OnInitialize()
        {
            MDL0Object* header = Header;
            _nodeId = header->_nodeId;

            SetSizeInternal(_totalLength = header->_totalLength);
            _mdl0Offset = header->_mdl0Offset;
            _stringOffset = header->_stringOffset;

            ModelLinker linker = Model._linker;

            MatrixNode = (_nodeId >= 0 && _nodeId < Model._linker.NodeCache.Length) ? Model._linker.NodeCache[_nodeId] : null;

            _vertexFormat = header->_vertexFormat;
            _vertexSpecs = header->_vertexSpecs;
            _arrayFlags = header->_arrayFlags;

            HasPosMatrix = _arrayFlags.HasPosMatrix;
            for (int i = 0; i < 8; i++)
                HasTextureMatrix[i] = _arrayFlags.GetHasTexMatrix(i);

            _numFacepoints = header->_numVertices;
            _numFaces = header->_numFaces;

            _flag = header->_flag;

            _primBufferSize = header->_primitives._bufferSize;
            _primSize = header->_primitives._size;
            _primOffset = header->_primitives._offset;

            _defBufferSize = header->_defintions._bufferSize;
            _defSize = header->_defintions._size;
            _defOffset = header->_defintions._offset;

            _entryIndex = header->_index;

            //Conditional name assignment
            if ((_name == null) && (header->_stringOffset != 0))
                if (!_replaced)
                    _name = header->ResourceString;
                else
                    _name = "polygon" + Index;

            //Link nodes
            if (header->_vertexId >= 0 && Model._vertList != null)
                foreach (MDL0VertexNode v in Model._vertList)
                    if (header->_vertexId == v.ID)
                    {
                        (_vertexNode = v)._objects.Add(this);
                        break;
                    }

            if (header->_normalId >= 0 && Model._normList != null)
                foreach (MDL0NormalNode n in Model._normList)
                    if (header->_normalId == n.ID)
                    {
                        (_normalNode = n)._objects.Add(this);
                        break;
                    }

            int id;
            for (int i = 0; i < 2; i++)
                if ((id = ((bshort*)header->_colorIds)[i]) >= 0 && Model._colorList != null)
                    foreach (MDL0ColorNode c in Model._colorList)
                        if (id == c.ID)
                        {
                            (_colorSet[i] = c)._objects.Add(this);
                            break;
                        }

            for (int i = 0; i < 8; i++)
                if ((id = ((bshort*)header->_uids)[i]) >= 0 && Model._uvList != null)
                    foreach (MDL0UVNode u in Model._uvList)
                        if (id == u.ID)
                        {
                            (_uvSet[i] = u)._objects.Add(this);
                            break;
                        }

            if (Model._version > 9)
            {
                if (header->_furVectorId >= 0)
                    foreach (MDL0FurVecNode v in Model._furVecList)
                        if (header->_furVectorId == v.ID)
                        {
                            (_furVecNode = v)._objects.Add(this);
                            break;
                        }

                if (header->_furLayerCoordId >= 0)
                    foreach (MDL0FurPosNode n in Model._furPosList)
                        if (header->_furLayerCoordId == n.ID)
                        {
                            (_furPosNode = n)._objects.Add(this);
                            break;
                        }
            }

            //Link element indices for rebuild
            _elementIndices[0] = (short)(_vertexNode != null ? _vertexNode.Index : -1);
            _elementIndices[1] = (short)(_normalNode != null ? _normalNode.Index : -1);
            for (int i = 2; i < 4; i++)
                _elementIndices[i] = (short)(_colorSet[i - 2] != null ? _colorSet[i - 2].Index : -1);
            for (int i = 4; i < 12; i++)
                _elementIndices[i] = (short)(_uvSet[i - 4] != null ? _uvSet[i - 4].Index : -1);
            _elementIndices[12] = (short)(_furVecNode != null ? _furVecNode.Index : -1);
            _elementIndices[13] = (short)(_furPosNode != null ? _furPosNode.Index : -1);

            //Create primitive manager
            if (_parent != null)
            {
                int i = 0;
                _manager = new PrimitiveManager(header, Model._assets, linker.NodeCache, this);
                if (_manager._vertices != null)
                    foreach (Vertex3 v in _manager._vertices)
                    {
                        v._index = i++;
                        v._object = this;
                    }
            }

            //Get polygon UVAT groups
            MDL0PolygonDefs* Defs = (MDL0PolygonDefs*)header->DefList;
            UVATGroups = new CPElementSpec(
                (uint)Defs->UVATA,
                (uint)Defs->UVATB,
                (uint)Defs->UVATC);

            //Read internal object node cache and read influence list
            if (Model._linker.NodeCache != null)
            {
                if (_matrixNode == null)
                {
                    _influences = new List<IMatrixNode>();
                    bushort* weights = header->WeightIndices(Model._version);
                    int count = *(bint*)weights; weights += 2;
                    for (int i = 0; i < count; i++)
                        if (*weights < Model._linker.NodeCache.Length)
                            _influences.Add(Model._linker.NodeCache[*weights++]);
                        else
                            weights++;
                }
            }

            //Check for errors
            if (header->_totalLength % 0x20 != 0)
            {
                Model._errors.Add("Object " + Index + " has an improper data length.");
                SignalPropertyChange(); _rebuild = true;
            }
            if ((int)(0x24 + header->_primitives._offset) % 0x20 != 0)
            {
                Model._errors.Add("Object " + Index + " has an improper primitives start offset.");
                SignalPropertyChange(); _rebuild = true;
            }
            if (CheckVertexFormat())
            {
                Model._errors.Add("Object " + Index + " has a facepoint descriptor that does not match its linked nodes.");
                SignalPropertyChange(); _rebuild = true;

                for (int i = 0; i < 2; i++)
                    if (_colorSet[i] != null && _manager._faceData[i + 2] == null)
                    {
                        _manager._faceData[i + 2] = new UnsafeBuffer(_manager._pointCount * 4);
                        _colorChanged[i] = true;
                    }
            }
            if (HasTexMtx && !Weighted)
            {
                Model._errors.Add("Object " + Index + " has texture matrices but is not weighted.");
                for (int i = 0; i < 8; i++)
                    HasTextureMatrix[i] = false;
                SignalPropertyChange();
                _rebuild = true;
            }

            //if (!Weighted)
            //{
            //    bool notFloat = HasANonFloatAsset;
            //    foreach (PrimitiveGroup p in _primGroups)
            //    {
            //        bool o = false;
            //        foreach (PrimitiveHeader ph in p._headers)
            //            if (ph.Type != WiiPrimitiveType.TriangleList && notFloat)
            //            {
            //                Model._errors.Add("Object " + Index + " will explode in-game due to assets that are not written as float.");
            //                SignalPropertyChange();

            //                if (_vertexNode.Format != WiiVertexComponentType.Float)
            //                    _vertexNode._forceRebuild = _vertexNode._forceFloat = true;

            //                if (_normalNode != null && _normalNode.Format != WiiVertexComponentType.Float)
            //                    _normalNode._forceRebuild = _normalNode._forceFloat = true;

            //                for (int i = 4; i < 12; i++)
            //                    if (_uvSet[i - 4] != null && _uvSet[i - 4].Format != WiiVertexComponentType.Float)
            //                        _uvSet[i - 4]._forceRebuild = _uvSet[i - 4]._forceFloat = true;

            //                o = true;
            //                break;
            //            }
            //        if (o)
            //            break;
            //    }
            //}

            return false;
        }