private static void CreateMDL0Object(
            InstanceEntry inst,
            NodeEntry node,
            ResourceNode parent,
            PrimitiveManager manager,
            MDL0Node model,
            DecoderShell shell)
        {
            if (manager != null)
            {
                Error = "There was a problem creating a new object for " + (node._name != null ? node._name : node._id);

                MDL0ObjectNode poly = new MDL0ObjectNode()
                {
                    _manager   = manager,
                    _name      = node._name != null ? node._name : node._id,
                    _drawCalls = new BindingList <DrawCall>()
                };

                //Attach material
                if (inst._material != null)
                {
                    foreach (MaterialEntry mat in shell._materials)
                    {
                        if (mat._id == inst._material._target)
                        {
                            poly._drawCalls.Add(new DrawCall(poly)
                            {
                                MaterialNode = mat._node as MDL0MaterialNode
                            });
                        }
                    }
                }

                model._numTriangles  += poly._numFaces = manager._faceCount = manager._pointCount / 3;
                model._numFacepoints += poly._numFacepoints = manager._pointCount;

                poly._parent = model._objGroup;
                model._objList.Add(poly);

                model.ResetToBindState();

                //Attach single-bind
                if (parent != null && parent is MDL0BoneNode)
                {
                    MDL0BoneNode bone = (MDL0BoneNode)parent;
                    poly.DeferUpdateAssets();
                    poly.MatrixNode = bone;

                    foreach (DrawCall c in poly._drawCalls)
                    {
                        c.VisibilityBoneNode = bone;
                    }
                }
                else if (model._boneList.Count == 0)
                {
                    Error = String.Format("There was a problem rigging {0} to a single bone.", poly._name);

                    Box          box  = poly.GetBox();
                    MDL0BoneNode bone = new MDL0BoneNode()
                    {
                        Scale       = Vector3.One,
                        Translation = (box.Max + box.Min) / 2.0f,
                        _name       = "TransN_" + poly.Name,
                        Parent      = TempRootBone,
                    };

                    poly.DeferUpdateAssets();
                    poly.MatrixNode = bone;
                    ((MDL0BoneNode)TempRootBone).RecalcBindState(true, false, false);

                    foreach (DrawCall c in poly._drawCalls)
                    {
                        c.VisibilityBoneNode = bone;
                    }
                }
                else
                {
                    Error = String.Format("There was a problem checking if {0} is rigged to a single bone.", poly._name);

                    foreach (DrawCall c in poly._drawCalls)
                    {
                        c.VisibilityBoneNode = model._boneList[0] as MDL0BoneNode;
                    }

                    IMatrixNode mtxNode    = null;
                    bool        singlebind = true;

                    foreach (Vertex3 v in poly._manager._vertices)
                    {
                        if (v.MatrixNode != null)
                        {
                            if (mtxNode == null)
                            {
                                mtxNode = v.MatrixNode;
                            }

                            if (v.MatrixNode != mtxNode)
                            {
                                singlebind = false;
                                break;
                            }
                        }
                    }

                    if (singlebind && poly._matrixNode == null)
                    {
                        //Reassign reference entries
                        if (poly._manager._vertices[0].MatrixNode != null)
                        {
                            poly._manager._vertices[0].MatrixNode.Users.Add(poly);
                        }

                        foreach (Vertex3 v in poly._manager._vertices)
                        {
                            if (v.MatrixNode != null)
                            {
                                v.MatrixNode.Users.Remove(v);
                            }
                        }

                        poly._nodeId = -2; //Continued on polygon rebuild
                    }
                }
            }
        }
Exemple #2
0
 public NodeOffset(uint offset, IMatrixNode node)
 {
     _offset = offset;
     _node   = node;
 }
