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 {
|
||||
fn to_block(&self, color: Rgb<u8>) -> Block {
|
||||
match self {
|
||||
&DeBlock::Block(block) => Block::new(block, color),
|
||||
&DeBlock::Air(sprite, ori) => {
|
||||
match *self {
|
||||
DeBlock::Block(block) => Block::new(block, color),
|
||||
DeBlock::Air(sprite, ori) => {
|
||||
let block = Block::new(BlockKind::Air, color).with_sprite(sprite);
|
||||
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);
|
||||
block.with_ori(ori).unwrap_or(block)
|
||||
},
|
||||
|
@ -9,8 +9,9 @@ pub use self::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
terrain::{Block, BlockKind},
|
||||
vol::{IntoFullPosIterator, IntoFullVolIterator, ReadVol, SizedVol, Vox, WriteVol},
|
||||
volumes::dyna::Dyna, terrain::{Block, BlockKind},
|
||||
volumes::dyna::Dyna,
|
||||
};
|
||||
use dot_vox::DotVoxData;
|
||||
use vek::*;
|
||||
@ -19,19 +20,17 @@ pub type TerrainSegment = Dyna<Block, ()>;
|
||||
|
||||
impl From<Segment> for TerrainSegment {
|
||||
fn from(value: Segment) -> Self {
|
||||
TerrainSegment::from_fn(value.sz, (), |pos| {
|
||||
match value.get(pos) {
|
||||
Err(_) | Ok(Cell::Empty) => Block::empty(),
|
||||
Ok(cell) => {
|
||||
if cell.is_hollow() {
|
||||
Block::empty()
|
||||
} else if cell.is_glowy() {
|
||||
Block::new(BlockKind::GlowingRock, cell.get_color().unwrap())
|
||||
} else {
|
||||
Block::new(BlockKind::Misc, cell.get_color().unwrap())
|
||||
}
|
||||
TerrainSegment::from_fn(value.sz, (), |pos| match value.get(pos) {
|
||||
Err(_) | Ok(Cell::Empty) => Block::empty(),
|
||||
Ok(cell) => {
|
||||
if cell.is_hollow() {
|
||||
Block::empty()
|
||||
} else if cell.is_glowy() {
|
||||
Block::new(BlockKind::GlowingRock, cell.get_color().unwrap())
|
||||
} else {
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
// start_input has custom implementation in the following character states that
|
||||
|
@ -22,6 +22,7 @@ pub mod glide_wield;
|
||||
pub mod idle;
|
||||
pub mod leap_melee;
|
||||
pub mod leap_shockwave;
|
||||
pub mod mount_sprite;
|
||||
pub mod music;
|
||||
pub mod rapid_melee;
|
||||
pub mod repeater_ranged;
|
||||
@ -40,4 +41,3 @@ pub mod use_item;
|
||||
pub mod utils;
|
||||
pub mod wallrun;
|
||||
pub mod wielding;
|
||||
pub mod mount_sprite;
|
||||
|
@ -1,9 +1,16 @@
|
||||
use serde::{Serialize, Deserialize};
|
||||
use serde::{Deserialize, Serialize};
|
||||
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)]
|
||||
pub struct StaticData {
|
||||
@ -13,7 +20,6 @@ pub struct StaticData {
|
||||
pub sprite_pos: Vec3<i32>,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Data {
|
||||
/// 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.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);
|
||||
|
||||
@ -46,4 +57,4 @@ impl CharacterBehavior for Data {
|
||||
|
||||
update
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ use crate::{
|
||||
event::{LocalEvent, ServerEvent},
|
||||
outcome::Outcome,
|
||||
states::{behavior::JoinData, utils::CharacterState::Idle, *},
|
||||
terrain::{TerrainGrid, UnlockKind, SpriteKind},
|
||||
terrain::{SpriteKind, TerrainGrid, UnlockKind},
|
||||
util::Dir,
|
||||
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()
|
||||
.rotated_z(std::f32::consts::PI * 0.25 * ori as f32)
|
||||
.translated_3d(
|
||||
pos.map(|e| e as f32) + Vec3::new(0.5, 0.5, 0.0)
|
||||
);
|
||||
sprite_kind.mount_offsets().iter().map(move |(pos, dir)| {
|
||||
((mat * pos.with_w(1.0)).xyz(), (mat * dir.with_w(0.0)).xyz())
|
||||
})
|
||||
}
|
||||
.rotated_z(std::f32::consts::PI * 0.25 * ori as f32)
|
||||
.translated_3d(pos.map(|e| e as f32) + Vec3::new(0.5, 0.5, 0.0));
|
||||
sprite_kind
|
||||
.mount_offsets()
|
||||
.iter()
|
||||
.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;
|
||||
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>) {
|
||||
if let Some((kind, ori)) = data.terrain.get(pos).ok().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) {
|
||||
if let Some((kind, ori)) = data
|
||||
.terrain
|
||||
.get(pos)
|
||||
.ok()
|
||||
.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 {
|
||||
static_data: mount_sprite::StaticData {
|
||||
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);
|
||||
// Closure to check if distance between a point and the block is less than
|
||||
// MAX_PICKUP_RANGE and the radius of the body
|
||||
let block_range_check = |pos: Vec3<f32>| {
|
||||
(block_pos_f32 - pos).magnitude_squared()
|
||||
< (range + body.max_radius()).powi(2)
|
||||
(block_pos_f32 - pos).magnitude_squared() < (range + body.max_radius()).powi(2)
|
||||
};
|
||||
|
||||
// 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
|
||||
// interacting with sprite Use manhattan distance * 1.5 for number
|
||||
// of iterations
|
||||
let iters =
|
||||
(3.0 * (block_pos_f32 - player_pos).map(|x| x.abs()).sum()) as usize;
|
||||
let iters = (3.0 * (block_pos_f32 - player_pos).map(|x| x.abs()).sum()) as usize;
|
||||
// Heuristic compares manhattan distance of start and end pos
|
||||
let heuristic = move |pos: &Vec3<i32>, _: &Vec3<i32>| {
|
||||
(block_pos - pos).map(|x| x.abs()).sum() as f32
|
||||
};
|
||||
let heuristic =
|
||||
move |pos: &Vec3<i32>, _: &Vec3<i32>| (block_pos - pos).map(|x| x.abs()).sum() as f32;
|
||||
|
||||
let mut astar = Astar::new(
|
||||
iters,
|
||||
@ -994,18 +1011,27 @@ pub fn handle_manipulate_loadout(
|
||||
},
|
||||
InventoryAction::Collect(sprite_pos) => {
|
||||
// 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)
|
||||
.ok()
|
||||
.copied()
|
||||
.and_then(|b| b.get_sprite());
|
||||
// Checks if position has a collectible sprite as well as what sprite is at the
|
||||
// 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 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_cfg = data.terrain
|
||||
let sprite_cfg = data
|
||||
.terrain
|
||||
.pos_chunk(sprite_pos)
|
||||
.and_then(|chunk| chunk.meta().sprite_cfg_at(sprite_chunk_pos));
|
||||
let required_item =
|
||||
@ -1034,21 +1060,20 @@ pub fn handle_manipulate_loadout(
|
||||
let (buildup_duration, use_duration, recover_duration) =
|
||||
sprite_interact.durations();
|
||||
|
||||
update.character =
|
||||
CharacterState::SpriteInteract(sprite_interact::Data {
|
||||
static_data: sprite_interact::StaticData {
|
||||
buildup_duration,
|
||||
use_duration,
|
||||
recover_duration,
|
||||
sprite_pos,
|
||||
sprite_kind: sprite_interact,
|
||||
was_wielded: data.character.is_wield(),
|
||||
was_sneak: data.character.is_stealthy(),
|
||||
required_item,
|
||||
},
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Buildup,
|
||||
})
|
||||
update.character = CharacterState::SpriteInteract(sprite_interact::Data {
|
||||
static_data: sprite_interact::StaticData {
|
||||
buildup_duration,
|
||||
use_duration,
|
||||
recover_duration,
|
||||
sprite_pos,
|
||||
sprite_kind: sprite_interact,
|
||||
was_wielded: data.character.is_wield(),
|
||||
was_sneak: data.character.is_stealthy(),
|
||||
required_item,
|
||||
},
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Buildup,
|
||||
})
|
||||
} else {
|
||||
output_events.emit_local(LocalEvent::CreateOutcome(
|
||||
Outcome::FailedSpriteUnlock { pos: sprite_pos },
|
||||
|
@ -3,7 +3,8 @@ use crate::{
|
||||
comp::{fluid_dynamics::LiquidKind, tool::ToolKind},
|
||||
consts::FRIC_GROUND,
|
||||
lottery::LootSpec,
|
||||
make_case_elim, rtsim, vol::Vox,
|
||||
make_case_elim, rtsim,
|
||||
vol::Vox,
|
||||
};
|
||||
use num_derive::FromPrimitive;
|
||||
use num_traits::FromPrimitive;
|
||||
@ -118,13 +119,9 @@ pub struct Block {
|
||||
}
|
||||
|
||||
impl Vox for Block {
|
||||
fn empty() -> Self {
|
||||
Block::empty()
|
||||
}
|
||||
fn empty() -> Self { Block::empty() }
|
||||
|
||||
fn is_empty(&self) -> bool {
|
||||
self.is_air() && self.get_sprite().is_none()
|
||||
}
|
||||
fn is_empty(&self) -> bool { self.is_air() && self.get_sprite().is_none() }
|
||||
}
|
||||
|
||||
impl Deref for Block {
|
||||
@ -431,10 +428,7 @@ impl Block {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_mountable(&self) -> bool {
|
||||
self.get_sprite()
|
||||
.map_or(false, |s| s.is_mountable())
|
||||
}
|
||||
pub fn is_mountable(&self) -> bool { self.get_sprite().map_or(false, |s| s.is_mountable()) }
|
||||
|
||||
#[inline]
|
||||
pub fn is_bonkable(&self) -> bool {
|
||||
|
@ -484,29 +484,38 @@ impl SpriteKind {
|
||||
z: 0.0,
|
||||
};
|
||||
match self {
|
||||
SpriteKind::ChairSingle => &[(Vec3 {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: 0.5,
|
||||
}, UNIT_Y)],
|
||||
SpriteKind::ChairDouble => &[(Vec3 {
|
||||
x: -0.5,
|
||||
y: 0.0,
|
||||
z: 0.6,
|
||||
}, UNIT_Y),
|
||||
(Vec3 {
|
||||
x: 0.5,
|
||||
y: -0.1,
|
||||
z: 0.6,
|
||||
}, UNIT_Y)],
|
||||
SpriteKind::ChairSingle => &[(
|
||||
Vec3 {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: 0.5,
|
||||
},
|
||||
UNIT_Y,
|
||||
)],
|
||||
SpriteKind::ChairDouble => &[
|
||||
(
|
||||
Vec3 {
|
||||
x: -0.5,
|
||||
y: 0.0,
|
||||
z: 0.6,
|
||||
},
|
||||
UNIT_Y,
|
||||
),
|
||||
(
|
||||
Vec3 {
|
||||
x: 0.5,
|
||||
y: -0.1,
|
||||
z: 0.6,
|
||||
},
|
||||
UNIT_Y,
|
||||
),
|
||||
],
|
||||
_ => &[],
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_mountable(&self) -> bool {
|
||||
!self.mount_offsets().is_empty()
|
||||
}
|
||||
pub fn is_mountable(&self) -> bool { !self.mount_offsets().is_empty() }
|
||||
|
||||
/// Which tool (if any) is needed to collect this sprite?
|
||||
#[inline]
|
||||
|
@ -46,9 +46,7 @@ make_case_elim!(
|
||||
);
|
||||
|
||||
impl Default for StructureBlock {
|
||||
fn default() -> Self {
|
||||
StructureBlock::None
|
||||
}
|
||||
fn default() -> Self { StructureBlock::None }
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -86,7 +84,9 @@ impl assets::Compound for StructuresGroup {
|
||||
.0
|
||||
.iter()
|
||||
.map(|sp| {
|
||||
let base = cache.load::<Arc<BaseStructure<StructureBlock>>>(&sp.specifier)?.cloned();
|
||||
let base = cache
|
||||
.load::<Arc<BaseStructure<StructureBlock>>>(&sp.specifier)?
|
||||
.cloned();
|
||||
Ok(Structure {
|
||||
center: Vec3::from(sp.center),
|
||||
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());
|
||||
if let Some(model) = dot_vox_data.models.get(0) {
|
||||
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 = &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,
|
||||
scene::camera::{self, Camera},
|
||||
session::{
|
||||
interactable::{BlockInteraction, Interactable},
|
||||
settings_change::{
|
||||
Audio, Chat as ChatChange, Interface as InterfaceChange, SettingsChange,
|
||||
}, interactable::{Interactable, BlockInteraction},
|
||||
},
|
||||
},
|
||||
settings::chat::ChatFilter,
|
||||
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 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)
|
||||
.map(|vox| *vox)
|
||||
.unwrap_or_else(|_| Block::empty())
|
||||
|
@ -147,7 +147,12 @@ pub struct 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_arr = mat.into_col_arrays();
|
||||
|
@ -8,8 +8,9 @@ use crate::{
|
||||
segment::{generate_mesh_base_vol_figure, generate_mesh_base_vol_terrain},
|
||||
},
|
||||
render::{
|
||||
pipelines::terrain::{BoundLocals as BoundTerrainLocals, Locals as TerrainLocals}, BoneMeshes, ColLightInfo,
|
||||
FigureModel, Instances, Mesh, Renderer, SpriteInstance, TerrainVertex,
|
||||
pipelines::terrain::{BoundLocals as BoundTerrainLocals, Locals as TerrainLocals},
|
||||
BoneMeshes, ColLightInfo, FigureModel, Instances, Mesh, Renderer, SpriteInstance,
|
||||
TerrainVertex,
|
||||
},
|
||||
scene::{
|
||||
camera::CameraMode,
|
||||
@ -36,7 +37,7 @@ use core::{hash::Hash, ops::Range};
|
||||
use crossbeam_utils::atomic;
|
||||
use hashbrown::{hash_map::Entry, HashMap};
|
||||
use serde::Deserialize;
|
||||
use std::{sync::Arc, array::from_fn};
|
||||
use std::{array::from_fn, sync::Arc};
|
||||
use vek::*;
|
||||
|
||||
/// A type produced by mesh worker threads corresponding to the information
|
||||
@ -321,16 +322,20 @@ where
|
||||
/// the model, we don't return skeleton data.
|
||||
pub fn get_model<'b>(
|
||||
&'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,
|
||||
body: Skel::Body,
|
||||
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,
|
||||
camera_mode: CameraMode,
|
||||
character_state: Option<&CharacterState>,
|
||||
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).
|
||||
let key = FigureKey {
|
||||
body,
|
||||
@ -851,10 +856,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_blocks_of_interest<'c>(
|
||||
&'c self,
|
||||
body: Skel::Body,
|
||||
) -> Option<&'c BlocksOfInterest> {
|
||||
pub fn get_blocks_of_interest(&self, body: Skel::Body) -> Option<&BlocksOfInterest> {
|
||||
let key = FigureKey {
|
||||
body,
|
||||
item_key: None,
|
||||
@ -869,12 +871,12 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_sprites<'c>(
|
||||
&'c self,
|
||||
pub fn get_sprites(
|
||||
&self,
|
||||
body: Skel::Body,
|
||||
) -> Option<(
|
||||
&'c BoundTerrainLocals,
|
||||
&'c [Instances<SpriteInstance>; SPRITE_LOD_LEVELS],
|
||||
&BoundTerrainLocals,
|
||||
&[Instances<SpriteInstance>; SPRITE_LOD_LEVELS],
|
||||
)> {
|
||||
let key = FigureKey {
|
||||
body,
|
||||
@ -909,7 +911,12 @@ where
|
||||
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::{
|
||||
assets::{self, AssetExt, AssetHandle, DotVoxAsset, ReloadWatcher, Ron},
|
||||
comp::{
|
||||
@ -24,7 +26,9 @@ use common::{
|
||||
theropod::{self, BodyType as TBodyType, Species as TSpecies},
|
||||
},
|
||||
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 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,
|
||||
None => {
|
||||
error!("No specification exists for {:?}", obj);
|
||||
|
||||
|
||||
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 {
|
||||
type BoneMesh = ShipBoneMeshes;
|
||||
type Extra = ();
|
||||
type Manifests = AssetHandle<Self::Spec>;
|
||||
type Spec = ShipSpec;
|
||||
type BoneMesh = ShipBoneMeshes;
|
||||
type ModelEntryFuture<const N: usize> = TerrainModelEntryFuture<N>;
|
||||
type Spec = ShipSpec;
|
||||
|
||||
fn load_spec() -> Result<Self::Manifests, assets::Error> { Self::Spec::load("") }
|
||||
|
||||
|
@ -14,9 +14,9 @@ use crate::{
|
||||
terrain::{BoundLocals as BoundTerrainLocals, Locals as TerrainLocals},
|
||||
trail, ColLights,
|
||||
},
|
||||
ColLightInfo, FigureBoneData, FigureDrawer, FigureLocals, FigureModel, FigureShadowDrawer,
|
||||
Instances, Mesh, Quad, RenderError, Renderer, SpriteDrawer, SpriteInstance, SubModel,
|
||||
TerrainVertex, CullingMode, AltIndices,
|
||||
AltIndices, ColLightInfo, CullingMode, FigureBoneData, FigureDrawer, FigureLocals,
|
||||
FigureModel, FigureShadowDrawer, Instances, Mesh, Quad, RenderError, Renderer,
|
||||
SpriteDrawer, SpriteInstance, SubModel, TerrainVertex,
|
||||
},
|
||||
scene::{
|
||||
camera::{Camera, CameraMode, Dependents},
|
||||
@ -6312,7 +6312,7 @@ impl FigureMgr {
|
||||
&'a self,
|
||||
drawer: &mut SpriteDrawer<'_, 'a>,
|
||||
state: &State,
|
||||
focus_pos: Vec3<f32>,
|
||||
cam_pos: Vec3<f32>,
|
||||
sprite_render_distance: f32,
|
||||
) {
|
||||
span!(_guard, "render", "FigureManager::render_sprites");
|
||||
@ -6322,28 +6322,48 @@ impl FigureMgr {
|
||||
let sprite_hid_detail_distance = sprite_render_distance * 0.35;
|
||||
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.read_storage::<Pos>(),
|
||||
&ecs.read_storage::<Body>(),
|
||||
ecs.read_storage::<Health>().maybe(),
|
||||
ecs.read_storage::<Inventory>().maybe(),
|
||||
ecs.read_storage::<Scale>().maybe(),
|
||||
ecs.read_storage::<Collider>().maybe(),
|
||||
)
|
||||
.join()
|
||||
// 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(
|
||||
entity,
|
||||
body,
|
||||
collider,
|
||||
) {
|
||||
let focus_dist_sqrd = pos.0.distance_squared(focus_pos);
|
||||
if let Some((data, sprite_instances)) =
|
||||
self.get_sprite_instances(entity, body, collider)
|
||||
{
|
||||
let dist_sqrd = cam_pos.distance_squared(pos.0);
|
||||
let radius = collider.map_or(f32::INFINITY, |collider| collider.bounding_radius());
|
||||
|
||||
// TODO NOW: LOD
|
||||
drawer.draw(data, &sprite_instances[0], &AltIndices { deep_end: 0, underground_end: 0 }, CullingMode::None)
|
||||
let dist_sqrd = dist_sqrd - radius * radius;
|
||||
|
||||
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,
|
||||
mut_count: vol.mut_count,
|
||||
};
|
||||
self.volume_model_cache.get_sprites(
|
||||
vk,
|
||||
)
|
||||
self.volume_model_cache.get_sprites(vk)
|
||||
} else {
|
||||
self.ship_model_cache.get_sprites(
|
||||
*body,
|
||||
)
|
||||
self.ship_model_cache.get_sprites(*body)
|
||||
}
|
||||
},
|
||||
_ => None,
|
||||
@ -7157,8 +7173,12 @@ impl FigureColLights {
|
||||
);
|
||||
});
|
||||
|
||||
let terrain_locals =
|
||||
renderer.create_terrain_bound_locals(&[TerrainLocals::new(pos, ori, Vec2::zero(), 0.0)]);
|
||||
let terrain_locals = renderer.create_terrain_bound_locals(&[TerrainLocals::new(
|
||||
pos,
|
||||
ori,
|
||||
Vec2::zero(),
|
||||
0.0,
|
||||
)]);
|
||||
|
||||
let sprite_instances =
|
||||
sprite_instances.map(|instances| renderer.create_instances(&instances));
|
||||
|
@ -1355,7 +1355,7 @@ impl Scene {
|
||||
self.figure_mgr.render_sprites(
|
||||
&mut sprite_drawer,
|
||||
state,
|
||||
focus_pos,
|
||||
cam_pos,
|
||||
scene_data.sprite_render_distance,
|
||||
);
|
||||
self.terrain.render_sprites(
|
||||
|
@ -10,9 +10,10 @@ use crate::{
|
||||
},
|
||||
render::{
|
||||
pipelines::{self, ColLights},
|
||||
AltIndices, ColLightInfo, FirstPassDrawer, FluidVertex, GlobalModel, Instances, LodData, Mesh, Model,
|
||||
RenderError, Renderer, SpriteDrawer, SpriteGlobalsBindGroup, SpriteInstance, SpriteVertex,
|
||||
SpriteVerts, TerrainLocals, TerrainShadowDrawer, TerrainVertex, SPRITE_VERT_PAGE_SIZE, CullingMode,
|
||||
AltIndices, ColLightInfo, CullingMode, FirstPassDrawer, FluidVertex, GlobalModel,
|
||||
Instances, LodData, Mesh, Model, RenderError, Renderer, SpriteDrawer,
|
||||
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 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 variation = seed as usize % cfg.variations.len();
|
||||
@ -360,7 +367,9 @@ fn mesh_worker(
|
||||
let mesh = mesh.as_ref().unwrap();
|
||||
(&*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 {
|
||||
pos,
|
||||
// Extract sprite locations from volume
|
||||
@ -394,7 +403,8 @@ fn mesh_worker(
|
||||
(0..TerrainChunk::RECT_SIZE.x as i32)
|
||||
.flat_map(|x| {
|
||||
(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()?))),
|
||||
@ -1228,11 +1238,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
|
||||
let sprite_instances =
|
||||
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 {
|
||||
|
@ -892,7 +892,8 @@ impl PlayState for SessionState {
|
||||
if let Some(interactable) = &self.interactable {
|
||||
match interactable {
|
||||
Interactable::Block(_, pos, interaction) => {
|
||||
if matches!(interaction, BlockInteraction::Mount(_)) {
|
||||
if matches!(interaction, BlockInteraction::Mount(_))
|
||||
{
|
||||
client.mount_sprite(*pos)
|
||||
}
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user