mirror of
https://github.com/neocturne/MinedMap.git
synced 2025-03-04 17:23:33 +01:00
Move coord offset to new util module, make more efficient
div_floor_mod() generates inefficient code. For power-of-2 divisors, shift and mask can be used instead.
This commit is contained in:
parent
b80d9ee420
commit
21035a1f7f
4 changed files with 90 additions and 60 deletions
|
@ -8,39 +8,16 @@ use std::{
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use glam::Vec3;
|
use glam::Vec3;
|
||||||
use lru::LruCache;
|
use lru::LruCache;
|
||||||
use num_integer::div_mod_floor;
|
|
||||||
|
|
||||||
use minedmap::{
|
use minedmap::{
|
||||||
io::{fs, storage},
|
io::{fs, storage},
|
||||||
resource::{block_color, needs_biome},
|
resource::{block_color, needs_biome},
|
||||||
types::*,
|
types::*,
|
||||||
|
util::coord_offset,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{common::*, region_group::RegionGroup};
|
use super::{common::*, region_group::RegionGroup};
|
||||||
|
|
||||||
/// Offsets a chunk and block coordinate pair by a number of blocks
|
|
||||||
///
|
|
||||||
/// As the new coordinate may end up in a different region, a region offset
|
|
||||||
/// is returned together with the new chunk and block coordinates.
|
|
||||||
fn coord_offset<const AXIS: u8>(
|
|
||||||
chunk: ChunkCoord<AXIS>,
|
|
||||||
block: BlockCoord<AXIS>,
|
|
||||||
offset: i32,
|
|
||||||
) -> (i8, ChunkCoord<AXIS>, BlockCoord<AXIS>) {
|
|
||||||
const CHUNKS: i32 = CHUNKS_PER_REGION as i32;
|
|
||||||
const BLOCKS: i32 = BLOCKS_PER_CHUNK as i32;
|
|
||||||
let coord = chunk.0 as i32 * BLOCKS + block.0 as i32 + offset;
|
|
||||||
let (region_chunk, block) = div_mod_floor(coord, BLOCKS);
|
|
||||||
let (region, chunk) = div_mod_floor(region_chunk, CHUNKS);
|
|
||||||
(
|
|
||||||
region
|
|
||||||
.try_into()
|
|
||||||
.expect("the region coordinate should be in the valid range"),
|
|
||||||
ChunkCoord::new(chunk),
|
|
||||||
BlockCoord::new(block),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn biome_at(
|
fn biome_at(
|
||||||
region_group: &RegionGroup<Rc<ProcessedRegion>>,
|
region_group: &RegionGroup<Rc<ProcessedRegion>>,
|
||||||
chunk: ChunkCoords,
|
chunk: ChunkCoords,
|
||||||
|
@ -283,37 +260,3 @@ impl<'a> TileRenderer<'a> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_coord_offset() {
|
|
||||||
const CHUNKS: i32 = CHUNKS_PER_REGION as i32;
|
|
||||||
const BLOCKS: i32 = BLOCKS_PER_CHUNK as i32;
|
|
||||||
|
|
||||||
for chunk in ChunkX::iter() {
|
|
||||||
for block in BlockX::iter() {
|
|
||||||
assert_eq!(coord_offset(chunk, block, 0), (0, chunk, block));
|
|
||||||
assert_eq!(
|
|
||||||
coord_offset(chunk, block, -(CHUNKS * BLOCKS)),
|
|
||||||
(-1, chunk, block)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
coord_offset(chunk, block, CHUNKS * BLOCKS),
|
|
||||||
(1, chunk, block)
|
|
||||||
);
|
|
||||||
|
|
||||||
for offset in -(CHUNKS * BLOCKS)..(CHUNKS * BLOCKS) {
|
|
||||||
let (region2, chunk2, block2) = coord_offset(chunk, block, offset);
|
|
||||||
assert!((-1..=1).contains(®ion2));
|
|
||||||
let coord = chunk.0 as i32 * BLOCKS + block.0 as i32 + offset;
|
|
||||||
let coord2 =
|
|
||||||
((region2 as i32 * CHUNKS) + chunk2.0 as i32) * BLOCKS + block2.0 as i32;
|
|
||||||
assert_eq!(coord2, coord);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
pub mod io;
|
pub mod io;
|
||||||
pub mod resource;
|
pub mod resource;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
pub mod util;
|
||||||
pub mod world;
|
pub mod world;
|
||||||
|
|
|
@ -47,7 +47,8 @@ macro_rules! coord_type {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const BLOCKS_PER_CHUNK: usize = 16;
|
pub const BLOCK_BITS: u8 = 4;
|
||||||
|
pub const BLOCKS_PER_CHUNK: usize = 1 << BLOCK_BITS;
|
||||||
coord_type!(BlockCoord, BLOCKS_PER_CHUNK);
|
coord_type!(BlockCoord, BLOCKS_PER_CHUNK);
|
||||||
|
|
||||||
/// A block X coordinate relative to a chunk
|
/// A block X coordinate relative to a chunk
|
||||||
|
@ -136,7 +137,8 @@ impl Debug for SectionBlockCoords {
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct SectionY(pub i32);
|
pub struct SectionY(pub i32);
|
||||||
|
|
||||||
pub const CHUNKS_PER_REGION: usize = 32;
|
pub const CHUNK_BITS: u8 = 5;
|
||||||
|
pub const CHUNKS_PER_REGION: usize = 1 << CHUNK_BITS;
|
||||||
coord_type!(ChunkCoord, CHUNKS_PER_REGION);
|
coord_type!(ChunkCoord, CHUNKS_PER_REGION);
|
||||||
|
|
||||||
/// A chunk X coordinate relative to a region
|
/// A chunk X coordinate relative to a region
|
||||||
|
|
84
src/util.rs
Normal file
84
src/util.rs
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
use crate::types::*;
|
||||||
|
|
||||||
|
pub trait ShiftMask: Sized {
|
||||||
|
type MaskedOutput;
|
||||||
|
|
||||||
|
/// Apply a right shift to a value, and return both the result and the
|
||||||
|
/// bytes that were shifted out
|
||||||
|
fn shift_mask(self, shift: u8) -> (Self, Self::MaskedOutput);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShiftMask for u32 {
|
||||||
|
type MaskedOutput = u32;
|
||||||
|
|
||||||
|
fn shift_mask(self, shift: u8) -> (u32, u32) {
|
||||||
|
let mask = (1 << shift) - 1;
|
||||||
|
(self >> shift, self & mask)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShiftMask for i32 {
|
||||||
|
type MaskedOutput = u32;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn shift_mask(self, shift: u8) -> (i32, u32) {
|
||||||
|
let mask = (1 << shift) - 1;
|
||||||
|
(self >> shift, (self as u32) & mask)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Offsets a chunk and block coordinate pair by a number of blocks
|
||||||
|
///
|
||||||
|
/// As the new coordinate may end up in a different region, a region offset
|
||||||
|
/// is returned together with the new chunk and block coordinates.
|
||||||
|
#[inline]
|
||||||
|
pub fn coord_offset<const AXIS: u8>(
|
||||||
|
chunk: ChunkCoord<AXIS>,
|
||||||
|
block: BlockCoord<AXIS>,
|
||||||
|
offset: i32,
|
||||||
|
) -> (i8, ChunkCoord<AXIS>, BlockCoord<AXIS>) {
|
||||||
|
let coord = ((chunk.0 as i32) << BLOCK_BITS | block.0 as i32) + offset;
|
||||||
|
let (region_chunk, block) = coord.shift_mask(BLOCK_BITS);
|
||||||
|
let (region, chunk) = region_chunk.shift_mask(CHUNK_BITS);
|
||||||
|
(
|
||||||
|
region
|
||||||
|
.try_into()
|
||||||
|
.expect("the region coordinate should be in the valid range"),
|
||||||
|
ChunkCoord::new(chunk),
|
||||||
|
BlockCoord::new(block),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_coord_offset() {
|
||||||
|
const CHUNKS: i32 = CHUNKS_PER_REGION as i32;
|
||||||
|
const BLOCKS: i32 = BLOCKS_PER_CHUNK as i32;
|
||||||
|
|
||||||
|
for chunk in ChunkX::iter() {
|
||||||
|
for block in BlockX::iter() {
|
||||||
|
assert_eq!(coord_offset(chunk, block, 0), (0, chunk, block));
|
||||||
|
assert_eq!(
|
||||||
|
coord_offset(chunk, block, -(CHUNKS * BLOCKS)),
|
||||||
|
(-1, chunk, block)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
coord_offset(chunk, block, CHUNKS * BLOCKS),
|
||||||
|
(1, chunk, block)
|
||||||
|
);
|
||||||
|
|
||||||
|
for offset in -(CHUNKS * BLOCKS)..(CHUNKS * BLOCKS) {
|
||||||
|
let (region2, chunk2, block2) = coord_offset(chunk, block, offset);
|
||||||
|
assert!((-1..=1).contains(®ion2));
|
||||||
|
let coord = chunk.0 as i32 * BLOCKS + block.0 as i32 + offset;
|
||||||
|
let coord2 =
|
||||||
|
((region2 as i32 * CHUNKS) + chunk2.0 as i32) * BLOCKS + block2.0 as i32;
|
||||||
|
assert_eq!(coord2, coord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue