mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
lod for sprites on volumes
This commit is contained in:
parent
fcb7011cde
commit
d292234c47
@ -173,13 +173,13 @@ pub mod figuredata {
|
|||||||
|
|
||||||
impl DeBlock {
|
impl DeBlock {
|
||||||
fn to_block(&self, color: Rgb<u8>) -> Block {
|
fn to_block(&self, color: Rgb<u8>) -> Block {
|
||||||
match self {
|
match *self {
|
||||||
&DeBlock::Block(block) => Block::new(block, color),
|
DeBlock::Block(block) => Block::new(block, color),
|
||||||
&DeBlock::Air(sprite, ori) => {
|
DeBlock::Air(sprite, ori) => {
|
||||||
let block = Block::new(BlockKind::Air, color).with_sprite(sprite);
|
let block = Block::new(BlockKind::Air, color).with_sprite(sprite);
|
||||||
block.with_ori(ori).unwrap_or(block)
|
block.with_ori(ori).unwrap_or(block)
|
||||||
},
|
},
|
||||||
&DeBlock::Water(sprite, ori) => {
|
DeBlock::Water(sprite, ori) => {
|
||||||
let block = Block::new(BlockKind::Water, color).with_sprite(sprite);
|
let block = Block::new(BlockKind::Water, color).with_sprite(sprite);
|
||||||
block.with_ori(ori).unwrap_or(block)
|
block.with_ori(ori).unwrap_or(block)
|
||||||
},
|
},
|
||||||
|
@ -9,8 +9,9 @@ pub use self::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
terrain::{Block, BlockKind},
|
||||||
vol::{IntoFullPosIterator, IntoFullVolIterator, ReadVol, SizedVol, Vox, WriteVol},
|
vol::{IntoFullPosIterator, IntoFullVolIterator, ReadVol, SizedVol, Vox, WriteVol},
|
||||||
volumes::dyna::Dyna, terrain::{Block, BlockKind},
|
volumes::dyna::Dyna,
|
||||||
};
|
};
|
||||||
use dot_vox::DotVoxData;
|
use dot_vox::DotVoxData;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
@ -19,19 +20,17 @@ pub type TerrainSegment = Dyna<Block, ()>;
|
|||||||
|
|
||||||
impl From<Segment> for TerrainSegment {
|
impl From<Segment> for TerrainSegment {
|
||||||
fn from(value: Segment) -> Self {
|
fn from(value: Segment) -> Self {
|
||||||
TerrainSegment::from_fn(value.sz, (), |pos| {
|
TerrainSegment::from_fn(value.sz, (), |pos| match value.get(pos) {
|
||||||
match value.get(pos) {
|
Err(_) | Ok(Cell::Empty) => Block::empty(),
|
||||||
Err(_) | Ok(Cell::Empty) => Block::empty(),
|
Ok(cell) => {
|
||||||
Ok(cell) => {
|
if cell.is_hollow() {
|
||||||
if cell.is_hollow() {
|
Block::empty()
|
||||||
Block::empty()
|
} else if cell.is_glowy() {
|
||||||
} else if cell.is_glowy() {
|
Block::new(BlockKind::GlowingRock, cell.get_color().unwrap())
|
||||||
Block::new(BlockKind::GlowingRock, cell.get_color().unwrap())
|
} else {
|
||||||
} else {
|
Block::new(BlockKind::Misc, cell.get_color().unwrap())
|
||||||
Block::new(BlockKind::Misc, cell.get_color().unwrap())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,12 @@ pub trait CharacterBehavior {
|
|||||||
fn talk(&self, data: &JoinData, _output_events: &mut OutputEvents) -> StateUpdate {
|
fn talk(&self, data: &JoinData, _output_events: &mut OutputEvents) -> StateUpdate {
|
||||||
StateUpdate::from(data)
|
StateUpdate::from(data)
|
||||||
}
|
}
|
||||||
fn mount_sprite(&self, data: &JoinData, _output_events: &mut OutputEvents, _pos: Vec3<i32>) -> StateUpdate {
|
fn mount_sprite(
|
||||||
|
&self,
|
||||||
|
data: &JoinData,
|
||||||
|
_output_events: &mut OutputEvents,
|
||||||
|
_pos: Vec3<i32>,
|
||||||
|
) -> StateUpdate {
|
||||||
StateUpdate::from(data)
|
StateUpdate::from(data)
|
||||||
}
|
}
|
||||||
// start_input has custom implementation in the following character states that
|
// start_input has custom implementation in the following character states that
|
||||||
|
@ -22,6 +22,7 @@ pub mod glide_wield;
|
|||||||
pub mod idle;
|
pub mod idle;
|
||||||
pub mod leap_melee;
|
pub mod leap_melee;
|
||||||
pub mod leap_shockwave;
|
pub mod leap_shockwave;
|
||||||
|
pub mod mount_sprite;
|
||||||
pub mod music;
|
pub mod music;
|
||||||
pub mod rapid_melee;
|
pub mod rapid_melee;
|
||||||
pub mod repeater_ranged;
|
pub mod repeater_ranged;
|
||||||
@ -40,4 +41,3 @@ pub mod use_item;
|
|||||||
pub mod utils;
|
pub mod utils;
|
||||||
pub mod wallrun;
|
pub mod wallrun;
|
||||||
pub mod wielding;
|
pub mod wielding;
|
||||||
pub mod mount_sprite;
|
|
||||||
|
@ -1,9 +1,16 @@
|
|||||||
use serde::{Serialize, Deserialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use vek::Vec3;
|
use vek::Vec3;
|
||||||
|
|
||||||
use crate::{comp::{character_state::OutputEvents, StateUpdate, CharacterState}, util::Dir};
|
use crate::{
|
||||||
|
comp::{character_state::OutputEvents, CharacterState, StateUpdate},
|
||||||
|
util::Dir,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{behavior::{CharacterBehavior, JoinData}, utils::{handle_orientation, end_ability, handle_wield}, idle};
|
use super::{
|
||||||
|
behavior::{CharacterBehavior, JoinData},
|
||||||
|
idle,
|
||||||
|
utils::{end_ability, handle_orientation, handle_wield},
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct StaticData {
|
pub struct StaticData {
|
||||||
@ -13,7 +20,6 @@ pub struct StaticData {
|
|||||||
pub sprite_pos: Vec3<i32>,
|
pub sprite_pos: Vec3<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct Data {
|
pub struct Data {
|
||||||
/// Struct containing data that does not change over the course of the
|
/// Struct containing data that does not change over the course of the
|
||||||
@ -27,7 +33,12 @@ impl CharacterBehavior for Data {
|
|||||||
update.pos.0 = self.static_data.mount_pos;
|
update.pos.0 = self.static_data.mount_pos;
|
||||||
update.vel.0 = Vec3::zero();
|
update.vel.0 = Vec3::zero();
|
||||||
|
|
||||||
handle_orientation(data, &mut update, 1.0, Some(Dir::new(self.static_data.mount_dir)));
|
handle_orientation(
|
||||||
|
data,
|
||||||
|
&mut update,
|
||||||
|
1.0,
|
||||||
|
Some(Dir::new(self.static_data.mount_dir)),
|
||||||
|
);
|
||||||
|
|
||||||
handle_wield(data, &mut update);
|
handle_wield(data, &mut update);
|
||||||
|
|
||||||
@ -46,4 +57,4 @@ impl CharacterBehavior for Data {
|
|||||||
|
|
||||||
update
|
update
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ use crate::{
|
|||||||
event::{LocalEvent, ServerEvent},
|
event::{LocalEvent, ServerEvent},
|
||||||
outcome::Outcome,
|
outcome::Outcome,
|
||||||
states::{behavior::JoinData, utils::CharacterState::Idle, *},
|
states::{behavior::JoinData, utils::CharacterState::Idle, *},
|
||||||
terrain::{TerrainGrid, UnlockKind, SpriteKind},
|
terrain::{SpriteKind, TerrainGrid, UnlockKind},
|
||||||
util::Dir,
|
util::Dir,
|
||||||
vol::ReadVol,
|
vol::ReadVol,
|
||||||
};
|
};
|
||||||
@ -785,26 +785,40 @@ pub fn attempt_sit(data: &JoinData<'_>, update: &mut StateUpdate) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sprite_mount_points(sprite_kind: SpriteKind, pos: Vec3<i32>, ori: u8) -> impl ExactSizeIterator<Item = (Vec3<f32>, Vec3<f32>)> {
|
pub fn sprite_mount_points(
|
||||||
|
sprite_kind: SpriteKind,
|
||||||
|
pos: Vec3<i32>,
|
||||||
|
ori: u8,
|
||||||
|
) -> impl ExactSizeIterator<Item = (Vec3<f32>, Vec3<f32>)> {
|
||||||
let mat = Mat4::identity()
|
let mat = Mat4::identity()
|
||||||
.rotated_z(std::f32::consts::PI * 0.25 * ori as f32)
|
.rotated_z(std::f32::consts::PI * 0.25 * ori as f32)
|
||||||
.translated_3d(
|
.translated_3d(pos.map(|e| e as f32) + Vec3::new(0.5, 0.5, 0.0));
|
||||||
pos.map(|e| e as f32) + Vec3::new(0.5, 0.5, 0.0)
|
sprite_kind
|
||||||
);
|
.mount_offsets()
|
||||||
sprite_kind.mount_offsets().iter().map(move |(pos, dir)| {
|
.iter()
|
||||||
((mat * pos.with_w(1.0)).xyz(), (mat * dir.with_w(0.0)).xyz())
|
.map(move |(pos, dir)| ((mat * pos.with_w(1.0)).xyz(), (mat * dir.with_w(0.0)).xyz()))
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const SPRITE_MOUNT_RANGE: f32 = 2.0;
|
const SPRITE_MOUNT_RANGE: f32 = 2.0;
|
||||||
pub const SPRITE_MOUNT_RANGE_SQR: f32 = SPRITE_MOUNT_RANGE * SPRITE_MOUNT_RANGE;
|
pub const SPRITE_MOUNT_RANGE_SQR: f32 = SPRITE_MOUNT_RANGE * SPRITE_MOUNT_RANGE;
|
||||||
|
|
||||||
pub fn attempt_mount_sprite(data: &JoinData<'_>, update: &mut StateUpdate, pos: Vec3<i32>) {
|
pub fn attempt_mount_sprite(data: &JoinData<'_>, update: &mut StateUpdate, pos: Vec3<i32>) {
|
||||||
if let Some((kind, ori)) = data.terrain.get(pos).ok().and_then(|block| block.get_sprite().zip(block.get_ori())) {
|
if let Some((kind, ori)) = data
|
||||||
if let Some((mount_pos, mount_dir)) = sprite_mount_points(kind, pos, ori).min_by_key(|(pos, _)| {
|
.terrain
|
||||||
OrderedFloat(data.pos.0.distance_squared(*pos))
|
.get(pos)
|
||||||
}) {
|
.ok()
|
||||||
if reach_block(data.pos.0, pos, SPRITE_MOUNT_RANGE_SQR, data.body, data.terrain) {
|
.and_then(|block| block.get_sprite().zip(block.get_ori()))
|
||||||
|
{
|
||||||
|
if let Some((mount_pos, mount_dir)) = sprite_mount_points(kind, pos, ori)
|
||||||
|
.min_by_key(|(pos, _)| OrderedFloat(data.pos.0.distance_squared(*pos)))
|
||||||
|
{
|
||||||
|
if reach_block(
|
||||||
|
data.pos.0,
|
||||||
|
pos,
|
||||||
|
SPRITE_MOUNT_RANGE_SQR,
|
||||||
|
data.body,
|
||||||
|
data.terrain,
|
||||||
|
) {
|
||||||
update.character = CharacterState::MountSprite(mount_sprite::Data {
|
update.character = CharacterState::MountSprite(mount_sprite::Data {
|
||||||
static_data: mount_sprite::StaticData {
|
static_data: mount_sprite::StaticData {
|
||||||
mount_pos,
|
mount_pos,
|
||||||
@ -887,13 +901,18 @@ pub fn attempt_swap_equipped_weapons(data: &JoinData<'_>, update: &mut StateUpda
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reach_block(player_pos: Vec3<f32>, block_pos: Vec3<i32>, range: f32, body: &Body, terrain: &TerrainGrid) -> bool {
|
fn reach_block(
|
||||||
|
player_pos: Vec3<f32>,
|
||||||
|
block_pos: Vec3<i32>,
|
||||||
|
range: f32,
|
||||||
|
body: &Body,
|
||||||
|
terrain: &TerrainGrid,
|
||||||
|
) -> bool {
|
||||||
let block_pos_f32 = block_pos.map(|x| x as f32 + 0.5);
|
let block_pos_f32 = block_pos.map(|x| x as f32 + 0.5);
|
||||||
// Closure to check if distance between a point and the block is less than
|
// Closure to check if distance between a point and the block is less than
|
||||||
// MAX_PICKUP_RANGE and the radius of the body
|
// MAX_PICKUP_RANGE and the radius of the body
|
||||||
let block_range_check = |pos: Vec3<f32>| {
|
let block_range_check = |pos: Vec3<f32>| {
|
||||||
(block_pos_f32 - pos).magnitude_squared()
|
(block_pos_f32 - pos).magnitude_squared() < (range + body.max_radius()).powi(2)
|
||||||
< (range + body.max_radius()).powi(2)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Checks if player's feet or head is near to block
|
// Checks if player's feet or head is near to block
|
||||||
@ -903,12 +922,10 @@ fn reach_block(player_pos: Vec3<f32>, block_pos: Vec3<i32>, range: f32, body: &B
|
|||||||
// Do a check that a path can be found between sprite and entity
|
// Do a check that a path can be found between sprite and entity
|
||||||
// interacting with sprite Use manhattan distance * 1.5 for number
|
// interacting with sprite Use manhattan distance * 1.5 for number
|
||||||
// of iterations
|
// of iterations
|
||||||
let iters =
|
let iters = (3.0 * (block_pos_f32 - player_pos).map(|x| x.abs()).sum()) as usize;
|
||||||
(3.0 * (block_pos_f32 - player_pos).map(|x| x.abs()).sum()) as usize;
|
|
||||||
// Heuristic compares manhattan distance of start and end pos
|
// Heuristic compares manhattan distance of start and end pos
|
||||||
let heuristic = move |pos: &Vec3<i32>, _: &Vec3<i32>| {
|
let heuristic =
|
||||||
(block_pos - pos).map(|x| x.abs()).sum() as f32
|
move |pos: &Vec3<i32>, _: &Vec3<i32>| (block_pos - pos).map(|x| x.abs()).sum() as f32;
|
||||||
};
|
|
||||||
|
|
||||||
let mut astar = Astar::new(
|
let mut astar = Astar::new(
|
||||||
iters,
|
iters,
|
||||||
@ -994,18 +1011,27 @@ pub fn handle_manipulate_loadout(
|
|||||||
},
|
},
|
||||||
InventoryAction::Collect(sprite_pos) => {
|
InventoryAction::Collect(sprite_pos) => {
|
||||||
// First, get sprite data for position, if there is a sprite
|
// First, get sprite data for position, if there is a sprite
|
||||||
let sprite_at_pos = data.terrain
|
let sprite_at_pos = data
|
||||||
|
.terrain
|
||||||
.get(sprite_pos)
|
.get(sprite_pos)
|
||||||
.ok()
|
.ok()
|
||||||
.copied()
|
.copied()
|
||||||
.and_then(|b| b.get_sprite());
|
.and_then(|b| b.get_sprite());
|
||||||
// Checks if position has a collectible sprite as well as what sprite is at the
|
// Checks if position has a collectible sprite as well as what sprite is at the
|
||||||
// position
|
// position
|
||||||
let sprite_interact = sprite_at_pos.and_then(Option::<sprite_interact::SpriteInteractKind>::from);
|
let sprite_interact =
|
||||||
|
sprite_at_pos.and_then(Option::<sprite_interact::SpriteInteractKind>::from);
|
||||||
if let Some(sprite_interact) = sprite_interact {
|
if let Some(sprite_interact) = sprite_interact {
|
||||||
if reach_block(data.pos.0, sprite_pos, MAX_PICKUP_RANGE, data.body, data.terrain) {
|
if reach_block(
|
||||||
|
data.pos.0,
|
||||||
|
sprite_pos,
|
||||||
|
MAX_PICKUP_RANGE,
|
||||||
|
data.body,
|
||||||
|
data.terrain,
|
||||||
|
) {
|
||||||
let sprite_chunk_pos = TerrainGrid::chunk_offs(sprite_pos);
|
let sprite_chunk_pos = TerrainGrid::chunk_offs(sprite_pos);
|
||||||
let sprite_cfg = data.terrain
|
let sprite_cfg = data
|
||||||
|
.terrain
|
||||||
.pos_chunk(sprite_pos)
|
.pos_chunk(sprite_pos)
|
||||||
.and_then(|chunk| chunk.meta().sprite_cfg_at(sprite_chunk_pos));
|
.and_then(|chunk| chunk.meta().sprite_cfg_at(sprite_chunk_pos));
|
||||||
let required_item =
|
let required_item =
|
||||||
@ -1034,21 +1060,20 @@ pub fn handle_manipulate_loadout(
|
|||||||
let (buildup_duration, use_duration, recover_duration) =
|
let (buildup_duration, use_duration, recover_duration) =
|
||||||
sprite_interact.durations();
|
sprite_interact.durations();
|
||||||
|
|
||||||
update.character =
|
update.character = CharacterState::SpriteInteract(sprite_interact::Data {
|
||||||
CharacterState::SpriteInteract(sprite_interact::Data {
|
static_data: sprite_interact::StaticData {
|
||||||
static_data: sprite_interact::StaticData {
|
buildup_duration,
|
||||||
buildup_duration,
|
use_duration,
|
||||||
use_duration,
|
recover_duration,
|
||||||
recover_duration,
|
sprite_pos,
|
||||||
sprite_pos,
|
sprite_kind: sprite_interact,
|
||||||
sprite_kind: sprite_interact,
|
was_wielded: data.character.is_wield(),
|
||||||
was_wielded: data.character.is_wield(),
|
was_sneak: data.character.is_stealthy(),
|
||||||
was_sneak: data.character.is_stealthy(),
|
required_item,
|
||||||
required_item,
|
},
|
||||||
},
|
timer: Duration::default(),
|
||||||
timer: Duration::default(),
|
stage_section: StageSection::Buildup,
|
||||||
stage_section: StageSection::Buildup,
|
})
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
output_events.emit_local(LocalEvent::CreateOutcome(
|
output_events.emit_local(LocalEvent::CreateOutcome(
|
||||||
Outcome::FailedSpriteUnlock { pos: sprite_pos },
|
Outcome::FailedSpriteUnlock { pos: sprite_pos },
|
||||||
|
@ -3,7 +3,8 @@ use crate::{
|
|||||||
comp::{fluid_dynamics::LiquidKind, tool::ToolKind},
|
comp::{fluid_dynamics::LiquidKind, tool::ToolKind},
|
||||||
consts::FRIC_GROUND,
|
consts::FRIC_GROUND,
|
||||||
lottery::LootSpec,
|
lottery::LootSpec,
|
||||||
make_case_elim, rtsim, vol::Vox,
|
make_case_elim, rtsim,
|
||||||
|
vol::Vox,
|
||||||
};
|
};
|
||||||
use num_derive::FromPrimitive;
|
use num_derive::FromPrimitive;
|
||||||
use num_traits::FromPrimitive;
|
use num_traits::FromPrimitive;
|
||||||
@ -118,13 +119,9 @@ pub struct Block {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Vox for Block {
|
impl Vox for Block {
|
||||||
fn empty() -> Self {
|
fn empty() -> Self { Block::empty() }
|
||||||
Block::empty()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_empty(&self) -> bool {
|
fn is_empty(&self) -> bool { self.is_air() && self.get_sprite().is_none() }
|
||||||
self.is_air() && self.get_sprite().is_none()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for Block {
|
impl Deref for Block {
|
||||||
@ -431,10 +428,7 @@ impl Block {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_mountable(&self) -> bool {
|
pub fn is_mountable(&self) -> bool { self.get_sprite().map_or(false, |s| s.is_mountable()) }
|
||||||
self.get_sprite()
|
|
||||||
.map_or(false, |s| s.is_mountable())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_bonkable(&self) -> bool {
|
pub fn is_bonkable(&self) -> bool {
|
||||||
|
@ -484,29 +484,38 @@ impl SpriteKind {
|
|||||||
z: 0.0,
|
z: 0.0,
|
||||||
};
|
};
|
||||||
match self {
|
match self {
|
||||||
SpriteKind::ChairSingle => &[(Vec3 {
|
SpriteKind::ChairSingle => &[(
|
||||||
x: 0.0,
|
Vec3 {
|
||||||
y: 0.0,
|
x: 0.0,
|
||||||
z: 0.5,
|
y: 0.0,
|
||||||
}, UNIT_Y)],
|
z: 0.5,
|
||||||
SpriteKind::ChairDouble => &[(Vec3 {
|
},
|
||||||
x: -0.5,
|
UNIT_Y,
|
||||||
y: 0.0,
|
)],
|
||||||
z: 0.6,
|
SpriteKind::ChairDouble => &[
|
||||||
}, UNIT_Y),
|
(
|
||||||
(Vec3 {
|
Vec3 {
|
||||||
x: 0.5,
|
x: -0.5,
|
||||||
y: -0.1,
|
y: 0.0,
|
||||||
z: 0.6,
|
z: 0.6,
|
||||||
}, UNIT_Y)],
|
},
|
||||||
|
UNIT_Y,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Vec3 {
|
||||||
|
x: 0.5,
|
||||||
|
y: -0.1,
|
||||||
|
z: 0.6,
|
||||||
|
},
|
||||||
|
UNIT_Y,
|
||||||
|
),
|
||||||
|
],
|
||||||
_ => &[],
|
_ => &[],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_mountable(&self) -> bool {
|
pub fn is_mountable(&self) -> bool { !self.mount_offsets().is_empty() }
|
||||||
!self.mount_offsets().is_empty()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Which tool (if any) is needed to collect this sprite?
|
/// Which tool (if any) is needed to collect this sprite?
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -46,9 +46,7 @@ make_case_elim!(
|
|||||||
);
|
);
|
||||||
|
|
||||||
impl Default for StructureBlock {
|
impl Default for StructureBlock {
|
||||||
fn default() -> Self {
|
fn default() -> Self { StructureBlock::None }
|
||||||
StructureBlock::None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -86,7 +84,9 @@ impl assets::Compound for StructuresGroup {
|
|||||||
.0
|
.0
|
||||||
.iter()
|
.iter()
|
||||||
.map(|sp| {
|
.map(|sp| {
|
||||||
let base = cache.load::<Arc<BaseStructure<StructureBlock>>>(&sp.specifier)?.cloned();
|
let base = cache
|
||||||
|
.load::<Arc<BaseStructure<StructureBlock>>>(&sp.specifier)?
|
||||||
|
.cloned();
|
||||||
Ok(Structure {
|
Ok(Structure {
|
||||||
center: Vec3::from(sp.center),
|
center: Vec3::from(sp.center),
|
||||||
base,
|
base,
|
||||||
@ -145,7 +145,10 @@ impl ReadVol for Structure {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn load_base_structure<B: Default>(dot_vox_data: &DotVoxData, mut to_block: impl FnMut(Rgb<u8>) -> B) -> BaseStructure<B> {
|
pub(crate) fn load_base_structure<B: Default>(
|
||||||
|
dot_vox_data: &DotVoxData,
|
||||||
|
mut to_block: impl FnMut(Rgb<u8>) -> B,
|
||||||
|
) -> BaseStructure<B> {
|
||||||
let mut palette = std::array::from_fn(|_| B::default());
|
let mut palette = std::array::from_fn(|_| B::default());
|
||||||
if let Some(model) = dot_vox_data.models.get(0) {
|
if let Some(model) = dot_vox_data.models.get(0) {
|
||||||
for (i, col) in dot_vox_data
|
for (i, col) in dot_vox_data
|
||||||
@ -184,7 +187,9 @@ impl assets::Compound for BaseStructure<StructureBlock> {
|
|||||||
let dot_vox_data = cache.load::<DotVoxAsset>(specifier)?.read();
|
let dot_vox_data = cache.load::<DotVoxAsset>(specifier)?.read();
|
||||||
let dot_vox_data = &dot_vox_data.0;
|
let dot_vox_data = &dot_vox_data.0;
|
||||||
|
|
||||||
Ok(load_base_structure(dot_vox_data, |col| StructureBlock::Filled(BlockKind::Misc, col)))
|
Ok(load_base_structure(dot_vox_data, |col| {
|
||||||
|
StructureBlock::Filled(BlockKind::Misc, col)
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,9 +71,10 @@ use crate::{
|
|||||||
render::UiDrawer,
|
render::UiDrawer,
|
||||||
scene::camera::{self, Camera},
|
scene::camera::{self, Camera},
|
||||||
session::{
|
session::{
|
||||||
|
interactable::{BlockInteraction, Interactable},
|
||||||
settings_change::{
|
settings_change::{
|
||||||
Audio, Chat as ChatChange, Interface as InterfaceChange, SettingsChange,
|
Audio, Chat as ChatChange, Interface as InterfaceChange, SettingsChange,
|
||||||
}, interactable::{Interactable, BlockInteraction},
|
},
|
||||||
},
|
},
|
||||||
settings::chat::ChatFilter,
|
settings::chat::ChatFilter,
|
||||||
ui::{
|
ui::{
|
||||||
|
@ -177,7 +177,7 @@ where
|
|||||||
};
|
};
|
||||||
let get_opacity = |vol: &mut V, pos: Vec3<i32>| vol.get(pos).map_or(true, |vox| vox.is_fluid());
|
let get_opacity = |vol: &mut V, pos: Vec3<i32>| vol.get(pos).map_or(true, |vox| vox.is_fluid());
|
||||||
let should_draw = |vol: &mut V, pos: Vec3<i32>, delta: Vec3<i32>, _uv| {
|
let should_draw = |vol: &mut V, pos: Vec3<i32>, delta: Vec3<i32>, _uv| {
|
||||||
super::terrain::should_draw_greedy(pos, delta, &|vox| {
|
super::terrain::should_draw_greedy(pos, delta, |vox| {
|
||||||
vol.get(vox)
|
vol.get(vox)
|
||||||
.map(|vox| *vox)
|
.map(|vox| *vox)
|
||||||
.unwrap_or_else(|_| Block::empty())
|
.unwrap_or_else(|_| Block::empty())
|
||||||
|
@ -147,7 +147,12 @@ pub struct Locals {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Locals {
|
impl Locals {
|
||||||
pub fn new(model_offs: Vec3<f32>, ori: Quaternion<f32>, atlas_offs: Vec2<u32>, load_time: f32) -> Self {
|
pub fn new(
|
||||||
|
model_offs: Vec3<f32>,
|
||||||
|
ori: Quaternion<f32>,
|
||||||
|
atlas_offs: Vec2<u32>,
|
||||||
|
load_time: f32,
|
||||||
|
) -> Self {
|
||||||
let mat = Mat4::from(ori).translated_3d(model_offs);
|
let mat = Mat4::from(ori).translated_3d(model_offs);
|
||||||
|
|
||||||
let mat_arr = mat.into_col_arrays();
|
let mat_arr = mat.into_col_arrays();
|
||||||
|
@ -8,8 +8,9 @@ use crate::{
|
|||||||
segment::{generate_mesh_base_vol_figure, generate_mesh_base_vol_terrain},
|
segment::{generate_mesh_base_vol_figure, generate_mesh_base_vol_terrain},
|
||||||
},
|
},
|
||||||
render::{
|
render::{
|
||||||
pipelines::terrain::{BoundLocals as BoundTerrainLocals, Locals as TerrainLocals}, BoneMeshes, ColLightInfo,
|
pipelines::terrain::{BoundLocals as BoundTerrainLocals, Locals as TerrainLocals},
|
||||||
FigureModel, Instances, Mesh, Renderer, SpriteInstance, TerrainVertex,
|
BoneMeshes, ColLightInfo, FigureModel, Instances, Mesh, Renderer, SpriteInstance,
|
||||||
|
TerrainVertex,
|
||||||
},
|
},
|
||||||
scene::{
|
scene::{
|
||||||
camera::CameraMode,
|
camera::CameraMode,
|
||||||
@ -36,7 +37,7 @@ use core::{hash::Hash, ops::Range};
|
|||||||
use crossbeam_utils::atomic;
|
use crossbeam_utils::atomic;
|
||||||
use hashbrown::{hash_map::Entry, HashMap};
|
use hashbrown::{hash_map::Entry, HashMap};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::{sync::Arc, array::from_fn};
|
use std::{array::from_fn, sync::Arc};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
/// A type produced by mesh worker threads corresponding to the information
|
/// A type produced by mesh worker threads corresponding to the information
|
||||||
@ -321,16 +322,20 @@ where
|
|||||||
/// the model, we don't return skeleton data.
|
/// the model, we don't return skeleton data.
|
||||||
pub fn get_model<'b>(
|
pub fn get_model<'b>(
|
||||||
&'b self,
|
&'b self,
|
||||||
// TODO: If we ever convert to using an atlas here, use this.
|
// TODO: If we ever convert to using an atlas here, use this.
|
||||||
_col_lights: &super::FigureColLights,
|
_col_lights: &super::FigureColLights,
|
||||||
body: Skel::Body,
|
body: Skel::Body,
|
||||||
inventory: Option<&Inventory>,
|
inventory: Option<&Inventory>,
|
||||||
// TODO: Consider updating the tick by putting it in a Cell.
|
// TODO: Consider updating the tick by putting it in a Cell.
|
||||||
_tick: u64,
|
_tick: u64,
|
||||||
camera_mode: CameraMode,
|
camera_mode: CameraMode,
|
||||||
character_state: Option<&CharacterState>,
|
character_state: Option<&CharacterState>,
|
||||||
item_key: Option<ItemKey>,
|
item_key: Option<ItemKey>,
|
||||||
) -> Option<&<<Skel::Body as BodySpec>::ModelEntryFuture<LOD_COUNT> as ModelEntryFuture<LOD_COUNT>>::ModelEntry>{
|
) -> Option<
|
||||||
|
&'b <<Skel::Body as BodySpec>::ModelEntryFuture<LOD_COUNT> as ModelEntryFuture<
|
||||||
|
LOD_COUNT,
|
||||||
|
>>::ModelEntry,
|
||||||
|
> {
|
||||||
// TODO: Use raw entries to avoid lots of allocation (among other things).
|
// TODO: Use raw entries to avoid lots of allocation (among other things).
|
||||||
let key = FigureKey {
|
let key = FigureKey {
|
||||||
body,
|
body,
|
||||||
@ -851,10 +856,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_blocks_of_interest<'c>(
|
pub fn get_blocks_of_interest(&self, body: Skel::Body) -> Option<&BlocksOfInterest> {
|
||||||
&'c self,
|
|
||||||
body: Skel::Body,
|
|
||||||
) -> Option<&'c BlocksOfInterest> {
|
|
||||||
let key = FigureKey {
|
let key = FigureKey {
|
||||||
body,
|
body,
|
||||||
item_key: None,
|
item_key: None,
|
||||||
@ -869,12 +871,12 @@ where
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_sprites<'c>(
|
pub fn get_sprites(
|
||||||
&'c self,
|
&self,
|
||||||
body: Skel::Body,
|
body: Skel::Body,
|
||||||
) -> Option<(
|
) -> Option<(
|
||||||
&'c BoundTerrainLocals,
|
&BoundTerrainLocals,
|
||||||
&'c [Instances<SpriteInstance>; SPRITE_LOD_LEVELS],
|
&[Instances<SpriteInstance>; SPRITE_LOD_LEVELS],
|
||||||
)> {
|
)> {
|
||||||
let key = FigureKey {
|
let key = FigureKey {
|
||||||
body,
|
body,
|
||||||
@ -909,7 +911,12 @@ where
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
renderer.update_consts(&mut *model.terrain_locals, &[TerrainLocals::new(pos, ori, Vec2::zero(), 0.0)])
|
renderer.update_consts(&mut *model.terrain_locals, &[TerrainLocals::new(
|
||||||
|
pos,
|
||||||
|
ori,
|
||||||
|
Vec2::zero(),
|
||||||
|
0.0,
|
||||||
|
)])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
use super::cache::{FigureKey, ToolKey, TerrainModelEntryFuture, FigureModelEntryFuture, ModelEntryFuture};
|
use super::cache::{
|
||||||
|
FigureKey, FigureModelEntryFuture, ModelEntryFuture, TerrainModelEntryFuture, ToolKey,
|
||||||
|
};
|
||||||
use common::{
|
use common::{
|
||||||
assets::{self, AssetExt, AssetHandle, DotVoxAsset, ReloadWatcher, Ron},
|
assets::{self, AssetExt, AssetHandle, DotVoxAsset, ReloadWatcher, Ron},
|
||||||
comp::{
|
comp::{
|
||||||
@ -24,7 +26,9 @@ use common::{
|
|||||||
theropod::{self, BodyType as TBodyType, Species as TSpecies},
|
theropod::{self, BodyType as TBodyType, Species as TSpecies},
|
||||||
},
|
},
|
||||||
figure::{Cell, DynaUnionizer, MatCell, MatSegment, Material, Segment},
|
figure::{Cell, DynaUnionizer, MatCell, MatSegment, Material, Segment},
|
||||||
vol::{IntoFullPosIterator, ReadVol, Vox}, terrain::Block, volumes::dyna::Dyna,
|
terrain::Block,
|
||||||
|
vol::{IntoFullPosIterator, ReadVol, Vox},
|
||||||
|
volumes::dyna::Dyna,
|
||||||
};
|
};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use serde::{Deserialize, Deserializer};
|
use serde::{Deserialize, Deserializer};
|
||||||
@ -5273,7 +5277,7 @@ fn mesh_ship_bone<'a, K: fmt::Debug + Eq + Hash, V, F: Fn(&V) -> Option<&'a Voxe
|
|||||||
Some(spec) => spec,
|
Some(spec) => spec,
|
||||||
None => {
|
None => {
|
||||||
error!("No specification exists for {:?}", obj);
|
error!("No specification exists for {:?}", obj);
|
||||||
|
|
||||||
return None;
|
return None;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -5283,11 +5287,11 @@ fn mesh_ship_bone<'a, K: fmt::Debug + Eq + Hash, V, F: Fn(&V) -> Option<&'a Voxe
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl BodySpec for ship::Body {
|
impl BodySpec for ship::Body {
|
||||||
|
type BoneMesh = ShipBoneMeshes;
|
||||||
type Extra = ();
|
type Extra = ();
|
||||||
type Manifests = AssetHandle<Self::Spec>;
|
type Manifests = AssetHandle<Self::Spec>;
|
||||||
type Spec = ShipSpec;
|
|
||||||
type BoneMesh = ShipBoneMeshes;
|
|
||||||
type ModelEntryFuture<const N: usize> = TerrainModelEntryFuture<N>;
|
type ModelEntryFuture<const N: usize> = TerrainModelEntryFuture<N>;
|
||||||
|
type Spec = ShipSpec;
|
||||||
|
|
||||||
fn load_spec() -> Result<Self::Manifests, assets::Error> { Self::Spec::load("") }
|
fn load_spec() -> Result<Self::Manifests, assets::Error> { Self::Spec::load("") }
|
||||||
|
|
||||||
|
@ -14,9 +14,9 @@ use crate::{
|
|||||||
terrain::{BoundLocals as BoundTerrainLocals, Locals as TerrainLocals},
|
terrain::{BoundLocals as BoundTerrainLocals, Locals as TerrainLocals},
|
||||||
trail, ColLights,
|
trail, ColLights,
|
||||||
},
|
},
|
||||||
ColLightInfo, FigureBoneData, FigureDrawer, FigureLocals, FigureModel, FigureShadowDrawer,
|
AltIndices, ColLightInfo, CullingMode, FigureBoneData, FigureDrawer, FigureLocals,
|
||||||
Instances, Mesh, Quad, RenderError, Renderer, SpriteDrawer, SpriteInstance, SubModel,
|
FigureModel, FigureShadowDrawer, Instances, Mesh, Quad, RenderError, Renderer,
|
||||||
TerrainVertex, CullingMode, AltIndices,
|
SpriteDrawer, SpriteInstance, SubModel, TerrainVertex,
|
||||||
},
|
},
|
||||||
scene::{
|
scene::{
|
||||||
camera::{Camera, CameraMode, Dependents},
|
camera::{Camera, CameraMode, Dependents},
|
||||||
@ -6312,7 +6312,7 @@ impl FigureMgr {
|
|||||||
&'a self,
|
&'a self,
|
||||||
drawer: &mut SpriteDrawer<'_, 'a>,
|
drawer: &mut SpriteDrawer<'_, 'a>,
|
||||||
state: &State,
|
state: &State,
|
||||||
focus_pos: Vec3<f32>,
|
cam_pos: Vec3<f32>,
|
||||||
sprite_render_distance: f32,
|
sprite_render_distance: f32,
|
||||||
) {
|
) {
|
||||||
span!(_guard, "render", "FigureManager::render_sprites");
|
span!(_guard, "render", "FigureManager::render_sprites");
|
||||||
@ -6322,28 +6322,48 @@ impl FigureMgr {
|
|||||||
let sprite_hid_detail_distance = sprite_render_distance * 0.35;
|
let sprite_hid_detail_distance = sprite_render_distance * 0.35;
|
||||||
let sprite_high_detail_distance = sprite_render_distance * 0.15;
|
let sprite_high_detail_distance = sprite_render_distance * 0.15;
|
||||||
|
|
||||||
for (entity, pos, body, _, inventory, scale, collider) in (
|
for (entity, pos, body, _, collider) in (
|
||||||
&ecs.entities(),
|
&ecs.entities(),
|
||||||
&ecs.read_storage::<Pos>(),
|
&ecs.read_storage::<Pos>(),
|
||||||
&ecs.read_storage::<Body>(),
|
&ecs.read_storage::<Body>(),
|
||||||
ecs.read_storage::<Health>().maybe(),
|
ecs.read_storage::<Health>().maybe(),
|
||||||
ecs.read_storage::<Inventory>().maybe(),
|
|
||||||
ecs.read_storage::<Scale>().maybe(),
|
|
||||||
ecs.read_storage::<Collider>().maybe(),
|
ecs.read_storage::<Collider>().maybe(),
|
||||||
)
|
)
|
||||||
.join()
|
.join()
|
||||||
// Don't render dead entities
|
// Don't render dead entities
|
||||||
.filter(|(_, _, _, health, _, _, _)| health.map_or(true, |h| !h.is_dead))
|
.filter(|(_, _, _, health, _)| health.map_or(true, |h| !h.is_dead))
|
||||||
{
|
{
|
||||||
if let Some((data, sprite_instances)) = self.get_sprite_instances(
|
if let Some((data, sprite_instances)) =
|
||||||
entity,
|
self.get_sprite_instances(entity, body, collider)
|
||||||
body,
|
{
|
||||||
collider,
|
let dist_sqrd = cam_pos.distance_squared(pos.0);
|
||||||
) {
|
let radius = collider.map_or(f32::INFINITY, |collider| collider.bounding_radius());
|
||||||
let focus_dist_sqrd = pos.0.distance_squared(focus_pos);
|
|
||||||
|
|
||||||
// TODO NOW: LOD
|
let dist_sqrd = dist_sqrd - radius * radius;
|
||||||
drawer.draw(data, &sprite_instances[0], &AltIndices { deep_end: 0, underground_end: 0 }, CullingMode::None)
|
|
||||||
|
if dist_sqrd < sprite_render_distance.powi(2) {
|
||||||
|
let lod_level = if dist_sqrd < sprite_high_detail_distance.powi(2) {
|
||||||
|
0
|
||||||
|
} else if dist_sqrd < sprite_hid_detail_distance.powi(2) {
|
||||||
|
1
|
||||||
|
} else if dist_sqrd < sprite_mid_detail_distance.powi(2) {
|
||||||
|
2
|
||||||
|
} else if dist_sqrd < sprite_low_detail_distance.powi(2) {
|
||||||
|
3
|
||||||
|
} else {
|
||||||
|
4
|
||||||
|
};
|
||||||
|
|
||||||
|
drawer.draw(
|
||||||
|
data,
|
||||||
|
&sprite_instances[lod_level],
|
||||||
|
&AltIndices {
|
||||||
|
deep_end: 0,
|
||||||
|
underground_end: 0,
|
||||||
|
},
|
||||||
|
CullingMode::None,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6935,13 +6955,9 @@ impl FigureMgr {
|
|||||||
entity,
|
entity,
|
||||||
mut_count: vol.mut_count,
|
mut_count: vol.mut_count,
|
||||||
};
|
};
|
||||||
self.volume_model_cache.get_sprites(
|
self.volume_model_cache.get_sprites(vk)
|
||||||
vk,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
self.ship_model_cache.get_sprites(
|
self.ship_model_cache.get_sprites(*body)
|
||||||
*body,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => None,
|
_ => None,
|
||||||
@ -7157,8 +7173,12 @@ impl FigureColLights {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
let terrain_locals =
|
let terrain_locals = renderer.create_terrain_bound_locals(&[TerrainLocals::new(
|
||||||
renderer.create_terrain_bound_locals(&[TerrainLocals::new(pos, ori, Vec2::zero(), 0.0)]);
|
pos,
|
||||||
|
ori,
|
||||||
|
Vec2::zero(),
|
||||||
|
0.0,
|
||||||
|
)]);
|
||||||
|
|
||||||
let sprite_instances =
|
let sprite_instances =
|
||||||
sprite_instances.map(|instances| renderer.create_instances(&instances));
|
sprite_instances.map(|instances| renderer.create_instances(&instances));
|
||||||
|
@ -1355,7 +1355,7 @@ impl Scene {
|
|||||||
self.figure_mgr.render_sprites(
|
self.figure_mgr.render_sprites(
|
||||||
&mut sprite_drawer,
|
&mut sprite_drawer,
|
||||||
state,
|
state,
|
||||||
focus_pos,
|
cam_pos,
|
||||||
scene_data.sprite_render_distance,
|
scene_data.sprite_render_distance,
|
||||||
);
|
);
|
||||||
self.terrain.render_sprites(
|
self.terrain.render_sprites(
|
||||||
|
@ -10,9 +10,10 @@ use crate::{
|
|||||||
},
|
},
|
||||||
render::{
|
render::{
|
||||||
pipelines::{self, ColLights},
|
pipelines::{self, ColLights},
|
||||||
AltIndices, ColLightInfo, FirstPassDrawer, FluidVertex, GlobalModel, Instances, LodData, Mesh, Model,
|
AltIndices, ColLightInfo, CullingMode, FirstPassDrawer, FluidVertex, GlobalModel,
|
||||||
RenderError, Renderer, SpriteDrawer, SpriteGlobalsBindGroup, SpriteInstance, SpriteVertex,
|
Instances, LodData, Mesh, Model, RenderError, Renderer, SpriteDrawer,
|
||||||
SpriteVerts, TerrainLocals, TerrainShadowDrawer, TerrainVertex, SPRITE_VERT_PAGE_SIZE, CullingMode,
|
SpriteGlobalsBindGroup, SpriteInstance, SpriteVertex, SpriteVerts, TerrainLocals,
|
||||||
|
TerrainShadowDrawer, TerrainVertex, SPRITE_VERT_PAGE_SIZE,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -260,7 +261,13 @@ pub fn get_sprite_instances<'a, I: 'a>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let wpos = to_wpos(rel_pos);
|
let wpos = to_wpos(rel_pos);
|
||||||
let seed = (wpos.x as u64).overflowing_mul(3).0.overflowing_add((wpos.y as u64).overflowing_mul(7).0).0.overflowing_add((wpos.x as u64).overflowing_mul(wpos.y as u64).0).0; // Awful PRNG
|
let seed = (wpos.x as u64)
|
||||||
|
.overflowing_mul(3)
|
||||||
|
.0
|
||||||
|
.overflowing_add((wpos.y as u64).overflowing_mul(7).0)
|
||||||
|
.0
|
||||||
|
.overflowing_add((wpos.x as u64).overflowing_mul(wpos.y as u64).0)
|
||||||
|
.0; // Awful PRNG
|
||||||
|
|
||||||
let ori = (block.get_ori().unwrap_or((seed % 4) as u8 * 2)) & 0b111;
|
let ori = (block.get_ori().unwrap_or((seed % 4) as u8 * 2)) & 0b111;
|
||||||
let variation = seed as usize % cfg.variations.len();
|
let variation = seed as usize % cfg.variations.len();
|
||||||
@ -360,7 +367,9 @@ fn mesh_worker(
|
|||||||
let mesh = mesh.as_ref().unwrap();
|
let mesh = mesh.as_ref().unwrap();
|
||||||
(&*mesh.light_map, &*mesh.glow_map)
|
(&*mesh.light_map, &*mesh.glow_map)
|
||||||
};
|
};
|
||||||
let to_wpos = |rel_pos: Vec3<f32>| Vec3::from(pos * TerrainChunk::RECT_SIZE.map(|e: u32| e as i32)) + rel_pos.as_();
|
let to_wpos = |rel_pos: Vec3<f32>| {
|
||||||
|
Vec3::from(pos * TerrainChunk::RECT_SIZE.map(|e: u32| e as i32)) + rel_pos.as_()
|
||||||
|
};
|
||||||
MeshWorkerResponse {
|
MeshWorkerResponse {
|
||||||
pos,
|
pos,
|
||||||
// Extract sprite locations from volume
|
// Extract sprite locations from volume
|
||||||
@ -394,7 +403,8 @@ fn mesh_worker(
|
|||||||
(0..TerrainChunk::RECT_SIZE.x as i32)
|
(0..TerrainChunk::RECT_SIZE.x as i32)
|
||||||
.flat_map(|x| {
|
.flat_map(|x| {
|
||||||
(0..TerrainChunk::RECT_SIZE.y as i32).flat_map(move |y| {
|
(0..TerrainChunk::RECT_SIZE.y as i32).flat_map(move |y| {
|
||||||
(z_bounds.0 as i32..z_bounds.1 as i32).map(move |z| Vec3::new(x, y, z).as_())
|
(z_bounds.0 as i32..z_bounds.1 as i32)
|
||||||
|
.map(move |z| Vec3::new(x, y, z).as_())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.filter_map(|rel_pos| Some((rel_pos, *volume.get(to_wpos(rel_pos)).ok()?))),
|
.filter_map(|rel_pos| Some((rel_pos, *volume.get(to_wpos(rel_pos)).ok()?))),
|
||||||
@ -1228,11 +1238,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
|||||||
|
|
||||||
let sprite_instances =
|
let sprite_instances =
|
||||||
response.sprite_instances.map(|(instances, alt_indices)| {
|
response.sprite_instances.map(|(instances, alt_indices)| {
|
||||||
(
|
(renderer.create_instances(&instances), alt_indices)
|
||||||
renderer
|
|
||||||
.create_instances(&instances),
|
|
||||||
alt_indices,
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(mesh) = response.mesh {
|
if let Some(mesh) = response.mesh {
|
||||||
|
@ -892,7 +892,8 @@ impl PlayState for SessionState {
|
|||||||
if let Some(interactable) = &self.interactable {
|
if let Some(interactable) = &self.interactable {
|
||||||
match interactable {
|
match interactable {
|
||||||
Interactable::Block(_, pos, interaction) => {
|
Interactable::Block(_, pos, interaction) => {
|
||||||
if matches!(interaction, BlockInteraction::Mount(_)) {
|
if matches!(interaction, BlockInteraction::Mount(_))
|
||||||
|
{
|
||||||
client.mount_sprite(*pos)
|
client.mount_sprite(*pos)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user