Skip to content

Commit

Permalink
Create the 'input' module to replace 'lifecycle' (#604)
Browse files Browse the repository at this point in the history
First, the 'lifecycle' concept is less important than in previous
versions. There is just a single 'run' function that takes a Settings
instance and a closure, instead of a whole mess of behind-the-scenes
work. Most of the 'lifecycle' module (with the exception of a few Window
functions) is just about receiving input from the user. The new name
makes this more clear.

Additionally, there were some ergonomic issues with re-exporting blinds
structures rather than wrapping them in new code. Primarily, this
required understanding "what is the mint crate" and "why do I care" and
"how do I use it." End users of Quicksilver shouldn't have to concern
themselves with this, so these parts of the blinds API have been wrapped
over.

The Settings struct also needed to be decoupled from blinds. There are
more settings than just window management (for example, disable
searching for 'static/' assets) so there are now Quicksilver-specific
Settings.

The old module and its members have been left around for convenience,
because the alpha frequently requires updating for new features or
critical bugfixes. However, they are strongly deprecated and will be
subject to removal before beta.

Also, re-export Graphics and Input at the top level. They are needed
in literally every Quicksilver application, because you need to name the
types to run 'app.'
  • Loading branch information
ryanisaacg committed May 8, 2020
1 parent 4c0cb68 commit d105757
Show file tree
Hide file tree
Showing 20 changed files with 633 additions and 140 deletions.
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## WIP
- Fix compile issues with font-related features
- [BREAKING] Replace 'lifecycle' module with 'input' module:
- [BREAKING] Rename `EventStream` to `Input`
- Integrate the input state cache directly into `Input`
- [BREAKING] The `blinds::Window` struct and the `Event` enums are now wrapped with methods that use `quicksilver::geom::Vector` instead of `mint::Vector2`

## v0.4.0-alpha0.3
- Update `golem` to `v0.1.1` to fix non-power-of-2 textures
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ ttf = ["font", "elefont/rusttype", "rusttype"]
maintenance = { status = "actively-developed" }

[dependencies]
blinds = { version = "0.1.0", default-features = false, features = ["gl"] }
blinds = { version = "0.1.4", default-features = false, features = ["gl", "image"] }
bytemuck = "1.0"
elefont = { version = "0.1.3", features = ["rusttype", "unicode-normalization"], optional = true }
gestalt = { version = "0.1", optional = true }
Expand Down
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,21 @@ Then replace `src/main.rs` with the following (the contents of quicksilver's
use quicksilver::{
geom::{Rectangle, Vector},
graphics::{Color, Graphics},
lifecycle::{run, EventStream, Settings, Window},
Result,
input::{Input, Window},
Result, Settings, run,
};

fn main() {
run(
Settings {
size: Vector::new(800.0, 600.0).into(),
title: "Square Example",
..Settings::default()
},
app,
);
}

async fn app(window: Window, mut gfx: Graphics, mut events: EventStream) -> Result<()> {
async fn app(window: Window, mut gfx: Graphics, mut input: Input) -> Result<()> {
// Clear the screen to a blank, white color
gfx.clear(Color::WHITE);
// Paint a blue square with a red outline in the center of our screen
Expand All @@ -55,7 +54,7 @@ async fn app(window: Window, mut gfx: Graphics, mut events: EventStream) -> Resu
// Send the data to be drawn
gfx.present(&window)?;
loop {
while let Some(_) = events.next_event().await {}
while let Some(_) = input.next_event().await {}
}
}
```
Expand Down
12 changes: 3 additions & 9 deletions examples/00_window.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
// Example 0: The Window
// The simplest example: Do absolutely nothing other than just opening a window

use mint::Vector2;
use quicksilver::{
graphics::Graphics,
lifecycle::{run, EventStream, Settings, Window},
Result,
};
use quicksilver::{run, Graphics, Input, Result, Settings, Window};

// main() serves as our kicking-off point, but it doesn't have our application logic
// Actual logic goes in our app function, which is async
// 'run' manages loading resources asynchronously and dealing with the event loop
fn main() {
run(
Settings {
size: Vector2 { x: 800.0, y: 600.0 },
title: "Window Example",
..Settings::default()
},
Expand All @@ -23,9 +17,9 @@ fn main() {
}

// Our actual logic! Not much to see for this example
async fn app(_window: Window, _gfx: Graphics, mut events: EventStream) -> Result<()> {
async fn app(_window: Window, _gfx: Graphics, mut input: Input) -> Result<()> {
loop {
while let Some(_) = events.next_event().await {
while let Some(_) = input.next_event().await {
// Normally we'd do some processing here
}
// And then we'd do updates and drawing here
Expand Down
10 changes: 4 additions & 6 deletions examples/01_square.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,21 @@
// Open a window, and draw a colored square in it
use quicksilver::{
geom::{Rectangle, Vector},
graphics::{Color, Graphics},
lifecycle::{run, EventStream, Settings, Window},
Result,
graphics::Color,
run, Graphics, Input, Result, Settings, Window,
};

fn main() {
run(
Settings {
size: Vector::new(800.0, 600.0).into(),
title: "Square Example",
..Settings::default()
},
app,
);
}

async fn app(window: Window, mut gfx: Graphics, mut events: EventStream) -> Result<()> {
async fn app(window: Window, mut gfx: Graphics, mut input: Input) -> Result<()> {
// Clear the screen to a blank, white color
gfx.clear(Color::WHITE);
// Paint a blue square with a red outline in the center of our screen
Expand All @@ -29,6 +27,6 @@ async fn app(window: Window, mut gfx: Graphics, mut events: EventStream) -> Resu
// Send the data to be drawn
gfx.present(&window)?;
loop {
while let Some(_) = events.next_event().await {}
while let Some(_) = input.next_event().await {}
}
}
10 changes: 4 additions & 6 deletions examples/02_image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@
// Draw an image to the screen
use quicksilver::{
geom::{Rectangle, Vector},
graphics::{Color, Graphics, Image},
lifecycle::{run, EventStream, Settings, Window},
Result,
graphics::{Color, Image},
run, Graphics, Input, Result, Settings, Window,
};

fn main() {
run(
Settings {
size: Vector::new(800.0, 600.0).into(),
title: "Image Example",
..Settings::default()
},
Expand All @@ -19,7 +17,7 @@ fn main() {
}

// This time we might return an error, so we use a Result
async fn app(window: Window, mut gfx: Graphics, mut events: EventStream) -> Result<()> {
async fn app(window: Window, mut gfx: Graphics, mut input: Input) -> Result<()> {
// Load the image and wait for it to finish
// We also use '?' to handle errors like file-not-found
let image = Image::load(&gfx, "image.png").await?;
Expand All @@ -30,6 +28,6 @@ async fn app(window: Window, mut gfx: Graphics, mut events: EventStream) -> Resu
gfx.present(&window)?;

loop {
while let Some(_) = events.next_event().await {}
while let Some(_) = input.next_event().await {}
}
}
10 changes: 4 additions & 6 deletions examples/03_rgb_triangle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,21 @@
// Open a window, and draw the standard GPU triangle
use quicksilver::{
geom::Vector,
graphics::{Color, Element, Graphics, Mesh, Vertex},
lifecycle::{run, EventStream, Settings, Window},
Result,
graphics::{Color, Element, Mesh, Vertex},
run, Graphics, Input, Result, Settings, Window,
};

fn main() {
run(
Settings {
size: Vector::new(800.0, 600.0).into(),
title: "RGB Triangle Example",
..Settings::default()
},
app,
);
}

async fn app(window: Window, mut gfx: Graphics, mut events: EventStream) -> Result<()> {
async fn app(window: Window, mut gfx: Graphics, mut input: Input) -> Result<()> {
// Clear the screen to a blank, black color
gfx.clear(Color::BLACK);
// Paint a triangle with red, green, and blue vertices, blending the colors for the pixels in-between
Expand Down Expand Up @@ -54,6 +52,6 @@ async fn app(window: Window, mut gfx: Graphics, mut events: EventStream) -> Resu
// Send the data to be drawn
gfx.present(&window)?;
loop {
while let Some(_) = events.next_event().await {}
while let Some(_) = input.next_event().await {}
}
}
10 changes: 4 additions & 6 deletions examples/04_render_to_texture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,21 @@
// Render some data to an image, and draw that image to the screen
use quicksilver::{
geom::{Circle, Rectangle, Vector},
graphics::{Color, Graphics, Image, PixelFormat, Surface},
lifecycle::{run, EventStream, Settings, Window},
Result,
graphics::{Color, Image, PixelFormat, Surface},
run, Graphics, Input, Result, Settings, Window,
};

fn main() {
run(
Settings {
size: Vector::new(800.0, 600.0).into(),
title: "Square Example",
..Settings::default()
},
app,
);
}

async fn app(window: Window, mut gfx: Graphics, mut events: EventStream) -> Result<()> {
async fn app(window: Window, mut gfx: Graphics, mut input: Input) -> Result<()> {
gfx.clear(Color::WHITE);
// Create a surface, which allows rendering to an image
let mut surface = Surface::new(
Expand Down Expand Up @@ -50,6 +48,6 @@ async fn app(window: Window, mut gfx: Graphics, mut events: EventStream) -> Resu

gfx.present(&window)?;
loop {
while let Some(_) = events.next_event().await {}
while let Some(_) = input.next_event().await {}
}
}
10 changes: 4 additions & 6 deletions examples/05_blending.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@
use quicksilver::{
geom::{Rectangle, Vector},
graphics::blend::{BlendChannel, BlendFactor, BlendFunction, BlendInput, BlendMode},
graphics::{Color, Graphics, Image},
lifecycle::{run, EventStream, Settings, Window},
Result,
graphics::{Color, Image},
run, Graphics, Input, Result, Settings, Window,
};

fn main() {
run(
Settings {
size: Vector::new(800.0, 600.0).into(),
title: "Blend Example",
..Settings::default()
},
Expand All @@ -20,7 +18,7 @@ fn main() {
}

// This time we might return an error, so we use a Result
async fn app(window: Window, mut gfx: Graphics, mut events: EventStream) -> Result<()> {
async fn app(window: Window, mut gfx: Graphics, mut input: Input) -> Result<()> {
let image = Image::load(&gfx, "image.png").await?;
gfx.clear(Color::WHITE);
// Set the blend pipeline
Expand Down Expand Up @@ -63,6 +61,6 @@ async fn app(window: Window, mut gfx: Graphics, mut events: EventStream) -> Resu
gfx.present(&window)?;

loop {
while let Some(_) = events.next_event().await {}
while let Some(_) = input.next_event().await {}
}
}
10 changes: 4 additions & 6 deletions examples/06_timers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,21 @@
// Use timers to know when to draw and to have a consistent update cycle.
use quicksilver::{
geom::{Rectangle, Vector},
graphics::{Color, Graphics},
lifecycle::{run, EventStream, Settings, Window},
Result, Timer,
graphics::Color,
run, Graphics, Input, Result, Settings, Timer, Window,
};

fn main() {
run(
Settings {
size: Vector::new(800.0, 600.0).into(),
title: "Square Example",
..Settings::default()
},
app,
);
}

async fn app(window: Window, mut gfx: Graphics, mut events: EventStream) -> Result<()> {
async fn app(window: Window, mut gfx: Graphics, mut input: Input) -> Result<()> {
// Clear the screen to a blank, white color
gfx.clear(Color::WHITE);

Expand All @@ -31,7 +29,7 @@ async fn app(window: Window, mut gfx: Graphics, mut events: EventStream) -> Resu
let mut rect = Rectangle::new(Vector::new(0.0, 100.0), Vector::new(100.0, 100.0));

loop {
while let Some(_) = events.next_event().await {}
while let Some(_) = input.next_event().await {}

// We use a while loop rather than an if so that we can try to catch up in the event of having a slow down.
while update_timer.tick() {
Expand Down
10 changes: 4 additions & 6 deletions examples/07_text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,21 @@
// Write some text on the screen
use quicksilver::{
geom::Vector,
graphics::{Color, Graphics, VectorFont},
lifecycle::{run, EventStream, Settings, Window},
Result,
graphics::{Color, VectorFont},
run, Graphics, Input, Result, Settings, Window,
};

fn main() {
run(
Settings {
size: Vector::new(800.0, 600.0).into(),
title: "Font Example",
..Settings::default()
},
app,
);
}

async fn app(window: Window, mut gfx: Graphics, mut events: EventStream) -> Result<()> {
async fn app(window: Window, mut gfx: Graphics, mut input: Input) -> Result<()> {
// Load the Font, just like loading any other asset
let ttf = VectorFont::load("font.ttf").await?;
let mut font = ttf.to_renderer(&gfx, 72.0)?;
Expand All @@ -33,6 +31,6 @@ async fn app(window: Window, mut gfx: Graphics, mut events: EventStream) -> Resu
gfx.present(&window)?;

loop {
while let Some(_) = events.next_event().await {}
while let Some(_) = input.next_event().await {}
}
}
50 changes: 50 additions & 0 deletions examples/08_input.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Example 8: Input
// Respond to user keyboard and mouse input onscreen
use quicksilver::{
geom::{Circle, Rectangle, Vector},
graphics::Color,
input::Key,
run, Graphics, Input, Result, Settings, Window,
};

fn main() {
run(
Settings {
title: "Input Example",
..Settings::default()
},
app,
);
}

async fn app(window: Window, mut gfx: Graphics, mut input: Input) -> Result<()> {
// Keep track of the position of the square
let mut square_position = Vector::new(300, 300);
loop {
while let Some(_) = input.next_event().await {}
// Check the state of the keys, and move the square accordingly
const SPEED: f32 = 2.0;
if input.key_down(Key::A) {
square_position.x -= SPEED;
}
if input.key_down(Key::D) {
square_position.x += SPEED;
}
if input.key_down(Key::W) {
square_position.y -= SPEED;
}
if input.key_down(Key::S) {
square_position.y += SPEED;
}

gfx.clear(Color::WHITE);
// Paint a blue square at the given position
gfx.fill_rect(
&Rectangle::new(square_position, Vector::new(64.0, 64.0)),
Color::BLUE,
);
// Paint a red square at the mouse position
gfx.fill_circle(&Circle::new(input.mouse().location(), 32.0), Color::RED);
gfx.present(&window)?;
}
}
Loading

0 comments on commit d105757

Please sign in to comment.