static PrimitiveManager DecodePrimitivesUnweighted(NodeEntry n, GeometryEntry geo)
        {
            PrimitiveManager manager = DecodePrimitives(n._matrix, geo);

            Vector3* pVert = null;
            ushort* pVInd = (ushort*)manager._indices.Address;
            int vCount = 0;
            List<Vertex3> vertList = new List<Vertex3>(manager._pointCount);

            manager._vertices = vertList;

            //Find vertex source
            foreach (SourceEntry s in geo._sources)
                if (s._id == geo._verticesInput._source)
                {
                    UnsafeBuffer b = s._arrayData as UnsafeBuffer;
                    pVert = (Vector3*)b.Address;
                    vCount = b.Length / 12;
                    break;
                }

            UnsafeBuffer remap = new UnsafeBuffer(vCount * 2);
            ushort* pRemap = (ushort*)remap.Address;

            //Create remap table
            for (int i = 0; i < vCount; i++)
            {
                //Create Vertex and look for match
                Vertex3 v = new Vertex3(n._matrix * pVert[i]);

                int index = 0;
                while (index < vertList.Count)
                {
                    if (v.Equals(vertList[index]))
                        break;
                    index++;
                }
                if (index == vertList.Count)
                    vertList.Add(v);

                pRemap[i] = (ushort)index;
            }

            //Remap vertex indices
            for (int i = 0; i < manager._pointCount; i++, pVInd++)
                *pVInd = pRemap[*pVInd];

            remap.Dispose();

            return manager;
        }
        static PrimitiveManager DecodePrimitivesWeighted(NodeEntry n, GeometryEntry geo, SkinEntry skin, SceneEntry scene, InfluenceManager infManager, ref string Error)
        {
            PrimitiveManager manager = DecodePrimitives(n._matrix, geo);

            MDL0BoneNode[] boneList;
            MDL0BoneNode bone = null;
            int boneCount;
            string[] jointStrings = null;
            byte* pCmd = stackalloc byte[4];
            int cmdCount = skin._weightInputs.Count;
            float weight = 0;
            float* pWeights = null;
            Vector3* pVert = null, pNorms = null;
            ushort* pVInd = (ushort*)manager._indices.Address;
            List<Vertex3> vertList = new List<Vertex3>(skin._weightCount);
            Matrix* pMatrix = null;

            UnsafeBuffer remap = new UnsafeBuffer(skin._weightCount * 2);
            ushort* pRemap = (ushort*)remap.Address;

            pNorms = (Vector3*)manager._faceData[1].Address;

            manager._vertices = vertList;

            //Find vertex source
            foreach (SourceEntry s in geo._sources)
                if (s._id == geo._verticesInput._source)
                {
                    pVert = (Vector3*)((UnsafeBuffer)s._arrayData).Address;
                    break;
                }

            //Find joint source
            foreach (InputEntry inp in skin._jointInputs)
                if (inp._semantic == SemanticType.JOINT)
                {
                    foreach (SourceEntry src in skin._sources)
                        if (src._id == inp._source)
                        {
                            jointStrings = src._arrayData as string[];
                            break;
                        }
                }
                else if (inp._semantic == SemanticType.INV_BIND_MATRIX)
                {
                    foreach (SourceEntry src in skin._sources)
                        if (src._id == inp._source)
                        {
                            pMatrix = (Matrix*)((UnsafeBuffer)src._arrayData).Address;
                            break;
                        }
                }

            Error = "There was a problem creating the list of bones for geometry entry " + geo._name;

            //Populate bone list
            boneCount = jointStrings.Length;
            boneList = new MDL0BoneNode[boneCount];
            for (int i = 0; i < boneCount; i++)
                boneList[i] = scene.FindNode(jointStrings[i])._node as MDL0BoneNode;

            //Build command list
            foreach (InputEntry inp in skin._weightInputs)
            {
                switch (inp._semantic)
                {
                    case SemanticType.JOINT:
                        pCmd[inp._offset] = 1;
                        break;

                    case SemanticType.WEIGHT:
                        pCmd[inp._offset] = 2;

                        //Get weight source
                        foreach (SourceEntry src in skin._sources)
                            if (src._id == inp._source)
                            {
                                pWeights = (float*)((UnsafeBuffer)src._arrayData).Address;
                                break;
                            }

                        break;

                    default:
                        pCmd[inp._offset] = 0;
                        break;
                }
            }

            Error = "There was a problem creating vertex influences for geometry entry " + geo._name;

            //Build vertex list and remap table
            for (int i = 0; i < skin._weightCount; i++)
            {
                //Create influence
                int iCount = skin._weights[i].Length / cmdCount;
                Influence inf = new Influence(/*iCount*/);
                fixed (int* p = skin._weights[i])
                {
                    int* iPtr = p;
                    for (int x = 0; x < iCount; x++)
                    {
                        for (int z = 0; z < cmdCount; z++, iPtr++)
                            if (pCmd[z] == 1)
                                bone = boneList[*iPtr];
                            else if (pCmd[z] == 2)
                                weight = pWeights[*iPtr];
                        inf._weights.Add(new BoneWeight(bone, weight));
                    }
                }

                inf.CalcMatrix();

                Error = "There was a problem creating a vertex from the geometry entry " + geo._name + ".\nMake sure that all the vertices are weighted properly.";

                Vertex3 v;
                if (inf._weights.Count > 1)
                {
                    //Match with manager
                    inf = infManager.FindOrCreate(inf, true);
                    v = new Vertex3(n._matrix * skin._bindMatrix * pVert[i], inf); //World position
                }
                else
                {
                    bone = inf._weights[0].Bone;
                    v = new Vertex3(n._matrix * bone._inverseBindMatrix * skin._bindMatrix * pVert[i], bone); //Local position
                }

                ushort index = 0;
                while (index < vertList.Count)
                {
                    if (v.Equals(vertList[index])) break;
                    index++;
                }
                if (index == vertList.Count)
                    vertList.Add(v);

                pRemap[i] = index;
            }

            Error = "There was a problem fixing normal rotations for geometry entry " + geo._name;

            //Remap vertex indices and fix normals
            for (int i = 0; i < manager._pointCount; i++, pVInd++)
            {
                *pVInd = pRemap[*pVInd];
                Vertex3 v = null;
                if (*pVInd < vertList.Count)
                    v = vertList[*pVInd];
                if (v != null && v._matrixNode != null)
                    if (v._matrixNode.Weights.Count > 1)
                        pNorms[i] = skin._bindMatrix.GetRotationMatrix() * pNorms[i];
                    else
                        pNorms[i] = skin._bindMatrix.GetRotationMatrix() * v._matrixNode.Weights[0].Bone._inverseBindMatrix.GetRotationMatrix() * pNorms[i];
            }

            remap.Dispose();
            return manager;
        }
        static PrimitiveManager DecodePrimitivesWeighted(NodeEntry n, GeometryEntry geo, SkinEntry skin, SceneEntry scene, InfluenceManager infManager, ref string Error)
        {
            PrimitiveManager manager = DecodePrimitives(n._matrix, geo);

            MDL0BoneNode[] boneList;
            MDL0BoneNode   bone = null;
            int            boneCount;

            string[]       jointStrings = null;
            byte *         pCmd = stackalloc byte[4];
            int            cmdCount = skin._weightInputs.Count;
            float          weight = 0;
            float *        pWeights = null;
            Vector3 *      pVert = null, pNorms = null;
            ushort *       pVInd    = (ushort *)manager._indices.Address;
            List <Vertex3> vertList = new List <Vertex3>(skin._weightCount);
            Matrix *       pMatrix  = null;

            UnsafeBuffer remap  = new UnsafeBuffer(skin._weightCount * 2);
            ushort *     pRemap = (ushort *)remap.Address;

            pNorms = (Vector3 *)manager._faceData[1].Address;

            manager._vertices = vertList;

            //Find vertex source
            foreach (SourceEntry s in geo._sources)
            {
                if (s._id == geo._verticesInput._source)
                {
                    pVert = (Vector3 *)((UnsafeBuffer)s._arrayData).Address;
                    break;
                }
            }

            //Find joint source
            foreach (InputEntry inp in skin._jointInputs)
            {
                if (inp._semantic == SemanticType.JOINT)
                {
                    foreach (SourceEntry src in skin._sources)
                    {
                        if (src._id == inp._source)
                        {
                            jointStrings = src._arrayData as string[];
                            break;
                        }
                    }
                }
                else if (inp._semantic == SemanticType.INV_BIND_MATRIX)
                {
                    foreach (SourceEntry src in skin._sources)
                    {
                        if (src._id == inp._source)
                        {
                            pMatrix = (Matrix *)((UnsafeBuffer)src._arrayData).Address;
                            break;
                        }
                    }
                }
            }

            Error = "There was a problem creating the list of bones for geometry entry " + geo._name;

            //Populate bone list
            boneCount = jointStrings.Length;
            boneList  = new MDL0BoneNode[boneCount];
            for (int i = 0; i < boneCount; i++)
            {
                boneList[i] = scene.FindNode(jointStrings[i])._node as MDL0BoneNode;
            }

            //Build command list
            foreach (InputEntry inp in skin._weightInputs)
            {
                switch (inp._semantic)
                {
                case SemanticType.JOINT:
                    pCmd[inp._offset] = 1;
                    break;

                case SemanticType.WEIGHT:
                    pCmd[inp._offset] = 2;

                    //Get weight source
                    foreach (SourceEntry src in skin._sources)
                    {
                        if (src._id == inp._source)
                        {
                            pWeights = (float *)((UnsafeBuffer)src._arrayData).Address;
                            break;
                        }
                    }

                    break;

                default:
                    pCmd[inp._offset] = 0;
                    break;
                }
            }

            Error = "There was a problem creating vertex influences for geometry entry " + geo._name;

            //Build vertex list and remap table
            for (int i = 0; i < skin._weightCount; i++)
            {
                //Create influence
                int       iCount = skin._weights[i].Length / cmdCount;
                Influence inf    = new Influence(/*iCount*/);
                fixed(int *p = skin._weights[i])
                {
                    int *iPtr = p;

                    for (int x = 0; x < iCount; x++)
                    {
                        for (int z = 0; z < cmdCount; z++, iPtr++)
                        {
                            if (pCmd[z] == 1)
                            {
                                bone = boneList[*iPtr];
                            }
                            else if (pCmd[z] == 2)
                            {
                                weight = pWeights[*iPtr];
                            }
                        }
                        inf._weights.Add(new BoneWeight(bone, weight));
                    }
                }

                inf.CalcMatrix();

                Error = "There was a problem creating a vertex from the geometry entry " + geo._name + ".\nMake sure that all the vertices are weighted properly.";

                Vertex3 v;
                if (inf._weights.Count > 1)
                {
                    //Match with manager
                    inf = infManager.FindOrCreate(inf, true);
                    v   = new Vertex3(n._matrix * skin._bindMatrix * pVert[i], inf); //World position
                }
                else
                {
                    bone = inf._weights[0].Bone;
                    v    = new Vertex3(n._matrix * bone._inverseBindMatrix * skin._bindMatrix * pVert[i], bone); //Local position
                }

                ushort index = 0;
                while (index < vertList.Count)
                {
                    if (v.Equals(vertList[index]))
                    {
                        break;
                    }
                    index++;
                }
                if (index == vertList.Count)
                {
                    vertList.Add(v);
                }

                pRemap[i] = index;
            }

            Error = "There was a problem fixing normal rotations for geometry entry " + geo._name;

            //Remap vertex indices and fix normals
            for (int i = 0; i < manager._pointCount; i++, pVInd++)
            {
                *       pVInd = pRemap[*pVInd];
                Vertex3 v     = null;
                if (*pVInd < vertList.Count)
                {
                    v = vertList[*pVInd];
                }
                if (v != null && v._matrixNode != null)
                {
                    if (v._matrixNode.Weights.Count > 1)
                    {
                        pNorms[i] = skin._bindMatrix.GetRotationMatrix() * pNorms[i];
                    }
                    else
                    {
                        pNorms[i] = skin._bindMatrix.GetRotationMatrix() * v._matrixNode.Weights[0].Bone._inverseBindMatrix.GetRotationMatrix() * pNorms[i];
                    }
                }
            }

            remap.Dispose();
            return(manager);
        }
        public static unsafe void PMD2MDL0(MDL0Node model)
        {
            model._version = 9;
            model._isImport = true;
            Collada._importOptions = BrawlLib.Properties.Settings.Default.ColladaImportOptions;
            Collada._importOptions._forceCCW = true;
            Collada._importOptions._fltVerts = true;
            Collada._importOptions._fltNrms = true;
            Collada._importOptions._fltUVs = true;

            model.InitGroups();

            List<MDL0BoneNode> BoneCache = new List<MDL0BoneNode>();

            int index = 0;
            if (!String.IsNullOrWhiteSpace(_header._modelNameEnglish))
                model.Name = _header._modelNameEnglish;
            else
                model.Name = _header._modelName;

            if (!String.IsNullOrWhiteSpace(_header._commentEnglish))
                MessageBox.Show(_header._commentEnglish);
            else
                MessageBox.Show(_header._comment);

            ModelBone parent = null;
            foreach (ModelBone b in _bones)
            {
                MDL0BoneNode bone = new MDL0BoneNode();

                if (!String.IsNullOrWhiteSpace(b._boneNameEnglish))
                    bone._name = b._boneNameEnglish;
                else
                    bone._name = b._boneName;

                bone._entryIndex = index++;

                if (b._parentBoneIndex != ushort.MaxValue)
                {
                    parent = _bones[b._parentBoneIndex];
                    foreach (MDL0BoneNode v in model._boneGroup._children)
                        AssignParent(v, b, bone, parent);
                }
                else
                {
                    bone.Parent = model._boneGroup;
                    bone._bindState._scale = new Vector3(1.0f);
                    bone._bindState._translate = new Vector3(b._wPos[0], b._wPos[1], b._wPos[2]);
                    bone._bindState.CalcTransforms();
                    bone.RecalcBindState();
                }

                BoneCache.Add(bone);
            }

            MDL0ShaderNode texSpa = null, tex = null, colorSpa = null, color = null;

            index = 0;
            foreach (ModelMaterial m in _materials)
            {
                MDL0MaterialNode mn = new MDL0MaterialNode();
                mn.Name = "Material" + index++;

                MDL0MaterialRefNode texRef = null;
                MDL0MaterialRefNode spaRef = null;

                if (!String.IsNullOrEmpty(m._textureFileName))
                    if (m._textureFileName.Contains('*'))
                    {
                        string[] names = m._textureFileName.Split('*');
                        if (!String.IsNullOrEmpty(names[0]))
                        {
                            texRef = new MDL0MaterialRefNode();
                            texRef.Name = names[0].Substring(0, names[0].IndexOf('.'));
                        }
                        if (!String.IsNullOrEmpty(names[1]))
                        {
                            spaRef = new MDL0MaterialRefNode();
                            spaRef.Name = names[1].Substring(0, names[1].IndexOf('.'));
                            spaRef.MapMode = MDL0MaterialRefNode.MappingMethod.EnvCamera;
                            spaRef.UWrapMode = MDL0MaterialRefNode.WrapMode.Clamp;
                            spaRef.VWrapMode = MDL0MaterialRefNode.WrapMode.Clamp;
                            spaRef.Projection = Wii.Graphics.TexProjection.STQ;
                            spaRef.InputForm = Wii.Graphics.TexInputForm.ABC1;
                            spaRef.Coordinates = Wii.Graphics.TexSourceRow.Normals;
                            spaRef.Normalize = true;
                        }
                    }
                    else
                    {
                        texRef = new MDL0MaterialRefNode();
                        texRef.Name = m._textureFileName.Substring(0, m._textureFileName.IndexOf('.'));
                        texRef.Coordinates = Wii.Graphics.TexSourceRow.TexCoord0;
                    }

                if (texRef != null)
                {
                    (texRef._texture = model.FindOrCreateTexture(texRef.Name))._references.Add(texRef);
                    texRef._parent = mn;
                    mn._children.Add(texRef);
                }
                if (spaRef != null)
                {
                    (spaRef._texture = model.FindOrCreateTexture(spaRef.Name))._references.Add(spaRef);
                    spaRef._parent = mn;
                    mn._children.Add(spaRef);
                }

                mn._chan1._matColor = new RGBAPixel((byte)(m._diffuseColor[0] * 255), (byte)(m._diffuseColor[1] * 255), (byte)(m._diffuseColor[2] * 255), 255);
                mn._chan1.ColorMaterialSource = GXColorSrc.Register;

                if (texRef != null && spaRef != null)
                {
                    if (texSpa == null)
                    {
                        MDL0ShaderNode n = TexSpaShader;
                        n._parent = model._shadGroup;
                        model._shadList.Add(n);
                        texSpa = n;
                    }
                    mn.ShaderNode = texSpa;
                }
                else if (texRef != null)
                {
                    if (tex == null)
                    {
                        MDL0ShaderNode n = TexShader;
                        n._parent = model._shadGroup;
                        model._shadList.Add(n);
                        tex = n;
                    }
                    mn.ShaderNode = tex;
                }
                else if (spaRef != null)
                {
                    if (colorSpa == null)
                    {
                        MDL0ShaderNode n = ColorSpaShader;
                        n._parent = model._shadGroup;
                        model._shadList.Add(n);
                        colorSpa = n;
                    }
                    mn.ShaderNode = colorSpa;
                }
                else
                {
                    if (color == null)
                    {
                        MDL0ShaderNode n = ColorShader;
                        n._parent = model._shadGroup;
                        model._shadList.Add(n);
                        color = n;
                    }
                    mn.ShaderNode = color;
                }

                mn._parent = model._matGroup;
                model._matList.Add(mn);
            }

            model._numFaces = 0;
            model._numFacepoints = 0;

            int x = 0;
            int offset = 0;
            foreach (ModelMaterial m in _materials)
            {
                PrimitiveManager manager = new PrimitiveManager() { _pointCount = (int)m._faceVertCount };
                MDL0ObjectNode p = new MDL0ObjectNode() { _manager = manager, _opaMaterial = (MDL0MaterialNode)model._matList[x] };
                p._opaMaterial._objects.Add(p);
                p._manager._vertices = new List<Vertex3>();
                p.Name = "polygon" + x++;
                p._parent = model._objGroup;

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

                p._manager._indices = new UnsafeBuffer((int)m._faceVertCount * 2);
                p._manager._faceData[0] = new UnsafeBuffer((int)m._faceVertCount * 12);
                p._manager._faceData[1] = new UnsafeBuffer((int)m._faceVertCount * 12);
                p._manager._faceData[4] = new UnsafeBuffer((int)m._faceVertCount * 8);

                p._manager._dirty[0] = true;
                p._manager._dirty[1] = true;
                p._manager._dirty[4] = true;

                ushort* Indices = (ushort*)p._manager._indices.Address;
                Vector3* Vertices = (Vector3*)p._manager._faceData[0].Address;
                Vector3* Normals = (Vector3*)p._manager._faceData[1].Address;
                Vector2* UVs = (Vector2*)p._manager._faceData[4].Address;

                manager._triangles = new NewPrimitive((int)m._faceVertCount, BeginMode.Triangles);
                uint[] pTriarr = manager._triangles._indices;
                uint pTri = 0;

                index = 0;
                List<int> usedVertices = new List<int>();
                List<int> vertexIndices = new List<int>();
                for (int s = offset, l = 0; l < (int)m._faceVertCount; l++, s++)
                {
                    ushort i = _faceIndices[s];
                    ModelVertex mv = _vertices[i];
                    ushort j = 0;
                    if (!usedVertices.Contains(i))
                    {
                        Influence inf;
                        BoneWeight weight1 = null, weight2 = null;

                        float weight = ((float)mv._boneWeight / 100.0f).Clamp(0.0f, 1.0f);

                        if (weight > 0.0f && weight < 1.0f)
                        {
                            weight1 = new BoneWeight(BoneCache[mv._boneIndex[0]], weight);
                            weight2 = new BoneWeight(BoneCache[mv._boneIndex[1]], 1.0f - weight);
                        }
                        else if (weight == 0.0f)
                            weight1 = new BoneWeight(BoneCache[mv._boneIndex[1]]);
                        else
                            weight1 = new BoneWeight(BoneCache[mv._boneIndex[0]]);

                        if (weight2 != null)
                            inf = new Influence(new List<BoneWeight> { weight1, weight2 });
                        else
                            inf = new Influence(new List<BoneWeight> { weight1 });

                        Vector3 t = new Vector3();
                        Vertex3 v;
                        t._x = mv._position[0];
                        t._y = mv._position[1];
                        t._z = mv._position[2];
                        if (inf._weights.Count > 1)
                        {
                            inf = model._influences.FindOrCreate(inf, true);
                            inf.CalcMatrix();
                            v = new Vertex3(t, inf);
                        }
                        else
                        {
                            MDL0BoneNode bone = inf._weights[0].Bone;
                            v = new Vertex3(t * bone._inverseBindMatrix, bone);
                        }

                        p._manager._vertices.Add(v);
                        vertexIndices.Add(usedVertices.Count);
                        usedVertices.Add(i);
                        j = (ushort)(usedVertices.Count - 1);
                    }
                    else
                        j = (ushort)vertexIndices[usedVertices.IndexOf(i)];

                    *Indices++ = j;
                    pTriarr[pTri++] = (uint)l;
                    *Vertices++ = p._manager._vertices[j]._position;
                    *Normals++ = mv._normal;
                    *UVs++ = mv._texCoord;
                }
                model._objList.Add(p);
                offset += (int)m._faceVertCount;
            }

            //Check each polygon to see if it can be rigged to a single influence
            if (model._objList != null && model._objList.Count != 0)
                foreach (MDL0ObjectNode p in model._objList)
                {
                    IMatrixNode node = null;
                    bool singlebind = true;

                    foreach (Vertex3 v in p._manager._vertices)
                        if (v._matrixNode != null)
                        {
                            if (node == null)
                                node = v._matrixNode;

                            if (v._matrixNode != node)
                            {
                                singlebind = false;
                                break;
                            }
                        }

                    if (singlebind && p._matrixNode == null)
                    {
                        //Increase reference count ahead of time for rebuild
                        if (p._manager._vertices[0]._matrixNode != null)
                            p._manager._vertices[0]._matrixNode.ReferenceCount++;

                        foreach (Vertex3 v in p._manager._vertices)
                            if (v._matrixNode != null)
                                v._matrixNode.ReferenceCount--;

                        p._nodeId = -2; //Continued on polygon rebuild
                    }
                }

            //foreach (MDL0ObjectNode p in model._objList)
            //    foreach (MDL0MaterialNode m in model._matList)
            //    {
            //        MDL0MaterialNode m2 = p.OpaMaterialNode;

            //        if (m2 == null || m2.ShaderNode != m.ShaderNode || m2.Children.Count != m.Children.Count)
            //            continue;

            //        for (int i = 0; i < m.Children.Count; i++)
            //            if (m2.Children[i].Name != m.Children[i].Name)
            //                continue;

            //        p.OpaMaterialNode = m;
            //        break;
            //    }
            //for (int i = 0; i < model._matList.Count; i++)
            //    if (((MDL0MaterialNode)model._matList[i])._objects.Count == 0)
            //        model._matList.RemoveAt(i--);

            model.CleanGroups();
            model.BuildFromScratch(null);
        }
        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;
        }
        static PrimitiveManager DecodePrimitivesUnweighted(Matrix bindMatrix, GeometryEntry geo)
        {
            PrimitiveManager manager = DecodePrimitives(geo);

            Vector3 *      pVert = null, pNorms = null;
            ushort *       pVInd    = (ushort *)manager._indices.Address;
            int            vCount   = 0;
            List <Vertex3> vertList = new List <Vertex3>(manager._pointCount);

            manager._vertices = vertList;

            if (manager._faceData[1] != null)
            {
                pNorms = (Vector3 *)manager._faceData[1].Address;
            }

            //Find vertex source
            foreach (SourceEntry s in geo._sources)
            {
                if (s._id == geo._verticesInput._source)
                {
                    UnsafeBuffer b = s._arrayData as UnsafeBuffer;
                    pVert  = (Vector3 *)b.Address;
                    vCount = b.Length / 12;
                    break;
                }
            }

            UnsafeBuffer remap  = new UnsafeBuffer(vCount * 2);
            ushort *     pRemap = (ushort *)remap.Address;

            //Create remap table
            for (int i = 0; i < vCount; i++)
            {
                //Create vertex and look for match
                Vertex3 v = new Vertex3(bindMatrix * pVert[i]);

                int index = 0;
                while (index < vertList.Count)
                {
                    if (v.Equals(vertList[index]))
                    {
                        break;
                    }
                    index++;
                }
                if (index == vertList.Count)
                {
                    vertList.Add(v);
                }

                pRemap[i] = (ushort)index;
            }

            //Remap vertex indices and fix normals
            for (int i = 0; i < manager._pointCount; i++, pVInd++)
            {
                *pVInd = pRemap[*pVInd];

                if (pNorms != null)
                {
                    pNorms[i] = bindMatrix.GetRotationMatrix() * pNorms[i];
                }
            }

            remap.Dispose();

            return(manager);
        }
        static PrimitiveManager DecodePrimitivesWeighted(GeometryEntry geo, SkinEntry skin, SceneEntry scene, InfluenceManager infManager)
        {
            PrimitiveManager manager = DecodePrimitives(geo);

            MDL0BoneNode[] boneList;
            MDL0BoneNode   bone = null;
            int            boneCount;

            string[]       jointStrings = null;
            byte *         pCmd         = stackalloc byte[4];
            int            cmdCount     = skin._weightInputs.Count;
            float          weight       = 0;
            float *        pWeights     = null;
            Vector3 *      pVert        = null;
            ushort *       pVInd        = (ushort *)manager._faceData[0].Address;
            List <Vertex3> vertList     = new List <Vertex3>(skin._weightCount);
            Matrix *       pMatrix      = null;

            UnsafeBuffer remap  = new UnsafeBuffer(skin._weightCount * 2);
            ushort *     pRemap = (ushort *)remap.Address;

            manager._vertices = vertList;

            //Find vertex source
            foreach (SourceEntry s in geo._sources)
            {
                if (s._id == geo._verticesInput._source)
                {
                    pVert = (Vector3 *)((UnsafeBuffer)s._arrayData).Address;
                    break;
                }
            }

            //Find joint source
            foreach (InputEntry inp in skin._jointInputs)
            {
                if (inp._semantic == SemanticType.JOINT)
                {
                    foreach (SourceEntry src in skin._sources)
                    {
                        if (src._id == inp._source)
                        {
                            jointStrings = src._arrayData as string[];
                            break;
                        }
                    }
                }
                else if (inp._semantic == SemanticType.INV_BIND_MATRIX)
                {
                    foreach (SourceEntry src in skin._sources)
                    {
                        if (src._id == inp._source)
                        {
                            pMatrix = (Matrix *)((UnsafeBuffer)src._arrayData).Address;
                            break;
                        }
                    }
                }
            }

            //Populate bone list
            boneCount = jointStrings.Length;
            boneList  = new MDL0BoneNode[boneCount];
            for (int i = 0; i < boneCount; i++)
            {
                boneList[i] = scene.FindNode(jointStrings[i])._node as MDL0BoneNode;
            }

            //Build command list
            foreach (InputEntry inp in skin._weightInputs)
            {
                switch (inp._semantic)
                {
                case SemanticType.JOINT:
                    pCmd[inp._offset] = 1;
                    break;

                case SemanticType.WEIGHT:
                    pCmd[inp._offset] = 2;

                    //Get weight source
                    foreach (SourceEntry src in skin._sources)
                    {
                        if (src._id == inp._source)
                        {
                            pWeights = (float *)((UnsafeBuffer)src._arrayData).Address;
                            break;
                        }
                    }

                    break;

                default:
                    pCmd[inp._offset] = 0;
                    break;
                }
            }

            //Build vertex list and remap table
            for (int i = 0; i < skin._weightCount; i++)
            {
                //Create influence
                int       iCount = skin._weights[i].Length / cmdCount;
                Influence inf    = new Influence(iCount);
                fixed(int *p = skin._weights[i])
                {
                    int *iPtr = p;

                    for (int x = 0; x < iCount; x++)
                    {
                        for (int z = 0; z < cmdCount; z++, iPtr++)
                        {
                            if (pCmd[z] == 1)
                            {
                                bone = boneList[*iPtr];
                            }
                            else if (pCmd[z] == 2)
                            {
                                weight = pWeights[*iPtr];
                            }
                        }

                        inf._weights[x] = new BoneWeight(bone, weight);
                    }
                }

                Vertex3 v;
                if (inf._weights.Length > 1)
                {
                    //Match with manager
                    inf = infManager.AddOrCreate(inf);
                    v   = new Vertex3(skin._bindMatrix * pVert[i], inf); //World position
                }
                else
                {
                    bone = inf._weights[0].Bone;
                    v    = new Vertex3(bone._inverseBindMatrix * skin._bindMatrix * pVert[i], bone); //Local position
                }

                //Create Vertex, set to world position.
                //Vertex3 v = new Vertex3(skin._bindMatrix * pVert[i], inf);

                //Fix single-bind vertices
                //if (inf._weights.Length == 1)
                //    v.Position = inf._weights[0].Bone._inverseBindMatrix * v.Position;

                ushort index = 0;
                while (index < vertList.Count)
                {
                    if (v.Equals(vertList[index]))
                    {
                        break;
                    }
                    index++;
                }
                if (index == vertList.Count)
                {
                    vertList.Add(v);
                }

                pRemap[i] = index;
            }

            //Remap vertex indices
            for (int i = 0; i < manager._pointCount; i++, pVInd++)
            {
                *pVInd = pRemap[*pVInd];
            }

            remap.Dispose();

            return(manager);
        }
        private bool CompareVertexDistance(Vector3 point, ref Vertex3 match)
        {
            if (TargetModel._polyIndex != -1)
            {
                MDL0ObjectNode o = TargetModel._objList[TargetModel._polyIndex] as MDL0ObjectNode;
                if (o._render)
                    foreach (Vertex3 v in o._manager._vertices)
                    {
                        float t = v.WeightedPosition.TrueDistance(point);
                        if (Math.Abs(t) < 0.025f)
                        {
                            match = v;
                            return true;
                        }
                    }
                else
                    foreach (MDL0ObjectNode w in TargetModel._objList)
                        if (w._render)
                            foreach (Vertex3 v in w._manager._vertices)
                            {
                                float t = v.WeightedPosition.TrueDistance(point);
                                if (Math.Abs(t) < 0.025f)
                                {
                                    match = v;
                                    return true;
                                }
                            }
            }
            else
                foreach (MDL0ObjectNode o in TargetModel._objList)
                    if (o._render)
                        foreach (Vertex3 v in o._manager._vertices)
                        {
                            float t = v.WeightedPosition.TrueDistance(point);
                            if (Math.Abs(t) < 0.025f)
                            {
                                match = v;
                                return true;
                            }
                        }

            return false;
        }
        public bool Equals(Vertex3 v)
        {
            if (object.ReferenceEquals(this, v))
                return true;

            return (Position == v.Position) && (_matrixNode == v._matrixNode);
        }
