embedded = []
hosted = ["dep:termios", "dep:libc"]
default = ["hosted"]
+hosted_full_speed = ["hosted"]
[profile.release]
panic = "abort"
-.PHONY: all run size dump emu clean
+.PHONY: all run size dump emu emu_full_speed clean
ARCH = $(shell uname -m)
ifneq ("$(ARCH)", "ppc64")
emu:
cargo run --release
+emu_full_speed:
+ cargo run --release --features=hosted_full_speed
+
clean:
cargo clean
@rm -f *.o rust_voxels_game.elf rust_voxels_game.bin rust_voxels_game.hex
}
}
-#[cfg(feature = "hosted")]
+#[cfg(all(feature = "hosted", not(feature = "hosted_full_speed")))]
fn console_write(b: u8) {
use core::{
sync::atomic::{AtomicU32, Ordering},
let _ = std::io::stdout().write_all(&[b]);
}
+#[cfg(feature = "hosted_full_speed")]
+fn console_write(b: u8) {
+ use std::io::Write;
+
+ let _ = std::io::stdout().write_all(&[b]);
+}
+
pub struct Console(());
impl Console {
-#[cfg(feature = "hosted")]
-use core::fmt;
-use core::ops::{
- Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Shl, ShlAssign, Shr,
- ShrAssign, Sub, SubAssign,
+use core::{
+ fmt,
+ ops::{
+ Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Shl, ShlAssign, Shr,
+ ShrAssign, Sub, SubAssign,
+ },
};
macro_rules! impl_assign_op {
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
pub struct Fix64(i64);
-#[cfg(feature = "hosted")]
impl fmt::Display for Fix64 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let frac_digits = (Fix64::FRAC_BITS + 3) / 4;
}
}
-#[cfg(feature = "hosted")]
impl fmt::Debug for Fix64 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
impl Div for Fix64 {
type Output = Self;
+ #[inline(always)]
fn div(self, rhs: Fix64) -> Self::Output {
Fix64((((self.0 as i128) << Self::FRAC_BITS) / rhs.0 as i128) as i64)
}
world.render(screen, pos, forward, right, down);
restore_cursor.map(|f| f(world));
screen.display(console);
- writeln!(console, "Press WASD to move, IJKL to change look dir, F to move down, R to move up").unwrap();
- writeln!(console, "0-9 to place a block, - to delete a block, ESC to exit.").unwrap();
+ writeln!(
+ console,
+ "Press WASD to move, IJKL to change look dir, F to move down, R to move up"
+ )
+ .unwrap();
+ writeln!(
+ console,
+ "0-9 to place a block, - to delete a block, ESC to exit."
+ )
+ .unwrap();
loop {
let (prev_pos, hit_pos) = world.get_hit_pos(pos, forward);
let mut new_pos = pos;
pub blocks: [[[Block; Self::SIZE]; Self::SIZE]; Self::SIZE],
}
+#[derive(Copy, Clone, Debug)]
struct RayCastDimension {
next_pos: i64,
next_t: Fix64,
}
impl RayCastDimension {
+ const fn at_inf(pos: i64) -> Self {
+ Self {
+ next_pos: pos,
+ next_t: Fix64::from_bits(i64::MAX),
+ t_step: Fix64::from_int(0),
+ pos_step: 0,
+ }
+ }
+ const fn is_at_inf(self) -> bool {
+ self.pos_step == 0
+ }
+ #[inline(always)]
fn new(start: Fix64, dir: Fix64) -> Option<Self> {
let pos_step = dir.signum();
if pos_step == 0 {
let array_pos = Self::array_pos(pos);
self.get_array_mut(array_pos)
}
+ #[inline(always)]
pub fn get(&self, pos: Vec3D<i64>) -> Option<&Block> {
let array_pos = Self::array_pos(pos);
self.get_array(array_pos)
pub fn positions() -> impl Iterator<Item = Vec3D<i64>> {
Self::array_positions().map(Self::from_array_pos)
}
+ #[inline(never)]
fn cast_ray_impl(
&self,
start: Vec3D<Fix64>,
};
f(pos, block)
};
- let mut pos = start.map(Fix64::floor).into_array();
+ let pos = start.map(Fix64::floor);
let mut ray_casters = start
.zip(dir)
- .map(|(start, dir)| RayCastDimension::new(start, dir))
+ .zip(pos)
+ .map(
+ #[inline(always)]
+ |((start, dir), pos)| {
+ RayCastDimension::new(start, dir).unwrap_or(RayCastDimension::at_inf(pos))
+ },
+ )
.into_array();
+ let mut pos = pos.into_array();
+ if ray_casters[0].is_at_inf() && ray_casters[1].is_at_inf() && ray_casters[2].is_at_inf() {
+ return ControlFlow::Break(());
+ }
loop {
f(Vec3D::from_array(pos))?;
- let mut min_index = None;
- let mut min_t = Fix64::from_bits(i64::MAX);
- for (index, ray_caster) in ray_casters.iter().enumerate() {
- let Some(ray_caster) = ray_caster else {
- continue;
+ macro_rules! do_step_at_min {
+ ($ray_casters:ident, $pos:ident, [$index:literal]) => {
+ $pos[$index] = $ray_casters[$index].next_pos;
+ $ray_casters[$index].step();
+ };
+ ($ray_casters:ident, $pos:ident, [$index0:literal, $index1:literal $(, $rest:literal)*]) => {
+ if $ray_casters[$index1].next_t < $ray_casters[$index0].next_t {
+ do_step_at_min!($ray_casters, $pos, [$index1 $(, $rest)*]);
+ } else {
+ do_step_at_min!($ray_casters, $pos, [$index0 $(, $rest)*]);
+ }
};
- if ray_caster.next_t < min_t {
- min_t = ray_caster.next_t;
- min_index = Some(index);
- }
}
- let Some(min_index) = min_index else {
- return ControlFlow::Break(());
- };
- let ray_caster = ray_casters[min_index].as_mut().unwrap();
- pos[min_index] = ray_caster.next_pos;
- ray_caster.step();
+ do_step_at_min!(ray_casters, pos, [0, 1, 2]);
}
}
pub fn cast_ray(