1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
//! The thing to be rendered every time

extern crate rayon;
extern crate sdl2;

use std::sync::mpsc::channel;
use std::thread::spawn;

use rayon::scope;

use sdl2::rect::Rect;
use sdl2::render::Canvas;
use sdl2::video::Window;

use drawable::{DrawSettings, Drawable, Position, State};
use window::YEvent;

/// An action that allows the [`Scene`] to communicate with the [`WindowManager`]
///
/// [`WindowManager`]: ../window/struct.WindowManager.html
#[allow(unused)]
#[derive(PartialEq)]
pub enum Action {
    /// Don't do anything
    Continue,
    /// The current scene is done, move on to the next one
    Done,
}

/// A scene is like a [`Drawable`], but without the modularity, it's in the top level and
/// no wrappers for it exists. Unless you're doing something advanced, a
/// [`DrawableWrapper`] around your [`Drawable`]s should do fine.
///
/// [`Drawable`]: ../drawable/struct.Drawable.html
pub trait Scene: Send {
    /// Do a tick
    fn update(&mut self, _dt: f64);
    /// Draw the content of this scene to a `Canvas`.
    fn draw(&self, canvas: &mut Canvas<Window>, settings: DrawSettings);
    /// Called when an event occured
    fn event(&mut self, _event: YEvent);
    /// What to do
    fn action(&self) -> Action;
    /// Register everything. The scene equivalent of [`Drawable::register`]
    ///
    /// [`Drawable::register`]: ../drawable/struct.Drawable.html#method.register
    fn register(&mut self);
    /// Load everything. The scene equivalent of [`Drawable::load`]
    ///
    /// [`Drawable::load`]: ../drawable/struct.Drawable.html#method.register
    fn load(&mut self);
}

/// A wrapper to make a [`Drawable`] into a [`Scene`]. This is probably all you will need
/// in terms of scenes, there's really not much else you can do with one.
///
/// [`Drawable`]: ../drawable/struct.Drawable.html
pub struct DrawableWrapper<T: Drawable>(pub T);

impl<T: Drawable> Scene for DrawableWrapper<T> {
    fn update(&mut self, dt: f64) {
        self.0.update(dt);
    }

    fn draw(&self, canvas: &mut Canvas<Window>, settings: DrawSettings) {
        let (w, h) = canvas.window().size();
        self.0
            .draw(canvas, &Position::Rect(Rect::new(0, 0, w, h)), settings);
    }

    fn event(&mut self, event: YEvent) {
        match event {
            YEvent::Step => {
                self.0.step();
            }
            YEvent::Other(e) => {
                self.0.event(e);
            }
            YEvent::StepSlide => {}
        }
    }

    fn action(&self) -> Action {
        if self.0.state() == State::Hidden {
            Action::Done
        } else {
            Action::Continue
        }
    }

    fn register(&mut self) {
        self.0.register()
    }
    fn load(&mut self) {
        self.0.load()
    }
}

/// A list of scenes that are showed in order. When the current scene's action is [`Action::Done`]
/// the next scene is loaded.
pub struct SceneList {
    /// The list of scenes
    pub scenes: Vec<Box<dyn Scene>>,

    /// The index of the current scene being showed. Garuanteed to always be in bounds
    current_scene: usize,
}

impl SceneList {
    /// Create a new SceneList
    pub fn new(scenes: Vec<Box<dyn Scene>>) -> SceneList {
        SceneList {
            scenes,
            current_scene: 0,
        }
    }

    /// Gets what scene is being shown
    pub fn get_current_scene(&self) -> usize {
        self.current_scene
    }
}

impl Scene for SceneList {
    fn update(&mut self, dt: f64) {
        self.scenes[self.current_scene].update(dt);

        if self.scenes[self.current_scene].action() == Action::Done {
            self.current_scene += 1;
        }
    }
    fn draw(&self, canvas: &mut Canvas<Window>, settings: DrawSettings) {
        self.scenes[self.current_scene].draw(canvas, settings);
    }
    fn event(&mut self, event: YEvent) {
        match event {
            YEvent::StepSlide => self.current_scene += 1,
            _ => {
                self.scenes[self.current_scene].event(event);
            }
        }
    }
    fn action(&self) -> Action {
        if self.current_scene >= self.scenes.len() {
            Action::Done
        } else {
            Action::Continue
        }
    }
    fn register(&mut self) {
        for scene in &mut self.scenes {
            scene.register();
        }
    }

    fn load(&mut self) {
        let nscenes = self.scenes.len();

        let (tx, rx) = channel::<usize>();

        spawn(move || {
            let mut statuses = vec![0; nscenes]; // 0 = not loaded, 1 = loading, 2 = loaded
            print_state(&statuses);
            let mut count = 0;
            while let Ok(idx) = rx.recv() {
                count += 1;
                statuses[idx] += 1;
                eprint!("\x1b[{}A", nscenes); // Clear
                print_state(&statuses);
                if count >= 2 * nscenes {
                    break;
                }
            }
        });

        let s = &mut self.scenes;

        scope(move |sc| {
            for (i, scene) in s.iter_mut().enumerate() {
                let send = tx.clone();

                sc.spawn(move |_| {
                    send.send(i).unwrap();
                    scene.load();
                    send.send(i).unwrap();
                });
            }
        });
    }
}

fn print_state(statuses: &[u8]) {
    for (i, status) in statuses.iter().enumerate() {
        eprint!("\x1b[KScene {}: ", i + 1);
        match status {
            0 => eprintln!("..."),
            1 => eprintln!("Loading"),
            2 => eprintln!("Done"),
            _ => eprintln!("o no! {}", status),
        }
    }
}