1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 06:16:04 +00:00

binary_search

This commit is contained in:
mat 2022-06-29 18:27:21 -05:00
parent 2782a2dd13
commit c42a898c2c
4 changed files with 79 additions and 73 deletions

View file

@ -14,16 +14,16 @@ pub enum Direction {
#[derive(Clone, Copy, Debug)]
pub enum Axis {
X,
Y,
Z,
X = 0,
Y = 1,
Z = 2,
}
#[derive(Clone, Copy, Debug)]
pub enum AxisCycle {
None,
Forward,
Backward,
None = 0,
Forward = 1,
Backward = 2,
}
impl Axis {
@ -36,6 +36,15 @@ impl Axis {
Axis::Z => z,
}
}
pub fn from_ordinal(ordinal: u32) -> Self {
match ordinal {
0 => Axis::X,
1 => Axis::Y,
2 => Axis::Z,
_ => panic!("Invalid ordinal {}", ordinal),
}
}
}
impl AxisCycle {
@ -57,11 +66,11 @@ impl AxisCycle {
Self::Backward => Self::Forward,
}
}
pub fn cycle(self, axis: Axis) -> Self {
pub fn cycle(self, axis: Axis) -> Axis {
match self {
Self::None => Self::None,
Self::Forward => Self::from_ordinal(floor_mod(axis as i32 + 1, 3)),
Self::Backward => Self::from_ordinal(floor_mod(axis as i32 - 1, 3)),
Self::None => axis,
Self::Forward => Axis::from_ordinal(floor_mod(axis as i32 + 1, 3)),
Self::Backward => Axis::from_ordinal(floor_mod(axis as i32 - 1, 3)),
}
}
}

View file

@ -41,3 +41,20 @@ pub fn floor_mod(x: i32, y: u32) -> u32 {
x as u32 % y
}
}
// TODO: make this generic
pub fn binary_search(mut min: u32, max: u32, predicate: &dyn Fn(u32) -> bool) -> u32 {
let mut diff = max - min;
while diff > 0 {
let diff_mid = diff / 2;
let mid = min + diff_mid;
if predicate(mid) {
diff = diff_mid;
} else {
min = mid + 1;
diff -= diff_mid + 1;
}
}
min
}

View file

