-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a minifb frontend and a spinning square demo
The frontend adds support for writing simple demos with window creation, event handling, and a main loop, using the minifb crate.
- Loading branch information
1 parent
e469a7e
commit 07367be
Showing
6 changed files
with
215 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,22 @@ | ||
[package] | ||
name = "retrofire-demos" | ||
version = "0.1.0" | ||
version = "0.3.0" | ||
edition = "2021" | ||
license.workspace = true | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
re = { path = "../core", package="retrofire-core", features = ["std"] } | ||
rf = { path = "../front", package = "retrofire-front" } | ||
|
||
minifb = { version = "0.25.0", optional = true } | ||
softbuffer = { version = "0.3.0", optional = true } | ||
winit = { version = "0.28.6", optional = true } | ||
|
||
[features] | ||
minifb = ["dep:minifb", "rf/minifb"] | ||
|
||
[[bin]] | ||
name = "square" | ||
required-features = ["minifb"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
#![cfg(feature = "minifb")] | ||
|
||
use std::ops::ControlFlow::Continue; | ||
|
||
use re::geom::{vertex, Tri, Vertex}; | ||
use re::math::color::{rgb, Color3f}; | ||
use re::math::mat::{perspective, rotate_z, translate, viewport}; | ||
use re::math::{rads, vec2, vec3, Mat4x4, Vec3}; | ||
use re::render::raster::Frag; | ||
use re::render::shader::Shader; | ||
use re::render::{render, ModelToProjective, ModelToView}; | ||
use rf::minifb::Window; | ||
|
||
fn main() { | ||
let verts = [ | ||
vertex(vec3(-1.0, -1.0, 0.0), rgb(1.0, 0.3, 0.1)), | ||
vertex(vec3(-1.0, 1.0, 0.0), rgb(0.2, 0.8, 0.3)), | ||
vertex(vec3(1.0, -1.0, 0.0), rgb(0.2, 0.5, 1.0)), | ||
vertex(vec3(1.0, 1.0, 0.0), rgb(1.0, 0.3, 0.1)), | ||
]; | ||
|
||
let mut win = Window::builder() | ||
.title("minifb front demo") | ||
.size(640, 480) | ||
.build(); | ||
|
||
let shader = Shader::new( | ||
|Vertex { pos, attrib }: Vertex<Vec3, _>, | ||
mvp: &Mat4x4<ModelToProjective>| { | ||
vertex(mvp.apply(&pos.to()), attrib) | ||
}, | ||
|frag: Frag<Color3f>| frag.var.to_color4(), | ||
); | ||
|
||
let modelview = translate(vec3(0.0, 0.0, 2.0)); | ||
let project = perspective(1.0, 4.0 / 3.0, 0.1..1000.0); | ||
let viewport = viewport(vec2(10, 10)..vec2(630, 470)); | ||
|
||
win.run(|frame| { | ||
let secs = frame.t.as_secs_f32(); | ||
|
||
let mv: Mat4x4<ModelToView> = modelview | ||
.compose(&rotate_z(rads(secs))) | ||
.compose(&translate(vec3(0.0, 0.0, secs.sin()))) | ||
.to(); | ||
let mvp = mv.then(&project); | ||
|
||
render( | ||
&[Tri([0, 1, 2]), Tri([3, 2, 1])], | ||
&verts, | ||
&shader, | ||
&mvp, | ||
viewport, | ||
&mut frame.buf, | ||
); | ||
Continue(()) | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
//! Frontend using the `minifb` crate for window creation and event handling. | ||
use std::ops::ControlFlow::{self, Break}; | ||
use std::time::{Duration, Instant}; | ||
|
||
use minifb::{Key, KeyRepeat, WindowOptions}; | ||
|
||
use retrofire_core::render::target::Framebuf; | ||
use retrofire_core::util::buf::{AsMutSlice2, Buf2}; | ||
|
||
use crate::Frame; | ||
|
||
pub struct Window { | ||
/// The wrapped minifb window. | ||
pub imp: minifb::Window, | ||
/// The width and height of the window. | ||
pub size: (usize, usize), | ||
} | ||
|
||
/// Builder for creating `Window`s. | ||
pub struct Builder<'title> { | ||
pub size: (usize, usize), | ||
pub title: &'title str, | ||
pub max_fps: Option<f32>, | ||
pub opts: WindowOptions, | ||
} | ||
|
||
impl Default for Builder<'_> { | ||
fn default() -> Self { | ||
Self { | ||
size: (800, 600), | ||
title: "// retrofire application //", | ||
max_fps: Some(60.0), | ||
opts: WindowOptions::default(), | ||
} | ||
} | ||
} | ||
|
||
impl<'t> Builder<'t> { | ||
/// Sets the width and height of the window. | ||
pub fn size(mut self, w: usize, h: usize) -> Self { | ||
self.size = (w, h); | ||
self | ||
} | ||
/// Sets the title of the window. | ||
pub fn title(mut self, title: &'t str) -> Self { | ||
self.title = title; | ||
self | ||
} | ||
/// Sets the fps cap of the window. | ||
pub fn max_fps(mut self, fps: Option<f32>) -> Self { | ||
self.max_fps = fps; | ||
self | ||
} | ||
/// Sets other `minifb` options. | ||
pub fn options(mut self, opts: WindowOptions) -> Self { | ||
self.opts = opts; | ||
self | ||
} | ||
|
||
/// Creates the window. | ||
pub fn build(self) -> Window { | ||
let mut imp = minifb::Window::new( | ||
self.title, | ||
self.size.0, | ||
self.size.1, | ||
self.opts, | ||
) | ||
.unwrap(); | ||
imp.limit_update_rate( | ||
self.max_fps | ||
.map(|fps| Duration::from_secs_f32(1.0 / fps)), | ||
); | ||
Window { | ||
imp, | ||
size: self.size, | ||
} | ||
} | ||
} | ||
|
||
impl Window { | ||
/// Returns a window builder. | ||
pub fn builder() -> Builder<'static> { | ||
Builder::default() | ||
} | ||
|
||
/// Updates the window content with `fb`. | ||
/// # Panics | ||
pub fn present(&mut self, fb: &[u32]) { | ||
let (w, h) = self.size; | ||
self.imp.update_with_buffer(fb, w, h).unwrap(); | ||
} | ||
|
||
/// Repeatedly calls `frame_fn` | ||
pub fn run<F>(&mut self, mut frame_fn: F) | ||
where | ||
F: FnMut(&mut Frame) -> ControlFlow<()>, | ||
{ | ||
let (w, h) = self.size; | ||
let mut cb = Buf2::new_default(w, h); | ||
let mut zb = Buf2::new_default(w, h); | ||
|
||
let start = Instant::now(); | ||
let mut last = Instant::now(); | ||
loop { | ||
if !self.imp.is_open() | ||
|| self | ||
.imp | ||
.is_key_pressed(Key::Escape, KeyRepeat::No) | ||
{ | ||
return; | ||
} | ||
|
||
cb.fill(0); | ||
zb.fill(f32::INFINITY); | ||
|
||
let frame = &mut Frame { | ||
t: start.elapsed(), | ||
dt: last.elapsed(), | ||
buf: Framebuf { | ||
color_buf: cb.as_mut_slice2(), | ||
depth_buf: zb.as_mut_slice2(), | ||
}, | ||
}; | ||
last = Instant::now(); | ||
if let Break(()) = frame_fn(frame) { | ||
return; | ||
} | ||
self.present(cb.data_mut()); | ||
} | ||
} | ||
} |