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
//! A simple api for creating and drawing to a window
//!
//! waow is a beginner friendly creative coding library.
//! It provides functionality for creating a window,
//! and preforming various operations about it such as
//! drawing shapes, and reading user input
//!
//! For a quick start, see the [examples](https://github.com/samgcode/waow/tree/master/examples)
use error_iter::ErrorIter;
use log::error;
use pixels::{Pixels, SurfaceTexture};
use winit::{
dpi::LogicalSize,
event::Event,
event_loop::{ControlFlow, EventLoop},
window::WindowBuilder,
};
mod canvas;
mod color;
pub mod shapes;
/// Canvas that can be drawn to and gets displayed on the screen
pub use canvas::Canvas;
/// represents an RGBA color
pub use color::Color;
/// Represents an input key
pub use winit::event::VirtualKeyCode as KeyCode;
/// Handles user input events
pub use winit_input_helper::WinitInputHelper as Input;
/// Holds the configuration of the canvas.
///
/// Passed into the [`create()`] method to set the various
/// attributes of the canvas
///
/// # Examples
/// ```
/// use waow::*;
///
/// let app = App {};
/// create(
/// app,
/// CanvasConfiguration {
/// width: 400,
/// height: 400,
/// background_color: Color::from_rgba(0.0, 0.0, 0.0, 1.0),
/// window_name: String::from("waow!"),
/// },
/// );
///
/// struct App {}
/// impl Run for App {
/// fn start(&mut self, _canvas: &mut Canvas) {}
/// fn draw(&mut self, _canvas: &mut Canvas, _input: &Input) {}
/// }
/// ```
pub struct CanvasConfiguration {
pub width: u32,
pub height: u32,
pub background_color: Color,
pub window_name: String,
}
/// Defines the behavior for an app that effects the canvas
///
/// The `start()` method is called before the first frame
/// The `draw()` method is called every frame
///
/// # Examples
/// ```
/// use waow::*;
///
/// struct App {}
/// impl Run for App {
/// fn start(&mut self, _canvas: &mut Canvas) {}
/// fn draw(&mut self, canvas: &mut Canvas, _input: &Input) {
/// canvas.draw_square(50, 50, 20, Color::from_rgba(1.0, 0.0, 0.0, 1.0), None)
/// }
/// }
/// ```
pub trait Run {
fn start(&mut self, canvas: &mut Canvas);
fn draw(&mut self, canvas: &mut Canvas, input: &Input);
}
/// Creates a canvas to draw on
///
/// Creates a new window with the given [`CanvasConfiguration`]
/// and runs the app with the canvas
/// # Examples
/// ```
/// use waow::*;
///
/// fn main() {
/// let app = App {};
/// create(
/// app,
/// CanvasConfiguration {
/// width: 400,
/// height: 400,
/// background_color: Color::from_rgba(0.0, 0.0, 0.0, 1.0),
/// window_name: String::from("waow!"),
/// },
/// );
/// }
///
/// struct App {}
/// impl Run for App {
/// fn start(&mut self, _canvas: &mut Canvas) {}
/// fn draw(&mut self, canvas: &mut Canvas, input: &Input) {
/// if let Some(mouse_pos) = input.mouse() {
/// let mut color = Color::from_rgba(1.0, 0.0, 0.0, 1.0);
/// if input.key_held(KeyCode::D) {
/// color = Color::from_rgba(0.0, 1.0, 0.0, 1.0);
/// }
/// canvas.draw_square(mouse_pos.0 as i16, mouse_pos.1 as i16, 20, color, None);
/// }
/// }
/// }
/// ```
pub fn create(mut app: impl Run + 'static, config: CanvasConfiguration) {
env_logger::init();
let event_loop = EventLoop::new();
let mut input = Input::new();
let mut canvas = Canvas::new(&config);
let (width, height) = (config.width, config.height);
let window = {
let size = LogicalSize::new(width as f64, height as f64);
WindowBuilder::new()
.with_title(config.window_name)
.with_inner_size(size)
.with_resizable(false)
.with_min_inner_size(size)
.build(&event_loop)
.unwrap()
};
let mut pixels = {
let window_size = window.inner_size();
let surface_texture = SurfaceTexture::new(window_size.width, window_size.height, &window);
Pixels::new(width, height, surface_texture).unwrap()
};
app.start(&mut canvas);
event_loop.run(move |event, _, control_flow| {
if let Event::RedrawRequested(_) = event {
canvas.draw_to_buffer(pixels.frame_mut());
if let Err(err) = pixels.render() {
log_error("pixels.render", err);
*control_flow = ControlFlow::Exit;
return;
}
}
if input.update(&event) {
if input.close_requested() {
*control_flow = ControlFlow::Exit;
return;
}
app.draw(&mut canvas, &input);
window.request_redraw();
}
});
}
fn log_error<E: std::error::Error + 'static>(method_name: &str, err: E) {
error!("{method_name}() failed: {err}");
for source in err.sources().skip(1) {
error!(" Caused by: {source}");
}
}