Exemple #3
0
        private void GetBaseInfluence()
        {
            if (_node != null)
            {
                modelPanel1.RemoveReference(_node);
            }

            MDL0BoneNode[] boneCache = _externalModel._linker.BoneCache;
            if ((_node = (MDL0ObjectNode)comboBox1.SelectedItem).Weighted)
            {
                int least = int.MaxValue;
                foreach (IMatrixNode inf in _node.Influences)
                {
                    if (inf is MDL0BoneNode && ((MDL0BoneNode)inf).BoneIndex < least)
                    {
                        least = ((MDL0BoneNode)inf).BoneIndex;
                    }
                }

                if (least != int.MaxValue)
                {
                    MDL0BoneNode temp = (MDL0BoneNode)boneCache[least];
                    _baseInf = (IMatrixNode)temp.Parent;
                }
            }
            else
            {
                _baseInf = _node.MatrixNode;
            }

            if (_baseInf is Influence)
            {
                label2.Hide();
                comboBox2.Hide();
            }
            else if (_baseInf is MDL0BoneNode)
            {
                label2.Show();
                comboBox2.Show();
            }

            baseBone.Text = _baseInf.ToString();

            if (comboBox3.SelectedIndex == 0 && _baseInf is MDL0BoneNode)
            {
                int i = 0;
                foreach (MDL0BoneNode s in comboBox2.Items)
                {
                    if (s.Name == baseBone.Text)
                    {
                        comboBox2.SelectedIndex = i;
                        break;
                    }
                    i++;
                }
            }

            _node.IsRendering = true;
            modelPanel1.ClearTargets();
            modelPanel1.AddTarget(_node);
            modelPanel1.SetCamWithBox(_node.GetBox());
        }
Exemple #4
0
 public Vertex3(Vector3 position, IMatrixNode influence)
 {
     Position   = position;
     MatrixNode = influence;
 }
        private static void WriteVertices(string name, List<Vertex3> vertices, IMatrixNode singleBind, XmlWriter writer)
        {
            bool first = true;

            //Position source
            writer.WriteStartElement("source");
            writer.WriteAttributeString("id", name + "_Positions");

            //Array start
            writer.WriteStartElement("float_array");
            writer.WriteAttributeString("id", name + "_PosArr");
            writer.WriteAttributeString("count", (vertices.Count * 3).ToString());

            foreach (Vertex3 v in vertices)
            {
                if (first)
                    first = false;
                else
                    writer.WriteString(" ");

                Vector3 p = v.WeightedPosition;
                writer.WriteString(String.Format("{0} {1} {2}", p._x.ToString(CultureInfo.InvariantCulture.NumberFormat), p._y.ToString(CultureInfo.InvariantCulture.NumberFormat), p._z.ToString(CultureInfo.InvariantCulture.NumberFormat)));
            }

            writer.WriteEndElement(); //float_array

            //Technique
            writer.WriteStartElement("technique_common");

            writer.WriteStartElement("accessor");
            writer.WriteAttributeString("source", "#" + name + "_PosArr");
            writer.WriteAttributeString("count", vertices.Count.ToString());
            writer.WriteAttributeString("stride", "3");

            writer.WriteStartElement("param");
            writer.WriteAttributeString("name", "X");
            writer.WriteAttributeString("type", "float");
            writer.WriteEndElement(); //param
            writer.WriteStartElement("param");
            writer.WriteAttributeString("name", "Y");
            writer.WriteAttributeString("type", "float");
            writer.WriteEndElement(); //param
            writer.WriteStartElement("param");
            writer.WriteAttributeString("name", "Z");
            writer.WriteAttributeString("type", "float");
            writer.WriteEndElement(); //param

            writer.WriteEndElement(); //accessor
            writer.WriteEndElement(); //technique_common

            writer.WriteEndElement(); //source
        }
