/// <summary>
 ///   Read in a data source, including the technique, accessors, 
 ///   joints, and combiners.  Sometimes this is in the context of 
 ///   a controller, in which case controller is not null.
 /// </summary>
 /// <param name="controller"></param>
 /// <param name="node"></param>
 public virtual void ReadSource( Controller controller, XmlNode node, ColladaMeshInfo meshInfo )
 {
     string sourceId = node.Attributes[ "id" ].Value;
     Source source = null;
     foreach( XmlNode childNode in node.ChildNodes )
     {
         switch( childNode.Name )
         {
         case "array":
             {
                 string arrayId = childNode.Attributes[ "id" ].Value;
                 DataSource dataSource = new DataSource( arrayId );
                 ReadWeaklyTypedArray( dataSource, childNode, meshInfo );
                 source = new Source( sourceId, dataSource );
             }
             break;
         case "bool_array":
             {
                 string arrayId = childNode.Attributes[ "id" ].Value;
                 DataSource dataSource = new DataSource( arrayId );
                 ReadBoolArray( dataSource, childNode, meshInfo );
                 source = new Source( sourceId, dataSource );
             }
             break;
         case "float_array":
             {
                 string arrayId = childNode.Attributes[ "id" ].Value;
                 DataSource dataSource = new DataSource( arrayId );
                 ReadFloatArray( dataSource, childNode, meshInfo );
                 source = new Source( sourceId, dataSource );
             }
             break;
         case "int_array":
             {
                 string arrayId = childNode.Attributes[ "id" ].Value;
                 DataSource dataSource = new DataSource( arrayId );
                 ReadIntArray( dataSource, childNode, meshInfo );
                 source = new Source( sourceId, dataSource );
             }
             break;
         case "Name_array":
             {
                 string arrayId = childNode.Attributes[ "id" ].Value;
                 DataSource dataSource = new DataSource( arrayId );
                 ReadStringArray( dataSource, childNode, meshInfo );
                 source = new Source( sourceId, dataSource );
             }
             break;
         case "technique":
             break; // Skip these in the first pass
         }
     }
     foreach( XmlNode childNode in node.ChildNodes )
     {
         switch( childNode.Name )
         {
         case "array":
         case "bool_array":
         case "float_array":
         case "int_array":
         case "Name_array":
             break; // Skip these in the second pass
         case "technique":
             ReadTechnique( controller, source, childNode, meshInfo );
             break;
         default:
             DebugMessage( childNode );
             break;
         }
     }
     Sources[ sourceId ] = source;
 }
 public void ReadTechnique( Controller controller,
                           Source source, XmlNode node, ColladaMeshInfo meshInfo )
 {
     foreach( XmlNode childNode in node.ChildNodes )
     {
         switch( childNode.Name )
         {
         case "accessor":
             {
                 // default the accessor id to the source id
                 string accessorId = source.SourceId;
                 if( childNode.Attributes[ "id" ] != null )
                     accessorId = childNode.Attributes[ "id" ].Value;
                 string arrayId = childNode.Attributes[ "source" ].Value;
                 // Get the part after the '#'
                 if( arrayId.StartsWith( "#" ) )
                     arrayId = arrayId.Substring( 1 );
                 else
                     log.InfoFormat( "Array Id {0} does not start with '#'", arrayId );
                 Debug.Assert( DataSources.ContainsKey( arrayId ) );
                 DataSource dataSource = DataSources[ arrayId ];
                 // TODO: Check stride and offset
                 Accessor accessor = new Accessor( dataSource, accessorId );
                 int stride = -1;
                 if( childNode.Attributes[ "stride" ] != null )
                     stride = int.Parse( childNode.Attributes[ "stride" ].Value );
                 accessor.Stride = stride;
                 ReadAccessor( accessor, childNode );
                 // Link this accessor in both as the source, and the id, which
                 // allows us to reference it by either name
                 Accessors[ accessorId ] = accessor;
                 Accessors[ source.SourceId ] = accessor;
                 source.AddAccessor( accessor );
             }
             break;
         case "combiner":
             ReadCombiner( source.SourceId, childNode, meshInfo );
             break;
         case "joints":
             {
                 SkinController skinController = controller as SkinController;
                 Debug.Assert( skinController != null );
                 ReadJoints( skinController, childNode, meshInfo );
             }
             break;
         default:
             DebugMessage( childNode );
             break;
         }
     }
 }
 public void ReadTechniqueCommon( Controller controller,
                                        Source source, XmlNode node,
                                        ColladaMeshInfo meshInfo )
 {
     ReadTechnique( controller, source, node, meshInfo );
 }