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 { 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 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 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 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 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 cx.cx.draw_lists[self.draw_list.id()].codeflow_parent_id = codeflow_parent_id;
166
167 if cx.cx.draw_lists[self.draw_list.id()].draw_items.len() != 0 && !will_redraw {
169 return Redrawing::no();
177 }
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 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 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