working scissor proof of concept

This commit is contained in:
Aleksander
2025-09-24 21:53:43 +02:00
parent 8d41d8bbd1
commit 8f75d451e4
11 changed files with 175 additions and 146 deletions

View File

@@ -11,9 +11,9 @@
<div margin_left="16" gap="8" flex_direction="column"> <div margin_left="16" gap="8" flex_direction="column">
<label id="label_current_option" text="Click any of these buttons" size="20" weight="bold" /> <label id="label_current_option" text="Click any of these buttons" size="20" weight="bold" />
<div gap="4"> <div gap="4">
<Button id="button_red" text="Red button" width="220" height="32" color="#FF0000" /> <Button id="button_red" text="Red button" width="150" height="32" color="#FF0000" />
<Button id="button_aqua" text="Aqua button" width="220" height="32" color="#00FFFF" /> <Button id="button_aqua" text="Aqua button" width="150" height="32" color="#00FFFF" />
<Button id="button_yellow" text="Yellow button" width="220" height="32" color="#FFFF00" /> <Button id="button_yellow" text="Yellow button" width="150" height="32" color="#FFFF00" />
</div> </div>
<Button id="button_click_me" text="Click me" width="128" height="24" color="#FFFFFF" /> <Button id="button_click_me" text="Click me" width="128" height="24" color="#FFFFFF" />

View File

