internal void ApplySRT0Texture(SRT0TextureNode node, int index, bool linear)
 {
     if ((node == null) || (index == 0)) //Reset to identity
         _frameState = new FrameState() { _scale = new Vector3(1) };
     else
         _frameState = new FrameState(node.GetAnimFrame(index - 1, linear));
 }
        public override bool OnInitialize()
        {
            MDL0TextureRef* header = Header;

            _texPtr = header->_texPtr;
            _pltPtr = header->_pltPtr;
            _index1 = header->_index1;
            _index2 = header->_index2;
            _uWrap = header->_uWrap;
            _vWrap = header->_vWrap;
            _minFltr = header->_minFltr;
            _magFltr = header->_magFltr;
            _lodBias = header->_lodBias;
            _maxAniso = header->_maxAniso;
            _clampBias = header->_clampBias == 1;
            _texelInterp = header->_texelInterp == 1;
            _pad = header->_pad;

            if (header->_texOffset != 0)
            {
                if (_replaced && header->_texOffset >= Parent.WorkingUncompressed.Length)
                    Name = null;
                else
                {
                    if (_replaced)
                        Name = header->TextureName;
                    else
                        _name = header->TextureName;
                    _texture = Model.FindOrCreateTexture(_name);
                    _texture._references.Add(this);
                }
            }
            if (header->_pltOffset != 0)
            {
                if (_replaced && header->_pltOffset >= Parent.WorkingUncompressed.Length)
                    _palette = null;
                else
                {
                    string name = header->PaletteName;
                    _palette = Model.FindOrCreatePalette(name);
                    _palette._references.Add(this);
                }
            }

            int len = ((MDL0MaterialNode)Parent).XFCommands.Length;
            if (len != 0 && Index * 2 < len)
            {
                TexMtxFlags = new XFTexMtxInfo(((MDL0MaterialNode)Parent).XFCommands[Index * 2].values[0]);
                DualTexFlags = new XFDualTex(((MDL0MaterialNode)Parent).XFCommands[Index * 2 + 1].values[0]);
                getValues();
            }

            //if (PaletteNode == null && TextureNode != null)
            //{
            //    if (TextureNode.Source == null)
            //        TextureNode.GetSource();

            //    if (TextureNode.Source is TEX0Node && ((TEX0Node)TextureNode.Source).HasPalette)
            //    {
            //        Model._errors.Add("A palette was not set to texture reference " + Index + " in material " + Parent.Index + " (" + Parent.Name + ").");
            //        PaletteNode = Model.FindOrCreatePalette(TextureNode.Name);

            //        SignalPropertyChange();
            //    }
            //}

            MDL0TexSRTData* TexSettings = ((MDL0MaterialNode)Parent).Header->TexMatrices(((MDL0MaterialNode)Parent)._initVersion);

            _texFlags = TexSettings->GetTexFlags(Index);
            _texMatrix = TexSettings->GetTexMatrices(Index);

            _flags = (TexFlags)((((MDL0MaterialNode)Parent)._layerFlags >> (4 * Index)) & 0xF);

            _bindState = new FrameState(
                new Vector3(_texFlags.TexScale._x, _texFlags.TexScale._y, 1),
                new Vector3(_texFlags.TexRotation, 0, 0),
                new Vector3(_texFlags.TexTranslation._x, _texFlags.TexTranslation._y, 0));

            return false;
        }
        public void RecalcFrameState()
        {
            if (_overrideBone != null)
            {
                _frameMatrix = _overrideBone._frameMatrix;
                _inverseFrameMatrix = _overrideBone._inverseFrameMatrix;
            }
            else
            {
                if (_overrideTranslate != new Vector3())
                    _frameState = new FrameState(_frameState.Scale, _frameState.Rotate, _frameState.Translate + _overrideTranslate);

                if (_parent is MDL0BoneNode)
                {
                    _frameMatrix = ((MDL0BoneNode)_parent)._frameMatrix * _frameState._transform;
                    _inverseFrameMatrix = _frameState._iTransform * ((MDL0BoneNode)_parent)._inverseFrameMatrix;
                }
                else
                {
                    _frameMatrix = _frameState._transform;
                    _inverseFrameMatrix = _frameState._iTransform;
                }
            }

            //if (_overriding.Count != 0)
            //    foreach (MDL0BoneNode b in _overriding)
            //        b.RecalcFrameState();

            if (BillboardSetting == BillboardFlags.PerspectiveSTD)
                MuliplyRotation();

            foreach (MDL0BoneNode bone in Children)
                bone.RecalcFrameState();
        }
        internal void ApplyCHR0(CHR0Node node, int index, bool linear)
        {
            CHR0EntryNode e;

            _frameState = _bindState;

            if (node != null && index > 0 && (e = node.FindChild(Name, false) as CHR0EntryNode) != null) //Set to anim pose
                fixed (FrameState* v = &_frameState)
                {
                    float* f = (float*)v;
                    for (int i = 0; i < 9; i++)
                        if (e.Keyframes[(KeyFrameMode)(i + 0x10)] > 0)
                            f[i] = e.GetFrameValue((KeyFrameMode)(i + 0x10), index - 1, linear, node.Loop);

                    _frameState.CalcTransforms();
                }

            foreach (MDL0BoneNode b in Children)
                b.ApplyCHR0(node, index, linear);
        }
        //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);

            //Assign true parent using parent header offset
            int offset = header->_parentOffset;
            //Offsets are always < 0, because parent entries are listed before children
            if (offset < 0)
            {
                //Get address of parent header
                MDL0Bone* pHeader = (MDL0Bone*)((byte*)header + offset);
                //Search bone list for matching header
                foreach (MDL0BoneNode bone in Parent._children)
                    if (pHeader == bone.Header)
                    {
                        _parent = bone;
                        break;
                    }
            }

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

            //Assign fields
            _flags1 = (BoneFlags)(uint)header->_flags;
            _flags2 = (BillboardFlags)(uint)header->_bbFlags;
            _bbNodeId = header->_bbNodeId;
            _nodeIndex = header->_nodeId;
            _boneIndex = header->_index;
            _headerLen = header->_headerLen;
            _mdl0Offset = header->_mdl0Offset;
            _stringOffset = header->_stringOffset;
            _parentOffset = header->_parentOffset;
            _firstChildOffset = header->_firstChildOffset;
            _nextOffset = header->_nextOffset;
            _prevOffset = header->_prevOffset;
            _userDataOffset = header->_userDataOffset;

            if (_flags2 != 0 && _flags1.HasFlag(BoneFlags.HasGeometry))
                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;

            _bMin = header->_boxMin;
            _bMax = header->_boxMax;

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

            //We don't want to process children because not all have been parsed yet.
            //Child assigning will be handled by the parent group.
            return false;
        }