1use crate::{
2 recording_handlers, AnimationCallback, AnimationData, Attribute, Buffer, Framebuffer, Id,
3 IdName, RecordingData, RenderCallback, RendererData, RendererDataBuilder, RendererJs,
4 RendererJsInner, Texture, Uniform,
5};
6
7use log::{error, info};
8
9use std::cell::RefCell;
10use std::ops::Deref;
11use std::rc::Rc;
12use wasm_bindgen::prelude::Closure;
13use wasm_bindgen::{JsCast, JsValue};
14use web_sys::{
15 window, HtmlCanvasElement, WebGl2RenderingContext, WebGlProgram, WebGlShader,
16 WebGlTransformFeedback, WebGlVertexArrayObject,
17};
18
19#[derive(Debug)]
23pub struct Renderer<
24 VertexShaderId: Id,
25 FragmentShaderId: Id,
26 ProgramId: Id,
27 UniformId: Id + IdName,
28 BufferId: Id,
29 AttributeId: Id + IdName,
30 TextureId: Id,
31 FramebufferId: Id,
32 TransformFeedbackId: Id,
33 VertexArrayObjectId: Id,
34 UserCtx: Clone + 'static,
35> {
36 renderer_data: Rc<
37 RefCell<
38 RendererData<
39 VertexShaderId,
40 FragmentShaderId,
41 ProgramId,
42 UniformId,
43 BufferId,
44 AttributeId,
45 TextureId,
46 FramebufferId,
47 TransformFeedbackId,
48 VertexArrayObjectId,
49 UserCtx,
50 >,
51 >,
52 >,
53 animation_data: Rc<
54 RefCell<
55 AnimationData<
56 VertexShaderId,
57 FragmentShaderId,
58 ProgramId,
59 UniformId,
60 BufferId,
61 AttributeId,
62 TextureId,
63 FramebufferId,
64 TransformFeedbackId,
65 VertexArrayObjectId,
66 UserCtx,
67 >,
68 >,
69 >,
70 recording_data: Option<Rc<RefCell<RecordingData>>>,
71}
72
73impl<
74 VertexShaderId: 'static + Id,
75 FragmentShaderId: 'static + Id,
76 ProgramId: 'static + Id,
77 UniformId: 'static + Id + IdName,
78 BufferId: 'static + Id,
79 AttributeId: 'static + Id + IdName,
80 TextureId: 'static + Id,
81 FramebufferId: 'static + Id,
82 TransformFeedbackId: 'static + Id,
83 VertexArrayObjectId: 'static + Id,
84 UserCtx: Clone + 'static,
85 >
86 Renderer<
87 VertexShaderId,
88 FragmentShaderId,
89 ProgramId,
90 UniformId,
91 BufferId,
92 AttributeId,
93 TextureId,
94 FramebufferId,
95 TransformFeedbackId,
96 VertexArrayObjectId,
97 UserCtx,
98 >
99{
100 pub(crate) fn new(
101 renderer_data: RendererData<
102 VertexShaderId,
103 FragmentShaderId,
104 ProgramId,
105 UniformId,
106 BufferId,
107 AttributeId,
108 TextureId,
109 FramebufferId,
110 TransformFeedbackId,
111 VertexArrayObjectId,
112 UserCtx,
113 >,
114 ) -> Self {
115 Self::new_with_rc_renderer(Rc::new(RefCell::new(renderer_data)))
116 }
117
118 pub(crate) fn new_with_rc_renderer(
120 renderer_data: Rc<
121 RefCell<
122 RendererData<
123 VertexShaderId,
124 FragmentShaderId,
125 ProgramId,
126 UniformId,
127 BufferId,
128 AttributeId,
129 TextureId,
130 FramebufferId,
131 TransformFeedbackId,
132 VertexArrayObjectId,
133 UserCtx,
134 >,
135 >,
136 >,
137 ) -> Self {
138 Self {
139 recording_data: None,
140 renderer_data,
141 animation_data: Rc::new(RefCell::new(AnimationData::new())),
142 }
143 }
144
145 pub fn initialize_recorder(&mut self) {
150 if let Some(_) = &self.recording_data {
151 error!("Error initializing recorder: a recorder has already been initialized. This is a no-op");
152 return;
153 }
154
155 let canvas = {
156 let renderer_ref = self.renderer_data.borrow();
157 renderer_ref.canvas().clone()
158 };
159 let recording_data = RecordingData::new(&canvas);
160 let media_recorder = recording_data.media_recorder().clone();
161 let recording_data = Rc::new(RefCell::new(recording_data));
162
163 {
164 let mut recording_data_ref = recording_data.borrow_mut();
165 recording_data_ref
166 .add_event_listener(recording_handlers::make_handle_dataavailable(
167 media_recorder.clone(),
168 Rc::clone(&recording_data),
169 ))
170 .add_event_listener(recording_handlers::make_handle_start(
171 media_recorder.clone(),
172 Rc::clone(&recording_data),
173 ))
174 .add_event_listener(recording_handlers::make_handle_error(
175 media_recorder.clone(),
176 Rc::clone(&recording_data),
177 ))
178 .add_event_listener(recording_handlers::make_handle_stop(
179 media_recorder.clone(),
180 Rc::clone(&recording_data),
181 ))
182 .add_event_listener(recording_handlers::make_handle_pause(
183 media_recorder.clone(),
184 Rc::clone(&recording_data),
185 ))
186 .add_event_listener(recording_handlers::make_handle_pause(
187 media_recorder.clone(),
188 Rc::clone(&recording_data),
189 ))
190 .add_event_listener(recording_handlers::make_handle_resume(
191 media_recorder,
192 Rc::clone(&recording_data),
193 ));
194 }
195
196 self.recording_data.replace(recording_data);
197
198 info!("Recorder successfully initialized")
199 }
200
201 pub fn start_animating(&self) {
202 if self.is_animating() {
204 error!("`start_animating` was called, but `Renderer` is already animating. Cancelling the previous animation and staring a new one");
205 self.stop_animating();
206 }
207
208 self.animation_data.borrow_mut().set_is_animating(true);
209 let f = Rc::new(RefCell::new(None));
210 let g = Rc::clone(&f);
211 let animation_data = Rc::clone(&self.animation_data);
212 let renderer_data = Rc::clone(&self.renderer_data);
213 {
214 let animation_data = Rc::clone(&self.animation_data);
215 *g.borrow_mut() = Some(Closure::wrap(Box::new(move || {
216 if !animation_data.borrow().is_animating() {
218 return;
219 }
220
221 animation_data
223 .borrow_mut()
224 .call_animation_callback(Rc::clone(&renderer_data));
225
226 let animation_id = Self::request_animation_frame(f.borrow().as_ref().unwrap());
228 animation_data.borrow_mut().set_request_id(animation_id);
229 }) as Box<dyn Fn()>));
230 }
231
232 let id = Self::request_animation_frame(g.borrow().as_ref().unwrap());
233 animation_data.borrow_mut().set_request_id(id);
234 }
235
236 pub fn stop_animating(&self) {
237 if !self.is_animating() {
238 error!("`stop_animating` was called, but `Renderer` is not currently animating");
239 return;
240 }
241
242 self.animation_data.borrow_mut().set_is_animating(false);
243 window()
244 .unwrap()
245 .cancel_animation_frame(self.animation_data.borrow().request_id())
246 .expect("Should be able to cancel animation frame")
247 }
248
249 pub fn set_animation_callback(
250 &mut self,
251 animation_callback: Option<
252 impl Into<
253 AnimationCallback<
254 VertexShaderId,
255 FragmentShaderId,
256 ProgramId,
257 UniformId,
258 BufferId,
259 AttributeId,
260 TextureId,
261 FramebufferId,
262 TransformFeedbackId,
263 VertexArrayObjectId,
264 UserCtx,
265 >,
266 >,
267 >,
268 ) {
269 self.animation_data
270 .borrow_mut()
271 .set_animation_callback(animation_callback.map(|cb| cb.into()));
272 }
273
274 pub fn start_recording(&mut self) {
275 const ERROR_START: &str = "Error trying to start video recording";
276
277 if !self.recorder_initialized() {
278 self.initialize_recorder();
279 }
280
281 if let Some(recording_data) = &self.recording_data {
282 if let Err(err) = recording_data
283 .borrow_mut()
284 .media_recorder()
285 .start_with_time_slice(RecordingData::SAVE_DATA_INTERVAL)
286 {
287 error!("{ERROR_START}: {err:?}");
288 }
289 } else {
290 error!("{ERROR_START}: there was an error initializing the recorder");
291 }
292 }
293
294 pub fn stop_recording(&self) {
295 const ERROR_START: &str = "Error trying to stop video recording";
296
297 if !self.is_recording() {
298 error!("{ERROR_START}: recorder is not currently recording");
299 return;
300 }
301
302 if let Some(recording_data) = &self.recording_data {
303 if let Err(err) = recording_data.borrow_mut().media_recorder().stop() {
304 error!("{ERROR_START}: {err:?}");
305 }
306 } else {
307 error!("{ERROR_START}: recorder was not properly initialized");
308 }
309 }
310
311 pub fn clear_recorded_data(&self) {
312 const ERROR_START: &str = "Error trying to clear video recording data";
313
314 if let Some(recording_data) = &self.recording_data {
315 recording_data.borrow_mut().recorded_chunks_mut().clear();
316 } else {
317 error!("{ERROR_START}: recorder was not properly initialized");
318 }
319 }
320
321 pub fn recorder_initialized(&self) -> bool {
322 self.recording_data.is_some()
323 }
324
325 pub fn is_animating(&self) -> bool {
326 self.animation_data.borrow().is_animating()
327 }
328
329 pub fn is_recording(&self) -> bool {
330 self.recording_data
331 .as_ref()
332 .map_or(false, |recording_data| {
333 recording_data.borrow().is_recording()
334 })
335 }
336
337 pub(crate) fn renderer_data(
338 &self,
339 ) -> Rc<
340 RefCell<
341 RendererData<
342 VertexShaderId,
343 FragmentShaderId,
344 ProgramId,
345 UniformId,
346 BufferId,
347 AttributeId,
348 TextureId,
349 FramebufferId,
350 TransformFeedbackId,
351 VertexArrayObjectId,
352 UserCtx,
353 >,
354 >,
355 > {
356 Rc::clone(&self.renderer_data)
357 }
358
359 pub(crate) fn request_animation_frame(f: &Closure<dyn Fn()>) -> i32 {
360 window()
361 .unwrap()
362 .request_animation_frame(f.as_ref().unchecked_ref())
363 .expect("should register `requestAnimationFrame` ok")
364 }
365}
366
367impl<
368 VertexShaderId: Id,
369 FragmentShaderId: Id,
370 ProgramId: Id,
371 UniformId: Id + IdName,
372 BufferId: Id,
373 AttributeId: Id + IdName,
374 TextureId: Id,
375 FramebufferId: Id,
376 TransformFeedbackId: Id,
377 VertexArrayObjectId: Id,
378 UserCtx: Clone,
379 > Drop
380 for Renderer<
381 VertexShaderId,
382 FragmentShaderId,
383 ProgramId,
384 UniformId,
385 BufferId,
386 AttributeId,
387 TextureId,
388 FramebufferId,
389 TransformFeedbackId,
390 VertexArrayObjectId,
391 UserCtx,
392 >
393{
394 fn drop(&mut self) {
395 if let Some(recording_data) = &self.recording_data {
399 recording_data.borrow_mut().remove_all_event_listeners();
400 }
401
402 if self.is_recording() {
403 self.stop_recording();
404 }
405
406 if self.is_animating() {
407 self.stop_animating();
408 }
409 }
410}
411
412impl<
413 VertexShaderId: Id,
414 FragmentShaderId: Id,
415 ProgramId: Id,
416 UniformId: Id + IdName,
417 BufferId: Id,
418 AttributeId: Id + IdName,
419 TextureId: Id,
420 FramebufferId: Id,
421 TransformFeedbackId: Id,
422 VertexArrayObjectId: Id,
423 UserCtx: Clone,
424 >
425 From<
426 RendererData<
427 VertexShaderId,
428 FragmentShaderId,
429 ProgramId,
430 UniformId,
431 BufferId,
432 AttributeId,
433 TextureId,
434 FramebufferId,
435 TransformFeedbackId,
436 VertexArrayObjectId,
437 UserCtx,
438 >,
439 >
440 for Renderer<
441 VertexShaderId,
442 FragmentShaderId,
443 ProgramId,
444 UniformId,
445 BufferId,
446 AttributeId,
447 TextureId,
448 FramebufferId,
449 TransformFeedbackId,
450 VertexArrayObjectId,
451 UserCtx,
452 >
453{
454 fn from(
455 renderer_data: RendererData<
456 VertexShaderId,
457 FragmentShaderId,
458 ProgramId,
459 UniformId,
460 BufferId,
461 AttributeId,
462 TextureId,
463 FramebufferId,
464 TransformFeedbackId,
465 VertexArrayObjectId,
466 UserCtx,
467 >,
468 ) -> Self {
469 Renderer::new(renderer_data)
470 }
471}
472
473impl<
475 VertexShaderId: Id,
476 FragmentShaderId: Id,
477 ProgramId: Id,
478 UniformId: Id + IdName,
479 BufferId: Id,
480 AttributeId: Id + IdName,
481 TextureId: Id,
482 FramebufferId: Id,
483 TransformFeedbackId: Id,
484 VertexArrayObjectId: Id,
485 UserCtx: Clone,
486 >
487 Renderer<
488 VertexShaderId,
489 FragmentShaderId,
490 ProgramId,
491 UniformId,
492 BufferId,
493 AttributeId,
494 TextureId,
495 FramebufferId,
496 TransformFeedbackId,
497 VertexArrayObjectId,
498 UserCtx,
499 >
500{
501 pub fn builder() -> RendererDataBuilder<
502 VertexShaderId,
503 FragmentShaderId,
504 ProgramId,
505 UniformId,
506 BufferId,
507 AttributeId,
508 TextureId,
509 FramebufferId,
510 TransformFeedbackId,
511 VertexArrayObjectId,
512 UserCtx,
513 > {
514 RendererDataBuilder::default()
515 }
516
517 pub fn canvas(&self) -> HtmlCanvasElement {
518 self.deref().borrow().canvas().to_owned()
519 }
520
521 pub fn gl(&self) -> WebGl2RenderingContext {
522 self.deref().borrow().deref().gl().to_owned()
523 }
524
525 pub fn fragment_shader(&self, fragment_shader_id: &FragmentShaderId) -> Option<WebGlShader> {
526 self.deref()
527 .borrow()
528 .fragment_shader(fragment_shader_id)
529 .map(Clone::clone)
530 }
531
532 pub fn vertex_shader(&self, vertex_shader_id: &VertexShaderId) -> Option<WebGlShader> {
533 self.deref()
534 .borrow()
535 .vertex_shader(vertex_shader_id)
536 .map(Clone::clone)
537 }
538
539 pub fn program(&self, program_id: &ProgramId) -> Option<WebGlProgram> {
540 self.deref().borrow().program(program_id).map(Clone::clone)
541 }
542
543 pub fn uniform(&self, uniform_id: &UniformId) -> Option<Uniform<ProgramId, UniformId>> {
544 self.deref().borrow().uniform(uniform_id).map(Clone::clone)
545 }
546
547 pub fn buffer(&self, buffer_id: &BufferId) -> Option<Buffer<BufferId>> {
548 self.deref().borrow().buffer(buffer_id).map(Clone::clone)
549 }
550
551 pub fn attribute(
552 &self,
553 attribute_id: &AttributeId,
554 ) -> Option<Attribute<VertexArrayObjectId, BufferId, AttributeId>> {
555 self.deref()
556 .borrow()
557 .attribute(attribute_id)
558 .map(Clone::clone)
559 }
560
561 pub fn texture(&self, texture_id: &TextureId) -> Option<Texture<TextureId>> {
562 self.deref().borrow().texture(texture_id).map(Clone::clone)
563 }
564
565 pub fn framebuffer(
566 &self,
567 framebuffer_id: &FramebufferId,
568 ) -> Option<Framebuffer<FramebufferId>> {
569 self.deref()
570 .borrow()
571 .framebuffer(framebuffer_id)
572 .map(Clone::clone)
573 }
574
575 pub fn transform_feedback(
576 &self,
577 transform_feedback_id: &TransformFeedbackId,
578 ) -> Option<WebGlTransformFeedback> {
579 self.deref()
580 .borrow()
581 .transform_feedback(transform_feedback_id)
582 .map(Clone::clone)
583 }
584
585 pub fn vao(&self, vao_id: &VertexArrayObjectId) -> Option<WebGlVertexArrayObject> {
586 self.deref().borrow().vao(vao_id).map(Clone::clone)
587 }
588
589 pub fn user_ctx(&self) -> Option<UserCtx> {
590 self.deref().borrow().user_ctx().map(Clone::clone)
591 }
592
593 pub fn use_program(&self, program_id: &ProgramId) -> &Self {
594 self.deref().borrow().use_program(program_id);
595 self
596 }
597
598 pub fn use_vao(&self, vao_id: &VertexArrayObjectId) -> &Self {
599 self.deref().borrow().use_vao(vao_id);
600 self
601 }
602 pub fn update_uniform(&self, uniform_id: &UniformId) -> &Self {
603 self.deref().borrow().update_uniform(uniform_id);
604 self
605 }
606
607 pub fn update_uniforms(&self) -> &Self {
608 self.deref().borrow().update_uniforms();
609 self
610 }
611
612 pub fn render(&self) -> &Self {
613 self.deref().borrow().render();
614 self
615 }
616
617 pub fn save_image(&self) {
618 self.deref().borrow().save_image()
619 }
620
621 pub fn render_callback(
622 &self,
623 ) -> RenderCallback<
624 VertexShaderId,
625 FragmentShaderId,
626 ProgramId,
627 UniformId,
628 BufferId,
629 AttributeId,
630 TextureId,
631 FramebufferId,
632 TransformFeedbackId,
633 VertexArrayObjectId,
634 UserCtx,
635 > {
636 self.deref().borrow().render_callback()
637 }
638}
639
640impl<
641 VertexShaderId: Id,
642 FragmentShaderId: Id,
643 ProgramId: Id,
644 UniformId: Id + IdName,
645 BufferId: Id,
646 AttributeId: Id + IdName,
647 TextureId: Id,
648 FramebufferId: Id,
649 TransformFeedbackId: Id,
650 VertexArrayObjectId: Id,
651 UserCtx: Clone,
652 >
653 From<
654 Rc<
655 RefCell<
656 RendererData<
657 VertexShaderId,
658 FragmentShaderId,
659 ProgramId,
660 UniformId,
661 BufferId,
662 AttributeId,
663 TextureId,
664 FramebufferId,
665 TransformFeedbackId,
666 VertexArrayObjectId,
667 UserCtx,
668 >,
669 >,
670 >,
671 >
672 for Renderer<
673 VertexShaderId,
674 FragmentShaderId,
675 ProgramId,
676 UniformId,
677 BufferId,
678 AttributeId,
679 TextureId,
680 FramebufferId,
681 TransformFeedbackId,
682 VertexArrayObjectId,
683 UserCtx,
684 >
685{
686 fn from(
687 renderer_data: Rc<
688 RefCell<
689 RendererData<
690 VertexShaderId,
691 FragmentShaderId,
692 ProgramId,
693 UniformId,
694 BufferId,
695 AttributeId,
696 TextureId,
697 FramebufferId,
698 TransformFeedbackId,
699 VertexArrayObjectId,
700 UserCtx,
701 >,
702 >,
703 >,
704 ) -> Self {
705 Renderer::new_with_rc_renderer(renderer_data)
706 }
707}
708
709impl<
710 VertexShaderId: Id,
711 FragmentShaderId: Id,
712 ProgramId: Id,
713 UniformId: Id + IdName,
714 BufferId: Id,
715 AttributeId: Id + IdName,
716 TextureId: Id,
717 FramebufferId: Id,
718 TransformFeedbackId: Id,
719 VertexArrayObjectId: Id,
720 UserCtx: Clone,
721 > Deref
722 for Renderer<
723 VertexShaderId,
724 FragmentShaderId,
725 ProgramId,
726 UniformId,
727 BufferId,
728 AttributeId,
729 TextureId,
730 FramebufferId,
731 TransformFeedbackId,
732 VertexArrayObjectId,
733 UserCtx,
734 >
735{
736 type Target = Rc<
737 RefCell<
738 RendererData<
739 VertexShaderId,
740 FragmentShaderId,
741 ProgramId,
742 UniformId,
743 BufferId,
744 AttributeId,
745 TextureId,
746 FramebufferId,
747 TransformFeedbackId,
748 VertexArrayObjectId,
749 UserCtx,
750 >,
751 >,
752 >;
753
754 fn deref(&self) -> &Self::Target {
755 &self.renderer_data
756 }
757}
758
759impl From<RendererJsInner> for JsValue {
760 fn from(js_renderer_handle_inner: RendererJsInner) -> Self {
761 let js_renderer_handle: RendererJs = js_renderer_handle_inner.into();
762 js_renderer_handle.into()
763 }
764}