/// <summary>
        /// Sets the model that this object was instanced from
        /// </summary>
        public ModelInstance( Model source )
        {
            m_Source = source;

            //	Set up the animation layers
            if ( source.Animations == null )
            {
                return;
            }

            m_Layers = new AnimationLayer[ ( int )ModelPart.NumParts ];
            for ( int layerIndex = 0; layerIndex < ( int )ModelPart.NumParts; ++layerIndex )
            {
                m_ReferencePoints[ layerIndex ] = new ReferencePoint( ( ModelPart )layerIndex );

                ModelMesh partMesh = source.GetPartMesh( ( ModelPart )layerIndex );

                if ( partMesh == null )
                {
                    continue;
                }
                if ( source.Animations != null )
                {
                    //	TODO: This assigns the entire animation set to each layer, which isn't correct (although it'll work OK)
                    m_Layers[ layerIndex ] = new AnimationLayer( source.Animations, ( ModelPart )layerIndex );
                }
            }
        }
        /// <summary>
        /// Loads... stuff
        /// </summary>
        public override object Load( ISource source, LoadParameters parameters )
        {
            parameters.CanCache = true;

            Vector3 scale = new Vector3
                (
                    DynamicProperties.GetProperty( parameters.Properties, "scaleX", 1.0f ),
                    DynamicProperties.GetProperty( parameters.Properties, "scaleY", 1.0f ),
                    DynamicProperties.GetProperty( parameters.Properties, "scaleZ", 1.0f )
                );

            Matrix44 transform = new Matrix44( );
            transform.Scale( scale.X, scale.Y, scale.Z );

            //	create the model
            Model model = new Model( );

            //	oh dear another md3 hack - directories mean articulated models, with skins and animations. Files
            //	mean single objects
            if ( source is IFolder )
            {
                //	Load animations
                model.Animations = LoadAnimations( AnimationFile( source ) );
                LoadNestedModel( model, source, transform );
            }
            else
            {
                LoadObjectModel( model, source, transform );
            }
            return model;
        }
 /// <summary>
 /// Nests one model part's mesh inside another, using a named tag as a transform
 /// </summary>
 private static void NestMesh( Model model, ModelPart parent, ModelPart child, string tagName )
 {
     model.GetPartMesh( parent ).AddNestedPart( child, model.GetPartMesh( parent ).GetTagIndex( tagName ) );
 }
        private static void LoadObjectModel( Model model, ISource source, Matrix44 transform )
        {
            //	Load the skin file for the current part
            IDictionary< string, ITexture2d > textureTable = LoadSkin( source, DefaultSkinFile( source, ModelPart.Weapon ) );

            //	Load the MD3 associated with the current part
            ModelMesh partMesh = LoadMd3( source, model, ModelPart.Weapon, transform, source, textureTable );
            model.SetPartMesh( ModelPart.Weapon, partMesh );
            model.SetRootMesh( partMesh );
        }
        private static void LoadNestedModel( Model model, ISource source, Matrix44 transform )
        {
            //	Run through all the parts
            for ( int partIndex = 0; partIndex < ( int )ModelPart.NumParts; ++partIndex )
            {
                ModelPart curPart = ( ModelPart )partIndex;

                if ( curPart == ModelPart.Weapon )
                {
                    //	The weapon does not have a related mesh, so just ignore...
                    continue;
                }
                //	Load the skin file for the current part
                IDictionary< string, ITexture2d > surfaceTextureTable = LoadSkin( source, DefaultSkinFile( source, curPart ) );

                //	Load the MD3 associated with the current part
                ModelMesh partMesh = LoadMd3( source, model, curPart, transform, MeshFile( source, curPart ), surfaceTextureTable );
                model.SetPartMesh( curPart, partMesh );
            }

            model.SetRootMesh( model.GetPartMesh( ModelPart.Lower ) );
            NestMesh( model, ModelPart.Lower, ModelPart.Upper, "tag_torso" );
            NestMesh( model, ModelPart.Upper, ModelPart.Head, "tag_head" );
            NestMesh( model, ModelPart.Upper, ModelPart.Weapon, "tag_weapon" );
        }
        /// <summary>
        /// Loads an MD3 mesh resource from a stream
        /// </summary>
        private static ModelMesh LoadMd3( ISource source, Model model, ModelPart part, Matrix44 transform, ISource md3Source, IDictionary<string, ITexture2d> surfaceTextureTable )
        {
            using ( Stream inputStream = OpenStream( md3Source ) )
            {
                BinaryReader reader = new BinaryReader( inputStream );

                //	http://icculus.org/homepages/phaethon/q3a/formats/md3format.html

                //	Make sure of the MD3 identity
                byte[] ident		= reader.ReadBytes( 4 );
                if ( ( ident[ 0 ] != 'I' ) || ( ident[ 1 ] != 'D' ) || ( ident[ 2 ] != 'P' ) || ( ident[ 3 ] != '3' ) )
                {
                    throw new ApplicationException( "Failed to load MD3 resource - stream did not start with 'IDP3' MD3 identifier" );
                }

                //	Read in header
                //int version			=
                reader.ReadInt32( );
                //string name			=
                ReadString( reader, MaxPathLength );
                //int flags			=
                reader.ReadInt32( );
                int numFrames		= reader.ReadInt32( );
                int numTags			= reader.ReadInt32( );
                int numSurfaces		= reader.ReadInt32( );
                //int numSkins		=
                reader.ReadInt32( );
                int framesOffset	= reader.ReadInt32( );
                int tagsOffset		= reader.ReadInt32( );
                int surfacesOffset	= reader.ReadInt32( );
                //int eofOffset		=
                reader.ReadInt32( );

                //	TODO: Can load directly into mesh frame, tag and surface structures - don't do this intermediate step
                ModelMesh mesh = new ModelMesh( model, part );

                ReadFrames( reader, framesOffset, numFrames, mesh, transform );
                ReadTags( reader, tagsOffset, numTags, numFrames, mesh, transform );
                ReadSurfaces( source, reader, surfacesOffset, numSurfaces, numFrames, mesh, surfaceTextureTable, transform );

                //	TODO: REMOVE. test frames
                string md3Name = md3Source.ToString( );
                if ( md3Name.IndexOf( "Upper" ) != -1 )
                {
                    mesh.DefaultFrame = 151;
                }
                else if ( md3Name.IndexOf( "Head" ) != -1 )
                {
                    mesh.DefaultFrame = 0;
                }
                else
                {
                    mesh.DefaultFrame = 0;
                }

                return mesh;
            }
        }
 /// <summary>
 /// Constructor
 /// </summary>
 public ModelMesh( Model model, ModelPart part )
 {
     m_Model = model;
     m_Part = part;
 }