initial mask impl
This commit is contained in:
@@ -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
46
src/layout/mask.rs
Normal 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) {}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user