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