mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Site2 util
This commit is contained in:
parent
4b1900d3ea
commit
5642680687
@ -1,6 +1,7 @@
|
||||
use super::*;
|
||||
use crate::{
|
||||
block::block_from_structure,
|
||||
site2::util::Dir,
|
||||
util::{RandomField, Sampler},
|
||||
};
|
||||
use common::{
|
||||
@ -27,13 +28,13 @@ pub enum Primitive {
|
||||
Ramp {
|
||||
aabb: Aabb<i32>,
|
||||
inset: i32,
|
||||
dir: u8,
|
||||
dir: Dir,
|
||||
},
|
||||
Gable {
|
||||
aabb: Aabb<i32>,
|
||||
inset: i32,
|
||||
// X axis parallel or Y axis parallel
|
||||
dir: bool,
|
||||
dir: Dir,
|
||||
},
|
||||
Cylinder(Aabb<i32>),
|
||||
Cone(Aabb<i32>),
|
||||
@ -92,6 +93,7 @@ pub enum Fill {
|
||||
Sprite(SpriteKind),
|
||||
Block(Block),
|
||||
Brick(BlockKind, Rgb<u8>, u8),
|
||||
Gradient(util::gradient::Gradient, BlockKind),
|
||||
// TODO: the offset field for Prefab is a hack that breaks the compositionality of Translate,
|
||||
// we probably need an evaluator for the primitive tree that gets which point is queried at
|
||||
// leaf nodes given an input point to make Translate/Rotate work generally
|
||||
@ -115,19 +117,19 @@ impl Fill {
|
||||
Primitive::Ramp { aabb, inset, dir } => {
|
||||
let inset = (*inset).max(aabb.size().reduce_min());
|
||||
let inner = match dir {
|
||||
0 => Aabr {
|
||||
Dir::X => Aabr {
|
||||
min: Vec2::new(aabb.min.x - 1 + inset, aabb.min.y),
|
||||
max: Vec2::new(aabb.max.x, aabb.max.y),
|
||||
},
|
||||
1 => Aabr {
|
||||
Dir::NegX => Aabr {
|
||||
min: Vec2::new(aabb.min.x, aabb.min.y),
|
||||
max: Vec2::new(aabb.max.x - inset, aabb.max.y),
|
||||
},
|
||||
2 => Aabr {
|
||||
Dir::Y => Aabr {
|
||||
min: Vec2::new(aabb.min.x, aabb.min.y - 1 + inset),
|
||||
max: Vec2::new(aabb.max.x, aabb.max.y),
|
||||
},
|
||||
_ => Aabr {
|
||||
Dir::NegY => Aabr {
|
||||
min: Vec2::new(aabb.min.x, aabb.min.y),
|
||||
max: Vec2::new(aabb.max.x, aabb.max.y - inset),
|
||||
},
|
||||
@ -156,7 +158,7 @@ impl Fill {
|
||||
},
|
||||
Primitive::Gable { aabb, inset, dir } => {
|
||||
let inset = (*inset).max(aabb.size().reduce_min());
|
||||
let inner = if *dir {
|
||||
let inner = if dir.is_y() {
|
||||
Aabr {
|
||||
min: Vec2::new(aabb.min.x - 1 + inset, aabb.min.y),
|
||||
max: Vec2::new(aabb.max.x - inset, aabb.max.y),
|
||||
@ -270,6 +272,7 @@ impl Fill {
|
||||
.get((pos + Vec3::new(pos.z, pos.z, 0)) / Vec3::new(2, 2, 1))
|
||||
% *range as u32) as u8,
|
||||
)),
|
||||
Fill::Gradient(gradient, bk) => Some(Block::new(*bk, gradient.sample(pos.as_()))),
|
||||
Fill::Prefab(p, tr, seed) => p.get(pos - tr).ok().and_then(|sb| {
|
||||
let col_sample = canvas_info.col(canvas_info.wpos)?;
|
||||
block_from_structure(
|
||||
@ -403,22 +406,22 @@ impl Painter {
|
||||
self.prim(Primitive::Ramp {
|
||||
aabb,
|
||||
inset,
|
||||
dir: 0,
|
||||
dir: Dir::X,
|
||||
})
|
||||
.intersect(self.prim(Primitive::Ramp {
|
||||
aabb,
|
||||
inset,
|
||||
dir: 1,
|
||||
dir: Dir::NegX,
|
||||
}))
|
||||
.intersect(self.prim(Primitive::Ramp {
|
||||
aabb,
|
||||
inset,
|
||||
dir: 2,
|
||||
dir: Dir::Y,
|
||||
}))
|
||||
.intersect(self.prim(Primitive::Ramp {
|
||||
aabb,
|
||||
inset,
|
||||
dir: 3,
|
||||
dir: Dir::NegY,
|
||||
}))
|
||||
}
|
||||
|
||||
@ -460,6 +463,11 @@ impl<'a> PrimitiveRef<'a> {
|
||||
pub fn fill(self, fill: Fill) { self.painter.fill(self, fill); }
|
||||
|
||||
pub fn clear(self) { self.painter.fill(self, Fill::Block(Block::empty())); }
|
||||
|
||||
pub fn sample(self, sampling: impl Fn(Vec3<i32>) -> bool + 'static) -> PrimitiveRef<'a> {
|
||||
self.painter
|
||||
.prim(Primitive::sampling(self, Box::new(sampling)))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Structure {
|
||||
|
@ -1,6 +1,7 @@
|
||||
mod gen;
|
||||
pub mod plot;
|
||||
mod tile;
|
||||
pub mod util;
|
||||
|
||||
use self::tile::{HazardKind, KeepKind, Ori, RoofKind, Tile, TileGrid, TileKind, TILE_SIZE};
|
||||
pub use self::{
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::*;
|
||||
use crate::Land;
|
||||
use crate::{site2::util::Dir, Land};
|
||||
use common::terrain::{Block, BlockKind, SpriteKind};
|
||||
use rand::prelude::*;
|
||||
use vek::*;
|
||||
@ -118,7 +118,7 @@ impl Structure for House {
|
||||
.with_z(alt + roof + roof_height),
|
||||
},
|
||||
inset: roof_height,
|
||||
dir: true,
|
||||
dir: Dir::Y,
|
||||
}),
|
||||
painter.prim(Primitive::Gable {
|
||||
aabb: Aabb {
|
||||
@ -135,7 +135,7 @@ impl Structure for House {
|
||||
.with_z(alt + roof + roof_height - 1),
|
||||
},
|
||||
inset: roof_height - 1,
|
||||
dir: true,
|
||||
dir: Dir::Y,
|
||||
}),
|
||||
)
|
||||
},
|
||||
@ -154,7 +154,7 @@ impl Structure for House {
|
||||
.with_z(alt + roof + roof_height),
|
||||
},
|
||||
inset: roof_height,
|
||||
dir: false,
|
||||
dir: Dir::X,
|
||||
}),
|
||||
painter.prim(Primitive::Gable {
|
||||
aabb: Aabb {
|
||||
@ -171,7 +171,7 @@ impl Structure for House {
|
||||
.with_z(alt + roof + roof_height - 1),
|
||||
},
|
||||
inset: roof_height - 1,
|
||||
dir: false,
|
||||
dir: Dir::X,
|
||||
}),
|
||||
)
|
||||
},
|
||||
@ -190,7 +190,7 @@ impl Structure for House {
|
||||
.with_z(alt + roof + roof_height),
|
||||
},
|
||||
inset: roof_height,
|
||||
dir: true,
|
||||
dir: Dir::Y,
|
||||
}),
|
||||
painter.prim(Primitive::Gable {
|
||||
aabb: Aabb {
|
||||
@ -203,7 +203,7 @@ impl Structure for House {
|
||||
.with_z(alt + roof + roof_height - 1),
|
||||
},
|
||||
inset: roof_height - 1,
|
||||
dir: true,
|
||||
dir: Dir::Y,
|
||||
}),
|
||||
),
|
||||
_ => (
|
||||
@ -221,7 +221,7 @@ impl Structure for House {
|
||||
.with_z(alt + roof + roof_height),
|
||||
},
|
||||
inset: roof_height,
|
||||
dir: false,
|
||||
dir: Dir::X,
|
||||
}),
|
||||
painter.prim(Primitive::Gable {
|
||||
aabb: Aabb {
|
||||
@ -237,7 +237,7 @@ impl Structure for House {
|
||||
.with_z(alt + roof + roof_height - 1),
|
||||
},
|
||||
inset: roof_height - 1,
|
||||
dir: false,
|
||||
dir: Dir::X,
|
||||
}),
|
||||
),
|
||||
};
|
||||
@ -905,7 +905,7 @@ impl Structure for House {
|
||||
.with_z(alt + height),
|
||||
},
|
||||
inset: storey,
|
||||
dir: 3,
|
||||
dir: Dir::NegY,
|
||||
}),
|
||||
1 => painter.prim(Primitive::Ramp {
|
||||
aabb: Aabb {
|
||||
@ -921,7 +921,7 @@ impl Structure for House {
|
||||
.with_z(alt + height),
|
||||
},
|
||||
inset: storey,
|
||||
dir: 1,
|
||||
dir: Dir::NegX,
|
||||
}),
|
||||
2 => painter.prim(Primitive::Ramp {
|
||||
aabb: Aabb {
|
||||
@ -937,7 +937,7 @@ impl Structure for House {
|
||||
.with_z(alt + height),
|
||||
},
|
||||
inset: storey,
|
||||
dir: 2,
|
||||
dir: Dir::Y,
|
||||
}),
|
||||
_ => painter.prim(Primitive::Ramp {
|
||||
aabb: Aabb {
|
||||
@ -953,7 +953,7 @@ impl Structure for House {
|
||||
.with_z(alt + height),
|
||||
},
|
||||
inset: storey,
|
||||
dir: 0,
|
||||
dir: Dir::X,
|
||||
}),
|
||||
};
|
||||
let shed_empty = match self.front {
|
||||
@ -971,7 +971,7 @@ impl Structure for House {
|
||||
.with_z(alt + height - 1),
|
||||
},
|
||||
inset: storey - 1,
|
||||
dir: 3,
|
||||
dir: Dir::NegY,
|
||||
}),
|
||||
1 => painter.prim(Primitive::Ramp {
|
||||
aabb: Aabb {
|
||||
@ -987,7 +987,7 @@ impl Structure for House {
|
||||
.with_z(alt + height - 1),
|
||||
},
|
||||
inset: storey - 1,
|
||||
dir: 1,
|
||||
dir: Dir::NegX,
|
||||
}),
|
||||
2 => painter.prim(Primitive::Ramp {
|
||||
aabb: Aabb {
|
||||
@ -1003,7 +1003,7 @@ impl Structure for House {
|
||||
.with_z(alt + height),
|
||||
},
|
||||
inset: storey - 1,
|
||||
dir: 2,
|
||||
dir: Dir::Y,
|
||||
}),
|
||||
_ => painter.prim(Primitive::Ramp {
|
||||
aabb: Aabb {
|
||||
@ -1019,7 +1019,7 @@ impl Structure for House {
|
||||
.with_z(alt + height),
|
||||
},
|
||||
inset: storey - 1,
|
||||
dir: 0,
|
||||
dir: Dir::X,
|
||||
}),
|
||||
};
|
||||
painter.fill(
|
||||
@ -1232,7 +1232,7 @@ impl Structure for House {
|
||||
.with_z(alt + height + 1),
|
||||
},
|
||||
inset: 3,
|
||||
dir: true,
|
||||
dir: Dir::Y,
|
||||
}),
|
||||
1 => painter.prim(Primitive::Gable {
|
||||
aabb: Aabb {
|
||||
@ -1245,7 +1245,7 @@ impl Structure for House {
|
||||
.with_z(alt + height + 1),
|
||||
},
|
||||
inset: 3,
|
||||
dir: false,
|
||||
dir: Dir::X,
|
||||
}),
|
||||
2 => painter.prim(Primitive::Gable {
|
||||
aabb: Aabb {
|
||||
@ -1258,7 +1258,7 @@ impl Structure for House {
|
||||
.with_z(alt + height + 1),
|
||||
},
|
||||
inset: 3,
|
||||
dir: true,
|
||||
dir: Dir::Y,
|
||||
}),
|
||||
_ => painter.prim(Primitive::Gable {
|
||||
aabb: Aabb {
|
||||
@ -1271,7 +1271,7 @@ impl Structure for House {
|
||||
.with_z(alt + height + 1),
|
||||
},
|
||||
inset: 3,
|
||||
dir: false,
|
||||
dir: Dir::X,
|
||||
}),
|
||||
};
|
||||
let window_min = match self.front {
|
||||
@ -1494,7 +1494,7 @@ impl Structure for House {
|
||||
max: Vec2::new(stair_origin.x + 10, stair_origin.y + stair_width).with_z(alt + previous_height + 1),
|
||||
},
|
||||
inset: storey,
|
||||
dir: 0,
|
||||
dir: Dir::X,
|
||||
})
|
||||
/*},
|
||||
1 => {
|
||||
@ -1573,7 +1573,7 @@ impl Structure for House {
|
||||
max: Vec2::new(stair_origin.x + 8, stair_origin.y + 2 * stair_width).with_z(alt + previous_height + 1),
|
||||
},
|
||||
inset: storey,
|
||||
dir: 1,
|
||||
dir: Dir::NegX,
|
||||
})
|
||||
/*},
|
||||
1 => {
|
||||
|
92
world/src/site2/util/gradient.rs
Normal file
92
world/src/site2/util/gradient.rs
Normal file
@ -0,0 +1,92 @@
|
||||
use vek::*;
|
||||
|
||||
/// A wrapping mode, used to determine what to do when sampling outside of 0..=1
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum WrapMode {
|
||||
/// ..............______
|
||||
/// No repeat ___/
|
||||
Clamp,
|
||||
/// Saw wave repeat / / / /
|
||||
Repeat,
|
||||
/// Triangle wave repeat /\/\/\/\/
|
||||
PingPong,
|
||||
}
|
||||
|
||||
impl WrapMode {
|
||||
fn sample(&self, t: f32) -> f32 {
|
||||
match self {
|
||||
WrapMode::Clamp => t.clamp(0.0, 1.0),
|
||||
WrapMode::Repeat => (1.0 + t.fract()).fract(),
|
||||
WrapMode::PingPong => 1.0 - 2.0 * ((t / 2.0).fract().abs() - 0.5).abs(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Shape {
|
||||
Point,
|
||||
/// Vector should be normalized for Gradient size to work properly
|
||||
Plane(Vec3<f32>),
|
||||
/// Vector should be normalized for Gradient size to work properly
|
||||
Line(Vec3<f32>),
|
||||
}
|
||||
|
||||
impl Shape {
|
||||
/// Create a new plane shape with the given normal.
|
||||
pub fn plane(normal: Vec3<f32>) -> Self { Shape::Plane(normal.normalized()) }
|
||||
|
||||
/// Create an infinite line shape with the given direction.
|
||||
pub fn radial_line(direction: Vec3<f32>) -> Self { Shape::Line(direction.normalized()) }
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Gradient {
|
||||
/// The center of the gradient shape
|
||||
pub(super) center: Vec3<f32>,
|
||||
/// The distance the gradient is sampled along
|
||||
pub(super) size: f32,
|
||||
/// The shape that the distance is computed to to get the gradient color.
|
||||
pub(super) shape: Shape,
|
||||
/// How the graduint should repeat when the distance from the shape is
|
||||
/// greater than size
|
||||
pub(super) repeat: WrapMode,
|
||||
/// The colors the gradient is lerped between
|
||||
pub(super) colors: (Rgb<u8>, Rgb<u8>),
|
||||
}
|
||||
|
||||
impl Gradient {
|
||||
pub fn new(center: Vec3<f32>, size: f32, shape: Shape, colors: (Rgb<u8>, Rgb<u8>)) -> Self {
|
||||
Gradient {
|
||||
center,
|
||||
size,
|
||||
shape,
|
||||
repeat: WrapMode::Clamp,
|
||||
colors,
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a repeat mode to the gradient
|
||||
#[must_use]
|
||||
pub fn with_repeat(mut self, repeat: WrapMode) -> Self {
|
||||
self.repeat = repeat;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sample the gradient at a certain point, will always return a color
|
||||
/// that's in the range color.0..=color.1
|
||||
pub fn sample(&self, pos: Vec3<f32>) -> Rgb<u8> {
|
||||
// Calculate t by dividing the distance from the shape divided by size
|
||||
let t = self.repeat.sample(match self.shape {
|
||||
Shape::Point => pos.distance(self.center) / self.size,
|
||||
Shape::Plane(normal) => (pos - self.center).dot(normal) / self.size,
|
||||
Shape::Line(line) => {
|
||||
let u = pos - self.center;
|
||||
(u.dot(line) * line - u).magnitude() / self.size
|
||||
},
|
||||
});
|
||||
// Lerp colors
|
||||
self.colors.0.map2(self.colors.1, |a, b| {
|
||||
(a as f32 * (1.0 - t) + b as f32 * t) as u8
|
||||
})
|
||||
}
|
||||
}
|
140
world/src/site2/util/mod.rs
Normal file
140
world/src/site2/util/mod.rs
Normal file
@ -0,0 +1,140 @@
|
||||
pub mod gradient;
|
||||
|
||||
use rand::Rng;
|
||||
use vek::*;
|
||||
|
||||
/// A 2d direction.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum Dir {
|
||||
X,
|
||||
Y,
|
||||
NegX,
|
||||
NegY,
|
||||
}
|
||||
|
||||
impl Dir {
|
||||
pub fn choose(rng: &mut impl Rng) -> Dir {
|
||||
match rng.gen_range(0..4) {
|
||||
0 => Dir::X,
|
||||
1 => Dir::Y,
|
||||
3 => Dir::NegX,
|
||||
_ => Dir::NegY,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_vector(vec: Vec2<i32>) -> Dir {
|
||||
if vec.x.abs() > vec.y.abs() {
|
||||
if vec.x > 0 { Dir::X } else { Dir::NegX }
|
||||
} else if vec.y > 0 {
|
||||
Dir::Y
|
||||
} else {
|
||||
Dir::NegY
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn opposite(self) -> Dir {
|
||||
match self {
|
||||
Dir::X => Dir::NegX,
|
||||
Dir::NegX => Dir::X,
|
||||
Dir::Y => Dir::NegY,
|
||||
Dir::NegY => Dir::Y,
|
||||
}
|
||||
}
|
||||
|
||||
/// Rotate the direction anti clock wise
|
||||
#[must_use]
|
||||
pub fn rotate_left(self) -> Dir {
|
||||
match self {
|
||||
Dir::X => Dir::Y,
|
||||
Dir::NegX => Dir::NegY,
|
||||
Dir::Y => Dir::NegX,
|
||||
Dir::NegY => Dir::X,
|
||||
}
|
||||
}
|
||||
|
||||
/// Rotate the direction clock wise
|
||||
#[must_use]
|
||||
pub fn rotate_right(self) -> Dir {
|
||||
match self {
|
||||
Dir::X => Dir::NegY,
|
||||
Dir::NegX => Dir::Y,
|
||||
Dir::Y => Dir::X,
|
||||
Dir::NegY => Dir::NegX,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_vec2(self) -> Vec2<i32> {
|
||||
match self {
|
||||
Dir::X => Vec2::new(1, 0),
|
||||
Dir::NegX => Vec2::new(-1, 0),
|
||||
Dir::Y => Vec2::new(0, 1),
|
||||
Dir::NegY => Vec2::new(0, -1),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_vec3(self) -> Vec3<i32> {
|
||||
match self {
|
||||
Dir::X => Vec3::new(1, 0, 0),
|
||||
Dir::NegX => Vec3::new(-1, 0, 0),
|
||||
Dir::Y => Vec3::new(0, 1, 0),
|
||||
Dir::NegY => Vec3::new(0, -1, 0),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a 3x3 matrix that rotates Vec3(1, 0, 0) to the direction you get
|
||||
/// in to_vec3. Inteded to be used with Primitive::Rotate.
|
||||
///
|
||||
/// Example:
|
||||
/// ```
|
||||
/// use vek::Vec3;
|
||||
/// use veloren_world::site2::util::Dir;
|
||||
/// let dir = Dir::X;
|
||||
///
|
||||
/// assert_eq!(dir.to_mat3x3() * Vec3::new(1, 0, 0), dir.to_vec3());
|
||||
///
|
||||
/// let dir = Dir::NegX;
|
||||
///
|
||||
/// assert_eq!(dir.to_mat3x3() * Vec3::new(1, 0, 0), dir.to_vec3());
|
||||
///
|
||||
/// let dir = Dir::Y;
|
||||
///
|
||||
/// assert_eq!(dir.to_mat3x3() * Vec3::new(1, 0, 0), dir.to_vec3());
|
||||
///
|
||||
/// let dir = Dir::NegY;
|
||||
///
|
||||
/// assert_eq!(dir.to_mat3x3() * Vec3::new(1, 0, 0), dir.to_vec3());
|
||||
/// ```
|
||||
pub fn to_mat3x3(self) -> Mat3<i32> {
|
||||
match self {
|
||||
Dir::X => Mat3::new(1, 0, 0, 0, 1, 0, 0, 0, 1),
|
||||
Dir::NegX => Mat3::new(-1, 0, 0, 0, -1, 0, 0, 0, 1),
|
||||
Dir::Y => Mat3::new(0, -1, 0, 1, 0, 0, 0, 0, 1),
|
||||
Dir::NegY => Mat3::new(0, 1, 0, -1, 0, 0, 0, 0, 1),
|
||||
}
|
||||
}
|
||||
|
||||
/// Translates this direction to worldspace as if it was relative to the
|
||||
/// other direction
|
||||
#[must_use]
|
||||
pub fn relative_to(self, other: Dir) -> Dir {
|
||||
match other {
|
||||
Dir::X => self,
|
||||
Dir::NegX => self.opposite(),
|
||||
Dir::Y => self.rotate_right(),
|
||||
Dir::NegY => self.rotate_left(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Is this direction parallel to x
|
||||
pub fn is_x(self) -> bool { matches!(self, Dir::X | Dir::NegX) }
|
||||
|
||||
/// Is this direction parallel to y
|
||||
pub fn is_y(self) -> bool { matches!(self, Dir::Y | Dir::NegY) }
|
||||
}
|
||||
|
||||
impl std::ops::Neg for Dir {
|
||||
type Output = Dir;
|
||||
|
||||
fn neg(self) -> Self::Output { self.opposite() }
|
||||
}
|
Loading…
Reference in New Issue
Block a user