public DialogResult ShowDialog(MDL0Node internalModel, MDL0Node externalModel)
        {
            _internalModel = internalModel;
            _externalModel = externalModel;
            _externalModel._renderBones = false;

            comboBox1.Items.AddRange(_externalModel.FindChild("Objects", true).Children.ToArray());
            comboBox2.Items.AddRange(_internalModel._linker.BoneCache);

            comboBox1.SelectedIndex = comboBox2.SelectedIndex = comboBox3.SelectedIndex = 0;
            _parent = (MDL0BoneNode)comboBox2.SelectedItem;

            return base.ShowDialog(null);
        }
        /// <summary>
        /// Call before and after making a modification to a bone's framestate.
        /// </summary>
        /// <param name="bone"></param>
        public void BoneChange(MDL0BoneNode bone)
        {
            SaveState state = new SaveState();
            state._bone = bone;
            state._frameState = bone._frameState;
            state._animation = SelectedCHR0;
            state._frameIndex = CurrentFrame;

            if (before)
                AddUndo(state);
            else
                AddRedo(state);

            before = !before;
        }
        private void CreateNode()
        {
            MDL0GroupNode group = _resource as MDL0GroupNode;
            MDL0Node model = group.Parent as MDL0Node;

            switch (group._type.ToString("g"))
            {
                case "Bones":
                    MDL0BoneNode bone = new MDL0BoneNode() { Name = "NewBone" };
                    model._boneGroup.InsertChild(bone, false, 0);
                    bone._flags1 = (BoneFlags)284;
                    bone.Scale = new Vector3(1, 1, 1);
                    bone._bindMatrix = Matrix.Identity;
                    bone._inverseBindMatrix = Matrix.Identity;
                    bone.Moved = true;
                    break;
            }
        }
Beispiel #4
0
        private void OnBillboardModeChanged()
        {
            if (BillboardSetting == BillboardFlags.Off)
            {
                MDL0BoneNode n = this;
                while ((n = n.Parent as MDL0BoneNode) != null)
                {
                    if (n.BillboardSetting != BillboardFlags.Off)
                    {
                        break;
                    }
                }

                if (n != null)
                {
                    BBRefNode = n;
                    foreach (MDL0BoneNode b in Children)
                    {
                        b.RecursiveSetBillboard(BBRefNode);
                    }
                }
                else
                {
                    BBRefNode = null;
                    foreach (MDL0BoneNode b in Children)
                    {
                        b.RecursiveSetBillboard(null);
                    }
                }
            }
            else
            {
                BBRefNode = null;
                foreach (MDL0BoneNode b in Children)
                {
                    b.RecursiveSetBillboard(this);
                }
            }
        }
        public CHR0EntryNode CreateEntryFromBone(MDL0BoneNode b, int framesToGenerate, bool generateOrigin)
        {
            CHR0EntryNode n = new CHR0EntryNode();

            if (!generateOrigin)
            {
                if (b.isOriginRot() && b.isOriginScale() && b.isOriginTrans())
                {
                    //Console.WriteLine("      " + b + " has all values equal to origin. Not generating keyframes.");
                    return(null);
                }
            }
            n._name = this.FindName(b.Name);
            AddChild(n);
            n.SetSize(_numFrames, Loop);
            //Console.WriteLine(_numFrames);
            for (int i = 0; i < framesToGenerate; ++i)
            {
                n.generateKeyframeFromBone(b, i, true, generateOrigin);
            }
            SignalPropertyChange();
            return(n);
        }
Beispiel #6
0
        //Initialize should only be called from parent group during parse.
        //Bones need not be imported/exported anyways
        public override bool OnInitialize()
        {
            MDL0Bone *header = Header;

            SetSizeInternal(header->_headerLen);

            //Conditional name assignment
            if (_name == null && header->_stringOffset != 0)
            {
                _name = header->ResourceString;
            }

            //Assign fields
            _boneFlags      = (BoneFlags)(uint)header->_flags;
            _billboardFlags = (BillboardFlags)(uint)header->_bbFlags;
            _nodeIndex      = header->_nodeId;
            _entryIndex     = header->_index;

            _bbRefNode = !_replaced && _boneFlags.HasFlag(BoneFlags.HasBillboardParent) ?
                         Model._linker.NodeCache[header->_bbNodeId] as MDL0BoneNode : null;

            if (_billboardFlags != BillboardFlags.Off)
            {
                Model._billboardBones.Add(this); //Update mesh in T-Pose
            }
            _bindState         = _frameState = new FrameState(header->_scale, (Vector3)header->_rotation, header->_translation);
            _bindMatrix        = _frameMatrix = header->_transform;
            _inverseBindMatrix = _inverseFrameMatrix = header->_transformInv;

            _extents = header->_extents;

            (_userEntries = new UserDataCollection()).Read(header->UserDataAddress);

            //We don't want to process children because not all have been parsed yet.
            //Child assignments will be handled by the parent group.
            return(false);
        }
        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);
        }
 public BoneWeight(MDL0BoneNode bone, float weight)
 {
     Bone = bone; Weight = weight;
 }
 public Influence(MDL0BoneNode bone)
 {
     _weights = new List<BoneWeight> { new BoneWeight(bone) };
 }
        private void EnumNode(NodeEntry node, ResourceNode parent, SceneEntry scene, MDL0Node model, DecoderShell shell)
        {
            MDL0BoneNode bone = null;
            Influence inf = null;

            if (node._type == NodeType.JOINT)
            {
                Error = "There was a problem creating a new bone.";

                bone = new MDL0BoneNode();
                bone._name = node._name != null ? node._name : node._id;

                bone._bindState = node._transform;
                node._node = bone;

                parent._children.Add(bone);
                bone._parent = parent;

                bone.RecalcBindState();
                bone.CalcFlags();

                foreach (NodeEntry e in node._children)
                    EnumNode(e, bone, scene, model, shell);

                inf = new Influence(bone);
                model._influences._influences.Add(inf);
            }
            else
                foreach (NodeEntry e in node._children)
                    EnumNode(e, parent, scene, model, shell);

            foreach (InstanceEntry inst in node._instances)
            {
                if (inst._type == InstanceType.Controller)
                {
                    foreach (SkinEntry skin in shell._skins)
                        if (skin._id == inst._url)
                        {
                            foreach (GeometryEntry g in shell._geometry)
                                if (g._id == skin._skinSource)
                                {
                                    Error = @"
                                    There was a problem decoding weighted primitives for the object " + (node._name != null ? node._name : node._id) +
                                    ".\nOne or more vertices may not be weighted correctly.";
                                    Say("Decoding weighted primitives for " + (g._name != null ? g._name : g._id) + "...");
                                    CreateObject(inst, node, parent, DecodePrimitivesWeighted(node, g, skin, scene, model._influences, ref Error), model, shell);
                                    break;
                                }
                            break;
                        }
                }
                else if (inst._type == InstanceType.Geometry)
                {
                    foreach (GeometryEntry g in shell._geometry)
                        if (g._id == inst._url)
                        {
                            Error = "There was a problem decoding unweighted primitives for the object " + (node._name != null ? node._name : node._id) + ".";
                            Say("Decoding unweighted primitives for " + (g._name != null ? g._name : g._id) + "...");
                            CreateObject(inst, node, parent, DecodePrimitivesUnweighted(node, g), model, shell);
                            break;
                        }
                }
                else
                {
                    foreach (NodeEntry e in shell._nodes)
                        if (e._id == inst._url)
                            EnumNode(e, parent, scene, model, shell);
                }
            }
        }
        internal void Parse(MDL0Node model)
        {
            Influence   inf;
            ModelLinker linker = model._linker;

            switch (_type)
            {
            case MDLResourceType.Definitions:
                if (linker.Defs != null)
                {
                    ExtractGroup(linker.Defs, typeof(MDL0DefNode));
                }
                break;

            case MDLResourceType.Bones:
                //Break if there are no bones defined
                if (linker.Bones == null)
                {
                    break;
                }

                //Parse bones from raw data (flat list).
                //Bones re-assign parents in their Initialize block, so parents are true.
                ExtractGroup(linker.Bones, typeof(MDL0BoneNode));

                //Cache flat list
                linker.BoneCache = _children.ToArray();

                //Make sure the node cache is the correct size
                int highest = 0;
                foreach (MDL0BoneNode b in _children)
                {
                    if (b._nodeIndex >= linker.NodeCache.Length && b._nodeIndex > highest)
                    {
                        highest = b._nodeIndex;
                    }
                }
                if (highest >= linker.NodeCache.Length)
                {
                    linker.NodeCache = new IMatrixNode[highest + 1];
                }

                //Reset children so we can rebuild
                _children.Clear();

                //Populate node cache
                MDL0BoneNode bone = null;
                int          index;
                int          count = linker.BoneCache.Length;
                for (int i = 0; i < count; i++)
                {
                    linker.NodeCache[(bone = linker.BoneCache[i] as MDL0BoneNode)._nodeIndex] = bone;
                }

                //Now that bones and primary influences have been cached, we can create weighted influences.
                foreach (ResourcePair p in *linker.Defs)
                {
                    if (p.Name == "NodeTree")
                    {
                        //Use node tree to rebuild bone heirarchy
                        byte *pData = (byte *)p.Data;

Top:
                        if (*pData == 2)
                        {
                            bone  = linker.BoneCache[*(bushort *)(pData + 1)] as MDL0BoneNode;
                            index = *(bushort *)(pData + 3);

                            if (bone.Header->_parentOffset == 0)
                            {
                                _children.Add(bone);
                            }
                            else
                            {
                                (bone._parent = linker.NodeCache[index] as ResourceNode)._children.Add(bone);
                            }

                            pData += 5;
                            goto Top;
                        }
                    }
                    else if (p.Name == "NodeMix")
                    {
                        //Use node mix to create weight groups
                        byte *pData = (byte *)p.Data;

Top:
                        switch (*pData)
                        {
                        //Type 3 is for weighted influences
                        case 3:
                            //Get index/count fields
                            index = *(bushort *)(pData + 1);
                            count = pData[3];
                            //Get data pointer (offset of 4)
                            MDL0NodeType3Entry *nEntry = (MDL0NodeType3Entry *)(pData + 4);
                            //Create influence with specified count
                            inf = new Influence(count);
                            //Iterate through weights, adding each to the influence
                            //Here, we are referring back to the NodeCache to grab the bone.
                            //Note that the weights do not reference other influences, only bones. There is a good reason for this.
                            for (int i = 0; i < count; i++, nEntry++)
                            {
                                if ((linker.NodeCache[nEntry->_id] as MDL0BoneNode) == null)
                                {
                                    Console.WriteLine("Null bone entry!");
                                }
                                else
                                {
                                    inf._weights[i] = new BoneWeight(linker.NodeCache[nEntry->_id] as MDL0BoneNode, nEntry->_value);
                                }
                            }

                            //Add influence to model object, while adding it to the cache.
                            linker.NodeCache[index] = model._influences.AddOrCreate(inf);

                            //Move data pointer to next entry
                            pData = (byte *)nEntry;
                            goto Top;

                        //Type 5 is for primary influences
                        case 5:
                            pData += 5;
                            goto Top;
                        }
                    }
                }
                int z = 0;
                foreach (IMatrixNode m in linker.NodeCache)
                {
                    if (!m.IsPrimaryNode)
                    {
                        ((Influence)m)._permanentID = z; break;
                    }
                    z++;
                }
                break;

            case MDLResourceType.Materials:
                if (linker.Materials != null)
                {
                    ExtractGroup(linker.Materials, typeof(MDL0MaterialNode));
                }
                break;

            case MDLResourceType.Shaders:
                if (linker.Shaders != null)
                {
                    ExtractGroup(linker.Shaders, typeof(MDL0ShaderNode));
                }
                break;

            case MDLResourceType.Vertices:
                if (linker.Vertices != null)
                {
                    ExtractGroup(linker.Vertices, typeof(MDL0VertexNode));
                }
                break;

            case MDLResourceType.Normals:
                if (linker.Normals != null)
                {
                    ExtractGroup(linker.Normals, typeof(MDL0NormalNode));
                }
                break;

            case MDLResourceType.UVs:
                if (linker.UVs != null)
                {
                    ExtractGroup(linker.UVs, typeof(MDL0UVNode));
                }
                break;

            case MDLResourceType.Objects:
                //Break if no polygons defined
                if (linker.Polygons == null)
                {
                    break;
                }

                //Extract
                ExtractGroup(linker.Polygons, typeof(MDL0PolygonNode));

                //Attach materials to polygons.
                //This assumes that materials have already been parsed.

                List <ResourceNode> matList = ((MDL0Node)_parent)._matList;
                MDL0PolygonNode     poly;
                MDL0MaterialNode    mat;

                //Find DrawOpa or DrawXlu entry in Definition list
                foreach (ResourcePair p in *linker.Defs)
                {
                    if ((p.Name == "DrawOpa") || (p.Name == "DrawXlu"))
                    {
                        ushort dIndex = 0;
                        byte * pData  = (byte *)p.Data;
                        while (*pData++ == 4)
                        {
                            //Get polygon from index
                            dIndex = *(bushort *)(pData + 2);
                            if (dIndex >= _children.Count || dIndex < 0)
                            {
                                ((MDL0Node)Parent)._errors.Add("Object index was greater than the actual object count.");
                                SignalPropertyChange();
                                dIndex = 0;
                            }
                            poly = _children[dIndex] as MDL0PolygonNode;
                            //Get material from index
                            mat = matList[*(bushort *)pData] as MDL0MaterialNode;
                            //Get bone from index and assign
                            int boneIndex = *(bushort *)(pData + 4);
                            if (linker.BoneCache != null && boneIndex >= 0 && boneIndex < linker.BoneCache.Length)
                            {
                                poly.BoneNode = linker.BoneCache[boneIndex] as MDL0BoneNode;
                            }
                            //Assign material to polygon and add polygon to material reference list
                            (poly._material = mat)._polygons.Add(poly);
                            //Increment pointer
                            pData += 7;
                        }
                    }
                }
                break;

            case MDLResourceType.Colors:
                if (linker.Colors != null)
                {
                    ExtractGroup(linker.Colors, typeof(MDL0ColorNode));
                }
                break;

            case MDLResourceType.Textures:
                if (linker.Textures != null)
                {
                    ExtractGroup(linker.Textures, typeof(MDL0TextureNode));
                }
                break;

            case MDLResourceType.Palettes:
                if (linker.Palettes != null)
                {
                    ExtractGroup(linker.Palettes, typeof(MDL0TextureNode));
                }
                break;
            }
        }
        internal void Parse(MDL0Node model)
        {
            Influence   inf;
            ModelLinker linker = model._linker;

            int typeIndex = (int)_type;

            fixed(ResourceGroup **gList = &linker.Defs)
            if (gList[typeIndex] != null)
                ExtractGroup(gList[typeIndex], ModelLinker.TypeBank[typeIndex]);
            else
                return;     //Nothing to read

            //Special handling for bones and objects
            if (_type == MDLResourceType.Bones)
            {
                //Bones have been parsed from raw data as a flat list.
                //Bones re-assign parents in their Initialize block, so parents are true.
                //Parents must be assigned now as bones will be moved in memory when assigned as children.

                //Cache flat list
                linker.BoneCache = _children.Select(x => x as MDL0BoneNode).ToArray();

                //Reset children so we can rebuild
                _children.Clear();

                //Assign children using each bones' parent offset in case NodeTree is corrupted.
                //Bone parents are assigned when they are initialized in a flat array.
                foreach (MDL0BoneNode b in linker.BoneCache)
                {
                    MDL0Bone *header = b.Header;

                    //Assign true parent using parent header offset
                    int offset = header->_parentOffset;
                    if (offset != 0)
                    {
                        //Get address of parent header
                        MDL0Bone *pHeader = (MDL0Bone *)((byte *)header + offset);
                        //Search bone list for matching header
                        foreach (MDL0BoneNode b2 in linker.BoneCache)
                        {
                            if (pHeader == b2.Header)
                            {
                                b._parent = b2;
                                break;
                            }
                        }
                    }

                    if (b._boneFlags.HasFlag(BoneFlags.HasBillboardParent))
                    {
                        b._bbRefNode = model._linker.BoneCache[header->_bbIndex] as MDL0BoneNode;
                    }
                }

                //Make sure the node cache is the correct size
                int highest = 0;

                //Add bones to their parent's child lists and find highest node id
                foreach (MDL0BoneNode b in linker.BoneCache)
                {
                    b._parent._children.Add(b);

                    if (b._nodeIndex >= linker.NodeCache.Length && b._nodeIndex > highest)
                    {
                        highest = b._nodeIndex;
                    }
                }

                if (highest >= linker.NodeCache.Length)
                {
                    linker.NodeCache = new IMatrixNode[highest + 1];
                }

                //Populate node cache
                MDL0BoneNode bone = null;
                int          index;
                int          count = linker.BoneCache.Length;

                for (int i = 0; i < count; i++)
                {
                    linker.NodeCache[(bone = linker.BoneCache[i] as MDL0BoneNode)._nodeIndex] = bone;
                }

                int nullCount = 0;

                bool nodeTreeError = false;

                //Now that bones and primary influences have been cached, we can create weighted influences.
                foreach (ResourcePair p in *linker.Defs)
                {
                    if (p.Name == "NodeTree")
                    {
                        //Double check bone tree using the NodeTree definition.
                        //If the NodeTree is corrupt, the user will be informed that it needs to be rebuilt.
                        byte *pData     = (byte *)p.Data;
                        bool  fixCS0159 = false;

                        List <MDL0BoneNode> bones = linker.BoneCache.ToList();

STop:
                        if (*pData == 2)
                        {
                            bone  = linker.BoneCache[*(bushort *)(pData + 1)] as MDL0BoneNode;
                            index = *(bushort *)(pData + 3); //Parent bone node index

                            if (bone.Header->_parentOffset == 0)
                            {
                                if (!_children.Contains(bone))
                                {
                                    nodeTreeError = true;
                                    continue;
                                }
                                else
                                {
                                    bones.Remove(bone);
                                }
                            }
                            else
                            {
                                MDL0BoneNode parent = linker.NodeCache[index] as MDL0BoneNode;
                                if (parent == null || bone._parent != parent || !parent._children.Contains(bone))
                                {
                                    nodeTreeError = true;
                                    continue;
                                }
                                else
                                {
                                    bones.Remove(bone);
                                }
                            }
                            pData    += 5;
                            fixCS0159 = true;
                        }
                        if (fixCS0159)
                        {
                            fixCS0159 = false;
                            goto STop;
                        }

                        if (bones.Count > 0)
                        {
                            nodeTreeError = true;
                        }
                    }
                    else if (p.Name == "NodeMix")
                    {
                        //Use node mix to create weight groups
                        byte *pData     = (byte *)p.Data;
                        bool  fixCS0159 = false;
TTop:
                        switch (*pData)
                        {
                        //Type 3 is for weighted influences
                        case 3:
                            //Get index/count fields
                            index = *(bushort *)(pData + 1);
                            count = pData[3];
                            //Get data pointer (offset of 4)
                            MDL0NodeType3Entry *nEntry = (MDL0NodeType3Entry *)(pData + 4);
                            //Create influence with specified count
                            inf = new Influence();
                            //Iterate through weights, adding each to the influence
                            //Here, we are referring back to the NodeCache to grab the bone.
                            //Note that the weights do not reference other influences, only bones. There is a good reason for this.
                            MDL0BoneNode b           = null;
                            List <int>   nullIndices = new List <int>();
                            for (int i = 0; i < count; i++, nEntry++)
                            {
                                if (nEntry->_id < linker.NodeCache.Length && (b = (linker.NodeCache[nEntry->_id] as MDL0BoneNode)) != null)
                                {
                                    inf.AddWeight(new BoneWeight(b, nEntry->_value));
                                }
                                else
                                {
                                    nullIndices.Add(i);
                                }
                            }

                            bool noWeights = false;
                            if ((nullCount = nullIndices.Count) > 0)
                            {
                                List <BoneWeight> newWeights = new List <BoneWeight>();
                                for (int i = 0; i < inf.Weights.Count; i++)
                                {
                                    if (!nullIndices.Contains(i))
                                    {
                                        newWeights.Add(inf.Weights[i]);
                                    }
                                }
                                if (newWeights.Count == 0)
                                {
                                    noWeights = true;
                                }
                                else
                                {
                                    inf.SetWeights(newWeights);
                                }
                            }

                            //Add influence to model object, while adding it to the cache.
                            //Don't add user references here, they will be added during each object's initialization
                            if (!noWeights)
                            {
                                ((Influence)(linker.NodeCache[index] = model._influences.FindOrCreate(inf)))._index = index;
                            }

                            //Move data pointer to next entry
                            pData     = (byte *)nEntry;
                            fixCS0159 = true;
                            break;

                        //Type 5 is for primary influences
                        case 5:
                            pData    += 5;
                            fixCS0159 = true;
                            break;
                        }
                        if (fixCS0159)
                        {
                            fixCS0159 = false;
                            goto TTop;
                        }
                    }
                }

                if (nullCount > 0)
                {
                    model._errors.Add("There were " + nullCount + " null weights in NodeMix.");
                }

                if (nodeTreeError)
                {
                    model._errors.Add("The NodeTree definition did not match the bone tree.");
                }
            }

            else if (_type == MDLResourceType.Objects)
            {
                //Attach materials to polygons.
                //This assumes that materials have already been parsed.

                List <ResourceNode> matList = ((MDL0Node)_parent)._matList;
                MDL0ObjectNode      obj;
                MDL0MaterialNode    mat;

                //Find DrawOpa or DrawXlu entry in Definition list
                foreach (ResourcePair p in *linker.Defs)
                {
                    if ((p.Name == "DrawOpa") || (p.Name == "DrawXlu"))
                    {
                        bool isXLU = p.Name == "DrawXlu";

                        ushort objectIndex = 0;
                        byte * pData       = (byte *)p.Data;
                        while (*pData++ == 4)
                        {
                            //Get object with index
                            objectIndex = *(bushort *)(pData + 2);
                            if (objectIndex >= _children.Count || objectIndex < 0)
                            {
                                model._errors.Add("Object index was greater than the actual object count.");
                                objectIndex = 0;
                            }
                            obj = _children[objectIndex] as MDL0ObjectNode;

                            //Get material with index
                            mat = matList[*(bushort *)pData] as MDL0MaterialNode;

                            //Get bone with index
                            int          boneIndex = *(bushort *)(pData + 4);
                            MDL0BoneNode visBone   = null;
                            if (linker.BoneCache != null && boneIndex >= 0 && boneIndex < linker.BoneCache.Length)
                            {
                                visBone = linker.BoneCache[boneIndex] as MDL0BoneNode;
                            }

                            obj._drawCalls.Add(new DrawCall(obj)
                            {
                                _drawOrder         = pData[6],
                                _isXLU             = isXLU,
                                MaterialNode       = mat,
                                VisibilityBoneNode = visBone,
                            });

                            //Increment pointer
                            pData += 7;
                        }
                    }
                }

                foreach (MDL0ObjectNode m in _children)
                {
                    int max = 0;
                    foreach (DrawCall c in m._drawCalls)
                    {
                        max = Maths.Max(max, c.MaterialNode.Children.Count);
                        if (c.MaterialNode.MetalMaterial != null)
                        {
                            max = Maths.Max(max, c.MaterialNode.MetalMaterial.Children.Count);
                        }
                    }

                    bool hasUnused = false;
                    if (m._manager != null)
                    {
                        for (int i = max; i < 8; i++)
                        {
                            if (m._manager.HasTextureMatrix[i])
                            {
                                m._manager.HasTextureMatrix[i] = false;
                                m._forceRebuild = true;
                                hasUnused       = true;
                            }
                        }
                    }
                    if (hasUnused)
                    {
                        ((MDL0Node)Parent)._errors.Add("Object " + m.Index + " has unused texture matrices.");
                    }

                    //This error doesn't seem to always be true for factory models...
                    //if (m.HasTexMtx && m.HasNonFloatVertices)
                    //{
                    //    ((MDL0Node)Parent)._errors.Add("Object " + m.Index + " has texture matrices and non-float vertices, meaning it will explode in-game.");
                    //    m.SignalPropertyChange();
                    //}
                }
            }
        }