Exemple #6
0
        //Returns true if the vertex's matrix node is changed.
        private bool Weight(float value, Vertex3 vertex, WeightType type)
        {
            if (_targetBone == null || _targetBone.Locked)
            {
                return(false);
            }

            Influence  targetInf    = null;
            BoneWeight targetWeight = null;
            float      max          = 1.0f;

            //Get the matrix that influences this vertex
            IMatrixNode node = vertex.GetMatrixNode();

            bool startsAsBone = false;

            //Convert a single bone into an influence so bones can be added to it later
            if (node is MDL0BoneNode)
            {
                startsAsBone = true;
                node         = new Influence(node as MDL0BoneNode);
            }

            //Duplicate the influence if it affects more than just this vertex
            targetInf = node.Users.Count > 1 ?
                        (node as Influence).Clone() :
                        node as Influence;

            //Find or add the current bone to the influence
            List <BoneWeight> weights = targetInf.Weights;
            int selectedIndex         = weights.Select(x => x.Bone).ToArray().IndexOf(TargetBone);

            if (selectedIndex < 0)
            {
                weights.Add(new BoneWeight(TargetBone, 0.0f));
                selectedIndex = weights.Count - 1;
            }

            //Get the weight at the index of the current bone
            targetWeight = targetInf.Weights[selectedIndex];

            //Can't do anything to a locked weight
            if (targetWeight.Locked)
            {
                return(false);
            }

            //Get the sum of all weights that can be edited by subtracting all locked values from 1.0f
            max = 1.0f;
            foreach (BoneWeight b in weights)
            {
                if (b.Locked)
                {
                    max -= b.Weight;
                }
            }

            //Get the new value for the target weight
            //Clamp it between 0.0f and the max value
            switch (type)
            {
            default:
                value = RoundValue(value, max);
                break;

            case WeightType.Add:
                value = RoundValue(targetWeight.Weight + value, max);
                break;

            case WeightType.Multiply:
                value = RoundValue(targetWeight.Weight * value, max);
                break;
            }

            //Nothing to do if there's no change in value
            if (targetWeight.Weight == value)
            {
                return(false);
            }

            //Collect all unlocked weights that are not the current weight
            //These are weights that will be changed to accomodate the current weight edit
            List <int> editableWeights = new List <int>();

            for (int i = 0; i < targetInf.Weights.Count; i++)
            {
                if (!targetInf.Weights[i].Locked && i != selectedIndex)
                {
                    editableWeights.Add(i);
                }
            }

            //Return if nothing can be edited
            if (editableWeights.Count == 0)
            {
                return(false);
            }

            //Set the current weight with the calculated value
            targetWeight.Weight = value;

            //Get the change in value, divide it by all other editable weights,
            //and then add that value to those weights to bring the overall weight sum back to 1.0f
            float perBoneDiff = (targetWeight.Weight - value) / editableWeights.Count;

            if (value < max)
            {
                foreach (int i in editableWeights)
                {
                    targetInf.Weights[i].Weight = RoundValue(targetInf.Weights[i].Weight + perBoneDiff, 1.0f);
                }
            }
            else
            {
                foreach (int i in editableWeights)
                {
                    targetInf.Weights[i].Weight = 0.0f;
                }
            }

            //Normalize the influence just in case, this will scale all weights so they add up to 1.0f
            //Don't let the modified value be normalized, lock it
            bool locked = targetWeight.Locked;

            targetWeight.Locked = true;
            targetInf.Normalize();
            targetWeight.Locked = locked;

            //Clean influence by removing zero weights
            for (int i = 0; i < targetInf.Weights.Count; i++)
            {
                if (targetInf.Weights[i].Weight <= 0.0f)
                {
                    targetInf.Weights.RemoveAt(i--);
                }
            }

            MDL0ObjectNode obj   = vertex.Parent as MDL0ObjectNode;
            MDL0Node       model = obj.Model;
            IMatrixNode    matrixNode;

            //See if the influence is just one bone
            if (targetInf.Weights.Count == 1)
            {
                matrixNode = targetInf.Weights[0].Bone;
                if (!startsAsBone && !_anyConverted.Contains(obj))
                {
                    _anyConverted.Add(obj);
                }
            }
            else
            {
                matrixNode = model._influences.FindOrCreate(targetInf);
                if (startsAsBone && !_anyConverted.Contains(obj))
                {
                    _anyConverted.Add(obj);
                }
            }

            //Move influence to each vertex before modifying the influence of one vertex
            if (obj.MatrixNode != null)
            {
                obj.TryConvertMatrixToVertex();
            }

            vertex.DeferUpdateAssets();
            vertex.MatrixNode = matrixNode;

            return(true);
        }
