/// <summary>
        /// Loads a COLLADA section
        /// </summary>
        /// <param name="reader">XML reader</param>
        public override object LoadSection( XmlReader reader )
        {
            Hashtable sources = new Hashtable( );
            MeshVertices vertices = null;
            MeshPolygons polygons = null;

            while ( reader.Read( ) && reader.NodeType != XmlNodeType.EndElement )
            {
                if ( reader.NodeType != XmlNodeType.Element )
                {
                    continue;
                }

                switch ( reader.Name )
                {
                    case "source":
                        {
                            sources[ reader.GetAttribute( "id" ) ] = new MeshSource( reader );
                            break;
                        }

                    case "vertices":
                        {
                            vertices = new MeshVertices( reader, sources );
                            break;
                        }

                    case "polygons":
                        {
                            polygons = new MeshPolygons( reader, false, false );
                            break;
                        }

                    case "triangles":
                        {
                            polygons = new MeshPolygons( reader, true, false );
                            break;
                        }

                    default:
                        {
                            ReadPastElement( reader );
                            break;
                        }
                }

            }

            return BuildMesh( vertices, polygons );
        }
        /// <summary>
        /// Builds an OpenGL mesh
        /// </summary>
        private object BuildMesh( MeshVertices vertices, MeshPolygons polygons )
        {
            OpenGlMesh mesh = new OpenGlMesh( );

            //	Set up the index buffer in the mesh
            if ( polygons.StoredAsTriangles )
            {
                int[] indexBuffer = new int[ polygons.Polygons.Count * 3 ];

                int curIndex = 0;
                foreach ( MeshPolygon curPoly in polygons.Polygons )
                {
                    indexBuffer[ curIndex++ ] = curPoly.Indices[ 0 ];
                    indexBuffer[ curIndex++ ] = curPoly.Indices[ 1 ];
                    indexBuffer[ curIndex++ ] = curPoly.Indices[ 2 ];
                }

                mesh.CreateGroups( 1 );
                mesh.SetGroup( 0, new OpenGlIndexedGroup( Gl.GL_TRIANGLES, indexBuffer ) );
            }
            else
            {
                throw new ApplicationException( "sorry, non-triange index buffers not implemented yet" );
            }

            mesh.CreateVertexBuffers( vertices.Sources.Count );
            int vboIndex = 0;

            foreach ( MeshTaggedSource curSource in vertices.Sources )
            {
                //	Convert the source semantic to an opengl client state
                //	Swap y and z elements
                //	TODO: Should be a resource flag, at the very least
                bool swapYz = false;
                int clientState = 0;
                switch ( curSource.Semantic )
                {
                    case "POSITION": clientState = Gl.GL_VERTEX_ARRAY; swapYz = true; break;
                    case "NORMAL": clientState = Gl.GL_NORMAL_ARRAY; swapYz = true; break;
                    case "COLOR": clientState = Gl.GL_COLOR_ARRAY; break;
                    default:
                        throw new ApplicationException( string.Format( "Unknown mesh semantic \"{0}\"", curSource.Semantic ) );
                }

                //	Store the stride (note, for GL this has a slightly different meaning, I think. TODO: Check COLLADA spec. to make sure)
                int numObjects = curSource.Source.Data.Count / curSource.Source.Stride;
                short stride = 0;
                short numElements = ( short )curSource.Source.Stride;

                Type dataType = curSource.Source.DataType;
                switch ( Type.GetTypeCode( dataType ) )
                {
                    case TypeCode.Single:
                        {
                            //	HACK: Swap y and z coordinates - in blender (the 3d editor I'm currently using), z is up, in the engine, y is up.
                            float[] bufferData = ( float[] )curSource.Source.Data.ToArray( dataType );
                            if ( swapYz )
                            {
                                for ( int index = 0; index < bufferData.Length; index += 3 )
                                {
                                    float tmp = bufferData[ index + 1 ];
                                    bufferData[ index + 1 ] = bufferData[ index + 2 ];
                                    bufferData[ index + 2 ] = tmp;
                                }
                            }
                            mesh.SetVertexBuffer( vboIndex, new OpenGlVertexBuffer( numObjects, 0, clientState, stride, numElements, Gl.GL_STATIC_DRAW_ARB, bufferData ) );
                            break;
                        }

                    case TypeCode.Int32:
                        {
                            int[] bufferData = ( int[] )curSource.Source.Data.ToArray( dataType );
                            mesh.SetVertexBuffer( vboIndex, new OpenGlVertexBuffer( numObjects, 0, clientState, stride, numElements, Gl.GL_STATIC_DRAW_ARB, bufferData ) );
                            break;
                        }

                    case TypeCode.Byte:
                        {
                            byte[] bufferData = ( byte[] )curSource.Source.Data.ToArray( dataType );
                            mesh.SetVertexBuffer( vboIndex, new OpenGlVertexBuffer( numObjects, 0, clientState, stride, numElements, Gl.GL_STATIC_DRAW_ARB, bufferData ) );
                            break;
                        }

                    default:
                        {
                            throw new ApplicationException( string.Format( "Unhandled vertex source type \"{0}\"", curSource.Source.DataType.Name ) );
                        }
                }

                ++vboIndex;
            }

            return mesh;
        }