Example #10
0
        internal unsafe void Precalc(MDL0PolygonNode parent, IMatrixNode[] nodes)
        {
            //If already calculated, and no weights, skip?
            bool hasNodes = parent.Model._linker.NodeCache.Length > 0;

            if ((_precVertices != null) && hasNodes)
            {
                return;
            }

            Vector3[] verts, norms = null;
            Vector3 * vPtr = null, nPtr = null;

            RGBAPixel[][] colors   = new RGBAPixel[2][];
            Vector2[][]   uvs      = new Vector2[8][];
            uint *        ptrCache = stackalloc uint[10];

            //Points
            verts = parent._vertexNode.Vertices;
            if (_precVertices == null)
            {
                _precVertices = new UnsafeBuffer(_elementCount * 12);
            }
            vPtr = (Vector3 *)_precVertices.Address;

            //Normals
            if (parent._normalNode != null)
            {
                norms = parent._normalNode.Normals;
                if (_precNormals == null)
                {
                    _precNormals = new UnsafeBuffer(_elementCount * 12);
                }
                nPtr = (Vector3 *)_precNormals.Address;
            }
            else if (_precNormals != null)
            {
                _precNormals.Dispose();
                _precNormals = null;
            }

            ////Colors
            //for (int i = 0; i < 1; i++)
            //{
            //    if (parent._colorSet[i] != null)
            //    {
            //        colors[i] = parent._colorSet[i].Colors;
            //        if (_precColors == null)
            //            _precColors = new UnsafeBuffer(_elementCount * 4);
            //        ptrCache[i] = (uint)_precColors.Address;
            //    }
            //    else if (_precColors != null)
            //    {
            //        _precColors.Dispose();
            //        _precColors = null;
            //    }
            //}

            //UVs
            for (int i = 0; i < 8; i++)
            {
                if (parent._uvSet[i] != null)
                {
                    uvs[i] = parent._uvSet[i].Points;
                    if (_precUVs[i] == null)
                    {
                        _precUVs[i] = new UnsafeBuffer(_elementCount * 8);
                    }
                    ptrCache[i + 2] = (uint)_precUVs[i].Address;
                }
                else if (_precUVs[i] != null)
                {
                    _precUVs[i].Dispose();
                    _precUVs[i] = null;
                }
            }

            int count = _vertices.Count;

            for (int x = 0; x < count; x++)
            {
                Vertex3 vert = _vertices[x];

                ////Vertices
                //if (hasNodes)
                //    *vPtr++ = nodes[vert.Influence.NodeIndex].Matrix.Multiply(verts[vert.Position]);
                //else
                //    *vPtr++ = verts[vert.Position];

                ////Normals
                //if (nPtr != null)
                //{
                //    if (hasNodes)
                //        *nPtr++ = nodes[vert.Influence.NodeIndex].Matrix.Multiply(norms[vert.Normal]);
                //    else
                //        *nPtr++ = norms[vert.Normal.Length];
                //}

                ////Colors
                //for (int i = 0; i < 1; i++)
                //{
                //    RGBAPixel* cPtr = (RGBAPixel*)ptrCache[i];
                //    if (cPtr != null)
                //        cPtr[x] = colors[i][vert.Color[i]];
                //}

                ////UVs
                //for (int i = 0; i < 8; i++)
                //{
                //    Vector2* uPtr = (Vector2*)ptrCache[i + 2];
                //    if (uPtr != null)
                //        uPtr[x] = uvs[i][vert.UV[i]];
                //}
            }
        }
        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();
        }
 public void SetWeight(float value, Vertex3 vertex)
 {
     Weight(value, vertex, false);
 }
 public void IncrementWeight(float value, Vertex3 vertex)
 {
     Weight(value, vertex, true);
 }