From 68cda2a7fbfdf3cc4ad981a7af6776563e4e5ca8 Mon Sep 17 00:00:00 2001 From: shivshank Date: Fri, 27 Jul 2018 19:30:10 -0400 Subject: [PATCH] Add a few more buffer customization methods --- src/core.rs | 26 ++++++++------ src/grayscale_fragment_shader.glsl | 11 ++++++ src/lib.rs | 58 +++++++++++++++++++++++++++++- 3 files changed, 83 insertions(+), 12 deletions(-) create mode 100644 src/grayscale_fragment_shader.glsl diff --git a/src/core.rs b/src/core.rs index 5369619..5b545ad 100644 --- a/src/core.rs +++ b/src/core.rs @@ -111,6 +111,9 @@ pub fn init_framebuffer( ); gl::BindBuffer(gl::ARRAY_BUFFER, 0); gl::BindVertexArray(0); + + // So the user doesn't have to consider alignment in their buffer + gl::PixelStorei(gl::PACK_ALIGNMENT, 1); } Framebuffer { @@ -247,21 +250,22 @@ impl Framebuffer { self.relink_program(); } - // TODO: require passing new image data - pub fn change_buffer_format(&mut self, format: BufferFormat) { + pub fn use_grayscale_shader(&mut self) { + self.use_fragment_shader(include_str!("./grayscale_fragment_shader.glsl")); + } + + pub fn change_buffer_format( + &mut self, + format: BufferFormat, + ) { self.texture_format = (format, T::to_gl_enum()); } - // TODO: resize_buffer + pub fn resize_buffer(&mut self, buffer_width: u32, buffer_height: u32) { + self.buffer_width = buffer_width as _; + self.buffer_height = buffer_height as _; + } - /// Set the size of the OpenGL viewport. - /// - /// This does not resize the window or image buffer, only the area to which OpenGL draws. You - /// only need to call this function when you are handling events manually and have a resizable - /// window. - /// - /// You will know if you need to call this function, as in that case only part of the window - /// will be getting drawn, typically after an update. pub fn resize_viewport(&mut self, width: u32, height: u32) { self.vp_width = width as _; self.vp_height = height as _; diff --git a/src/grayscale_fragment_shader.glsl b/src/grayscale_fragment_shader.glsl new file mode 100644 index 0000000..f40bb20 --- /dev/null +++ b/src/grayscale_fragment_shader.glsl @@ -0,0 +1,11 @@ +#version 330 core + +in vec2 v_uv; + +out vec4 frag_color; + +uniform sampler2D u_tex0; + +void main() { + frag_color = texture(u_tex0, v_uv).rrra; +} diff --git a/src/lib.rs b/src/lib.rs index f19acde..15384dc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,7 +17,7 @@ //! ``` //! //! The default buffer format is 32bit RGBA, so every pixel is four bytes. Buffer[0] is the top -//! left pixel. +//! left pixel. The buffer should be tightly packed with no padding after each row. //! //! # Interlude: Library philosophy //! @@ -76,6 +76,8 @@ pub use breakout::GlutinBreakout; pub use config::Config; pub use core::{Internal, BufferFormat}; +use core::ToGlType; + /// Creates a non resizable window and framebuffer with a given size in pixels. /// /// Please note that the window size is in logical device pixels, so on a high DPI monitor the @@ -162,6 +164,60 @@ impl MiniGlFb { self.internal.update_buffer(image_data); } + /// Changes the format of the image buffer. + /// + /// OpenGL will interpret any missing components as 0, except the alpha which it will assume is + /// 255. For instance, if you set the format to BufferFormat::RG, OpenGL will render every + /// pixel reading the two values you passed for the first two components, and then assume 0 + /// for the blue component, and 255 for the alpha. + /// + /// If you want to render in grayscale by providing a single component for each pixel, set + /// the buffer format to BufferFormat::R, and call `use_grayscale_shader` (which will replace + /// the fragment shader with one that sets all components equal to the red component). + /// + /// The type `T` does not affect how the texture is sampled, only how the buffer you pass is + /// interpreted. Since there is no way exposed to change the internal format of the texture, + /// (for instance if you wanted to make it an HDR image with floating point components) only + /// the types `u8` and `i8` are supported. Open an issue if you have a use case for other + /// types. + /// + /// # Example + /// + /// ```rust + /// fb.change_buffer_format::(BufferFormat::R); + /// fb.use_grayscale_shader(); + /// ``` + pub fn change_buffer_format(&mut self, format: BufferFormat) { + self.internal.fb.change_buffer_format::(format); + } + + /// Resizes the buffer. + /// + /// This does not affect the size of the window. The texture will be scaled to fit. + pub fn resize_buffer(&mut self, buffer_width: u32, buffer_height: u32) { + self.internal.fb.resize_buffer(buffer_width, buffer_height); + } + + /// Switch to a shader that only uses the first component from your buffer. + /// + /// This **does not** switch to a shader which converts RGB(A) images to grayscale, for + /// instance, by preserving percieved luminance. + pub fn use_grayscale_shader(&mut self) { + self.internal.fb.use_grayscale_shader(); + } + + /// Set the size of the OpenGL viewport (does not trigger a redraw). + /// + /// This does not resize the window or image buffer, only the area to which OpenGL draws. You + /// only need to call this function when you are handling events manually and have a resizable + /// window. + /// + /// You will know if you need to call this function, as in that case only part of the window + /// will be getting drawn, typically after an update. + pub fn resize_viewport(&mut self, width: u32, height: u32) { + self.internal.fb.resize_viewport(width, height); + } + /// Keeps the window open until the user closes it. pub fn persist(&mut self) { self.internal.persist();