Exemple #7
0
 public Vertex3(Vector3 position, Vector3 normal, IMatrixNode influence)
 {
     Position = position;
     Normal   = normal;
     Inf      = influence;
 }
        internal unsafe List<Vertex3> Finish(Vector3* pVert, IMatrixNode[] nodeTable)
        {
            //Create vertex list from remap table
            List<Vertex3> list = new List<Vertex3>(RemapSize);

            if (!Weighted)
            {
                //Add vertex to list using raw value.
                for (int i = 0; i < RemapSize; i++)
                {
                    Vertex3 v = new Vertex3(pVert[RemapTable[i]]) { _facepoints = _points[i] };
                    foreach (Facepoint f in v._facepoints) f._vertex = v;
                    list.Add(v);
                }
            }
            else if (nodeTable != null)
            {
                for (int i = 0; i < RemapSize; i++)
                {
                    int x = RemapTable[i];
                    //Create new vertex, assigning the value + influence from the remap table
                    Vertex3 v = new Vertex3(pVert[x & 0xFFFF], nodeTable[x >> 16]) { _facepoints = _points[i] };
                    foreach (Facepoint f in v._facepoints) f._vertex = v;
                    //Add vertex to list
                    list.Add(v);
                }
            }

            return list;
        }
 public NodeOffset(uint offset, IMatrixNode node)
 {
     _offset = offset;
     _node = node;
 }
 public Vertex3(Vector3 position, IMatrixNode influence)
 {
     Position = position;
     MatrixNode = influence;
 }
        //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);
                }
            }
        }
        private void GetBaseInfluence()
        {
            ResourceNode[] boneCache = _externalModel._linker.BoneCache;
            if ((_node = (MDL0ObjectNode)comboBox1.SelectedItem).Weighted)
            {
                int least = int.MaxValue;
                foreach (IMatrixNode inf in _node.Influences)
                    if (inf is MDL0BoneNode && ((MDL0BoneNode)inf).BoneIndex < least)
                        least = ((MDL0BoneNode)inf).BoneIndex;

                if (least != int.MaxValue)
                {
                    MDL0BoneNode temp = (MDL0BoneNode)boneCache[least];
                    _baseInf = (IMatrixNode)temp.Parent;
                }
            }
            else _baseInf = _node.MatrixNode;

            if (_baseInf is Influence)
            {
                label2.Hide();
                comboBox2.Hide();
            }
            else if (_baseInf is MDL0BoneNode)
            {
                label2.Show();
                comboBox2.Show();
            }

            baseBone.Text = _baseInf.ToString();

            if (comboBox3.SelectedIndex == 0 && _baseInf is MDL0BoneNode)
            {
                int i = 0;
                foreach (MDL0BoneNode s in comboBox2.Items)
                {
                    if (s.Name == baseBone.Text)
                    {
                        comboBox2.SelectedIndex = i;
                        break;
                    }
                    i++;
                }
            }

            modelPanel1.AddTarget(_node);
            Vector3 min, max;
            _node.GetBox(out min, out max);
            modelPanel1.SetCamWithBox(min, max);
        }
        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            modelPanel1.ClearTargets();

            _mergeModels = checkBox1.Checked;
            if (_mergeModels)
            {
                label1.Hide();
                comboBox1.Hide();
                _baseInf = (IMatrixNode)_externalModel._linker.BoneCache[0];
                baseBone.Text = _baseInf.ToString();

                modelPanel1.AddTarget(_externalModel);
                Vector3 min, max;
                _externalModel.GetBox(out min, out max);
                modelPanel1.SetCamWithBox(min, max);
            }
            else
            {
                label1.Show();
                comboBox1.Show();
                GetBaseInfluence();
            }
        }
