/// <summary>
        /// luo luuranko.
        /// </summary>
        /// <param name="jointInfos"></param>
        /// <param name="baseFrame"></param>
        /// <param name="animFrameData"></param>
        /// <param name="frameIndex"></param>
        /// <param name="num_joints"></param>
        /// <param name="md5anim"></param>
        void BuildFrameSkeleton(ref MD5JointInfo[] jointInfos,
            ref MD5BaseFrameJoint[] baseFrame,
            ref float[] animFrameData,
            int frameIndex,
            int num_joints, ref Animation md5anim)
        {
            int i;

            for (i = 0; i < num_joints; ++i)
            {
                MD5BaseFrameJoint baseJoint = baseFrame[i];
                Vector3 animatedPos;
                Quaternion animatedOrient;
                int j = 0;

                animatedPos = baseJoint.pos;
                animatedOrient = baseJoint.orient;

                if ((jointInfos[i].flags & 1) > 0) /* Tx */
                {
                    animatedPos.X = animFrameData[jointInfos[i].startIndex + j];
                    ++j;
                }

                if ((jointInfos[i].flags & 2) > 0) /* Ty */
                {
                    animatedPos.Y = animFrameData[jointInfos[i].startIndex + j];
                    ++j;
                }

                if ((jointInfos[i].flags & 4) > 0) /* Tz */
                {
                    animatedPos.Z = animFrameData[jointInfos[i].startIndex + j];
                    ++j;
                }

                if ((jointInfos[i].flags & 8) > 0) /* Qx */
                {
                    animatedOrient.X = animFrameData[jointInfos[i].startIndex + j];
                    ++j;
                }

                if ((jointInfos[i].flags & 16) > 0) /* Qy */
                {
                    animatedOrient.Y = animFrameData[jointInfos[i].startIndex + j];
                    ++j;
                }

                if ((jointInfos[i].flags & 32) > 0) /* Qz */
                {
                    animatedOrient.Z = animFrameData[jointInfos[i].startIndex + j];
                    ++j;
                }

                /* Compute orient quaternion's w value */
                MathExt.ComputeW(ref animatedOrient);

                int parent = jointInfos[i].parent;
                md5anim.skelFrames[frameIndex, i].parent = parent;
                md5anim.skelFrames[frameIndex, i].name = jointInfos[i].name;

                /* Has parent? */
                if (md5anim.skelFrames[frameIndex, i].parent < 0)
                {
                    md5anim.skelFrames[frameIndex, i].pos = animatedPos;
                    md5anim.skelFrames[frameIndex, i].orient = animatedOrient;
                }
                else
                {
                    MD5Joint parentJoint = md5anim.skelFrames[frameIndex, parent];
                    Vector3 rpos; /* Rotated Position */

                    /* Add positions */
                    rpos = MathExt.RotatePoint(ref parentJoint.orient, ref animatedPos);

                    md5anim.skelFrames[frameIndex, i].pos.X = rpos.X + parentJoint.pos.X;
                    md5anim.skelFrames[frameIndex, i].pos.Y = rpos.Y + parentJoint.pos.Y;
                    md5anim.skelFrames[frameIndex, i].pos.Z = rpos.Z + parentJoint.pos.Z;

                    /* Concatenate rotations */
                    md5anim.skelFrames[frameIndex, i].orient = MathExt.Mult(ref parentJoint.orient, ref animatedOrient);
                    md5anim.skelFrames[frameIndex, i].orient = MathExt.Normalize(ref md5anim.skelFrames[frameIndex, i].orient);
                }

            }
        }
 /// <summary>
 /// aseta haluttu animaatio
 /// </summary>
 /// <param name="animName"></param>
 public override void UseAnimation(string animName)
 {
     if (curAnim.animName != animName)
     {
         for (int q = 0; q < animations.Count; q++)
         {
             if (animations[q].animName == animName)
             {
                 curAnim = animations[q];
                 break;
             }
         }
     }
 }
        /// <summary>
        /// lasketaan frame
        /// </summary>
        /// <param name="anim"></param>
        /// <param name="dt"></param>
        void Animate(ref Animation anim, float dt)
        {
            int maxFrames = anim.numFrames - 1;

            anim.lastTime += dt;

            /* move to next frame */
            if (anim.lastTime >= anim.maxTime)
            {
                anim.curFrame++;
                anim.nextFrame++;
                anim.lastTime = 0.0f;

                if (anim.curFrame > maxFrames)
                    anim.curFrame = 0;

                if (anim.nextFrame > maxFrames)
                    anim.nextFrame = 0;

            }
        }
        /// <summary>
        /// lataa md5-animaatio.
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="anim"></param>
        public override void LoadAnim(string animName, string fileName)
        {
            if (fileName == null || fileName == "") return;

            Animation anim = new Animation();
            anim.animName = animName;

            Buffer t = new Buffer();
            MD5JointInfo[] jointInfos = null;
            MD5BaseFrameJoint[] baseFrame = null;
            float[] animFrameData = null;
            int numAnimatedComponents = 0;
            int frame_index;
            int i;

            using (System.IO.StreamReader file = new System.IO.StreamReader(Settings.DataDir + fileName))
            {
                string line;
                while ((line = file.ReadLine()) != null)
                {
                    if (line == "") continue;

                    // Read number of joints
                    if (ParseLine(ref t, line, "numFrames %d"))
                    {
                        /* Allocate memory for skeleton frames and bounding boxes */
                        anim.numFrames = t.ibuffer[0];
                        if (anim.numFrames > 0)
                        {
                            anim.bboxes = new MD5BoundingBox[anim.numFrames];
                        }
                    }

                    if (ParseLine(ref t, line, "numJoints %d"))
                    {
                        /* Allocate memory for joints of each frame */
                        anim.numJoints = t.ibuffer[0];
                        if (anim.numJoints > 0)
                        {
                            /* Allocate temporary memory for building skeleton frames */
                            jointInfos = new MD5JointInfo[anim.numJoints];
                            baseFrame = new MD5BaseFrameJoint[anim.numJoints];
                        }
                        anim.skelFrames = new MD5Joint[anim.numFrames, anim.numJoints];
                    }

                    if (ParseLine(ref t, line, "frameRate %d"))
                    {
                        anim.frameRate = t.ibuffer[0];
                    }

                    if (ParseLine(ref t, line, "numAnimatedComponents %d"))
                    {
                        numAnimatedComponents = t.ibuffer[0];
                        if (numAnimatedComponents > 0)
                        {
                            /* Allocate memory for animation frame data */
                            animFrameData = new float[numAnimatedComponents];
                        }

                    }

                    if (line.Equals("hierarchy {"))
                    {
                        for (i = 0; i < anim.numJoints; ++i)
                        {
                            /* Read whole line */
                            line = file.ReadLine();
                            Cleanstring(ref line);

                            /* Read joint info */
                            ParseLine(ref t, line, "%s %d %d %d");
                            jointInfos[i].name = t.sbuffer;
                            jointInfos[i].parent = t.ibuffer[0];
                            jointInfos[i].flags = t.ibuffer[1];
                            jointInfos[i].startIndex = t.ibuffer[2];
                        }
                    }

                    if (line.Equals("bounds {"))
                    {
                        for (i = 0; i < anim.numFrames; ++i)
                        {
                            /* Read whole line */
                            line = file.ReadLine();
                            Cleanstring(ref line);

                            /* Read bounding box */
                            ParseLine(ref t, line, "( %f %f %f ) ( %f %f %f )");
                            anim.bboxes[i].min.X = t.fbuffer[0];
                            anim.bboxes[i].min.Y = t.fbuffer[1];
                            anim.bboxes[i].min.Z = t.fbuffer[2];
                            anim.bboxes[i].max.X = t.fbuffer[3];
                            anim.bboxes[i].max.Y = t.fbuffer[4];
                            anim.bboxes[i].max.Z = t.fbuffer[5];
                        }
                    }

                    if (line.Equals("baseframe {"))
                    {
                        for (i = 0; i < anim.numJoints; ++i)
                        {
                            /* Read whole line */
                            line = file.ReadLine();
                            Cleanstring(ref line);

                            /* Read base frame joint */
                            ParseLine(ref t, line, "( %f %f %f ) ( %f %f %f )");

                            if (t.fbuffer.Length == 6)
                            {
                                baseFrame[i].pos.X = t.fbuffer[0];
                                baseFrame[i].pos.Y = t.fbuffer[1];
                                baseFrame[i].pos.Z = t.fbuffer[2];
                                baseFrame[i].orient.X = t.fbuffer[3];
                                baseFrame[i].orient.Y = t.fbuffer[4];
                                baseFrame[i].orient.Z = t.fbuffer[5];

                                /* Compute the w component */
                                MathExt.ComputeW(ref baseFrame[i].orient);

                            }
                        }
                    }

                    if (ParseLine(ref t, line, "frame %d"))
                    {
                        frame_index = t.ibuffer[0];

                        /* Read frame data */
                        for (i = 0; i < numAnimatedComponents; )
                        {
                            line = file.ReadLine();
                            if (line[0] == '}') break;
                            Cleanstring(ref line);
                            string[] splt = line.Split(' ');

                            for (int ww = 0; ww < splt.Length; ww++)
                            {
                                animFrameData[i++] = float.Parse(splt[ww]);
                            }
                        }

                        /* Build frame skeleton from the collected data */
                        BuildFrameSkeleton(ref jointInfos, ref baseFrame, ref animFrameData, frame_index, anim.numJoints, ref anim);
                    }
                }

                anim.curFrame = 0;
                anim.nextFrame = 1;

                anim.lastTime = 0;
                anim.maxTime = 1.0f / anim.frameRate;

                /* Allocate memory for animated skeleton */
                skeleton = new MD5Joint[anim.numJoints];
                animated = true;

                Vector3 min = new Vector3(9999, 9999, 9999);
                Vector3 max = new Vector3(-9999, -9999, -9999);

                // laske bboxit
                for (int q = 0; q < anim.numFrames; q++)
                {
                    if (anim.bboxes[q].min.X < min.X) min.X = anim.bboxes[q].min.X;
                    if (anim.bboxes[q].min.Y < min.Y) min.Y = anim.bboxes[q].min.Y;
                    if (anim.bboxes[q].min.Z < min.Z) min.Z = anim.bboxes[q].min.Z;

                    if (anim.bboxes[q].max.X > max.X) max.X = anim.bboxes[q].max.X;
                    if (anim.bboxes[q].max.Y > max.Y) max.Y = anim.bboxes[q].max.Y;
                    if (anim.bboxes[q].max.Z > max.Z) max.Z = anim.bboxes[q].max.Z;
                }

                Boundings = new BoundingVolume();
                Boundings.CreateBoundingVolume(this, min, max);

                Update(0);
                animations.Add(anim);

                Log.WriteDebugLine("Animation: " + fileName);

                UseAnimation(animName);
            }
        }