Beispiel #14
0
        private unsafe void RenderCatchCollision(TKContext c, Vector3 cam)
        {
            if (_event != 0x060A0800 && _event != 0x060A0900 && _event != 0x060A0A00)
            {
                return;
            }

            ResourceNode[] bl = _model._linker.BoneCache;

            int boneindex = _parameters[1];
            int size      = HitboxSize;

            Root.GetBoneIndex(ref boneindex);

            if (boneindex == 0) // if a hitbox is on TopN, make it follow TransN
            {
                if (Root.Data != null)
                {
                    boneindex = Root.Data._misc._boneRefs[4].boneIndex;
                    Root.GetBoneIndex(ref boneindex);
                }
                else
                {
                    int transindex = 0;
                    foreach (MDL0BoneNode bn in bl)
                    {
                        if (bn.Name.Equals("TransN"))
                        {
                            break;
                        }
                        transindex++;
                    }
                    if (transindex != bl.Length)
                    {
                        boneindex = transindex;
                    }
                }
            }
            MDL0BoneNode b = bl[boneindex] as MDL0BoneNode;

            Matrix     r         = b.Matrix.GetRotationMatrix();
            FrameState state     = b.Matrix.Derive();
            Vector3    bonePos   = state._translate;
            Vector3    pos       = new Vector3(Util.UnScalar(_parameters[3]), Util.UnScalar(_parameters[4]), Util.UnScalar(_parameters[5])) / state._scale;
            Vector3    globalPos = r.Multiply(pos);

            Matrix  m         = Matrix.TransformMatrix(new Vector3(1), state._rotate, globalPos + bonePos);
            Vector3 resultPos = m.GetPoint();

            m = Matrix.TransformMatrix(new Vector3(Util.UnScalar(size)), new Vector3(), resultPos);
            GL.PushMatrix();
            GL.MultMatrix((float *)&m);
            int    res       = 16;
            double drawangle = 360.0 / res;

            Vector3 color = Util.GetTypeColor(Util.HitboxType.Throwing);

            GL.Color4((color._x / 255.0f), (color._y / 225.0f), (color._z / 255.0f), 0.375f);
            GLDisplayList spheres = c.GetSphereList();

            spheres.Call();

            GL.PopMatrix();
        }
