makepad_draw/
draw_list_2d.rs

1use {
2    crate::{
3        makepad_platform::*,
4        nav::*,
5        cx_2d::{Cx2d},
6        turtle::{Walk,AlignEntry}
7    }
8};
9
10 
11#[derive(Debug)]
12pub struct DrawList2d { // draw info per UI element
13    pub (crate) draw_list: DrawList,
14    pub (crate) dirty_check_rect: Rect,
15}
16
17impl LiveHook for DrawList2d {}
18impl LiveNew for DrawList2d {
19    fn new(cx: &mut Cx) -> Self {
20        let draw_list = cx.draw_lists.alloc();
21        Self {
22            dirty_check_rect: Default::default(),
23            draw_list,
24        }
25    }
26    
27    fn live_type_info(_cx: &mut Cx) -> LiveTypeInfo {
28        LiveTypeInfo {
29            module_id: LiveModuleId::from_str(&module_path!()).unwrap(),
30            live_type: LiveType::of::<Self>(),
31            live_ignore: true,
32            fields: Vec::new(),
33            type_name: id_lut!(View)
34        }
35    }
36}
37impl LiveApply for DrawList2d {
38    //fn type_id(&self) -> std::any::TypeId {std::any::TypeId::of::<Self>()}
39    fn apply(&mut self, cx: &mut Cx, from: ApplyFrom, start_index: usize, nodes: &[LiveNode]) -> usize {
40        
41        if !nodes[start_index].value.is_structy_type() {
42            cx.apply_error_wrong_type_for_struct(live_error_origin!(), start_index, nodes, live_id!(View));
43            return nodes.skip_node(start_index);
44        }
45        cx.draw_lists[self.draw_list.id()].debug_id = nodes[start_index].id;
46        let mut index = start_index + 1;
47        loop {
48            if nodes[index].value.is_close() {
49                index += 1;
50                break;
51            }
52            match nodes[index].id {
53                live_id!(debug_id) => cx.draw_lists[self.draw_list.id()].debug_id = LiveNew::new_apply_mut_index(cx, from, &mut index, nodes),
54                _ => {
55                    cx.apply_error_no_matching_field(live_error_origin!(), index, nodes);
56                    index = nodes.skip_node(index);
57                }
58            }
59        }
60        return index;
61    }
62}
63
64impl DrawList2d {
65    
66    pub fn draw_list_id(&self) -> DrawListId {self.draw_list.id()}
67    
68    
69    pub fn set_view_transform(&self, cx: &mut Cx, mat: &Mat4) {
70        
71        fn set_view_transform_recur(draw_list_id: DrawListId, cx: &mut Cx, mat: &Mat4) {
72            /*if cx.draw_lists[draw_list_id].locked_view_transform {
73                return
74            }*/
75            cx.draw_lists[draw_list_id].uniform_view_transform(mat);
76            let draw_items_len = cx.draw_lists[draw_list_id].draw_items.len();
77            for draw_item_id in 0..draw_items_len {
78                if let Some(sub_list_id) = cx.draw_lists[draw_list_id].draw_items[draw_item_id].sub_list() {
79                    set_view_transform_recur(sub_list_id, cx, mat);
80                }
81            }
82        }
83        
84        set_view_transform_recur(self.draw_list.id(), cx, mat);
85    }
86
87    pub fn begin_overlay_last(&mut self, cx: &mut Cx2d) {
88        self.begin_overlay_inner(cx, true)
89    }
90    
91    pub fn begin_overlay_reuse(&mut self, cx: &mut Cx2d) {
92        self.begin_overlay_inner(cx, false)
93    }
94    
95    pub fn begin_overlay_inner(&mut self, cx: &mut Cx2d, always_last:bool) {
96        let pass_id = cx.pass_stack.last().unwrap().pass_id;
97        let redraw_id = cx.cx.redraw_id;
98        
99        cx.draw_lists[self.draw_list.id()].pass_id = Some(pass_id);
100        
101        let codeflow_parent_id = cx.draw_list_stack.last().cloned().unwrap();
102        
103        let overlay_id = cx.overlay_id.unwrap();
104        if always_last{
105            cx.draw_lists[overlay_id].store_sub_list_last(redraw_id, self.draw_list.id());
106        }
107        else{
108            cx.draw_lists[overlay_id].store_sub_list(redraw_id, self.draw_list.id());
109        }
110        
111        cx.nav_list_item_push(codeflow_parent_id, NavItem::Child(self.draw_list.id()));
112        
113        cx.cx.draw_lists[self.draw_list.id()].codeflow_parent_id = Some(codeflow_parent_id);
114        if cx.passes[pass_id].main_draw_list_id.unwrap() == self.draw_list.id() {
115            cx.passes[pass_id].paint_dirty = true;
116        }
117        
118        cx.cx.draw_lists[self.draw_list.id()].clear_draw_items(redraw_id);
119        
120        cx.nav_list_clear(self.draw_list.id());
121        
122        cx.draw_list_stack.push(self.draw_list.id());
123    }
124    
125    
126    pub fn begin_always(&mut self, cx: &mut Cx2d) {
127        self.begin_maybe(cx, None).expect_redraw();
128    }
129    
130    pub fn begin(&mut self, cx: &mut Cx2d, walk: Walk) -> Redrawing {
131        self.begin_maybe(cx, Some(walk))
132    }
133    
134    fn begin_maybe(&mut self, cx: &mut Cx2d, cache_check: Option<Walk>) -> Redrawing {
135        
136        // check if we have a pass id parent
137        let pass_id = cx.pass_stack.last().unwrap().pass_id;
138        let redraw_id = cx.cx.redraw_id;
139        
140        cx.draw_lists[self.draw_list.id()].pass_id = Some(pass_id);
141        
142        let codeflow_parent_id = cx.draw_list_stack.last().cloned();
143        
144        let will_redraw = cache_check.is_none() || cx.will_redraw(self, cache_check.unwrap());
145        
146        let is_main_draw_list = if cx.passes[pass_id].main_draw_list_id.is_none() {
147            cx.passes[pass_id].main_draw_list_id = Some(self.draw_list.id());
148            true
149        }
150        else{
151            false
152        };
153        
154        // find the parent draw list id
155        if let Some(parent_id) = codeflow_parent_id {
156            if !is_main_draw_list{
157                let parent = &mut cx.cx.draw_lists[parent_id];
158                parent.append_sub_list(redraw_id, self.draw_list.id());
159                
160                cx.nav_list_item_push(parent_id, NavItem::Child(self.draw_list.id()));
161            }
162        }
163        
164        // set nesting draw list id for incremental repaint scanning
165        cx.cx.draw_lists[self.draw_list.id()].codeflow_parent_id = codeflow_parent_id;
166        
167        // check redraw status
168        if cx.cx.draw_lists[self.draw_list.id()].draw_items.len() != 0 && !will_redraw {
169            /*
170            let w = Size::Fixed(cx.cx.draw_lists[self.draw_list.id()].rect.size.x);
171            let h = Size::Fixed(cx.cx.draw_lists[self.draw_list.id()].rect.size.y);
172            let walk = Walk {abs_pos: None, width: w, height: h, margin: walk.margin};
173            //let pos = cx.peek_walk_pos(walk);
174            //if pos == cx.cx.draw_lists[self.draw_list.id()].rect.pos {
175             cx.walk_turtle(walk);*/
176            return Redrawing::no();
177            //}
178        }
179        
180        if cx.passes[pass_id].main_draw_list_id.unwrap() == self.draw_list.id() {
181            cx.passes[pass_id].paint_dirty = true;
182        }
183        
184        cx.cx.draw_lists[self.draw_list.id()].clear_draw_items(redraw_id);
185        
186        cx.nav_list_clear(self.draw_list.id());
187        
188        cx.draw_list_stack.push(self.draw_list.id());
189        
190        Redrawing::yes()
191    }
192    
193    pub fn end(&mut self, cx: &mut Cx2d) {
194        let draw_list_id = cx.draw_list_stack.pop().unwrap();
195        if draw_list_id != self.draw_list.id() {
196            panic!("Mismatch in drawlist id in view.end, check your begin/end pairs");
197        }
198        if cx.cx.draw_lists[draw_list_id].redraw_id != cx.cx.redraw_id {
199            panic!("calling end on a view that didnt get begin called this redraw cycle");
200        }
201    }
202    
203    pub fn get_view_transform(&self, cx: &Cx) -> Mat4 {
204        let cxview = &cx.draw_lists[self.draw_list.id()];
205        return cxview.get_view_transform()
206    }
207    
208    pub fn redraw(&self, cx: &mut Cx) {
209        cx.redraw_list(self.draw_list.id());
210    }
211    
212    pub fn redraw_self_and_children(&self, cx: &mut Cx) {
213        cx.redraw_list_and_children(self.draw_list.id());
214    }
215}
216
217
218impl<'a> Cx2d<'a> {
219    
220    pub fn new_draw_call(&mut self, draw_vars: &DrawVars) -> Option<&mut CxDrawItem> {
221        return self.get_draw_call(false, draw_vars);
222    }
223    
224    pub fn append_to_draw_call(&mut self, draw_vars: &DrawVars) -> Option<&mut CxDrawItem> {
225        return self.get_draw_call(true, draw_vars);
226    }
227    
228    pub fn get_current_draw_list_id(&self) -> Option<DrawListId> {
229        self.draw_list_stack.last().cloned()
230    }
231    
232    pub fn get_draw_call(&mut self, append: bool, draw_vars: &DrawVars) -> Option<&mut CxDrawItem> {
233        
234        if draw_vars.draw_shader.is_none() {
235            return None
236        }
237        let draw_shader = draw_vars.draw_shader.unwrap();
238        
239        if draw_shader.draw_shader_generation != self.draw_shaders.generation {
240            return None
241        }
242        
243        let sh = &self.cx.draw_shaders[draw_shader.draw_shader_id];
244        
245        let current_draw_list_id = *self.draw_list_stack.last().unwrap();
246        let draw_list = &mut self.cx.draw_lists[current_draw_list_id];
247        
248        if append && !sh.mapping.flags.draw_call_always {
249            if let Some(index) = draw_list.find_appendable_drawcall(sh, draw_vars) {
250                return Some(&mut draw_list.draw_items[index]);
251            }
252        }
253        
254        Some(draw_list.append_draw_call(self.cx.redraw_id, sh, draw_vars))
255    }
256    
257    pub fn begin_many_instances(&mut self, draw_vars: &DrawVars) -> Option<ManyInstances> {
258        
259        let draw_list_id = self.get_current_draw_list_id().unwrap();
260        let draw_item = self.append_to_draw_call(draw_vars);
261        if draw_item.is_none() {
262            return None
263        }
264        let draw_item = draw_item.unwrap();
265        //let draw_call = draw_item.kind.draw_call().unwrap();
266        let mut instances = None;
267        
268        std::mem::swap(&mut instances, &mut draw_item.instances);
269        Some(ManyInstances {
270            instance_area: InstanceArea {
271                draw_list_id,
272                draw_item_id: draw_item.draw_item_id,
273                instance_count: 0,
274                instance_offset: instances.as_ref().unwrap().len(),
275                redraw_id: draw_item.redraw_id
276            },
277            aligned: None,
278            instances: instances.unwrap()
279        })
280    }
281    
282    pub fn begin_many_aligned_instances(&mut self, draw_vars: &DrawVars) -> Option<ManyInstances> {
283        let mut li = self.begin_many_instances(draw_vars);
284        if li.is_none() {
285            return None;
286        }
287        li.as_mut().unwrap().aligned = Some(self.align_list.len());
288        self.align_list.push(AlignEntry::Unset);
289        li
290    }
291    
292    pub fn end_many_instances(&mut self, many_instances: ManyInstances) -> Area {
293        let mut ia = many_instances.instance_area;
294        let draw_list = &mut self.draw_lists[ia.draw_list_id];
295        let draw_item = &mut draw_list.draw_items[ia.draw_item_id];
296        let draw_call = draw_item.kind.draw_call().unwrap();
297        
298        let mut instances = Some(many_instances.instances);
299        std::mem::swap(&mut instances, &mut draw_item.instances);
300        ia.instance_count = (draw_item.instances.as_ref().unwrap().len() - ia.instance_offset) / draw_call.total_instance_slots;
301        if let Some(aligned) = many_instances.aligned {
302            self.align_list[aligned] = AlignEntry::Area(ia.clone().into());
303        }
304        ia.into()
305    }
306    
307    pub fn add_instance(&mut self, draw_vars: &DrawVars) -> Area {
308        let data = draw_vars.as_slice();
309        let draw_list_id = self.get_current_draw_list_id().unwrap();
310        let draw_item = self.append_to_draw_call(draw_vars);
311        if draw_item.is_none() {
312            return Area::Empty
313        }
314        let draw_item = draw_item.unwrap();
315        let draw_call = draw_item.draw_call().unwrap();
316        let instance_count = data.len() / draw_call.total_instance_slots;
317        let check = data.len() % draw_call.total_instance_slots;
318        if check > 0 {
319            panic!("Data not multiple of total slots");
320        }
321        let ia = InstanceArea {
322            draw_list_id,
323            draw_item_id: draw_item.draw_item_id,
324            instance_count: instance_count,
325            instance_offset: draw_item.instances.as_ref().unwrap().len(),
326            redraw_id: draw_item.redraw_id
327        };
328        draw_item.instances.as_mut().unwrap().extend_from_slice(data);
329        ia.into()
330    }
331    
332    pub fn add_aligned_instance(&mut self, draw_vars: &DrawVars) -> Area {
333        let data = draw_vars.as_slice();
334        let draw_list_id = self.get_current_draw_list_id().unwrap();
335        let draw_item = self.append_to_draw_call(draw_vars);
336        if draw_item.is_none() {
337            return Area::Empty
338        }
339        let draw_item = draw_item.unwrap();
340        let draw_call = draw_item.draw_call().unwrap();
341        let instance_count = data.len() / draw_call.total_instance_slots;
342        let check = data.len() % draw_call.total_instance_slots;
343        if check > 0 {
344            println!("Data not multiple of total slots");
345            return Area::Empty
346        }
347        let ia: Area = (InstanceArea {
348            draw_list_id,
349            draw_item_id: draw_item.draw_item_id,
350            instance_count: instance_count,
351            instance_offset: draw_item.instances.as_ref().unwrap().len(),
352            redraw_id: draw_item.redraw_id
353        }).into();
354        draw_item.instances.as_mut().unwrap().extend_from_slice(data);
355        self.align_list.push(AlignEntry::Area(ia.clone()));
356        ia
357    }
358    
359    pub fn add_aligned_rect_area(&mut self, area: &mut Area, rect: Rect) {
360        let draw_list_id = *self.draw_list_stack.last().unwrap();
361        let draw_list = &mut self.cx.draw_lists[draw_list_id];
362        // ok so we have to add
363        let rect_id = draw_list.rect_areas.len();
364        draw_list.rect_areas.push(CxRectArea {
365            rect,
366            draw_clip:Default::default(),
367        });
368        let new_area = Area::Rect(RectArea {
369            draw_list_id,
370            redraw_id: self.redraw_id,
371            rect_id
372        });
373        self.align_list.push(AlignEntry::Area(new_area));
374        self.update_area_refs(*area, new_area);
375        *area = new_area;
376    }
377}
378
379#[derive(Debug)]
380pub struct ManyInstances {
381    pub instance_area: InstanceArea,
382    pub aligned: Option<usize>,
383    pub instances: Vec<f32>
384}
385
386#[derive(Clone)]
387pub struct AlignedInstance {
388    pub inst: InstanceArea,
389    pub index: usize
390}
391
392pub type Redrawing = Result<(), ()>;
393
394pub trait RedrawingApi {
395    fn no() -> Redrawing {Result::Err(())}
396    fn yes() -> Redrawing {Result::Ok(())}
397    fn is_redrawing(&self) -> bool;
398    fn is_not_redrawing(&self) -> bool;
399    fn expect_redraw(&self);
400}
401
402impl RedrawingApi for Redrawing {
403    fn is_redrawing(&self) -> bool {
404        match *self {
405            Result::Ok(_) => true,
406            Result::Err(_) => false
407        }
408    }
409    fn is_not_redrawing(&self) -> bool {
410        match *self {
411            Result::Ok(_) => false,
412            Result::Err(_) => true
413        }
414    }
415    fn expect_redraw(&self) {
416        if !self.is_redrawing() {
417            panic!("assume_redraw_yes it should redraw")
418        }
419    }
420}
421
422/*
423pub enum ViewRedrawing {
424    Yes,
425    No
426}
427
428impl ViewRedrawing {
429    pub fn assume_redrawing(&self){
430        if !self.is_redrawing(){
431            panic!("assume_redraw_yes it should redraw")
432        }
433    }
434    
435    pub fn not_redrawing(&self)->bool{
436        !self.is_redrawing()
437    }
438    
439    pub fn is_redrawing(&self) -> bool {
440        match self {
441            Self::Yes => true,
442            _ => false
443        }
444    }
445}
446
447impl FromResidual for ViewRedrawing {
448    fn from_residual(_: ()) -> Self {
449        Self::No
450    }
451}
452
453impl Try for ViewRedrawing {
454    type Output = ();
455    type Residual = ();
456    
457    fn from_output(_: Self::Output) -> Self {
458        Self::Yes
459    }
460    
461    fn branch(self) -> ControlFlow<Self::Residual,
462    Self::Output> {
463        match self {
464            Self::Yes => ControlFlow::Continue(()),
465            Self::No => ControlFlow::Break(())
466        }
467    }
468}
469*/