Exemple #14
0
        private void Weight(float value, Vertex3 vertex, bool increment)
        {
            //LET'S TANGO

            Influence  targetInf     = null;
            BoneWeight targetWeight  = null;
            float      max           = 1.0f;
            int        selectedIndex = 0;

            IMatrixNode node = vertex.MatrixNode;

            if (node == null)
            {
                vertex._object.ConvertInf();
                node = vertex.MatrixNode;
            }

            List <BoneWeight> weights = node.Weights;

            if (_targetBone == null || _targetBone._locked)
            {
                return;
            }

            MDL0BoneNode origBone = null;

            if (node is MDL0BoneNode)
            {
                origBone = node as MDL0BoneNode;
                node     = new Influence(origBone);
            }

            bool refs = node.Users.Count > 1;

            if (refs)
            {
                targetInf = (node as Influence).Clone();
            }
            else
            {
                targetInf = (node as Influence);
            }

            weights = targetInf._weights;

            selectedIndex = vertex.IndexOfBone(TargetBone);
            if (selectedIndex == -1)
            {
                weights.Add(new BoneWeight(TargetBone, 0.0f));
                selectedIndex = weights.Count - 1;
            }

            targetWeight = targetInf._weights[selectedIndex];
            if (targetWeight.Locked)
            {
                return;
            }

            max = 1.0f;
            foreach (BoneWeight b in weights)
            {
                if (b.Locked)
                {
                    max -= b.Weight;
                }
            }

            value = increment ? RoundValue(targetWeight.Weight + value, max) : RoundValue(value, max);

            if (targetWeight.Weight == value)
            {
                return;
            }

            List <int> editableWeights = new List <int>();

            int c = 0;

            foreach (BoneWeight b in targetInf._weights)
            {
                if (!b.Locked && c != selectedIndex)
                {
                    editableWeights.Add(c);
                }
                c++;
            }

            if (editableWeights.Count == 0)
            {
                return;
            }

            float diff = targetWeight.Weight - value;

            targetWeight.Weight = value;

            float val = diff / (editableWeights.Count);

            if (value != max)
            {
                foreach (int i in editableWeights)
                {
                    targetInf._weights[i].Weight = (float)Math.Round((targetInf._weights[i].Weight + val).Clamp(0.0f, 1.0f), 7);
                }
            }
            else
            {
                foreach (int i in editableWeights)
                {
                    targetInf._weights[i].Weight = 0;
                }
            }

            //Don't want the modified value to be normalized
            bool locked = targetWeight.Locked;

            targetWeight.Locked = true;
            targetInf.Normalize();
            targetWeight.Locked = locked;

            vertex.MatrixNode = vertex._object.Model._influences.FindOrCreate(targetInf, false);
            vertex._object.ConvertInf();
            vertex._object.Model.SignalPropertyChange();

            _mainWindow.UpdateModel();
        }
        internal unsafe void RenderVerts(TKContext ctx, IMatrixNode _singleBind, MDL0BoneNode selectedBone, Vector3 cam, bool pass2)
        {
            if (!_render)
                return;

            foreach (Vertex3 v in _vertices)
            {
                Color w = v._highlightColor != Color.Transparent ? v._highlightColor : (_singleBind != null && _singleBind == selectedBone) ? Color.Red : v.GetWeightColor(selectedBone);
                if (w != Color.Transparent)
                    GL.Color4(w);
                else
                    GL.Color4(DefaultVertColor);

                float d = cam.DistanceTo(_singleBind == null ? v.WeightedPosition : _singleBind.Matrix * v.WeightedPosition);
                if (d == 0) d = 0.000000000001f;
                GL.PointSize((5000 / d).Clamp(1.0f, !pass2 ? 5.0f : 8.0f));

                GL.Begin(BeginMode.Points);
                GL.Vertex3(v.WeightedPosition._x, v.WeightedPosition._y, v.WeightedPosition._z);
                GL.End();
            }
        }
        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);
        }