1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
use fxhash::hash32;
use glam::IVec2;
use crate::{
config::TILESET_SCALING,
proc_gen::tileset_loader::{Tile, TileOrientation, Tileset, TilesetPixelType},
};
pub fn split_position(world: IVec2, tileset: &Tileset) -> (IVec2, IVec2, TileOrientation) {
let s = tileset.dimensions.short as i32;
let tx = world.x.div_euclid(s);
let ty = world.y.div_euclid(s);
let fx = world.x.rem_euclid(s);
let fy = world.y.rem_euclid(s);
match (tx - ty).rem_euclid(4) {
// left half of horizontal tile
0 => (
IVec2::new(tx, ty),
IVec2::new(fx, fy),
TileOrientation::Horizontal,
),
// right half of horizontal tile
1 => (
IVec2::new(tx - 1, ty),
IVec2::new(fx + s, fy),
TileOrientation::Horizontal,
),
// top half of vertical tile
3 => (
IVec2::new(tx, ty),
IVec2::new(fx, fy),
TileOrientation::Vertical,
),
// bottom half of vertical tile
2 => (
IVec2::new(tx, ty - 1),
IVec2::new(fx, fy + s),
TileOrientation::Vertical,
),
_ => unreachable!(),
}
}
// better "%" for hashes since it prefers the high bits
#[inline]
fn reduce(h: u32, n: usize) -> usize {
(((h as u128) * (n as u128)) >> 32) as usize
}
fn pick_variant(tile_pos: IVec2, orientation: TileOrientation, tileset: &Tileset) -> &Tile {
let h = hash32(&tile_pos);
match orientation {
TileOrientation::Horizontal => {
&tileset.horizontal_tiles[reduce(h, tileset.horizontal_tiles.len())]
}
TileOrientation::Vertical => {
&tileset.vertical_tiles[reduce(h, tileset.vertical_tiles.len())]
}
}
}
// TODO: optimize
fn get_pixel_at_position(world: IVec2, tileset: &Tileset) -> TilesetPixelType {
let scaled_world = world.div_euclid(IVec2::new(TILESET_SCALING, TILESET_SCALING));
let (tile_pos, local, orientation) = split_position(scaled_world, tileset);
let tile = pick_variant(tile_pos, orientation, tileset);
let width = match orientation {
TileOrientation::Horizontal => tileset.dimensions.long as i32,
TileOrientation::Vertical => tileset.dimensions.short as i32,
};
tile.pixels[(local.x + local.y * width) as usize]
}
pub fn tiles_overlapping(
a: IVec2,
b: IVec2,
tileset: &Tileset,
) -> impl Iterator<Item = (IVec2, &Tile, TileOrientation)> {
let s = IVec2::new(
tileset.dimensions.short as i32,
tileset.dimensions.short as i32,
);
let ta = a.div_euclid(s) - 1;
let tb = (b - 1).div_euclid(s);
(ta.y..=tb.y)
.flat_map(move |ty| (ta.x..=tb.x).map(move |tx| (tx, ty)))
.filter_map(move |(tx, ty)| match (tx - ty).rem_euclid(4) {
0 => Some((
IVec2::new(tx, ty),
pick_variant(IVec2::new(tx, ty), TileOrientation::Horizontal, tileset),
TileOrientation::Horizontal,
)),
3 => Some((
IVec2::new(tx, ty),
pick_variant(IVec2::new(tx, ty), TileOrientation::Vertical, tileset),
TileOrientation::Vertical,
)),
_ => None,
})
}
// pub fn get_cell_at_position(world: IVec2, tileset: &Tileset) -> Cell {
// let pixel = get_pixel_at_position(world, tileset);
// match pixel {
// TilesetPixelType::Void => Cell::void(),
// TilesetPixelType::Terrain => Cell::from_material(MaterialId::Dirt),
// }
// }
|