@@ -5,6 +5,7 @@ use glam::{Mat4, Vec2};
use taffy::TraversePartialTree; use taffy::TraversePartialTree;
use crate::{ use crate::{
drawing,
layout::Widget, layout::Widget,
renderer_vk::text::custom_glyph::CustomGlyph, renderer_vk::text::custom_glyph::CustomGlyph,
transform_stack::{self, TransformStack}, transform_stack::{self, TransformStack},
@@ -111,26 +112,18 @@ pub struct Rectangle {
pub round_units: u8, pub round_units: u8,
} }
#[derive(Clone, Copy)] pub struct PrimitiveExtent {
pub struct Scissor {
pub x: u32,
pub y: u32,
pub w: u32,
pub h: u32,
}
pub struct RenderPrimitive {
pub(super) boundary: Boundary, pub(super) boundary: Boundary,
pub(super) transform: Mat4, pub(super) transform: Mat4,
pub(super) depth: f32, pub(super) depth: f32, // FIXME: remove this
pub(super) payload: PrimitivePayload,
} }
pub enum PrimitivePayload { pub enum RenderPrimitive {
Rectangle(Rectangle), Rectangle(PrimitiveExtent, Rectangle),
Text(Rc<RefCell<Buffer>>), Text(PrimitiveExtent, Rc<RefCell<Buffer>>),
Sprite(Option<CustomGlyph>), //option because we want as_slice Sprite(PrimitiveExtent, Option<CustomGlyph>), //option because we want as_slice
Scissor(Scissor), ScissorEnable(Boundary),
ScissorDisable,
} }
fn draw_widget( fn draw_widget(
@@ -161,6 +154,13 @@ fn draw_widget(
dim: Vec2::new(l.size.width, l.size.height), dim: Vec2::new(l.size.width, l.size.height),
}); });
// FIXME: this is temporary
// FIXME: implement scissor stack (do not allow growing!)
if info.is_some() {
let boundary = drawing::Boundary::construct(state.transform_stack);
state.primitives.push(drawing::RenderPrimitive::ScissorEnable(boundary));
}
let draw_params = widget::DrawParams { let draw_params = widget::DrawParams {
node_id, node_id,
taffy_layout: l, taffy_layout: l,
@@ -171,6 +171,10 @@ fn draw_widget(
draw_children(layout, state, node_id, &transform); draw_children(layout, state, node_id, &transform);
if info.is_some() {
state.primitives.push(drawing::RenderPrimitive::ScissorDisable);
}
state.transform_stack.pop(); state.transform_stack.pop();
if let Some(info) = &info { if let Some(info) = &info {

View File

@@ -14,7 +14,7 @@ use vulkano::{
}, },
pipeline::{ pipeline::{
Pipeline, PipelineBindPoint, Pipeline, PipelineBindPoint,
graphics::{vertex_input::Vertex, viewport::Viewport}, graphics::{self, vertex_input::Vertex, viewport::Viewport},
}, },
}; };
@@ -38,6 +38,7 @@ where
vertices: Range<u32>, vertices: Range<u32>,
instances: Range<u32>, instances: Range<u32>,
descriptor_sets: Vec<Arc<DescriptorSet>>, descriptor_sets: Vec<Arc<DescriptorSet>>,
vk_scissor: &graphics::viewport::Scissor,
) -> anyhow::Result<Self> { ) -> anyhow::Result<Self> {
let viewport = Viewport { let viewport = Viewport {
offset: [0.0, 0.0], offset: [0.0, 0.0],
@@ -64,6 +65,7 @@ where
unsafe { unsafe {
command_buffer command_buffer
.set_viewport(0, smallvec![viewport])? .set_viewport(0, smallvec![viewport])?
.set_scissor(0, smallvec![*vk_scissor])?
.bind_pipeline_graphics(pipeline_inner)? .bind_pipeline_graphics(pipeline_inner)?
.bind_descriptor_sets( .bind_descriptor_sets(
PipelineBindPoint::Graphics, PipelineBindPoint::Graphics,
@@ -88,12 +90,7 @@ where
}) })
} }
pub fn update_sampler( pub fn update_sampler(&self, set: usize, texture: Arc<ImageView>, filter: Filter) -> anyhow::Result<()> {
&self,
set: usize,
texture: Arc<ImageView>,
filter: Filter,
) -> anyhow::Result<()> {
let sampler = Sampler::new( let sampler = Sampler::new(
self.graphics.device.clone(), self.graphics.device.clone(),
SamplerCreateInfo { SamplerCreateInfo {
@@ -105,10 +102,7 @@ where
)?; )?;
unsafe { unsafe {
self.descriptor_sets[set].update_by_ref( self.descriptor_sets[set].update_by_ref([WriteDescriptorSet::image_view_sampler(0, texture, sampler)], [])?;
[WriteDescriptorSet::image_view_sampler(0, texture, sampler)],
[],
)?;
} }
Ok(()) Ok(())

View File

@@ -16,7 +16,7 @@ use vulkano::{
pipeline::{ pipeline::{
DynamicState, GraphicsPipeline, Pipeline, PipelineLayout, DynamicState, GraphicsPipeline, Pipeline, PipelineLayout,
graphics::{ graphics::{
GraphicsPipelineCreateInfo, self, GraphicsPipelineCreateInfo,
color_blend::{AttachmentBlend, ColorBlendAttachmentState, ColorBlendState}, color_blend::{AttachmentBlend, ColorBlendAttachmentState, ColorBlendState},
input_assembly::{InputAssemblyState, PrimitiveTopology}, input_assembly::{InputAssemblyState, PrimitiveTopology},
multisample::MultisampleState, multisample::MultisampleState,
@@ -91,7 +91,7 @@ where
}], }],
..Default::default() ..Default::default()
}), }),
dynamic_state: std::iter::once(DynamicState::Viewport).collect(), dynamic_state: [DynamicState::Viewport, DynamicState::Scissor].into_iter().collect(),
subpass: Some(subpass.into()), subpass: Some(subpass.into()),
..GraphicsPipelineCreateInfo::layout(layout) ..GraphicsPipelineCreateInfo::layout(layout)
}, },
@@ -105,7 +105,6 @@ where
}) })
} }
pub fn inner(&self) -> Arc<GraphicsPipeline> { pub fn inner(&self) -> Arc<GraphicsPipeline> {
self.pipeline.clone() self.pipeline.clone()
} }
@@ -151,11 +150,7 @@ where
} }
#[allow(clippy::needless_pass_by_value)] #[allow(clippy::needless_pass_by_value)]
pub fn uniform_buffer_upload<T>( pub fn uniform_buffer_upload<T>(&self, set: usize, data: Vec<T>) -> anyhow::Result<Arc<DescriptorSet>>
&self,
set: usize,
data: Vec<T>,
) -> anyhow::Result<Arc<DescriptorSet>>
where where
T: BufferContents + Copy, T: BufferContents + Copy,
{ {
@@ -163,8 +158,7 @@ where
self.graphics.memory_allocator.clone(), self.graphics.memory_allocator.clone(),
SubbufferAllocatorCreateInfo { SubbufferAllocatorCreateInfo {
buffer_usage: BufferUsage::UNIFORM_BUFFER, buffer_usage: BufferUsage::UNIFORM_BUFFER,
memory_type_filter: MemoryTypeFilter::PREFER_DEVICE memory_type_filter: MemoryTypeFilter::PREFER_DEVICE | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
..Default::default() ..Default::default()
}, },
); );
@@ -219,6 +213,7 @@ where
vertices: Range<u32>, vertices: Range<u32>,
instances: Range<u32>, instances: Range<u32>,
descriptor_sets: Vec<Arc<DescriptorSet>>, descriptor_sets: Vec<Arc<DescriptorSet>>,
vk_scissor: &graphics::viewport::Scissor,
) -> anyhow::Result<WGfxPass<V>> { ) -> anyhow::Result<WGfxPass<V>> {
WGfxPass::new( WGfxPass::new(
&self.clone(), &self.clone(),
@@ -227,6 +222,7 @@ where
vertices, vertices,
instances, instances,
descriptor_sets, descriptor_sets,
vk_scissor,
) )
} }
} }

