public void LoadTagData()
        {
            BinaryReader br = new BinaryReader(m_stream);

            //Load the ANTR header
            m_Header.Load(ref br);

            //Seek to the Animation Section
            br.BaseStream.Position = m_Header.Nodes.Offset;
            m_Nodes = new ANTR_NODE[m_Header.Nodes.Count];
            for (int n = 0; n < m_Header.Nodes.Count; n++)
            {
                m_Nodes[n] = new ANTR_NODE();
                m_Nodes[n].Load(ref br);
            }

            //Seek to the Animation Section
            br.BaseStream.Position = m_Header.Animations.Offset;

            m_Animations     = new ANTR_ANIMATION[m_Header.Animations.Count];
            m_Keyframes      = new KEYFRAME[m_Header.Animations.Count][];
            m_AnimationNames = new string[m_Header.Animations.Count];
            int len;

            for (int i = 0; i < m_Header.Animations.Count; i++)
            {
                m_Animations[i] = new ANTR_ANIMATION();
                m_Animations[i].Load(ref br);

                len = 0;
                while ((m_Animations[i].name[len++] != '\0') && (len < 32))
                {
                    ;
                }
                m_AnimationNames[i] = new string(m_Animations[i].name, 0, len - 1);
            }

            for (int i = 0; i < m_Header.Animations.Count; i++)
            {
                DecompressAnimation(ref br, i);
            }
        }
        public void DecompressAnimation(ref BinaryReader br, int ani_index)
        {
            //allocate keyframe data to store decompressed animations
            ANTR_ANIMATION AnimationHeader = m_Animations[ani_index];

            m_Keyframes[ani_index] = new KEYFRAME[AnimationHeader.FrameCount * AnimationHeader.NodeCount];

            int node_count = AnimationHeader.NodeCount; //helper var for readability

            for (int f = 0; f < AnimationHeader.FrameCount; f++)
            {
                for (int n = 0; n < AnimationHeader.NodeCount; n++)
                {
                    m_Keyframes[ani_index][f * node_count + n] = new KEYFRAME();
                }
            }


            //Skip FrameInfo section, nothing of interest (yet anyway)
            br.BaseStream.Seek(AnimationHeader.FrameInfoSize, SeekOrigin.Current);


            //Fill in static data
            float[] TransData = new float[3];
            short[] RotData   = new short[4];
            float   Scale;

            for (int n = 0; n < AnimationHeader.NodeCount; n++)
            {
                if (IsNodeDynamic(n, AnimationHeader.RotateStaticMask) == false)
                {
                    RotData[0] = br.ReadInt16();
                    RotData[1] = br.ReadInt16();
                    RotData[2] = br.ReadInt16();
                    RotData[3] = br.ReadInt16();

                    for (int f = 0; f < AnimationHeader.FrameCount; f++)
                    {
                        Quaternion.DecompressQuaternion_64bit(RotData, m_Keyframes[ani_index][f * node_count + n].rotation);
                        Quaternion.NormalizeQuaternion(m_Keyframes[ani_index][f * node_count + n].rotation);
                    }
                }
                if (IsNodeDynamic(n, AnimationHeader.TranslateStaticMask) == false)
                {
                    TransData[0] = br.ReadSingle();
                    TransData[1] = br.ReadSingle();
                    TransData[2] = br.ReadSingle();

                    for (int f = 0; f < AnimationHeader.FrameCount; f++)
                    {
                        m_Keyframes[ani_index][f * node_count + n].translation[0] = TransData[0];
                        m_Keyframes[ani_index][f * node_count + n].translation[1] = TransData[1];
                        m_Keyframes[ani_index][f * node_count + n].translation[2] = TransData[2];
                    }
                }
                if (IsNodeDynamic(n, AnimationHeader.ScaleStaticMask) == false)
                {
                    Scale = br.ReadSingle();
                    for (int f = 0; f < AnimationHeader.FrameCount; f++)
                    {
                        m_Keyframes[ani_index][f * node_count + n].scale = Scale;
                    }
                }
            }

            //Fill in dynamic data
            for (int f = 0; f < AnimationHeader.FrameCount; f++)
            {
                for (int n = 0; n < AnimationHeader.NodeCount; n++)
                {
                    if (IsNodeDynamic(n, AnimationHeader.RotateStaticMask) == true)
                    {
                        RotData[0] = br.ReadInt16();
                        RotData[1] = br.ReadInt16();
                        RotData[2] = br.ReadInt16();
                        RotData[3] = br.ReadInt16();
                        Quaternion.DecompressQuaternion_64bit(RotData, m_Keyframes[ani_index][f * node_count + n].rotation);
                        Quaternion.NormalizeQuaternion(m_Keyframes[ani_index][f * node_count + n].rotation);
                    }
                    if (IsNodeDynamic(n, AnimationHeader.TranslateStaticMask) == true)
                    {
                        TransData[0] = br.ReadSingle();
                        TransData[1] = br.ReadSingle();
                        TransData[2] = br.ReadSingle();
                        m_Keyframes[ani_index][f * node_count + n].translation[0] = TransData[0];
                        m_Keyframes[ani_index][f * node_count + n].translation[1] = TransData[1];
                        m_Keyframes[ani_index][f * node_count + n].translation[2] = TransData[2];
                    }
                    if (IsNodeDynamic(n, AnimationHeader.ScaleStaticMask) == true)
                    {
                        m_Keyframes[ani_index][f * node_count + n].scale = br.ReadSingle();
                    }
                }
            }
        }