Beispiel #15
0
        public void Advance(int eventid, ModelEditControl _mainWindow)
        {
            if (eventid >= Children.Count)
            {
                return;
            }

            int list, index, type;
            MoveDefEventNode e = Children[eventid] as MoveDefEventNode;

            if (!_runEvents &&
                e._event != 0x00050000 &&
                e._event != 0x00110100 &&
                e._event != 0x00120000 &&
                e._event != 0x00130000)
            {
                return;
            }

            //Code what to do for each event here.
            switch (e._event)
            {
            case 0x00010100:     //Synchronous Timer
                _waitFrames = (int)((float)e.EventData.parameters[0]._data / 60000f);
                break;

            case 0x00020000:     //No Operation
                break;

            case 0x00020100:     //Asynchronous Timer
                _waitFrames = Math.Max((int)((float)e.EventData.parameters[0]._data / 60000f) - _totalFrames, 0);
                break;

            case 0x00040100:     //Set loop data
                _loopCount      = (int)e.EventData.parameters[0]._data;
                _loopStartIndex = e.Index + 1;
                _runEvents      = false;
                break;

            case 0x00050000:     //Start looping
                _looping      = true;
                _loopEndIndex = e.Index;
                _eventIndex   = _loopStartIndex;
                _runEvents    = true;
                break;

            case 0x01010000:     //Loop Rest
                _waitFrames = 1;
                break;

            case 0x06000D00:     //Offensive Collison
            case 0x062B0D00:     //Thrown Collision
                e.HitboxID   = (int)(e.EventData.parameters[0]._data & 0xFFFF);
                e.HitboxSize = (int)(e.EventData.parameters[5]._data);
                offensiveCollisions.Add(e);
                break;

            case 0x06050100:     //Body Collision
                _mainWindow.hurtBoxType = (int)(e.EventData.parameters[0]._data);
                break;

            case 0x06080200:     //Bone Collision
                int id = (int)(e.EventData.parameters[0]._data);
                if (Root.Model != null && Root.Model._linker.BoneCache.Length > id && id > 0)
                {
                    MDL0BoneNode bone = Root.Model._linker.BoneCache[id] as MDL0BoneNode;
                    switch ((int)(e.EventData.parameters[1]._data))
                    {
                    case 0:
                        bone._nodeColor = Color.Transparent;
                        bone._boneColor = Color.Transparent;
                        break;

                    case 1:
                        bone._nodeColor = bone._boneColor = Color.FromArgb(255, 255, 0);
                        break;

                    default:
                        bone._nodeColor = bone._boneColor = Color.FromArgb(0, 0, 255);
                        break;
                    }
                    _mainWindow.boneCollisions.Add(bone);
                }
                break;

            case 0x06060100:     //Undo Bone Collision
                foreach (MDL0BoneNode bone in _mainWindow.boneCollisions)
                {
                    bone._nodeColor = bone._boneColor = Color.Transparent;
                }
                _mainWindow.boneCollisions = new List <MDL0BoneNode>();
                break;

            case 0x060A0800:     //Catch Collision 1
            case 0x060A0900:     //Catch Collision 2
            case 0x060A0A00:     //Catch Collision 3
                e.HitboxID   = (int)(e.EventData.parameters[0]._data);
                e.HitboxSize = (int)(e.EventData.parameters[2]._data);
                catchCollisions.Add(e);
                break;

            case 0x060D0000:     //Terminate Catch Collisions
                catchCollisions = new List <MoveDefEventNode>();
                break;

            case 0x00060000:     //Loop break?
                _looping    = false;
                _eventIndex = _loopEndIndex + 1;
                _loopTime   = 0;
                break;

            case 0x06150F00:     //Special Offensive Collison
                e.HitboxID   = (int)(e.EventData.parameters[0]._data & 0xFFFF);
                e.HitboxSize = (int)(e.EventData.parameters[5]._data);
                specialOffensiveCollisions.Add(e);
                break;

            case 0x06040000:     //Terminate Collisions
                offensiveCollisions        = new List <MoveDefEventNode>();
                specialOffensiveCollisions = new List <MoveDefEventNode>();
                break;

            case 0x06030100:     //Delete hitbox
                foreach (MoveDefEventNode ev in offensiveCollisions)
                {
                    if (ev.HitboxID == (int)(ev.EventData.parameters[0]._data))
                    {
                        offensiveCollisions.Remove(ev);
                        break;
                    }
                }
                foreach (MoveDefEventNode ev in specialOffensiveCollisions)
                {
                    if (ev.HitboxID == (int)(ev.EventData.parameters[0]._data))
                    {
                        specialOffensiveCollisions.Remove(ev);
                        break;
                    }
                }
                break;

            case 0x04060100:     //Set anim frame - subaction timer unaffected
                _mainWindow.SetFrame((int)((float)e.EventData.parameters[0]._data / 60000f));
                break;

            case 0x00070100:     //Go to subroutine and return
                Root.GetLocation((int)e.EventData.parameters[0]._data, out list, out type, out index);
                subRoutine = Root.GetAction(list, type, index);
                if (subRoutine != null)
                {
                    subRoutineSetAt = _totalFrames;
                    subRoutine.actionReferencedBy = this;
                    subRoutine._subRoutine        = true;
                }
                break;

            case 0x00080000:     //Return
                _return     = true;
                _eventIndex = Children.Count;
                _idling     = true;
                break;

            case 0x00090100:     //Go to and do not return unless called
                Root.GetLocation((int)e.EventData.parameters[0]._data, out list, out type, out index);
                MoveDefActionNode a = Root.GetAction(list, type, index);
                if (a != null)
                {
                    subRoutineSetAt      = _totalFrames;
                    a.actionReferencedBy = this;
                    a._delete            = true;
                    _mainWindow.pnlMoveset.selectedActionNodes.Add(a);
                    //if (_eventIndex == Children.Count)
                    _mainWindow.pnlMoveset.selectedActionNodes.Remove(this);
                }
                break;

            case 0x0B000200:     //Model Changer 1
            case 0x0B010200:     //Model Changer 2
                if (Root.Model._polyList == null)
                {
                    break;
                }
                if (Root.data.mdlVisibility.Children.Count == 0)
                {
                    break;
                }
                MoveDefModelVisRefNode entry = Root.data.mdlVisibility.Children[(e._event >> 16 & 1)] as MoveDefModelVisRefNode;
                if (entry.Children.Count == 0)
                {
                    break;
                }
                MoveDefBoneSwitchNode list1 = entry.Children[(int)e.EventData.parameters[0]._data] as MoveDefBoneSwitchNode;
                if (list1.Children.Count == 0)
                {
                    break;
                }
                if ((int)e.EventData.parameters[1]._data > list1.Children.Count)
                {
                    foreach (MDL0PolygonNode p in Root.Model._polyList)
                    {
                        p._render = false;
                    }
                    break;
                }
                else if ((int)e.EventData.parameters[1]._data < 0)
                {
                    foreach (MoveDefModelVisGroupNode l in list1.Children)
                    {
                        foreach (MoveDefBoneIndexNode b in l.Children)
                        {
                            if (b.BoneNode == null)
                            {
                                continue;
                            }

                            foreach (MDL0PolygonNode p in b.BoneNode._manPolys)
                            {
                                p._render = false;
                            }
                        }
                    }
                    break;
                }
                MoveDefModelVisGroupNode list2 = list1.Children[(int)e.EventData.parameters[1]._data] as MoveDefModelVisGroupNode;
                if (list2.Children.Count == 0)
                {
                    break;
                }
                foreach (MoveDefModelVisGroupNode l in list1.Children)
                {
                    if (l.Index != (int)e.EventData.parameters[1]._data)
                    {
                        foreach (MoveDefBoneIndexNode b in l.Children)
                        {
                            if (b.BoneNode == null)
                            {
                                continue;
                            }

                            foreach (MDL0PolygonNode p in b.BoneNode._manPolys)
                            {
                                p._render = false;
                            }
                        }
                    }
                }
                foreach (MoveDefBoneIndexNode b in list2.Children)
                {
                    if (b.BoneNode == null)
                    {
                        continue;
                    }

                    foreach (MDL0PolygonNode p in b.BoneNode._manPolys)
                    {
                        p._render = true;
                    }
                }
                break;

            case 0x0B020100:
                if (Root.Model._polyList != null)
                {
                    bool val = e.EventData.parameters[0]._data != 0;
                    foreach (MDL0PolygonNode p in Root.Model._polyList)
                    {
                        p._render = val;
                    }
                    if (val)
                    {
                        _mainWindow.pnlMoveset.ResetModelVis();
                    }
                }
                break;

            case 0x00100200:     //Switch
                _cases          = new List <MoveDefEventParameterNode>();
                _caseIndices    = new List <int>();
                _runEvents      = false;
                _loopStartIndex = e.Index;
                break;

            case 0x00110100:     //Case
                if (!_runEvents)
                {
                    if (_cases != null && _caseIndices != null)
                    {
                        _cases.Add(e.Children[0] as MoveDefEventParameterNode);
                        _caseIndices.Add(e.Index);
                    }
                }
                else
                {
                    _eventIndex   = _loopEndIndex + 1;
                    _loopEndIndex = -1;
                }
                break;

            case 0x00120000:     //Default Case
                _defaultCaseIndex = e.Index;
                break;

            case 0x00130000:     //End Switch
                _runEvents    = true;
                _loopEndIndex = e.Index;
                //Apply cases
                int i = 0;
                MoveDefEventParameterNode Switch = Children[_loopStartIndex].Children[1] as MoveDefEventParameterNode;
                foreach (MoveDefEventParameterNode p in _cases)
                {
                    if (Switch.Compare(p, 2))
                    {
                        _eventIndex = _caseIndices[i] + 1;
                        break;
                    }
                    i++;
                }
                if (i == _cases.Count && _defaultCaseIndex != -1)
                {
                    _eventIndex = _defaultCaseIndex + 1;
                }
                _cases            = null;
                _defaultCaseIndex = -1;
                _loopStartIndex   = -1;
                break;

            case 0x00180000:     //Break
                _eventIndex   = _loopEndIndex + 1;
                _loopEndIndex = -1;
                break;
            }
        }
        private void MergeChildren(MDL0BoneNode parent, MDL0BoneNode child, ResourceNode res)
        {
            bool found = false;
            MDL0BoneNode bone = null;
            foreach (MDL0BoneNode b1 in parent.Children)
                if (b1.Name == child.Name)
                {
                    found = true;
                    bone = b1;
                    foreach (MDL0BoneNode b in child.Children)
                        MergeChildren(b1, b, res);
                    break;
                }
            if (!found)
            {
                MDL0BoneNode b = child.Clone();
                parent.InsertChild(b, true, child.Index);
                bone = b;
            }
            else
                found = false;

            if (res is MDL0ObjectNode)
            {
                MDL0ObjectNode poly = res as MDL0ObjectNode;
                foreach (Vertex3 v in poly._manager._vertices)
                    if (v._matrixNode == child)
                        v.MatrixNode = bone;
            }
            else if (res is MDL0Node)
            {
                MDL0Node mdl = res as MDL0Node;
                foreach (MDL0ObjectNode poly in mdl.FindChild("Objects", true).Children)
                {
                    foreach (Vertex3 v in poly._manager._vertices)
                        if (v._matrixNode == child)
                            v.MatrixNode = bone;
                }
            }
        }
        private void CreateNode()
        {
            TreeView.BeginUpdate();

            int id = 1;
            string name = "NewBone0";
            MDL0Node model = ((MDL0BoneNode)_resource).Model;
            Top:
            foreach (MDL0BoneNode b in model._linker.BoneCache)
            {
                if (b.Name == name)
                {
                    name = "NewBone" + id++;
                    goto Top;
                }
            }
            MDL0BoneNode bone = new MDL0BoneNode() { Name = name };
            bone.Scale = new Vector3(1);

            bone._bindMatrix =
            bone._inverseBindMatrix =
            bone._frameMatrix =
            bone._inverseFrameMatrix =
            Matrix.Identity;

            _resource.AddChild(bone, true);
            bone.Moved = true;

            TreeView.EndUpdate();

            Nodes[Nodes.Count - 1].EnsureVisible();
            //TreeView.SelectedNode = Nodes[Nodes.Count - 1];
        }
        private void comboBox2_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (comboBox1.SelectedItem == null)
                return;

            _parent = (MDL0BoneNode)comboBox2.SelectedItem;
        }