View File

@@ -3,10 +3,10 @@ use std::{cell::RefCell, rc::Rc, sync::Arc};
use cosmic_text::Buffer; use cosmic_text::Buffer;
use glam::{Mat4, Vec2, Vec3}; use glam::{Mat4, Vec2, Vec3};
use slotmap::{SlotMap, new_key_type}; use slotmap::{SlotMap, new_key_type};
use vulkano::{buffer::view, pipeline::graphics::viewport}; use vulkano::pipeline::graphics::viewport;
use crate::{ use crate::{
drawing::{self, Scissor}, drawing::{self},
gfx::{WGfx, cmd::GfxCommandBuffer}, gfx::{WGfx, cmd::GfxCommandBuffer},
}; };
@@ -25,11 +25,17 @@ struct RendererPass<'a> {
text_areas: Vec<TextArea<'a>>, text_areas: Vec<TextArea<'a>>,
text_renderer: TextRenderer, text_renderer: TextRenderer,
rect_renderer: RectRenderer, rect_renderer: RectRenderer,
scissor: Option<Scissor>, scissor: Option<drawing::Boundary>,
pixel_scale: f32,
} }
impl RendererPass<'_> { impl RendererPass<'_> {
fn new(text_atlas: &mut TextAtlas, rect_pipeline: RectPipeline, scissor: Option<Scissor>) -> anyhow::Result<Self> { fn new(
text_atlas: &mut TextAtlas,
rect_pipeline: RectPipeline,
scissor: Option<drawing::Boundary>,
pixel_scale: f32,
) -> anyhow::Result<Self> {
let text_renderer = TextRenderer::new(text_atlas)?; let text_renderer = TextRenderer::new(text_atlas)?;
let rect_renderer = RectRenderer::new(rect_pipeline)?; let rect_renderer = RectRenderer::new(rect_pipeline)?;
@@ -39,6 +45,7 @@ impl RendererPass<'_> {
rect_renderer, rect_renderer,
text_areas: Vec::new(), text_areas: Vec::new(),
scissor, scissor,
pixel_scale,
}) })
} }
@@ -53,20 +60,34 @@ impl RendererPass<'_> {
return Ok(()); return Ok(());
} }
let vk_scissor = if let Some(scissor) = self.scissor { let vk_scissor = match self.scissor {
viewport::Scissor { Some(scissor) => {
offset: [scissor.x, scissor.y], let mut x = scissor.pos.x;
extent: [scissor.w, scissor.h], let mut y = scissor.pos.y;
let mut w = scissor.size.x;
let mut h = scissor.size.y;
// handle out-of-bounds scissors (x/y < 0)
if x < 0.0 {
w += x;
x = 0.0;
}
if y < 0.0 {
h += y;
y = 0.0;
}
viewport::Scissor {
offset: [(x * self.pixel_scale) as u32, (y * self.pixel_scale) as u32],
extent: [(w * self.pixel_scale) as u32, (h * self.pixel_scale) as u32],
}
} }
} else { None => viewport::Scissor::default(),
viewport::Scissor::default()
}; };
// TODO?
// cmd_buf.command_buffer.set_scissor(0, smallvec::smallvec![vk_scissor])?;
self.submitted = true; self.submitted = true;
self.rect_renderer.render(gfx, viewport, cmd_buf)?; self.rect_renderer.render(gfx, viewport, &vk_scissor, cmd_buf)?;
{ {
let mut font_system = FONT_SYSTEM.lock(); let mut font_system = FONT_SYSTEM.lock();
@@ -81,7 +102,7 @@ impl RendererPass<'_> {
)?; )?;
} }
self.text_renderer.render(text_atlas, viewport, cmd_buf)?; self.text_renderer.render(text_atlas, viewport, &vk_scissor, cmd_buf)?;
Ok(()) Ok(())
} }
@@ -202,7 +223,7 @@ impl Context {
let mut passes = Vec::<RendererPass>::new(); let mut passes = Vec::<RendererPass>::new();
let mut needs_new_pass = true; let mut needs_new_pass = true;
let mut next_scissor: Option<Scissor> = None; let mut next_scissor: Option<drawing::Boundary> = None;
for primitive in primitives { for primitive in primitives {
if needs_new_pass { if needs_new_pass {
@@ -210,54 +231,60 @@ impl Context {
&mut atlas.text_atlas, &mut atlas.text_atlas,
shared.rect_pipeline.clone(), shared.rect_pipeline.clone(),
next_scissor, next_scissor,
self.pixel_scale,
)?); )?);
next_scissor = None;
needs_new_pass = false; needs_new_pass = false;
} }
let pass = passes.last_mut().unwrap(); // always safe let pass = passes.last_mut().unwrap(); // always safe
match &primitive.payload { match &primitive {
drawing::PrimitivePayload::Rectangle(rectangle) => { drawing::RenderPrimitive::Rectangle(extent, rectangle) => {
pass pass
.rect_renderer .rect_renderer
.add_rect(primitive.boundary, *rectangle, &primitive.transform, primitive.depth); .add_rect(extent.boundary, *rectangle, &extent.transform, extent.depth);
} }
drawing::PrimitivePayload::Text(text) => { drawing::RenderPrimitive::Text(extent, text) => {
pass.text_areas.push(TextArea { pass.text_areas.push(TextArea {
buffer: text.clone(), buffer: text.clone(),
left: primitive.boundary.pos.x * self.pixel_scale, left: extent.boundary.pos.x * self.pixel_scale,
top: primitive.boundary.pos.y * self.pixel_scale, top: extent.boundary.pos.y * self.pixel_scale,
bounds: TextBounds::default(), //FIXME: just using boundary coords here doesn't work bounds: TextBounds::default(), //FIXME: just using boundary coords here doesn't work
scale: self.pixel_scale, scale: self.pixel_scale,
default_color: cosmic_text::Color::rgb(0, 0, 0), default_color: cosmic_text::Color::rgb(0, 0, 0),
custom_glyphs: &[], custom_glyphs: &[],
depth: primitive.depth, depth: extent.depth,
transform: primitive.transform, transform: extent.transform,
}); });
} }
drawing::PrimitivePayload::Sprite(sprites) => { drawing::RenderPrimitive::Sprite(extent, sprites) => {
pass.text_areas.push(TextArea { pass.text_areas.push(TextArea {
buffer: self.empty_text.clone(), buffer: self.empty_text.clone(),
left: primitive.boundary.pos.x * self.pixel_scale, left: extent.boundary.pos.x * self.pixel_scale,
top: primitive.boundary.pos.y * self.pixel_scale, top: extent.boundary.pos.y * self.pixel_scale,
bounds: TextBounds::default(), bounds: TextBounds::default(),
scale: self.pixel_scale, scale: self.pixel_scale,
custom_glyphs: sprites.as_slice(), custom_glyphs: sprites.as_slice(),
default_color: cosmic_text::Color::rgb(255, 0, 255), default_color: cosmic_text::Color::rgb(255, 0, 255),
depth: primitive.depth, depth: extent.depth,
transform: primitive.transform, transform: extent.transform,
}); });
} }
drawing::PrimitivePayload::Scissor(scissor) => { drawing::RenderPrimitive::ScissorEnable(boundary) => {
next_scissor = Some(*scissor); next_scissor = Some(*boundary);
needs_new_pass = true;
}
drawing::RenderPrimitive::ScissorDisable => {
next_scissor = None;
needs_new_pass = true; needs_new_pass = true;
} }
} }
} }
log::info!("count {}", passes.len());
for mut pass in passes { for mut pass in passes {
pass.submit(&shared.gfx, &mut self.viewport, cmd_buf, &mut atlas.text_atlas)? pass.submit(&shared.gfx, &mut self.viewport, cmd_buf, &mut atlas.text_atlas)?;
} }
Ok(()) Ok(())

