1#![allow(dead_code)]
2use std::{cell::RefCell, collections::HashMap, fs, path::PathBuf, rc::Rc};
3
4use glam::Vec2;
5use murrelet_common::MurreletTime;
6use serde::Serialize;
7
8use crate::{
9 device_state::{DeviceStateForRender, GraphicsAssets, GraphicsWindowConf},
10 gpu_livecode::ControlGraphicsRef,
11 graphics_ref::{
12 BasicUniform, Graphics, GraphicsCreator, GraphicsRef, GraphicsRefWithControlFn,
13 DEFAULT_LOADED_TEXTURE_FORMAT,
14 },
15 shader_str::*,
16};
17
18#[cfg(feature = "nannou")]
19use wgpu_for_nannou as wgpu;
20
21#[cfg(not(feature = "nannou"))]
22use wgpu_for_latest as wgpu;
23
24const DEFAULT_TEXTURE_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Rgba16Float;
27
28#[macro_export]
47macro_rules! build_shader {
48 (@parse ()) => {{""}}; (@parse (raw $raw:expr;$($tail:tt)*)) => {
61 {
62 let rest = build_shader!(@parse ($($tail)*));
63 format!("{}\n{}", $raw, rest)
64 }
65 };
66
67 (@parsecode ()) => {{""}}; (@parsecode (raw $raw:expr;$($tail:tt)*)) => {
70 {
71 let rest = build_shader!(@parsecode ($($tail)*));
72 format!("{}\n{}", $raw, rest)
73 }
74 };
75
76 (@parse (($($tail:tt)*))) => {
78 {
79 let prefix = ShaderStr::Prefix.to_str();
80 let rest = build_shader!(@parsecode ($($tail)*));
81 let suffix = ShaderStr::Suffix.to_str();
82 format!("{}\n{}\n{}", prefix, rest, suffix)
83 }
84 }; (@parse $($raw:tt)*) => {
88 {
89 println!("???");
90 "???"
91 }
93 };
94
95 ($($raw:tt)*) => {
97 {
98 format!(
99 "{}\n{}\n{}",
100 ShaderStr::Binding1Tex.to_str(),
101 ShaderStr::Includes.to_str(),
102 build_shader!(@parse ($($raw)*)),
103 )
104 }
105 };
106}
107
108pub enum ShaderStr {
110 Binding1Tex,
111 Binding2Tex,
112 Binding3d,
113 Includes,
114 Prefix,
115 Suffix,
116}
117impl ShaderStr {
118 pub fn to_str(&self) -> &str {
119 match self {
120 ShaderStr::Binding1Tex => BINDING_1TEX,
121 ShaderStr::Binding2Tex => BINDING_2TEX,
122 ShaderStr::Includes => INCLUDES,
123 ShaderStr::Prefix => PREFIX,
124 ShaderStr::Suffix => SUFFIX,
125 ShaderStr::Binding3d => BINDING_3D,
126 }
127 }
128}
129
130#[macro_export]
131macro_rules! build_shader_2tex {
132 ($($raw:tt)*) => {
134 {
135 format!(
136 "{}\n{}\n{}",
137 ShaderStr::Binding2Tex.to_str(),
138 ShaderStr::Includes.to_str(),
139 build_shader!(@parse ($($raw)*)),
140 )
141 }
142 };
143}
144
145#[macro_export]
146macro_rules! build_shader_3d {
147 ($($raw:tt)*) => {
148 {
149 format!(
150 "{}\n{}\n{}",
151 ShaderStr::Binding3d.to_str(),
152 ShaderStr::Includes.to_str(),
153 build_shader!(@parse ($($raw)*)),
154 )
155 }
156 };
157}
158
159#[derive(Serialize)]
160pub struct RenderDebugPrint {
161 pub src: String,
162 pub dest: String,
163}
164
165#[derive(Serialize)]
166pub struct WrappedRenderDebugPrint {
167 pub idx: String,
168 pub r: RenderDebugPrint,
169}
170
171pub trait RenderTrait {
172 fn render(&self, device_state_for_render: &DeviceStateForRender);
173 fn debug_print(&self) -> Vec<RenderDebugPrint>;
174
175 fn dest(&self) -> Option<GraphicsRef>;
176
177 fn is_choice(&self) -> bool {
179 false
180 }
181
182 fn adjust_choice(&mut self, _choice_val: usize) {}
183}
184
185pub struct SimpleRender {
186 pub source: GraphicsRef,
187 pub dest: GraphicsRef,
188}
189impl SimpleRender {
190 pub fn new_box(source: GraphicsRef, dest: GraphicsRef) -> Box<SimpleRender> {
191 Box::new(SimpleRender { source, dest })
192 }
193
194 fn dest(&self) -> Option<GraphicsRef> {
195 Some(self.dest.clone())
196 }
197}
198
199impl RenderTrait for SimpleRender {
200 fn render(&self, device: &DeviceStateForRender) {
201 self.source.render(device.device_state(), &self.dest);
202 }
203
204 fn debug_print(&self) -> Vec<RenderDebugPrint> {
205 vec![RenderDebugPrint {
206 src: self.source.name(),
207 dest: self.dest.name(),
208 }]
209 }
210
211 fn dest(&self) -> Option<GraphicsRef> {
212 Some(self.dest.clone())
213 }
214}
215
216pub struct TwoSourcesRender {
217 pub source_main: GraphicsRef,
218 pub source_other: GraphicsRef,
219 pub dest: GraphicsRef,
220}
221impl TwoSourcesRender {
222 pub fn new_box(
223 source_main: GraphicsRef,
224 source_other: GraphicsRef,
225 dest: GraphicsRef,
226 ) -> Box<TwoSourcesRender> {
227 Box::new(TwoSourcesRender {
228 source_main,
229 source_other,
230 dest,
231 })
232 }
233
234 fn dest(&self) -> Option<GraphicsRef> {
235 Some(self.dest.clone())
236 }
237}
238
239impl RenderTrait for TwoSourcesRender {
240 fn render(&self, device: &DeviceStateForRender) {
241 self.source_main.render(device.device_state(), &self.dest);
242 self.source_other
243 .render_2tex(device.device_state(), &self.dest);
244 }
245
246 fn debug_print(&self) -> Vec<RenderDebugPrint> {
247 vec![
248 RenderDebugPrint {
249 src: self.source_main.name(),
250 dest: self.dest.name(),
251 },
252 RenderDebugPrint {
253 src: self.source_other.name(),
254 dest: self.dest.name(),
255 },
256 ]
257 }
258
259 fn dest(&self) -> Option<GraphicsRef> {
260 Some(self.dest.clone())
261 }
262}
263
264pub struct PipelineRender<GraphicsConf> {
266 pub source: GraphicsRef,
267 pub pipeline: GPUPipelineRef<GraphicsConf>,
268 pub dest: GraphicsRef,
269}
270
271impl<GraphicsConf> PipelineRender<GraphicsConf> {
272 pub fn new_box(
273 source: GraphicsRef,
274 pipeline: GPUPipelineRef<GraphicsConf>,
275 dest: GraphicsRef,
276 ) -> Box<Self> {
277 Box::new(Self {
278 source,
279 pipeline,
280 dest,
281 })
282 }
283}
284impl<GraphicsConf> RenderTrait for PipelineRender<GraphicsConf> {
285 fn render(&self, device_state_for_render: &DeviceStateForRender) {
286 self.source.render(
288 device_state_for_render.device_state(),
289 &self.pipeline.source(),
290 );
291 self.pipeline.render(device_state_for_render);
292 }
293
294 fn debug_print(&self) -> Vec<RenderDebugPrint> {
295 self.pipeline.debug_print()
296 }
297
298 fn dest(&self) -> Option<GraphicsRef> {
299 Some(self.dest.clone())
300 }
301}
302
303pub struct ChoiceRender {
305 pub sources: Vec<GraphicsRef>,
306 pub dest: GraphicsRef,
307 choice: usize,
308}
309impl ChoiceRender {
310 pub fn new_box(sources: Vec<GraphicsRef>, dest: GraphicsRef) -> Box<ChoiceRender> {
311 Box::new(ChoiceRender {
312 sources,
313 dest,
314 choice: 0,
315 })
316 }
317}
318
319impl RenderTrait for ChoiceRender {
320 fn render(&self, device: &DeviceStateForRender) {
321 let source = &self.sources[self.choice % self.sources.len()];
322 let dest = &self.dest;
323 source.render(device.device_state(), dest);
324 }
325
326 fn debug_print(&self) -> Vec<RenderDebugPrint> {
327 todo!()
331 }
332
333 fn dest(&self) -> Option<GraphicsRef> {
334 Some(self.dest.clone())
335 }
336
337 fn is_choice(&self) -> bool {
338 true
339 }
340
341 fn adjust_choice(&mut self, choice_val: usize) {
343 self.choice = choice_val % self.sources.len()
344 }
345}
346
347pub struct PingPongRender {
348 pub k: usize,
349 pub ping: GraphicsRef, pub pong: GraphicsRef,
351}
352
353impl PingPongRender {
354 pub fn new_box(k: usize, ping: GraphicsRef, pong: GraphicsRef) -> Box<PingPongRender> {
355 Box::new(PingPongRender { k, ping, pong })
356 }
357}
358
359impl RenderTrait for PingPongRender {
360 fn render(&self, device: &DeviceStateForRender) {
361 let ping = &self.ping;
362 let pong = &self.pong;
363 for _ in 0..self.k {
364 ping.render(device.device_state(), &pong);
365 pong.render(device.device_state(), &ping);
366 }
367 }
368
369 fn debug_print(&self) -> Vec<RenderDebugPrint> {
370 let ping = &self.ping;
371 let pong = &self.pong;
372 vec![
373 RenderDebugPrint {
374 src: ping.name(),
375 dest: pong.name(),
376 },
377 RenderDebugPrint {
378 src: pong.name(),
379 dest: ping.name(),
380 },
381 RenderDebugPrint {
382 src: ping.name(),
383 dest: pong.name(),
384 },
385 RenderDebugPrint {
386 src: pong.name(),
387 dest: ping.name(),
388 },
389 ]
390 }
391
392 fn dest(&self) -> Option<GraphicsRef> {
393 Some(self.pong.clone())
394 }
395}
396
397pub struct TextureViewRender {
398 pub source: GraphicsRef,
399 pub dest: wgpu::TextureView,
400}
401
402impl TextureViewRender {
403 pub fn new_box(source: GraphicsRef, dest: wgpu::TextureView) -> Box<TextureViewRender> {
404 Box::new(TextureViewRender { source, dest })
405 }
406}
407
408impl RenderTrait for TextureViewRender {
409 fn render(&self, device: &DeviceStateForRender) {
410 let source = &self.source;
411 source.render_to_texture(device.device_state(), &self.dest);
412 }
413 fn debug_print(&self) -> Vec<RenderDebugPrint> {
414 let source = &self.source;
415 vec![RenderDebugPrint {
416 src: source.name(),
417 dest: "texture view!".to_string(),
418 }]
419 }
420
421 fn dest(&self) -> Option<GraphicsRef> {
422 None
423 }
424}
425
426pub struct DisplayRender {
427 pub source: GraphicsRef,
428}
429
430impl DisplayRender {
431 pub fn new_box(source: GraphicsRef) -> Box<DisplayRender> {
432 Box::new(DisplayRender { source })
433 }
434}
435
436impl RenderTrait for DisplayRender {
437 fn render(&self, device: &DeviceStateForRender) {
438 let source = &self.source;
439 source.render_to_texture(device.device_state(), device.display_view());
440 }
441 fn debug_print(&self) -> Vec<RenderDebugPrint> {
442 let source = &self.source;
443 vec![RenderDebugPrint {
444 src: source.name(),
445 dest: "output!".to_string(),
446 }]
447 }
448
449 fn dest(&self) -> Option<GraphicsRef> {
450 None
451 }
452}
453
454pub struct GPUPipeline<GraphicConf> {
455 pub dag: Vec<Box<dyn RenderTrait>>,
456 choices: Vec<usize>,
457 names: HashMap<String, GraphicsRef>, ctrl: Vec<GraphicsRefWithControlFn<GraphicConf>>,
459 source: Option<String>,
460}
461
462impl<GraphicConf> GPUPipeline<GraphicConf> {
463 pub fn new() -> GPUPipeline<GraphicConf> {
464 GPUPipeline {
465 dag: Vec::new(),
466 choices: Vec::new(),
467 names: HashMap::new(),
468 ctrl: Vec::new(),
469 source: None,
470 }
471 }
472
473 pub fn add_control_graphics(
474 &mut self,
475 _label: &str,
476 control_graphics_fn: GraphicsRefWithControlFn<GraphicConf>,
477 ) {
478 self.ctrl.push(control_graphics_fn)
479 }
480
481 pub fn control_graphics(&self, t: &GraphicConf) -> Vec<ControlGraphicsRef> {
482 let mut v = vec![];
483 for c in &self.ctrl {
484 v.extend(c.control_graphics(t).into_iter());
485 }
486 v
487 }
488
489 pub fn set_source(&mut self, src: &str) {
490 self.source = Some(src.to_string());
491 }
492
493 pub fn add_step(&mut self, d: Box<dyn RenderTrait>) {
494 let curr_idx = self.dag.len();
495
496 {
497 if d.is_choice() {
499 self.choices.push(curr_idx);
500 }
501 }
502
503 self.dag.push(d);
504 }
505
506 pub fn add_label(&mut self, name: &str, g: GraphicsRef) {
507 self.names.insert(name.to_string(), g);
508 }
509
510 pub fn get_graphic(&self, name: &str) -> Option<GraphicsRef> {
511 self.names.get(name).cloned()
512 }
513
514 pub fn adjust_choice(&mut self, choice_idx: usize, choice_val: usize) {
516 if choice_idx < self.choices.len() {
518 self.dag[self.choices[choice_idx]].adjust_choice(choice_val);
519 } else {
520 println!("what, that choice {:?} doesn't exist", choice_idx);
521 }
522 }
523
524 pub fn render(&self, device: &DeviceStateForRender) {
525 self.dag.iter().for_each(|x| x.render(device))
526 }
527
528 pub fn debug_print(&self) -> Vec<RenderDebugPrint> {
529 self.dag.iter().flat_map(|x| x.debug_print()).collect()
530 }
531
532 fn source(&self) -> GraphicsRef {
533 let name = self
535 .source
536 .as_ref()
537 .expect("should have set a source if you're gonna get it source");
538 self.get_graphic(&name)
539 .expect(&format!("gave a source {} that doesn't exist", name))
540 }
541}
542
543impl<GraphicsConf> Default for GPUPipeline<GraphicsConf> {
544 fn default() -> Self {
545 Self::new()
546 }
547}
548
549#[derive(Clone)]
550pub struct GPUPipelineRef<GraphicsConf>(Rc<RefCell<GPUPipeline<GraphicsConf>>>);
551
552impl<GraphicsConf> GPUPipelineRef<GraphicsConf> {
553 pub fn new(pipeline: GPUPipeline<GraphicsConf>) -> Self {
554 GPUPipelineRef(Rc::new(RefCell::new(pipeline)))
555 }
556
557 pub fn render(&self, device: &DeviceStateForRender) {
558 self.0.borrow().render(device)
559 }
560
561 pub fn debug_print(&self) -> Vec<RenderDebugPrint> {
562 self.0.borrow().debug_print()
563 }
564
565 pub fn source(&self) -> GraphicsRef {
566 self.0.borrow().source()
567 }
568
569 pub fn get_graphic(&self, name: &str) -> Option<GraphicsRef> {
570 self.0.borrow().get_graphic(name)
571 }
572
573 pub fn control_graphics(&self, conf: &GraphicsConf) -> Vec<ControlGraphicsRef> {
574 self.0.borrow().control_graphics(conf)
575 }
576}
577
578pub struct SingleTextureRender {
579 pub source: ImageTextureRef,
580 pub dest: GraphicsRef,
581}
582
583impl SingleTextureRender {
584 pub fn new_box(source: ImageTextureRef, dest: GraphicsRef) -> Box<SingleTextureRender> {
585 Box::new(SingleTextureRender { source, dest })
586 }
587}
588
589impl RenderTrait for SingleTextureRender {
590 fn render(&self, device_state_for_render: &DeviceStateForRender) {
592 let source_texture = &self.source;
593 let dest = &self.dest;
594 source_texture.render(device_state_for_render, dest);
595 }
596
597 fn debug_print(&self) -> Vec<RenderDebugPrint> {
598 let source = &self.source;
599 let dest = &self.dest;
600 vec![RenderDebugPrint {
601 src: source.name(),
602 dest: dest.name(),
603 }]
604 }
605
606 fn dest(&self) -> Option<GraphicsRef> {
607 Some(self.dest.clone())
608 }
609}
610
611#[macro_export]
613macro_rules! with_control_graphics {
614 ($name:ident = $instance:expr, |$param:ident: $ttype:ident| $body:expr) => {
615 let $name = $instance.with_control_graphics(
616 stringify!($name),
617 Arc::new(|$param: &$ttype| Box::new($body) as Box<dyn ControlGraphics>),
618 );
619 };
620}
621
622#[macro_export]
624macro_rules! pipeline_add_label {
625 ($pipeline:ident, $val:ident) => {{
626 $pipeline.add_label(stringify!($val), $val.graphics());
627 if let Some(ctrl) = $val.control_graphics_fn() {
628 $pipeline.add_control_graphics(stringify!($val), ctrl);
629 }
630 }};
631}
632
633#[macro_export]
634macro_rules! build_shader_pipeline {
635 () => {}; (@parse $pipeline:ident ()) => {}; (@parse $pipeline:ident ($source:ident -> DISPLAY;$($tail:tt)*)) => {
640 {
641 println!("add display");
642 $pipeline.add_step(
643 DisplayRender::new_box(
644 $source.graphics(),
645 )
646 );
647 pipeline_add_label!($pipeline, $source);
648
649 build_shader_pipeline!(@parse $pipeline ($($tail)*));
650 }
651 };
652
653 (@parse $pipeline:ident (*$source:ident -> $dest:ident;$($tail:tt)*)) => {
655 {
656 println!("add display");
657 $pipeline.add_step(
658 TextureRender::new_box(
659 $source.graphics(),
660 $dest.graphics(),
661 )
662 );
663 pipeline_add_label!($pipeline, $dest);
665
666 build_shader_pipeline!(@parse $pipeline ($($tail)*));
667 }
668 };
669
670 (@parse $pipeline:ident (+$source:ident -> $dest:ident;$($tail:tt)*)) => {
672 {
673 println!("add display");
674 $pipeline.add_step(
675 SingleTextureRender::new_box(
676 $source.clone(),
677 $dest.graphics(),
678 )
679 );
680 pipeline_add_label!($pipeline, $dest);
681
682 build_shader_pipeline!(@parse $pipeline ($($tail)*));
683 }
684 };
685
686 (@parse $pipeline:ident (($ping:ident <-> $pong:ident) * $count:expr;$($tail:tt)*)) => {
688 {
689 println!("add ping pong");
690 $pipeline.add_step(
691 PingPongRender::new_box(
692 $count,
693 $ping.graphics(),
694 $pong.graphics())
695 );
696 pipeline_add_label!($pipeline, $ping);
697 pipeline_add_label!($pipeline, $pong);
698
699 build_shader_pipeline!(@parse $pipeline ($($tail)*));
700 }
701 };
702
703 (@parse $pipeline:ident ([$source:ident$( | $source_rest:ident)*] -> $dest:ident;$($tail:tt)*)) => {
705 {
706 println!("add choice render $dest");
707 $pipeline.add_step(
708 ChoiceRender::new_box(
709 vec![
711 $source.graphics(),
712 $($source_rest.graphics(), )*
713 ],
714 $dest.graphics()
715 )
716 );
717 pipeline_add_label!($pipeline, $source);
718 $(pipeline_add_label!($pipeline, $source_rest);)*
719 pipeline_add_label!($pipeline, $dest);
720
721 build_shader_pipeline!(@parse $pipeline ($($tail)*));
722 }
723 };
724
725 (@parse $pipeline:ident (($source1:ident, $source2:ident) -> $dest:ident;$($tail:tt)*)) => {
727 {
728 println!("add two sources");
729
730 $pipeline.add_step(
731 TwoSourcesRender::new_box(
732 $source1.graphics(),
733 $source2.graphics(),
734 $dest.graphics())
735 );
736 pipeline_add_label!($pipeline, $source1);
737 pipeline_add_label!($pipeline, $source2);
738 pipeline_add_label!($pipeline, $dest);
739
740 build_shader_pipeline!(@parse $pipeline ($($tail)*));
741 }
742 };
743
744 (@parse $pipeline:ident ($source:ident -> $subpipe:ident => $dest:ident;$($tail:tt)*)) => {
746 {
747 println!("add pipeline");
748 let $dest = $subpipe.out().clone();
749 $pipeline.add_step(
750 PipelineRender::new_box(
751 $source.graphics(),
752 $subpipe.gpu_pipeline(),
753 $dest.graphics()
754 )
755 );
756 pipeline_add_label!($pipeline, $source);
757 pipeline_add_label!($pipeline, $dest);
758
759 build_shader_pipeline!(@parse $pipeline ($($tail)*));
760 }
761 };
762
763 (@parse $pipeline:ident ($source:ident -> $dest:ident;$($tail:tt)*)) => {
765 {
766 println!("add simple");
767 $pipeline.add_step(
768 SimpleRender::new_box(
769 $source.graphics(),
770 $dest.graphics()
771 )
772 );
773 pipeline_add_label!($pipeline, $source);
774 pipeline_add_label!($pipeline, $dest);
775
776 build_shader_pipeline!(@parse $pipeline ($($tail)*));
777 }
778 };
779
780 (@parse $($raw:tt)*) => {
782 {
783 println!("???");
784 unreachable!();
785 }
786 };
787
788 ($($raw:tt)*) => {
790 {
791 println!("new pipeline!");
792 let mut pipeline = GPUPipeline::new(); build_shader_pipeline!(@parse pipeline ($($raw)*));
794 pipeline
795 }
796 };
797}
798
799#[derive(Clone)]
800pub struct ImageTextureRef(Rc<RefCell<ImageTexture>>);
801impl ImageTextureRef {
802 pub fn render(&self, device_state_for_render: &DeviceStateForRender, dest: &GraphicsRef) {
803 self.0.borrow().render(device_state_for_render, dest)
804 }
805 pub fn name(&self) -> String {
806 self.0.borrow().graphics.name()
807 }
808
809 pub fn from_image_texture(im: ImageTexture) -> Self {
810 Self(Rc::new(RefCell::new(im)))
811 }
812}
813
814#[derive(Clone)]
815pub struct VideoTextureRef(Rc<RefCell<VideoTexture>>);
816pub struct VideoTexture {
817 name: String,
818 pub graphics: GraphicsRef,
819 pub binds: Vec<wgpu::BindGroup>, pub fps: u64,
821 last_time: Option<MurreletTime>,
822 curr_i: usize, }
824
825impl VideoTexture {
826 fn _load_path(path: &PathBuf, boomerang: bool) -> Vec<PathBuf> {
828 println!("reading path {:?}", path);
829 let paths = fs::read_dir(path).unwrap();
830 let mut p = paths
831 .filter_map(|entry| {
832 let entry = entry.unwrap();
833 let path = entry.path();
834 let metadata = fs::metadata(&path).unwrap();
835
836 if metadata.is_file()
837 && path
838 .extension()
839 .and_then(|x| x.to_str())
840 .map(|y| y == "png")
841 .unwrap_or(false)
842 {
843 println!("{:?}", entry);
844 Some(path)
845 } else {
846 None
847 }
848 })
849 .collect::<Vec<PathBuf>>();
850 p.sort_by(|a, b| a.file_name().cmp(&b.file_name()));
851
852 if boomerang {
853 let mut p2 = p.clone();
855 p2.reverse();
856 p2.pop();
857 p2.remove(0);
858
859 p.append(&mut p2);
860 }
861 p
862 }
863
864 pub fn overdue_for_an_update(&self) -> bool {
865 self.last_time
866 .map(|x| (MurreletTime::now() - x).as_millis_u128() >= (1000 / self.fps as u128))
868 .unwrap_or(true)
869 }
870
871 pub fn next_frame(&mut self) {
872 self.curr_i = (self.curr_i + 1) % self.binds.len();
873 self.last_time = Some(MurreletTime::now());
874 }
875
876 pub fn render(
877 &self,
878 device_state_for_render: &DeviceStateForRender,
879 output_texture_view: &wgpu::TextureView,
880 ) {
881 let bind_group = &self.binds[self.curr_i];
882 self.graphics.render_with_custom_bind_group(
883 device_state_for_render.device_state(),
884 output_texture_view,
885 bind_group,
886 )
887 }
888
889 pub fn new_mut(
890 c: &GraphicsWindowConf,
891 name: &str,
892 path: &[&str],
893 fps: u64,
894 boomerang: bool,
895 ) -> VideoTextureRef {
896 VideoTextureRef(Rc::new(RefCell::new(VideoTexture::new(
897 c, name, path, fps, boomerang,
898 ))))
899 }
900
901 pub fn new(
902 c: &GraphicsWindowConf,
903 name: &str,
904 raw_path: &[&str],
905 fps: u64,
906 boomerang: bool,
907 ) -> VideoTexture {
908 let device = c.device();
909
910 let assets_path = c.assets_path.force_path_buf();
911
912 let mut path = assets_path;
913 for loc in raw_path {
914 path = path.join(loc);
915 }
916
917 let src_paths = VideoTexture::_load_path(&path, boomerang);
918 assert!(src_paths.len() < 61); let source_dims = c.dims; let target_dims = c.dims;
926
927 let gradient_shader: String = build_shader! {
928 (
929 raw r###"
930 let multiplier = uniforms.more_info.x;
931 let source = uniforms.more_info_other.xy;
932 let targ = uniforms.more_info_other.za;
933
934 let multi = targ / source / multiplier;
935
936 let result: vec4<f32> = textureSample(tex, tex_sampler, tex_coords * multi);
937 "###;
938 )
939 };
940
941 let _uniforms = BasicUniform::from_dims(c.dims);
942
943 let conf = GraphicsCreator::default()
944 .with_first_texture_format(DEFAULT_TEXTURE_FORMAT)
945 .with_dst_format(DEFAULT_TEXTURE_FORMAT)
946 .with_mag_filter(wgpu::FilterMode::Linear)
947 .with_address_mode(wgpu::AddressMode::Repeat);
948
949 let graphics = GraphicsRef::new(name, c, &gradient_shader, &conf);
950 graphics.update_uniforms_other(
951 c,
952 [1.0, 0.0, 0.0, 0.0],
953 [
954 source_dims[0] as f32,
955 source_dims[1] as f32,
956 target_dims[0] as f32,
957 target_dims[1] as f32,
958 ],
959 );
960
961 let binds = src_paths
963 .iter()
964 .map(|path| {
965 let texture_and_desc =
967 Graphics::texture(source_dims, c.device(), DEFAULT_LOADED_TEXTURE_FORMAT);
968 GraphicsAssets::LocalFilesystem(path.to_path_buf())
969 .maybe_load_texture(c.device, &texture_and_desc.texture);
970 let texture_view =
971 texture_and_desc
972 .texture
973 .create_view(&wgpu::TextureViewDescriptor {
974 ..Default::default()
975 });
976 println!("texture {:?}", texture_view);
977 graphics
978 .graphics
979 .borrow()
980 .make_new_custom_bind_group(device, &texture_view)
981 })
982 .collect();
983
984 Self {
985 name: name.to_string(),
986 graphics,
987 binds,
988 fps,
989 last_time: None,
990 curr_i: 0,
991 }
992 }
993}
994
995pub struct ImageTexture {
996 name: String,
997 pub graphics: GraphicsRef,
998}
999
1000impl ImageTexture {
1001 pub fn render(&self, device_state_for_render: &DeviceStateForRender, other: &GraphicsRef) {
1002 self.graphics
1003 .render(device_state_for_render.device_state(), other);
1004 }
1005
1006 pub fn new_mut(
1007 name: &str,
1008 path: &PathBuf,
1009 c: &GraphicsWindowConf,
1010 address_mode: wgpu::AddressMode,
1011 ) -> ImageTextureRef {
1012 ImageTexture::new_mut_with_dims(name, path, c, address_mode)
1013 }
1014
1015 pub fn new_mut_with_dims(
1016 name: &str,
1017 path: &PathBuf,
1018 c: &GraphicsWindowConf,
1019 address_mode: wgpu::AddressMode,
1020 ) -> ImageTextureRef {
1021 ImageTextureRef(Rc::new(RefCell::new(ImageTexture::new(
1022 name,
1023 path,
1024 c,
1025 address_mode,
1026 ))))
1027 }
1028
1029 pub fn new(
1030 name: &str,
1031 src_path: &PathBuf,
1032 c: &GraphicsWindowConf,
1033 address_mode: wgpu::AddressMode,
1034 ) -> Self {
1035 let source_dims = c.dims; let target_dims = c.dims;
1042 println!("source: {:?} {:?}", source_dims, target_dims);
1043
1044 let repeat_img: String = build_shader! {
1045 (
1046 raw r###"
1047 // the sizes of the input and output maps are in pixels
1048 let entire_source_size_pxl = uniforms.more_info_other.xy;
1049 let target_size_pxl = uniforms.more_info_other.zw;
1050
1051 // let aspect = vec2<f32>(uniforms.dims.x / uniforms.dims.y);
1052
1053 let source_normalized_dims = vec2<f32>(1.0 / entire_source_size_pxl.x, 1.0 / entire_source_size_pxl.y); //uniforms.dims.zw;
1054
1055 // grab the intended size of the source window and offset.
1056 let windowed_source_size_pxl = uniforms.more_info.zw;
1057 let windowed_source_offset_pxl = uniforms.more_info.xy;
1058
1059 let windowed_source_offset_txl = windowed_source_offset_pxl * source_normalized_dims;
1060
1061 // how much of the source image should we sample?
1062 let window_to_entire_ratio = windowed_source_size_pxl / entire_source_size_pxl;
1063
1064 // how many times should we repeat the sampled image?
1065 let window_to_entire_multi = target_size_pxl / windowed_source_size_pxl;
1066
1067 // okay here we go
1068 // start with figuring out where in the square we should sample for
1069 let target_coords_txl1 = fract(tex_coords * window_to_entire_multi);
1070 // now figure out where in the square we should sample, this will just zoom in
1071 let target_coords_txl = target_coords_txl1 * window_to_entire_ratio + windowed_source_offset_txl;
1072
1073 let result: vec4<f32> = textureSample(tex, tex_sampler, target_coords_txl);
1074 "###;
1075 )
1076 };
1077
1078 let conf = GraphicsCreator::default()
1081 .with_first_texture_format(DEFAULT_LOADED_TEXTURE_FORMAT)
1082 .with_dst_format(DEFAULT_TEXTURE_FORMAT)
1083 .with_mag_filter(wgpu::FilterMode::Nearest)
1084 .with_address_mode(address_mode);
1085
1086 let graphics = GraphicsRef::new_with_src(
1087 name,
1088 c, &repeat_img,
1090 &conf,
1091 GraphicsAssets::LocalFilesystem(src_path.to_path_buf()),
1092 );
1093 graphics.update_uniforms_other(
1094 c,
1095 [0.0, 0.0, 0.0, 0.0],
1096 [
1097 source_dims[0] as f32,
1098 source_dims[1] as f32,
1099 target_dims[0] as f32,
1100 target_dims[1] as f32,
1101 ],
1102 );
1103
1104 Self {
1105 name: name.to_owned(),
1106 graphics,
1107 }
1108 }
1109
1110 pub fn new_nearest(name: &str, src_path: &PathBuf, c: &GraphicsWindowConf) -> Self {
1112 let repeat_img: String = build_shader! {
1115 (
1116 raw r###"
1117
1118
1119 let result: vec4<f32> = textureSample(tex, tex_sampler, tex_coords);
1120 "###;
1121 )
1122 };
1123
1124 let conf = GraphicsCreator::default()
1126 .with_mag_filter(wgpu::FilterMode::Nearest)
1127 .with_address_mode(wgpu::AddressMode::ClampToEdge);
1128
1129 let graphics = GraphicsRef::new_with_src(
1130 name,
1131 c,
1132 &repeat_img,
1133 &conf,
1134 GraphicsAssets::LocalFilesystem(src_path.to_path_buf()),
1135 );
1136 Self {
1137 name: name.to_owned(),
1138 graphics,
1139 }
1140 }
1141
1142 pub fn update_uniforms(&self, c: &GraphicsWindowConf, offset: Vec2, size: Vec2) {
1143 self.graphics
1144 .update_uniforms(c, [offset.x, offset.y, size.x, size.y]);
1145 }
1146}