Skip to content

Commit

Permalink
Merge pull request #35 from hecrj/feature/ui
Browse files Browse the repository at this point in the history
Basic GUI support
  • Loading branch information
hecrj authored Jun 9, 2019
2 parents a13751f + a5d2647 commit ac9cd91
Show file tree
Hide file tree
Showing 65 changed files with 5,714 additions and 1,002 deletions.
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ os:
- linux
- osx
- windows
cache: cargo
before_install:
- |
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
Expand Down
47 changes: 47 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

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

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

### Removed
- `Game::new`. `Game::load` should be used instead. [#35]
- `Game::on_input`. Input handlers now must be implemented using the new `Input`
trait. [#35]

[#25]: https://github.com/hecrj/coffee/pull/25
[#26]: https://github.com/hecrj/coffee/pull/26
[#28]: https://github.com/hecrj/coffee/pull/28
[#30]: https://github.com/hecrj/coffee/pull/30
[#35]: https://github.com/hecrj/coffee/pull/35
[#37]: https://github.com/hecrj/coffee/pull/37
[Elm]: https://elm-lang.org
[The Elm Architecture]: https://guide.elm-lang.org/architecture/
[`stretch`]: https://github.com/vislyhq/stretch


## [0.2.0] - 2019-04-28
Expand Down
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ debug = []
image = "0.21"
nalgebra = "0.18"
rayon = "1.0"
stretch = "0.2"
twox-hash = "1.3"

# gfx (OpenGL)
gfx = { version = "0.18", optional = true }
Expand Down
38 changes: 22 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ bugs. [Feel free to contribute!]
[Feel free to contribute!]: #contributing--feedback

## Features
* Responsive, customizable GUI with built-in widgets
* Declarative, type-safe asset loading
* Loading screens with progress tracking
* Built-in [debug view with performance metrics]
Expand Down Expand Up @@ -49,43 +50,43 @@ performance:
opt-level = 2
```

__Coffee moves fast and the `master` branch can contain breaking changes!__ If
you want to learn about a specific release, check out [the release list].

[the release list]: https://github.com/hecrj/coffee/releases

## Overview
Here is a minimal example that will open a window:

```rust
use coffee::graphics::{Color, Frame, Window, WindowSettings};
use coffee::load::Task;
use coffee::{Game, Result, Timer};
use coffee::graphics::{Color, Window, WindowSettings};

fn main() -> Result<()> {
MyGame::run(WindowSettings {
title: String::from("A caffeinated game"),
size: (1280, 1024),
resizable: true,
fullscreen: false,
})
}

struct MyGame {
// Your game state goes here...
// Your game state and assets go here...
}

impl Game for MyGame {
type View = (); // No view data.
type Input = (); // No input data.

const TICKS_PER_SECOND: u16 = 60; // Update rate
type Input = (); // No input data
type LoadingScreen = (); // No loading screen

fn new(_window: &mut Window) -> Result<(MyGame, Self::View, Self::Input)> {
fn load(_window: &Window) -> Task<MyGame> {
// Load your game assets here. Check out the `load` module!
Ok((MyGame { /* ... */ }, (), ()))
}

fn update(&mut self, _view: &Self::View, _window: &Window) {
// Update your game here
Task::new(|| MyGame { /* ... */ })
}

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

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

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

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

[`ggez`]: https://github.com/ggez/ggez
[Kenney]: https://kenney.nl
16 changes: 16 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ OpenGL, we run:
cargo run --example <example> --features opengl
```

__Coffee moves fast and the `master` branch can contain breaking changes!__ If
you want to learn about a specific release, check out [the release list].

[the release list]: https://github.com/hecrj/coffee/releases

## Particles

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

[particles]: https://github.com/hecrj/coffee/blob/master/images/examples/particles.png?raw=true

## User Interface

A tour showcasing the different built-in widgets available for building
responsive user interfaces in Coffee.

```
cargo run --example ui --features opengl,debug --release
```

[![GUI](https://thumbs.gfycat.com/LivelyOnlyHypacrosaurus-size_restricted.gif)](https://gfycat.com/livelyonlyhypacrosaurus)
83 changes: 36 additions & 47 deletions examples/color.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use coffee::graphics::{
Color, Font, Frame, Image, Point, Quad, Rectangle, Text, Window,
WindowSettings,
};
use coffee::load::{loading_screen, Join, LoadingScreen, Task};
use coffee::load::{loading_screen::ProgressBar, Join, Task};
use coffee::{Game, Result, Timer};

fn main() -> Result<()> {
Expand All @@ -14,31 +14,47 @@ fn main() -> Result<()> {
})
}

struct Colors;

impl Game for Colors {
type View = View;
type Input = ();
struct Colors {
palette: Image,
font: Font,
}

const TICKS_PER_SECOND: u16 = 10;
impl Colors {
const PRUSSIAN_BLUE: Color = Color {
r: 0.0,
g: 0.1922,
b: 0.3255,
a: 1.0,
};

fn new(window: &mut Window) -> Result<(Self, Self::View, Self::Input)> {
let load = Task::stage("Loading view...", View::load());
fn load() -> Task<Colors> {
(
Task::using_gpu(|gpu| {
Image::from_colors(gpu, &[Self::PRUSSIAN_BLUE])
}),
Font::load(include_bytes!(
"../resources/font/Inconsolata-Regular.ttf"
)),
)
.join()
.map(|(palette, font)| Colors { palette, font })
}
}

let mut loading_screen = loading_screen::ProgressBar::new(window.gpu());
let view = loading_screen.run(load, window)?;
impl Game for Colors {
type Input = ();
type LoadingScreen = ProgressBar;

Ok((Colors, view, ()))
fn load(_window: &Window) -> Task<Self> {
Task::stage("Loading view...", Colors::load())
}

fn update(&mut self, _view: &Self::View, _window: &Window) {}

fn draw(&self, view: &mut Self::View, frame: &mut Frame, _timer: &Timer) {
fn draw(&mut self, frame: &mut Frame, _timer: &Timer) {
frame.clear(Color::new(0.5, 0.5, 0.5, 1.0));

let target = &mut frame.as_target();

view.palette.draw(
self.palette.draw(
Quad {
source: Rectangle {
x: 0.0,
Expand All @@ -52,41 +68,14 @@ impl Game for Colors {
target,
);

view.font.add(Text {
content: String::from("Prussian blue"),
self.font.add(Text {
content: "Prussian blue",
position: Point::new(20.0, 500.0),
size: 50.0,
color: View::PRUSSIAN_BLUE,
color: Self::PRUSSIAN_BLUE,
..Text::default()
});

view.font.draw(target);
}
}

struct View {
palette: Image,
font: Font,
}

impl View {
const PRUSSIAN_BLUE: Color = Color {
r: 0.0,
g: 0.1922,
b: 0.3255,
a: 1.0,
};

fn load() -> Task<View> {
(
Task::using_gpu(|gpu| {
Image::from_colors(gpu, &[Self::PRUSSIAN_BLUE])
}),
Font::load(include_bytes!(
"../resources/font/Inconsolata-Regular.ttf"
)),
)
.join()
.map(|(palette, font)| View { palette, font })
self.font.draw(target);
}
}
Loading

0 comments on commit ac9cd91

Please sign in to comment.