Add an example with raqote (#118)
* Add an example with raqote * Fix raqote dependency
This commit is contained in:
parent
11dca72955
commit
6c36b3955b
|
@ -29,6 +29,7 @@ Rapidly prototype a simple 2D game, pixel-based animations, software renderers,
|
|||
- [Minimal example with SDL2](./examples/minimal-sdl2)
|
||||
- [Minimal example with `winit`](./examples/minimal-winit)
|
||||
- [Pixel Invaders](./examples/invaders)
|
||||
- [`raqote` example](./examples/raqote-winit)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
|
|
19
examples/raqote-winit/Cargo.toml
Normal file
19
examples/raqote-winit/Cargo.toml
Normal file
|
@ -0,0 +1,19 @@
|
|||
[package]
|
||||
name = "raqote-winit"
|
||||
version = "0.1.0"
|
||||
authors = ["Jay Oster <jay@kodewerx.org>"]
|
||||
edition = "2018"
|
||||
publish = false
|
||||
|
||||
[features]
|
||||
optimize = ["log/release_max_level_warn"]
|
||||
default = ["optimize"]
|
||||
|
||||
[dependencies]
|
||||
env_logger = "0.7"
|
||||
euclid = "0.20"
|
||||
log = "0.4"
|
||||
pixels = { path = "../.." }
|
||||
raqote = { version = "0.8", default-features = false }
|
||||
winit = "0.22"
|
||||
winit_input_helper = "0.6"
|
15
examples/raqote-winit/README.md
Normal file
15
examples/raqote-winit/README.md
Normal file
|
@ -0,0 +1,15 @@
|
|||
# Hello Raqote
|
||||
|
||||
![Hello Raqote](../../img/raqote-winit.png)
|
||||
|
||||
`raqote` example with `winit`.
|
||||
|
||||
## Running
|
||||
|
||||
```bash
|
||||
cargo run --release --package raqote-winit
|
||||
```
|
||||
|
||||
## About
|
||||
|
||||
This example uses `raqote` to rasterize and animate a few paths.
|
89
examples/raqote-winit/src/main.rs
Normal file
89
examples/raqote-winit/src/main.rs
Normal file
|
@ -0,0 +1,89 @@
|
|||
#![deny(clippy::all)]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
use crate::shapes::Shapes;
|
||||
use log::error;
|
||||
use pixels::{Error, Pixels, SurfaceTexture};
|
||||
use std::time::Instant;
|
||||
use winit::dpi::LogicalSize;
|
||||
use winit::event::{Event, VirtualKeyCode};
|
||||
use winit::event_loop::{ControlFlow, EventLoop};
|
||||
use winit::window::WindowBuilder;
|
||||
use winit_input_helper::WinitInputHelper;
|
||||
|
||||
mod shapes;
|
||||
|
||||
const WIDTH: u32 = 400;
|
||||
const HEIGHT: u32 = 400;
|
||||
|
||||
fn main() -> Result<(), Error> {
|
||||
env_logger::init();
|
||||
let event_loop = EventLoop::new();
|
||||
let mut input = WinitInputHelper::new();
|
||||
let window = {
|
||||
let size = LogicalSize::new(WIDTH as f64, HEIGHT as f64);
|
||||
WindowBuilder::new()
|
||||
.with_title("Hello Raqote")
|
||||
.with_inner_size(size)
|
||||
.with_min_inner_size(size)
|
||||
.build(&event_loop)
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
let (mut pixels, mut shapes) = {
|
||||
let window_size = window.inner_size();
|
||||
let surface_texture = SurfaceTexture::new(window_size.width, window_size.height, &window);
|
||||
|
||||
let pixels = Pixels::new(WIDTH, HEIGHT, surface_texture)?;
|
||||
let shapes = Shapes::new(window_size.width, window_size.height);
|
||||
|
||||
(pixels, shapes)
|
||||
};
|
||||
|
||||
let mut now = Instant::now();
|
||||
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
// Draw the current frame
|
||||
if let Event::RedrawRequested(_) = event {
|
||||
for (dst, &src) in pixels
|
||||
.get_frame()
|
||||
.chunks_exact_mut(4)
|
||||
.zip(shapes.get_frame().iter())
|
||||
{
|
||||
dst[0] = (src >> 16) as u8;
|
||||
dst[1] = (src >> 8) as u8;
|
||||
dst[2] = src as u8;
|
||||
dst[3] = (src >> 24) as u8;
|
||||
}
|
||||
|
||||
if pixels
|
||||
.render()
|
||||
.map_err(|e| error!("pixels.render() failed: {}", e))
|
||||
.is_err()
|
||||
{
|
||||
*control_flow = ControlFlow::Exit;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle input events
|
||||
if input.update(event) {
|
||||
// Close events
|
||||
if input.key_pressed(VirtualKeyCode::Escape) || input.quit() {
|
||||
*control_flow = ControlFlow::Exit;
|
||||
return;
|
||||
}
|
||||
|
||||
// Resize the window
|
||||
if let Some(size) = input.window_resized() {
|
||||
pixels.resize(size.width, size.height);
|
||||
}
|
||||
|
||||
// Update internal state and request a redraw
|
||||
shapes.draw(now.elapsed().as_secs_f32());
|
||||
window.request_redraw();
|
||||
|
||||
now = Instant::now();
|
||||
}
|
||||
});
|
||||
}
|
124
examples/raqote-winit/src/shapes.rs
Normal file
124
examples/raqote-winit/src/shapes.rs
Normal file
|
@ -0,0 +1,124 @@
|
|||
use euclid::{Angle, Vector2D};
|
||||
use raqote::*;
|
||||
|
||||
/// A context that can draw vector shapes
|
||||
pub struct Shapes {
|
||||
// The main draw target
|
||||
dt: DrawTarget,
|
||||
|
||||
// Center
|
||||
cx: f32,
|
||||
cy: f32,
|
||||
|
||||
// Background color
|
||||
r: f32,
|
||||
g: f32,
|
||||
b: f32,
|
||||
|
||||
// Two paths rotate in opposite directions
|
||||
t1: Transform,
|
||||
t2: Transform,
|
||||
}
|
||||
|
||||
impl Shapes {
|
||||
/// Create a new Shapes
|
||||
pub fn new(width: u32, height: u32) -> Self {
|
||||
Self {
|
||||
dt: DrawTarget::new(width as i32, height as i32),
|
||||
cx: (width / 2) as f32,
|
||||
cy: (width / 2) as f32,
|
||||
r: 0.0,
|
||||
g: 0.34,
|
||||
b: 0.88,
|
||||
t1: Transform::identity(),
|
||||
t2: Transform::identity(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Gain access to the underlying pixels
|
||||
pub fn get_frame(&self) -> &[u32] {
|
||||
self.dt.get_data()
|
||||
}
|
||||
|
||||
/// Draw all of the shapes
|
||||
pub fn draw(&mut self, delta: f32) {
|
||||
// This is not a good way to blend colors.
|
||||
// But it's fine for a demo.
|
||||
self.r += delta;
|
||||
self.g += delta * 0.71;
|
||||
self.b += delta * 1.33;
|
||||
|
||||
self.dt.clear(SolidSource {
|
||||
g: ((self.g.sin() + 1.0) * 127.5).round() as u8,
|
||||
r: ((self.r.sin() + 1.0) * 127.5).round() as u8,
|
||||
b: ((self.b.sin() + 1.0) * 127.5).round() as u8,
|
||||
a: 0xff,
|
||||
});
|
||||
|
||||
self.t1 = self.t1.post_translate(Vector2D::new(-self.cx, -self.cy));
|
||||
self.t1 = self.t1.post_rotate(Angle { radians: delta });
|
||||
self.t1 = self.t1.post_translate(Vector2D::new(self.cx, self.cy));
|
||||
self.dt.set_transform(&self.t1);
|
||||
|
||||
let mut pb = PathBuilder::new();
|
||||
pb.move_to(100., 10.);
|
||||
pb.cubic_to(150., 40., 175., 0., 200., 10.);
|
||||
pb.quad_to(120., 100., 80., 200.);
|
||||
pb.quad_to(150., 180., 300., 300.);
|
||||
pb.close();
|
||||
let path = pb.finish();
|
||||
|
||||
let gradient = Source::new_radial_gradient(
|
||||
Gradient {
|
||||
stops: vec![
|
||||
GradientStop {
|
||||
position: 0.2,
|
||||
color: Color::new(0xff, 0, 0xff, 0),
|
||||
},
|
||||
GradientStop {
|
||||
position: 0.8,
|
||||
color: Color::new(0xff, 0xff, 0xff, 0xff),
|
||||
},
|
||||
GradientStop {
|
||||
position: 1.,
|
||||
color: Color::new(0xff, 0xff, 0, 0xff),
|
||||
},
|
||||
],
|
||||
},
|
||||
Point::new(150., 150.),
|
||||
128.,
|
||||
Spread::Pad,
|
||||
);
|
||||
self.dt.fill(&path, &gradient, &DrawOptions::new());
|
||||
|
||||
self.t2 = self.t2.post_translate(Vector2D::new(-self.cx, -self.cy));
|
||||
self.t2 = self.t2.post_rotate(Angle { radians: -delta });
|
||||
self.t2 = self.t2.post_translate(Vector2D::new(self.cx, self.cy));
|
||||
self.dt.set_transform(&self.t2);
|
||||
|
||||
let mut pb = PathBuilder::new();
|
||||
pb.move_to(100., 100.);
|
||||
pb.line_to(300., 300.);
|
||||
pb.line_to(200., 300.);
|
||||
let path = pb.finish();
|
||||
|
||||
self.dt.stroke(
|
||||
&path,
|
||||
&Source::Solid(SolidSource {
|
||||
r: 0x0,
|
||||
g: 0x0,
|
||||
b: 0x80,
|
||||
a: 0x80,
|
||||
}),
|
||||
&StrokeStyle {
|
||||
cap: LineCap::Round,
|
||||
join: LineJoin::Round,
|
||||
width: 10.,
|
||||
miter_limit: 2.,
|
||||
dash_array: vec![10., 18.],
|
||||
dash_offset: 16.,
|
||||
},
|
||||
&DrawOptions::new(),
|
||||
);
|
||||
}
|
||||
}
|
BIN
img/raqote-winit.png
Normal file
BIN
img/raqote-winit.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
Loading…
Reference in a new issue