mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Mostly working train tracks.
This commit is contained in:
parent
7cb701e469
commit
08a50afd9f
@ -1,9 +1,18 @@
|
|||||||
#version 420 core
|
#version 420 core
|
||||||
|
|
||||||
|
#include <constants.glsl>
|
||||||
#include <globals.glsl>
|
#include <globals.glsl>
|
||||||
|
#include <srgb.glsl>
|
||||||
|
#include <sky.glsl>
|
||||||
|
#include <light.glsl>
|
||||||
|
#include <lod.glsl>
|
||||||
|
|
||||||
layout (location = 0)
|
layout (location = 0)
|
||||||
in vec4 f_color;
|
in vec4 f_color;
|
||||||
|
layout (location = 1)
|
||||||
|
in vec3 f_pos;
|
||||||
|
layout (location = 2)
|
||||||
|
in vec3 f_norm;
|
||||||
|
|
||||||
layout (std140, set = 1, binding = 0)
|
layout (std140, set = 1, binding = 0)
|
||||||
uniform u_locals {
|
uniform u_locals {
|
||||||
@ -11,9 +20,57 @@ uniform u_locals {
|
|||||||
vec4 w_color;
|
vec4 w_color;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
layout(set = 2, binding = 0)
|
||||||
|
uniform texture2D t_col_light;
|
||||||
|
layout(set = 2, binding = 1)
|
||||||
|
uniform sampler s_col_light;
|
||||||
|
|
||||||
layout (location = 0)
|
layout (location = 0)
|
||||||
out vec4 tgt_color;
|
out vec4 tgt_color;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
tgt_color = f_color;
|
vec3 cam_to_frag = normalize(f_pos - cam_pos.xyz);
|
||||||
|
vec3 view_dir = -cam_to_frag;
|
||||||
|
float point_shadow = shadow_at(f_pos, f_norm);
|
||||||
|
|
||||||
|
#if (SHADOW_MODE == SHADOW_MODE_CHEAP || SHADOW_MODE == SHADOW_MODE_MAP || FLUID_MODE == FLUID_MODE_SHINY)
|
||||||
|
float f_alt = alt_at(f_pos.xy);
|
||||||
|
#elif (SHADOW_MODE == SHADOW_MODE_NONE || FLUID_MODE == FLUID_MODE_CHEAP)
|
||||||
|
float f_alt = f_pos.z;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (SHADOW_MODE == SHADOW_MODE_CHEAP || SHADOW_MODE == SHADOW_MODE_MAP)
|
||||||
|
vec4 f_shadow = textureBicubic(t_horizon, s_horizon, pos_to_tex(f_pos.xy));
|
||||||
|
float sun_shade_frac = horizon_at2(f_shadow, f_alt, f_pos, sun_dir);
|
||||||
|
#elif (SHADOW_MODE == SHADOW_MODE_NONE)
|
||||||
|
float sun_shade_frac = 1.0;
|
||||||
|
#endif
|
||||||
|
float moon_shade_frac = 1.0;
|
||||||
|
|
||||||
|
DirectionalLight sun_info = get_sun_info(sun_dir, point_shadow * sun_shade_frac, f_pos);
|
||||||
|
DirectionalLight moon_info = get_moon_info(moon_dir, point_shadow * moon_shade_frac);
|
||||||
|
|
||||||
|
vec3 surf_color = f_color.xyz;
|
||||||
|
float alpha = 1.0;
|
||||||
|
const float n2 = 1.5;
|
||||||
|
const float R_s2s0 = pow((1.0 - n2) / (1.0 + n2), 2);
|
||||||
|
const float R_s1s0 = pow((1.3325 - n2) / (1.3325 + n2), 2);
|
||||||
|
const float R_s2s1 = pow((1.0 - 1.3325) / (1.0 + 1.3325), 2);
|
||||||
|
const float R_s1s2 = pow((1.3325 - 1.0) / (1.3325 + 1.0), 2);
|
||||||
|
float R_s = (f_pos.z < f_alt) ? mix(R_s2s1 * R_s1s0, R_s1s0, medium.x) : mix(R_s2s0, R_s1s2 * R_s2s0, medium.x);
|
||||||
|
|
||||||
|
vec3 k_a = vec3(1.0);
|
||||||
|
vec3 k_d = vec3(1.0);
|
||||||
|
vec3 k_s = vec3(R_s);
|
||||||
|
float max_light = 0.0;
|
||||||
|
vec3 cam_attenuation = vec3(1);
|
||||||
|
float fluid_alt = max(f_pos.z + 1, floor(f_alt + 1));
|
||||||
|
vec3 mu = medium.x == MEDIUM_WATER ? MU_WATER : vec3(0.0);
|
||||||
|
vec3 emitted_light, reflected_light;
|
||||||
|
max_light += get_sun_diffuse2(sun_info, moon_info, f_norm, view_dir, f_pos, mu, cam_attenuation, fluid_alt, k_a, k_d, k_s, alpha, f_norm, 1.0, emitted_light, reflected_light);
|
||||||
|
|
||||||
|
max_light += lights_at(f_pos, f_norm, view_dir, mu, cam_attenuation, fluid_alt, k_a, k_d, k_s, alpha, f_norm, 1.0, emitted_light, reflected_light);
|
||||||
|
surf_color = illuminate(max_light, view_dir, surf_color * emitted_light, surf_color * reflected_light * 1.0);
|
||||||
|
|
||||||
|
tgt_color = vec4(surf_color, 1.0);
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,10 @@
|
|||||||
|
|
||||||
layout (location = 0)
|
layout (location = 0)
|
||||||
in vec3 v_pos;
|
in vec3 v_pos;
|
||||||
|
layout (location = 1)
|
||||||
|
in vec4 v_color;
|
||||||
|
layout (location = 2)
|
||||||
|
in vec3 v_norm;
|
||||||
|
|
||||||
layout (std140, set = 1, binding = 0)
|
layout (std140, set = 1, binding = 0)
|
||||||
uniform u_locals {
|
uniform u_locals {
|
||||||
@ -14,9 +18,13 @@ uniform u_locals {
|
|||||||
|
|
||||||
layout (location = 0)
|
layout (location = 0)
|
||||||
out vec4 f_color;
|
out vec4 f_color;
|
||||||
|
layout (location = 1)
|
||||||
|
out vec3 f_pos;
|
||||||
|
layout (location = 2)
|
||||||
|
out vec3 f_norm;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
f_color = w_color;
|
f_color = w_color * v_color;
|
||||||
|
|
||||||
// Build rotation matrix
|
// Build rotation matrix
|
||||||
// https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles#Rotation_matrices
|
// https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles#Rotation_matrices
|
||||||
@ -41,5 +49,7 @@ void main() {
|
|||||||
float r22 = 1 - 2 * (pow(q1, 2) + pow(q2, 2));
|
float r22 = 1 - 2 * (pow(q1, 2) + pow(q2, 2));
|
||||||
rotation_matrix[2] = vec3(r20, r21, r22);
|
rotation_matrix[2] = vec3(r20, r21, r22);
|
||||||
|
|
||||||
gl_Position = all_mat * vec4((v_pos * rotation_matrix + w_pos.xyz) - focus_off.xyz, 1);
|
f_pos = (v_pos * rotation_matrix + w_pos.xyz) - focus_off.xyz;
|
||||||
|
f_norm = normalize(v_norm);
|
||||||
|
gl_Position = all_mat * vec4(f_pos, 1);
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,8 @@ impl<V, S: RectVolSize, M: Clone> Chonk<V, S, M> {
|
|||||||
|
|
||||||
pub fn meta(&self) -> &M { &self.meta }
|
pub fn meta(&self) -> &M { &self.meta }
|
||||||
|
|
||||||
|
pub fn meta_mut(&mut self) -> &mut M { &mut self.meta }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_min_z(&self) -> i32 { self.z_offset }
|
pub fn get_min_z(&self) -> i32 { self.z_offset }
|
||||||
|
|
||||||
|
@ -90,6 +90,9 @@ pub struct TerrainChunkMeta {
|
|||||||
temp: f32,
|
temp: f32,
|
||||||
humidity: f32,
|
humidity: f32,
|
||||||
site: Option<SiteKindMeta>,
|
site: Option<SiteKindMeta>,
|
||||||
|
tracks: Vec<CubicBezier3<f32>>,
|
||||||
|
debug_points: Vec<Vec3<f32>>,
|
||||||
|
debug_lines: Vec<LineSegment3<f32>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TerrainChunkMeta {
|
impl TerrainChunkMeta {
|
||||||
@ -116,6 +119,9 @@ impl TerrainChunkMeta {
|
|||||||
temp,
|
temp,
|
||||||
humidity,
|
humidity,
|
||||||
site,
|
site,
|
||||||
|
tracks: Vec::new(),
|
||||||
|
debug_points: Vec::new(),
|
||||||
|
debug_lines: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,6 +137,9 @@ impl TerrainChunkMeta {
|
|||||||
temp: 0.0,
|
temp: 0.0,
|
||||||
humidity: 0.0,
|
humidity: 0.0,
|
||||||
site: None,
|
site: None,
|
||||||
|
tracks: Vec::new(),
|
||||||
|
debug_points: Vec::new(),
|
||||||
|
debug_lines: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,6 +162,24 @@ impl TerrainChunkMeta {
|
|||||||
pub fn temp(&self) -> f32 { self.temp }
|
pub fn temp(&self) -> f32 { self.temp }
|
||||||
|
|
||||||
pub fn humidity(&self) -> f32 { self.humidity }
|
pub fn humidity(&self) -> f32 { self.humidity }
|
||||||
|
|
||||||
|
pub fn tracks(&self) -> &[CubicBezier3<f32>] { &self.tracks }
|
||||||
|
|
||||||
|
pub fn add_track(&mut self, bezier: CubicBezier3<f32>) {
|
||||||
|
self.tracks.push(bezier);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn debug_points(&self) -> &[Vec3<f32>] { &self.debug_points }
|
||||||
|
|
||||||
|
pub fn add_debug_point(&mut self, point: Vec3<f32>) {
|
||||||
|
self.debug_points.push(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn debug_lines(&self) -> &[LineSegment3<f32>] { &self.debug_lines }
|
||||||
|
|
||||||
|
pub fn add_debug_line(&mut self, line: LineSegment3<f32>) {
|
||||||
|
self.debug_lines.push(line);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Terrain type aliases
|
// Terrain type aliases
|
||||||
|
@ -2791,6 +2791,7 @@ fn handle_debug_column(
|
|||||||
let downhill = chunk.downhill;
|
let downhill = chunk.downhill;
|
||||||
let river = &chunk.river;
|
let river = &chunk.river;
|
||||||
let flux = chunk.flux;
|
let flux = chunk.flux;
|
||||||
|
let path = chunk.path;
|
||||||
|
|
||||||
Some(format!(
|
Some(format!(
|
||||||
r#"wpos: {:?}
|
r#"wpos: {:?}
|
||||||
@ -2806,7 +2807,8 @@ temp {:?}
|
|||||||
humidity {:?}
|
humidity {:?}
|
||||||
rockiness {:?}
|
rockiness {:?}
|
||||||
tree_density {:?}
|
tree_density {:?}
|
||||||
spawn_rate {:?} "#,
|
spawn_rate {:?}
|
||||||
|
path {:?} "#,
|
||||||
wpos,
|
wpos,
|
||||||
alt,
|
alt,
|
||||||
col.alt,
|
col.alt,
|
||||||
@ -2822,7 +2824,8 @@ spawn_rate {:?} "#,
|
|||||||
humidity,
|
humidity,
|
||||||
rockiness,
|
rockiness,
|
||||||
tree_density,
|
tree_density,
|
||||||
spawn_rate
|
spawn_rate,
|
||||||
|
path,
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
if let Some(s) = msg_generator(&calendar) {
|
if let Some(s) = msg_generator(&calendar) {
|
||||||
|
@ -7,18 +7,18 @@ use vek::*;
|
|||||||
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
|
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
|
||||||
pub struct Vertex {
|
pub struct Vertex {
|
||||||
pub pos: [f32; 3],
|
pub pos: [f32; 3],
|
||||||
|
pub color: [f32; 4],
|
||||||
|
pub normal: [f32; 3],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Vertex {
|
impl Vertex {
|
||||||
fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {
|
fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {
|
||||||
|
const ATTRIBUTES: [wgpu::VertexAttribute; 3] =
|
||||||
|
wgpu::vertex_attr_array![0 => Float32x3, 1 => Float32x4, 2 => Float32x3];
|
||||||
wgpu::VertexBufferLayout {
|
wgpu::VertexBufferLayout {
|
||||||
array_stride: Self::STRIDE,
|
array_stride: Self::STRIDE,
|
||||||
step_mode: wgpu::InputStepMode::Vertex,
|
step_mode: wgpu::InputStepMode::Vertex,
|
||||||
attributes: &[wgpu::VertexAttribute {
|
attributes: &ATTRIBUTES,
|
||||||
offset: 0,
|
|
||||||
shader_location: 0,
|
|
||||||
format: wgpu::VertexFormat::Float32x3,
|
|
||||||
}],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -46,6 +46,18 @@ impl From<Vec3<f32>> for Vertex {
|
|||||||
fn from(pos: Vec3<f32>) -> Vertex {
|
fn from(pos: Vec3<f32>) -> Vertex {
|
||||||
Vertex {
|
Vertex {
|
||||||
pos: [pos.x, pos.y, pos.z],
|
pos: [pos.x, pos.y, pos.z],
|
||||||
|
color: [1.0; 4],
|
||||||
|
normal: [0.0, 0.0, 1.0],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(Vec3<f32>, [f32; 4], Vec3<f32>)> for Vertex {
|
||||||
|
fn from((pos, color, normal): (Vec3<f32>, [f32; 4], Vec3<f32>)) -> Vertex {
|
||||||
|
Vertex {
|
||||||
|
pos: [pos.x, pos.y, pos.z],
|
||||||
|
color,
|
||||||
|
normal: [normal.x, normal.y, normal.z],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,68 @@ pub enum DebugShape {
|
|||||||
radius: f32,
|
radius: f32,
|
||||||
height: f32,
|
height: f32,
|
||||||
},
|
},
|
||||||
|
TrainTrack {
|
||||||
|
path: CubicBezier3<f32>,
|
||||||
|
rail_width: f32,
|
||||||
|
rail_sep: f32,
|
||||||
|
plank_width: f32,
|
||||||
|
plank_height: f32,
|
||||||
|
plank_sep: f32,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If (q, r) is the given `line`, append the following mesh to `mesh`, where
|
||||||
|
/// the distance between a-b is `width` and b-d is `height`:
|
||||||
|
/// e-----f
|
||||||
|
/// /| /|
|
||||||
|
/// / | r/ |
|
||||||
|
/// / | / |
|
||||||
|
/// / g-/-- h
|
||||||
|
/// / / / /
|
||||||
|
/// a-----b /
|
||||||
|
/// | / | /
|
||||||
|
/// | /q | /
|
||||||
|
/// |/ |/
|
||||||
|
/// c-----d
|
||||||
|
fn box_along_line(
|
||||||
|
line: LineSegment3<f32>,
|
||||||
|
width: f32,
|
||||||
|
height: f32,
|
||||||
|
color: [f32; 4],
|
||||||
|
mesh: &mut Mesh<DebugVertex>,
|
||||||
|
) {
|
||||||
|
// dx is along b-a
|
||||||
|
// dz is along b-d
|
||||||
|
let dx = Vec3::unit_z().cross(line.end - line.start).normalized();
|
||||||
|
let dz = dx.cross(line.end - line.start).normalized();
|
||||||
|
let w = width / 2.0;
|
||||||
|
let h = height / 2.0;
|
||||||
|
let LineSegment3 { start: q, end: r } = line;
|
||||||
|
let a = q - w * dx + h * dz;
|
||||||
|
let b = q + w * dx + h * dz;
|
||||||
|
let c = q - w * dx - h * dz;
|
||||||
|
let d = q + w * dx - h * dz;
|
||||||
|
let e = r - w * dx + h * dz;
|
||||||
|
let f = r + w * dx + h * dz;
|
||||||
|
let g = r - w * dx - h * dz;
|
||||||
|
let h = r + w * dx - h * dz;
|
||||||
|
|
||||||
|
let quad = |x: Vec3<f32>, y: Vec3<f32>, z: Vec3<f32>, w: Vec3<f32>| {
|
||||||
|
let normal = x.cross(y);
|
||||||
|
Quad::<DebugVertex>::new(
|
||||||
|
(x, color, normal).into(),
|
||||||
|
(y, color, normal).into(),
|
||||||
|
(z, color, normal).into(),
|
||||||
|
(w, color, normal).into(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
mesh.push_quad(quad(a, c, d, b));
|
||||||
|
mesh.push_quad(quad(a, b, f, e));
|
||||||
|
mesh.push_quad(quad(a, e, g, c));
|
||||||
|
mesh.push_quad(quad(b, d, h, f));
|
||||||
|
mesh.push_quad(quad(e, f, h, g));
|
||||||
|
mesh.push_quad(quad(d, c, g, h));
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DebugShape {
|
impl DebugShape {
|
||||||
@ -34,8 +96,9 @@ impl DebugShape {
|
|||||||
|
|
||||||
match self {
|
match self {
|
||||||
DebugShape::Line([a, b]) => {
|
DebugShape::Line([a, b]) => {
|
||||||
let h = Vec3::new(0.0, 1.0, 0.0);
|
//let h = Vec3::new(0.0, 1.0, 0.0);
|
||||||
mesh.push_quad(quad(*a, a + h, b + h, *b));
|
//mesh.push_quad(quad(*a, a + h, b + h, *b));
|
||||||
|
box_along_line(LineSegment3 { start: *a, end: *b }, 0.1, 0.1, [1.0; 4], &mut mesh);
|
||||||
},
|
},
|
||||||
DebugShape::Cylinder { radius, height } => {
|
DebugShape::Cylinder { radius, height } => {
|
||||||
const SUBDIVISIONS: u8 = 16;
|
const SUBDIVISIONS: u8 = 16;
|
||||||
@ -140,6 +203,46 @@ impl DebugShape {
|
|||||||
// 3) Draw second half-cylinder
|
// 3) Draw second half-cylinder
|
||||||
draw_cylinder_sector(&mut mesh, p1, HALF_SECTORS, TOTAL);
|
draw_cylinder_sector(&mut mesh, p1, HALF_SECTORS, TOTAL);
|
||||||
},
|
},
|
||||||
|
DebugShape::TrainTrack {
|
||||||
|
path,
|
||||||
|
rail_width,
|
||||||
|
rail_sep,
|
||||||
|
plank_width,
|
||||||
|
plank_height,
|
||||||
|
plank_sep,
|
||||||
|
} => {
|
||||||
|
const STEEL_COLOR: [f32; 4] = [0.6, 0.6, 0.6, 1.0];
|
||||||
|
const WOOD_COLOR: [f32; 4] = [0.6, 0.2, 0.0, 1.0];
|
||||||
|
const SUBPLANK_LENGTH: usize = 5;
|
||||||
|
let length = path.length_by_discretization(100);
|
||||||
|
let num_planks = (length / (plank_sep + plank_width)).ceil() as usize;
|
||||||
|
let step_size = 1.0 / (SUBPLANK_LENGTH * num_planks) as f32;
|
||||||
|
for i in 0..(SUBPLANK_LENGTH * num_planks) {
|
||||||
|
let start = path.evaluate(i as f32 * step_size);
|
||||||
|
let end = path.evaluate((i + 1) as f32 * step_size);
|
||||||
|
let center = LineSegment3 { start, end };
|
||||||
|
let dx = *rail_sep * Vec3::unit_z().cross(center.end - center.start).normalized();
|
||||||
|
let dz = -dx.cross(center.end - center.start).normalized();
|
||||||
|
let left = LineSegment3 {
|
||||||
|
start: center.start + dx,
|
||||||
|
end: center.end + dx,
|
||||||
|
};
|
||||||
|
let right = LineSegment3 {
|
||||||
|
start: center.start - dx,
|
||||||
|
end: center.end - dx,
|
||||||
|
};
|
||||||
|
box_along_line(left, *rail_width, *rail_width, STEEL_COLOR, &mut mesh);
|
||||||
|
box_along_line(right, *rail_width, *rail_width, STEEL_COLOR, &mut mesh);
|
||||||
|
//box_along_line(center, 0.1, 0.1, [1.0, 0.0, 0.0, 1.0], &mut mesh);
|
||||||
|
if i % SUBPLANK_LENGTH == 0 {
|
||||||
|
let across = LineSegment3 {
|
||||||
|
start: center.start - 1.5 * dx - *rail_width * dz,
|
||||||
|
end: center.start + 1.5 * dx - *rail_width * dz,
|
||||||
|
};
|
||||||
|
box_along_line(across, *plank_width, *plank_height, WOOD_COLOR, &mut mesh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
mesh
|
mesh
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ use common::{
|
|||||||
comp,
|
comp,
|
||||||
outcome::Outcome,
|
outcome::Outcome,
|
||||||
resources::DeltaTime,
|
resources::DeltaTime,
|
||||||
terrain::{BlockKind, TerrainChunk},
|
terrain::{BlockKind, TerrainChunk, TerrainGrid},
|
||||||
vol::ReadVol,
|
vol::ReadVol,
|
||||||
};
|
};
|
||||||
use common_base::{prof_span, span};
|
use common_base::{prof_span, span};
|
||||||
@ -1301,8 +1301,43 @@ impl Scene {
|
|||||||
client: &Client,
|
client: &Client,
|
||||||
settings: &Settings,
|
settings: &Settings,
|
||||||
hitboxes: &mut HashMap<specs::Entity, DebugShapeId>,
|
hitboxes: &mut HashMap<specs::Entity, DebugShapeId>,
|
||||||
|
tracks: &mut HashMap<Vec2<i32>, Vec<DebugShapeId>>,
|
||||||
) {
|
) {
|
||||||
let ecs = client.state().ecs();
|
let ecs = client.state().ecs();
|
||||||
|
{
|
||||||
|
let terrain_grid = ecs.read_resource::<TerrainGrid>();
|
||||||
|
for (key, chunk) in terrain_grid.iter() {
|
||||||
|
tracks.entry(key).or_insert_with(|| {
|
||||||
|
let mut ret = Vec::new();
|
||||||
|
for bezier in chunk.meta().tracks().iter() {
|
||||||
|
let shape_id = self.debug.add_shape(DebugShape::TrainTrack {
|
||||||
|
path: *bezier,
|
||||||
|
rail_width: 0.25,
|
||||||
|
rail_sep: 1.0,
|
||||||
|
plank_width: 0.5,
|
||||||
|
plank_height: 0.125,
|
||||||
|
plank_sep: 2.0,
|
||||||
|
});
|
||||||
|
ret.push(shape_id);
|
||||||
|
self.debug.set_context(shape_id, [0.0; 4], [1.0; 4], [0.0, 0.0, 0.0, 1.0]);
|
||||||
|
}
|
||||||
|
for point in chunk.meta().debug_points().iter() {
|
||||||
|
let shape_id = self.debug.add_shape(DebugShape::Cylinder {
|
||||||
|
radius: 0.1,
|
||||||
|
height: 0.1,
|
||||||
|
});
|
||||||
|
ret.push(shape_id);
|
||||||
|
self.debug.set_context(shape_id, point.with_w(0.0).into_array(), [1.0; 4], [0.0, 0.0, 0.0, 1.0]);
|
||||||
|
}
|
||||||
|
for line in chunk.meta().debug_lines().iter() {
|
||||||
|
let shape_id = self.debug.add_shape(DebugShape::Line([line.start.into(), line.end.into()]));
|
||||||
|
ret.push(shape_id);
|
||||||
|
self.debug.set_context(shape_id, [0.0; 4], [1.0; 4], [0.0, 0.0, 0.0, 1.0]);
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
let mut current_entities = hashbrown::HashSet::new();
|
let mut current_entities = hashbrown::HashSet::new();
|
||||||
if settings.interface.toggle_hitboxes {
|
if settings.interface.toggle_hitboxes {
|
||||||
let positions = ecs.read_component::<comp::Pos>();
|
let positions = ecs.read_component::<comp::Pos>();
|
||||||
@ -1343,6 +1378,7 @@ impl Scene {
|
|||||||
} else {
|
} else {
|
||||||
[0.0, 1.0, 0.0, 0.5]
|
[0.0, 1.0, 0.0, 0.5]
|
||||||
};
|
};
|
||||||
|
//let color = [1.0, 1.0, 1.0, 1.0];
|
||||||
let ori = ori.to_quat();
|
let ori = ori.to_quat();
|
||||||
let hb_ori = [ori.x, ori.y, ori.z, ori.w];
|
let hb_ori = [ori.x, ori.y, ori.z, ori.w];
|
||||||
self.debug.set_context(*shape_id, hb_pos, color, hb_ori);
|
self.debug.set_context(*shape_id, hb_pos, color, hb_ori);
|
||||||
|
@ -91,6 +91,7 @@ pub struct SessionState {
|
|||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
mumble_link: SharedLink,
|
mumble_link: SharedLink,
|
||||||
hitboxes: HashMap<specs::Entity, DebugShapeId>,
|
hitboxes: HashMap<specs::Entity, DebugShapeId>,
|
||||||
|
tracks: HashMap<Vec2<i32>, Vec<DebugShapeId>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents an active game session (i.e., the one being played).
|
/// Represents an active game session (i.e., the one being played).
|
||||||
@ -157,6 +158,7 @@ impl SessionState {
|
|||||||
mumble_link,
|
mumble_link,
|
||||||
hitboxes: HashMap::new(),
|
hitboxes: HashMap::new(),
|
||||||
metadata,
|
metadata,
|
||||||
|
tracks: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,8 +186,12 @@ impl SessionState {
|
|||||||
span!(_guard, "tick", "Session::tick");
|
span!(_guard, "tick", "Session::tick");
|
||||||
|
|
||||||
let mut client = self.client.borrow_mut();
|
let mut client = self.client.borrow_mut();
|
||||||
self.scene
|
self.scene.maintain_debug_hitboxes(
|
||||||
.maintain_debug_hitboxes(&client, &global_state.settings, &mut self.hitboxes);
|
&client,
|
||||||
|
&global_state.settings,
|
||||||
|
&mut self.hitboxes,
|
||||||
|
&mut self.tracks,
|
||||||
|
);
|
||||||
|
|
||||||
// All this camera code is just to determine if it's underwater for the sfx
|
// All this camera code is just to determine if it's underwater for the sfx
|
||||||
// filter
|
// filter
|
||||||
|
@ -15,7 +15,7 @@ use crate::{
|
|||||||
column::ColumnSample,
|
column::ColumnSample,
|
||||||
config::CONFIG,
|
config::CONFIG,
|
||||||
util::{FastNoise, RandomField, RandomPerm, Sampler},
|
util::{FastNoise, RandomField, RandomPerm, Sampler},
|
||||||
Canvas, IndexRef,
|
Canvas, CanvasInfo, IndexRef,
|
||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
assets::AssetExt,
|
assets::AssetExt,
|
||||||
@ -48,6 +48,52 @@ pub struct Colors {
|
|||||||
|
|
||||||
const EMPTY_AIR: Block = Block::air(SpriteKind::Empty);
|
const EMPTY_AIR: Block = Block::air(SpriteKind::Empty);
|
||||||
|
|
||||||
|
pub struct PathLocals {
|
||||||
|
pub riverless_alt: f32,
|
||||||
|
pub alt: f32,
|
||||||
|
pub water_dist: f32,
|
||||||
|
pub bridge_offset: f32,
|
||||||
|
pub depth: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PathLocals {
|
||||||
|
pub fn new(info: &CanvasInfo, col: &ColumnSample, path_nearest: Vec2<f32>) -> PathLocals {
|
||||||
|
// Try to use the column at the centre of the path for sampling to make them
|
||||||
|
// flatter
|
||||||
|
let col_pos = -info.wpos().map(|e| e as f32) + path_nearest;
|
||||||
|
let col00 = info.col(info.wpos() + col_pos.map(|e| e.floor() as i32) + Vec2::new(0, 0));
|
||||||
|
let col10 = info.col(info.wpos() + col_pos.map(|e| e.floor() as i32) + Vec2::new(1, 0));
|
||||||
|
let col01 = info.col(info.wpos() + col_pos.map(|e| e.floor() as i32) + Vec2::new(0, 1));
|
||||||
|
let col11 = info.col(info.wpos() + col_pos.map(|e| e.floor() as i32) + Vec2::new(1, 1));
|
||||||
|
let col_attr = |col: &ColumnSample| {
|
||||||
|
Vec3::new(col.riverless_alt, col.alt, col.water_dist.unwrap_or(1000.0))
|
||||||
|
};
|
||||||
|
let [riverless_alt, alt, water_dist] = match (col00, col10, col01, col11) {
|
||||||
|
(Some(col00), Some(col10), Some(col01), Some(col11)) => Lerp::lerp(
|
||||||
|
Lerp::lerp(col_attr(col00), col_attr(col10), path_nearest.x.fract()),
|
||||||
|
Lerp::lerp(col_attr(col01), col_attr(col11), path_nearest.x.fract()),
|
||||||
|
path_nearest.y.fract(),
|
||||||
|
),
|
||||||
|
_ => col_attr(col),
|
||||||
|
}
|
||||||
|
.into_array();
|
||||||
|
let (bridge_offset, depth) = (
|
||||||
|
((water_dist.max(0.0) * 0.2).min(f32::consts::PI).cos() + 1.0) * 5.0,
|
||||||
|
((1.0 - ((water_dist + 2.0) * 0.3).min(0.0).cos().abs())
|
||||||
|
* (riverless_alt + 5.0 - alt).max(0.0)
|
||||||
|
* 1.75
|
||||||
|
+ 3.0) as i32,
|
||||||
|
);
|
||||||
|
PathLocals {
|
||||||
|
riverless_alt,
|
||||||
|
alt,
|
||||||
|
water_dist,
|
||||||
|
bridge_offset,
|
||||||
|
depth,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn apply_paths_to(canvas: &mut Canvas) {
|
pub fn apply_paths_to(canvas: &mut Canvas) {
|
||||||
let info = canvas.info();
|
let info = canvas.info();
|
||||||
canvas.foreach_col(|canvas, wpos2d, col| {
|
canvas.foreach_col(|canvas, wpos2d, col| {
|
||||||
@ -67,32 +113,13 @@ pub fn apply_paths_to(canvas: &mut Canvas) {
|
|||||||
{
|
{
|
||||||
let inset = 0;
|
let inset = 0;
|
||||||
|
|
||||||
// Try to use the column at the centre of the path for sampling to make them
|
let PathLocals {
|
||||||
// flatter
|
riverless_alt,
|
||||||
let col_pos = -info.wpos().map(|e| e as f32) + path_nearest;
|
alt: _,
|
||||||
let col00 = info.col(info.wpos() + col_pos.map(|e| e.floor() as i32) + Vec2::new(0, 0));
|
water_dist: _,
|
||||||
let col10 = info.col(info.wpos() + col_pos.map(|e| e.floor() as i32) + Vec2::new(1, 0));
|
bridge_offset,
|
||||||
let col01 = info.col(info.wpos() + col_pos.map(|e| e.floor() as i32) + Vec2::new(0, 1));
|
depth,
|
||||||
let col11 = info.col(info.wpos() + col_pos.map(|e| e.floor() as i32) + Vec2::new(1, 1));
|
} = PathLocals::new(&canvas.info(), col, path_nearest);
|
||||||
let col_attr = |col: &ColumnSample| {
|
|
||||||
Vec3::new(col.riverless_alt, col.alt, col.water_dist.unwrap_or(1000.0))
|
|
||||||
};
|
|
||||||
let [riverless_alt, alt, water_dist] = match (col00, col10, col01, col11) {
|
|
||||||
(Some(col00), Some(col10), Some(col01), Some(col11)) => Lerp::lerp(
|
|
||||||
Lerp::lerp(col_attr(col00), col_attr(col10), path_nearest.x.fract()),
|
|
||||||
Lerp::lerp(col_attr(col01), col_attr(col11), path_nearest.x.fract()),
|
|
||||||
path_nearest.y.fract(),
|
|
||||||
),
|
|
||||||
_ => col_attr(col),
|
|
||||||
}
|
|
||||||
.into_array();
|
|
||||||
let (bridge_offset, depth) = (
|
|
||||||
((water_dist.max(0.0) * 0.2).min(f32::consts::PI).cos() + 1.0) * 5.0,
|
|
||||||
((1.0 - ((water_dist + 2.0) * 0.3).min(0.0).cos().abs())
|
|
||||||
* (riverless_alt + 5.0 - alt).max(0.0)
|
|
||||||
* 1.75
|
|
||||||
+ 3.0) as i32,
|
|
||||||
);
|
|
||||||
let surface_z = (riverless_alt + bridge_offset).floor() as i32;
|
let surface_z = (riverless_alt + bridge_offset).floor() as i32;
|
||||||
|
|
||||||
for z in inset - depth..inset {
|
for z in inset - depth..inset {
|
||||||
|
@ -30,6 +30,7 @@ pub use crate::{
|
|||||||
canvas::{Canvas, CanvasInfo},
|
canvas::{Canvas, CanvasInfo},
|
||||||
config::{Features, CONFIG},
|
config::{Features, CONFIG},
|
||||||
land::Land,
|
land::Land,
|
||||||
|
layer::PathLocals,
|
||||||
};
|
};
|
||||||
pub use block::BlockGen;
|
pub use block::BlockGen;
|
||||||
pub use column::ColumnSample;
|
pub use column::ColumnSample;
|
||||||
@ -41,7 +42,7 @@ use crate::{
|
|||||||
index::Index,
|
index::Index,
|
||||||
layer::spot::Spot,
|
layer::spot::Spot,
|
||||||
site::{SiteKind, SpawnRules},
|
site::{SiteKind, SpawnRules},
|
||||||
util::{Grid, Sampler},
|
util::{Grid, Sampler, NEIGHBORS},
|
||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
assets,
|
assets,
|
||||||
@ -358,6 +359,65 @@ impl World {
|
|||||||
entities: Vec::new(),
|
entities: Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut splines = Vec::new();
|
||||||
|
let g = |v: Vec2<f32>| -> Vec3<f32> {
|
||||||
|
let path_nearest =
|
||||||
|
self.sim
|
||||||
|
.get_nearest_path(v.as_::<i32>())
|
||||||
|
.map(|x| x.1)
|
||||||
|
.unwrap_or(v.as_::<f32>());
|
||||||
|
let alt = if let Some(c) = canvas.col_or_gen(v.as_::<i32>()) {
|
||||||
|
let pl = PathLocals::new(&canvas, &c, path_nearest);
|
||||||
|
pl.riverless_alt + pl.bridge_offset + 0.75
|
||||||
|
} else {
|
||||||
|
sim_chunk.alt
|
||||||
|
};
|
||||||
|
v.with_z(alt)
|
||||||
|
};
|
||||||
|
fn hermit_to_bezier(p0: Vec3<f32>, m0: Vec3<f32>, p3: Vec3<f32>, m3: Vec3<f32>) -> CubicBezier3<f32> {
|
||||||
|
let hermite = Vec4::new(p0, p3, m0, m3);
|
||||||
|
let hermite = hermite.map(|v| v.with_w(0.0));
|
||||||
|
let hermite: [[f32; 4]; 4] =
|
||||||
|
hermite.map(|v: Vec4<f32>| v.into_array()).into_array();
|
||||||
|
// https://courses.engr.illinois.edu/cs418/sp2009/notes/12-MoreSplines.pdf
|
||||||
|
let mut m = Mat4::from_row_arrays([
|
||||||
|
[1.0, 0.0, 0.0, 0.0],
|
||||||
|
[0.0, 0.0, 0.0, 1.0],
|
||||||
|
[-3.0, 3.0, 0.0, 0.0],
|
||||||
|
[0.0, 0.0, -3.0, 3.0],
|
||||||
|
]);
|
||||||
|
m.invert();
|
||||||
|
let bezier = m * Mat4::from_row_arrays(hermite);
|
||||||
|
let bezier: Vec4<Vec4<f32>> =
|
||||||
|
Vec4::<[f32; 4]>::from(bezier.into_row_arrays())
|
||||||
|
.map(Vec4::from);
|
||||||
|
let bezier = bezier.map(|v| Vec3::from(v));
|
||||||
|
CubicBezier3::from(bezier)
|
||||||
|
}
|
||||||
|
for (_, _, _, _, bez, _) in self.sim.get_nearest_ways(chunk_center_wpos2d, &|chunk| Some(chunk.path)) {
|
||||||
|
if bez.length_by_discretization(16) < 0.125 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/*if bez.ctrl.as_::<i32>().distance_squared(chunk_center_wpos2d) > 20i32.pow(2) {
|
||||||
|
continue;
|
||||||
|
}*/
|
||||||
|
//println!("chunk: {:?}, bez: {:?}", chunk_center_wpos2d, bez);
|
||||||
|
let a = 0.0;
|
||||||
|
let b = 1.0;
|
||||||
|
for bez in bez.split((a + b) / 2.0) {
|
||||||
|
let p0 = g(bez.evaluate(a));
|
||||||
|
let p1 = g(bez.evaluate(a + (b - a) / 3.0));
|
||||||
|
let p2 = g(bez.evaluate(a + 2.0 * (b-a)/3.0));
|
||||||
|
let p3 = g(bez.evaluate(b));
|
||||||
|
splines.push(hermit_to_bezier(p0, 3.0 * (p1 - p0), p3, 3.0 * (p3 - p2)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for spline in splines.into_iter() {
|
||||||
|
canvas.chunk.meta_mut().add_track(spline);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if index.features.caverns {
|
if index.features.caverns {
|
||||||
layer::apply_caverns_to(&mut canvas, &mut dynamic_rng);
|
layer::apply_caverns_to(&mut canvas, &mut dynamic_rng);
|
||||||
}
|
}
|
||||||
|
@ -2133,14 +2133,11 @@ impl WorldSim {
|
|||||||
Some(z0 + z1 + z2 + z3)
|
Some(z0 + z1 + z2 + z3)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the distance to the nearest way in blocks, along with the
|
pub fn get_nearest_ways<'a, M: Clone + Lerp<Output = M>>(
|
||||||
/// closest point on the way, the way metadata, and the tangent vector
|
&'a self,
|
||||||
/// of that way.
|
|
||||||
pub fn get_nearest_way<M: Clone + Lerp<Output = M>>(
|
|
||||||
&self,
|
|
||||||
wpos: Vec2<i32>,
|
wpos: Vec2<i32>,
|
||||||
get_way: impl Fn(&SimChunk) -> Option<(Way, M)>,
|
get_way: &'a impl Fn(&SimChunk) -> Option<(Way, M)>,
|
||||||
) -> Option<(f32, Vec2<f32>, M, Vec2<f32>)> {
|
) -> impl Iterator<Item=(usize, f32, Vec2<f32>, M, QuadraticBezier2<f32>, impl FnOnce() -> Vec2<f32>)> + 'a {
|
||||||
let chunk_pos = wpos.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| {
|
let chunk_pos = wpos.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| {
|
||||||
e.div_euclid(sz as i32)
|
e.div_euclid(sz as i32)
|
||||||
});
|
});
|
||||||
@ -2150,10 +2147,9 @@ impl WorldSim {
|
|||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
let get_way = &get_way;
|
|
||||||
LOCALITY
|
LOCALITY
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|ctrl| {
|
.filter_map(move |ctrl| {
|
||||||
let (way, meta) = get_way(self.get(chunk_pos + *ctrl)?)?;
|
let (way, meta) = get_way(self.get(chunk_pos + *ctrl)?)?;
|
||||||
let ctrl_pos = get_chunk_centre(chunk_pos + *ctrl).map(|e| e as f32)
|
let ctrl_pos = get_chunk_centre(chunk_pos + *ctrl).map(|e| e as f32)
|
||||||
+ way.offset.map(|e| e as f32);
|
+ way.offset.map(|e| e as f32);
|
||||||
@ -2163,7 +2159,7 @@ impl WorldSim {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (start_pos, _start_idx, start_meta) = if chunk_connections != 2 {
|
let (start_pos, start_idx, start_meta) = if chunk_connections != 2 {
|
||||||
(ctrl_pos, None, meta.clone())
|
(ctrl_pos, None, meta.clone())
|
||||||
} else {
|
} else {
|
||||||
let (start_idx, start_rpos) = NEIGHBORS
|
let (start_idx, start_rpos) = NEIGHBORS
|
||||||
@ -2186,8 +2182,8 @@ impl WorldSim {
|
|||||||
NEIGHBORS
|
NEIGHBORS
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter(move |(i, _)| way.neighbors & (1 << *i as u8) != 0)
|
.filter(move |(i, _)| way.neighbors & (1 << *i as u8) != 0 && Some(*i) != start_idx)
|
||||||
.filter_map(move |(_, end_rpos)| {
|
.filter_map(move |(i, end_rpos)| {
|
||||||
let end_pos_chunk = chunk_pos + *ctrl + end_rpos;
|
let end_pos_chunk = chunk_pos + *ctrl + end_rpos;
|
||||||
let (end_way, end_meta) = get_way(self.get(end_pos_chunk)?)?;
|
let (end_way, end_meta) = get_way(self.get(end_pos_chunk)?)?;
|
||||||
let end_pos = get_chunk_centre(end_pos_chunk).map(|e| e as f32)
|
let end_pos = get_chunk_centre(end_pos_chunk).map(|e| e as f32)
|
||||||
@ -2209,15 +2205,27 @@ impl WorldSim {
|
|||||||
} else {
|
} else {
|
||||||
Lerp::lerp(meta.clone(), end_meta, nearest_interval - 0.5)
|
Lerp::lerp(meta.clone(), end_meta, nearest_interval - 0.5)
|
||||||
};
|
};
|
||||||
Some((dist_sqrd, pos, meta, move || {
|
Some((i, dist_sqrd, pos, meta, bez, move || {
|
||||||
bez.evaluate_derivative(nearest_interval).normalized()
|
bez.evaluate_derivative(nearest_interval).normalized()
|
||||||
}))
|
}))
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.flatten()
|
.flatten()
|
||||||
.min_by_key(|(dist_sqrd, _, _, _)| (dist_sqrd * 1024.0) as i32)
|
}
|
||||||
.map(|(dist, pos, meta, calc_tangent)| (dist.sqrt(), pos, meta, calc_tangent()))
|
|
||||||
|
/// Return the distance to the nearest way in blocks, along with the
|
||||||
|
/// closest point on the way, the way metadata, and the tangent vector
|
||||||
|
/// of that way.
|
||||||
|
pub fn get_nearest_way<M: Clone + Lerp<Output = M>>(
|
||||||
|
&self,
|
||||||
|
wpos: Vec2<i32>,
|
||||||
|
get_way: impl Fn(&SimChunk) -> Option<(Way, M)>,
|
||||||
|
) -> Option<(f32, Vec2<f32>, M, Vec2<f32>)> {
|
||||||
|
let get_way = &get_way;
|
||||||
|
self.get_nearest_ways(wpos, get_way)
|
||||||
|
.min_by_key(|(_, dist_sqrd, _, _, _, _)| (dist_sqrd * 1024.0) as i32)
|
||||||
|
.map(|(_, dist, pos, meta, _, calc_tangent)| (dist.sqrt(), pos, meta, calc_tangent()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_nearest_path(&self, wpos: Vec2<i32>) -> Option<(f32, Vec2<f32>, Path, Vec2<f32>)> {
|
pub fn get_nearest_path(&self, wpos: Vec2<i32>) -> Option<(f32, Vec2<f32>, Path, Vec2<f32>)> {
|
||||||
@ -2228,6 +2236,14 @@ impl WorldSim {
|
|||||||
self.get_nearest_way(wpos, |chunk| Some(chunk.cave))
|
self.get_nearest_way(wpos, |chunk| Some(chunk.cave))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_nearest_path_for_direction(&self, wpos: Vec2<i32>, dir: usize) -> Option<(f32, Vec2<f32>, Path, QuadraticBezier2<f32>, Vec2<f32>)> {
|
||||||
|
self.get_nearest_ways(wpos, &|chunk| Some(chunk.path))
|
||||||
|
.filter(|(i, _, _, _, _, _)| *i == dir)
|
||||||
|
.min_by_key(|(_, dist_sqrd, _, _, _, _)| (dist_sqrd * 1024.0) as i32)
|
||||||
|
.map(|(_, dist, pos, meta, bez, calc_tangent)| (dist.sqrt(), pos, meta, bez, calc_tangent()))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Create a [`Lottery<Option<ForestKind>>`] that generates [`ForestKind`]s
|
/// Create a [`Lottery<Option<ForestKind>>`] that generates [`ForestKind`]s
|
||||||
/// according to the conditions at the given position. If no or fewer
|
/// according to the conditions at the given position. If no or fewer
|
||||||
/// trees are appropriate for the conditions, `None` may be generated.
|
/// trees are appropriate for the conditions, `None` may be generated.
|
||||||
|
Loading…
Reference in New Issue
Block a user