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
mod runtime; use std::sync::{Arc, Mutex}; pub const SAMPLES_PER_SECOND: u32 = 48_000; #[repr(C)] #[derive(Copy, Clone, Debug)] pub struct Pixel { pub red: f32, pub green: f32, pub blue: f32, pub alpha: f32, } #[repr(C)] #[derive(Copy, Clone, Debug)] pub struct Sample { pub left: f32, pub right: f32, } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum Button { Left, Right, Up, Down, Action, } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum ButtonState { Pressed, Released, } #[derive(Copy, Clone, Debug)] pub enum Event { Button { state: ButtonState, button: Button }, Key { character: char }, } pub trait Synthesizer: Send + 'static { /// Synthesize audio /// /// Called by the runtime as needed to fill the outgoing audio buffer /// /// * `samples_played` β number of samples written by previous calls to synthesize /// * `output_buffer` β the audio samples that synthesize should write fn synthesize(&mut self, _samples_played: u64, _output_buffer: &mut [Sample]) {} } pub trait Program: 'static { /// Initialize a new Program object fn new() -> Self where Self: Sized; /// Return the desired width and height of pixel surface /// /// Will be called immediately before calling `render()`. /// Determines the length of the pixel slice passed to /// `render()`. If (256, 256) is returned, the pixel /// slice passed to `render()` will contain 256 * 256, /// elements. fn dimensions(&self) -> (usize, usize); /// Return the vertex shader to be used in the runtime's /// rendering pipeline /// /// Will be called immediately before calling `render()` fn vertex_shader(&self) -> &str { include_str!("vertex_shader.glsl") } /// Return the fragment shader to be used in the runtime's /// rendering pipeline /// /// Will be called immediately before calling `render()` fn fragment_shader(&self) -> &str { include_str!("fragment_shader.glsl") } /// Return the title of the program /// /// Called by the runtime to set the window title fn title(&self) -> &str { "pxl" } /// Return true if the program should stop running /// /// Called by the runtime at the end of every pass through the event loop fn should_quit(&mut self) -> bool { false } /// Process events and update the state of the program /// /// Called by the runtime 60 times per second. /// /// * `events` β events that have occurred since the last call to `tick` fn tick(&mut self, _events: &[Event]) {} /// Draw to the display /// /// Called by the runtime whenever the display is ready to present a new frame /// /// WIDTH β first element of the tuple returned by `dimensions()` /// HEIGHT β second element of the tuple returned by `dimensions()` /// /// * `pixels` β a slice of pixels with `WIDTH * HEIGHT` elements /// `pixels[x + y * WIDTH]` is the `x`th pixel in the /// `y`th row, with `(0,0)` starting in the upper left /// corner of the screen fn render(&mut self, _pixels: &mut [Pixel]) {} /// The program's synthesizer /// /// Will be called by the runtime during initialization. If it returns /// Some, the contained Synthesizer will be moved to a dedicated audio /// thread and called periodically to produce samples for the outgoing /// audio stream. /// /// In order to prevent buffer underruns, avoid locking the `Mutex` /// containing the Synthesizer for long periods of time. fn synthesizer(&self) -> Option<Arc<Mutex<Synthesizer>>> { None } } pub fn run<P: Program>() -> ! { let program = P::new(); let result = runtime::Runtime::new(Box::new(program)).and_then(|runtime| runtime.run()); if let Err(error) = result { eprintln!("{}", error); std::process::exit(1); } else { std::process::exit(0); } }