use crate::*;
type GL = web_sys::WebGl2RenderingContext;
pub fn upload
(
gl : &GL,
texture : Option< &web_sys::WebGlTexture >,
img : &web_sys::HtmlImageElement
)
{
gl.bind_texture( GL::TEXTURE_2D, texture );
gl.pixel_storei( GL::UNPACK_FLIP_Y_WEBGL, 1 );
gl.tex_image_2d_with_u32_and_u32_and_html_image_element
(
GL::TEXTURE_2D,
0,
GL::RGBA as i32,
GL::RGBA,
GL::UNSIGNED_BYTE,
&img
).expect( "Failed to upload data to texture" );
gl.pixel_storei( GL::UNPACK_FLIP_Y_WEBGL, 0 );
}
pub struct SpriteSheet
{
pub sprites_in_row : u32,
pub sprite_width : u32,
pub sprite_height : u32,
pub amount : u32,
}
pub fn create_and_upload( gl : &GL, img : &web_sys::HtmlImageElement ) -> Option< web_sys::WebGlTexture >
{
let texture = gl.create_texture();
if texture.is_none() { return None; }
gl.bind_texture( GL::TEXTURE_2D, texture.as_ref() );
gl.pixel_storei( GL::UNPACK_FLIP_Y_WEBGL, 1 );
gl.tex_image_2d_with_u32_and_u32_and_html_image_element
(
GL::TEXTURE_2D,
0,
GL::RGBA as i32,
GL::RGBA,
GL::UNSIGNED_BYTE,
&img
).expect( "Failed to upload data to texture" );
gl.pixel_storei( GL::UNPACK_FLIP_Y_WEBGL, 0 );
texture
}
pub fn upload_no_flip
(
gl : &GL,
texture : Option< &web_sys::WebGlTexture >,
img : &web_sys::HtmlImageElement
)
{
gl.bind_texture( GL::TEXTURE_2D, texture );
gl.pixel_storei( GL::UNPACK_FLIP_Y_WEBGL, 0 );
gl.tex_image_2d_with_u32_and_u32_and_html_image_element
(
GL::TEXTURE_2D,
0,
GL::RGBA as i32,
GL::RGBA,
GL::UNSIGNED_BYTE,
&img
).expect( "Failed to upload data to texture" );
}
pub fn create_and_upload_no_flip( gl : &GL, img : &web_sys::HtmlImageElement ) -> Option< web_sys::WebGlTexture >
{
let texture = gl.create_texture();
gl.bind_texture( GL::TEXTURE_2D, texture.as_ref() );
gl.pixel_storei( GL::UNPACK_FLIP_Y_WEBGL, 0 );
gl.tex_image_2d_with_u32_and_u32_and_html_image_element
(
GL::TEXTURE_2D,
0,
GL::RGBA as i32,
GL::RGBA,
GL::UNSIGNED_BYTE,
&img
).expect( "Failed to upload data to texture" );
texture
}
pub fn update_video( gl : &GL, texture : &web_sys::WebGlTexture, video_element : &web_sys::HtmlVideoElement )
{
gl.bind_texture( GL::TEXTURE_2D, Some( texture ) );
gl.tex_image_2d_with_i32_and_i32_and_i32_and_format_and_type_and_html_video_element
(
GL::TEXTURE_2D,
0,
GL::RGBA as i32,
video_element.width() as i32,
video_element.height() as i32,
0,
GL::RGBA,
GL::UNSIGNED_BYTE,
&video_element
).expect( "Failed to upload data to texture" );
}
pub async fn upload_sprite( gl : &GL, image_element : &web_sys::HtmlImageElement, sprite_sheet : &SpriteSheet ) -> Result< web_sys::WebGlTexture, WebglError >
{
let load_promise = js_sys::Promise::new
(
&mut | resolve, reject |
{
let on_load = wasm_bindgen::prelude::Closure::once_into_js
(
move || { resolve.call0( &JsValue::NULL ).unwrap() }
);
let on_error = wasm_bindgen::prelude::Closure::once_into_js
(
move || { reject.call1( &JsValue::NULL, &JsValue::from_str( "Failed to load image" ) ).unwrap() }
);
image_element.set_onload( Some( on_load.as_ref().unchecked_ref() ) );
image_element.set_onerror( Some( on_error.as_ref().unchecked_ref() ) );
}
);
JsFuture::from( load_promise ).await.unwrap();
let texture = gl.create_texture().ok_or( WebglError::FailedToAllocateResource( "Sprite texture" ) )?;
gl.bind_texture( GL::TEXTURE_2D_ARRAY, Some( &texture ) );
let ( img_width, img_height ) = ( image_element.width(), image_element.height() );
let image_data =
{
let tmp_canvas = canvas::make()?;
tmp_canvas.style().remove_property( "width" ).unwrap();
tmp_canvas.style().remove_property( "height" ).unwrap();
tmp_canvas.set_width( img_width );
tmp_canvas.set_height( img_height );
let ctx = context::from_canvas_2d( &tmp_canvas )?;
ctx.draw_image_with_html_image_element( image_element, 0.0, 0.0 ).unwrap();
let data = ctx.get_image_data( 0.0, 0.0, img_width as f64, img_height as f64 ).unwrap().data().to_vec();
tmp_canvas.remove();
data
};
gl.tex_storage_3d
(
GL::TEXTURE_2D_ARRAY,
8,
GL::RGBA8,
sprite_sheet.sprite_width as i32,
sprite_sheet.sprite_height as i32,
sprite_sheet.amount as i32
);
let pbo = buffer::create( &gl )?;
gl.bind_buffer( GL::PIXEL_UNPACK_BUFFER, Some( &pbo ) );
gl.buffer_data_with_js_u8_array
(
GL::PIXEL_UNPACK_BUFFER,
&js_sys::Uint8Array::from( image_data.as_bytes() ),
GL::STATIC_DRAW
);
gl.pixel_storei( GL::UNPACK_ROW_LENGTH, img_width as i32 );
gl.pixel_storei( GL::UNPACK_IMAGE_HEIGHT, img_height as i32 );
for i in 0..sprite_sheet.amount
{
let col = i % sprite_sheet.sprites_in_row * sprite_sheet.sprite_width;
let row = i / sprite_sheet.sprites_in_row * sprite_sheet.sprite_height;
gl.pixel_storei( GL::UNPACK_SKIP_PIXELS, col as i32 );
gl.pixel_storei( GL::UNPACK_SKIP_ROWS, row as i32 );
gl.tex_sub_image_3d_with_i32(
GL::TEXTURE_2D_ARRAY,
0,
0,
0,
i as i32,
sprite_sheet.sprite_width as i32,
sprite_sheet.sprite_height as i32,
1,
GL::RGBA,
GL::UNSIGNED_BYTE,
0
).unwrap();
}
gl.tex_parameteri( GL::TEXTURE_2D_ARRAY, GL::TEXTURE_MIN_FILTER, GL::NEAREST as i32 );
gl.tex_parameteri( GL::TEXTURE_2D_ARRAY, GL::TEXTURE_MAG_FILTER, GL::NEAREST as i32 );
gl.generate_mipmap( GL::TEXTURE_2D_ARRAY );
gl.tex_parameteri( GL::TEXTURE_2D_ARRAY, GL::TEXTURE_BASE_LEVEL, 0 );
Ok( texture )
}
pub fn default_parameters( gl : &GL )
{
filter_linear( gl );
wrap_repeat( gl );
}
pub fn filter_linear( gl : &GL )
{
gl.tex_parameteri( GL::TEXTURE_2D, GL::TEXTURE_MIN_FILTER, GL::LINEAR as i32 );
gl.tex_parameteri( GL::TEXTURE_2D, GL::TEXTURE_MAG_FILTER, GL::LINEAR as i32 );
}
pub fn filter_nearest( gl : &GL )
{
gl.tex_parameteri( GL::TEXTURE_2D, GL::TEXTURE_MIN_FILTER, GL::NEAREST as i32 );
gl.tex_parameteri( GL::TEXTURE_2D, GL::TEXTURE_MAG_FILTER, GL::NEAREST as i32 );
}
pub fn wrap_repeat( gl : &GL )
{
gl.tex_parameteri( GL::TEXTURE_2D, GL::TEXTURE_WRAP_S, GL::REPEAT as i32 );
gl.tex_parameteri( GL::TEXTURE_2D, GL::TEXTURE_WRAP_T, GL::REPEAT as i32 );
gl.tex_parameteri( GL::TEXTURE_2D, GL::TEXTURE_WRAP_R, GL::REPEAT as i32 );
}
pub fn wrap_clamp( gl : &GL )
{
gl.tex_parameteri( GL::TEXTURE_2D, GL::TEXTURE_WRAP_S, GL::CLAMP_TO_EDGE as i32 );
gl.tex_parameteri( GL::TEXTURE_2D, GL::TEXTURE_WRAP_T, GL::CLAMP_TO_EDGE as i32 );
gl.tex_parameteri( GL::TEXTURE_2D, GL::TEXTURE_WRAP_R, GL::CLAMP_TO_EDGE as i32 );
}