Beispiel #19
0
        public void RunEvent(int eventIndex)
        {
            //Get the current event and its id
            Event e = this[eventIndex];

            if (e == null)
            {
                return;
            }

            uint eventId    = e.EventID;
            byte eNameSpace = e.NameSpace;
            byte eID        = e.ID;
            byte eCount     = (byte)e.Count;
            byte eUnk       = e.Unknown;

            //Get raw parameter list
            int[] p = e.Select(x => x.Data).ToArray();

            //Run event only if allowed or if an exception
            if (!_runEvents && !_runExceptions.Contains((eNameSpace << 8) | eID))
            {
                return;
            }

            //Variables that are used often
            int                 id;
            Script              script;
            Event               ev;
            int                 index;
            ArticleInfo         articleInfo;
            HitBox              hitbox;
            RequirementInfo     reqInfo;
            ActionChangeInfo    aChangeInfo;
            SubActionChangeInfo sChangeInfo;

            //Code what to do for each event here!
            switch (eventId)
            {
            case 0x01000000:     //Loop Rest 1 for Goto
                Application.DoEvents();
                break;

            case 0x00010100:     //Synchronous Timer
                _waitFrames = (int)(e[0].RealValue + 0.5f);
                break;

            case 0x00020000:     //No Operation
                break;

            case 0x00020100:     //Asynchronous Timer
                _waitFrames = Math.Max((int)(e[0].RealValue + 0.5f) - _frameIndex, 0);
                break;

            case 0x00040100:     //Set loop data
                _loopCount      = p[0];
                _loopStartIndex = e.Index + 1;
                _runEvents      = false;
                break;

            case 0x00050000:     //Start looping
                _looping      = true;
                _loopEndIndex = e.Index;
                _eventIndex   = _loopStartIndex;
                _runEvents    = true;
                break;

            case 0x000A0100:     //If
            case 0x000A0200:     //If Value
            case 0x000A0300:     //If Unk
            case 0x000A0400:     //If Comparison
                if (_runEvents)
                {
                    _currentIf = _ifIndex++;
                    _runEvents = false;
                    _ifInfo    = new IfInfo();

                    index = eventIndex + 1;
                    while (true)
                    {
                        if (index < Count)
                        {
                            ev = this[index];
                            id = (int)ev.EventID;
                            if (id == 0x000B0100 ||
                                id == 0x000B0200 ||
                                id == 0x000B0300 ||
                                id == 0x000B0400)
                            {
                                index++;
                            }
                            else
                            {
                                break;
                            }
                        }
                        else
                        {
                            break;
                        }
                    }
                    _ifInfo._reqIndices = new List <int>();
                    _ifInfo._reqIndices.Add(index);

                    _ifEndIndices.Add(0);
                    reqInfo = new RequirementInfo(p[0]);
                    for (int i = 1; i < ((eventId >> 8) & 0xFF); i++)
                    {
                        reqInfo._values.Add(e[i]);
                    }
                    _ifInfo._requirements = new List <List <RequirementInfo> >();
                    _ifInfo._requirements.Add(new List <RequirementInfo>());
                    _ifInfo._requirements[0].Add(reqInfo);
                }
                else
                {
                    _ifIndex++;
                }
                break;

            case 0x000E0000:     //Else
                if (!_runEvents)
                {
                    if (_ifIndex == _currentIf)
                    {
                        _ifInfo._elseIndex = eventIndex;
                    }
                }
                else
                {
                    if (_ifIndex == _currentIf + 1)
                    {
                        _eventIndex = _ifInfo._endIndex;
                    }
                }
                break;

            case 0x000D0100:     //Else If (req)
            case 0x000D0200:     //Else If Value (req val)
            case 0x000D0300:     //Else If Unk (req val unk)
            case 0x000D0400:     //Else If Comparison (req var val var)

                if (!_runEvents)
                {
                    if (_ifIndex == _currentIf)
                    {
                        index = eventIndex + 1;
                        while (true)
                        {
                            if (index < Count)
                            {
                                ev = this[index];
                                id = (int)ev.EventID;
                                if (id == 0x000B0100 ||
                                    id == 0x000B0200 ||
                                    id == 0x000B0300 ||
                                    id == 0x000B0400)
                                {
                                    index++;
                                }
                                else
                                {
                                    break;
                                }
                            }
                            else
                            {
                                break;
                            }
                        }
                        _ifInfo._reqIndices.Add(index);
                    }
                }
                else
                {
                    if (_ifIndex == _currentIf + 1)
                    {
                        _eventIndex = _ifInfo._endIndex;
                    }
                }

                if (!_runEvents && _ifIndex == _currentIf + 1)
                {
                    reqInfo = new RequirementInfo(p[0]);
                    for (int i = 1; i < eCount; i++)
                    {
                        reqInfo._values.Add(e[i]);
                    }
                    _ifInfo._requirements.Add(new List <RequirementInfo>());
                    _ifInfo._requirements[0].Add(reqInfo);
                }
                break;

            case 0x000B0100:     //And If
            case 0x000B0200:     //And If Value
            case 0x000B0300:     //And If Unk
            case 0x000B0400:     //And If Comparison
                if (!_runEvents && _ifIndex == _currentIf + 1)
                {
                    reqInfo = new RequirementInfo(p[0]);
                    for (int i = 1; i < eCount; i++)
                    {
                        reqInfo._values.Add(e[i]);
                    }
                    _ifInfo._requirements.Add(new List <RequirementInfo>());
                    _ifInfo._requirements[0].Add(reqInfo);
                }
                break;

            case 0x000F0000:     //End if
                _ifIndex--;
                if (!_runEvents)
                {
                    if (_ifIndex == _currentIf)
                    {
                        _ifInfo._endIndex = _ifEndIndices[_currentIf] = eventIndex + 1;
                        _eventIndex       = _ifInfo.Run();
                        _runEvents        = true;
                    }
                }
                break;

            case 0x00100200:     //Switch
                _cases       = new List <Parameter>();
                _caseIndices = new List <int>();

                //Turn off events to examine them until end switch
                //Then the examined data will be evaluated
                _runEvents = false;

                _switchStartIndex = eventIndex;
                break;

            case 0x00110100:     //Case
                if (!_runEvents)
                {
                    if (_cases != null && _caseIndices != null)
                    {
                        _cases.Add(e[0]);
                        _caseIndices.Add(e.Index);
                    }
                }
                else
                {
                    _eventIndex     = _switchEndIndex + 1;
                    _switchEndIndex = -1;
                }
                break;

            case 0x00120000:     //Default Case
                _defaultCaseIndex = e.Index;
                break;

            case 0x00130000:     //End Switch
                _runEvents      = true;
                _switchEndIndex = e.Index;

                //Apply cases
                index = 0;
                if (_switchStartIndex >= 0 && _switchStartIndex < Count)
                {
                    Parameter Switch = this[_switchStartIndex][1];
                    foreach (Parameter param in _cases)
                    {
                        if (Switch.Compare(param, 2))
                        {
                            _eventIndex = _caseIndices[index] + 1;
                            break;
                        }
                        index++;
                    }
                }

                if (_cases != null && index == _cases.Count && _defaultCaseIndex != -1)
                {
                    _eventIndex = _defaultCaseIndex + 1;
                }

                _defaultCaseIndex = -1;
                _switchStartIndex = -1;
                _cases            = null;

                break;

            case 0x00180000:     //Break
                _eventIndex     = _switchEndIndex + 1;
                _switchEndIndex = -1;
                break;

            case 0x10050200:     //Article Visiblity
                id = p[0];
                if (id < 0 || id >= RunTime._articles.Length)
                {
                    break;
                }
                articleInfo = RunTime._articles[id];
                if (articleInfo != null && articleInfo._model != null)
                {
                    articleInfo._model._visible = p[1] != 0;
                }
                break;

            case 0x01010000:     //Loop Rest
                _waitFrames = 1;
                break;

            case 0x06000D00:     //Offensive Collison
            case 0x062B0D00:     //Thrown Collision
                hitbox            = new HitBox(e, Article != null ? Article.Index : -1);
                hitbox.HitboxID   = (int)(p[0] & 0xFFFF);
                hitbox.HitboxSize = p[5];
                RunTime._hitBoxes.Add(hitbox);
                break;

            case 0x06050100:     //Body Collision
                _hurtBoxType = p[0];
                break;

            case 0x06080200:     //Bone Collision
                id = p[0];
                if (Root.Model != null && Root.Model._linker.BoneCache.Length > id && id >= 0)
                {
                    MDL0BoneNode bone = Root.Model._linker.BoneCache[id] as MDL0BoneNode;
                    switch ((int)p[1])
                    {
                    case 0:
                        bone._nodeColor = Color.Transparent;
                        bone._boneColor = Color.Transparent;
                        break;

                    case 1:
                        bone._nodeColor = bone._boneColor = Color.FromArgb(255, 255, 0);
                        break;

                    default:
                        bone._nodeColor = bone._boneColor = Color.FromArgb(0, 0, 255);
                        break;
                    }
                    _boneCollisions.Add(bone);
                }
                break;

            case 0x06060100:     //Undo Bone Collision
                foreach (MDL0BoneNode bone in _boneCollisions)
                {
                    bone._nodeColor = bone._boneColor = Color.Transparent;
                }
                _boneCollisions = new List <MDL0BoneNode>();
                break;

            case 0x060A0800:     //Catch Collision 1
            case 0x060A0900:     //Catch Collision 2
            case 0x060A0A00:     //Catch Collision 3
                hitbox            = new HitBox(e, Article != null ? Article.Index : -1);
                hitbox.HitboxID   = p[0];
                hitbox.HitboxSize = p[2];
                RunTime._hitBoxes.Add(hitbox);
                break;

            case 0x060D0000:     //Terminate Catch Collisions
                for (int i = 0; i < RunTime._hitBoxes.Count; i++)
                {
                    if (RunTime._hitBoxes[i].IsCatch())
                    {
                        RunTime._hitBoxes.RemoveAt(i--);
                    }
                }
                break;

            case 0x00060000:     //Loop break
                _looping    = false;
                _eventIndex = _loopEndIndex + 1;
                _loopTime   = 0;
                break;

            case 0x06150F00:     //Special Offensive Collison
                hitbox            = new HitBox(e, Article != null ? Article.Index : -1);
                hitbox.HitboxID   = (int)(p[0] & 0xFFFF);
                hitbox.HitboxSize = p[5];
                RunTime._hitBoxes.Add(hitbox);
                break;

            case 0x06040000:     //Terminate Collisions
                for (int i = 0; i < RunTime._hitBoxes.Count; i++)
                {
                    if (RunTime._hitBoxes[i].IsOffensive(true))
                    {
                        RunTime._hitBoxes.RemoveAt(i--);
                    }
                }
                break;

            case 0x06030100:     //Delete hitbox
                for (int i = 0; i < RunTime._hitBoxes.Count; i++)
                {
                    HitBox hbox = RunTime._hitBoxes[i];
                    if (hbox.HitboxID == p[0] && hbox.IsOffensive(true))
                    {
                        RunTime._hitBoxes.RemoveAt(i--);
                        break;
                    }
                }
                break;

            case 0x060C0100:     //Delete Catch Collision
                for (int i = 0; i < RunTime._hitBoxes.Count; i++)
                {
                    HitBox hbox = RunTime._hitBoxes[i];
                    if (hbox.HitboxID == p[0] && hbox.IsCatch())
                    {
                        RunTime._hitBoxes.RemoveAt(i--);
                        break;
                    }
                }
                break;

            case 0x061B0500:     //Move hitbox
                foreach (HitBox hbox in RunTime._hitBoxes)
                {
                    if (hbox.HitboxID == p[0] && hbox.IsOffensive(true))
                    {
                        hbox._parameters[1] = p[1];
                        hbox._parameters[6] = p[2];
                        hbox._parameters[7] = p[3];
                        hbox._parameters[8] = p[4];
                        break;
                    }
                }
                break;

            case 0x04060100:     //Set animation frame
                //if (Article == null)
                //    RunTime.SetFrame((int)(e[0].RealValue + 0.05f));
                //else
                //    RunTime._articles[Article.Index].SetFrame((int)(e[0].RealValue + 0.05f));
                break;

            case 0x00070100:     //Subroutine
                script = (e[0] as EventOffset)._script;
                if (script != null && script != _script)
                {
                    script.Reset();
                    RunTime._runningScripts.Add(script);
                    script.SetFrame(0);
                }
                break;

            case 0x00080000:     //Return
                _return     = true;
                _eventIndex = Count;
                if (RunTime._runningScripts.Contains(_script))
                {
                    RunTime._runningScripts.Remove(_script);
                }
                break;

            case 0x00090100:     //Go to
                script = (e[0] as EventOffset)._script;
                if (script != null && script != _script)
                {
                    RunTime._runningScripts.Remove(_script);
                    script.Reset();
                    RunTime._runningScripts.Add(script);
                    script.SetFrame(0);
                }
                break;

            case 0x0A030100:     //Stop sound
                id = p[0];
                if (RunTime._playingSounds.ContainsKey(id))
                {
                    List <AudioInfo> aList = RunTime._playingSounds[id];
                    foreach (AudioInfo aInfo in aList)
                    {
                        if (aInfo._buffer != null)
                        {
                            aInfo._buffer.Stop();
                            aInfo._buffer.Dispose();
                            aInfo._stream.Dispose();
                        }
                    }
                    RunTime._playingSounds.Remove(id);
                }
                break;

            case 0x0A000100:     //Play sound
            case 0x0A010100:
            case 0x0A020100:
            case 0x0A040100:
            case 0x0A050100:
            case 0x0A060100:
            case 0x0A070100:
            case 0x0A080100:
            case 0x0A090100:
            case 0x0A0A0100:
            case 0x0A0B0100:
            case 0x0A0C0100:
            case 0x0A0D0100:
            case 0x0A0E0100:
            case 0x0A0F0100:

                if (RunTime._muteSFX)
                {
                    break;
                }

                id = p[0];
                if (Manager.SoundArchive != null)
                {
                    RSARNode             node   = Manager.SoundArchive;
                    List <RSAREntryNode> sounds = node._infoCache[0];
                    if (id >= 0 && id < sounds.Count)
                    {
                        RSARSoundNode s = sounds[id] as RSARSoundNode;
                        if (s != null)
                        {
                            IAudioStream stream = s.CreateStreams()[0];
                            AudioBuffer  b      = Manager._audioProvider.CreateBuffer(stream);
                            AudioInfo    info   = new AudioInfo(b, stream);

                            if (RunTime._playingSounds.ContainsKey(id))
                            {
                                RunTime._playingSounds[id].Add(info);
                            }
                            else
                            {
                                RunTime._playingSounds[id] = new List <AudioInfo>()
                                {
                                    info
                                }
                            };

                            b.Reset();
                            b.Seek(0);
                            b.Play();
                        }
                    }
                }
                break;

            case 0x0B000200:     //Model Changer 1
            case 0x0B010200:     //Model Changer 2

                ModelVisibility visNode = null;
                if (Article != null)
                {
                    //Check if we have data to work with
                    articleInfo = RunTime._articles[Article.Index];

                    if (articleInfo == null ||
                        articleInfo._model == null ||
                        articleInfo._model._objList == null ||
                        articleInfo._article._mdlVis == null ||
                        articleInfo._article._mdlVis.Count == 0)
                    {
                        break;
                    }

                    visNode = articleInfo._article._mdlVis;
                }
                else
                {
                    //Check if we have data to work with
                    if (Root.Model._objList == null ||
                        Root.Data._modelVis.Count == 0)
                    {
                        break;
                    }

                    visNode = Root.Data._modelVis;
                }

                //Get the target reference
                ModelVisReference refEntry = Root.Data._modelVis[((int)(eventId >> 16 & 1))];

                //Check if the reference and switch id is usable
                if (refEntry.Count == 0 || p[0] < 0 || p[0] >= refEntry.Count)
                {
                    break;
                }

                //Turn off objects
                ModelVisBoneSwitch SwitchNode = refEntry[p[0]];
                foreach (ModelVisGroup grp in SwitchNode)
                {
                    foreach (BoneIndexValue b in grp._bones)
                    {
                        if (b.BoneNode != null)
                        {
                            foreach (MDL0ObjectNode obj in b.BoneNode._manPolys)
                            {
                                obj._render = false;
                            }
                        }
                    }
                }

                //Check if the group id is usable
                if (p[1] > SwitchNode.Count || p[1] < 0)
                {
                    break;
                }

                //Turn on objects
                ModelVisGroup group = SwitchNode[p[1]];
                if (group != null)
                {
                    foreach (BoneIndexValue b in group._bones)
                    {
                        if (b.BoneNode != null)
                        {
                            foreach (MDL0ObjectNode obj in b.BoneNode._manPolys)
                            {
                                obj._render = true;
                            }
                        }
                    }
                }

                break;

            case 0x0B020100:     //Model visibility
                if (Article == null)
                {
                    Root.Model._visible = p[0] != 0;
                }
                else if (Article.Index < RunTime._articles.Length && RunTime._articles[Article.Index]._model != null)
                {
                    RunTime._articles[Article.Index]._model._visible = p[0] != 0;
                }
                break;

            case 0x0D000200:     //Concurrent Infinite Loop
                index = p[0];
                EventOffset off = (e[1] as EventOffset);
                if (off._script != null)
                {
                    if (RunTime._concurrentLoopScripts.ContainsKey(index))
                    {
                        RunTime._concurrentLoopScripts.Remove(index);
                    }
                    RunTime._concurrentLoopScripts.Add(index, off._script);
                }
                break;

            case 0x0D010100:     //Terminate Concurrent Infinite Loop
                index = p[0];
                if (RunTime._concurrentLoopScripts.ContainsKey(index))
                {
                    RunTime._concurrentLoopScripts.Remove(index);
                }
                break;

            case 0x0E000100:     //Set Air/Ground
                RunTime._location = (RunTime.Location)(p[0]);
                break;

            case 0x10000100:     //Generate Article
            case 0x10000200:     //Generate Article
            case 0x10030100:     //Remove Article

                //These events do a similar job!
                bool removeArticle = eID == 3;

                //Make sure we have all the data we need available
                MainControl main  = MainForm.Instance._mainControl;
                MovesetFile mNode = Manager.Moveset;
                if (mNode == null)
                {
                    break;
                }
                DataSection d = mNode.Data;
                if (d == null)
                {
                    break;
                }

                //Get the id of the article to be called and check it
                int aId2 = p[0];
                if (aId2 < 0 || aId2 >= RunTime._articles.Length)
                {
                    break;
                }

                //Get the called article from the article list
                articleInfo = RunTime._articles[aId2];

                if (articleInfo == null)
                {
                    return;
                }

                //Remove or add the article
                if (removeArticle)
                {
                    if (!articleInfo.Running)
                    {
                        return;
                    }

                    //Remove the article's model from the scene
                    if (articleInfo._model != null)
                    {
                        main.RemoveTarget(articleInfo._model);
                        articleInfo._model._visible = false;
                    }

                    //This article is no longer available for use
                    articleInfo.Running = false;
                }
                else
                {
                    if (articleInfo.Running)
                    {
                        return;
                    }

                    //Add the article's model to the scene
                    if (articleInfo._model != null)
                    {
                        main.AddTarget(articleInfo._model);
                        articleInfo._model._visible = true;
                    }

                    //This article is now available for use
                    articleInfo.Running = true;
                }
                break;

            case 0x10040200:     //Set Anchored Article SubAction
            case 0x10070200:     //Set Remote Article SubAction
                id = p[0];
                int sId = p[1];
                if (id < 0 || id >= RunTime._articles.Length)
                {
                    break;
                }

                //Get the called article from the article list
                articleInfo = RunTime._articles[id];
                if (articleInfo != null)
                {
                    articleInfo.SubactionIndex = sId;
                    articleInfo._setAt         = _frameIndex;
                }
                break;

            case 0x10010200:     //Set Ex-Anchored Article Action
                break;

            case 0x12000200:     //Basic Var Set
            case 0x12060200:     //Float Var Set
                e[1].RealValue = e[0].RealValue;
                break;

            case 0x12010200:     //Basic Var Add
            case 0x12070200:     //Float Var Add
                e[1].RealValue = e[1].RealValue + e[0].RealValue;
                break;

            case 0x12020200:     //Basic Var Sub
            case 0x12080200:     //Float Var Sub
                e[1].RealValue = e[1].RealValue - e[0].RealValue;
                break;

            case 0x12030100:     //Basic Var Inc
                e[0].RealValue = e[0].RealValue + 1.0f;
                break;

            case 0x12040100:     //Basic Var Dec
                e[0].RealValue = e[0].RealValue - 1.0f;
                break;

            case 0x120A0100:     //Bit Variable Set
                e[0].RealValue = 1.0f;
                break;

            case 0x120B0100:     //Bit Variable Clear
                e[0].RealValue = 0.0f;
                break;

            case 0x120F0200:     //Float Variable Multiply
                e[1].RealValue = e[1].RealValue * e[0].RealValue;
                break;

            case 0x12100200:     //Float Variable Divide
                if (e[0].RealValue != 0)
                {
                    e[1].RealValue = e[1].RealValue / e[0].RealValue;
                }
                break;

            case 0x64000000:     //Allow Interrupt
                RunTime._allowInterrupt = true;
                break;

            case 0x02000300:     //Change Action Status
            case 0x02000400:
            case 0x02000500:
            case 0x02000600:

                break;

            case 0x02010200:     //Change Action
            case 0x02010300:
            case 0x02010400:
            case 0x02010500:
                aChangeInfo = new ActionChangeInfo(p[0]);
                reqInfo     = new RequirementInfo(p[1]);
                for (int i = 2; i < Count; i++)
                {
                    reqInfo._values.Add(e[i]);
                }
                aChangeInfo._requirements.Add(reqInfo);
                RunTime.AddActionChangeInfo(aChangeInfo);
                break;

            case 0x02040100:     //Additional Change Action Requirement
            case 0x02040200:
            case 0x02040300:
            case 0x02040400:

                break;

            case 0x02060100:     //Enable Action Status ID
                break;

            case 0x02080100:     //Disable Action Status ID
                break;

            case 0x02090200:     //Invert Action Status ID
                break;

            case 0x020A0100:     //Allow Specific Interrupt
                break;

            case 0x020B0100:     //Disallow Specific Interrupt
                break;

            case 0x020C0100:     //Unregister Interrupt
                break;

            case 0x04000100:     //Change Subaction
            case 0x04000200:
                sChangeInfo = new SubActionChangeInfo(p[0], eCount == 2 && p[1] != 0);
                RunTime.AddSubActionChangeInfo(sChangeInfo);
                break;

            case 0x04010200:     //Change Subaction
                sChangeInfo = new SubActionChangeInfo(p[0], false);
                sChangeInfo._requirements.Add(new RequirementInfo(p[1]));
                RunTime.AddSubActionChangeInfo(sChangeInfo);
                break;
            }
        }
        private static unsafe void WriteControllers(MDL0Node model, XmlWriter writer)
        {
            if (model._objList == null)
                return;

            writer.WriteStartElement("library_controllers");

            int g = 0;
            //List<MDL0BoneNode> boneSet = new List<MDL0BoneNode>();

            MDL0BoneNode[] bones = new MDL0BoneNode[model._linker.BoneCache.Length];
            model._linker.BoneCache.CopyTo(bones, 0);

            //foreach (MDL0BoneNode b in model._linker.BoneCache)
            //{
            //    b._nodeIndex = g++;
            //    boneSet.Add(b);
            //}

            HashSet<float> temp = new HashSet<float>();
            Matrix m;
            bool first;

            foreach (MDL0ObjectNode poly in model._objList)
            {
                List<Vertex3> verts = poly._manager._vertices;

                writer.WriteStartElement("controller");
                writer.WriteAttributeString("id", poly.Name + "_Controller");
                writer.WriteStartElement("skin");
                writer.WriteAttributeString("source", "#" + poly.Name);

                writer.WriteStartElement("bind_shape_matrix");

                //Set bind pose matrix
                //if (poly._singleBind != null)
                //    m = poly._singleBind.Matrix;
                //else
                    m = Matrix.Identity;

                writer.WriteString(WriteMatrix(m));

                writer.WriteEndElement();

                //Get list of used bones and weights

                //int index = 0;
                if (poly._matrixNode != null)
                {
                    foreach (BoneWeight w in poly._matrixNode.Weights)
                    {
                        //if (!boneSet.Contains(w.Bone))
                        //{
                        //    boneSet.Add(w.Bone);
                        //    w.Bone._nodeIndex = index++;
                        //}
                        //if (!weightSet.Contains(w.Weight))
                            temp.Add(w.Weight);
                    }
                }
                else
                {
                    foreach (Vertex3 v in verts)
                        foreach (BoneWeight w in v._matrixNode.Weights)
                        {
                            //if (!boneSet.Contains(w.Bone))
                            //{
                            //    boneSet.Add(w.Bone);
                            //    w.Bone._nodeIndex = index++;
                            //}
                            //if (!weightSet.Contains(w.Weight))
                                temp.Add(w.Weight);
                        }
                }

                float[] weightSet = new float[temp.Count];
                temp.CopyTo(weightSet);

                //Write joint source
                writer.WriteStartElement("source");
                writer.WriteAttributeString("id", poly.Name + "_Joints");

                //Node array
                writer.WriteStartElement("Name_array");
                writer.WriteAttributeString("id", poly.Name + "_JointArr");
                //writer.WriteAttributeString("count", boneSet.Count.ToString());
                writer.WriteAttributeString("count", bones.Length.ToString());

                first = true;
                //foreach (MDL0BoneNode b in boneSet)
                foreach (MDL0BoneNode b in bones)
                {
                    if (first)
                        first = false;
                    else
                        writer.WriteString(" ");
                    writer.WriteString(b.Name);
                }
                writer.WriteEndElement(); //Name_array

                //Technique
                writer.WriteStartElement("technique_common");
                writer.WriteStartElement("accessor");
                writer.WriteAttributeString("source", String.Format("#{0}_JointArr", poly.Name));
                //writer.WriteAttributeString("count", boneSet.Count.ToString());
                writer.WriteAttributeString("count", bones.Length.ToString());
                writer.WriteStartElement("param");
                writer.WriteAttributeString("name", "JOINT");
                writer.WriteAttributeString("type", "Name");
                writer.WriteEndElement(); //param
                writer.WriteEndElement(); //accessor
                writer.WriteEndElement(); //technique

                writer.WriteEndElement(); //joint source

                //Inverse matrices source
                writer.WriteStartElement("source");
                writer.WriteAttributeString("id", poly.Name + "_Matrices");

                writer.WriteStartElement("float_array");
                writer.WriteAttributeString("id", poly.Name + "_MatArr");
                //writer.WriteAttributeString("count", (boneSet.Count * 16).ToString());
                writer.WriteAttributeString("count", (bones.Length * 16).ToString());

                first = true;
                foreach (MDL0BoneNode b in bones)
                {
                    if (first)
                        first = false;
                    else
                        writer.WriteString(" ");
                    writer.WriteString(WriteMatrix(b.InverseBindMatrix));
                }
                writer.WriteEndElement(); //float_array

                //Technique
                writer.WriteStartElement("technique_common");
                writer.WriteStartElement("accessor");
                writer.WriteAttributeString("source", String.Format("#{0}_MatArr", poly.Name));
                //writer.WriteAttributeString("count", boneSet.Count.ToString());
                writer.WriteAttributeString("count", bones.Length.ToString());
                writer.WriteAttributeString("stride", "16");
                writer.WriteStartElement("param");
                writer.WriteAttributeString("type", "float4x4");
                writer.WriteEndElement(); //param
                writer.WriteEndElement(); //accessor
                writer.WriteEndElement(); //technique

                writer.WriteEndElement(); //source

                //Weights source
                writer.WriteStartElement("source");
                writer.WriteAttributeString("id", poly.Name + "_Weights");

                writer.WriteStartElement("float_array");
                writer.WriteAttributeString("id", poly.Name + "_WeightArr");
                writer.WriteAttributeString("count", weightSet.Length.ToString());
                first = true;

                foreach (float f in weightSet)
                {
                    if (first)
                        first = false;
                    else
                        writer.WriteString(" ");
                    writer.WriteValue(f);
                }
                writer.WriteEndElement();

                //Technique
                writer.WriteStartElement("technique_common");
                writer.WriteStartElement("accessor");
                writer.WriteAttributeString("source", String.Format("#{0}_WeightArr", poly.Name));
                writer.WriteAttributeString("count", weightSet.Length.ToString());
                writer.WriteStartElement("param");
                writer.WriteAttributeString("type", "float");
                writer.WriteEndElement(); //param
                writer.WriteEndElement(); //accessor
                writer.WriteEndElement(); //technique

                writer.WriteEndElement(); //source

                //Joint bindings
                writer.WriteStartElement("joints");
                writer.WriteStartElement("input");
                writer.WriteAttributeString("semantic", "JOINT");
                writer.WriteAttributeString("source", String.Format("#{0}_Joints", poly.Name));
                writer.WriteEndElement(); //input
                writer.WriteStartElement("input");
                writer.WriteAttributeString("semantic", "INV_BIND_MATRIX");
                writer.WriteAttributeString("source", String.Format("#{0}_Matrices", poly.Name));
                writer.WriteEndElement(); //input
                writer.WriteEndElement(); //joints

                //Vertex weights, one for each vertex in geometry
                writer.WriteStartElement("vertex_weights");
                writer.WriteAttributeString("count", verts.Count.ToString());
                writer.WriteStartElement("input");
                writer.WriteAttributeString("semantic", "JOINT");
                writer.WriteAttributeString("offset", "0");
                writer.WriteAttributeString("source", String.Format("#{0}_Joints", poly.Name));
                writer.WriteEndElement(); //input
                writer.WriteStartElement("input");
                writer.WriteAttributeString("semantic", "WEIGHT");
                writer.WriteAttributeString("offset", "1");
                writer.WriteAttributeString("source", String.Format("#{0}_Weights", poly.Name));
                writer.WriteEndElement(); //input

                writer.WriteStartElement("vcount");
                first = true;
                if (poly._matrixNode != null)
                    for (int i = 0; i < verts.Count; i++)
                    {
                        if (first)
                            first = false;
                        else
                            writer.WriteString(" ");
                        writer.WriteString(poly._matrixNode.Weights.Count.ToString(CultureInfo.InvariantCulture.NumberFormat));
                    }
                else
                    foreach (Vertex3 v in verts)
                    {
                        if (first)
                            first = false;
                        else
                            writer.WriteString(" ");
                        writer.WriteString(v._matrixNode.Weights.Count.ToString(CultureInfo.InvariantCulture.NumberFormat));
                    }

                writer.WriteEndElement(); //vcount

                writer.WriteStartElement("v");

                first = true;
                if (poly._matrixNode != null)
                    for (int i = 0; i < verts.Count; i++)
                        foreach (BoneWeight w in poly._matrixNode.Weights)
                        {
                            if (first)
                                first = false;
                            else
                                writer.WriteString(" ");
                            //writer.WriteString(w.Bone._nodeIndex.ToString());
                            writer.WriteString(Array.IndexOf(bones, w.Bone).ToString(CultureInfo.InvariantCulture.NumberFormat));
                            writer.WriteString(" ");
                            writer.WriteString(Array.IndexOf(weightSet, w.Weight).ToString(CultureInfo.InvariantCulture.NumberFormat));
                        }
                else
                    foreach (Vertex3 v in verts)
                        foreach (BoneWeight w in v._matrixNode.Weights)
                        {
                            if (first)
                                first = false;
                            else
                                writer.WriteString(" ");
                            //writer.WriteString(w.Bone._nodeIndex.ToString());
                            writer.WriteString(Array.IndexOf(bones, w.Bone).ToString(CultureInfo.InvariantCulture.NumberFormat));
                            writer.WriteString(" ");
                            writer.WriteString(Array.IndexOf(weightSet, w.Weight).ToString(CultureInfo.InvariantCulture.NumberFormat));
                        }

                writer.WriteEndElement(); //v

                writer.WriteEndElement(); //vertex_weights

                writer.WriteEndElement(); //skin
                writer.WriteEndElement(); //controller

                //boneSet.Clear();
                //weightSet.Clear();
            }

            writer.WriteEndElement();
        }
 //private List<MDL0BoneNode> _overriding = new List<MDL0BoneNode>();
 //[Browsable(false)]
 //public List<MDL0BoneNode> Overriding
 //{
 //    get { return _overriding; }
 //    set { _overriding = value; }
 //}
 public MDL0BoneNode Clone()
 {
     MDL0BoneNode b = new MDL0BoneNode();
     b._name = _name;
     b._bindState = new FrameState(_bindState._scale, _bindState._rotate, _bindState._translate);
     return b;
 }
        public void HighlightStuff(MouseEventArgs e)
        {
            modelPanel.Cursor = Cursors.Default;
            float depth = modelPanel.GetDepth(e.X, e.Y);

            _hiX = _hiY = _hiZ = _hiCirc = _hiSphere = false;

            MDL0BoneNode bone = SelectedBone;
            //Vertex3 vertex = TargetVertex;
            MDL0ObjectNode poly = modelListsPanel1.SelectedPolygon;

            if (bone != null)
            {
                //Get the location of the bone
                Vector3 center = BoneLoc;

                //Standard radius scaling snippet. This is used for orb scaling depending on camera distance.
                float radius = center.TrueDistance(modelPanel._camera.GetPoint()) / _orbRadius * 0.1f;

                if (_editType == TransformType.Rotation)
                {
                    //Get point projected onto our orb.
                    Vector3 point = modelPanel.ProjectCameraSphere(new Vector2(e.X, e.Y), center, radius, false);

                    //Get the distance of the mouse point from the bone
                    float distance = point.TrueDistance(center);

                    if (Math.Abs(distance - radius) < (radius * _selectOrbScale)) //Point lies within orb radius
                    {
                        _hiSphere = true;

                        //Determine axis snapping
                        Vector3 angles = (bone._inverseFrameMatrix * point).GetAngles() * Maths._rad2degf;
                        angles._x = (float)Math.Abs(angles._x);
                        angles._y = (float)Math.Abs(angles._y);
                        angles._z = (float)Math.Abs(angles._z);

                        if (Math.Abs(angles._y - 90.0f) <= _axisSnapRange)
                            _hiX = true;
                        else if (angles._x >= (180 - _axisSnapRange) || angles._x <= _axisSnapRange)
                            _hiY = true;
                        else if (angles._y >= (180 - _axisSnapRange) || angles._y <= _axisSnapRange)
                            _hiZ = true;
                    }
                    else if (Math.Abs(distance - (radius * _circOrbScale)) < (radius * _selectOrbScale)) //Point lies on circ line
                        _hiCirc = true;

                    if (_hiX || _hiY || _hiZ || _hiCirc)
                        modelPanel.Cursor = Cursors.Hand;
                }
                else if (_editType == TransformType.Translation)
                {
                    Vector3 point = modelPanel.UnProject(e.X, e.Y, depth);
                    Vector3 diff = (point - center) / radius;

                    float halfDist = _axisHalfLDist;
                    if (diff._x > -_axisSelectRange && diff._x < (_axisLDist + 0.01f) &&
                        diff._y > -_axisSelectRange && diff._y < (_axisLDist + 0.01f) &&
                        diff._z > -_axisSelectRange && diff._z < (_axisLDist + 0.01f))
                    {
                        //Point lies within axes
                        if (diff._x < halfDist && diff._y < halfDist && diff._z < halfDist)
                        {
                            //Point lies inside the double drag areas
                            if (diff._x > _axisSelectRange)
                                _hiX = true;
                            if (diff._y > _axisSelectRange)
                                _hiY = true;
                            if (diff._z > _axisSelectRange)
                                _hiZ = true;

                            modelPanel.Cursor = Cursors.Hand;
                        }
                        else
                        {
                            //Check if point lies on a specific axis
                            float errorRange = _axisSelectRange;

                            if (diff._x > halfDist && Math.Abs(diff._y) < errorRange && Math.Abs(diff._z) < errorRange)
                                _hiX = true;
                            if (diff._y > halfDist && Math.Abs(diff._x) < errorRange && Math.Abs(diff._z) < errorRange)
                                _hiY = true;
                            if (diff._z > halfDist && Math.Abs(diff._x) < errorRange && Math.Abs(diff._y) < errorRange)
                                _hiZ = true;

                            if (!_hiX && !_hiY && !_hiZ)
                                goto GetBone;
                            else
                                modelPanel.Cursor = Cursors.Hand;
                        }
                    }
                    else
                        goto GetBone;
                }
                else if (_editType == TransformType.Scale)
                {
                    Vector3 point = modelPanel.UnProject(e.X, e.Y, depth);
                    Vector3 diff = (point - center) / radius;

                    if (diff._x > -_axisSelectRange && diff._x < (_axisLDist + 0.01f) &&
                        diff._y > -_axisSelectRange && diff._y < (_axisLDist + 0.01f) &&
                        diff._z > -_axisSelectRange && diff._z < (_axisLDist + 0.01f))
                    {
                        //Point lies within axes

                        //Check if point lies on a specific axis first
                        float errorRange = _axisSelectRange;

                        if (diff._x > errorRange && Math.Abs(diff._y) < errorRange && Math.Abs(diff._z) < errorRange)
                            _hiX = true;
                        if (diff._y > errorRange && Math.Abs(diff._x) < errorRange && Math.Abs(diff._z) < errorRange)
                            _hiY = true;
                        if (diff._z > errorRange && Math.Abs(diff._x) < errorRange && Math.Abs(diff._y) < errorRange)
                            _hiZ = true;

                        if (!_hiX && !_hiY && !_hiZ)
                        {
                            //Determine if the point is in the double or triple drag triangles
                            float halfDist = _scaleHalf2LDist;
                            float centerDist = _scaleHalf1LDist;
                            if (IsInTriangle(diff, new Vector3(), new Vector3(halfDist, 0, 0), new Vector3(0, halfDist, 0)))
                                if (IsInTriangle(diff, new Vector3(), new Vector3(centerDist, 0, 0), new Vector3(0, centerDist, 0)))
                                    _hiX = _hiY = _hiZ = true;
                                else _hiX = _hiY = true;
                            else if (IsInTriangle(diff, new Vector3(), new Vector3(halfDist, 0, 0), new Vector3(0, 0, halfDist)))
                                if (IsInTriangle(diff, new Vector3(), new Vector3(centerDist, 0, 0), new Vector3(0, 0, centerDist)))
                                    _hiX = _hiY = _hiZ = true;
                                else _hiX = _hiZ = true;
                            else if (IsInTriangle(diff, new Vector3(), new Vector3(0, halfDist, 0), new Vector3(0, 0, halfDist)))
                                if (IsInTriangle(diff, new Vector3(), new Vector3(0, centerDist, 0), new Vector3(0, 0, centerDist)))
                                    _hiX = _hiY = _hiZ = true;
                                else _hiY = _hiZ = true;

                            if (!_hiX && !_hiY && !_hiZ)
                                goto GetBone;
                            else
                                modelPanel.Cursor = Cursors.Hand;
                        }
                        else
                            modelPanel.Cursor = Cursors.Hand;
                    }
                    else
                        goto GetBone;
                }
            }

            //modelPanel1.Invalidate();

            GetBone:

            //Try selecting new bone
            //if (modelPanel._selecting)
            //{

            //}
            //else
            {
                if (!(_scaling || _rotating || _translating) && (depth < 1.0f) && (_targetModel != null) && (_targetModel._boneList != null))
                {
                    MDL0BoneNode o = null;

                    Vector3 point = modelPanel.UnProject(e.X, e.Y, depth);

                    //Find orb near chosen point
                    if (_editingAll)
                    {
                        foreach (MDL0Node m in _targetModels)
                            foreach (MDL0BoneNode b in m._boneList)
                                if (CompareDistanceRecursive(b, point, ref o))
                                    break;
                    }
                    else
                        foreach (MDL0BoneNode b in _targetModel._boneList)
                            if (CompareDistanceRecursive(b, point, ref o))
                                break;

                    if (_hiBone != null && _hiBone != SelectedBone)
                        _hiBone._nodeColor = Color.Transparent;

                    if ((_hiBone = o) != null)
                    {
                        _hiBone._nodeColor = Color.FromArgb(255, 128, 0);
                        modelPanel.Cursor = Cursors.Hand;
                    }
                }
                else if (_hiBone != null)
                {
                    if (_hiBone != SelectedBone)
                        _hiBone._nodeColor = Color.Transparent;
                    _hiBone = null;
                }
            }

            modelPanel.Invalidate();
        }
        public MDL0Node ImportModel(string filePath)
        {
            MDL0Node model = new MDL0Node() { _name = Path.GetFileNameWithoutExtension(filePath) };
            model.InitGroups();
            if (_importOptions._setOrigPath)
                model._originalPath = filePath;

            //Parse the collada file and use the data to create an MDL0
            using (DecoderShell shell = DecoderShell.Import(filePath))
            try
            {
                model._version = _importOptions._modelVersion;

                Error = "There was a problem reading the model.";

                //Extract images, removing duplicates
                foreach (ImageEntry img in shell._images)
                {
                    string name;
                    MDL0TextureNode tex;

                    if (img._path != null)
                        name = Path.GetFileNameWithoutExtension(img._path);
                    else
                        name = img._name != null ? img._name : img._id;

                    tex = model.FindOrCreateTexture(name);
                    img._node = tex;
                }

                //Extract materials and create shaders
                int tempNo = -1;
                foreach (MaterialEntry mat in shell._materials)
                {
                    tempNo += 1;
                    MDL0MaterialNode matNode = new MDL0MaterialNode();

                    matNode._parent = model._matGroup;
                    matNode._name = mat._name != null ? mat._name : mat._id;

                    if (tempNo == 0)
                    {
                        MDL0ShaderNode shadNode = new MDL0ShaderNode();
                        shadNode._parent = model._shadGroup;
                        shadNode._name = "Shader" + tempNo;
                        model._shadList.Add(shadNode);
                    }
                    matNode.Shader = "Shader0";
                    matNode.ShaderNode = (MDL0ShaderNode)model._shadGroup.Children[0];

                    mat._node = matNode;
                    matNode._cull = _importOptions._culling;

                    //Find effect
                    if (mat._effect != null)
                        foreach (EffectEntry eff in shell._effects)
                            if (eff._id == mat._effect) //Attach textures and effects to material
                                if (eff._shader != null)
                                    foreach (LightEffectEntry l in eff._shader._effects)
                                        if (l._type == LightEffectType.diffuse && l._texture != null)
                                        {
                                            string path = l._texture;
                                            foreach (EffectNewParam p in eff._newParams)
                                                if (p._sid == l._texture)
                                                {
                                                    path = p._sampler2D._url;
                                                    if (!String.IsNullOrEmpty(p._sampler2D._source))
                                                    {
                                                        foreach (EffectNewParam p2 in eff._newParams)
                                                            if (p2._sid == p._sampler2D._source)
                                                                path = p2._path;
                                                    }
                                                }

                                            foreach (ImageEntry img in shell._images)
                                                if (img._id == path)
                                                {
                                                    MDL0MaterialRefNode mr = new MDL0MaterialRefNode();
                                                    (mr._texture = img._node as MDL0TextureNode)._references.Add(mr);
                                                    mr._name = mr._texture.Name;
                                                    matNode._children.Add(mr);
                                                    mr._parent = matNode;
                                                    mr._minFltr = mr._magFltr = 1;
                                                    mr._index1 = mr._index2 = mr.Index;
                                                    mr._uWrap = mr._vWrap = (int)_importOptions._wrap;
                                                    break;
                                                }
                                        }

                    matNode._numTextures = (byte)matNode.Children.Count;
                    model._matList.Add(matNode);
                }

                Say("Extracting scenes...");

                //Extract scenes
                foreach (SceneEntry scene in shell._scenes)
                {
                    //Parse joints first
                    NodeEntry[] joints = scene._nodes.Where(x => x._type == NodeType.JOINT).ToArray();
                    NodeEntry[] nodes = scene._nodes.Where(x => x._type != NodeType.JOINT).ToArray();
                    foreach (NodeEntry node in joints)
                        EnumNode(node, model._boneGroup, scene, model, shell);
                    foreach (NodeEntry node in nodes)
                        EnumNode(node, model._boneGroup, scene, model, shell);
                }

                //If there are no bones, rig all objects to a single bind.
                if (model._boneGroup._children.Count == 0)
                {
                    for (int i = 0; i < 2; i++)
                    {
                        MDL0BoneNode bone = new MDL0BoneNode();
                        bone.Scale = new Vector3(1);

                        bone._bindMatrix =
                        bone._inverseBindMatrix =
                        Matrix.Identity;

                        switch (i)
                        {
                            case 0:
                                bone._name = "TopN";
                                model._boneGroup._children.Add(bone);
                                bone._parent = model._boneGroup;
                                break;
                            case 1:
                                bone._name = "TransN";
                                model._boneGroup._children[0]._children.Add(bone);
                                bone._parent = model._boneGroup._children[0];
                                bone.ReferenceCount = model._objList.Count;
                                break;
                        }
                    }
                    if (model._objList != null && model._objList.Count != 0)
                        foreach (MDL0ObjectNode poly in model._objList)
                        {
                            poly._nodeId = 0;
                            poly.MatrixNode = (MDL0BoneNode)model._boneGroup._children[0]._children[0];
                        }
                }
                else
                {
                    //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
                            }
                        }
                }

                //Remove original color buffers if option set
                if (_importOptions._ignoreColors)
                {
                    if (model._objList != null && model._objList.Count != 0)
                        foreach (MDL0ObjectNode p in model._objList)
                            for (int x = 2; x < 4; x++)
                                if (p._manager._faceData[x] != null)
                                {
                                    p._manager._faceData[x].Dispose();
                                    p._manager._faceData[x] = null;
                                }
                }

                //Add color buffers if option set
                if (_importOptions._addClrs)
                {
                    RGBAPixel pixel = _importOptions._dfltClr;

                    //Add a color buffer to objects that don't have one
                    if (model._objList != null && model._objList.Count != 0)
                        foreach (MDL0ObjectNode p in model._objList)
                            if (p._manager._faceData[2] == null)
                            {
                                RGBAPixel* pIn = (RGBAPixel*)(p._manager._faceData[2] = new UnsafeBuffer(4 * p._manager._pointCount)).Address;
                                for (int i = 0; i < p._manager._pointCount; i++)
                                    *pIn++ = pixel;
                            }
                }

                //Apply defaults to materials
                if (model._matList != null)
                    foreach (MDL0MaterialNode p in model._matList)
                    {
                        if (_importOptions._mdlType == 0)
                        {
                            p._lSet = 20;
                            p._fSet = 4;
                            p._ssc = 3;

                            p.C1ColorEnabled = true;
                            p.C1AlphaMaterialSource = GXColorSrc.Vertex;
                            p.C1ColorMaterialSource = GXColorSrc.Vertex;
                            p.C1ColorDiffuseFunction = GXDiffuseFn.Clamped;
                            p.C1ColorAttenuation = GXAttnFn.Spotlight;
                            p.C1AlphaEnabled = true;
                            p.C1AlphaDiffuseFunction = GXDiffuseFn.Clamped;
                            p.C1AlphaAttenuation = GXAttnFn.Spotlight;

                            p.C2ColorDiffuseFunction = GXDiffuseFn.Disabled;
                            p.C2ColorAttenuation = GXAttnFn.None;
                            p.C2AlphaDiffuseFunction = GXDiffuseFn.Disabled;
                            p.C2AlphaAttenuation = GXAttnFn.None;
                        }
                        else
                        {
                            p._lSet = 0;
                            p._fSet = 0;
                            p._ssc = 1;

                            p._chan1.Color = new LightChannelControl(1795);
                            p._chan1.Alpha = new LightChannelControl(1795);
                            p._chan2.Color = new LightChannelControl(1795);
                            p._chan2.Alpha = new LightChannelControl(1795);
                        }
                    }

                //Set materials to use register color if option set
                if (_importOptions._useReg && model._objList != null)
                    foreach (MDL0ObjectNode p in model._objList)
                    {
                        MDL0MaterialNode m = p.OpaMaterialNode;
                        if (m != null && p._manager._faceData[2] == null && p._manager._faceData[3] == null)
                        {
                            m.C1MaterialColor = _importOptions._dfltClr;
                            m.C1ColorMaterialSource = GXColorSrc.Register;
                            m.C1AlphaMaterialSource = GXColorSrc.Register;
                        }
                    }

                //Remap materials if option set
                if (_importOptions._rmpMats && model._matList != null && model._objList != null)
                {
                    foreach (MDL0ObjectNode p in model._objList)
                        foreach (MDL0MaterialNode m in model._matList)
                            if (m.Children.Count > 0 &&
                                m.Children[0] != null &&
                                p.OpaMaterialNode != null &&
                                p.OpaMaterialNode.Children.Count > 0 &&
                                p.OpaMaterialNode.Children[0] != null &&
                                m.Children[0].Name == p.OpaMaterialNode.Children[0].Name &&
                                m.C1ColorMaterialSource == p.OpaMaterialNode.C1ColorMaterialSource)
                            {
                                p.OpaMaterialNode = m;
                                break;
                            }

                    //Remove unused materials
                    for (int i = 0; i < model._matList.Count; i++)
                        if (((MDL0MaterialNode)model._matList[i])._objects.Count == 0)
                            model._matList.RemoveAt(i--);
                }

                Error = "There was a problem writing the model.";

                //Clean the model and then build it!
                if (model != null)
                {
                    model.CleanGroups();
                    model.BuildFromScratch(this);
                }
            }
            catch (Exception x)
            {
                MessageBox.Show("Cannot continue importing this model.\n" + Error + "\n\nException:\n" + x.ToString());
                model = null;
                Close();
            }
            finally
            {
                //Clean up the mess we've made
                GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
            }
            return model;
        }
        private static unsafe void WriteBone(MDL0BoneNode bone, XmlWriter writer)
        {
            writer.WriteStartElement("node");
            writer.WriteAttributeString("id", bone.Name);
            writer.WriteAttributeString("name", bone._name);
            writer.WriteAttributeString("sid", bone.Name);
            writer.WriteAttributeString("type", "JOINT");

            //writer.WriteStartElement("matrix");
            //writer.WriteString(WriteMatrix(bone._bindState._transform));
            //writer.WriteEndElement(); //matrix

            if (bone._bindState._translate != new Vector3())
            {
                writer.WriteStartElement("translate");
                writer.WriteString(
                    bone._bindState._translate._x.ToString(CultureInfo.InvariantCulture.NumberFormat) + " " +
                    bone._bindState._translate._y.ToString(CultureInfo.InvariantCulture.NumberFormat) + " " +
                    bone._bindState._translate._z.ToString(CultureInfo.InvariantCulture.NumberFormat));
                writer.WriteEndElement(); //translate
            }

            if (bone._bindState._rotate._z != 0)
            {
                writer.WriteStartElement("rotate");
                writer.WriteString("0 0 1 " +
                    bone._bindState._rotate._z.ToString(CultureInfo.InvariantCulture.NumberFormat));
                writer.WriteEndElement(); //rotate
            }
            if (bone._bindState._rotate._y != 0)
            {
                writer.WriteStartElement("rotate");
                writer.WriteString("0 1 0 " +
                    bone._bindState._rotate._y.ToString(CultureInfo.InvariantCulture.NumberFormat));
                writer.WriteEndElement(); //rotate
            }
            if (bone._bindState._rotate._x != 0)
            {
                writer.WriteStartElement("rotate");
                writer.WriteString("1 0 0 " +
                    bone._bindState._rotate._x.ToString(CultureInfo.InvariantCulture.NumberFormat));
                writer.WriteEndElement(); //rotate
            }
            if (bone._bindState._scale != new Vector3(1))
            {
                writer.WriteStartElement("scale");
                writer.WriteString(
                    bone._bindState._scale._x.ToString(CultureInfo.InvariantCulture.NumberFormat) + " " +
                    bone._bindState._scale._y.ToString(CultureInfo.InvariantCulture.NumberFormat) + " " +
                    bone._bindState._scale._z.ToString(CultureInfo.InvariantCulture.NumberFormat));
                writer.WriteEndElement(); //scale
            }

            //Write single-bind geometry
            //foreach (MDL0PolygonNode poly in bone._infPolys)
            //    WritePolyInstance(poly, writer);

            foreach (MDL0BoneNode b in bone.Children)
                WriteBone(b, writer);

            writer.WriteEndElement(); //node
        }
        internal void Parse(MDL0Node model)
        {
            Influence   inf;
            ModelLinker linker = model._linker;

            switch (_type)
            {
            case MDLResourceType.Definitions:
                if (linker.Defs != null)
                {
                    ExtractGroup(linker.Defs, typeof(MDL0DefNode));
                }
                break;

            case MDLResourceType.Bones:
                //Break if there are no bones defined
                if (linker.Bones == null)
                {
                    break;
                }

                //Parse bones from raw data (flat list).
                //Bones re-assign parents in their Initialize block, so parents are true.
                //Parents must be assigned now as bones will be moved in memory when assigned as children.
                ExtractGroup(linker.Bones, typeof(MDL0BoneNode));

                //Cache flat list
                linker.BoneCache = _children.ToArray();

                //Make sure the node cache is the correct size
                int highest = 0;
                foreach (MDL0BoneNode b in linker.BoneCache)
                {
                    if (b._nodeIndex >= linker.NodeCache.Length && b._nodeIndex > highest)
                    {
                        highest = b._nodeIndex;
                    }
                }
                if (highest >= linker.NodeCache.Length)
                {
                    linker.NodeCache = new IMatrixNode[highest + 1];
                }

                //Reset children so we can rebuild
                _children.Clear();

                //Assign children using each bones' parent offset in case NodeTree is corrupted
                foreach (MDL0BoneNode b in linker.BoneCache)
                {
                    b._parent._children.Add(b);
                }

                //Populate node cache
                MDL0BoneNode bone = null;
                int          index;
                int          count = linker.BoneCache.Length;
                for (int i = 0; i < count; i++)
                {
                    linker.NodeCache[(bone = linker.BoneCache[i] as MDL0BoneNode)._nodeIndex] = bone;
                }

                int nullCount = 0;

                bool nodeTreeError = false;

                //Now that bones and primary influences have been cached, we can create weighted influences.
                foreach (ResourcePair p in *linker.Defs)
                {
                    if (p.Name == "NodeTree")
                    {
                        //Double check bone tree using the NodeTree definition.
                        //If the NodeTree is corrupt, the user will be informed that it needs to be rebuilt.
                        byte *pData = (byte *)p.Data;

Top:
                        if (*pData == 2)
                        {
                            bone  = linker.BoneCache[*(bushort *)(pData + 1)] as MDL0BoneNode;
                            index = *(bushort *)(pData + 3);

                            if (bone.Header->_parentOffset == 0)
                            {
                                if (!_children.Contains(bone))
                                {
                                    nodeTreeError = true;
                                    continue;
                                }
                            }
                            else
                            {
                                ResourceNode n = linker.NodeCache[index] as ResourceNode;
                                if (n == null || bone._parent != n || !n._children.Contains(bone))
                                {
                                    nodeTreeError = true;
                                    continue;
                                }
                            }
                            pData += 5;
                            goto Top;
                        }
                    }
                    else
                    if (p.Name == "NodeMix")
                    {
                        //Use node mix to create weight groups
                        byte *pData = (byte *)p.Data;

Top:
                        switch (*pData)
                        {
                        //Type 3 is for weighted influences
                        case 3:
                            //Get index/count fields
                            index = *(bushort *)(pData + 1);
                            count = pData[3];
                            //Get data pointer (offset of 4)
                            MDL0NodeType3Entry *nEntry = (MDL0NodeType3Entry *)(pData + 4);
                            //Create influence with specified count
                            inf = new Influence();
                            //Iterate through weights, adding each to the influence
                            //Here, we are referring back to the NodeCache to grab the bone.
                            //Note that the weights do not reference other influences, only bones. There is a good reason for this.
                            MDL0BoneNode b           = null;
                            List <int>   nullIndices = new List <int>();
                            for (int i = 0; i < count; i++, nEntry++)
                            {
                                if (nEntry->_id < linker.NodeCache.Length && (b = (linker.NodeCache[nEntry->_id] as MDL0BoneNode)) != null)
                                {
                                    inf._weights.Add(new BoneWeight(b, nEntry->_value));
                                }
                                else
                                {
                                    nullIndices.Add(i);
                                    nullCount++;
                                }
                            }

                            bool d = false;
                            if (nullIndices.Count > 0)
                            {
                                List <BoneWeight> newWeights = new List <BoneWeight>();
                                for (int i = 0; i < inf._weights.Count; i++)
                                {
                                    if (!nullIndices.Contains(i))
                                    {
                                        newWeights.Add(inf._weights[i]);
                                    }
                                }
                                if (newWeights.Count == 0)
                                {
                                    d = true;
                                }
                                else
                                {
                                    inf._weights = newWeights;
                                }
                            }

                            //Add influence to model object, while adding it to the cache.
                            if (!d)
                            {
                                ((Influence)(linker.NodeCache[index] = model._influences.FindOrCreate(inf, true)))._index = index;
                            }

                            //Move data pointer to next entry
                            pData = (byte *)nEntry;
                            goto Top;

                        //Type 5 is for primary influences
                        case 5:
                            pData += 5;
                            goto Top;
                        }
                    }
                }

                if (nullCount > 0)
                {
                    model._errors.Add("There were " + nullCount + " null weights in NodeMix.");
                    SignalPropertyChange();
                }

                if (nodeTreeError)
                {
                    model._errors.Add("The NodeTree definition did not match the bone tree.");
                    SignalPropertyChange();
                }

                break;

            case MDLResourceType.Materials:
                if (linker.Materials != null)
                {
                    ExtractGroup(linker.Materials, typeof(MDL0MaterialNode));
                }
                break;

            case MDLResourceType.Shaders:
                if (linker.Shaders != null)
                {
                    ExtractGroup(linker.Shaders, typeof(MDL0ShaderNode));
                }
                break;

            case MDLResourceType.Vertices:
                if (linker.Vertices != null)
                {
                    ExtractGroup(linker.Vertices, typeof(MDL0VertexNode));
                }
                break;

            case MDLResourceType.Normals:
                if (linker.Normals != null)
                {
                    ExtractGroup(linker.Normals, typeof(MDL0NormalNode));
                }
                break;

            case MDLResourceType.UVs:
                if (linker.UVs != null)
                {
                    ExtractGroup(linker.UVs, typeof(MDL0UVNode));
                }
                break;

            case MDLResourceType.FurLayerCoords:
                if (linker.FurLayerCoords != null)
                {
                    ExtractGroup(linker.FurLayerCoords, typeof(MDL0FurPosNode));
                }
                break;

            case MDLResourceType.FurVectors:
                if (linker.FurVectors != null)
                {
                    ExtractGroup(linker.FurVectors, typeof(MDL0FurVecNode));
                }
                break;

            case MDLResourceType.Objects:
                //Break if no polygons defined
                if (linker.Polygons == null)
                {
                    break;
                }

                //Extract
                ExtractGroup(linker.Polygons, typeof(MDL0ObjectNode));

                //Attach materials to polygons.
                //This assumes that materials have already been parsed.

                List <ResourceNode> matList = ((MDL0Node)_parent)._matList;
                MDL0ObjectNode      poly;
                MDL0MaterialNode    mat;

                //Find DrawOpa or DrawXlu entry in Definition list
                foreach (ResourcePair p in *linker.Defs)
                {
                    if ((p.Name == "DrawOpa") || (p.Name == "DrawXlu"))
                    {
                        bool   opa    = p.Name == "DrawOpa";
                        ushort dIndex = 0;
                        byte * pData  = (byte *)p.Data;
                        while (*pData++ == 4)
                        {
                            //Get polygon from index
                            dIndex = *(bushort *)(pData + 2);
                            if (dIndex >= _children.Count || dIndex < 0)
                            {
                                model._errors.Add("Object index was greater than the actual object count.");
                                SignalPropertyChange();
                                dIndex = 0;
                            }
                            poly            = _children[dIndex] as MDL0ObjectNode;
                            poly._drawIndex = pData[6];
                            //Get material from index
                            mat = matList[*(bushort *)pData] as MDL0MaterialNode;
                            //Get bone from index and assign
                            int boneIndex = *(bushort *)(pData + 4);
                            if (linker.BoneCache != null && boneIndex >= 0 && boneIndex < linker.BoneCache.Length)
                            {
                                poly.BoneNode = linker.BoneCache[boneIndex] as MDL0BoneNode;
                            }
                            //Assign material to polygon
                            if (opa)
                            {
                                poly.OpaMaterialNode = mat;
                            }
                            else
                            {
                                poly.XluMaterialNode = mat;
                            }
                            //Increment pointer
                            pData += 7;
                        }
                    }
                }

                foreach (MDL0ObjectNode m in _children)
                {
                    int max = Maths.Max(
                        m.OpaMaterialNode != null ? m.OpaMaterialNode.Children.Count : 0,
                        m.XluMaterialNode != null ? m.XluMaterialNode.Children.Count : 0,
                        m.OpaMaterialNode != null && m.OpaMaterialNode.MetalMaterial != null ? m.OpaMaterialNode.MetalMaterial.Children.Count : 0,
                        m.XluMaterialNode != null && m.XluMaterialNode.MetalMaterial != null ? m.XluMaterialNode.MetalMaterial.Children.Count : 0);

                    bool hasUnused = false;
                    for (int i = max; i < 8; i++)
                    {
                        if (m.HasTextureMatrix[i])
                        {
                            m.HasTextureMatrix[i] = false;
                            m._rebuild            = true;
                            hasUnused             = true;
                        }
                    }
                    if (hasUnused)
                    {
                        ((MDL0Node)Parent)._errors.Add("Object " + m.Index + " has unused texture matrices.");
                        m.SignalPropertyChange();
                    }

                    if (m.HasTexMtx && m.HasNonFloatVertices)
                    {
                        ((MDL0Node)Parent)._errors.Add("Object " + m.Index + " has texture matrices and non-float vertices, meaning it will explode in-game.");
                        m.SignalPropertyChange();
                    }
                }
                break;

            case MDLResourceType.Colors:
                if (linker.Colors != null)
                {
                    ExtractGroup(linker.Colors, typeof(MDL0ColorNode));
                }
                break;

            case MDLResourceType.Textures:
                if (linker.Textures != null)
                {
                    ExtractGroup(linker.Textures, typeof(MDL0TextureNode));
                }
                break;

            case MDLResourceType.Palettes:
                if (linker.Palettes != null)
                {
                    ExtractGroup(linker.Palettes, typeof(MDL0TextureNode));
                }
                break;
            }
        }
