jQuery.glCheckError = function( gl, error_log ) { var error = gl.getError(); if (error != gl.NO_ERROR) { var error_str = "GL Error: " + error + " " + gl.enum_strings[error]; if ( typeof error_log === 'function' ) { error_log( error_str ); } throw error_str; } } // jQuery.glProgram = function( gl, config, complete ) // // Example config: // // var g_BumpReflectProgram = // { // VertexProgramURL: '/shaders/bump_reflect.vs', // FragmentProgramURL: '/shaders/bump_reflect.fs', // ErrorLog: error_log, // }; jQuery.glProgram = function( gl, config, complete ) { this.Program = null; this.UniformLocations = { }; this.AttributeIndices = []; this.Uniforms = []; this.UniformTypes = { }; this.Attributes = []; this.AttributeTypes = { }; this.ErrorLog = config.error_log; this.BoundTextureCount = 0; this.Use = function() { gl.useProgram( this.Program ); this.BoundTextureCount = 0; } this.BindModel = function( model, bindings ) { var attribute_ndx = this.AttributeIndices; gl.bindBuffer(gl.ARRAY_BUFFER, model.VertexBuffer ); for ( var model_stream_name in bindings ) { var program_stream_name = bindings[ model_stream_name ]; var program_attribute = this.AttributeIndices[ program_stream_name ]; var model_stream_offset = model.VertexStreamBufferOffsets[ model_stream_name ]; var model_stream_stride = model.VertexStreamBufferStrides[ model_stream_name ]; var model_stream_type = model.VertexStreamBufferGLTypes[ model_stream_name ]; gl.vertexAttribPointer( program_attribute, model_stream_stride, model_stream_type, false, 0, model_stream_offset ); gl.enableVertexAttribArray( program_attribute ); } gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, model.IndexBuffer ); $.glCheckError( gl, this.ErrorLog ); this.Model = model; } this.BindUniform = function( uniform_name, value ) { var uniform_type = this.UniformTypes[ uniform_name ]; switch (uniform_type) { case 'mat4': { gl.uniformMatrix4fv( this.UniformLocations[ uniform_name ], gl.FALSE, new Float32Array( value ) ); } break; case 'sampler2D': { gl.activeTexture( gl[ 'TEXTURE' + this.BoundTextureCount ] ); if ( value instanceof jQuery.glTexture ) { gl.bindTexture( gl.TEXTURE_2D, value.Texture ); } else { gl.bindTexture( gl.TEXTURE_2D, value ); } gl.uniform1i( this.UniformLocations[ uniform_name ], this.BoundTextureCount ); this.BoundTextureCount++; } break; case 'samplerCube': { gl.activeTexture( gl[ 'TEXTURE' + this.BoundTextureCount ] ); gl.bindTexture( gl.TEXTURE_CUBE_MAP, value ); gl.uniform1i( this.UniformLocations[ uniform_name ], this.BoundTextureCount ); this.BoundTextureCount++; } break; } } this.DrawModel = function() { var model = this.Model; // Model must be bound with BindModel first. gl.drawElements( gl.TRIANGLES, model.IndexCount, model.IndexStreamGLType, 0 ); } this.CreateBestVertexBindings = function( model ) { var bindings = new Object(); for (var i=0;i