public void ExpandLibraryNode( LibraryNode lnode, string referrerId, Matrix4 localTransform, Matrix4 transform, ColladaMeshInfo meshInfo )
 {
     // recurse through any child nodes
     int childNo = 0;
     foreach( LibraryNode child in lnode.children )
         ExpandLibraryNode( child, referrerId + "." + (childNo++).ToString(), localTransform, transform, meshInfo );
     // expand geometry_instance references
     int instNo = 0;
     foreach( string geoInstanceId in lnode.geoInstanceIds )
     {
         GeometryInstance geoInstance = new GeometryInstance( referrerId + "." + (instNo++).ToString(), null, localTransform, transform );
         if( meshInfo.Geometries.ContainsKey( geoInstanceId ) )
         {
             // this was an instance_geometry instead of an instance_controller in 1.4 terms
             geoInstance.controller = null;
             geoInstance.geoSet = meshInfo.Geometries[ geoInstanceId ].Clone( geoInstance.name );
             meshInfo.GeoInstances.Add( geoInstance );
         }
     }
 }
        public void ReadWeaklyTypedArray( DataSource source, XmlNode node, ColladaMeshInfo meshInfo )
        {
            string type = "string";

            if( node.Attributes[ "type" ] != null )
                type = node.Attributes[ "type" ].Value;

            switch( type )
            {
            case "float":
                ReadFloatArray( source, node, meshInfo );
                break;
            case "string":
            case "Name":
                ReadStringArray( source, node, meshInfo );
                break;
            default:
                log.WarnFormat( "Unhandled array type: {0}", type );
                break;
            }
        }
        /// <summary>
        ///   Import into the mesh, using the skeleton provided, and 
        ///   assigning the animation data to a new animation.
        /// </summary>
        /// <param name="transform">the world transform to apply to this object</param>
        /// <param name="mesh">the mesh we will populate</param>
        /// <param name="skeleton">the skeleton to which we will add animations (or null if we are creating one)</param>
        /// <param name="animationName">the name that will be used for the animation</param>
        /// <param name="materialNamespace">namespace used for generation of material names</param>
        public void Import( Matrix4 transform, Mesh mesh, Skeleton skeleton, string animationName, string materialNamespace )
        {
            ColladaMeshReader reader = null;

            XmlDocument document = new XmlDocument();

            document.Load( m_Stream );

            XmlElement rootElement = document.DocumentElement;

            // This is slightly weird. The client calls this method on this object,
            // but then we determine which version of collada we're actually looking
            // at, and create a new instances of a derived collada reader.  As an
            // outcome, we have to copy fields from the factory-created instance
            // back to this instance.
            // TODO: Need a static factory method on the base class to create the
            // collada reader instance, then call that instance from the client;
            // that way we'll only have one instance in the first place.
            reader = GetColladaParser( rootElement );

            reader.m_ColladaRootNode = rootElement;
            reader.m_Document = document;

            reader.m_MaterialBuilder = new MaterialScriptBuilder( materialNamespace );

            ColladaMeshInfo meshInfo = new ColladaMeshInfo( mesh );

            reader.ReadCollada( rootElement, meshInfo );

            meshInfo.NoRiggingCulling = NoRiggingCulling;

            meshInfo.Process( transform, skeleton, m_BaseFile, animationName );

            this.m_MaterialBuilder = reader.MaterialBuilder;
        }
        public virtual void ReadMesh( string geometryName, XmlNode node, ColladaMeshInfo meshInfo )
        {
            Dictionary<int, List<InputSourceCollection>> inputSources =
                new Dictionary<int, List<InputSourceCollection>>();
            Dictionary<string, VertexSet> vertexSets = new Dictionary<string, VertexSet>();

            foreach( XmlNode childNode in node.ChildNodes )
            {
                switch( childNode.Name )
                {
                case "source":
                    ReadSource( null, childNode, meshInfo );
                    break;
                case "vertices":
                    // Read in inputs and vertex sets that should apply to all
                    // the sub-portions of this geometry.
                    ReadVertices( vertexSets, childNode, meshInfo );
                    break;
                case "lines":
                case "linestrips":
                case "triangles":
                case "trifans":
                case "tristrips":
                case "polygons":
                    // Handle this in the second pass
                    break;
                default:
                    DebugMessage( childNode );
                    break;
                }
            }

            int submeshIndex = 0;
            foreach( XmlNode childNode in node.ChildNodes )
            {
                switch( childNode.Name )
                {
                case "source":
                case "vertices":
                    // these were handled in the first pass
                    break;
                case "polygons":
                case "triangles":
                    {
                        string name = string.Format( "{0}.{1}", geometryName, submeshIndex++ );
                        if( !meshInfo.Geometries.ContainsKey( geometryName ) )
                            meshInfo.Geometries[ geometryName ] = new GeometrySet( geometryName );
                        GeometrySet geoSet = meshInfo.Geometries[ geometryName ];
                        MeshGeometry geometry = new MeshGeometry( name, geoSet );
                        foreach( VertexSet vertexSet in vertexSets.Values )
                            geometry.AddVertexSet( vertexSet );
                        foreach( int inputIndex in inputSources.Keys )
                            geometry.AddInputs( inputIndex, inputSources[ inputIndex ] );
                        geoSet.Add( geometry );
                        ReadPolygons( geometry, vertexSets, childNode, meshInfo );
                        break;
                    }
                case "lines":
                case "linestrips":
                case "trifans":
                case "tristrips":
                default:
                    DebugMessage( childNode );
                    break;
                }
            }
        }
        public virtual void ReadMaterial( XmlNode node, ColladaMeshInfo meshInfo )
        {
            string id = node.Attributes[ "id" ].Value;
            List<MaterialTechnique_13> materialTechniques = new List<MaterialTechnique_13>();
            foreach( XmlNode childNode in node.ChildNodes )
            {
                switch( childNode.Name )
                {
                case "shader":
                    ReadShader( materialTechniques, childNode );
                    break;
                default:
                    DebugMessage( childNode );
                    break;
                }
            }

            MaterialBuilder.AddTechniques( id, materialTechniques );
        }
        public void ReadJoints( SkinController controller,
                               XmlNode node, ColladaMeshInfo meshInfo )
        {
            Dictionary<int, List<InputSourceCollection>> inputSources =
                new Dictionary<int, List<InputSourceCollection>>();
            foreach( XmlNode childNode in node.ChildNodes )
            {
                switch( childNode.Name )
                {
                case "input":
                    ReadInput( inputSources, null, childNode, meshInfo );
                    break;
                default:
                    break;
                }
            }
            // process joints here
            InputSource jointInput = null;
            InputSource invBindMatrixInput = null;
            foreach( List<InputSourceCollection> inputs in inputSources.Values )
            {
                foreach( InputSourceCollection tmp in inputs )
                {
                    Debug.Assert( tmp.GetSources().Count == 1 );
                    InputSource source = tmp.GetSources()[ 0 ];
                    switch( source.Semantic )
                    {
                    case "JOINT":
                        jointInput = source;
                        break;
                    case "INV_BIND_MATRIX":
                        invBindMatrixInput = source;
                        break;
                    default:
                        log.InfoFormat( "Unhandled joint input semantic: {0}", source.Semantic );
                        break;
                    }
                }
            }
            Debug.Assert( jointInput != null && invBindMatrixInput != null );
            string jointParam = "";
            if( jointInput.Accessor.ContainsParam( "JOINT" ) )
                jointParam = "JOINT";
            string invBindParam = "";
            if( invBindMatrixInput.Accessor.ContainsParam( "INV_BIND_MATRIX" ) )
                invBindParam = "INV_BIND_MATRIX";
            else if( invBindMatrixInput.Accessor.ContainsParam( "TRANSFORM" ) )
                invBindParam = "TRANSFORM";
            for( int ptIndex = 0; ptIndex < jointInput.Count; ++ptIndex )
            {
                string jointName = (String) jointInput.Accessor.GetParam( jointParam, ptIndex );
                Matrix4 invBindMatrix = (Matrix4) invBindMatrixInput.Accessor.GetParam( invBindParam, ptIndex );
                if( controller.InverseBindMatrices.ContainsKey( jointName ) )
                {
                    string msg =
                        string.Format( "Duplicate inverse bind matrix found in controller '{0}' for joint '{1}'; Aborting export.",
                                      controller.Name, jointName );

                    log.Error( msg );
                    throw new Exception( msg );
                }
                // Debug.Assert(controller.InvBindTransforms[jointName] == invBindMatrix);
                controller.InverseBindMatrices[ jointName ] = invBindMatrix;
            }
        }
        public void ReadInstanceGeometry( string nodeName, string parentBone, Matrix4 localTransform, Matrix4 transform, XmlNode node, ColladaMeshInfo meshInfo )
        {
            string instance = UrlFragementName( node );

            if( nodeName == null )
            {
                nodeName = instance;
            }

            // It's possible that we failed to build geometries referenced by the
            // a geometry instance (e.g. if the geometry only contains 'line'
            // primitives), so only create the instance if the geometry is present.
            if( meshInfo.Geometries.ContainsKey( instance ) )
            {
                GeometryInstance geoInstance = CreateGeometryInstance( nodeName, parentBone, ref localTransform, ref transform, node, meshInfo );

                geoInstance.controller = null;
                geoInstance.geoSet = meshInfo.Geometries[ instance ];

                meshInfo.GeoInstances.Add( geoInstance );
            }
        }
 public virtual void ReadInput( Dictionary<int, List<InputSourceCollection>> inputSources,
                               Dictionary<string, VertexSet> vertexSets,
                               XmlNode node, ColladaMeshInfo meshInfo )
 {
     InputSourceCollection input = null;
     string source = node.Attributes[ "source" ].Value;
     // Get the part after the '#'
     source = source.Substring( 1 );
     string semantic = node.Attributes[ "semantic" ].Value;
     int inputIndex = inputSources.Count;
     if( node.Attributes[ "idx" ] != null )
         inputIndex = int.Parse( node.Attributes[ "idx" ].Value );
     if( !inputSources.ContainsKey( inputIndex ) )
         inputSources[ inputIndex ] = new List<InputSourceCollection>();
     if( semantic == "VERTEX" )
     {
         VertexSet vertexSet = vertexSets[ source ];
         // Dereference the vertex input and add that instead.
         if( inputSources != null )
         {
             VertexInputSource vertexInput = new VertexInputSource();
             foreach( InputSourceCollection tmp in vertexSet.vertexEntries )
                 vertexInput.AddSource( tmp );
             inputSources[ inputIndex ].Add( vertexInput );
         }
     }
     else
     {
         if( !Accessors.ContainsKey( source ) )
         {
             Debug.Assert( false, "Missing accessor for source: " + source );
             return;
         }
         Accessor accessor = Accessors[ source ];
         if( inputSources != null )
         {
             input = new InputSource( source, semantic, accessor );
             inputSources[ inputIndex ].Add( input );
         }
     }
 }
 public void ReadCombiner( string currentSource, XmlNode node, ColladaMeshInfo meshInfo )
 {
     Dictionary<int, List<InputSourceCollection>> inputSources =
         new Dictionary<int, List<InputSourceCollection>>();
     foreach( XmlNode childNode in node.ChildNodes )
     {
         switch( childNode.Name )
         {
         case "input":
             ReadInput( inputSources, null, childNode, meshInfo );
             break;
         case "v":
             // Ignore in this pass
             break;
         default:
             break;
         }
     }
     List<CombinerComponents> combComps = new List<CombinerComponents>();
     int vertexIndex = 0;
     foreach( XmlNode childNode in node.ChildNodes )
     {
         switch( childNode.Name )
         {
         case "input":
             // Ignore in this pass
             break;
         case "v":
             {
                 CombinerComponents cc = ReadCombinerV( vertexIndex++, inputSources, childNode );
                 if( cc != null )
                     combComps.Add( cc );
             }
             break;
         default:
             DebugMessage( childNode );
             break;
         }
     }
     Combiners[ currentSource ] = combComps;
 }
 /// <summary>
 ///    Reads bone information from the file.
 /// </summary>
 public override void ReadCollada( XmlNode node, ColladaMeshInfo meshInfo )
 {
     foreach( XmlNode childNode in node.ChildNodes )
     {
         switch( childNode.Name )
         {
         case "library":
             ReadLibrary( childNode, meshInfo );
             break;
         case "asset":
             ReadAsset( childNode, meshInfo );
             break;
         case "scene":
             ReadScene( childNode, meshInfo );
             break;
         default:
             DebugMessage( childNode );
             break;
         }
     }
 }
 public virtual void ReadChannel( string parentAnimationName, string animationName,
                                 XmlNode node, ColladaMeshInfo meshInfo )
 {
     string samplerId = node.Attributes[ "source" ].Value;
     string targetId = node.Attributes[ "target" ].Value;
     // Strip off the leading '#'
     samplerId = samplerId.Substring( 1 );
     Sampler sampler = meshInfo.Samplers[ samplerId ];
     Channel channel = new Channel( sampler, targetId, "matrix" );
     channel.AnimationName = animationName;
     channel.ParentAnimationName = parentAnimationName;
     meshInfo.Channels.Add( channel );
 }
 public virtual void ReadAsset( XmlNode node, ColladaMeshInfo meshInfo )
 {
     foreach( XmlNode childNode in node.ChildNodes )
     {
         switch( childNode.Name )
         {
         case "unit":
             ReadUnit( childNode, meshInfo );
             break;
         case "up_axis":
             ReadUpAxis( childNode, meshInfo );
             break;
         default:
             DebugMessage( childNode );
             break;
         }
     }
 }
        private bool IsInstanceGeometry( XmlNode node, ColladaMeshInfo meshInfo )
        {
            string instanceName = UrlFragementName( node );

            if( String.Empty != instanceName )
            {
                return meshInfo.Geometries.ContainsKey( instanceName );
            }

            return false;
        }
 public void ReadAnimationLibrary( XmlNode node, ColladaMeshInfo meshInfo )
 {
     foreach( XmlNode childNode in node.ChildNodes )
     {
         switch( childNode.Name )
         {
         case "animation":
             ReadAnimation( null, childNode, meshInfo );
             break;
         default:
             DebugMessage( childNode );
             break;
         }
     }
 }
        private static GeometryInstance CreateGeometryInstance( string nodeName, string parentBone, ref Matrix4 localTransform, ref Matrix4 transform, XmlNode node, ColladaMeshInfo meshInfo )
        {
            GeometryInstance geoInstance = new GeometryInstance( nodeName, parentBone, localTransform, transform );

            #if WORKS_AS_EXPECTED
            XmlNode bindNode = node.SelectSingleNode( "bind_material" );

            if( null != bindNode )
            {
                geoInstance.bindMaterial = new BindMaterial( bindNode, meshInfo.materialNamespace );
            }
            #else
            foreach( XmlNode child in node.ChildNodes )
            {
                if( "bind_material" == child.Name )
                {
                    geoInstance.bindMaterial = new BindMaterial( child, MaterialScriptBuilder.MaterialNamespace );
                }
            }
            #endif
            return geoInstance;
        }
 public virtual void ReadImageLibrary( XmlNode node, ColladaMeshInfo meshInfo )
 {
     foreach( XmlNode childNode in node.ChildNodes )
     {
         switch( childNode.Name )
         {
         case "image":
             ReadImage( childNode, meshInfo );
             break;
         default:
             DebugMessage( childNode );
             break;
         }
     }
 }
        public InputSourceCollection ReadInput( XmlNode node, ColladaMeshInfo meshInfo )
        {
            string sourceId = node.Attributes[ "source" ].Value;
            // Get the part after the '#'
            sourceId = sourceId.Substring( 1 );
            string semantic = node.Attributes[ "semantic" ].Value;
            // offset source semantic set

            Accessor accessor = null;

            if( !Accessors.ContainsKey( sourceId ) )
            {
                if( Sources.ContainsKey( sourceId ) )
                {
                    Source source = Sources[ sourceId ];
                    Debug.Assert( source.Accessors.Count == 1 );
                    accessor = Accessors[ source.Accessors[ 0 ].AccessorId ];
                    return new InputSource( sourceId, semantic, accessor );
                }
                // TODO: Check combiners as well.
                Debug.Assert( false, "Missing accessor for source: " + sourceId );
                return null;
            }

            accessor = Accessors[ sourceId ];
            return new InputSource( sourceId, semantic, accessor );
        }
        public virtual void ReadController( XmlNode node, ColladaMeshInfo meshInfo )
        {
            // Set up the current geometry name
            string controllerName = node.Attributes[ "id" ].Value;
            string target = node.Attributes[ "target" ].Value;

            SkinController controller = new SkinController( controllerName );
            controller.Target = meshInfo.Geometries[ target ];

            meshInfo.Controllers[ controllerName ] = controller;

            foreach( XmlNode childNode in node.ChildNodes )
            {
                switch( childNode.Name )
                {
                case "skin":
                    ReadSkin( controller, childNode, meshInfo );
                    break;
                default:
                    DebugMessage( childNode );
                    break;
                }
            }
        }
        public void ReadInstanceController( string nodeName, string parentBone, Matrix4 localTransform, Matrix4 transform, XmlNode node, ColladaMeshInfo meshInfo )
        {
            string instance = UrlFragementName( node );

            if( nodeName == null )
            {
                nodeName = instance;
            }

            if( !meshInfo.Controllers.ContainsKey( instance ) )
            {
                log.WarnFormat( "Cannot find controller instance named '{0}'", instance );
            }
            else
            {
                GeometryInstance geoInstance = CreateGeometryInstance( nodeName, parentBone, ref localTransform, ref transform, node, meshInfo );

                geoInstance.controller = meshInfo.Controllers[ instance ];
                geoInstance.geoSet = meshInfo.Controllers[ instance ].Target;

                meshInfo.GeoInstances.Add( geoInstance );
            }
        }
        public void ReadControllerLibrary( XmlNode node, ColladaMeshInfo meshInfo )
        {
            #if UNORDERED
            foreach (XmlNode childNode in node.ChildNodes) {
                switch (childNode.Name) {
                    case "controller":
                        ReadController(childNode, meshInfo);
                        break;
                    default:
                        DebugMessage(childNode);
                        break;
                }
            }
            #else
            XmlElement libElement = node as XmlElement;

            List<XmlNode> orderedControllerNodes = new List<XmlNode>();

            foreach( XmlNode childNode in node.ChildNodes )
            {
                if( IsMorphController( childNode ) )
                {
                    orderedControllerNodes.Add( childNode );
                }
            }
            foreach( XmlNode childNode in node.ChildNodes )
            {
                if( IsSkinController( childNode ) )
                {
                    orderedControllerNodes.Add( childNode );
                }
            }
            foreach( XmlNode childNode in orderedControllerNodes )
            {
                ReadController( childNode, meshInfo );
            }
            #endif
        }
 public void ReadIntArray( DataSource source, XmlNode node, ColladaMeshInfo meshInfo )
 {
     string id = node.Attributes[ "id" ].Value;
     int count = int.Parse( node.Attributes[ "count" ].Value );
     DataSources[ id ] = source;
     FillArray( source.IntData, node.InnerText );
     Debug.Assert( source.IntData.Count == count );
 }
 public void ReadExtra( XmlNode node, ColladaMeshInfo meshInfo )
 {
     foreach( XmlNode childNode in node.ChildNodes )
     {
         switch( childNode.Name )
         {
         case "technique":
             ReadExtraTechnique( childNode, meshInfo );
             break;
         default:
             DebugMessage( childNode );
             break;
         }
     }
 }
 public virtual void ReadLibrary( XmlNode node, ColladaMeshInfo meshInfo )
 {
     string type = node.Attributes[ "type" ].Value;
     switch( type )
     {
     case "IMAGE":
         ReadImageLibrary( node, meshInfo );
         break;
     case "TEXTURE":
         ReadTextureLibrary( node, meshInfo );
         break;
     case "MATERIAL":
         ReadMaterialLibrary( node, meshInfo );
         break;
     case "GEOMETRY":
         ReadGeometryLibrary( node, meshInfo );
         break;
     case "CONTROLLER":
         ReadControllerLibrary( node, meshInfo );
         break;
     case "ANIMATION":
         ReadAnimationLibrary( node, meshInfo );
         break;
     default:
         log.InfoFormat( "Ignoring unhandled library type: {0}", type );
         break;
     }
 }
 public void ReadExtraTechnique( XmlNode node, ColladaMeshInfo meshInfo )
 {
     XmlAttribute attr = node.Attributes[ "profile" ];
     if( attr != null && attr.Value == "MAYA" )
     {
         log.Info( "Handling maya technique" );
         foreach( XmlNode childNode in node.ChildNodes )
         {
             switch( childNode.Name )
             {
             case "param":
                 ReadExtraTechniqueParam( childNode, meshInfo );
                 break;
             default:
                 DebugMessage( childNode );
                 break;
             }
         }
     }
     else
     {
         log.InfoFormat( "Skipping extra technique with unknown profile: {0}", attr );
     }
 }
 public void ReadMaterialLibrary( XmlNode node, ColladaMeshInfo meshInfo )
 {
     foreach( XmlNode childNode in node.ChildNodes )
     {
         switch( childNode.Name )
         {
         case "material":
             ReadMaterial( childNode, meshInfo );
             break;
         default:
             DebugMessage( childNode );
             break;
         }
     }
 }
 /// <summary>
 ///   Right now, I use this to set the layer of objects to avoid drawing controls
 /// </summary>
 /// <param name="node"></param>
 public void ReadExtraTechniqueParam( XmlNode node, ColladaMeshInfo meshInfo )
 {
     XmlAttribute attr;
     attr = node.Attributes[ "type" ];
     if( attr == null || attr.Value != "layer" )
     {
         log.InfoFormat( "Skipping extra technique parameter with unknown type: {0}", attr );
         return;
     }
     attr = node.Attributes[ "name" ];
     if( attr == null || attr.Value == "" )
     {
         log.Info( "Skipping unnamed layer in extra technique parameter" );
         return;
     }
     string layer = attr.Value;
     // Ok, looks like these are the names of nodes that should not be displayed
     string[] values = node.InnerText.Split( (char[]) null, StringSplitOptions.RemoveEmptyEntries );
     foreach( string val in values )
         meshInfo.Layers[ val ] = layer;
 }
        public virtual void ReadNode( List<NamedTransform> parentTransforms, string parentBone, XmlNode node, ColladaMeshInfo meshInfo )
        {
            List<NamedTransform> transformChain = new List<NamedTransform>();
            foreach( XmlNode childNode in node.ChildNodes )
            {
                switch( childNode.Name )
                {
                case "rotate":
                    {
                        float angle = 0;
                        Vector3 axis = Vector3.UnitY;
                        ReadRotate( ref angle, ref axis, childNode );
                        transformChain.Add( new NamedRotateTransform( GetSid( childNode ), angle, axis ) );
                    }
                    break;
                case "scale":
                    {
                        Vector3 scale = Vector3.UnitScale;
                        ReadVector( ref scale, childNode );
                        transformChain.Add( new NamedScaleTransform( GetSid( childNode ), scale ) );
                    }
                    break;
                case "translate":
                    {
                        Vector3 translation = Vector3.Zero;
                        ReadVector( ref translation, childNode );
                        transformChain.Add( new NamedTranslateTransform( GetSid( childNode ), translation ) );
                    }
                    break;
                case "skew":
                    {
                        // FIXME: For now, just handle skew with a matrix
                        Matrix4 matrix = Matrix4.Identity;
                        ReadSkewMatrix( ref matrix, childNode );
                        transformChain.Add( new NamedMatrixTransform( GetSid( childNode ), matrix ) );
                    }
                    break;
                case "matrix":
                    {
                        Matrix4 matrix = Matrix4.Identity;
                        ReadMatrix( ref matrix, childNode );
                        transformChain.Add( new NamedMatrixTransform( GetSid( childNode ), matrix ) );
                    }
                    break;
                case "instance":
                case "node":
                case "lookat":
                case "perspective":
                case "boundingbox":
                case "extras":
                default:
                    break;
                }
            }

            if( node.Attributes[ "type" ] != null &&
                node.Attributes[ "id" ] != null )
            {
                string nodeId = node.Attributes[ "id" ].Value;
                switch( node.Attributes[ "type" ].Value )
                {
                case "JOINT":
                    {
                        meshInfo.JointTransformChains[ nodeId ] = transformChain;
                        meshInfo.BoneParents[ nodeId ] = parentBone;
                        parentBone = nodeId;
                    }
                    break;
                case "NODE":
                    // the default
                    break;
                default:
                    DebugMessage( node );
                    break;
                }
            }

            foreach( XmlNode childNode in node.ChildNodes )
            {
                switch( childNode.Name )
                {
                case "instance":
                    {
                        Matrix4 transform = Matrix4.Identity;
                        foreach( NamedTransform t in transformChain )
                        {
                            transform = t.Transform * transform;
                            Debug.Assert( transform != Matrix4.Zero );
                        }
                        Matrix4 localTransform = transform;
                        foreach( NamedTransform t in parentTransforms )
                        {
                            transform = t.Transform * transform;
                            Debug.Assert( transform != Matrix4.Zero );
                        }

                        if( IsInstanceGeometry( childNode, meshInfo ) )
                        {
                            ReadInstanceGeometry( null, parentBone, localTransform, transform, childNode, meshInfo );
                        }
                        else
                        {
                            ReadInstanceController( null, parentBone, localTransform, transform, childNode, meshInfo );
                        }
                        break;
                    }
                case "node":
                    ReadNode( transformChain, parentBone, childNode, meshInfo );
                    break;
                case "rotate":
                case "scale":
                case "translate":
                case "skew":
                case "matrix":
                    break;
                case "lookat":
                case "perspective":
                case "boundingbox":
                case "extras":
                default:
                    DebugMessage( childNode );
                    break;
                }
            }
        }
        public void ReadGeometry( XmlNode node, ColladaMeshInfo meshInfo )
        {
            // Set up the current geometry name
            string geometryName = node.Attributes[ "id" ].Value;

            foreach( XmlNode childNode in node.ChildNodes )
            {
                switch( childNode.Name )
                {
                case "mesh":
                    ReadMesh( geometryName, childNode, meshInfo );
                    break;
                case "extra":
                default:
                    DebugMessage( childNode );
                    break;
                }
            }
        }
 public virtual void ReadCollada( XmlNode node, ColladaMeshInfo meshInfo )
 {
     throw new NotImplementedException();
 }
 public virtual void ReadImage( XmlNode node, ColladaMeshInfo meshInfo )
 {
     string id = node.Attributes[ "id" ].Value;
     string source = node.Attributes[ "source" ].Value;
     int slashIndex = source.LastIndexOf( '/' );
     if( slashIndex >= 0 )
         source = source.Substring( slashIndex + 1 );
     MaterialBuilder.AddImage( id, source );
 }