From 8bd17d71d202ac7fb1cc51120af6b3cdfc643b9f Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Sat, 10 Jul 2021 23:50:01 +0200 Subject: [PATCH] renderer: Support cropping and scaling --- anvil/src/drawing.rs | 6 +-- anvil/src/udev.rs | 3 +- src/backend/renderer/gles2/mod.rs | 30 +++++------ src/backend/renderer/mod.rs | 85 ++++++++++++++++++++++--------- 4 files changed, 79 insertions(+), 45 deletions(-) diff --git a/anvil/src/drawing.rs b/anvil/src/drawing.rs index 913c3c6..821aca7 100644 --- a/anvil/src/drawing.rs +++ b/anvil/src/drawing.rs @@ -155,7 +155,7 @@ where let mut location = *location; if let Some(ref data) = states.data_map.get::>() { let mut data = data.borrow_mut(); - let buffer_scale = data.buffer_scale as f32; + let buffer_scale = data.buffer_scale; if let Some(texture) = data .texture .as_mut() @@ -167,12 +167,12 @@ where let current = states.cached_state.current::(); location += current.location; } - let render_scale = output_scale as f32 / buffer_scale; if let Err(err) = frame.render_texture_at( &texture.texture, location.to_f64().to_physical(output_scale as f64).to_i32_round(), + buffer_scale, + output_scale as f64, Transform::Normal, /* TODO */ - render_scale, 1.0, ) { result = Err(err.into()); diff --git a/anvil/src/udev.rs b/anvil/src/udev.rs index ac835d9..ead4f40 100644 --- a/anvil/src/udev.rs +++ b/anvil/src/udev.rs @@ -755,8 +755,9 @@ fn render_surface( .to_f64() .to_physical(output_scale as f64) .to_i32_round(), + 1, + output_scale as f64, Transform::Normal, - output_scale, 1.0, )?; } diff --git a/src/backend/renderer/gles2/mod.rs b/src/backend/renderer/gles2/mod.rs index 9583055..510e9b1 100644 --- a/src/backend/renderer/gles2/mod.rs +++ b/src/backend/renderer/gles2/mod.rs @@ -11,7 +11,7 @@ use std::sync::{ }; use std::{collections::HashSet, os::raw::c_char}; -use cgmath::{prelude::*, Matrix3}; +use cgmath::{prelude::*, Matrix3, Vector2}; mod shaders; mod version; @@ -76,7 +76,9 @@ impl Gles2Texture { /// /// Ownership over the texture is taken by the renderer, you should not free the texture yourself. /// - /// *Safety*: The renderer cannot make sure `tex` is a valid texture id. + /// # Safety + /// + /// The renderer cannot make sure `tex` is a valid texture id. pub unsafe fn from_raw( renderer: &Gles2Renderer, tex: ffi::types::GLuint, @@ -979,20 +981,6 @@ impl Drop for Gles2Renderer { } } -static VERTS: [ffi::types::GLfloat; 8] = [ - 1.0, 0.0, // top right - 0.0, 0.0, // top left - 1.0, 1.0, // bottom right - 0.0, 1.0, // bottom left -]; - -static TEX_COORDS: [ffi::types::GLfloat; 8] = [ - 1.0, 0.0, // top right - 0.0, 0.0, // top left - 1.0, 1.0, // bottom right - 0.0, 1.0, // bottom left -]; - impl Gles2Renderer { /// Run custom code in the GL context owned by this renderer. /// @@ -1085,6 +1073,13 @@ impl Renderer for Gles2Renderer { } } +static VERTS: [ffi::types::GLfloat; 8] = [ + 1.0, 0.0, // top right + 0.0, 0.0, // top left + 1.0, 1.0, // bottom right + 0.0, 1.0, // bottom left +]; + impl Frame for Gles2Frame { type Error = Gles2Error; type TextureId = Gles2Texture; @@ -1102,6 +1097,7 @@ impl Frame for Gles2Frame { &mut self, tex: &Self::TextureId, mut matrix: Matrix3, + tex_coords: [Vector2; 4], alpha: f32, ) -> Result<(), Self::Error> { //apply output transformation @@ -1150,7 +1146,7 @@ impl Frame for Gles2Frame { ffi::FLOAT, ffi::FALSE, 0, - TEX_COORDS.as_ptr() as *const _, + tex_coords.as_ptr() as *const _, // cgmath::Vector2 is marked as repr(C), this cast should be safe ); self.gl diff --git a/src/backend/renderer/mod.rs b/src/backend/renderer/mod.rs index 7947920..dffc150 100644 --- a/src/backend/renderer/mod.rs +++ b/src/backend/renderer/mod.rs @@ -10,16 +10,18 @@ use std::collections::HashSet; use std::error::Error; -use crate::utils::{Physical, Point, Size}; +use crate::utils::{Buffer, Physical, Point, Rectangle, Size}; #[cfg(feature = "wayland_frontend")] -use crate::{utils::Rectangle, wayland::compositor::SurfaceData}; -use cgmath::{prelude::*, Matrix3, Vector2}; +use crate::wayland::compositor::SurfaceData; +use cgmath::{prelude::*, Matrix3, Vector2, Vector3}; #[cfg(feature = "wayland_frontend")] use wayland_server::protocol::{wl_buffer, wl_shm}; #[cfg(feature = "renderer_gl")] pub mod gles2; +#[cfg(feature = "wayland_frontend")] +use crate::backend::allocator::{dmabuf::Dmabuf, Format}; #[cfg(all( feature = "wayland_frontend", feature = "backend_egl", @@ -29,11 +31,6 @@ use crate::backend::egl::{ display::{EGLBufferReader, BUFFER_READER}, Error as EglError, }; -#[cfg(feature = "wayland_frontend")] -use crate::{ - backend::allocator::{dmabuf::Dmabuf, Format}, - utils::Buffer, -}; #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] /// Possible transformations to two-dimensional planes @@ -142,9 +139,9 @@ pub trait Unbind: Renderer { /// A two dimensional texture pub trait Texture { - /// Size of the texture plane (w x h) - fn size(&self) -> (u32, u32) { - (self.width(), self.height()) + /// Size of the texture plane + fn size(&self) -> Size { + Size::from((self.width() as i32, self.height() as i32)) } /// Width of the texture plane @@ -166,34 +163,57 @@ pub trait Frame { /// If called outside this operation may error-out, do nothing or modify future rendering results in any way. fn clear(&mut self, color: [f32; 4]) -> Result<(), Self::Error>; /// Render a texture to the current target using given projection matrix and alpha. - /// - /// This operation is only valid in between a `begin` and `finish`-call. - /// If called outside this operation may error-out, do nothing or modify future rendering results in any way. + /// The given verticies are used to source the texture. This is mostly useful for cropping the texture. fn render_texture( &mut self, texture: &Self::TextureId, matrix: Matrix3, + tex_coords: [Vector2; 4], alpha: f32, ) -> Result<(), Self::Error>; + /// Render a texture to the current target as a flat 2d-plane at a given - /// position, applying the given transformation with the given alpha value. - /// - /// This operation is only valid in between a `begin` and `finish`-call. - /// If called outside this operation may error-out, do nothing or modify future rendering results in any way. + /// position and applying the given transformation with the given alpha value. fn render_texture_at( &mut self, texture: &Self::TextureId, - pos: Point, + pos: Point, + texture_scale: i32, + output_scale: f64, + transform: Transform, + alpha: f32, + ) -> Result<(), Self::Error> { + self.render_texture_from_to( + texture, + Rectangle::from_loc_and_size(Point::::from((0, 0)), texture.size()), + Rectangle::from_loc_and_size( + pos, + texture + .size() + .to_logical(texture_scale) + .to_f64() + .to_physical(output_scale), + ), + transform, + alpha, + ) + } + + /// Render part of a texture as given by src to the current target into the rectangle described by dest + /// as a flat 2d-plane after applying the given transformations. + fn render_texture_from_to( + &mut self, + texture: &Self::TextureId, + src: Rectangle, + dest: Rectangle, transform: Transform, - scale: f32, alpha: f32, ) -> Result<(), Self::Error> { let mut mat = Matrix3::::identity(); // position and scale - let size = texture.size(); - mat = mat * Matrix3::from_translation(Vector2::new(pos.x as f32, pos.y as f32)); - mat = mat * Matrix3::from_nonuniform_scale(size.0 as f32 * scale, size.1 as f32 * scale); + mat = mat * Matrix3::from_translation(Vector2::new(dest.loc.x as f32, dest.loc.y as f32)); + mat = mat * Matrix3::from_nonuniform_scale(dest.size.w as f32, dest.size.h as f32); //apply surface transformation mat = mat * Matrix3::from_translation(Vector2::new(0.5, 0.5)); @@ -204,7 +224,24 @@ pub trait Frame { mat = mat * transform.invert().matrix(); mat = mat * Matrix3::from_translation(Vector2::new(-0.5, -0.5)); - self.render_texture(texture, mat, alpha) + // this matrix should be regular, we can expect invert to succeed + let tex_size = texture.size(); + let texture_mat = Matrix3::from_nonuniform_scale(tex_size.w as f32, tex_size.h as f32) + .invert() + .unwrap(); + let verts = [ + (texture_mat * Vector3::new((src.loc.x + src.size.w) as f32, src.loc.y as f32, 0.0)).truncate(), // top-right + (texture_mat * Vector3::new(src.loc.x as f32, src.loc.y as f32, 0.0)).truncate(), // top-left + (texture_mat + * Vector3::new( + (src.loc.x + src.size.w) as f32, + (src.loc.y + src.size.h) as f32, + 0.0, + )) + .truncate(), // bottom-right + (texture_mat * Vector3::new(src.loc.x as f32, (src.loc.y + src.size.h) as f32, 0.0)).truncate(), // bottom-left + ]; + self.render_texture(texture, mat, verts, alpha) } }