Skip to content

Commit

Permalink
push more staging changes (still wip)
Browse files Browse the repository at this point in the history
  • Loading branch information
burgerindividual committed Aug 5, 2023
1 parent 48d7cc3 commit 7f73019
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 59 deletions.
128 changes: 84 additions & 44 deletions native/core/src/graph/coords.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,88 +22,129 @@ pub struct LocalCoordinateContext {
iter_start_section_idx: LocalSectionIndex,
iter_start_section_coords: u8x3,

// similar to the previous, but rounded to the closest region coord and relative to the world
// similar to the previous, but rounded to the closest region coord and relative to the worldFd
// origin, rather than the data structure origin.
iter_start_region_coord: i32x3,
iter_start_region_coords: i32x3,

fog_distance_squared: f32,

world_bottom_section_y: i32,
world_top_section_y: i32,
world_bottom_section_y: i8,
world_top_section_y: i8,
}

impl LocalCoordinateContext {
pub const NODE_HEIGHT_OFFSET: u8 = 128;

pub fn new(
world_pos: f64x3,
planes: [f32x6; 4],
fog_distance: f32,
section_view_distance: i32,
world_bottom_section_y: i32,
world_top_section_y: i32,
world_bottom_section_y: i8,
world_top_section_y: i8,
) -> Self {
let frustum = LocalFrustum::new(planes);

let camera_section_world_coords = world_pos.floor().cast::<i64>() >> i64x3::splat(4);

// the cast to u8 puts it in the local coordinate space
// the cast to u8 puts it in the local coordinate space by effectively doing a mod 256
let camera_section_coords = camera_section_world_coords.cast::<u8>();
let camera_coords = (world_pos % f64x3::splat(256.0)).cast::<f32>();

let camera_coords = (camera_section_coords.cast::<i32>() << i32x3::splat(4)).cast::<f32>();
let iter_start_section_coords = simd_swizzle!(
camera_section_coords - Simd::splat(section_view_distance),
Simd::splat(world_bottom_section_y as u8),
[First(X), Second(0), First(Z)]
);
let iter_start_section_idx = LocalSectionIndex::pack(iter_start_section_coords);

// this lower bound may not be necessary
let fog_distance_capped = fog_distance.min(((section_view_distance + 1) << 4) as f32);
let fog_distance_squared = fog_distance_capped * fog_distance_capped;

LocalCoordinateContext {
frustum,
camera_coords,
camera_section_coords,
iter_start_section_idx: LocalSectionIndex(),
iter_start_region_coord: Default::default(),
iter_start_section_idx,
iter_start_section_coords,
iter_start_region_coords,
fog_distance_squared,
world_bottom_section_y,
world_top_section_y,
}
}

#[inline(always)]
pub fn bounds_inside_world(&self, local_bounds: LocalBoundingBox) -> BoundsCheckResult {
// on the x and z axis, check if the bounding box is inside the fog.
let camera_coords_xz = simd_swizzle!(self.camera_coords, [X, Z, X, Z]);

// the first pair of lanes is the closest xz to the player in the chunk,
// the second pair of lanes is the furthest xz from the player in the chunk
let extrema_in_chunk = camera_coords_xz
.simd_min(simd_swizzle!(
local_bounds.min,
local_bounds.max,
[Second(X), Second(Z), First(X), First(Z)]
))
.simd_max(simd_swizzle!(
local_bounds.min,
local_bounds.max,
[First(X), First(Z), Second(X), Second(Z)]
));

let differences = camera_coords_xz - extrema_in_chunk;
pub fn bounds_inside_world_height<const LEVEL: u8>(
&self,
local_node_height: i8,
) -> BoundsCheckResult {
let node_min_y = local_node_height as i32;
let node_max_y = node_min_y + (1 << LEVEL) - 1;
let world_min_y = self.world_bottom_section_y as i32;
let world_max_y = self.world_top_section_y as i32;

let min_in_bounds = node_min_y >= world_min_y && node_min_y <= world_max_y;
let max_in_bounds = node_max_y >= world_min_y && node_max_y <= world_max_y;

unsafe { BoundsCheckResult::from_int_unchecked(min_in_bounds as u8 + max_in_bounds as u8) }
}

// this only cares about the x and z axis
#[inline(always)]
pub fn bounds_inside_fog<const LEVEL: u8>(
&self,
local_bounds: LocalBoundingBox,
) -> BoundsCheckResult {
// find closest to (0,0) because the bounding box coordinates are relative to the camera
let closest_in_chunk = local_bounds
.min
.abs()
.simd_lt(local_bounds.max.abs())
.select(local_bounds.min, local_bounds.max);

let furthest_in_chunk = {
let adjusted_int = unsafe {
// minus 1 if the input is negative
// SAFETY: values will never be out of range
closest_in_chunk.to_int_unchecked::<i32>()
+ (closest_in_chunk.to_bits().cast::<i32>() >> Simd::splat(31))
};

let add_bit = Simd::splat(0b1000 << LEVEL);
// additive is nonzero if the bit is *not* set
let additive = ((adjusted_int & add_bit) ^ add_bit) << Simd::splat(1);

// set the bottom (4 + LEVEL) bits to 0
let bitmask = Simd::splat(-1 << (4 + LEVEL));

((adjusted_int + additive) & bitmask).cast::<f32>()
};

// combine operations and single out the XZ lanes on both extrema from here.
// also, we don't have to subtract from the camera pos because the bounds are already
// relative to it
let differences = simd_swizzle!(
closest_in_chunk,
furthest_in_chunk,
[First(X), First(Z), Second(X), Second(Z)]
);
let differences_squared = differences * differences;

// lane 1 is closest dist, lane 2 is furthest dist
// add Xs and Zs
let distances_squared =
simd_swizzle!(differences_squared, [0, 2]) + simd_swizzle!(differences_squared, [1, 3]);

let fog_result = unsafe {
// janky way of calculating the result from the two points
unsafe {
BoundsCheckResult::from_int_unchecked(
distances_squared
.simd_lt(f32x2::splat(self.fog_distance_squared))
.select(u32x2::splat(1), u32x2::splat(0))
.reduce_sum() as u8,
)
};

// on the y axis, check if the bounding box is inside the world height.
let height_result = BoundsCheckResult::Outside;

BoundsCheckResult::combine(fog_result, height_result)
}
}

#[inline(always)]
Expand All @@ -115,15 +156,13 @@ impl LocalCoordinateContext {
}

#[inline(always)]
pub fn node_get_local_bounds<const LEVEL: usize>(
&self,
local_origin: u8x3,
) -> LocalBoundingBox {
let min_pos = local_origin.cast::<f32>()
+ local_origin
pub fn node_get_local_bounds<const LEVEL: u8>(&self, local_node_pos: u8x3) -> LocalBoundingBox {
let min_pos = local_node_pos.cast::<f32>()
+ local_node_pos
.simd_lt(self.iter_start_section_coords)
.cast()
.select(Simd::splat(256.0_f32), Simd::splat(0.0_f32));
.select(Simd::splat(256.0_f32), Simd::splat(0.0_f32))
- self.camera_coords;

let max_pos = min_pos + Simd::splat((16 << LEVEL) as f32);

Expand Down Expand Up @@ -155,6 +194,7 @@ impl BoundsCheckResult {
}
}

/// Relative to the camera position
pub struct LocalBoundingBox {
pub min: f32x3,
pub max: f32x3,
Expand Down
34 changes: 21 additions & 13 deletions native/core/src/graph/frustum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,31 @@ impl LocalFrustum {
#[inline(always)]
pub fn test_local_bounding_box(&self, bb: &LocalBoundingBox) -> BoundsCheckResult {
unsafe {
// The unsafe mask shenanigans here just checks if the sign bit is set for each lane.
// This is faster than doing a manual comparison with something like simd_gt, and compiles
// down to 1 instruction each (vmaskmovps) on x86 machines with AVX.
// These unsafe mask shenanigans just check if the sign bit is set for each lane.
// This is faster than doing a manual comparison with something like simd_gt.
let is_neg_x =
Mask::from_int_unchecked(self.plane_xs.to_bits().cast::<i32>() >> Simd::splat(31));
let is_neg_y =
Mask::from_int_unchecked(self.plane_ys.to_bits().cast::<i32>() >> Simd::splat(31));
let is_neg_z =
Mask::from_int_unchecked(self.plane_zs.to_bits().cast::<i32>() >> Simd::splat(31));

let points_x =
Mask::from_int_unchecked(self.plane_xs.to_bits().cast::<i32>() >> Simd::splat(31))
.select(Simd::splat(bb.min.x()), Simd::splat(bb.max.x()));
let bb_min_x = Simd::splat(bb.min.x());
let bb_max_x = Simd::splat(bb.max.x());
let outside_bounds_x = is_neg_x.select(bb_min_x, bb_max_x);
let inside_bounds_x = is_neg_x.select(bb_max_x, bb_min_x);

let points_y =
Mask::from_int_unchecked(self.plane_ys.to_bits().cast::<i32>() >> Simd::splat(31))
.select(Simd::splat(bb.min.y()), Simd::splat(bb.max.y()));
let bb_min_y = Simd::splat(bb.min.y());
let bb_max_y = Simd::splat(bb.max.y());
let outside_bounds_y = is_neg_y.select(bb_min_y, bb_max_y);
let inside_bounds_y = is_neg_y.select(bb_max_y, bb_min_y);

let points_z =
Mask::from_int_unchecked(self.plane_zs.to_bits().cast::<i32>() >> Simd::splat(31))
.select(Simd::splat(bb.min.z()), Simd::splat(bb.max.z()));
let bb_min_z = Simd::splat(bb.min.z());
let bb_max_z = Simd::splat(bb.max.z());
let outside_bounds_z = is_neg_z.select(bb_min_z, bb_max_z);
let inside_bounds_z = is_neg_z.select(bb_max_z, bb_min_z);

let points_dot = self.plane_xs.fast_fma(
let outside_length_sq = self.plane_xs.fast_fma(
points_x,
self.plane_ys.fast_fma(points_y, self.plane_zs * points_z),
);
Expand Down
4 changes: 4 additions & 0 deletions native/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@ mod jni;
mod math;
mod mem;
mod panic;

pub fn test<const VAL: usize>() {
test::<{ VAL - 1 }>()
}
3 changes: 1 addition & 2 deletions native/core/src/math.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ pub trait Coords3<T> {
fn y(&self) -> T;
fn z(&self) -> T;
}
ays)]
fn x(&self) -

impl<T> Coords3<T> for Simd<T, 3>
where
T: SimdElement,
Expand Down

0 comments on commit 7f73019

Please sign in to comment.