View File

@@ -4,7 +4,7 @@ use glam::Mat4;
use vulkano::{ use vulkano::{
buffer::{BufferContents, BufferUsage, Subbuffer}, buffer::{BufferContents, BufferUsage, Subbuffer},
format::Format, format::Format,
pipeline::graphics::{input_assembly::PrimitiveTopology, vertex_input::Vertex}, pipeline::graphics::{self, input_assembly::PrimitiveTopology, vertex_input::Vertex},
}; };
use crate::{ use crate::{
@@ -136,6 +136,7 @@ impl RectRenderer {
&mut self, &mut self,
gfx: &Arc<WGfx>, gfx: &Arc<WGfx>,
viewport: &mut Viewport, viewport: &mut Viewport,
vk_scissor: &graphics::viewport::Scissor,
cmd_buf: &mut GfxCommandBuffer, cmd_buf: &mut GfxCommandBuffer,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let res = viewport.resolution(); let res = viewport.resolution();
@@ -154,6 +155,7 @@ impl RectRenderer {
0..4, 0..4,
0..self.rect_vertices.len() as _, 0..self.rect_vertices.len() as _,
vec![set0, set1], vec![set0, set1],
vk_scissor,
)?; )?;
CachedPass { pass, res } CachedPass { pass, res }
} }

