makepad_draw/
draw_list_2d.rs

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