@ -1,4 +1,4 @@
use azalea_core::BitSet;
use azalea_core::{Axis, BitSet};
// TODO: every impl of DiscreteVoxelShape could be turned into a single enum as an optimization
@ -19,9 +19,7 @@ pub trait DiscreteVoxelShape {
// }
// return false;
// }
fn x_size(&self) -> u32;
fn y_size(&self) -> u32;
fn z_size(&self) -> u32;
fn size(&self, axis: Axis) -> u32;
fn first_full_x(&self) -> u32;
fn first_full_y(&self) -> u32;
@ -126,14 +124,8 @@ impl BitSetDiscreteVoxelShape {
}
impl DiscreteVoxelShape for BitSetDiscreteVoxelShape {
fn x_size(&self) -> u32 {
self.x_size
}
fn y_size(&self) -> u32 {
self.y_size
}
fn z_size(&self) -> u32 {
self.z_size
fn size(&self, axis: Axis) -> u32 {
axis.choose(self.x_size, self.y_size, self.z_size)
}
fn first_full_x(&self) -> u32 {

View file

@ -1,7 +1,7 @@
use azalea_core::{Axis, AxisCycle};
use azalea_core::{binary_search, Axis, AxisCycle};
use crate::{BitSetDiscreteVoxelShape, DiscreteVoxelShape, AABB, EPSILON};
use std::ops::Add;
use std::{cmp, ops::Add};
pub struct Shapes {}
@ -40,9 +40,7 @@ impl Shapes {
pub trait VoxelShape {
fn shape(&self) -> Box<dyn DiscreteVoxelShape>;
fn get_x_coords(&self) -> Vec<f64>;
fn get_y_coords(&self) -> Vec<f64>;
fn get_z_coords(&self) -> Vec<f64>;
fn get_coords(&self, axis: Axis) -> Vec<f64>;
// TODO: optimization: should this be changed to return ArrayVoxelShape?
// i might change the implementation of empty_shape in the future so not 100% sure
@ -52,12 +50,22 @@ pub trait VoxelShape {
}
Box::new(ArrayVoxelShape::new(
self.shape(),
self.get_x_coords().iter().map(|c| c + x).collect(),
self.get_y_coords().iter().map(|c| c + y).collect(),
self.get_z_coords().iter().map(|c| c + z).collect(),
self.get_coords(Axis::X).iter().map(|c| c + x).collect(),
self.get_coords(Axis::Y).iter().map(|c| c + y).collect(),
self.get_coords(Axis::Z).iter().map(|c| c + z).collect(),
))
}
fn get(&self, axis: Axis, index: usize) -> f64 {
self.get_coords(axis)[index]
}
fn find_index(&self, axis: Axis, coord: f64) -> u32 {
binary_search(0, self.shape().size(axis) + 1, &|t| {
coord < self.get(axis, t as usize)
}) - 1
}
fn collide(&self, axis: &Axis, entity_box: &AABB, movement: f64) -> f64 {
self.collide_x(AxisCycle::between(*axis, Axis::X), entity_box, movement)
}
@ -77,25 +85,31 @@ pub trait VoxelShape {
let z_axis = inverse_axis_cycle.cycle(Axis::Z);
// i gave up on names at this point (these are the obfuscated names from fernflower)
let var9 = entity_box.max(x_axis);
let var11 = entity_box.min(x_axis);
let var9 = entity_box.max(&x_axis);
let var11 = entity_box.min(&x_axis);
let var13 = self.find_index(x_axis, var11 + EPSILON);
let var14 = self.find_index(x_axis, var9 - EPSILON);
let var15 = cmp::max(0, self.find_index(y_axis, entity_box.min(y_axis) + EPSILON));
let var15 = cmp::max(
0,
self.find_index(y_axis, entity_box.min(&y_axis) + EPSILON),
);
let var16 = cmp::min(
self.shape().get_size(y_axis),
self.find_index(y_axis, entity_box.max(y_axis) - EPSILON) + 1,
self.shape().size(y_axis),
self.find_index(y_axis, entity_box.max(&y_axis) - EPSILON) + 1,
);
let var17 = cmp::max(0, self.find_index(z_axis, entity_box.min(z_axis) + EPSILON));
let var17 = cmp::max(
0,
self.find_index(z_axis, entity_box.min(&z_axis) + EPSILON),
);
let var18 = cmp::min(
self.shape().get_size(z_axis),
self.find_index(z_axis, entity_box.max(z_axis) - EPSILON) + 1,
self.shape().size(z_axis),
self.find_index(z_axis, entity_box.max(&z_axis) - EPSILON) + 1,
);
let var19 = self.shape().get_size(x_axis);
let var19 = self.shape().size(x_axis);
if movement > 0. {
for var20 in var14 + 1..var19 {
@ -105,7 +119,7 @@ pub trait VoxelShape {
.shape()
.is_full_wide(inverse_axis_cycle, var20, var21, var22)
{
let var23 = self.get(x_axis, var20) - var9;
let var23 = self.get(x_axis, var20 as usize) - var9;
if var23 >= -EPSILON {
movement = cmp::min(movement, var23);
}
@ -158,9 +172,9 @@ impl ArrayVoxelShape {
ys: Vec<f64>,
zs: Vec<f64>,
) -> Self {
let x_size = shape.x_size() + 1;
let y_size = shape.y_size() + 1;
let z_size = shape.z_size() + 1;
let x_size = shape.size(Axis::X) + 1;
let y_size = shape.size(Axis::Y) + 1;
let z_size = shape.size(Axis::Z) + 1;
// Lengths of point arrays must be consistent with the size of the VoxelShape.
assert_eq!(x_size, xs.len() as u32);
@ -188,16 +202,8 @@ impl VoxelShape for ArrayVoxelShape {
self.shape.clone()
}
fn get_x_coords(&self) -> Vec<f64> {
self.xs.clone()
}
fn get_y_coords(&self) -> Vec<f64> {
self.ys.clone()
}
fn get_z_coords(&self) -> Vec<f64> {
self.zs.clone()
fn get_coords(&self, axis: Axis) -> Vec<f64> {
axis.choose(self.xs.clone(), self.ys.clone(), self.zs.clone())
}
}
@ -206,26 +212,8 @@ impl VoxelShape for CubeVoxelShape {
self.shape.clone()
}
fn get_x_coords(&self) -> Vec<f64> {
let size = self.shape.x_size();
let mut parts = Vec::with_capacity(size as usize);
for i in 0..size {
parts.push(i as f64 / size as f64);
}
parts
}
fn get_y_coords(&self) -> Vec<f64> {
let size = self.shape.y_size();
let mut parts = Vec::with_capacity(size as usize);
for i in 0..size {
parts.push(i as f64 / size as f64);
}
parts
}
fn get_z_coords(&self) -> Vec<f64> {
let size = self.shape.z_size();
fn get_coords(&self, axis: Axis) -> Vec<f64> {
let size = self.shape.size(axis);
let mut parts = Vec::with_capacity(size as usize);
for i in 0..size {
parts.push(i as f64 / size as f64);