feat: support textures

This commit is contained in:
thetek 2023-05-21 12:44:27 +02:00
parent 43786ef0f6
commit d9e03f1b7b
7 changed files with 98 additions and 14 deletions

View File

@ -21,7 +21,7 @@ js-sys = "0.3.61"
[dependencies.web-sys]
version = "0.3.61"
features = ["Document", "Element", "HtmlCanvasElement", "WebGlBuffer", "WebGlProgram", "WebGl2RenderingContext", "WebGlShader", "WebGlVertexArrayObject", "Window"]
features = ["Document", "Element", "HtmlCanvasElement", "HtmlImageElement", "ImageData", "WebGlBuffer", "WebGlProgram", "WebGl2RenderingContext", "WebGlUniformLocation", "WebGlShader", "WebGlTexture", "WebGlVertexArrayObject", "Window"]
[profile.release]
opt-level = "s" # optimize for small code size

View File

@ -9,10 +9,10 @@ pub fn run() -> Result<(), JsValue> {
let mut renderer = Renderer::new("canvas")?;
let vertices: Vec<f32> = vec![
-0.5, 0.5, 0.0, 1.0, 0.0, 0.0, //
-0.5, -0.5, 0.0, 1.0, 1.0, 0.0, //
0.5, -0.5, 0.0, 0.0, 1.0, 0.0, //
0.5, 0.5, 0.0, 0.0, 0.0, 1.0, //
-0.5, 0.5, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, //
-0.5, -0.5, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, //
0.5, -0.5, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, //
0.5, 0.5, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, //
];
let indices: Vec<u16> = vec![
@ -22,8 +22,10 @@ pub fn run() -> Result<(), JsValue> {
renderer.set_buffer(&vertices, &indices, true)?;
renderer.set_shader_program(VERT_SRC, FRAG_SRC)?;
renderer.map_shader_attribute("aCoord", 3, 6, 0)?;
renderer.map_shader_attribute("aColor", 3, 6, 3)?;
renderer.map_shader_attribute("aCoord", 3, 8, 0)?;
renderer.map_shader_attribute("aColor", 3, 8, 3)?;
renderer.map_shader_attribute("aTexCoord", 2, 8, 6)?;
renderer.set_texture("/texture.png")?;
renderer.draw()?;

View File

@ -1,16 +1,19 @@
use std::mem::size_of;
use std::{mem::size_of, rc::Rc};
use js_sys::{Float32Array, Uint16Array, WebAssembly::Memory};
use wasm_bindgen::{JsCast, JsValue};
use wasm_bindgen::{prelude::Closure, JsCast, JsValue};
use web_sys::{
window, HtmlCanvasElement, WebGl2RenderingContext, WebGl2RenderingContext as Gl, WebGlBuffer,
WebGlProgram, WebGlShader,
window, HtmlCanvasElement, HtmlImageElement, WebGl2RenderingContext,
WebGl2RenderingContext as Gl, WebGlBuffer, WebGlProgram, WebGlShader, WebGlTexture,
};
use crate::utils;
pub struct Renderer {
gl: WebGl2RenderingContext,
buffer: Option<Buffer>,
shader_program: Option<WebGlProgram>,
texture: Option<Rc<WebGlTexture>>,
}
pub struct Buffer {
@ -38,6 +41,7 @@ impl Renderer {
gl,
buffer: None,
shader_program: None,
texture: None,
})
}
@ -48,14 +52,25 @@ impl Renderer {
.shader_program
.as_ref()
.ok_or("no shader program is specified")?;
let texture = match &self.texture {
Some(x) => Some(unsafe { Rc::downgrade(x).as_ptr().as_ref() }.unwrap()),
None => None,
};
gl.clear_color(0.0, 0.0, 0.0, 1.0);
gl.clear(Gl::COLOR_BUFFER_BIT);
gl.use_program(Some(shader_program));
gl.bind_buffer(Gl::ARRAY_BUFFER, Some(&buffer.vertex_buffer));
gl.bind_buffer(Gl::ELEMENT_ARRAY_BUFFER, Some(&buffer.index_buffer));
gl.use_program(Some(shader_program));
gl.active_texture(Gl::TEXTURE0);
gl.bind_texture(Gl::TEXTURE_2D, texture);
let sampler_location = gl
.get_uniform_location(shader_program, "uTexture")
.ok_or("failed to get uniform location")?;
gl.uniform1i(Some(&sampler_location), 0);
gl.draw_elements_with_i32(
Gl::TRIANGLES,
@ -66,6 +81,7 @@ impl Renderer {
gl.bind_buffer(Gl::ARRAY_BUFFER, None);
gl.bind_buffer(Gl::ELEMENT_ARRAY_BUFFER, None);
gl.bind_texture(Gl::TEXTURE_2D, None);
Ok(())
}
@ -244,4 +260,65 @@ impl Renderer {
Ok(())
}
pub fn set_texture(&mut self, path: &str) -> Result<(), JsValue> {
let texture = self.load_texture(path)?;
self.texture = Some(texture);
Ok(())
}
fn load_texture(&self, path: &str) -> Result<Rc<WebGlTexture>, JsValue> {
let gl = &self.gl;
let texture = gl.create_texture().ok_or("failed to create texture")?;
gl.bind_texture(Gl::TEXTURE_2D, Some(&texture));
let pixel: [u8; 4] = [255, 255, 255, 255];
gl.tex_image_2d_with_i32_and_i32_and_i32_and_format_and_type_and_opt_u8_array(
Gl::TEXTURE_2D,
0,
Gl::RGBA as i32,
1,
1,
0,
Gl::RGBA,
Gl::UNSIGNED_BYTE,
Some(&pixel),
)?;
let img = HtmlImageElement::new().unwrap();
img.set_cross_origin(Some(""));
let imgrc = Rc::new(img);
let texture = Rc::new(texture);
{
let img = imgrc.clone();
let texture = texture.clone();
let gl = Rc::new(gl.clone());
let a = Closure::wrap(Box::new(move || {
gl.bind_texture(Gl::TEXTURE_2D, Some(&texture));
if let Err(e) = 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,
) {
utils::alert_err(e);
};
gl.generate_mipmap(Gl::TEXTURE_2D);
}) as Box<dyn FnMut()>);
imgrc.set_onload(Some(a.as_ref().unchecked_ref()));
a.forget();
}
imgrc.set_src(path);
gl.bind_texture(Gl::TEXTURE_2D, None);
Ok(texture)
}
}

View File

@ -1,7 +1,10 @@
precision mediump float;
varying vec3 vColor;
varying vec2 vTexCoord;
uniform sampler2D uTexture;
void main(void) {
gl_FragColor = vec4(vColor, 1.0);
gl_FragColor = texture2D(uTexture, vTexCoord) * vec4(vColor, 1.0);
}

View File

@ -2,10 +2,13 @@ precision mediump float;
attribute vec3 aCoord;
attribute vec3 aColor;
attribute vec2 aTexCoord;
varying vec3 vColor;
varying vec2 vTexCoord;
void main(void) {
gl_Position = vec4(aCoord, 1.0);
vColor = aColor;
vTexCoord = aTexCoord;
}

1
www/.gitignore vendored
View File

@ -1,2 +1 @@
node_modules
dist

BIN
www/dist/texture.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 B