View File

@@ -13,6 +13,7 @@ use glam::{Mat4, Vec2, Vec3};
use vulkano::{ use vulkano::{
buffer::{BufferUsage, Subbuffer}, buffer::{BufferUsage, Subbuffer},
command_buffer::CommandBufferUsage, command_buffer::CommandBufferUsage,
pipeline::graphics,
}; };
struct CachedPass { struct CachedPass {
@@ -78,12 +79,7 @@ impl TextRenderer {
let height = (glyph.height * text_area.scale).round() as u16; let height = (glyph.height * text_area.scale).round() as u16;
let (x, y, x_bin, y_bin) = if glyph.snap_to_physical_pixel { let (x, y, x_bin, y_bin) = if glyph.snap_to_physical_pixel {
( (x.round() as i32, y.round() as i32, SubpixelBin::Zero, SubpixelBin::Zero)
x.round() as i32,
y.round() as i32,
SubpixelBin::Zero,
SubpixelBin::Zero,
)
} else { } else {
let (x, x_bin) = SubpixelBin::new(x); let (x, x_bin) = SubpixelBin::new(x);
let (y, y_bin) = SubpixelBin::new(y); let (y, y_bin) = SubpixelBin::new(y);
@@ -252,6 +248,7 @@ impl TextRenderer {
&mut self, &mut self,
atlas: &TextAtlas, atlas: &TextAtlas,
viewport: &mut Viewport, viewport: &mut Viewport,
vk_scissor: &graphics::viewport::Scissor,
cmd_buf: &mut GfxCommandBuffer, cmd_buf: &mut GfxCommandBuffer,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
if self.glyph_vertices.is_empty() { if self.glyph_vertices.is_empty() {
@@ -277,6 +274,7 @@ impl TextRenderer {
0..4, 0..4,
0..self.glyph_vertices.len() as u32, 0..self.glyph_vertices.len() as u32,
descriptor_sets, descriptor_sets,
vk_scissor,
)?; )?;
CachedPass { pass, res } CachedPass { pass, res }
} }
@@ -351,10 +349,7 @@ fn prepare_glyph(
if let Some(a) = inner.try_allocate(image.width as usize, image.height as usize) { if let Some(a) = inner.try_allocate(image.width as usize, image.height as usize) {
break a; break a;
} }
if !par if !par.atlas.grow(par.font_system, par.cache, image.content_type)? {
.atlas
.grow(par.font_system, par.cache, image.content_type)?
{
anyhow::bail!( anyhow::bail!(
"Atlas full. atlas: {:?} cache_key: {:?}", "Atlas full. atlas: {:?} cache_key: {:?}",
image.content_type, image.content_type,
@@ -393,16 +388,14 @@ fn prepare_glyph(
inner.glyphs_in_use.insert(par.cache_key); inner.glyphs_in_use.insert(par.cache_key);
// Insert the glyph into the cache and return the details reference // Insert the glyph into the cache and return the details reference
inner inner.glyph_cache.get_or_insert(par.cache_key, || GlyphDetails {
.glyph_cache width: image.width,
.get_or_insert(par.cache_key, || GlyphDetails { height: image.height,
width: image.width, gpu_cache,
height: image.height, atlas_id,
gpu_cache, top: image.top,
atlas_id, left: image.left,
top: image.top, })
left: image.left,
})
}; };
let mut x = par.x + i32::from(details.left); let mut x = par.x + i32::from(details.left);

View File

@@ -5,7 +5,7 @@ use slotmap::Key;
use taffy::AvailableSpace; use taffy::AvailableSpace;
use crate::{ use crate::{
drawing::{self, Boundary}, drawing::{self, Boundary, PrimitiveExtent},
event::CallbackDataCommon, event::CallbackDataCommon,
globals::Globals, globals::Globals,
i18n::{I18n, Translation}, i18n::{I18n, Translation},
@@ -118,12 +118,14 @@ impl WidgetObj for WidgetLabel {
buffer.set_size(&mut font_system, Some(boundary.size.x), Some(boundary.size.y)); buffer.set_size(&mut font_system, Some(boundary.size.x), Some(boundary.size.y));
} }
state.primitives.push(drawing::RenderPrimitive { state.primitives.push(drawing::RenderPrimitive::Text(
boundary, PrimitiveExtent {
depth: state.depth, boundary,
payload: drawing::PrimitivePayload::Text(self.buffer.clone()), depth: state.depth,
transform: state.transform_stack.get().transform, transform: state.transform_stack.get().transform,
}); },
self.buffer.clone(),
));
} }
fn measure( fn measure(

View File

@@ -4,7 +4,7 @@ use super::drawing::RenderPrimitive;
use crate::{ use crate::{
any::AnyTrait, any::AnyTrait,
drawing, drawing::{self, PrimitiveExtent},
event::{ event::{
self, CallbackData, CallbackDataCommon, CallbackMetadata, Event, EventAlterables, EventListenerKind, self, CallbackData, CallbackDataCommon, CallbackMetadata, Event, EventAlterables, EventListenerKind,
EventListenerVec, MouseWheelEvent, EventListenerVec, MouseWheelEvent,
@@ -244,34 +244,38 @@ impl WidgetState {
// Horizontal handle // Horizontal handle
if enabled_horiz && info.handle_size.x < 1.0 { if enabled_horiz && info.handle_size.x < 1.0 {
state.primitives.push(drawing::RenderPrimitive { state.primitives.push(drawing::RenderPrimitive::Rectangle(
boundary: drawing::Boundary::from_pos_size( PrimitiveExtent {
Vec2::new( boundary: drawing::Boundary::from_pos_size(
transform.pos.x + transform.dim.x * (1.0 - info.handle_size.x) * self.data.scrolling.x, Vec2::new(
transform.pos.y + transform.dim.y - thickness - margin, transform.pos.x + transform.dim.x * (1.0 - info.handle_size.x) * self.data.scrolling.x,
transform.pos.y + transform.dim.y - thickness - margin,
),
Vec2::new(transform.dim.x * info.handle_size.x, thickness),
), ),
Vec2::new(transform.dim.x * info.handle_size.x, thickness), depth: state.depth,
), transform: transform.transform,
depth: state.depth, },
transform: transform.transform, rect_params,
payload: drawing::PrimitivePayload::Rectangle(rect_params), ));
});
} }
// Vertical handle // Vertical handle
if enabled_vert && info.handle_size.y < 1.0 { if enabled_vert && info.handle_size.y < 1.0 {
state.primitives.push(drawing::RenderPrimitive { state.primitives.push(drawing::RenderPrimitive::Rectangle(
boundary: drawing::Boundary::from_pos_size( PrimitiveExtent {
Vec2::new( boundary: drawing::Boundary::from_pos_size(
transform.pos.x + transform.dim.x - thickness - margin, Vec2::new(
transform.pos.y + transform.dim.y * (1.0 - info.handle_size.y) * self.data.scrolling.y, transform.pos.x + transform.dim.x - thickness - margin,
transform.pos.y + transform.dim.y * (1.0 - info.handle_size.y) * self.data.scrolling.y,
),
Vec2::new(thickness, transform.dim.y * info.handle_size.y),
), ),
Vec2::new(thickness, transform.dim.y * info.handle_size.y), depth: state.depth,
), transform: transform.transform,
depth: state.depth, },
transform: transform.transform, rect_params,
payload: drawing::PrimitivePayload::Rectangle(rect_params), ));
});
} }
} }

View File

@@ -1,7 +1,7 @@
use slotmap::Key; use slotmap::Key;
use crate::{ use crate::{
drawing::{self, GradientMode}, drawing::{self, GradientMode, PrimitiveExtent},
layout::WidgetID, layout::WidgetID,
widget::util::WLength, widget::util::WLength,
}; };
@@ -43,19 +43,21 @@ impl WidgetObj for WidgetRectangle {
WLength::Percent(percent) => (f32::min(boundary.size.x, boundary.size.y) * percent / 2.0) as u8, WLength::Percent(percent) => (f32::min(boundary.size.x, boundary.size.y) * percent / 2.0) as u8,
}; };
state.primitives.push(drawing::RenderPrimitive { state.primitives.push(drawing::RenderPrimitive::Rectangle(
boundary, PrimitiveExtent {
depth: state.depth, boundary,
transform: state.transform_stack.get().transform, depth: state.depth,
payload: drawing::PrimitivePayload::Rectangle(drawing::Rectangle { transform: state.transform_stack.get().transform,
},
drawing::Rectangle {
color: self.params.color, color: self.params.color,
color2: self.params.color2, color2: self.params.color2,
gradient: self.params.gradient, gradient: self.params.gradient,
border: self.params.border, border: self.params.border,
border_color: self.params.border_color, border_color: self.params.border_color,
round_units, round_units,
}), },
}); ));
} }
fn get_id(&self) -> WidgetID { fn get_id(&self) -> WidgetID {

View File

@@ -4,7 +4,7 @@ use cosmic_text::{Attrs, Buffer, Color, Shaping, Weight};
use slotmap::Key; use slotmap::Key;
use crate::{ use crate::{
drawing::{self}, drawing::{self, PrimitiveExtent},
layout::WidgetID, layout::WidgetID,
renderer_vk::text::{ renderer_vk::text::{
DEFAULT_METRICS, FONT_SYSTEM, DEFAULT_METRICS, FONT_SYSTEM,
@@ -55,12 +55,14 @@ impl WidgetObj for WidgetSprite {
snap_to_physical_pixel: true, snap_to_physical_pixel: true,
}; };
state.primitives.push(drawing::RenderPrimitive { state.primitives.push(drawing::RenderPrimitive::Sprite(
boundary, PrimitiveExtent {
depth: state.depth, boundary,
payload: drawing::PrimitivePayload::Sprite(Some(glyph)), depth: state.depth,
transform: state.transform_stack.get().transform, transform: state.transform_stack.get().transform,
}); },
Some(glyph),
));
} else { } else {
// Source not set or not available, display error text // Source not set or not available, display error text
let mut buffer = Buffer::new_empty(DEFAULT_METRICS); let mut buffer = Buffer::new_empty(DEFAULT_METRICS);
@@ -73,13 +75,16 @@ impl WidgetObj for WidgetSprite {
// set text last in order to avoid expensive re-shaping // set text last in order to avoid expensive re-shaping
buffer.set_text("Error", &attrs, Shaping::Basic); buffer.set_text("Error", &attrs, Shaping::Basic);
} }
state.primitives.push(drawing::RenderPrimitive {
boundary, state.primitives.push(drawing::RenderPrimitive::Text(
depth: state.depth, PrimitiveExtent {
payload: drawing::PrimitivePayload::Text(Rc::new(RefCell::new(buffer))), boundary,
transform: state.transform_stack.get().transform, depth: state.depth,
}); transform: state.transform_stack.get().transform,
} },
Rc::new(RefCell::new(buffer)),
))
};
} }
fn measure( fn measure(