Beispiel #26
0
        private void FixChildren(MDL0BoneNode node, int axis)
        {
            KeyframeEntry kfe;

            foreach (MDL0BoneNode b in node.Children)
            {
                CHR0EntryNode _target = (CHR0EntryNode)FindChild(b.Name, true);
                if (_target != null)
                {
                    switch (axis)
                    {
                    case 0: //X, correct Y and Z
                        for (int l = 0; l < _target.FrameCount; l++)
                        {
                            for (int g = 0x13; g < 0x16; g++)
                            {
                                if (g != 0x13)
                                {
                                    if ((kfe = _target.GetKeyframe((KeyFrameMode)g, l)) != null)
                                    {
                                        kfe._value *= -1;
                                    }
                                }
                            }
                        }
                        break;

                    case 1: //Y, correct X and Z
                        for (int l = 0; l < _target.FrameCount; l++)
                        {
                            for (int g = 0x13; g < 0x16; g++)
                            {
                                if (g != 0x14)
                                {
                                    if ((kfe = _target.GetKeyframe((KeyFrameMode)g, l)) != null)
                                    {
                                        kfe._value *= -1;
                                    }
                                }
                            }
                        }
                        break;

                    case 2: //Z, correct X and Y
                        for (int l = 0; l < _target.FrameCount; l++)
                        {
                            for (int g = 0x13; g < 0x16; g++)
                            {
                                if (g != 0x15)
                                {
                                    if ((kfe = _target.GetKeyframe((KeyFrameMode)g, l)) != null)
                                    {
                                        kfe._value *= -1;
                                    }
                                }
                            }
                        }
                        break;
                    }
                }
                FixChildren(b, axis);
            }
        }
 public Color GetWeightColor(MDL0BoneNode targetBone)
 {
     float weight = -1;
     if (_matrixNode == null || targetBone == null)
         return Color.Transparent;
     if (_matrixNode is MDL0BoneNode)
         if (_matrixNode == targetBone)
             weight = 1.0f;
         else
             return Color.Transparent;
     else
         foreach (BoneWeight b in ((Influence)_matrixNode)._weights)
             if (b.Bone == targetBone)
             {
                 weight = b.Weight;
                 break;
             }
     if (weight == -1)
         return Color.Transparent;
     int r = ((int)(weight * 255.0f)).Clamp(0, 0xFF);
     return Color.FromArgb(r, 0, 0xFF - r);
 }
        public void RemoveBone(MDL0BoneNode bone)
        {
            foreach (MDL0BoneNode b in bone.Children)
                RemoveBone(b);

            //    _influences.RemoveBone(bone);
            //    foreach (MDL0ObjectNode o in _polyList)
            //        if (o.MatrixNode == bone)
            //            o.MatrixNode = bone.Parent as MDL0BoneNode;

            //Top:
            //    if (bone.References.Count != 0)
            //    {
            //        bone.References[bone.References.Count - 1].MatrixNode = bone.Parent as MDL0BoneNode;
            //        goto Top;
            //    }
        }
 public int IndexOfBone(MDL0BoneNode b)
 {
     return Array.IndexOf(GetBones(), b);
 }
 public BoneWeight(MDL0BoneNode bone)
     : this(bone, 1.0f)
 {
 }
 public BoneWeight WeightForBone(MDL0BoneNode b)
 {
     int i = IndexOfBone(b); if (i == -1) return null; return GetBoneWeights()[i];
 }
        private unsafe void RenderOrb(MDL0BoneNode bone, GLDisplayList list)
        {
            Matrix m = Matrix.TransformMatrix(new Vector3(MDL0BoneNode._nodeRadius), new Vector3(), bone._frameMatrix.GetPoint());
            GL.PushMatrix();
            GL.MultMatrix((float*)&m);

            list.Call();
            GL.PopMatrix();
        }
        private bool CompareDistanceRecursive(MDL0BoneNode bone, Vector3 point, ref MDL0BoneNode match)
        {
            Vector3 center = bone._frameMatrix.GetPoint();
            float dist = center.TrueDistance(point);

            if (Math.Abs(dist - MDL0BoneNode._nodeRadius) < 0.01)
            {
                match = bone;
                return true;
            }

            foreach (MDL0BoneNode b in bone.Children)
                if (CompareDistanceRecursive(b, point, ref match))
                    return true;

            return false;
        }
        public static void AssignParent(MDL0BoneNode pBone, ModelBone child, MDL0BoneNode cBone, ModelBone parent)
        {
            if (pBone._entryIndex == child._parentBoneIndex)
            {
                //Link child to its parent
                (cBone._parent = pBone)._children.Add(cBone);

                //Convert the world point into a local point relative to the bone's parent
                Matrix m = (Matrix.TranslationMatrix(child._wPos) * Matrix.Invert(Matrix.TranslationMatrix(parent._wPos)));

                //Derive to state and recalc bind matrices
                cBone._bindState = m.Derive();
                cBone.RecalcBindState();
            }
            else //Parent not found, continue searching children.
                foreach (MDL0BoneNode pMatch in pBone._children)
                    AssignParent(pMatch, child, cBone, parent);
        }
