gooey/presentation/fmod/
remote.rs

1//! Remote FMOD backend
2
3use std::sync;
4use lazy_static::lazy_static;
5use unbounded_spsc;
6
7use crate::interface::{self, view, View};
8use crate::tree::{NodeId, Tree};
9use super::{Audio, Presentation};
10
11lazy_static!{
12  /// Used to transfer view display events to the FMOD backend
13  static ref DISPLAY_RECEIVER
14    : sync::Mutex <Option <
15      unbounded_spsc::Receiver <Vec <(NodeId, view::Display)>>>>
16    = sync::Mutex::new (None);
17}
18
19/// Remote FMOD handle
20#[derive(Debug)]
21pub struct Remote {
22  display : unbounded_spsc::Sender <Vec <(NodeId, view::Display)>>,
23}
24
25/// Audition backend that can receive and handle display updates
26pub struct Fmod {
27  pub inner : super::Fmod,
28  updates   : unbounded_spsc::Receiver <Vec <(NodeId, view::Display)>>,
29  /// Counts number of batches of display events have been processed
30  display_counter : u64,
31  /// Counts number of frames that have been rendered
32  frame           : u64
33}
34
35impl Default for Remote {
36  fn default() -> Self {
37    let display = {
38      let (sender, receiver) =
39        unbounded_spsc::channel::<Vec <(NodeId, view::Display)>>();
40      {
41        let mut display_receiver_lock = DISPLAY_RECEIVER.lock().unwrap();
42        debug_assert!(display_receiver_lock.is_none());
43        *display_receiver_lock = Some (receiver);
44      }
45      sender
46    };
47    Remote {
48      display
49    }
50  }
51}
52
53impl Audio        for Remote { }
54impl Presentation for Remote {
55  fn with_root (root : View, id : NodeId) -> Self {
56    let remote = Self::default();
57    log::debug!("fmod remote with root: {:?}", remote);
58    remote.display.send (vec![(
59      id.clone(),
60      view::Display::Create (root, id, interface::CreateOrder::Append)
61    )]).unwrap();
62    remote
63  }
64
65  fn get_input (&mut self, _ : &mut Vec <view::Input>) { /* no-op */ }
66
67  fn display_view <V : AsRef <View>> (&mut self,
68    _view_tree      : &Tree <V>,
69    display_values : std::vec::Drain <(NodeId, view::Display)>
70  ) {
71    self.display.send (display_values.collect()).unwrap();
72  }
73}
74
75impl Fmod {
76  pub fn init() -> Self {
77    let inner = super::Fmod::default();
78    let updates = loop {
79      if let Some (receiver) = (*DISPLAY_RECEIVER).lock().unwrap().take() {
80        break receiver
81      }
82      std::thread::sleep (std::time::Duration::from_millis (100));
83    };
84    Fmod {
85      inner,
86      updates,
87      display_counter: 0,
88      frame:           0
89    }
90  }
91
92  #[inline]
93  pub fn display_counter (&self) -> u64 {
94    self.display_counter
95  }
96
97  #[inline]
98  pub fn reset_display_counter (&mut self) {
99    self.display_counter = 0;
100  }
101
102  pub fn process_display_events (&mut self) {
103    // process updates
104    while let Ok (updates) = self.updates.try_recv() {
105      for (node_id, display) in updates {
106        self.inner.display_value (node_id, display);
107      }
108      self.display_counter += 1;
109    }
110  }
111
112  pub fn update_audition (&mut self) {
113    self.inner.audition.update();
114    self.frame += 1;
115  }
116
117  /// Pump display events and update
118  pub fn display (&mut self) {
119    log::trace!("fmod remote display...");
120    self.process_display_events();
121    self.update_audition();
122    log::trace!("...fmod remote display");
123  }
124}