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 SDL2](./examples/minimal-sdl2)
|
||||||
- [Minimal example with `winit`](./examples/minimal-winit)
|
- [Minimal example with `winit`](./examples/minimal-winit)
|
||||||
- [Pixel Invaders](./examples/invaders)
|
- [Pixel Invaders](./examples/invaders)
|
||||||
|
- [`raqote` example](./examples/raqote-winit)
|
||||||
|
|
||||||
## Troubleshooting
|
## 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