diff --git a/examples/hello.rs b/examples/hello.rs index d75f269..45d2446 100644 --- a/examples/hello.rs +++ b/examples/hello.rs @@ -35,7 +35,13 @@ fn main() -> Result<(), String> { context.window().request_redraw(); unsafe { + // Enable auto-conversion from/to sRGB gl.enable(glow::FRAMEBUFFER_SRGB); + + // Enable alpha blending + gl.enable(glow::BLEND); + gl.blend_func(glow::SRC_ALPHA, glow::ONE_MINUS_SRC_ALPHA); + gl.clear_color(0.4, 0.4, 0.4, 1.0); } @@ -51,13 +57,22 @@ fn main() -> Result<(), String> { } => { context.resize(new_size); + unsafe { + gl.viewport( + 0, + 0, + new_size.width as _, + new_size.height as _, + ); + } + size = new_size; } glutin::event::Event::RedrawRequested { .. } => { unsafe { gl.clear(glow::COLOR_BUFFER_BIT) } glyph_brush.queue(Section { - text: "Hello wgpu_glyph!", + text: "Hello glow_glyph!", screen_position: (30.0, 30.0), color: [0.0, 0.0, 0.0, 1.0], scale: Scale { x: 40.0, y: 40.0 }, @@ -66,7 +81,7 @@ fn main() -> Result<(), String> { }); glyph_brush.queue(Section { - text: "Hello wgpu_glyph!", + text: "Hello glow_glyph!", screen_position: (30.0, 90.0), color: [1.0, 1.0, 1.0, 1.0], scale: Scale { x: 40.0, y: 40.0 }, diff --git a/src/pipeline.rs b/src/pipeline.rs index fa572de..c5b9b38 100644 --- a/src/pipeline.rs +++ b/src/pipeline.rs @@ -9,6 +9,7 @@ use glyph_brush::rusttype::{point, Rect}; pub struct Pipeline { sampler: ::Sampler, program: ::Program, + vertex_array: ::VertexArray, instances: ::Buffer, cache: Cache, current_instances: usize, @@ -25,7 +26,7 @@ impl Pipeline { let sampler = unsafe { gl.create_sampler().expect("Create glyph sampler") }; - let cache = Cache::new(gl, cache_width, cache_height); + let cache = unsafe { Cache::new(gl, cache_width, cache_height) }; let program = unsafe { create_program( @@ -40,17 +41,18 @@ impl Pipeline { ) }; - let instances = - unsafe { gl.create_buffer().expect("Create instance buffer") }; + let (vertex_array, instances) = + unsafe { create_instance_buffer(gl, Instance::INITIAL_AMOUNT) }; Pipeline { sampler, program, cache, + vertex_array, instances, current_instances: 0, supported_instances: Instance::INITIAL_AMOUNT, - current_transform: [0.0; 16], + current_transform: IDENTITY_MATRIX, } } @@ -60,6 +62,36 @@ impl Pipeline { transform: [f32; 16], region: Option, ) { + unsafe { + gl.use_program(Some(self.program)); + } + + if self.current_transform != transform { + unsafe { + gl.uniform_matrix_4_f32_slice(Some(0), false, &transform); + } + + self.current_transform = transform; + } + + unsafe { + gl.active_texture(glow::TEXTURE0); + gl.bind_texture(glow::TEXTURE_2D, Some(self.cache.texture)); + gl.uniform_1_i32(Some(1), 0); + + gl.bind_vertex_array(Some(self.vertex_array)); + + gl.draw_arrays_instanced( + glow::TRIANGLE_STRIP, + 0, + 4, + self.current_instances as i32, + ); + + gl.bind_vertex_array(None); + gl.bind_texture(glow::TEXTURE_2D, None); + gl.use_program(None); + } } pub fn update_cache( @@ -69,7 +101,9 @@ impl Pipeline { size: [u16; 2], data: &[u8], ) { - self.cache.update(gl, offset, size, data); + unsafe { + self.cache.update(gl, offset, size, data); + } } pub fn increase_cache_size( @@ -78,7 +112,11 @@ impl Pipeline { width: u32, height: u32, ) { - self.cache = Cache::new(gl, width, height); + unsafe { + self.cache.destroy(gl); + + self.cache = Cache::new(gl, width, height); + } } pub fn upload(&mut self, gl: &glow::Context, instances: &[Instance]) { @@ -88,12 +126,28 @@ impl Pipeline { } if instances.len() > self.supported_instances { - // TODO + unsafe { + gl.delete_buffer(self.instances); + gl.delete_vertex_array(self.vertex_array); + } + let (new_vertex_array, new_instances) = + unsafe { create_instance_buffer(gl, instances.len()) }; + + self.vertex_array = new_vertex_array; + self.instances = new_instances; self.supported_instances = instances.len(); } - // TODO + unsafe { + gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.instances)); + gl.buffer_sub_data_u8_slice( + glow::ARRAY_BUFFER, + 0, + bytemuck::cast_slice(instances), + ); + gl.bind_buffer(glow::ARRAY_BUFFER, None); + } self.current_instances = instances.len(); } @@ -219,3 +273,63 @@ unsafe fn create_program( program } + +unsafe fn create_instance_buffer( + gl: &glow::Context, + size: usize, +) -> ( + ::VertexArray, + ::Buffer, +) { + let vertex_array = gl.create_vertex_array().expect("Create vertex array"); + let buffer = gl.create_buffer().expect("Create instance buffer"); + + gl.bind_vertex_array(Some(vertex_array)); + gl.bind_buffer(glow::ARRAY_BUFFER, Some(buffer)); + gl.buffer_data_size( + glow::ARRAY_BUFFER, + (size * std::mem::size_of::()) as i32, + glow::DYNAMIC_DRAW, + ); + + let stride = std::mem::size_of::() as i32; + + gl.enable_vertex_attrib_array(0); + gl.vertex_attrib_pointer_f32(0, 3, glow::FLOAT, false, stride, 0); + gl.vertex_attrib_divisor(0, 1); + + gl.enable_vertex_attrib_array(1); + gl.vertex_attrib_pointer_f32(1, 2, glow::FLOAT, false, stride, 4 * 3); + gl.vertex_attrib_divisor(1, 1); + + gl.enable_vertex_attrib_array(2); + gl.vertex_attrib_pointer_f32(2, 2, glow::FLOAT, false, stride, 4 * (3 + 2)); + gl.vertex_attrib_divisor(2, 1); + + gl.enable_vertex_attrib_array(3); + gl.vertex_attrib_pointer_f32( + 3, + 2, + glow::FLOAT, + false, + stride, + 4 * (3 + 2 + 2), + ); + gl.vertex_attrib_divisor(3, 1); + + gl.enable_vertex_attrib_array(4); + gl.vertex_attrib_pointer_f32( + 4, + 4, + glow::FLOAT, + false, + stride, + 4 * (3 + 2 + 2 + 2), + ); + gl.vertex_attrib_divisor(4, 1); + + gl.bind_vertex_array(None); + gl.bind_buffer(glow::ARRAY_BUFFER, None); + + (vertex_array, buffer) +} diff --git a/src/pipeline/cache.rs b/src/pipeline/cache.rs index b80ccc2..fd5ba5c 100644 --- a/src/pipeline/cache.rs +++ b/src/pipeline/cache.rs @@ -1,15 +1,55 @@ use glow::HasContext; pub struct Cache { - texture: ::Texture, + pub(crate) texture: ::Texture, } impl Cache { - pub fn new(gl: &glow::Context, width: u32, height: u32) -> Cache { - let texture = unsafe { - let handle = gl.create_texture().expect("Create glyph cache texture"); + pub unsafe fn new(gl: &glow::Context, width: u32, height: u32) -> Cache { + gl.pixel_store_i32(glow::UNPACK_ALIGNMENT, 1); - gl.tex_storage_2d(handle, 1, glow::R8, width as i32, height as i32); + let texture = { + let handle = + gl.create_texture().expect("Create glyph cache texture"); + + gl.bind_texture(glow::TEXTURE_2D, Some(handle)); + + #[cfg(debug_assertions)] + gl.object_label(glow::TEXTURE, handle, Some("Glyph cache")); + + gl.tex_parameter_i32( + glow::TEXTURE_2D, + glow::TEXTURE_WRAP_S, + glow::CLAMP_TO_EDGE as i32, + ); + gl.tex_parameter_i32( + glow::TEXTURE_2D, + glow::TEXTURE_WRAP_T, + glow::CLAMP_TO_EDGE as i32, + ); + gl.tex_parameter_i32( + glow::TEXTURE_2D, + glow::TEXTURE_MIN_FILTER, + glow::LINEAR as i32, + ); + gl.tex_parameter_i32( + glow::TEXTURE_2D, + glow::TEXTURE_MAG_FILTER, + glow::LINEAR as i32, + ); + + gl.tex_image_2d( + glow::TEXTURE_2D, + 0, + glow::R8 as i32, + width as i32, + height as i32, + 0, + glow::RED, + glow::UNSIGNED_BYTE, + None, + ); + gl.bind_texture(glow::TEXTURE_2D, None); handle }; @@ -17,7 +57,34 @@ impl Cache { Cache { texture } } - pub fn update(&self, gl: &glow::Context, offset: [u16; 2], size: [u16; 2], data: &[u8]) { - // TODO + pub unsafe fn update( + &self, + gl: &glow::Context, + offset: [u16; 2], + size: [u16; 2], + data: &[u8], + ) { + let [offset_x, offset_y] = offset; + let [width, height] = size; + + gl.bind_texture(glow::TEXTURE_2D, Some(self.texture)); + + gl.tex_sub_image_2d_u8_slice( + glow::TEXTURE_2D, + 0, + i32::from(offset_x), + i32::from(offset_y), + i32::from(width), + i32::from(height), + glow::RED, + glow::UNSIGNED_BYTE, + Some(data), + ); + + gl.bind_texture(glow::TEXTURE_2D, None); + } + + pub unsafe fn destroy(&self, gl: &glow::Context) { + gl.delete_texture(self.texture); } } diff --git a/src/shader/vertex.vert b/src/shader/vertex.vert index 18fc01c..ddfb139 100644 --- a/src/shader/vertex.vert +++ b/src/shader/vertex.vert @@ -2,11 +2,11 @@ layout(location = 0) uniform mat4 transform; -in vec3 left_top; -in vec2 right_bottom; -in vec2 tex_left_top; -in vec2 tex_right_bottom; -in vec4 color; +layout(location = 0) in vec3 left_top; +layout(location = 1) in vec2 right_bottom; +layout(location = 2) in vec2 tex_left_top; +layout(location = 3) in vec2 tex_right_bottom; +layout(location = 4) in vec4 color; out vec2 f_tex_pos; out vec4 f_color;