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:
parent
2782a2dd13
commit
c42a898c2c
4 changed files with 79 additions and 73 deletions
|
@ -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)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue