Skip to content

Commit ac9cd91

Browse files
authored
Merge pull request #35 from hecrj/feature/ui
Basic GUI support
2 parents a13751f + a5d2647 commit ac9cd91

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+5714
-1002
lines changed

.travis.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ os:
77
- linux
88
- osx
99
- windows
10-
cache: cargo
1110
before_install:
1211
- |
1312
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then

CHANGELOG.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [Unreleased]
88
### Added
9+
- __Responsive GUI support!__ The new `ui` module can be used to extend a `Game`
10+
and build a user interface. [#35]
11+
- GUI runtime based on [Elm] and [The Elm Architecture].
12+
- Layouting based on Flexbox and powered by [`stretch`].
13+
- Built-in GUI widgets. Specifically: buttons, sliders, checkboxes, radio
14+
buttons, rows, and columns.
15+
- Built-in GUI renderer. It is capable of rendering all the built-in GUI
16+
widgets.
17+
- Customization. The `ui::core` module can be used to implement custom widgets
18+
and renderers.
19+
- `Input` trait. It allows to implement reusable input handlers. [#35]
20+
- `KeyboardAndMouse` input handler. Useful to quickstart development and have
21+
easy access to the keyboard and the mouse from the get-go. [#35]
22+
- `CursorTaken` and `CursorReturned` input events. They are fired when the cursor
23+
is used/freed by the user interface.
924
- Off-screen text rendering support. `Font::draw` now supports any `Target`
1025
instead of a window `Frame`. [#25]
1126
- `Game::debug` performance tracking. Time spent on this method is now shown in
@@ -18,17 +33,49 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1833
- Implementation of `ParallelExtend` for `Batch`. A `Batch` can now be populated
1934
using multiple threads, useful to improve performance when dealing with many
2035
thousands of quads. [#37]
36+
- `Text` alignment. It can be defined using the new `HorizontalAlignment` and
37+
- `VerticalAlignment` types in the `graphics` module. [#35]
38+
- `Font::measure`. It allows to measure the dimensions of any `Text`. [#35]
39+
- `Rectangle::contains`. It returns whether or not a `Rectangle` contains a
40+
given `Point`. [#35]
41+
- `Sprite::scale`. It can be used to change the `Sprite` size when drawed.
42+
- `Default` implementation for `Sprite`. [#35]
43+
- `Debug::ui_duration`. It returns the average time spent running the UI runtime.
2144
- Multiple gravity centers based on mouse clicks in the particles example. [#30]
2245

2346
### Changed
47+
- The `View` associated type has been removed. Thus, implementors of the `Game`
48+
trait are also meant to hold the game assets. This simplifies the API
49+
considerably, and it helps model your game state-view relationship with
50+
precision, avoiding inconsistencies. [#35]
51+
- The `Game::Input` associated type now has to implement the new `Input` trait.
52+
This splits code quite nicely, as the `on_input` method moves away from `Game`.
53+
It also makes `Input` implementors reusable. For instance, a `KeyboardAndMouse`
54+
type has been implemented that can be used out of the box! [#35]
55+
- The `Game::LoadingScreen` associated type has been introduced. Given that all
56+
the `Game` associated types implement a trait with a `load` method, wiring a
57+
loading screen now is as simple as writing its name. Because of this, the
58+
`Game::new` method is no longer necessary and it is dropped. [#35]
59+
- `Game::draw` now takes a `Frame` directly instead of a `Window`. [#35]
60+
- `LoadingScreen::on_progress` has been renamed to `LoadingScreen::draw` and it
61+
now receives a `Frame` instead of a `Window`. [#35]
2462
- The performance of the particles example has been improved considerably on all
2563
platforms. [#37]
2664

65+
### Removed
66+
- `Game::new`. `Game::load` should be used instead. [#35]
67+
- `Game::on_input`. Input handlers now must be implemented using the new `Input`
68+
trait. [#35]
69+
2770
[#25]: https://github.com/hecrj/coffee/pull/25
2871
[#26]: https://github.com/hecrj/coffee/pull/26
2972
[#28]: https://github.com/hecrj/coffee/pull/28
3073
[#30]: https://github.com/hecrj/coffee/pull/30
74+
[#35]: https://github.com/hecrj/coffee/pull/35
3175
[#37]: https://github.com/hecrj/coffee/pull/37
76+
[Elm]: https://elm-lang.org
77+
[The Elm Architecture]: https://guide.elm-lang.org/architecture/
78+
[`stretch`]: https://github.com/vislyhq/stretch
3279

3380

3481
## [0.2.0] - 2019-04-28

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ debug = []
3131
image = "0.21"
3232
nalgebra = "0.18"
3333
rayon = "1.0"
34+
stretch = "0.2"
35+
twox-hash = "1.3"
3436

3537
# gfx (OpenGL)
3638
gfx = { version = "0.18", optional = true }

README.md

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ bugs. [Feel free to contribute!]
1818
[Feel free to contribute!]: #contributing--feedback
1919

2020
## Features
21+
* Responsive, customizable GUI with built-in widgets
2122
* Declarative, type-safe asset loading
2223
* Loading screens with progress tracking
2324
* Built-in [debug view with performance metrics]
@@ -49,43 +50,43 @@ performance:
4950
opt-level = 2
5051
```
5152

53+
__Coffee moves fast and the `master` branch can contain breaking changes!__ If
54+
you want to learn about a specific release, check out [the release list].
55+
56+
[the release list]: https://github.com/hecrj/coffee/releases
57+
5258
## Overview
5359
Here is a minimal example that will open a window:
5460

5561
```rust
62+
use coffee::graphics::{Color, Frame, Window, WindowSettings};
63+
use coffee::load::Task;
5664
use coffee::{Game, Result, Timer};
57-
use coffee::graphics::{Color, Window, WindowSettings};
5865

5966
fn main() -> Result<()> {
6067
MyGame::run(WindowSettings {
6168
title: String::from("A caffeinated game"),
6269
size: (1280, 1024),
6370
resizable: true,
71+
fullscreen: false,
6472
})
6573
}
6674

6775
struct MyGame {
68-
// Your game state goes here...
76+
// Your game state and assets go here...
6977
}
7078

7179
impl Game for MyGame {
72-
type View = (); // No view data.
73-
type Input = (); // No input data.
74-
75-
const TICKS_PER_SECOND: u16 = 60; // Update rate
80+
type Input = (); // No input data
81+
type LoadingScreen = (); // No loading screen
7682

77-
fn new(_window: &mut Window) -> Result<(MyGame, Self::View, Self::Input)> {
83+
fn load(_window: &Window) -> Task<MyGame> {
7884
// Load your game assets here. Check out the `load` module!
79-
Ok((MyGame { /* ... */ }, (), ()))
80-
}
81-
82-
fn update(&mut self, _view: &Self::View, _window: &Window) {
83-
// Update your game here
85+
Task::new(|| MyGame { /* ... */ })
8486
}
8587

86-
fn draw(&self, _view: &mut Self::View, window: &mut Window, _timer: &Timer) {
88+
fn draw(&mut self, frame: &mut Frame, _timer: &Timer) {
8789
// Clear the current frame
88-
let mut frame = window.frame();
8990
frame.clear(Color::BLACK);
9091

9192
// Draw your game here. Check out the `graphics` module!
@@ -104,13 +105,15 @@ Coffee builds upon
104105
* [`winit`] for windowing and mouse/keyboard events.
105106
* [`gfx` pre-ll] for OpenGL support, based heavily on the [`ggez`] codebase.
106107
* [`wgpu`] for _experimental_ Vulkan, Metal, D3D11 and D3D12 support.
108+
* [`stretch`] for responsive GUI layouting based on Flexbox.
107109
* [`glyph_brush`] for TrueType font rendering.
108110
* [`nalgebra`] for the `Point`, `Vector`, and `Transformation` types.
109111
* [`image`] for image loading and texture array building.
110112

111113
[`winit`]: https://github.com/rust-windowing/winit
112114
[`gfx` pre-ll]: https://github.com/gfx-rs/gfx/tree/pre-ll
113115
[`wgpu`]: https://github.com/gfx-rs/wgpu
116+
[`stretch`]: https://github.com/vislyhq/stretch
114117
[`glyph_brush`]: https://github.com/alexheretic/glyph-brush/tree/master/glyph-brush
115118
[`nalgebra`]: https://github.com/rustsim/nalgebra
116119
[`image`]: https://github.com/image-rs/image
@@ -134,7 +137,10 @@ the [Rust Community Discord]. I go by `@lone_scientist` there.
134137

135138
## Credits / Thank you
136139
* [`ggez`], an awesome, easy-to-use, good game engine that introduced me to
137-
Rust a month ago. Its graphics implementation served me as a guide to
138-
implement OpenGL support for Coffee.
140+
Rust. Its graphics implementation served me as a guide to implement OpenGL
141+
support for Coffee.
142+
* [Kenney], creators of amazing free game assets with no strings attached. The
143+
built-in GUI renderer in Coffee uses a modified version of their UI sprites.
139144

140145
[`ggez`]: https://github.com/ggez/ggez
146+
[Kenney]: https://kenney.nl

examples/README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ OpenGL, we run:
88
cargo run --example <example> --features opengl
99
```
1010

11+
__Coffee moves fast and the `master` branch can contain breaking changes!__ If
12+
you want to learn about a specific release, check out [the release list].
13+
14+
[the release list]: https://github.com/hecrj/coffee/releases
15+
1116
## Particles
1217

1318
A particle gravity simulator that showcases a loading screen, input handling,
@@ -26,3 +31,14 @@ cargo run --example particles --features opengl,debug --release
2631
![Particles example][particles]
2732

2833
[particles]: https://github.com/hecrj/coffee/blob/master/images/examples/particles.png?raw=true
34+
35+
## User Interface
36+
37+
A tour showcasing the different built-in widgets available for building
38+
responsive user interfaces in Coffee.
39+
40+
```
41+
cargo run --example ui --features opengl,debug --release
42+
```
43+
44+
[![GUI](https://thumbs.gfycat.com/LivelyOnlyHypacrosaurus-size_restricted.gif)](https://gfycat.com/livelyonlyhypacrosaurus)

examples/color.rs

Lines changed: 36 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use coffee::graphics::{
22
Color, Font, Frame, Image, Point, Quad, Rectangle, Text, Window,
33
WindowSettings,
44
};
5-
use coffee::load::{loading_screen, Join, LoadingScreen, Task};
5+
use coffee::load::{loading_screen::ProgressBar, Join, Task};
66
use coffee::{Game, Result, Timer};
77

88
fn main() -> Result<()> {
@@ -14,31 +14,47 @@ fn main() -> Result<()> {
1414
})
1515
}
1616

17-
struct Colors;
18-
19-
impl Game for Colors {
20-
type View = View;
21-
type Input = ();
17+
struct Colors {
18+
palette: Image,
19+
font: Font,
20+
}
2221

23-
const TICKS_PER_SECOND: u16 = 10;
22+
impl Colors {
23+
const PRUSSIAN_BLUE: Color = Color {
24+
r: 0.0,
25+
g: 0.1922,
26+
b: 0.3255,
27+
a: 1.0,
28+
};
2429

25-
fn new(window: &mut Window) -> Result<(Self, Self::View, Self::Input)> {
26-
let load = Task::stage("Loading view...", View::load());
30+
fn load() -> Task<Colors> {
31+
(
32+
Task::using_gpu(|gpu| {
33+
Image::from_colors(gpu, &[Self::PRUSSIAN_BLUE])
34+
}),
35+
Font::load(include_bytes!(
36+
"../resources/font/Inconsolata-Regular.ttf"
37+
)),
38+
)
39+
.join()
40+
.map(|(palette, font)| Colors { palette, font })
41+
}
42+
}
2743

28-
let mut loading_screen = loading_screen::ProgressBar::new(window.gpu());
29-
let view = loading_screen.run(load, window)?;
44+
impl Game for Colors {
45+
type Input = ();
46+
type LoadingScreen = ProgressBar;
3047

31-
Ok((Colors, view, ()))
48+
fn load(_window: &Window) -> Task<Self> {
49+
Task::stage("Loading view...", Colors::load())
3250
}
3351

34-
fn update(&mut self, _view: &Self::View, _window: &Window) {}
35-
36-
fn draw(&self, view: &mut Self::View, frame: &mut Frame, _timer: &Timer) {
52+
fn draw(&mut self, frame: &mut Frame, _timer: &Timer) {
3753
frame.clear(Color::new(0.5, 0.5, 0.5, 1.0));
3854

3955
let target = &mut frame.as_target();
4056

41-
view.palette.draw(
57+
self.palette.draw(
4258
Quad {
4359
source: Rectangle {
4460
x: 0.0,
@@ -52,41 +68,14 @@ impl Game for Colors {
5268
target,
5369
);
5470

55-
view.font.add(Text {
56-
content: String::from("Prussian blue"),
71+
self.font.add(Text {
72+
content: "Prussian blue",
5773
position: Point::new(20.0, 500.0),
5874
size: 50.0,
59-
color: View::PRUSSIAN_BLUE,
75+
color: Self::PRUSSIAN_BLUE,
6076
..Text::default()
6177
});
6278

63-
view.font.draw(target);
64-
}
65-
}
66-
67-
struct View {
68-
palette: Image,
69-
font: Font,
70-
}
71-
72-
impl View {
73-
const PRUSSIAN_BLUE: Color = Color {
74-
r: 0.0,
75-
g: 0.1922,
76-
b: 0.3255,
77-
a: 1.0,
78-
};
79-
80-
fn load() -> Task<View> {
81-
(
82-
Task::using_gpu(|gpu| {
83-
Image::from_colors(gpu, &[Self::PRUSSIAN_BLUE])
84-
}),
85-
Font::load(include_bytes!(
86-
"../resources/font/Inconsolata-Regular.ttf"
87-
)),
88-
)
89-
.join()
90-
.map(|(palette, font)| View { palette, font })
79+
self.font.draw(target);
9180
}
9281
}

0 commit comments

Comments
 (0)