use std::ops::Deref; pub use stdweb::Reference; use stdweb::web::*; use stdweb::unstable::TryInto; use glenum::*; use common::*; impl WebGLRenderingContext { pub fn new(canvas: &Element) -> WebGLRenderingContext { WebGLRenderingContext { common: GLContext::new(canvas, "webgl"), } } pub fn buffer_data_ptr(&self, kind: BufferKind, data_ptr: &[u8], draw: DrawMode) { js! { (@{&self.as_reference()}).bufferData(@{kind as u32},@{ data_ptr }, @{draw as u32}) }; } } impl WebGL2RenderingContext { pub fn new(canvas: &Element) -> WebGL2RenderingContext { WebGL2RenderingContext { common: GLContext::new(canvas, "webgl2"), } } } impl GLContext { pub fn log>(&self, msg: T) { // js!{ console.log(@{msg.into()})}; } pub fn new<'a>(canvas: &Element, context: &'a str) -> GLContext { let gl = js! { return (@{canvas}).getContext(@{context}); }; GLContext { reference: gl.into_reference().unwrap(), } } pub fn create_buffer(&self) -> WebGLBuffer { self.log("create_buffer"); let value = js! { return (@{self.as_reference()}).createBuffer(); }; WebGLBuffer(value.into_reference().expect("error: create_buffer")) } pub fn buffer_data(&self, kind: BufferKind, data: &[u8], draw: DrawMode) { self.log("buffer_data"); js! { (@{&self.as_reference()}).bufferData(@{kind as u32},@{ TypedArray::from(data) }, @{draw as u32}) }; } pub fn bind_buffer(&self, kind: BufferKind, buffer: &WebGLBuffer) { self.log("bind_buffer"); js! { (@{self.as_reference()}).bindBuffer(@{kind as u32},@{buffer.deref()}) }; } pub fn unbind_buffer(&self, kind: BufferKind) { self.log("unbind_buffer"); js! { (@{self.as_reference()}).bindBuffer(@{kind as u32},null) }; } pub fn create_shader(&self, kind: ShaderKind) -> WebGLShader { self.log("create_shader"); let value = js! { return (@{self.as_reference()}).createShader(@{ kind as u32 }); }; WebGLShader(value.into_reference().unwrap()) } pub fn shader_source(&self, shader: &WebGLShader, code: &str) { self.log("shader_source"); js! { (@{self.as_reference()}).shaderSource(@{shader.deref()},@{ code }) }; } pub fn compile_shader(&self, shader: &WebGLShader) { self.log("compile_shader"); js! { (@{self.as_reference()}).compileShader(@{shader.deref()}) }; js! { var compiled = (@{self.as_reference()}).getShaderParameter(@{shader.deref()}, 0x8B81); console.log("Shader compiled successfully:", compiled); var compilationLog = (@{self.as_reference()}).getShaderInfoLog(@{shader.deref()}); console.log("Shader compiler log:",compilationLog); }; } pub fn create_program(&self) -> WebGLProgram { self.log("create_program"); let value = js! { return (@{self.as_reference()}).createProgram(); }; WebGLProgram(value.into_reference().unwrap()) } pub fn link_program(&self, program: &WebGLProgram) { self.log("link_program"); js! { (@{self.as_reference()}).linkProgram(@{program.deref()}) }; } pub fn use_program(&self, program: &WebGLProgram) { self.log("use_program"); js! { (@{self.as_reference()}).useProgram(@{program.deref()}) }; } pub fn attach_shader(&self, program: &WebGLProgram, shader: &WebGLShader) { self.log("attach_shader"); js! { (@{self.as_reference()}).attachShader(@{program.deref()},@{shader.deref()}) }; } pub fn get_attrib_location(&self, program: &WebGLProgram, name: &str) -> Option { self.log("get_attrib_location"); let value = js! { return (@{self.as_reference()}).getAttribLocation(@{program.deref()},@{name}) }; value.try_into().ok() as _ } pub fn get_uniform_location( &self, program: &WebGLProgram, name: &str, ) -> Option { self.log("get_uniform_location"); let value = js! { return (@{self.as_reference()}).getUniformLocation(@{program.deref()},@{name});}; value .into_reference() .map(|reference| WebGLUniformLocation(reference)) } pub fn vertex_attrib_pointer( &self, location: u32, size: AttributeSize, kind: DataType, normalized: bool, stride: u32, offset: u32, ) { self.log("vertex_attribute_pointer"); let params = js! { return [@{location},@{size as u16},@{kind as i32},@{normalized}] }; js! { var p = @{params}; (@{self.as_reference()}).vertexAttribPointer(p[0],p[1],p[2],p[3],@{stride},@{offset}); }; } pub fn enable_vertex_attrib_array(&self, location: u32) { self.log("enabled_vertex_attrib_array"); js! { (@{self.as_reference()}).enableVertexAttribArray(@{location}) }; } pub fn clear_color(&self, r: f32, g: f32, b: f32, a: f32) { self.log("clear_color"); let params = js! { return [@{r},@{g},@{b},@{a}] }; js! { var p = @{params}; (@{self.as_reference()}).clearColor(p[0],p[1],p[2],p[3]); }; } pub fn enable(&self, flag: Flag) { self.log("enable"); js! { (@{self.as_reference()}).enable(@{flag as i32}) }; } pub fn clear(&self, bit: BufferBit) { self.log("clear"); js! { (@{self.as_reference()}).clear(@{bit as i32}) }; } pub fn viewport(&self, x: i32, y: i32, width: u32, height: u32) { self.log("viewport"); let params = js! { return [@{x},@{y},@{width},@{height}] }; js! { var p = @{params}; (@{self.as_reference()}).viewport(p[0],p[1],p[2],p[3]); }; } pub fn draw_elements(&self, mode: Primitives, count: usize, kind: DataType, offset: u32) { self.log("draw_elemnts"); let params = js! { return [@{count as u32},@{offset}] }; js! { var p = @{params}; (@{self.as_reference()}).drawElements(@{mode as i32},p[0],@{kind as i32},p[1]); }; } pub fn draw_arrays(&self, mode: Primitives, count: usize) { self.log("draw_arrays"); js! { (@{self.as_reference()}).drawArrays(@{mode as i32},0,@{count as i32}); }; } pub fn pixel_storei(&self, storage: PixelStorageMode, value: i32) { self.log("pixel_storei"); js!{ (@{self.as_reference()}).pixelStorei(@{storage as i32},@{value}); } } pub fn tex_image2d( &self, target: TextureBindPoint, level: u8, width: u16, height: u16, format: PixelFormat, kind: DataType, pixels: &[u8], ) { self.log("tex_img2d"); let params1 = js! { return [@{target as u32},@{level as u32},@{format as u32}] }; let params2 = js! { return [@{width as u32},@{height as u32},@{format as u32},@{kind as u32}] }; js!{ var p = @{params1}.concat(@{params2}); (@{self.as_reference()}).texImage2D(p[0],p[1], p[2] ,p[3],p[4],0,p[2],p[6],@{TypedArray::from(pixels)}); }; } pub fn tex_sub_image2d( &self, target: TextureBindPoint, level: u8, xoffset: u16, yoffset: u16, width: u16, height: u16, format: PixelFormat, kind: DataType, pixels: &[u8], ) { self.log("sub_tex_img2d"); let params1 = js! { return [@{target as u32},@{level as u32},@{xoffset as u32},@{yoffset as u32}] }; let params2 = js! { return [@{width as u32},@{height as u32},@{format as u32},@{kind as u32}] }; js!{ var p = @{params1}.concat(@{params2}); (@{self.as_reference()}).texSubImage2D(p[0],p[1],p[2],p[3],p[4],p[5],p[6],p[7],@{TypedArray::from(pixels)}); }; } pub fn compressed_tex_image2d( &self, target: TextureBindPoint, level: u8, compression: TextureCompression, width: u16, height: u16, data: &[u8], ) { self.log("compressed_tex_img2d"); let params = js! { return [@{target as u32},@{level as u32},@{width as u32},@{height as u32}] }; // for some reason this needs to be called otherwise invalid format error, extension initialization? let ext = js! { return ( (@{self.as_reference()}).getExtension("WEBGL_compressed_texture_s3tc") || (@{self.as_reference()}).getExtension("MOZ_WEBGL_compressed_texture_s3tc") || (@{self.as_reference()}).getExtension("WEBKIT_WEBGL_compressed_texture_s3tc") )}; js! { var p = @{params}; (@{self.as_reference()}).compressedTexImage2D( p[0], p[1], @{compression as u16}, p[2], p[3], 0, @{TypedArray::from(data)} ); } } /// pub fn create_texture(&self) -> WebGLTexture { self.log("create_tex"); let handle = js!{ return @{self.as_reference()}.createTexture() }; WebGLTexture(handle.into_reference().unwrap()) } pub fn delete_texture(&self, texture: &WebGLTexture) { self.log("delete_tex"); js!{ (@{self.as_reference()}).deleteTexture(@{&texture.0}) } } pub fn bind_texture(&self, texture: &WebGLTexture) { self.log("bind_tex"); js!{ (@{self.as_reference()}).bindTexture(@{TextureBindPoint::Texture2d as u32 }, @{&texture.0}) } } pub fn unbind_texture(&self) { self.log("unbind_tex"); js!{ (@{self.as_reference()}).bindTexture(@{TextureBindPoint::Texture2d as u32 },null) } } pub fn blend_func(&self, b1: BlendMode, b2: BlendMode) { self.log("blend_func"); js!{ (@{self.as_reference()}).blendFunc(@{b1 as u32},@{b2 as u32}) } } pub fn uniform_matrix_4fv(&self, location: WebGLUniformLocation, value: &[[f32; 4]; 4]) { self.log("uniform_matrix_4fv"); use std::mem; let array = unsafe { mem::transmute::<&[[f32; 4]; 4], &[f32; 16]>(value) as &[f32] }; js!{ (@{self.as_reference()}).uniformMatrix4fv(@{location.deref()},false,@{&array}) } } pub fn uniform_matrix_3fv(&self, location: WebGLUniformLocation, value: &[[f32; 3]; 3]) { self.log("uniform_matrix_3fv"); use std::mem; let array = unsafe { mem::transmute::<&[[f32; 3]; 3], &[f32; 9]>(value) as &[f32] }; js!{ (@{self.as_reference()}).uniformMatrix3fv(@{location.deref()},false,@{&array}) } } pub fn uniform_matrix_2fv(&self, location: WebGLUniformLocation, value: &[[f32; 2]; 2]) { use std::mem; let array = unsafe { mem::transmute::<&[[f32; 2]; 2], &[f32; 4]>(value) as &[f32] }; js!{ (@{self.as_reference()}).uniformMatrix2fv(@{location.deref()},false,@{&array}) } } pub fn uniform_1i(&self, location: WebGLUniformLocation, value: i32) { js!{ (@{self.as_reference()}).uniform1i(@{location.deref()},@{value}) } } pub fn uniform_1f(&self, location: WebGLUniformLocation, value: f32) { js!{ (@{self.as_reference()}).uniform1f(@{location.deref()},@{value}) } } pub fn uniform_4f(&self, location: WebGLUniformLocation, value: (f32, f32, f32, f32)) { js!{ var p = [@{value.0},@{value.1},@{value.2},@{value.3}]; } js!{ (@{self.as_reference()}).uniform4f(@{location.deref()},p[0],p[1],p[2],p[3]) } } pub fn create_vertex_array(&self) -> WebGLVertexArray { self.log("create_vertex_array"); let val = js! { return (@{&self.as_reference()}).createVertexArray() }; WebGLVertexArray(val.into_reference().unwrap()) } pub fn bind_vertex_array(&self, vao: WebGLVertexArray) { self.log("bind_vertex_array"); js! { (@{&self.as_reference()}).bindVertexArray(@{vao.deref()}) } } pub fn unbind_vertex_array(&self) { self.log("unbind_vertex_array"); js! { (@{&self.as_reference()}).bindVertexArray(0) } } pub fn get_program_parameter(&self, program: &WebGLProgram, pname: ShaderParameter) -> i32 { let res = js! { return (@{&self.as_reference()}).getProgramParameter(@{program.deref()},@{pname as u32}); }; res.try_into().unwrap() } pub fn get_active_uniform(&self, program: &WebGLProgram, location: u32) -> WebGLActiveInfo { let res = js! { return @{self.as_reference()}.getActiveUniform(@{program.deref()},@{location}) }; let name = js! { return @{&res}.name }; let size = js!{ return @{&res}.size }; let kind = js!{ return @{&res}.type }; let k: u32 = kind.try_into().unwrap(); use std::mem; WebGLActiveInfo::new( name.into_string().unwrap(), size.try_into().unwrap(), unsafe { mem::transmute::(k as _) }, res.into_reference().unwrap(), ) } pub fn get_active_attrib(&self, program: &WebGLProgram, location: u32) -> WebGLActiveInfo { let res = js! { return @{self.as_reference()}.getActiveAttrib(@{program.deref()},@{location}) }; let name = js! { return @{&res}.name }; let size = js!{ return @{&res}.size }; let kind = js!{ return @{&res}.type }; let k: u32 = kind.try_into().unwrap(); use std::mem; WebGLActiveInfo::new( name.into_string().unwrap(), size.try_into().unwrap(), unsafe { mem::transmute::(k as _) }, res.into_reference().unwrap(), ) } pub fn tex_parameteri(&self, pname: TextureParameter, param: i32) { js! { return @{self.as_reference()}.texParameteri(@{TextureBindPoint::Texture2d as u32},@{pname as u32},@{param}) }; } pub fn tex_parameterfv(&self, pname: TextureParameter, param: f32) { js! { return @{self.as_reference()}.texParameterf(@{TextureBindPoint::Texture2d as u32},@{pname as u32},@{param}) }; } }