makepad_platform/
area.rs

1use {
2    crate::{
3        makepad_math::*,
4        makepad_shader_compiler::{
5            ShaderTy
6        },
7        makepad_live_compiler::{
8            LiveId,
9        },
10        draw_list::DrawListId,
11        cx::Cx
12    }
13};
14
15#[derive(Clone, Hash, Ord, PartialOrd, Eq, Debug, PartialEq, Copy)]
16pub struct InstanceArea {
17    pub draw_list_id: DrawListId,
18    pub draw_item_id: usize,
19    pub instance_offset: usize,
20    pub instance_count: usize,
21    pub redraw_id: u64
22}
23/*
24#[derive(Clone, Hash, Ord, PartialOrd, Eq, Debug, PartialEq, Copy)]
25pub struct DrawListArea {
26    pub draw_list_id: DrawListId,
27    pub redraw_id: u64
28}*/
29
30#[derive(Clone, Hash, Ord, PartialOrd, Eq, Debug, PartialEq, Copy)]
31pub struct RectArea {
32    pub draw_list_id: DrawListId,
33    pub rect_id: usize,
34    pub redraw_id: u64
35}
36
37#[derive(Clone, Debug, Hash, PartialEq, Ord, PartialOrd, Eq, Copy)]
38pub enum Area {
39    Empty,
40    Instance(InstanceArea),
41    //DrawList(DrawListArea),
42    Rect(RectArea)
43}
44
45impl Default for Area {
46    fn default() -> Area {
47        Area::Empty
48    }
49}
50
51pub struct DrawReadRef<'a> {
52    pub repeat: usize,
53    pub stride: usize,
54    pub buffer: &'a [f32]
55}
56
57pub struct DrawWriteRef<'a> {
58    pub repeat: usize,
59    pub stride: usize,
60    pub buffer: &'a mut [f32]
61}
62
63impl Into<Area> for InstanceArea {
64    fn into(self) -> Area {
65        Area::Instance(self)
66    }
67}
68
69impl Area {
70    pub fn area(&self)->Self{
71        self.clone()
72    }
73    
74    pub fn redraw(&self, cx: &mut Cx) {
75        cx.redraw_area(*self);
76    }
77    
78    
79    pub fn valid_instance(&self, cx: &Cx) -> Option<&InstanceArea> {
80        if self.is_valid(cx) {
81            if let Self::Instance(inst) = self {
82                return Some(inst)
83            }
84        }
85        None
86    }
87    
88    pub fn is_empty(&self) -> bool {
89        if let Area::Empty = self {
90            return true
91        }
92        false
93    }
94    
95    pub fn draw_list_id(&self) -> Option<DrawListId> {
96        return match self {
97            Area::Instance(inst) => {
98                Some(inst.draw_list_id)
99            },
100            Area::Rect(list) => {
101                Some(list.draw_list_id)
102            }
103            _ => None
104        }
105    }
106    
107    pub fn redraw_id(&self) -> Option<u64> {
108        return match self {
109            Area::Instance(inst) => {
110                Some(inst.redraw_id)
111            },
112            Area::Rect(list) => {
113                Some(list.redraw_id)
114            }
115            _ => None
116        }
117    }
118    
119    pub fn is_first_instance(&self) -> bool {
120        return match self {
121            Area::Instance(inst) => {
122                inst.instance_offset == 0
123            },
124            _ => false,
125        }
126    }
127    
128    pub fn is_valid(&self, cx: &Cx) -> bool {
129        return match self {
130            Area::Instance(inst) => {
131                if inst.instance_count == 0 {
132                    return false
133                }
134                if let Some(draw_list) = cx.draw_lists.checked_index(inst.draw_list_id){
135                    if draw_list.redraw_id != inst.redraw_id {
136                        return false
137                    }
138                    return true
139                }
140                return false
141            },
142            Area::Rect(list) => {
143                if let Some(draw_list) = cx.draw_lists.checked_index(list.draw_list_id){
144                    if draw_list.redraw_id != list.redraw_id {
145                        return false
146                    }
147                    return true
148                }
149                return false
150            },
151            _ => false,
152        }
153    }
154
155    // returns the final screen rect
156    pub fn clipped_rect(&self, cx: &Cx) -> Rect {
157        
158        return match self {
159            Area::Instance(inst) => {
160                if inst.instance_count == 0 {
161                    //panic!();
162                    error!("get_rect called on instance_count ==0 area pointer, use mark/sweep correctly!");
163                    return Rect::default()
164                }
165                let draw_list = &cx.draw_lists[inst.draw_list_id];
166                if draw_list.redraw_id != inst.redraw_id {
167                    return Rect::default();
168                }
169                let draw_item = &draw_list.draw_items[inst.draw_item_id];
170                let draw_call = draw_item.draw_call().unwrap();
171                
172                if draw_item.instances.as_ref().unwrap().len() == 0 {
173                    error!("No instances but everything else valid?");
174                    return Rect::default()
175                }
176                if cx.draw_shaders.generation != draw_call.draw_shader.draw_shader_generation {
177                    error!("Generation invalid get_rect {} {:?} {} {}", draw_list.debug_id, inst, cx.draw_shaders.generation, draw_call.draw_shader.draw_shader_generation);
178                    return Rect::default()
179                }
180                let sh = &cx.draw_shaders[draw_call.draw_shader.draw_shader_id];
181                // ok now we have to patch x/y/w/h into it
182                let buf = draw_item.instances.as_ref().unwrap();
183                if let Some(rect_pos) = sh.mapping.rect_pos {
184                    let pos = dvec2(
185                        buf[inst.instance_offset + rect_pos + 0] as f64, 
186                        buf[inst.instance_offset + rect_pos + 1] as f64
187                    );
188                    if let Some(rect_size) = sh.mapping.rect_size {
189                        let size = dvec2(buf[inst.instance_offset + rect_size + 0] as f64, buf[inst.instance_offset + rect_size + 1] as f64);
190                        if let Some(draw_clip) = sh.mapping.draw_clip {
191                            let p1= dvec2(
192                                buf[inst.instance_offset + draw_clip + 0] as f64,
193                                buf[inst.instance_offset + draw_clip + 1] as f64,
194                            );
195                            let p2 = dvec2(
196                                buf[inst.instance_offset + draw_clip + 2] as f64,
197                                buf[inst.instance_offset + draw_clip + 3] as f64
198                            );
199                            if draw_list.draw_list_has_clip{
200                                let p3 = dvec2(
201                                    draw_list.draw_list_uniforms.view_clip.x as f64,
202                                    draw_list.draw_list_uniforms.view_clip.y as f64,
203                                );
204                                let p4 = dvec2(
205                                    draw_list.draw_list_uniforms.view_clip.z as f64,
206                                    draw_list.draw_list_uniforms.view_clip.w as f64,
207                                );
208                                let shift = dvec2(
209                                    draw_list.draw_list_uniforms.view_shift.x as f64,
210                                    draw_list.draw_list_uniforms.view_shift.y as f64
211                                );
212                                return Rect{pos,size}.clip((p1,p2)).translate(shift).clip((p3,p4));
213                            }
214                            else{
215                                return Rect{pos,size}.clip((p1,p2));
216                            }
217                        }
218                    }
219                }
220                Rect::default()
221            },
222            Area::Rect(ra) => {
223                // we need to clip this drawlist too
224                let draw_list = &cx.draw_lists[ra.draw_list_id];
225                let rect_area = &draw_list.rect_areas[ra.rect_id];
226                if draw_list.draw_list_has_clip{
227                    let p3 = dvec2(
228                        draw_list.draw_list_uniforms.view_clip.x as f64,
229                        draw_list.draw_list_uniforms.view_clip.y as f64,
230                    );
231                    let p4 = dvec2(
232                        draw_list.draw_list_uniforms.view_clip.z as f64,
233                        draw_list.draw_list_uniforms.view_clip.w as f64,
234                    );
235                    let shift = dvec2(
236                        draw_list.draw_list_uniforms.view_shift.x as f64,
237                        draw_list.draw_list_uniforms.view_shift.y as f64
238                    );
239                    return rect_area.rect.clip(rect_area.draw_clip).translate(shift).clip((p3,p4));
240                }
241                else{
242                    return rect_area.rect.clip(rect_area.draw_clip);
243                }                
244            },
245            _ => Rect::default(),
246        }
247    }
248    
249    pub fn rect(&self, cx: &Cx) -> Rect {
250        
251        return match self {
252            Area::Instance(inst) => {
253                if inst.instance_count == 0 {
254                    //panic!();
255                    error!("get_rect called on instance_count ==0 area pointer, use mark/sweep correctly!");
256                    return Rect::default()
257                }
258                let draw_list = &cx.draw_lists[inst.draw_list_id];
259                if draw_list.redraw_id != inst.redraw_id {
260                    return Rect::default();
261                }
262                let draw_item = &draw_list.draw_items[inst.draw_item_id];
263                let draw_call = draw_item.draw_call().unwrap();
264                
265                if draw_item.instances.as_ref().unwrap().len() == 0 {
266                    error!("No instances but everything else valid?");
267                    return Rect::default()
268                }
269                if cx.draw_shaders.generation != draw_call.draw_shader.draw_shader_generation {
270                    error!("Generation invalid get_rect {} {:?} {} {}", draw_list.debug_id, inst, cx.draw_shaders.generation, draw_call.draw_shader.draw_shader_generation);
271                    return Rect::default()
272                }
273                let sh = &cx.draw_shaders[draw_call.draw_shader.draw_shader_id];
274                // ok now we have to patch x/y/w/h into it
275                let buf = draw_item.instances.as_ref().unwrap();
276                if let Some(rect_pos) = sh.mapping.rect_pos {
277                    let pos = dvec2(buf[inst.instance_offset + rect_pos + 0] as f64, buf[inst.instance_offset + rect_pos + 1] as f64);
278                    if let Some(rect_size) = sh.mapping.rect_size {
279                        let size = dvec2(buf[inst.instance_offset + rect_size + 0] as f64, buf[inst.instance_offset + rect_size + 1] as f64);
280                        return Rect{pos,size};
281                    }
282                }
283                Rect::default()
284            },
285            Area::Rect(ra) => {
286                let draw_list = &cx.draw_lists[ra.draw_list_id];
287                if draw_list.redraw_id == ra.redraw_id{
288                    let rect_area = &draw_list.rect_areas[ra.rect_id];
289                    return rect_area.rect;                
290                }
291                Rect::default()
292            },
293            _ => Rect::default(),
294        }
295    }
296    
297    pub fn abs_to_rel(&self, cx: &Cx, abs: DVec2) -> DVec2 {
298        return match self {
299            Area::Instance(inst) => {
300                if inst.instance_count == 0 {
301                    error!("abs_to_rel_scroll called on instance_count ==0 area pointer, use mark/sweep correctly!");
302                    return abs
303                }
304                let draw_list = &cx.draw_lists[inst.draw_list_id];
305                if draw_list.redraw_id != inst.redraw_id {
306                    return abs;
307                }
308                let draw_item = &draw_list.draw_items[inst.draw_item_id];
309                let draw_call = draw_item.draw_call().unwrap();
310                if cx.draw_shaders.generation != draw_call.draw_shader.draw_shader_generation {
311                    error!("Generation invalid abs_to_rel {} {:?} {} {}", draw_list.debug_id, inst, cx.draw_shaders.generation, draw_call.draw_shader.draw_shader_generation);
312                    return abs;
313                }
314                
315                let sh = &cx.draw_shaders[draw_call.draw_shader.draw_shader_id];
316                // ok now we have to patch x/y/w/h into it
317                if let Some(rect_pos) = sh.mapping.rect_pos {
318                    let buf = draw_item.instances.as_ref().unwrap();
319                    let x = buf[inst.instance_offset + rect_pos + 0] as f64; 
320                    let y = buf[inst.instance_offset + rect_pos + 1] as f64;
321                    return DVec2 {
322                        x: abs.x - x,
323                        y: abs.y - y
324                    }
325                }
326                abs
327            },
328            Area::Rect(ra) => {
329                let draw_list = &cx.draw_lists[ra.draw_list_id];
330                let rect_area = &draw_list.rect_areas[ra.rect_id];
331                DVec2 {
332                    x: abs.x - rect_area.rect.pos.x,
333                    y: abs.y - rect_area.rect.pos.y
334                }
335            },
336            _ => abs,
337        }
338    }
339    
340    pub fn set_rect(&self, cx: &mut Cx, rect: &Rect) {
341        match self {
342            Area::Instance(inst) => {
343                let cxview = &mut cx.draw_lists[inst.draw_list_id];
344                if cxview.redraw_id != inst.redraw_id {
345                    //println!("set_rect called on invalid area pointer, use mark/sweep correctly!");
346                    return;
347                }
348                let draw_item = &mut cxview.draw_items[inst.draw_item_id];
349                //log!("{:?}", draw_item.kind.sub_list().is_some());
350                let draw_call = draw_item.kind.draw_call().unwrap();
351                if cx.draw_shaders.generation != draw_call.draw_shader.draw_shader_generation {
352                    return;
353                }
354                let sh = &cx.draw_shaders[draw_call.draw_shader.draw_shader_id]; // ok now we have to patch x/y/w/h into it
355                let buf = draw_item.instances.as_mut().unwrap();
356                if let Some(rect_pos) = sh.mapping.rect_pos {
357                    buf[inst.instance_offset + rect_pos + 0] = rect.pos.x as f32;
358                    buf[inst.instance_offset + rect_pos + 1] = rect.pos.y as f32;
359                }
360                if let Some(rect_size) = sh.mapping.rect_size {
361                    buf[inst.instance_offset + rect_size + 0] = rect.size.x as f32;
362                    buf[inst.instance_offset + rect_size + 1] = rect.size.y as f32;
363                }
364            },
365            Area::Rect(ra) => {
366                let draw_list = &mut cx.draw_lists[ra.draw_list_id];
367                let rect_area = &mut draw_list.rect_areas[ra.rect_id];
368                rect_area.rect = *rect
369            },
370            _ => ()
371        }
372    }
373    
374    pub fn get_read_ref<'a>(&self, cx: &'a Cx, id: LiveId, ty: ShaderTy) -> Option<DrawReadRef<'a >> {
375        match self {
376            Area::Instance(inst) => {
377                let draw_list = &cx.draw_lists[inst.draw_list_id];
378                let draw_item = &draw_list.draw_items[inst.draw_item_id];
379                let draw_call = draw_item.draw_call().unwrap();
380                if draw_list.redraw_id != inst.redraw_id {
381                    error!("get_instance_read_ref called on invalid area pointer, use mark/sweep correctly!");
382                    return None;
383                }
384                if cx.draw_shaders.generation != draw_call.draw_shader.draw_shader_generation {
385                    return None;
386                }
387                let sh = &cx.draw_shaders[draw_call.draw_shader.draw_shader_id];
388                if let Some(input) = sh.mapping.user_uniforms.inputs.iter().find( | input | input.id == id) {
389                    if input.ty != ty {
390                        panic!("get_read_ref wrong uniform type, expected {:?} got: {:?}!", input.ty, ty);
391                    }
392                    return Some(
393                        DrawReadRef {
394                            repeat: 1,
395                            stride: 0,
396                            buffer: &draw_call.user_uniforms[input.offset..]
397                        }
398                    )
399                }
400                if let Some(input) = sh.mapping.instances.inputs.iter().find( | input | input.id == id) {
401                    if input.ty != ty {
402                        panic!("get_read_ref wrong instance type, expected {:?} got: {:?}!", input.ty, ty);
403                    }
404                    if inst.instance_count == 0 {
405                        return None
406                    }
407                    return Some(
408                        DrawReadRef {
409                            repeat: inst.instance_count,
410                            stride: sh.mapping.instances.total_slots,
411                            buffer: &draw_item.instances.as_ref().unwrap()[(inst.instance_offset + input.offset)..],
412                        }
413                    )
414                }
415                panic!("get_read_ref property not found! {}", id);
416            }
417            _ => (),
418        }
419        None
420    }
421    
422    pub fn get_write_ref<'a>(&self, cx: &'a mut Cx, id: LiveId, ty: ShaderTy, name: &str) -> Option<DrawWriteRef<'a >> {
423        match self {
424            Area::Instance(inst) => {
425                let draw_list = &mut cx.draw_lists[inst.draw_list_id];
426                if draw_list.redraw_id != inst.redraw_id {
427                    return None;
428                }
429                let draw_item = &mut draw_list.draw_items[inst.draw_item_id];
430                let draw_call = draw_item.kind.draw_call_mut().unwrap();
431                if cx.draw_shaders.generation != draw_call.draw_shader.draw_shader_generation {
432                    return None;
433                }
434                let sh = &cx.draw_shaders[draw_call.draw_shader.draw_shader_id];
435                
436                if let Some(input) = sh.mapping.user_uniforms.inputs.iter().find( | input | input.id == id) {
437                    if input.ty != ty {
438                        panic!("get_write_ref {} wrong uniform type, expected {:?} got: {:?}!", name, input.ty, ty);
439                    }
440                    
441                    cx.passes[draw_list.pass_id.unwrap()].paint_dirty = true;
442                    draw_call.uniforms_dirty = true;
443                    
444                    return Some(
445                        DrawWriteRef {
446                            repeat: 1,
447                            stride: 0,
448                            buffer: &mut draw_call.user_uniforms[input.offset..]
449                        }
450                    )
451                }
452                if let Some(input) = sh.mapping.instances.inputs.iter().find( | input | input.id == id) {
453                    if input.ty != ty {
454                        panic!("get_write_ref {} wrong instance type, expected {:?} got: {:?}!", name, input.ty, ty);
455                    }
456                    
457                    cx.passes[draw_list.pass_id.unwrap()].paint_dirty = true;
458                    draw_call.instance_dirty = true;
459                    if inst.instance_count == 0 {
460                        return None
461                    }
462                    return Some(
463                        DrawWriteRef {
464                            repeat: inst.instance_count,
465                            stride: sh.mapping.instances.total_slots,
466                            buffer: &mut draw_item.instances.as_mut().unwrap()[(inst.instance_offset + input.offset)..]
467                        }
468                    )
469                }
470                panic!("get_write_ref {} property not found!", name);
471            }
472            _ => (),
473        }
474        None
475    }
476}
477