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 { pub view_id: Option<usize>,
15 pub is_clipped: bool,
16 pub is_overlay: bool, 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 let pass_id = *cx.pass_stack.last().expect("No pass found when begin_view");
47
48 if self.view_id.is_none() { 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 { 0
67 };
68
69 let (override_layout, is_root_for_pass) = if cx.passes[pass_id].main_view_id.is_none() {
70 let cxpass = &mut cx.passes[pass_id];
72 cxpass.main_view_id = Some(view_id);
73 (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 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 { view_id
99 }
100 };
101
102 if view_id != parent_view_id {
104 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 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 { 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 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 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 let cxview = &mut cx.views[view_id];
143
144 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 let draw_call_id = draw_list.draw_calls_len;
234 draw_list.draw_calls_len = draw_list.draw_calls_len + 1;
235
236 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 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; 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 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 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, pub shader_id: usize, pub shader_instance_id: usize,
383 pub instance: Vec<f32>,
384 pub current_instance_offset: usize, pub draw_uniforms: DrawUniforms, pub uniforms: Vec<f32>, 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, pub redraw_id: u64,
468 pub pass_id: usize,
469 pub do_v_scroll: bool, 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 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 for i in 0..16 {
554 self.view_uniforms.view_transform[i] = v.v[i];
555 }
556 }
557
558}