Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions common/src/main/rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions common/src/main/rust/marten/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ log.workspace = true
fern.workspace = true
humantime.workspace = true
colored.workspace = true
glamx = { version = "0.1" }

#rapier3d = { git = "https://github.com/ryanhcode/rapier", rev = "a728067629d4f85cef99f388e12c9b0ee8cd1164", features = ["simd-nightly", "parallel"] }
#parry3d = { version = "0.26.0", features = ["simd-nightly"] }
36 changes: 29 additions & 7 deletions common/src/main/rust/marten/src/level.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
//! A sparse voxel world.

use crate::octree::SubLevelOctree;
use glamx::{IVec3, Vec3};
use jni::JNIEnv;
use jni::descriptors::Desc;
use jni::objects::{GlobalRef, JMethodID};
use jni::sys::jdouble;

/// log_2 of the size of a chunk
pub const CHUNK_SHIFT: u8 = 4;
Expand Down Expand Up @@ -40,7 +42,7 @@ impl ChunkSection {
/// # Safety
/// This method assumes that the coordinate is > than 0 and < than `CHUNK_SIZE` on all axes.
#[inline(always)]
fn get_index(&self, x: i32, y: i32, z: i32) -> usize {
fn get_index(&self, IVec3 { x, y, z }: IVec3) -> usize {
(x + (z << 4) + (y << 8)) as usize
}

Expand All @@ -49,8 +51,8 @@ impl ChunkSection {
/// # Safety
/// This method assumes that the coordinate is > than 0 and < than `CHUNK_SIZE` on all axes.
/// If the coordinate is out of bounds, behavior is undefined.
pub fn set_block(&mut self, x: i32, y: i32, z: i32, state: BlockState) {
let index = self.get_index(x, y, z);
pub fn set_block(&mut self, pos: IVec3, state: BlockState) {
let index = self.get_index(pos);
self.blocks[index] = state;
}

Expand All @@ -59,8 +61,8 @@ impl ChunkSection {
/// # Safety
/// This method assumes that the coordinate is >= than 0 and < than `CHUNK_SIZE` on all axes.
/// If the coordinate is out of bounds, behavior is undefined.
pub fn get_block(&self, x: i32, y: i32, z: i32) -> BlockState {
let index = self.get_index(x, y, z);
pub fn get_block(&self, pos: IVec3) -> BlockState {
let index = self.get_index(pos);
unsafe { *self.blocks.get_unchecked(index) }
}
}
Expand All @@ -76,12 +78,26 @@ unsafe impl<'local> Desc<'local, JMethodID> for &SableMethodID {
}
}

#[derive(Debug, Clone, Copy)]
pub struct CollisionBox {
pub min: Vec3,
pub max: Vec3,
}
impl From<[jdouble; 6]> for CollisionBox {
fn from(value: [jdouble; 6]) -> Self {
let [min_x, min_y, min_z, max_x, max_y, max_z] = value.map(|v| v as f32);
Self {
min: Vec3::new(min_x, min_y, min_z),
max: Vec3::new(max_x, max_y, max_z),
}
}
}

/// The physics data of a blockstate
#[derive(Debug)]
pub struct VoxelColliderData {
/// Collision boxes within the 0-1 voxel space.
/// Formatted [min_x, min_y, min_z, max_x, max_y, max_z]
pub collision_boxes: Vec<(f32, f32, f32, f32, f32, f32)>,
pub collision_boxes: Vec<CollisionBox>,

/// If this should be treated as a fluid for buoyancy
pub is_fluid: bool,
Expand Down Expand Up @@ -133,6 +149,12 @@ impl OctreeChunkSection {
}
}

impl Default for OctreeChunkSection {
fn default() -> Self {
Self::new()
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VoxelPhysicsState {
Empty,
Expand Down
23 changes: 11 additions & 12 deletions common/src/main/rust/marten/src/octree.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! Flat octree for integer data

use glamx::IVec3;

/// The max size we allow an octree buffer to occupy
const MAX_SIZE: i32 = i32::MAX - 8 * 2;

Expand Down Expand Up @@ -55,7 +57,7 @@ impl SubLevelOctree {

/// @return a unique 0-7 index from a given x, y, z position in 0-1 ranges
#[inline(always)]
fn get_octant_index(x: i32, y: i32, z: i32) -> i32 {
fn get_octant_index(IVec3 { x, y, z }: IVec3) -> i32 {
(x & 1) | ((y & 1) << 1) | ((z & 1) << 2)
}

Expand Down Expand Up @@ -146,15 +148,13 @@ impl SubLevelOctree {
///
/// # Arguments
///
/// * `x` - the x position
/// * `y` - the y position
/// * `z` - the z position
/// * `pos` - the position
/// * `block` - the block ID
///
/// # Returns
///
/// * `bool` - if the insert modified the tree
pub fn insert(&mut self, x: i32, y: i32, z: i32, block: i32) -> bool {
pub fn insert(&mut self, pos: IVec3, block: i32) -> bool {
let mut shift = self.log_size - 1;
let mut index = 0;
let mut node = self.buffer[index as usize];
Expand All @@ -167,7 +167,7 @@ impl SubLevelOctree {
return false; // already equivalent
}

let octant_index = Self::get_octant_index(x >> shift, y >> shift, z >> shift);
let octant_index = Self::get_octant_index(pos >> shift);

if node > 0 {
branches_visited[branch_index as usize] = index;
Expand Down Expand Up @@ -197,18 +197,17 @@ impl SubLevelOctree {
///
/// # Arguments
///
/// * `x` - the x position
/// * `y` - the y position
/// * `z` - the z position
/// * `pos` - the position
/// * `log_size_of_target` - the log size of the target
///
/// # Returns
///
/// * `i32` - the block ID at the position, or -2 if the position is empty
pub fn query(&self, x: i32, y: i32, z: i32, log_size_of_target: i32) -> i32 {
pub fn query(&self, pos: IVec3, log_size_of_target: i32) -> i32 {
let size = 1 << self.log_size;

// check if out of bounds
if x < 0 || y < 0 || z < 0 || x >= size || y >= size || z >= size {
if pos.cmplt(IVec3::ZERO).any() || pos.cmpge(IVec3::splat(size)).any() {
return -2;
}

Expand All @@ -223,7 +222,7 @@ impl SubLevelOctree {
return -2;
}

let octant_index = Self::get_octant_index(x >> shift, y >> shift, z >> shift);
let octant_index = Self::get_octant_index(pos >> shift);

index = node + octant_index;
node = *unsafe { self.buffer.get_unchecked(index as usize) };
Expand Down
16 changes: 8 additions & 8 deletions common/src/main/rust/rapier/benches/collision_benchmark.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use criterion::{Criterion, criterion_group, criterion_main};
use marten::Real;
use marten::octree::SubLevelOctree;
use rapier3d::glamx::{DVec3, IVec3};
use rapier3d::math::Pose3;
use rapier3d::na::Vector3;
use rapier3d::prelude::ColliderHandle;
use sable_rapier::ActiveLevelColliderInfo;
use sable_rapier::algo::{DEFAULT_COLLISION_PARALLEL_CUTOFF, find_collision_pairs};
Expand All @@ -15,9 +15,9 @@ fn setup_dummy_sable_handle_a() -> ActiveLevelColliderInfo {
ActiveLevelColliderInfo {
static_mount: None,
collider: ColliderHandle::default(),
local_bounds_min: Some(Vector3::<i32>::new(0, 0, 0)),
local_bounds_max: Some(Vector3::<i32>::new(128, 128, 128)),
center_of_mass: Some(Vector3::<f64>::new(62.5, 62.5, 62.5)),
local_bounds_min: Some(IVec3::ZERO),
local_bounds_max: Some(IVec3::splat(128)),
center_of_mass: Some(DVec3::splat(62.5)),
octree: Some(octree),
chunk_map: None,
scene_id: 0,
Expand All @@ -32,9 +32,9 @@ fn setup_dummy_sable_handle_b() -> ActiveLevelColliderInfo {
ActiveLevelColliderInfo {
static_mount: None,
collider: ColliderHandle::default(),
local_bounds_min: Some(Vector3::<i32>::new(128, 0, 0)),
local_bounds_max: Some(Vector3::<i32>::new(256, 128, 128)),
center_of_mass: Some(Vector3::<f64>::new(128.0 + 64.5, 64.5, 64.5)),
local_bounds_min: Some(IVec3::new(128, 0, 0)),
local_bounds_max: Some(IVec3::new(256, 128, 128)),
center_of_mass: Some(DVec3::new(128.0 + 64.5, 64.5, 64.5)),
octree: Some(octree),
chunk_map: None,
scene_id: 0,
Expand All @@ -51,7 +51,7 @@ fn setup_sphere(octree: &mut SubLevelOctree) {
let dy = y as f64 - 64.5;
let dz = z as f64 - 64.5;
if dx * dx + dy * dy + dz * dz <= 63.5 * 63.5 {
octree.insert(x, y, z, 1);
octree.insert(IVec3::new(x, y, z), 1);
}
}
}
Expand Down
Loading