From d2123ba96eb9043f711ea405a8828f42a209c544 Mon Sep 17 00:00:00 2001 From: Daniel Bulant Date: Mon, 25 Nov 2024 15:23:12 +0100 Subject: [PATCH] update cushy + improved layout --- Cargo.lock | 24 ++++++++--------- src/pipeline.rs | 70 ++++++++++++++++++------------------------------- src/player.rs | 54 ++++++++++++++++++++++++++++++++++---- src/video.rs | 1 + 4 files changed, 88 insertions(+), 61 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 82c3a96..96add23 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -823,7 +823,7 @@ checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" [[package]] name = "cushy" version = "0.4.0" -source = "git+https://github.com/khonsulabs/cushy.git?branch=main#57f0c06b12f51cd7ef133794119bf1ba163e88d8" +source = "git+https://github.com/khonsulabs/cushy.git?branch=main#5e2819a98386a4d1f7485de23acd6603e43b6368" dependencies = [ "ahash", "alot", @@ -852,7 +852,7 @@ dependencies = [ [[package]] name = "cushy-macros" version = "0.4.0" -source = "git+https://github.com/khonsulabs/cushy.git?branch=main#57f0c06b12f51cd7ef133794119bf1ba163e88d8" +source = "git+https://github.com/khonsulabs/cushy.git?branch=main#5e2819a98386a4d1f7485de23acd6603e43b6368" dependencies = [ "attribute-derive", "manyhow", @@ -1576,9 +1576,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.1" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "heck" @@ -1798,7 +1798,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.15.1", + "hashbrown 0.15.2", ] [[package]] @@ -1926,7 +1926,7 @@ checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" [[package]] name = "kludgine" version = "0.11.0" -source = "git+https://github.com/khonsulabs/kludgine#1964cea13c1da08fb06d93c5101f3cd1f748c930" +source = "git+https://github.com/khonsulabs/kludgine#af4e6450c3bff3b2b6a6a3d7e9c0c2471b622578" dependencies = [ "ahash", "alot", @@ -4129,9 +4129,9 @@ checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" [[package]] name = "wgpu" -version = "23.0.0" +version = "23.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76ab52f2d3d18b70d5ab8dd270a1cff3ebe6dbe4a7d13c1cc2557138a9777fdc" +checksum = "80f70000db37c469ea9d67defdc13024ddf9a5f1b89cb2941b812ad7cde1735a" dependencies = [ "arrayvec", "cfg_aliases 0.1.1", @@ -4154,9 +4154,9 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "23.0.0" +version = "23.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e0c68e7b6322a03ee5b83fcd92caeac5c2a932f6457818179f4652ad2a9c065" +checksum = "d63c3c478de8e7e01786479919c8769f62a22eec16788d8c2ac77ce2c132778a" dependencies = [ "arrayvec", "bit-vec", @@ -4179,9 +4179,9 @@ dependencies = [ [[package]] name = "wgpu-hal" -version = "23.0.0" +version = "23.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de6e7266b869de56c7e3ed72a954899f71d14fec6cc81c102b7530b92947601b" +checksum = "89364b8a0b211adc7b16aeaf1bd5ad4a919c1154b44c9ce27838213ba05fd821" dependencies = [ "android_system_properties", "arrayvec", diff --git a/src/pipeline.rs b/src/pipeline.rs index 167e7c9..7a6fa27 100644 --- a/src/pipeline.rs +++ b/src/pipeline.rs @@ -7,7 +7,10 @@ use std::{ }; use cushy::{ - figures::{units::UPx, Rect}, + figures::{ + units::{Px, UPx}, + IntoUnsigned, Rect, + }, kludgine::{self, wgpu}, RenderOperation, }; @@ -304,7 +307,7 @@ impl VideoPipeline { } } - fn prepare(&mut self, queue: &wgpu::Queue, video_id: u64, bounds: Rect) { + fn prepare(&mut self, queue: &wgpu::Queue, video_id: u64, bounds: Rect) { if let Some(video) = self.videos.get(&video_id) { let uniforms = Uniforms { rect: [ @@ -327,38 +330,23 @@ impl VideoPipeline { fn draw(&self, pass: &mut wgpu::RenderPass, viewport: Rect, video_id: u64) { if let Some(video) = self.videos.get(&video_id) { - // let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - // label: Some("iced_video_player render pass"), - // color_attachments: &[Some(wgpu::RenderPassColorAttachment { - // view: target, - // resolve_target: None, - // ops: wgpu::Operations { - // load: wgpu::LoadOp::Load, - // store: wgpu::StoreOp::Store, - // }, - // })], - // depth_stencil_attachment: None, - // timestamp_writes: None, - // occlusion_query_set: None, - // }); - pass.set_pipeline(&self.pipeline); pass.set_bind_group(0, &video.bg0, &[]); - // pass.set_viewport( - // viewport.origin.x as _, - // viewport.origin.y as _, - // viewport.size.width as _, - // viewport.size.height as _, - // 0.0, - // 1.0, - // ); + pass.set_viewport( + viewport.origin.x.get() as _, + viewport.origin.y.get() as _, + viewport.size.width.get() as f32, + viewport.size.height.get() as f32, + 0.0, + 1.0, + ); pass.draw(0..4, 0..1); } } } pub(crate) struct VideoRO { - pipeline: Option, + pipeline: VideoPipeline, } impl RenderOperation for VideoRO { @@ -366,21 +354,19 @@ impl RenderOperation for VideoRO { type Prepared = VideoPrimitive; fn new(graphics: &mut cushy::kludgine::Graphics<'_>) -> Self { - VideoRO { pipeline: None } + VideoRO { + pipeline: VideoPipeline::new(graphics), + } } fn prepare( &mut self, context: Self::DrawInfo, - origin: cushy::figures::Point, + rect: Rect, graphics: &mut cushy::kludgine::Graphics<'_>, ) -> Self::Prepared { - let pipeline = self - .pipeline - .get_or_insert_with(|| VideoPipeline::new(graphics)); - if context.upload_frame { - pipeline.upload( + self.pipeline.upload( graphics.device(), graphics.queue(), context.video_id, @@ -389,26 +375,22 @@ impl RenderOperation for VideoRO { context.frame.lock().expect("lock frame mutex").as_slice(), ); } - - pipeline.prepare(graphics.queue(), context.video_id, graphics.clip_rect()); + self.pipeline + .prepare(graphics.queue(), context.video_id, rect); context } fn render( &self, prepared: &Self::Prepared, - origin: cushy::figures::Point, - opacity: f32, + _rect: Rect, + _opacity: f32, graphics: &mut cushy::kludgine::RenderingGraphics<'_, '_>, ) { - let pipeline = self.pipeline.as_ref().expect("prepare sets pipeline"); let rect = graphics.clip_rect(); - pipeline.draw( - // target, - graphics.pass_mut(), - rect, - prepared.video_id, - ); + dbg!(rect); + self.pipeline + .draw(graphics.pass_mut(), rect.into_unsigned(), prepared.video_id); } } diff --git a/src/player.rs b/src/player.rs index 6a692e1..077f50b 100644 --- a/src/player.rs +++ b/src/player.rs @@ -5,15 +5,19 @@ use std::{ use cushy::{ context::{GraphicsContext, LayoutContext}, - figures::{units::UPx, Size}, - value::{Destination, Dynamic, DynamicReader, Generation, Source}, + figures::{ + units::{Px, UPx}, + FloatConversion, IntoSigned, IntoUnsigned, Point, Rect, Size, + }, + value::{Destination, Dynamic, DynamicReader, Generation, Source, Value}, widget::Widget, + widgets::image::{Aspect, ImageScaling}, ConstraintLimit, }; use crate::{ pipeline::{VideoPrimitive, VideoRO}, - video::Video, + video::{Internal, Video}, Error, }; @@ -26,6 +30,7 @@ pub struct VideoPlayer { subtitles: Dynamic>, frame: Dynamic<()>, last_frame: Generation, + scaling: Value, } impl VideoPlayer { @@ -37,6 +42,7 @@ impl VideoPlayer { video, last_frame: Generation::default(), frame, + scaling: Default::default(), } } @@ -61,6 +67,41 @@ impl VideoPlayer { pub fn video(&self) -> &Video { &self.video } + + fn calculate_video_rect( + &self, + video: &Internal, + within_size: Size, + context: &mut GraphicsContext<'_, '_, '_, '_>, + ) -> Rect { + let within_size = within_size.into_signed(); + let size = Size { + width: Px::new(video.width), + height: Px::new(video.height), + }; + match self.scaling.get_tracking_invalidate(context) { + ImageScaling::Aspect { mode, orientation } => { + let scale_width = within_size.width.into_float() / size.width.into_float(); + let scale_height = within_size.height.into_float() / size.height.into_float(); + + let effective_scale = match mode { + Aspect::Fill => scale_width.max(scale_height), + Aspect::Fit => scale_width.min(scale_height), + }; + let scaled = size * effective_scale; + + let x = (within_size.width - scaled.width) * *orientation.width; + let y = (within_size.height - scaled.height) * *orientation.height; + + Rect::new(Point::new(x, y), scaled) + } + ImageScaling::Stretch => within_size.into(), + ImageScaling::Scale(factor) => { + let size = size.map(|px| px * factor); + size.into() + } + } + } } impl Widget for VideoPlayer { @@ -93,8 +134,11 @@ impl Widget for VideoPlayer { fn layout( &mut self, available_space: Size, - _context: &mut LayoutContext<'_, '_, '_, '_>, + context: &mut LayoutContext<'_, '_, '_, '_>, ) -> Size { - available_space.map(ConstraintLimit::max) + let inner = self.video.read(); + let rect = + self.calculate_video_rect(&inner, available_space.map(ConstraintLimit::max), context); + rect.size.into_unsigned() } } diff --git a/src/video.rs b/src/video.rs index d2fbafd..9305fa1 100644 --- a/src/video.rs +++ b/src/video.rs @@ -1,6 +1,7 @@ // This file is taken nearly one to one from https://github.com/jazzfool/iced_video_player use crate::Error; use cushy::value::{Destination, Dynamic}; +use glib::property::PropertyGet; use gstreamer as gst; use gstreamer_app as gst_app; use gstreamer_app::prelude::*;