makepad_render/
view.rs

1use crate::cx::*;
2
3#[derive(Clone)]
4pub struct ViewTexture {
5    sample_count: usize,
6    has_depth_stencil: bool,
7    fixed_size: Option<Vec2>
8}
9
10pub type ViewRedraw = Result<(), ()>;
11
12#[derive(Clone)]
13pub struct View { // draw info per UI element
14    pub view_id: Option<usize>,
15    pub is_clipped: bool,
16    pub is_overlay: bool, // this view is an overlay, rendered last
17    pub always_redraw: bool,
18}
19
20impl View {
21    pub fn proto_overlay(_cx: &mut Cx) -> Self {
22        Self {
23            is_clipped: true,
24            is_overlay: true,
25            always_redraw: false,
26            view_id: None,
27        }
28    }
29    
30    pub fn new(_cx: &mut Cx) -> Self {
31        Self {
32            is_clipped: true,
33            is_overlay: false,
34            always_redraw: false,
35            view_id: None,
36        }
37    }
38    
39    pub fn begin_view(&mut self, cx: &mut Cx, layout: Layout) -> ViewRedraw {
40        
41        if !cx.is_in_redraw_cycle {
42            panic!("calling begin_view outside of redraw cycle is not possible!");
43        }
44        
45        // check if we have a pass id parent
46        let pass_id = *cx.pass_stack.last().expect("No pass found when begin_view");
47        
48        if self.view_id.is_none() { // we need a draw_list_id
49            if cx.views_free.len() != 0 {
50                self.view_id = Some(cx.views_free.pop().unwrap());
51            }
52            else {
53                self.view_id = Some(cx.views.len());
54                cx.views.push(CxView {do_v_scroll: true, do_h_scroll: true, ..Default::default()});
55            }
56            let cxview = &mut cx.views[self.view_id.unwrap()];
57            cxview.initialize(pass_id, self.is_clipped, cx.redraw_id);
58        }
59        
60        let view_id = self.view_id.unwrap();
61        
62        let nesting_view_id = if cx.view_stack.len() > 0 {
63            *cx.view_stack.last().unwrap()
64        }
65        else { // return the root draw list
66            0
67        };
68        
69        let (override_layout, is_root_for_pass) = if cx.passes[pass_id].main_view_id.is_none() {
70            // we are the first view on a window
71            let cxpass = &mut cx.passes[pass_id];
72            cxpass.main_view_id = Some(view_id);
73            // we should take the window geometry and abs position as our turtle layout
74            (Layout {
75                abs_origin: Some(Vec2 {x: 0., y: 0.}),
76                abs_size: Some(cxpass.pass_size),
77                ..layout
78            }, true)
79        }
80        else {
81            (layout, false)
82        };
83        
84        let cxpass = &mut cx.passes[pass_id];
85        // find the parent draw list id
86        let parent_view_id = if self.is_overlay {
87            if cxpass.main_view_id.is_none() {
88                panic!("Cannot make overlay inside window without root view")
89            };
90            let main_view_id = cxpass.main_view_id.unwrap();
91            main_view_id
92        }
93        else {
94            if let Some(last_view_id) = cx.view_stack.last() {
95                *last_view_id
96            }
97            else { // we have no parent
98                view_id
99            }
100        };
101        
102        // push ourselves up the parent draw_stack
103        if view_id != parent_view_id {
104            // we need a new draw
105            let parent_cxview = &mut cx.views[parent_view_id];
106            
107            let id = parent_cxview.draw_calls_len;
108            parent_cxview.draw_calls_len = parent_cxview.draw_calls_len + 1;
109            
110            // see if we need to add a new one
111            if parent_cxview.draw_calls_len > parent_cxview.draw_calls.len() {
112                parent_cxview.draw_calls.push({
113                    DrawCall {
114                        view_id: parent_view_id,
115                        draw_call_id: parent_cxview.draw_calls.len(),
116                        redraw_id: cx.redraw_id,
117                        sub_view_id: view_id,
118                        ..Default::default()
119                    }
120                })
121            }
122            else { // or reuse a sub list node
123                let draw = &mut parent_cxview.draw_calls[id];
124                draw.sub_view_id = view_id;
125                draw.redraw_id = cx.redraw_id;
126            }
127        }
128        
129        // set nesting draw list id for incremental repaint scanning
130        cx.views[view_id].nesting_view_id = nesting_view_id;
131        
132        if !self.always_redraw && cx.views[view_id].draw_calls_len != 0 && !cx.view_will_redraw(view_id) {
133            
134            // walk the turtle because we aren't drawing
135            let w = Width::Fix(cx.views[view_id].rect.w);
136            let h = Height::Fix(cx.views[view_id].rect.h);
137            cx.walk_turtle(Walk {width: w, height: h, margin: override_layout.walk.margin});
138            return Err(());
139        }
140        
141        // prepare drawlist for drawing
142        let cxview = &mut cx.views[view_id];
143        
144        // update drawlist ids
145        cxview.redraw_id = cx.redraw_id;
146        cxview.draw_calls_len = 0;
147        
148        cx.view_stack.push(view_id);
149        
150        cx.begin_turtle(override_layout, Area::View(ViewArea {
151            view_id: view_id,
152            redraw_id: cx.redraw_id
153        }));
154        
155        if is_root_for_pass {
156            cx.passes[pass_id].paint_dirty = true;
157        }
158        
159        Ok(())
160    }
161    
162    pub fn view_will_redraw(&mut self, cx: &mut Cx) -> bool {
163        if let Some(view_id) = self.view_id {
164            cx.view_will_redraw(view_id)
165        }
166        else {
167            true
168        }
169    }
170    
171    pub fn end_view(&mut self, cx: &mut Cx) -> Area {
172        let view_id = self.view_id.unwrap();
173        let view_area = Area::View(ViewArea {view_id: view_id, redraw_id: cx.redraw_id});
174        let rect = cx.end_turtle(view_area);
175        let cxview = &mut cx.views[view_id];
176        cxview.rect = rect;
177        cx.view_stack.pop();
178        view_area
179    }
180    
181    pub fn get_rect(&mut self, cx: &Cx) -> Rect {
182        if let Some(view_id) = self.view_id {
183            let cxview = &cx.views[view_id];
184            return cxview.rect
185        }
186        Rect::default()
187    }
188    
189    
190    pub fn redraw_view_area(&self, cx: &mut Cx) {
191        if let Some(view_id) = self.view_id {
192            let cxview = &cx.views[view_id];
193            let area = Area::View(ViewArea {view_id: view_id, redraw_id: cxview.redraw_id});
194            cx.redraw_child_area(area);
195        }
196        else {
197            cx.redraw_child_area(Area::All)
198        }
199    }
200    
201    pub fn redraw_view_parent_area(&self, cx: &mut Cx) {
202        if let Some(view_id) = self.view_id {
203            let cxview = &cx.views[view_id];
204            let area = Area::View(ViewArea {view_id: view_id, redraw_id: cxview.redraw_id});
205            cx.redraw_parent_area(area);
206        }
207        else {
208            cx.redraw_parent_area(Area::All)
209        }
210    }
211    
212    pub fn get_view_area(&self, cx: &Cx) -> Area {
213        if let Some(view_id) = self.view_id {
214            let cxview = &cx.views[view_id];
215            Area::View(ViewArea {view_id: view_id, redraw_id: cxview.redraw_id})
216        }
217        else {
218            Area::Empty
219        }
220    }
221}
222
223impl Cx {
224    
225    pub fn new_instance_draw_call(&mut self, shader: &Shader, instance_count: usize) -> InstanceArea {
226        let (shader_id, shader_instance_id) = shader.shader_id.unwrap();
227        let sh = &self.shaders[shader_id];
228        
229        let current_view_id = *self.view_stack.last().unwrap();
230        
231        let draw_list = &mut self.views[current_view_id];
232        // we need a new draw call
233        let draw_call_id = draw_list.draw_calls_len;
234        draw_list.draw_calls_len = draw_list.draw_calls_len + 1;
235        
236        // see if we need to add a new one
237        if draw_call_id >= draw_list.draw_calls.len() {
238            draw_list.draw_calls.push(DrawCall {
239                draw_call_id: draw_call_id,
240                view_id: current_view_id,
241                redraw_id: self.redraw_id,
242                do_h_scroll: true,
243                do_v_scroll: true,
244                sub_view_id: 0,
245                shader_id: shader_id,
246                shader_instance_id: shader_instance_id,
247                uniforms_required: sh.mapping.uniform_props.total_slots,
248                instance: Vec::new(),
249                draw_uniforms: DrawUniforms::default(),
250                uniforms: Vec::new(),
251                textures_2d: Vec::new(),
252                current_instance_offset: 0,
253                instance_dirty: true,
254                uniforms_dirty: true,
255                platform: CxPlatformDrawCall::default()
256            });
257            let dc = &mut draw_list.draw_calls[draw_call_id];
258            return dc.get_current_instance_area(instance_count);
259        }
260        
261        // reuse a draw
262        let dc = &mut draw_list.draw_calls[draw_call_id];
263        dc.shader_id = shader_id;
264        dc.shader_instance_id = shader_instance_id;
265        dc.uniforms_required = sh.mapping.uniform_props.total_slots;
266        dc.sub_view_id = 0; // make sure its recognised as a draw call
267        // truncate buffers and set update frame
268        dc.redraw_id = self.redraw_id;
269        dc.instance.truncate(0);
270        dc.current_instance_offset = 0;
271        dc.uniforms.truncate(0);
272        dc.textures_2d.truncate(0); 
273        dc.instance_dirty = true;
274        dc.uniforms_dirty = true;
275        dc.do_h_scroll = true;
276        dc.do_v_scroll = true;
277        return dc.get_current_instance_area(instance_count);
278    }
279    
280    pub fn new_instance(&mut self, shader: &Shader, instance_count: usize) -> InstanceArea {
281        let (shader_id, shader_instance_id) = shader.shader_id.expect("shader id invalid");
282        if !self.is_in_redraw_cycle {
283            panic!("calling new_instance outside of redraw cycle is not possible!");
284        }
285        let current_view_id = *self.view_stack.last().expect("view stack is empty");
286        let draw_list = &mut self.views[current_view_id];
287        let sh = &self.shaders[shader_id];
288        // find our drawcall to append to the current layer
289        if draw_list.draw_calls_len > 0 {
290            for i in (0..draw_list.draw_calls_len).rev() {
291                let dc = &mut draw_list.draw_calls[i];
292                if dc.sub_view_id == 0 && dc.shader_id == shader_id && dc.shader_instance_id == shader_instance_id {
293                    // reuse this drawcmd and add an instance
294                    dc.current_instance_offset = dc.instance.len();
295                    let slot_align = dc.instance.len() % sh.mapping.instance_slots;
296                    if slot_align != 0 {
297                        panic!("Instance offset disaligned! shader: {} misalign: {} slots: {}", shader_id, slot_align, sh.mapping.instance_slots);
298                    }
299                    return dc.get_current_instance_area(instance_count);
300                }
301            }
302        }
303        
304        self.new_instance_draw_call(shader, instance_count)
305    }
306    
307    pub fn align_instance(&mut self, instance_area: InstanceArea) -> AlignedInstance {
308        let align_index = self.align_list.len();
309        self.align_list.push(Area::Instance(instance_area.clone()));
310        AlignedInstance {
311            inst: instance_area,
312            index: align_index
313        }
314    }
315    
316    pub fn update_aligned_instance_count(&mut self, aligned_instance: &AlignedInstance) {
317        if let Area::Instance(instance) = &mut self.align_list[aligned_instance.index] {
318            instance.instance_count = aligned_instance.inst.instance_count;
319        }
320    }
321    
322    pub fn set_view_scroll_x(&mut self, view_id: usize, scroll_pos: f32) {
323        let fac = self.get_delegated_dpi_factor(self.views[view_id].pass_id);
324        let cxview = &mut self.views[view_id];
325        cxview.unsnapped_scroll.x = scroll_pos;
326        let snapped = scroll_pos - scroll_pos % (1.0 / fac);
327        if cxview.snapped_scroll.x != snapped {
328            cxview.snapped_scroll.x = snapped;
329            self.passes[cxview.pass_id].paint_dirty = true;
330        }
331    }
332    
333    
334    pub fn set_view_scroll_y(&mut self, view_id: usize, scroll_pos: f32) {
335        let fac = self.get_delegated_dpi_factor(self.views[view_id].pass_id);
336        let cxview = &mut self.views[view_id];
337        cxview.unsnapped_scroll.y = scroll_pos;
338        let snapped = scroll_pos - scroll_pos % (1.0 / fac);
339        if cxview.snapped_scroll.y != snapped {
340            cxview.snapped_scroll.y = snapped;
341            self.passes[cxview.pass_id].paint_dirty = true;
342        }
343    }
344}
345
346#[derive(Clone)]
347pub struct AlignedInstance {
348    pub inst: InstanceArea,
349    pub index: usize
350}
351
352#[derive(Default, Clone)]
353#[repr(C)]
354pub struct DrawUniforms {
355    pub draw_clip_x1: f32,
356    pub draw_clip_y1: f32,
357    pub draw_clip_x2: f32,
358    pub draw_clip_y2: f32,
359    pub draw_scroll_x: f32,
360    pub draw_scroll_y: f32,
361    pub draw_scroll_z: f32,
362    pub draw_scroll_w: f32,
363    pub draw_zbias: f32,
364    pub pad1: f32,
365    pub pad2: f32,
366    pub pad3: f32
367}
368
369impl DrawUniforms {
370    pub fn as_slice(&self) -> &[f32; std::mem::size_of::<DrawUniforms>()] {
371        unsafe {std::mem::transmute(self)}
372    }
373}
374
375#[derive(Default, Clone)]
376pub struct DrawCall {
377    pub draw_call_id: usize,
378    pub view_id: usize,
379    pub redraw_id: u64,
380    pub sub_view_id: usize, // if not 0, its a subnode
381    pub shader_id: usize, // if shader_id changed, delete gl vao
382    pub shader_instance_id: usize,
383    pub instance: Vec<f32>,
384    pub current_instance_offset: usize, // offset of current instance
385    
386    pub draw_uniforms: DrawUniforms, // draw uniforms
387    
388    pub uniforms: Vec<f32>, // user uniforms
389    pub uniforms_required: usize,
390    
391    pub do_v_scroll: bool,
392    pub do_h_scroll: bool,
393    
394    pub textures_2d: Vec<u32>,
395    pub instance_dirty: bool,
396    pub uniforms_dirty: bool,
397    pub platform: CxPlatformDrawCall
398}
399
400impl DrawCall {
401    pub fn need_uniforms_now(&self) -> bool {
402        self.uniforms.len() < self.uniforms_required
403    }
404    
405    pub fn set_local_scroll(&mut self, scroll: Vec2, local_scroll: Vec2) {
406        self.draw_uniforms.draw_scroll_x = scroll.x;
407        if self.do_h_scroll {
408            self.draw_uniforms.draw_scroll_x += local_scroll.x;
409        }
410        self.draw_uniforms.draw_scroll_y = scroll.y;
411        if self.do_v_scroll {
412            self.draw_uniforms.draw_scroll_y += local_scroll.y;
413        }
414        self.draw_uniforms.draw_scroll_z = local_scroll.x;
415        self.draw_uniforms.draw_scroll_w = local_scroll.y;
416    }
417    
418    pub fn set_zbias(&mut self, zbias:f32){
419        self.draw_uniforms.draw_zbias = zbias;
420    }
421    
422    pub fn set_clip(&mut self, clip: (Vec2, Vec2)) {
423        self.draw_uniforms.draw_clip_x1 = clip.0.x;
424        self.draw_uniforms.draw_clip_y1 = clip.0.y;
425        self.draw_uniforms.draw_clip_x2 = clip.1.x;
426        self.draw_uniforms.draw_clip_y2 = clip.1.y;
427    }
428    
429    pub fn get_current_instance_area(&self, instance_count: usize) -> InstanceArea {
430        InstanceArea {
431            view_id: self.view_id,
432            draw_call_id: self.draw_call_id,
433            redraw_id: self.redraw_id,
434            instance_offset: self.current_instance_offset,
435            instance_count: instance_count
436        }
437    }
438    
439    pub fn clip_and_scroll_rect(&self, x: f32, y: f32, w: f32, h: f32) -> Rect {
440        let mut x1 = x - self.draw_uniforms.draw_scroll_x;
441        let mut y1 = y - self.draw_uniforms.draw_scroll_y;
442        let mut x2 = x1 + w;
443        let mut y2 = y1 + h;
444        x1 = self.draw_uniforms.draw_clip_x1.max(x1).min(self.draw_uniforms.draw_clip_x2);
445        y1 = self.draw_uniforms.draw_clip_y1.max(y1).min(self.draw_uniforms.draw_clip_y2);
446        x2 = self.draw_uniforms.draw_clip_x1.max(x2).min(self.draw_uniforms.draw_clip_x2);
447        y2 = self.draw_uniforms.draw_clip_y1.max(y2).min(self.draw_uniforms.draw_clip_y2);
448        return Rect {x: x1, y: y1, w: x2 - x1, h: y2 - y1};
449    }
450}
451
452#[derive(Default, Clone)]
453#[repr(C)]
454pub struct ViewUniforms {
455    view_transform: [f32; 16],
456}
457
458impl ViewUniforms {
459    pub fn as_slice(&self) -> &[f32; std::mem::size_of::<ViewUniforms>()] {
460        unsafe {std::mem::transmute(self)}
461    }
462}
463
464#[derive(Default, Clone)]
465pub struct CxView {
466    pub nesting_view_id: usize, // the id of the parent we nest in, codeflow wise
467    pub redraw_id: u64,
468    pub pass_id: usize,
469    pub do_v_scroll: bool, // this means we
470    pub do_h_scroll: bool,
471    pub draw_calls: Vec<DrawCall>,
472    pub draw_calls_len: usize,
473    pub parent_scroll: Vec2,
474    pub view_uniforms: ViewUniforms,
475    pub unsnapped_scroll: Vec2,
476    pub snapped_scroll: Vec2,
477    pub platform: CxPlatformView,
478    pub rect: Rect,
479    pub clipped: bool
480}
481
482impl CxView { 
483    pub fn initialize(&mut self, pass_id: usize, clipped: bool, redraw_id: u64) {
484        self.clipped = clipped;
485        self.redraw_id = redraw_id;
486        self.pass_id = pass_id; 
487    } 
488    
489    pub fn get_scrolled_rect(&self)->Rect{
490        Rect{
491            x:self.rect.x + self.parent_scroll.x,
492            y:self.rect.y + self.parent_scroll.y,
493            w:self.rect.w, 
494            h:self.rect.h ,
495        }
496    }
497
498    pub fn get_inverse_scrolled_rect(&self)->Rect{
499        Rect{
500            x:self.rect.x - self.parent_scroll.x,
501            y:self.rect.y - self.parent_scroll.y,
502            w:self.rect.w, 
503            h:self.rect.h ,
504        }
505    }
506    
507    pub fn intersect_clip(&self, clip: (Vec2, Vec2)) -> (Vec2, Vec2) {
508        if self.clipped {
509            let min_x = self.rect.x - self.parent_scroll.x;
510            let min_y = self.rect.y - self.parent_scroll.y;
511            let max_x = self.rect.x + self.rect.w - self.parent_scroll.x;
512            let max_y = self.rect.y + self.rect.h - self.parent_scroll.y;
513            
514            (Vec2 {
515                x: min_x.max(clip.0.x),
516                y: min_y.max(clip.0.y)
517            }, Vec2 {
518                x: max_x.min(clip.1.x),
519                y: max_y.min(clip.1.y)
520            })
521        }
522        else {
523            clip
524        }
525    }
526    /*
527    pub fn set_clipping_uniforms(&mut self) {
528        if self.clipped {
529           self.uniform_view_clip(self.rect.x, self.rect.y, self.rect.x + self.rect.w, self.rect.y + self.rect.h);
530        }
531        else {
532            self.uniform_view_clip(-50000.0, -50000.0, 50000.0, 50000.0);
533        }
534    }*/
535    
536    pub fn get_local_scroll(&self) -> Vec2 {
537        let xs = if self.do_v_scroll {self.snapped_scroll.x}else {0.};
538        let ys = if self.do_h_scroll {self.snapped_scroll.y}else {0.};
539        Vec2 {x: xs, y: ys}
540    }
541    
542    pub fn def_uniforms(sg: ShaderGen) -> ShaderGen {
543        sg.compose(shader_ast!({
544            let view_transform: mat4<ViewUniform>;
545            let draw_clip: vec4<DrawUniform>;
546            let draw_scroll: vec4<DrawUniform>;
547            let draw_zbias: float<DrawUniform>;
548        }))
549    }
550    
551    pub fn uniform_view_transform(&mut self, v: &Mat4) {
552        //dump in uniforms
553        for i in 0..16 {
554            self.view_uniforms.view_transform[i] = v.v[i];
555        }
556    }
557    
558}