initial mask impl

This commit is contained in:
2025-11-10 14:45:22 -05:00
parent 5c2022396a
commit 1c49db1b89
15 changed files with 398 additions and 74 deletions

View File

@@ -1,10 +1,6 @@
use std::ops::{Index, IndexMut};
use crate::{
layout::UiRegion,
render::{Primitive, PrimitiveHandle, Primitives},
util::Id,
};
use crate::render::{MaskIdx, Primitive, PrimitiveHandle, PrimitiveInst, Primitives};
struct LayerNode {
next: Ptr,
@@ -109,17 +105,11 @@ impl Layers {
LayerIndexIterator::new(&self.vec, self.last)
}
pub fn write<P: Primitive>(
&mut self,
layer: usize,
id: Id,
primitive: P,
region: UiRegion,
) -> PrimitiveHandle {
self[layer].primitives.write(layer, id, primitive, region)
pub fn write<P: Primitive>(&mut self, layer: usize, info: PrimitiveInst<P>) -> PrimitiveHandle {
self[layer].primitives.write(layer, info)
}
pub fn free(&mut self, h: &PrimitiveHandle) {
pub fn free(&mut self, h: &PrimitiveHandle) -> MaskIdx {
self[h.layer].primitives.free(h)
}
}

46
src/layout/mask.rs Normal file
View File

@@ -0,0 +1,46 @@
//! tree structure for masking
use crate::layout::UiRegion;
pub struct Masks {
data: Vec<MaskNode>,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct MaskPtr(u32);
#[repr(C)]
pub struct MaskNode {
/// TODO: this is just a rect for now,
/// but would like to support arbitrary masks
/// at some point; custom shader
/// would probably handle that case
/// bc you'd need to render to a special target
/// anyways
region: UiRegion,
prev: MaskPtr,
}
impl MaskPtr {
const NONE: Self = Self(u32::MAX);
}
impl Masks {
pub fn push(&mut self, parent: MaskPtr, region: UiRegion) -> MaskPtr {
match parent.0 {
_ => {
}
u32::MAX => {
let i = self.data.len();
self.data.push(MaskNode {
region,
prev: parent,
});
MaskPtr(i as u32)
}
}
}
pub fn pop(&mut self, i: usize) {}
}

View File

@@ -3,13 +3,14 @@ use crate::{
Layers, Modules, TextAttrs, TextBuffer, TextData, TextTexture, TextureHandle, Textures,
UiRegion, UiVec2, Vec2, WidgetId, Widgets,
},
render::{Primitive, PrimitiveHandle},
util::{HashMap, HashSet, Id},
render::{Mask, MaskIdx, Primitive, PrimitiveHandle, PrimitiveInst},
util::{HashMap, HashSet, Id, TrackedArena},
};
pub struct Painter<'a, 'c> {
ctx: &'a mut PainterCtx<'c>,
region: UiRegion,
mask: MaskIdx,
textures: Vec<TextureHandle>,
primitives: Vec<PrimitiveHandle>,
children: Vec<Id>,
@@ -25,6 +26,7 @@ pub struct PainterCtx<'a> {
pub active: &'a mut HashMap<Id, WidgetInstance>,
pub layers: &'a mut Layers,
pub textures: &'a mut Textures,
pub masks: &'a mut TrackedArena<Mask, u32>,
pub text: &'a mut TextData,
pub screen_size: Vec2,
pub modules: &'a mut Modules,
@@ -40,9 +42,11 @@ pub struct WidgetInstance {
pub primitives: Vec<PrimitiveHandle>,
pub children: Vec<Id>,
pub resize: Option<(Id, UiVec2)>,
pub mask: MaskIdx,
pub layer: usize,
}
#[derive(Default)]
pub struct PainterData {
pub widgets: Widgets,
pub active: HashMap<Id, WidgetInstance>,
@@ -52,21 +56,7 @@ pub struct PainterData {
pub output_size: Vec2,
pub modules: Modules,
pub px_dependent: HashSet<Id>,
}
impl Default for PainterData {
fn default() -> Self {
Self {
widgets: Widgets::new(),
layers: Default::default(),
textures: Textures::new(),
text: TextData::default(),
active: Default::default(),
output_size: Vec2::ZERO,
modules: Modules::default(),
px_dependent: Default::default(),
}
}
pub masks: TrackedArena<Mask, u32>,
}
impl<'a> PainterCtx<'a> {
@@ -80,6 +70,7 @@ impl<'a> PainterCtx<'a> {
screen_size: data.output_size,
modules: &mut data.modules,
px_dependent: &mut data.px_dependent,
masks: &mut data.masks,
draw_started: HashSet::default(),
}
}
@@ -122,6 +113,7 @@ impl<'a> PainterCtx<'a> {
id,
active.region,
active.parent,
active.mask,
Some(active.children),
);
self.active.get_mut(&id).unwrap().resize = active.resize;
@@ -130,7 +122,7 @@ impl<'a> PainterCtx<'a> {
pub fn draw(&mut self, id: Id) {
self.draw_started.clear();
self.layers.clear();
self.draw_inner(0, id, UiRegion::full(), None, None);
self.draw_inner(0, id, UiRegion::full(), None, MaskIdx::NONE, None);
}
fn draw_inner(
@@ -139,6 +131,7 @@ impl<'a> PainterCtx<'a> {
id: Id,
region: UiRegion,
parent: Option<Id>,
mask: MaskIdx,
old_children: Option<Vec<Id>>,
) {
// I have no idea if these checks work lol
@@ -173,6 +166,7 @@ impl<'a> PainterCtx<'a> {
let mut painter = Painter {
region,
mask,
layer,
id,
textures: Vec::new(),
@@ -196,6 +190,7 @@ impl<'a> PainterCtx<'a> {
primitives: painter.primitives,
children: painter.children,
resize,
mask: painter.mask,
layer,
};
for (cid, size) in sized_children {
@@ -238,7 +233,10 @@ impl<'a> PainterCtx<'a> {
let mut inst = self.active.remove(&id);
if let Some(inst) = &mut inst {
for h in &inst.primitives {
self.layers.free(h);
let mask = self.layers.free(h);
if mask != MaskIdx::NONE {
self.masks.remove(mask);
}
}
inst.textures.clear();
self.textures.free();
@@ -263,10 +261,19 @@ impl<'a> PainterCtx<'a> {
impl<'a, 'c> Painter<'a, 'c> {
fn primitive_at<P: Primitive>(&mut self, primitive: P, region: UiRegion) {
let h = self
.ctx
.layers
.write(self.layer, self.id, primitive, region);
let h = self.ctx.layers.write(
self.layer,
PrimitiveInst {
id: self.id,
primitive,
region,
mask_idx: self.mask,
},
);
if self.mask != MaskIdx::NONE {
// TODO: I have no clue if this works at all :joy:
self.ctx.masks.push_ref(self.mask);
}
self.primitives.push(h);
}
@@ -279,6 +286,11 @@ impl<'a, 'c> Painter<'a, 'c> {
self.primitive_at(primitive, region.within(&self.region));
}
pub fn set_mask(&mut self, region: UiRegion) {
assert!(self.mask == MaskIdx::NONE);
self.mask = self.ctx.masks.push(Mask { region });
}
/// Draws a widget within this widget's region.
pub fn widget<W>(&mut self, id: &WidgetId<W>) {
self.widget_at(id, self.region);
@@ -293,7 +305,7 @@ impl<'a, 'c> Painter<'a, 'c> {
fn widget_at<W>(&mut self, id: &WidgetId<W>, region: UiRegion) {
self.children.push(id.id);
self.ctx
.draw_inner(self.layer, id.id, region, Some(self.id), None);
.draw_inner(self.layer, id.id, region, Some(self.id), self.mask, None);
}
pub fn texture_within(&mut self, handle: &TextureHandle, region: UiRegion) {