Beispiel #35
0
        internal void Parse(MDL0Node model)
        {
            Influence   inf;
            ModelLinker linker = model._linker;

            switch (_type)
            {
            case MDLResourceType.Bones:
                //Break if there are no bones defined
                if (linker.Bones == null)
                {
                    break;
                }

                //Parse bones from raw data (flat list).
                //Bones re-assign parents in their Initialize block, so parents are true.
                ExtractGroup(linker.Bones, typeof(MDL0BoneNode));

                //Cache flat list
                linker.BoneCache = _children.ToArray();

                //Reset children so we can rebuild
                _children.Clear();

                //Populate node cache
                MDL0BoneNode bone = null;
                int          index;
                int          count = linker.BoneCache.Length;
                for (int i = 0; i < count; i++)
                {
                    //bone = linker.BoneCache[i] as MDL0BoneNode;
                    linker.NodeCache[(bone = linker.BoneCache[i] as MDL0BoneNode)._nodeIndex] = bone;
                }

                //Now that bones and primary influences have been cached, we can create weighted influences.

                foreach (ResourcePair p in *linker.Defs)
                {
                    if (p.Name == "NodeTree")
                    {
                        //Use node tree to rebuild bone heirarchy
                        byte *pData = (byte *)p.Data;

Top:
                        if (*pData == 2)
                        {
                            bone  = linker.BoneCache[*(bushort *)(pData + 1)] as MDL0BoneNode;
                            index = *(bushort *)(pData + 3);

                            if (bone.Header->_parentOffset == 0)
                            {
                                _children.Add(bone);
                            }
                            else
                            {
                                (bone._parent = linker.NodeCache[index] as ResourceNode)._children.Add(bone);
                            }

                            pData += 5;
                            goto Top;
                        }
                    }
                    else if (p.Name == "NodeMix")
                    {
                        //Use node mix to create weight groups
                        byte *pData = (byte *)p.Data;

Top:
                        switch (*pData)
                        {
                        //Type 3 is for weighted influences
                        case 3:
                            //Get index/count fields
                            index = *(bushort *)(pData + 1);
                            count = pData[3];
                            //Get data pointer (offset of 4)
                            MDL0NodeType3Entry *nEntry = (MDL0NodeType3Entry *)(pData + 4);

                            //Create influence with specified count
                            inf = new Influence(count);
                            //Iterate through weights, adding each to the influence
                            //Here, we are referring back to the NodeCache to grab the bone.
                            //Note that the weights do not reference other influences, only bones. There is a good reason for this.
                            for (int i = 0; i < count; i++, nEntry++)
                            {
                                inf._weights[i] = new BoneWeight(linker.NodeCache[nEntry->_id] as MDL0BoneNode, nEntry->_value);
                            }

                            //Add influence to model object, while adding it to the cache.
                            linker.NodeCache[index] = model._influences.AddOrCreate(inf);

                            //Move data pointer to next entry
                            pData = (byte *)nEntry;
                            goto Top;

                        //Type 5 is for primary influences
                        case 5:
                            pData += 5;
                            goto Top;
                        }
                    }
                }

                break;

            case MDLResourceType.Materials:
                if (linker.Materials != null)
                {
                    ExtractGroup(linker.Materials, typeof(MDL0MaterialNode));
                }
                break;

            case MDLResourceType.Shaders:
                if (linker.Shaders != null)
                {
                    ExtractGroup(linker.Shaders, typeof(MDL0ShaderNode));
                }
                break;

            case MDLResourceType.Polygons:
                //Break if no polygons defined
                if (linker.Polygons == null)
                {
                    break;
                }

                //Extract
                ExtractGroup(linker.Polygons, typeof(MDL0PolygonNode));

                //Attach materials to polygons.
                //This assumes that materials have already been parsed.

                List <ResourceNode> matList = ((MDL0Node)_parent)._matList;
                MDL0PolygonNode     poly;
                MDL0MaterialNode    mat;

                //Find DrawOpa or DrawXlu entry in Definition list
                foreach (ResourcePair p in *linker.Defs)
                {
                    if ((p.Name == "DrawOpa") || (p.Name == "DrawXlu"))
                    {
                        byte *pData = (byte *)p.Data;
                        while (*pData++ == 4)
                        {
                            //Get polygon from index
                            poly = _children[*(bushort *)(pData + 2)] as MDL0PolygonNode;
                            //Get material from index
                            mat = matList[*(bushort *)pData] as MDL0MaterialNode;
                            //Assign material to polygon
                            poly._material = mat;
                            //Add polygon to material reference list
                            mat._polygons.Add(poly);
                            //Increment pointer
                            pData += 7;
                        }
                    }
                }
                break;
            }
        }
 private void FixChildren(MDL0BoneNode node, int axis)
 {
     KeyframeEntry kfe;
     foreach (MDL0BoneNode b in node.Children)
     {
         CHR0EntryNode _target = (CHR0EntryNode)FindChild(b.Name, true);
         if (_target != null)
             switch (axis)
             {
                 case 0: //X, correct Y and Z
                     for (int l = 0; l < _target.FrameCount; l++)
                         for (int g = 0x13; g < 0x16; g++)
                             if (g != 0x13)
                                 if ((kfe = _target.GetKeyframe((KeyFrameMode)g, l)) != null)
                                     kfe._value *= -1;
                     break;
                 case 1: //Y, correct X and Z
                     for (int l = 0; l < _target.FrameCount; l++)
                         for (int g = 0x13; g < 0x16; g++)
                             if (g != 0x14)
                                 if ((kfe = _target.GetKeyframe((KeyFrameMode)g, l)) != null)
                                     kfe._value *= -1;
                     break;
                 case 2: //Z, correct X and Y
                     for (int l = 0; l < _target.FrameCount; l++)
                         for (int g = 0x13; g < 0x16; g++)
                             if (g != 0x15)
                                 if ((kfe = _target.GetKeyframe((KeyFrameMode)g, l)) != null)
                                     kfe._value *= -1;
                     break;
             }
         FixChildren(b, axis);
     }
 }
        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();
            }
        }