mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'zesterer/better-char-select-scene' into 'master'
Render render LoD terrain on char select, remove old backdrop figure See merge request veloren/veloren!4254
This commit is contained in:
commit
a852298010
@ -77,6 +77,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Linearize light colors on the CPU rather than in shaders on the GPU
|
- Linearize light colors on the CPU rather than in shaders on the GPU
|
||||||
- You can no longer stack self buffs
|
- You can no longer stack self buffs
|
||||||
- Renamed "Burning Potion" to "Potion of Combustion"
|
- Renamed "Burning Potion" to "Potion of Combustion"
|
||||||
|
- Render LoD terrain on the character selection screen
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
- Medium and large potions from all loot tables
|
- Medium and large potions from all loot tables
|
||||||
|
@ -151,6 +151,10 @@ float ShadowCalculationPoint(uint lightIndex, vec3 fragToLight, vec3 fragNorm, /
|
|||||||
|
|
||||||
float ShadowCalculationDirected(in vec3 fragPos)//in vec4 /*light_pos[2]*/sun_pos, vec3 fragPos)
|
float ShadowCalculationDirected(in vec3 fragPos)//in vec4 /*light_pos[2]*/sun_pos, vec3 fragPos)
|
||||||
{
|
{
|
||||||
|
// Don't try to calculate directed shadows if there are no directed light sources
|
||||||
|
// Applies, for example, in the char select menu
|
||||||
|
if (light_shadow_count.z < 1) { return 1.0; }
|
||||||
|
|
||||||
float bias = 0.000;//0.0005;//-0.0001;// 0.05 / (2.0 * view_distance.x);
|
float bias = 0.000;//0.0005;//-0.0001;// 0.05 / (2.0 * view_distance.x);
|
||||||
float diskRadius = 0.01;
|
float diskRadius = 0.01;
|
||||||
const vec3 sampleOffsetDirections[20] = vec3[]
|
const vec3 sampleOffsetDirections[20] = vec3[]
|
||||||
|
BIN
assets/voxygen/voxel/fixture/selection_bg.vox
(Stored with Git LFS)
BIN
assets/voxygen/voxel/fixture/selection_bg.vox
(Stored with Git LFS)
Binary file not shown.
@ -245,6 +245,7 @@ pub struct Client {
|
|||||||
available_recipes: HashMap<String, Option<SpriteKind>>,
|
available_recipes: HashMap<String, Option<SpriteKind>>,
|
||||||
lod_zones: HashMap<Vec2<i32>, lod::Zone>,
|
lod_zones: HashMap<Vec2<i32>, lod::Zone>,
|
||||||
lod_last_requested: Option<Instant>,
|
lod_last_requested: Option<Instant>,
|
||||||
|
lod_pos_fallback: Option<Vec2<f32>>,
|
||||||
force_update_counter: u64,
|
force_update_counter: u64,
|
||||||
|
|
||||||
max_group_size: u32,
|
max_group_size: u32,
|
||||||
@ -760,6 +761,7 @@ impl Client {
|
|||||||
|
|
||||||
lod_zones: HashMap::new(),
|
lod_zones: HashMap::new(),
|
||||||
lod_last_requested: None,
|
lod_last_requested: None,
|
||||||
|
lod_pos_fallback: None,
|
||||||
|
|
||||||
force_update_counter: 0,
|
force_update_counter: 0,
|
||||||
|
|
||||||
@ -901,7 +903,7 @@ impl Client {
|
|||||||
| ClientGeneral::DeleteCharacter(_)
|
| ClientGeneral::DeleteCharacter(_)
|
||||||
| ClientGeneral::Character(_, _)
|
| ClientGeneral::Character(_, _)
|
||||||
| ClientGeneral::Spectate(_) => &mut self.character_screen_stream,
|
| ClientGeneral::Spectate(_) => &mut self.character_screen_stream,
|
||||||
//Only in game
|
// Only in game
|
||||||
ClientGeneral::ControllerInputs(_)
|
ClientGeneral::ControllerInputs(_)
|
||||||
| ClientGeneral::ControlEvent(_)
|
| ClientGeneral::ControlEvent(_)
|
||||||
| ClientGeneral::ControlAction(_)
|
| ClientGeneral::ControlAction(_)
|
||||||
@ -922,7 +924,7 @@ impl Client {
|
|||||||
}
|
}
|
||||||
&mut self.in_game_stream
|
&mut self.in_game_stream
|
||||||
},
|
},
|
||||||
//Only in game, terrain
|
// Terrain
|
||||||
ClientGeneral::TerrainChunkRequest { .. }
|
ClientGeneral::TerrainChunkRequest { .. }
|
||||||
| ClientGeneral::LodZoneRequest { .. } => {
|
| ClientGeneral::LodZoneRequest { .. } => {
|
||||||
#[cfg(feature = "tracy")]
|
#[cfg(feature = "tracy")]
|
||||||
@ -931,7 +933,7 @@ impl Client {
|
|||||||
}
|
}
|
||||||
&mut self.terrain_stream
|
&mut self.terrain_stream
|
||||||
},
|
},
|
||||||
//Always possible
|
// Always possible
|
||||||
ClientGeneral::ChatMsg(_)
|
ClientGeneral::ChatMsg(_)
|
||||||
| ClientGeneral::Command(_, _)
|
| ClientGeneral::Command(_, _)
|
||||||
| ClientGeneral::Terminate => &mut self.general_stream,
|
| ClientGeneral::Terminate => &mut self.general_stream,
|
||||||
@ -1209,6 +1211,10 @@ impl Client {
|
|||||||
|
|
||||||
pub fn lod_zones(&self) -> &HashMap<Vec2<i32>, lod::Zone> { &self.lod_zones }
|
pub fn lod_zones(&self) -> &HashMap<Vec2<i32>, lod::Zone> { &self.lod_zones }
|
||||||
|
|
||||||
|
/// Set the fallback position used for loading LoD zones when the client
|
||||||
|
/// entity does not have a position.
|
||||||
|
pub fn set_lod_pos_fallback(&mut self, pos: Vec2<f32>) { self.lod_pos_fallback = Some(pos); }
|
||||||
|
|
||||||
/// Returns whether the specified recipe can be crafted and the sprite, if
|
/// Returns whether the specified recipe can be crafted and the sprite, if
|
||||||
/// any, that is required to do so.
|
/// any, that is required to do so.
|
||||||
pub fn can_craft_recipe(&self, recipe: &str, amount: u32) -> (bool, Option<SpriteKind>) {
|
pub fn can_craft_recipe(&self, recipe: &str, amount: u32) -> (bool, Option<SpriteKind>) {
|
||||||
@ -2101,9 +2107,11 @@ impl Client {
|
|||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
self.pending_chunks
|
self.pending_chunks
|
||||||
.retain(|_, created| now.duration_since(*created) < Duration::from_secs(3));
|
.retain(|_, created| now.duration_since(*created) < Duration::from_secs(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(lod_pos) = pos.map(|p| p.0.xy()).or(self.lod_pos_fallback) {
|
||||||
// Manage LoD zones
|
// Manage LoD zones
|
||||||
let lod_zone = pos.0.xy().map(|e| lod::from_wpos(e as i32));
|
let lod_zone = lod_pos.map(|e| lod::from_wpos(e as i32));
|
||||||
|
|
||||||
// Request LoD zones that are in range
|
// Request LoD zones that are in range
|
||||||
if self
|
if self
|
||||||
|
@ -129,7 +129,6 @@ impl ClientMsg {
|
|||||||
| ClientGeneral::ExitInGame
|
| ClientGeneral::ExitInGame
|
||||||
| ClientGeneral::PlayerPhysics { .. }
|
| ClientGeneral::PlayerPhysics { .. }
|
||||||
| ClientGeneral::TerrainChunkRequest { .. }
|
| ClientGeneral::TerrainChunkRequest { .. }
|
||||||
| ClientGeneral::LodZoneRequest { .. }
|
|
||||||
| ClientGeneral::UnlockSkill(_)
|
| ClientGeneral::UnlockSkill(_)
|
||||||
| ClientGeneral::RequestSiteInfo(_)
|
| ClientGeneral::RequestSiteInfo(_)
|
||||||
| ClientGeneral::RequestPlayerPhysics { .. }
|
| ClientGeneral::RequestPlayerPhysics { .. }
|
||||||
@ -141,7 +140,9 @@ impl ClientMsg {
|
|||||||
//Always possible
|
//Always possible
|
||||||
ClientGeneral::ChatMsg(_)
|
ClientGeneral::ChatMsg(_)
|
||||||
| ClientGeneral::Command(_, _)
|
| ClientGeneral::Command(_, _)
|
||||||
| ClientGeneral::Terminate => true,
|
| ClientGeneral::Terminate
|
||||||
|
// LodZoneRequest is required by the char select screen
|
||||||
|
| ClientGeneral::LodZoneRequest { .. } => true,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ClientMsg::Ping(_) => true,
|
ClientMsg::Ping(_) => true,
|
||||||
|
@ -330,7 +330,6 @@ impl ServerMsg {
|
|||||||
| ServerGeneral::InventoryUpdate(_, _)
|
| ServerGeneral::InventoryUpdate(_, _)
|
||||||
| ServerGeneral::GroupInventoryUpdate(_, _, _)
|
| ServerGeneral::GroupInventoryUpdate(_, _, _)
|
||||||
| ServerGeneral::TerrainChunkUpdate { .. }
|
| ServerGeneral::TerrainChunkUpdate { .. }
|
||||||
| ServerGeneral::LodZoneUpdate { .. }
|
|
||||||
| ServerGeneral::TerrainBlockUpdates(_)
|
| ServerGeneral::TerrainBlockUpdates(_)
|
||||||
| ServerGeneral::SetViewDistance(_)
|
| ServerGeneral::SetViewDistance(_)
|
||||||
| ServerGeneral::Outcomes(_)
|
| ServerGeneral::Outcomes(_)
|
||||||
@ -354,7 +353,8 @@ impl ServerMsg {
|
|||||||
| ServerGeneral::CreateEntity(_)
|
| ServerGeneral::CreateEntity(_)
|
||||||
| ServerGeneral::DeleteEntity(_)
|
| ServerGeneral::DeleteEntity(_)
|
||||||
| ServerGeneral::Disconnect(_)
|
| ServerGeneral::Disconnect(_)
|
||||||
| ServerGeneral::Notification(_) => true,
|
| ServerGeneral::Notification(_)
|
||||||
|
| ServerGeneral::LodZoneUpdate { .. } => true,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ServerMsg::Ping(_) => true,
|
ServerMsg::Ping(_) => true,
|
||||||
|
@ -195,7 +195,7 @@ impl Client {
|
|||||||
| ServerGeneral::SpectatePosition(_) => {
|
| ServerGeneral::SpectatePosition(_) => {
|
||||||
PreparedMsg::new(2, &g, &self.in_game_stream_params)
|
PreparedMsg::new(2, &g, &self.in_game_stream_params)
|
||||||
},
|
},
|
||||||
//In-game related, terrain
|
// Terrain
|
||||||
ServerGeneral::TerrainChunkUpdate { .. }
|
ServerGeneral::TerrainChunkUpdate { .. }
|
||||||
| ServerGeneral::LodZoneUpdate { .. }
|
| ServerGeneral::LodZoneUpdate { .. }
|
||||||
| ServerGeneral::TerrainBlockUpdates(_) => {
|
| ServerGeneral::TerrainBlockUpdates(_) => {
|
||||||
|
@ -61,61 +61,63 @@ impl<'a> System<'a> for Sys {
|
|||||||
|(chunk_send_emitter, server_emitter), (entity, client, maybe_presence)| {
|
|(chunk_send_emitter, server_emitter), (entity, client, maybe_presence)| {
|
||||||
let mut chunk_requests = Vec::new();
|
let mut chunk_requests = Vec::new();
|
||||||
let _ = super::try_recv_all(client, 5, |client, msg| {
|
let _ = super::try_recv_all(client, 5, |client, msg| {
|
||||||
let presence = match maybe_presence {
|
// SPECIAL CASE: LOD zone requests can be sent by non-present players
|
||||||
Some(g) => g,
|
if let ClientGeneral::LodZoneRequest { key } = &msg {
|
||||||
None => {
|
client.send(ServerGeneral::LodZoneUpdate {
|
||||||
debug!(?entity, "client is not in_game, ignoring msg");
|
key: *key,
|
||||||
trace!(?msg, "ignored msg content");
|
zone: lod.zone(*key).clone(),
|
||||||
if matches!(msg, ClientGeneral::TerrainChunkRequest { .. }) {
|
})?;
|
||||||
network_metrics.chunks_request_dropped.inc();
|
} else {
|
||||||
}
|
let presence = match maybe_presence {
|
||||||
return Ok(());
|
Some(g) => g,
|
||||||
},
|
None => {
|
||||||
};
|
debug!(?entity, "client is not in_game, ignoring msg");
|
||||||
match msg {
|
trace!(?msg, "ignored msg content");
|
||||||
ClientGeneral::TerrainChunkRequest { key } => {
|
if matches!(msg, ClientGeneral::TerrainChunkRequest { .. }) {
|
||||||
let in_vd = if let Some(pos) = positions.get(entity) {
|
network_metrics.chunks_request_dropped.inc();
|
||||||
pos.0.xy().map(|e| e as f64).distance_squared(
|
|
||||||
key.map(|e| e as f64 + 0.5)
|
|
||||||
* TerrainChunkSize::RECT_SIZE.map(|e| e as f64),
|
|
||||||
) < ((presence.terrain_view_distance.current() as f64 - 1.0
|
|
||||||
+ 2.5 * 2.0_f64.sqrt())
|
|
||||||
* TerrainChunkSize::RECT_SIZE.x as f64)
|
|
||||||
.powi(2)
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
};
|
|
||||||
if in_vd {
|
|
||||||
if terrain.get_key_arc(key).is_some() {
|
|
||||||
network_metrics.chunks_served_from_memory.inc();
|
|
||||||
chunk_send_emitter.emit(ChunkSendEntry {
|
|
||||||
chunk_key: key,
|
|
||||||
entity,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
network_metrics.chunks_generation_triggered.inc();
|
|
||||||
chunk_requests.push(ChunkRequest { entity, key });
|
|
||||||
}
|
}
|
||||||
} else {
|
return Ok(());
|
||||||
network_metrics.chunks_request_dropped.inc();
|
},
|
||||||
}
|
};
|
||||||
},
|
match msg {
|
||||||
ClientGeneral::LodZoneRequest { key } => {
|
ClientGeneral::TerrainChunkRequest { key } => {
|
||||||
client.send(ServerGeneral::LodZoneUpdate {
|
let in_vd = if let Some(pos) = positions.get(entity) {
|
||||||
key,
|
pos.0.xy().map(|e| e as f64).distance_squared(
|
||||||
zone: lod.zone(key).clone(),
|
key.map(|e| e as f64 + 0.5)
|
||||||
})?;
|
* TerrainChunkSize::RECT_SIZE.map(|e| e as f64),
|
||||||
},
|
) < ((presence.terrain_view_distance.current() as f64 - 1.0
|
||||||
_ => {
|
+ 2.5 * 2.0_f64.sqrt())
|
||||||
debug!(
|
* TerrainChunkSize::RECT_SIZE.x as f64)
|
||||||
"Kicking possibly misbehaving client due to invalud terrain \
|
.powi(2)
|
||||||
request"
|
} else {
|
||||||
);
|
true
|
||||||
server_emitter.emit(ServerEvent::ClientDisconnect(
|
};
|
||||||
entity,
|
if in_vd {
|
||||||
common::comp::DisconnectReason::NetworkError,
|
if terrain.get_key_arc(key).is_some() {
|
||||||
));
|
network_metrics.chunks_served_from_memory.inc();
|
||||||
},
|
chunk_send_emitter.emit(ChunkSendEntry {
|
||||||
|
chunk_key: key,
|
||||||
|
entity,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
network_metrics.chunks_generation_triggered.inc();
|
||||||
|
chunk_requests.push(ChunkRequest { entity, key });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
network_metrics.chunks_request_dropped.inc();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
debug!(
|
||||||
|
"Kicking possibly misbehaving client due to invalud terrain \
|
||||||
|
request"
|
||||||
|
);
|
||||||
|
server_emitter.emit(ServerEvent::ClientDisconnect(
|
||||||
|
entity,
|
||||||
|
common::comp::DisconnectReason::NetworkError,
|
||||||
|
));
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
|
@ -16,7 +16,8 @@
|
|||||||
let_chains,
|
let_chains,
|
||||||
generic_const_exprs,
|
generic_const_exprs,
|
||||||
maybe_uninit_uninit_array,
|
maybe_uninit_uninit_array,
|
||||||
maybe_uninit_array_assume_init
|
maybe_uninit_array_assume_init,
|
||||||
|
closure_lifetime_binder
|
||||||
)]
|
)]
|
||||||
#![recursion_limit = "2048"]
|
#![recursion_limit = "2048"]
|
||||||
|
|
||||||
|
@ -26,10 +26,12 @@ pub struct CharSelectionState {
|
|||||||
impl CharSelectionState {
|
impl CharSelectionState {
|
||||||
/// Create a new `CharSelectionState`.
|
/// Create a new `CharSelectionState`.
|
||||||
pub fn new(global_state: &mut GlobalState, client: Rc<RefCell<Client>>) -> Self {
|
pub fn new(global_state: &mut GlobalState, client: Rc<RefCell<Client>>) -> Self {
|
||||||
|
let sprite_render_context = (global_state.lazy_init)(global_state.window.renderer_mut());
|
||||||
let scene = Scene::new(
|
let scene = Scene::new(
|
||||||
global_state.window.renderer_mut(),
|
global_state.window.renderer_mut(),
|
||||||
Some("fixture.selection_bg"),
|
&mut client.borrow_mut(),
|
||||||
&client.borrow(),
|
&global_state.settings,
|
||||||
|
sprite_render_context,
|
||||||
);
|
);
|
||||||
let char_selection_ui = CharSelectionUi::new(global_state, &client.borrow());
|
let char_selection_ui = CharSelectionUi::new(global_state, &client.borrow());
|
||||||
|
|
||||||
@ -224,8 +226,12 @@ impl PlayState for CharSelectionState {
|
|||||||
as f32,
|
as f32,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.scene
|
self.scene.maintain(
|
||||||
.maintain(global_state.window.renderer_mut(), scene_data, loadout);
|
global_state.window.renderer_mut(),
|
||||||
|
scene_data,
|
||||||
|
loadout,
|
||||||
|
&client,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tick the client (currently only to keep the connection alive).
|
// Tick the client (currently only to keep the connection alive).
|
||||||
|
@ -1570,9 +1570,10 @@ pub struct AltIndices {
|
|||||||
|
|
||||||
/// The mode with which culling based on the camera position relative to the
|
/// The mode with which culling based on the camera position relative to the
|
||||||
/// terrain is performed.
|
/// terrain is performed.
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, Default)]
|
||||||
pub enum CullingMode {
|
pub enum CullingMode {
|
||||||
/// We need to render all elements of the given structure
|
/// We need to render all elements of the given structure
|
||||||
|
#[default]
|
||||||
None,
|
None,
|
||||||
/// We only need to render surface and shallow (i.e: in the overlapping
|
/// We only need to render surface and shallow (i.e: in the overlapping
|
||||||
/// region) elements of the structure
|
/// region) elements of the structure
|
||||||
|
@ -677,6 +677,9 @@ impl Camera {
|
|||||||
/// Get the orientation of the camera.
|
/// Get the orientation of the camera.
|
||||||
pub fn get_orientation(&self) -> Vec3<f32> { self.ori }
|
pub fn get_orientation(&self) -> Vec3<f32> { self.ori }
|
||||||
|
|
||||||
|
/// Get the orientation that the camera is moving toward.
|
||||||
|
pub fn get_tgt_orientation(&self) -> Vec3<f32> { self.tgt_ori }
|
||||||
|
|
||||||
/// Get the field of view of the camera in radians, taking into account
|
/// Get the field of view of the camera in radians, taking into account
|
||||||
/// fixation.
|
/// fixation.
|
||||||
pub fn get_effective_fov(&self) -> f32 { self.fov * self.fixate }
|
pub fn get_effective_fov(&self) -> f32 { self.fov * self.fixate }
|
||||||
|
@ -13,8 +13,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
scene::{
|
scene::{
|
||||||
camera::CameraMode,
|
camera::CameraMode,
|
||||||
terrain::{get_sprite_instances, BlocksOfInterest, SPRITE_LOD_LEVELS},
|
terrain::{get_sprite_instances, BlocksOfInterest, SpriteRenderState, SPRITE_LOD_LEVELS},
|
||||||
Terrain,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use anim::Skeleton;
|
use anim::Skeleton;
|
||||||
@ -632,7 +631,7 @@ where
|
|||||||
extra: <Skel::Body as BodySpec>::Extra,
|
extra: <Skel::Body as BodySpec>::Extra,
|
||||||
tick: u64,
|
tick: u64,
|
||||||
slow_jobs: &SlowJobPool,
|
slow_jobs: &SlowJobPool,
|
||||||
terrain: &Terrain,
|
sprite_render_state: &SpriteRenderState,
|
||||||
) -> (TerrainModelEntryLod<'c>, &'c Skel::Attr)
|
) -> (TerrainModelEntryLod<'c>, &'c Skel::Attr)
|
||||||
where
|
where
|
||||||
for<'a> &'a Skel::Body: Into<Skel::Attr>,
|
for<'a> &'a Skel::Body: Into<Skel::Attr>,
|
||||||
@ -695,8 +694,8 @@ where
|
|||||||
let key = v.key().clone();
|
let key = v.key().clone();
|
||||||
let slot = Arc::new(atomic::AtomicCell::new(None));
|
let slot = Arc::new(atomic::AtomicCell::new(None));
|
||||||
let manifests = self.manifests.clone();
|
let manifests = self.manifests.clone();
|
||||||
let sprite_data = Arc::clone(&terrain.sprite_data);
|
let sprite_data = Arc::clone(&sprite_render_state.sprite_data);
|
||||||
let sprite_config = Arc::clone(&terrain.sprite_config);
|
let sprite_config = Arc::clone(&sprite_render_state.sprite_config);
|
||||||
let slot_ = Arc::clone(&slot);
|
let slot_ = Arc::clone(&slot);
|
||||||
|
|
||||||
slow_jobs.spawn("FIGURE_MESHING", move || {
|
slow_jobs.spawn("FIGURE_MESHING", move || {
|
||||||
|
@ -6288,7 +6288,7 @@ impl FigureMgr {
|
|||||||
Arc::clone(vol),
|
Arc::clone(vol),
|
||||||
tick,
|
tick,
|
||||||
&slow_jobs,
|
&slow_jobs,
|
||||||
terrain,
|
&terrain.sprite_render_state,
|
||||||
);
|
);
|
||||||
|
|
||||||
let state = self
|
let state = self
|
||||||
@ -6315,7 +6315,7 @@ impl FigureMgr {
|
|||||||
(),
|
(),
|
||||||
tick,
|
tick,
|
||||||
&slow_jobs,
|
&slow_jobs,
|
||||||
terrain,
|
&terrain.sprite_render_state,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
// No way to determine model (this is okay, we might just not have received
|
// No way to determine model (this is okay, we might just not have received
|
||||||
@ -7535,7 +7535,7 @@ impl FigureStateMeta {
|
|||||||
pub struct FigureState<S, D = ()> {
|
pub struct FigureState<S, D = ()> {
|
||||||
meta: FigureStateMeta,
|
meta: FigureStateMeta,
|
||||||
skeleton: S,
|
skeleton: S,
|
||||||
extra: D,
|
pub extra: D,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, D> Deref for FigureState<S, D> {
|
impl<S, D> Deref for FigureState<S, D> {
|
||||||
|
@ -1430,7 +1430,7 @@ impl Scene {
|
|||||||
// Draws sprites
|
// Draws sprites
|
||||||
let mut sprite_drawer = first_pass.draw_sprites(
|
let mut sprite_drawer = first_pass.draw_sprites(
|
||||||
&self.terrain.sprite_globals,
|
&self.terrain.sprite_globals,
|
||||||
&self.terrain.sprite_atlas_textures,
|
&self.terrain.sprite_render_state.sprite_atlas_textures,
|
||||||
);
|
);
|
||||||
self.figure_mgr.render_sprites(
|
self.figure_mgr.render_sprites(
|
||||||
&mut sprite_drawer,
|
&mut sprite_drawer,
|
||||||
|
@ -1,35 +1,30 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
mesh::{greedy::GreedyMesh, segment::generate_mesh_base_vol_figure},
|
|
||||||
render::{
|
render::{
|
||||||
create_skybox_mesh, pipelines::FigureSpriteAtlasData, BoneMeshes, Consts, FigureModel,
|
create_skybox_mesh, pipelines::terrain::BoundLocals as BoundTerrainLocals, AltIndices,
|
||||||
FirstPassDrawer, GlobalModel, Globals, GlobalsBindGroup, Light, LodData, Mesh, Model,
|
Consts, FirstPassDrawer, GlobalModel, Globals, GlobalsBindGroup, Light, Model,
|
||||||
PointLightMatrix, RainOcclusionLocals, Renderer, Shadow, ShadowLocals, SkyboxVertex,
|
PointLightMatrix, RainOcclusionLocals, Renderer, Shadow, ShadowLocals, SkyboxVertex,
|
||||||
TerrainVertex,
|
SpriteGlobalsBindGroup,
|
||||||
},
|
},
|
||||||
scene::{
|
scene::{
|
||||||
camera::{self, Camera, CameraMode},
|
camera::{self, Camera, CameraMode},
|
||||||
figure::{
|
figure::{FigureAtlas, FigureModelCache, FigureState, FigureUpdateCommonParameters},
|
||||||
load_mesh, FigureAtlas, FigureModelCache, FigureModelEntry, FigureState,
|
terrain::{SpriteRenderContext, SpriteRenderState},
|
||||||
FigureUpdateCommonParameters,
|
CloudsLocals, CullingMode, Lod, PostProcessLocals,
|
||||||
},
|
|
||||||
},
|
},
|
||||||
window::{Event, PressState},
|
window::{Event, PressState},
|
||||||
|
Settings,
|
||||||
};
|
};
|
||||||
use anim::{
|
use anim::{character::CharacterSkeleton, ship::ShipSkeleton, Animation};
|
||||||
character::{CharacterSkeleton, IdleAnimation, SkeletonAttr},
|
|
||||||
fixture::FixtureSkeleton,
|
|
||||||
Animation,
|
|
||||||
};
|
|
||||||
use client::Client;
|
use client::Client;
|
||||||
use common::{
|
use common::{
|
||||||
comp::{
|
comp::{
|
||||||
humanoid,
|
humanoid,
|
||||||
inventory::{slot::EquipSlot, Inventory},
|
inventory::{slot::EquipSlot, Inventory},
|
||||||
item::ItemKind,
|
item::ItemKind,
|
||||||
|
ship,
|
||||||
},
|
},
|
||||||
figure::Segment,
|
|
||||||
slowjob::SlowJobPool,
|
slowjob::SlowJobPool,
|
||||||
terrain::BlockKind,
|
terrain::{BlockKind, CoordinateConversions},
|
||||||
vol::{BaseVol, ReadVol},
|
vol::{BaseVol, ReadVol},
|
||||||
};
|
};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
@ -46,18 +41,6 @@ impl ReadVol for VoidVol {
|
|||||||
fn get(&self, _pos: Vec3<i32>) -> Result<&'_ Self::Vox, Self::Error> { Ok(&()) }
|
fn get(&self, _pos: Vec3<i32>) -> Result<&'_ Self::Vox, Self::Error> { Ok(&()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_mesh(
|
|
||||||
greedy: &mut GreedyMesh<'_, FigureSpriteAtlasData>,
|
|
||||||
mesh: &mut Mesh<TerrainVertex>,
|
|
||||||
segment: Segment,
|
|
||||||
offset: Vec3<f32>,
|
|
||||||
bone_idx: u8,
|
|
||||||
) -> BoneMeshes {
|
|
||||||
let (opaque, _, /* shadow */ _, bounds) =
|
|
||||||
generate_mesh_base_vol_figure(segment, (greedy, mesh, offset, Vec3::one(), bone_idx));
|
|
||||||
(opaque /* , shadow */, bounds)
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Skybox {
|
struct Skybox {
|
||||||
model: Model<SkyboxVertex>,
|
model: Model<SkyboxVertex>,
|
||||||
}
|
}
|
||||||
@ -68,17 +51,22 @@ pub struct Scene {
|
|||||||
camera: Camera,
|
camera: Camera,
|
||||||
|
|
||||||
skybox: Skybox,
|
skybox: Skybox,
|
||||||
lod: LodData,
|
lod: Lod,
|
||||||
map_bounds: Vec2<f32>,
|
map_bounds: Vec2<f32>,
|
||||||
|
|
||||||
figure_atlas: FigureAtlas,
|
figure_atlas: FigureAtlas,
|
||||||
backdrop: Option<(FigureModelEntry<1>, FigureState<FixtureSkeleton>)>,
|
sprite_render_state: SpriteRenderState,
|
||||||
figure_model_cache: FigureModelCache,
|
sprite_globals: SpriteGlobalsBindGroup,
|
||||||
figure_state: Option<FigureState<CharacterSkeleton>>,
|
|
||||||
|
|
||||||
//turning_camera: bool,
|
turning_camera: bool,
|
||||||
turning_character: bool,
|
|
||||||
char_ori: f32,
|
char_pos: Vec3<f32>,
|
||||||
|
char_state: Option<FigureState<CharacterSkeleton>>,
|
||||||
|
char_model_cache: FigureModelCache<CharacterSkeleton>,
|
||||||
|
|
||||||
|
airship_pos: Vec3<f32>,
|
||||||
|
airship_state: Option<FigureState<ShipSkeleton, BoundTerrainLocals>>,
|
||||||
|
airship_model_cache: FigureModelCache<ShipSkeleton>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SceneData<'a> {
|
pub struct SceneData<'a> {
|
||||||
@ -95,8 +83,13 @@ pub struct SceneData<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Scene {
|
impl Scene {
|
||||||
pub fn new(renderer: &mut Renderer, backdrop: Option<&str>, client: &Client) -> Self {
|
pub fn new(
|
||||||
let start_angle = 90.0f32.to_radians();
|
renderer: &mut Renderer,
|
||||||
|
client: &mut Client,
|
||||||
|
settings: &Settings,
|
||||||
|
sprite_render_context: SpriteRenderContext,
|
||||||
|
) -> Self {
|
||||||
|
let start_angle = -90.0f32.to_radians();
|
||||||
let resolution = renderer.resolution().map(|e| e as f32);
|
let resolution = renderer.resolution().map(|e| e as f32);
|
||||||
|
|
||||||
let map_bounds = Vec2::new(
|
let map_bounds = Vec2::new(
|
||||||
@ -105,11 +98,10 @@ impl Scene {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let mut camera = Camera::new(resolution.x / resolution.y, CameraMode::ThirdPerson);
|
let mut camera = Camera::new(resolution.x / resolution.y, CameraMode::ThirdPerson);
|
||||||
camera.set_focus_pos(Vec3::unit_z() * 1.5);
|
|
||||||
camera.set_distance(3.4);
|
camera.set_distance(3.4);
|
||||||
camera.set_orientation(Vec3::new(start_angle, 0.0, 0.0));
|
camera.set_orientation(Vec3::new(start_angle, 0.1, 0.0));
|
||||||
|
|
||||||
let mut figure_atlas = FigureAtlas::new(renderer);
|
let figure_atlas = FigureAtlas::new(renderer);
|
||||||
|
|
||||||
let data = GlobalModel {
|
let data = GlobalModel {
|
||||||
globals: renderer.create_consts(&[Globals::default()]),
|
globals: renderer.create_consts(&[Globals::default()]),
|
||||||
@ -120,81 +112,48 @@ impl Scene {
|
|||||||
.create_rain_occlusion_bound_locals(&[RainOcclusionLocals::default()]),
|
.create_rain_occlusion_bound_locals(&[RainOcclusionLocals::default()]),
|
||||||
point_light_matrices: Box::new([PointLightMatrix::default(); 126]),
|
point_light_matrices: Box::new([PointLightMatrix::default(); 126]),
|
||||||
};
|
};
|
||||||
let lod = LodData::dummy(renderer);
|
let lod = Lod::new(renderer, client, settings);
|
||||||
|
|
||||||
let globals_bind_group = renderer.bind_globals(&data, &lod);
|
let globals_bind_group = renderer.bind_globals(&data, lod.get_data());
|
||||||
|
|
||||||
|
let world = client.world_data();
|
||||||
|
let char_chunk = world.chunk_size().map(|e| e as i32 / 2);
|
||||||
|
let char_pos = char_chunk.cpos_to_wpos().map(|e| e as f32).with_z(
|
||||||
|
world
|
||||||
|
.lod_alt
|
||||||
|
.get(char_chunk)
|
||||||
|
.map_or(0.0, |z| *z as f32 + 48.0),
|
||||||
|
);
|
||||||
|
client.set_lod_pos_fallback(char_pos.xy());
|
||||||
|
client.set_lod_distance(settings.graphics.lod_distance);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
data,
|
|
||||||
globals_bind_group,
|
globals_bind_group,
|
||||||
skybox: Skybox {
|
skybox: Skybox {
|
||||||
model: renderer.create_model(&create_skybox_mesh()).unwrap(),
|
model: renderer.create_model(&create_skybox_mesh()).unwrap(),
|
||||||
},
|
},
|
||||||
lod,
|
|
||||||
map_bounds,
|
map_bounds,
|
||||||
|
|
||||||
figure_model_cache: FigureModelCache::new(),
|
|
||||||
figure_state: None,
|
|
||||||
|
|
||||||
backdrop: backdrop.map(|specifier| {
|
|
||||||
let mut state = FigureState::new(renderer, FixtureSkeleton, ());
|
|
||||||
let mut greedy = FigureModel::make_greedy();
|
|
||||||
let mut opaque_mesh = Mesh::new();
|
|
||||||
let (segment, offset) = load_mesh(specifier, Vec3::new(-55.0, -49.5, -2.0));
|
|
||||||
let (_opaque_mesh, bounds) =
|
|
||||||
generate_mesh(&mut greedy, &mut opaque_mesh, segment, offset, 0);
|
|
||||||
// NOTE: Since MagicaVoxel sizes are limited to 256 × 256 × 256, and there are
|
|
||||||
// at most 3 meshed vertices per unique vertex, we know the
|
|
||||||
// total size is bounded by 2^24 * 3 * 1.5 which is bounded by
|
|
||||||
// 2^27, which fits in a u32.
|
|
||||||
let range = 0..opaque_mesh.vertices().len() as u32;
|
|
||||||
let (atlas_texture_data, atlas_size) = greedy.finalize();
|
|
||||||
let model = figure_atlas.create_figure(
|
|
||||||
renderer,
|
|
||||||
atlas_texture_data,
|
|
||||||
atlas_size,
|
|
||||||
(opaque_mesh, bounds),
|
|
||||||
[range],
|
|
||||||
);
|
|
||||||
let mut buf = [Default::default(); anim::MAX_BONE_COUNT];
|
|
||||||
let common_params = FigureUpdateCommonParameters {
|
|
||||||
entity: None,
|
|
||||||
pos: anim::vek::Vec3::zero(),
|
|
||||||
ori: anim::vek::Quaternion::rotation_from_to_3d(
|
|
||||||
anim::vek::Vec3::unit_y(),
|
|
||||||
anim::vek::Vec3::new(start_angle.sin(), -start_angle.cos(), 0.0),
|
|
||||||
),
|
|
||||||
scale: 1.0,
|
|
||||||
mount_transform_pos: None,
|
|
||||||
body: None,
|
|
||||||
tools: (None, None),
|
|
||||||
col: Rgba::broadcast(1.0),
|
|
||||||
dt: 15.0, // Want to get there immediately.
|
|
||||||
_lpindex: 0,
|
|
||||||
_visible: true,
|
|
||||||
is_player: false,
|
|
||||||
_camera: &camera,
|
|
||||||
terrain: None,
|
|
||||||
ground_vel: Vec3::zero(),
|
|
||||||
};
|
|
||||||
state.update(
|
|
||||||
renderer,
|
|
||||||
None,
|
|
||||||
&mut buf,
|
|
||||||
&common_params,
|
|
||||||
1.0,
|
|
||||||
Some(&model),
|
|
||||||
(),
|
|
||||||
);
|
|
||||||
(model, state)
|
|
||||||
}),
|
|
||||||
figure_atlas,
|
figure_atlas,
|
||||||
|
sprite_render_state: sprite_render_context.state,
|
||||||
|
sprite_globals: renderer.bind_sprite_globals(
|
||||||
|
&data,
|
||||||
|
lod.get_data(),
|
||||||
|
&sprite_render_context.sprite_verts_buffer,
|
||||||
|
),
|
||||||
|
lod,
|
||||||
|
data,
|
||||||
|
|
||||||
camera,
|
camera,
|
||||||
|
|
||||||
//turning_camera: false,
|
turning_camera: false,
|
||||||
turning_character: false,
|
char_pos,
|
||||||
char_ori: -start_angle,
|
char_state: None,
|
||||||
|
char_model_cache: FigureModelCache::new(),
|
||||||
|
|
||||||
|
airship_pos: char_pos - Vec3::unit_z() * 10.0,
|
||||||
|
airship_state: None,
|
||||||
|
airship_model_cache: FigureModelCache::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,20 +174,15 @@ impl Scene {
|
|||||||
},
|
},
|
||||||
Event::MouseButton(button, state) => {
|
Event::MouseButton(button, state) => {
|
||||||
if state == PressState::Pressed {
|
if state == PressState::Pressed {
|
||||||
//self.turning_camera = button == MouseButton::Right;
|
self.turning_camera = button == MouseButton::Left;
|
||||||
self.turning_character = button == MouseButton::Left;
|
|
||||||
} else {
|
} else {
|
||||||
//self.turning_camera = false;
|
self.turning_camera = false;
|
||||||
self.turning_character = false;
|
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
},
|
},
|
||||||
Event::CursorMove(delta) => {
|
Event::CursorMove(delta) => {
|
||||||
/*if self.turning_camera {
|
if self.turning_camera {
|
||||||
self.camera.rotate_by(Vec3::new(delta.x * 0.01, 0.0, 0.0))
|
self.camera.rotate_by(delta.with_z(0.0) * 0.01);
|
||||||
}*/
|
|
||||||
if self.turning_character {
|
|
||||||
self.char_ori += delta.x * 0.01;
|
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
},
|
},
|
||||||
@ -242,7 +196,13 @@ impl Scene {
|
|||||||
renderer: &mut Renderer,
|
renderer: &mut Renderer,
|
||||||
scene_data: SceneData,
|
scene_data: SceneData,
|
||||||
inventory: Option<&Inventory>,
|
inventory: Option<&Inventory>,
|
||||||
|
client: &Client,
|
||||||
) {
|
) {
|
||||||
|
self.camera
|
||||||
|
.force_focus_pos(self.char_pos + Vec3::unit_z() * 1.5);
|
||||||
|
let ori = self.camera.get_tgt_orientation();
|
||||||
|
self.camera
|
||||||
|
.set_orientation(Vec3::new(ori.x, ori.y.max(-0.25), ori.z));
|
||||||
self.camera.update(
|
self.camera.update(
|
||||||
scene_data.time,
|
scene_data.time,
|
||||||
/* 1.0 / 60.0 */ scene_data.delta_time,
|
/* 1.0 / 60.0 */ scene_data.delta_time,
|
||||||
@ -254,13 +214,18 @@ impl Scene {
|
|||||||
view_mat,
|
view_mat,
|
||||||
proj_mat,
|
proj_mat,
|
||||||
cam_pos,
|
cam_pos,
|
||||||
|
proj_mat_inv,
|
||||||
|
view_mat_inv,
|
||||||
..
|
..
|
||||||
} = self.camera.dependents();
|
} = self.camera.dependents();
|
||||||
const VD: f32 = 115.0; // View Distance
|
const VD: f32 = 0.0; // View Distance
|
||||||
|
|
||||||
const TIME: f64 = 8.6 * 60.0 * 60.0;
|
const TIME: f64 = 8.6 * 60.0 * 60.0;
|
||||||
const SHADOW_NEAR: f32 = 1.0;
|
const SHADOW_NEAR: f32 = 0.25;
|
||||||
const SHADOW_FAR: f32 = 25.0;
|
const SHADOW_FAR: f32 = 1.0;
|
||||||
|
|
||||||
|
self.lod
|
||||||
|
.maintain(renderer, client, self.camera.get_focus_pos(), &self.camera);
|
||||||
|
|
||||||
renderer.update_consts(&mut self.data.globals, &[Globals::new(
|
renderer.update_consts(&mut self.data.globals, &[Globals::new(
|
||||||
view_mat,
|
view_mat,
|
||||||
@ -268,7 +233,7 @@ impl Scene {
|
|||||||
cam_pos,
|
cam_pos,
|
||||||
self.camera.get_focus_pos(),
|
self.camera.get_focus_pos(),
|
||||||
VD,
|
VD,
|
||||||
self.lod.tgt_detail as f32,
|
self.lod.get_data().tgt_detail as f32,
|
||||||
self.map_bounds,
|
self.map_bounds,
|
||||||
TIME,
|
TIME,
|
||||||
scene_data.time,
|
scene_data.time,
|
||||||
@ -288,8 +253,12 @@ impl Scene {
|
|||||||
self.camera.get_mode(),
|
self.camera.get_mode(),
|
||||||
250.0,
|
250.0,
|
||||||
)]);
|
)]);
|
||||||
|
renderer.update_clouds_locals(CloudsLocals::new(proj_mat_inv, view_mat_inv));
|
||||||
|
renderer.update_postprocess_locals(PostProcessLocals::new(proj_mat_inv, view_mat_inv));
|
||||||
|
|
||||||
self.figure_model_cache
|
self.char_model_cache
|
||||||
|
.clean(&mut self.figure_atlas, scene_data.tick);
|
||||||
|
self.airship_model_cache
|
||||||
.clean(&mut self.figure_atlas, scene_data.tick);
|
.clean(&mut self.figure_atlas, scene_data.tick);
|
||||||
|
|
||||||
let item_info = |equip_slot| {
|
let item_info = |equip_slot| {
|
||||||
@ -310,12 +279,37 @@ impl Scene {
|
|||||||
|
|
||||||
let hands = (active_tool_hand, second_tool_hand);
|
let hands = (active_tool_hand, second_tool_hand);
|
||||||
|
|
||||||
|
fn figure_params(
|
||||||
|
camera: &Camera,
|
||||||
|
dt: f32,
|
||||||
|
pos: Vec3<f32>,
|
||||||
|
) -> FigureUpdateCommonParameters<'_> {
|
||||||
|
FigureUpdateCommonParameters {
|
||||||
|
entity: None,
|
||||||
|
pos: pos.into(),
|
||||||
|
ori: anim::vek::Quaternion::identity().rotated_z(std::f32::consts::PI * -0.5),
|
||||||
|
scale: 1.0,
|
||||||
|
mount_transform_pos: None,
|
||||||
|
body: None,
|
||||||
|
tools: (None, None),
|
||||||
|
col: Rgba::broadcast(1.0),
|
||||||
|
dt,
|
||||||
|
_lpindex: 0,
|
||||||
|
_visible: true,
|
||||||
|
is_player: false,
|
||||||
|
_camera: camera,
|
||||||
|
terrain: None,
|
||||||
|
ground_vel: Vec3::zero(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(body) = scene_data.body {
|
if let Some(body) = scene_data.body {
|
||||||
let figure_state = self.figure_state.get_or_insert_with(|| {
|
let char_state = self.char_state.get_or_insert_with(|| {
|
||||||
FigureState::new(renderer, CharacterSkeleton::default(), body)
|
FigureState::new(renderer, CharacterSkeleton::default(), body)
|
||||||
});
|
});
|
||||||
let tgt_skeleton = IdleAnimation::update_skeleton(
|
let params = figure_params(&self.camera, scene_data.delta_time, self.char_pos);
|
||||||
figure_state.skeleton_mut(),
|
let tgt_skeleton = anim::character::IdleAnimation::update_skeleton(
|
||||||
|
char_state.skeleton_mut(),
|
||||||
(
|
(
|
||||||
active_tool_kind,
|
active_tool_kind,
|
||||||
second_tool_kind,
|
second_tool_kind,
|
||||||
@ -324,51 +318,74 @@ impl Scene {
|
|||||||
),
|
),
|
||||||
scene_data.time as f32,
|
scene_data.time as f32,
|
||||||
&mut 0.0,
|
&mut 0.0,
|
||||||
&SkeletonAttr::from(&body),
|
&anim::character::SkeletonAttr::from(&body),
|
||||||
);
|
);
|
||||||
let dt_lerp = (scene_data.delta_time * 15.0).min(1.0);
|
let dt_lerp = (scene_data.delta_time * 15.0).min(1.0);
|
||||||
*figure_state.skeleton_mut() =
|
*char_state.skeleton_mut() =
|
||||||
Lerp::lerp(&*figure_state.skeleton_mut(), &tgt_skeleton, dt_lerp);
|
Lerp::lerp(&*char_state.skeleton_mut(), &tgt_skeleton, dt_lerp);
|
||||||
|
let (model, _) = self.char_model_cache.get_or_create_model(
|
||||||
let model = self
|
renderer,
|
||||||
.figure_model_cache
|
&mut self.figure_atlas,
|
||||||
.get_or_create_model(
|
body,
|
||||||
renderer,
|
inventory,
|
||||||
&mut self.figure_atlas,
|
(),
|
||||||
body,
|
scene_data.tick,
|
||||||
inventory,
|
CameraMode::default(),
|
||||||
(),
|
None,
|
||||||
scene_data.tick,
|
scene_data.slow_job_pool,
|
||||||
CameraMode::default(),
|
None,
|
||||||
None,
|
);
|
||||||
scene_data.slow_job_pool,
|
char_state.update(
|
||||||
None,
|
renderer,
|
||||||
)
|
None,
|
||||||
.0;
|
&mut [Default::default(); anim::MAX_BONE_COUNT],
|
||||||
let mut buf = [Default::default(); anim::MAX_BONE_COUNT];
|
¶ms,
|
||||||
let common_params = FigureUpdateCommonParameters {
|
1.0,
|
||||||
entity: None,
|
model,
|
||||||
pos: anim::vek::Vec3::zero(),
|
body,
|
||||||
ori: anim::vek::Quaternion::rotation_from_to_3d(
|
);
|
||||||
anim::vek::Vec3::unit_y(),
|
|
||||||
anim::vek::Vec3::new(self.char_ori.sin(), -self.char_ori.cos(), 0.0),
|
|
||||||
),
|
|
||||||
scale: 1.0,
|
|
||||||
mount_transform_pos: None,
|
|
||||||
body: None,
|
|
||||||
tools: (None, None),
|
|
||||||
col: Rgba::broadcast(1.0),
|
|
||||||
dt: scene_data.delta_time,
|
|
||||||
_lpindex: 0,
|
|
||||||
_visible: true,
|
|
||||||
is_player: false,
|
|
||||||
_camera: &self.camera,
|
|
||||||
terrain: None,
|
|
||||||
ground_vel: Vec3::zero(),
|
|
||||||
};
|
|
||||||
|
|
||||||
figure_state.update(renderer, None, &mut buf, &common_params, 1.0, model, body);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let airship_body = ship::Body::DefaultAirship;
|
||||||
|
let airship_state = self.airship_state.get_or_insert_with(|| {
|
||||||
|
FigureState::new(renderer, ShipSkeleton::default(), airship_body)
|
||||||
|
});
|
||||||
|
let params = figure_params(&self.camera, scene_data.delta_time, self.airship_pos);
|
||||||
|
let tgt_skeleton = anim::ship::IdleAnimation::update_skeleton(
|
||||||
|
airship_state.skeleton_mut(),
|
||||||
|
(
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
scene_data.time as f32,
|
||||||
|
scene_data.time as f32,
|
||||||
|
(params.ori * Vec3::unit_y()).into(),
|
||||||
|
(params.ori * Vec3::unit_y()).into(),
|
||||||
|
),
|
||||||
|
scene_data.time as f32,
|
||||||
|
&mut 0.0,
|
||||||
|
&anim::ship::SkeletonAttr::from(&airship_body),
|
||||||
|
);
|
||||||
|
let dt_lerp = (scene_data.delta_time * 15.0).min(1.0);
|
||||||
|
*airship_state.skeleton_mut() =
|
||||||
|
Lerp::lerp(&*airship_state.skeleton_mut(), &tgt_skeleton, dt_lerp);
|
||||||
|
let (model, _) = self.airship_model_cache.get_or_create_terrain_model(
|
||||||
|
renderer,
|
||||||
|
&mut self.figure_atlas,
|
||||||
|
airship_body,
|
||||||
|
(),
|
||||||
|
scene_data.tick,
|
||||||
|
scene_data.slow_job_pool,
|
||||||
|
&self.sprite_render_state,
|
||||||
|
);
|
||||||
|
airship_state.update(
|
||||||
|
renderer,
|
||||||
|
None,
|
||||||
|
&mut [Default::default(); anim::MAX_BONE_COUNT],
|
||||||
|
¶ms,
|
||||||
|
1.0,
|
||||||
|
model,
|
||||||
|
airship_body,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn global_bind_group(&self) -> &GlobalsBindGroup { &self.globals_bind_group }
|
pub fn global_bind_group(&self) -> &GlobalsBindGroup { &self.globals_bind_group }
|
||||||
@ -382,7 +399,7 @@ impl Scene {
|
|||||||
) {
|
) {
|
||||||
let mut figure_drawer = drawer.draw_figures();
|
let mut figure_drawer = drawer.draw_figures();
|
||||||
if let Some(body) = body {
|
if let Some(body) = body {
|
||||||
let model = &self.figure_model_cache.get_model(
|
let model = &self.char_model_cache.get_model(
|
||||||
&self.figure_atlas,
|
&self.figure_atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
@ -392,28 +409,61 @@ impl Scene {
|
|||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some((model, figure_state)) = model.zip(self.figure_state.as_ref()) {
|
if let Some((model, char_state)) = model.zip(self.char_state.as_ref()) {
|
||||||
if let Some(lod) = model.lod_model(0) {
|
if let Some(lod) = model.lod_model(0) {
|
||||||
figure_drawer.draw(
|
figure_drawer.draw(
|
||||||
lod,
|
lod,
|
||||||
figure_state.bound(),
|
char_state.bound(),
|
||||||
self.figure_atlas.texture(ModelEntryRef::Figure(model)),
|
self.figure_atlas.texture(ModelEntryRef::Figure(model)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((model, state)) = &self.backdrop {
|
let model = &self.airship_model_cache.get_model(
|
||||||
|
&self.figure_atlas,
|
||||||
|
ship::Body::DefaultAirship,
|
||||||
|
Default::default(),
|
||||||
|
tick,
|
||||||
|
CameraMode::default(),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
if let Some((model, airship_state)) = model.zip(self.airship_state.as_ref()) {
|
||||||
if let Some(lod) = model.lod_model(0) {
|
if let Some(lod) = model.lod_model(0) {
|
||||||
figure_drawer.draw(
|
figure_drawer.draw(
|
||||||
lod,
|
lod,
|
||||||
state.bound(),
|
airship_state.bound(),
|
||||||
self.figure_atlas.texture(ModelEntryRef::Figure(model)),
|
self.figure_atlas.texture(ModelEntryRef::Terrain(model)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
drop(figure_drawer);
|
drop(figure_drawer);
|
||||||
|
|
||||||
|
let mut sprite_drawer = drawer.draw_sprites(
|
||||||
|
&self.sprite_globals,
|
||||||
|
&self.sprite_render_state.sprite_atlas_textures,
|
||||||
|
);
|
||||||
|
if let (Some(sprite_instances), Some(data)) = (
|
||||||
|
self.airship_model_cache
|
||||||
|
.get_sprites(ship::Body::DefaultAirship),
|
||||||
|
self.airship_state.as_ref().map(|s| &s.extra),
|
||||||
|
) {
|
||||||
|
sprite_drawer.draw(
|
||||||
|
data,
|
||||||
|
&sprite_instances[0],
|
||||||
|
&AltIndices {
|
||||||
|
deep_end: 0,
|
||||||
|
underground_end: 0,
|
||||||
|
},
|
||||||
|
CullingMode::None,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
drop(sprite_drawer);
|
||||||
|
|
||||||
|
self.lod.render(drawer, Default::default());
|
||||||
|
|
||||||
drawer.draw_skybox(&self.skybox.model);
|
drawer.draw_skybox(&self.skybox.model);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -483,10 +483,6 @@ pub struct Terrain<V: RectRasterableVol = TerrainChunk> {
|
|||||||
/// might significantly reduce the number of textures we need for
|
/// might significantly reduce the number of textures we need for
|
||||||
/// particularly difficult locations.
|
/// particularly difficult locations.
|
||||||
atlas: AtlasAllocator,
|
atlas: AtlasAllocator,
|
||||||
/// FIXME: This could possibly become an `AssetHandle<SpriteSpec>`, to get
|
|
||||||
/// hot-reloading for free, but I am not sure if sudden changes of this
|
|
||||||
/// value would break something
|
|
||||||
pub sprite_config: Arc<SpriteSpec>,
|
|
||||||
chunks: HashMap<Vec2<i32>, TerrainChunkData>,
|
chunks: HashMap<Vec2<i32>, TerrainChunkData>,
|
||||||
/// Temporary storage for dead chunks that might still be shadowing chunks
|
/// Temporary storage for dead chunks that might still be shadowing chunks
|
||||||
/// in view. We wait until either the chunk definitely cannot be
|
/// in view. We wait until either the chunk definitely cannot be
|
||||||
@ -516,9 +512,8 @@ pub struct Terrain<V: RectRasterableVol = TerrainChunk> {
|
|||||||
|
|
||||||
// GPU data
|
// GPU data
|
||||||
// Maps sprite kind + variant to data detailing how to render it
|
// Maps sprite kind + variant to data detailing how to render it
|
||||||
pub sprite_data: Arc<HashMap<(SpriteKind, usize), [SpriteData; SPRITE_LOD_LEVELS]>>,
|
pub sprite_render_state: SpriteRenderState,
|
||||||
pub sprite_globals: SpriteGlobalsBindGroup,
|
pub sprite_globals: SpriteGlobalsBindGroup,
|
||||||
pub sprite_atlas_textures: Arc<AtlasTextures<pipelines::sprite::Locals, FigureSpriteAtlasData>>,
|
|
||||||
/// As stated previously, this is always the very latest texture into which
|
/// As stated previously, this is always the very latest texture into which
|
||||||
/// we allocate. Code cannot assume that this is the assigned texture
|
/// we allocate. Code cannot assume that this is the assigned texture
|
||||||
/// for any particular chunk; look at the `texture` field in
|
/// for any particular chunk; look at the `texture` field in
|
||||||
@ -533,12 +528,20 @@ impl TerrainChunkData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SpriteRenderContext {
|
pub struct SpriteRenderState {
|
||||||
sprite_config: Arc<SpriteSpec>,
|
/// FIXME: This could possibly become an `AssetHandle<SpriteSpec>`, to get
|
||||||
|
/// hot-reloading for free, but I am not sure if sudden changes of this
|
||||||
|
/// value would break something
|
||||||
|
pub sprite_config: Arc<SpriteSpec>,
|
||||||
// Maps sprite kind + variant to data detailing how to render it
|
// Maps sprite kind + variant to data detailing how to render it
|
||||||
sprite_data: Arc<HashMap<(SpriteKind, usize), [SpriteData; SPRITE_LOD_LEVELS]>>,
|
pub sprite_data: Arc<HashMap<(SpriteKind, usize), [SpriteData; SPRITE_LOD_LEVELS]>>,
|
||||||
sprite_atlas_textures: Arc<AtlasTextures<pipelines::sprite::Locals, FigureSpriteAtlasData>>,
|
pub sprite_atlas_textures: Arc<AtlasTextures<pipelines::sprite::Locals, FigureSpriteAtlasData>>,
|
||||||
sprite_verts_buffer: Arc<SpriteVerts>,
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SpriteRenderContext {
|
||||||
|
pub state: SpriteRenderState,
|
||||||
|
pub sprite_verts_buffer: Arc<SpriteVerts>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type SpriteRenderContextLazy = Box<dyn FnMut(&mut Renderer) -> SpriteRenderContext>;
|
pub type SpriteRenderContextLazy = Box<dyn FnMut(&mut Renderer) -> SpriteRenderContext>;
|
||||||
@ -705,10 +708,12 @@ impl SpriteRenderContext {
|
|||||||
let sprite_verts_buffer = renderer.create_sprite_verts(sprite_mesh);
|
let sprite_verts_buffer = renderer.create_sprite_verts(sprite_mesh);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
// TODO: these are all Arcs, would it makes sense to factor out the Arc?
|
state: SpriteRenderState {
|
||||||
sprite_config: Arc::clone(&sprite_config),
|
// TODO: these are all Arcs, would it makes sense to factor out the Arc?
|
||||||
sprite_data: Arc::new(sprite_data),
|
sprite_config: Arc::clone(&sprite_config),
|
||||||
sprite_atlas_textures: Arc::new(sprite_atlas_textures),
|
sprite_data: Arc::new(sprite_data),
|
||||||
|
sprite_atlas_textures: Arc::new(sprite_atlas_textures),
|
||||||
|
},
|
||||||
sprite_verts_buffer: Arc::new(sprite_verts_buffer),
|
sprite_verts_buffer: Arc::new(sprite_verts_buffer),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -732,7 +737,6 @@ impl<V: RectRasterableVol> Terrain<V> {
|
|||||||
|
|
||||||
Self {
|
Self {
|
||||||
atlas,
|
atlas,
|
||||||
sprite_config: sprite_render_context.sprite_config,
|
|
||||||
chunks: HashMap::default(),
|
chunks: HashMap::default(),
|
||||||
shadow_chunks: Vec::default(),
|
shadow_chunks: Vec::default(),
|
||||||
mesh_send_tmp: send,
|
mesh_send_tmp: send,
|
||||||
@ -740,8 +744,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
|||||||
mesh_todo: HashMap::default(),
|
mesh_todo: HashMap::default(),
|
||||||
mesh_todos_active: Arc::new(AtomicU64::new(0)),
|
mesh_todos_active: Arc::new(AtomicU64::new(0)),
|
||||||
mesh_recv_overflow: 0.0,
|
mesh_recv_overflow: 0.0,
|
||||||
sprite_data: sprite_render_context.sprite_data,
|
sprite_render_state: sprite_render_context.state,
|
||||||
sprite_atlas_textures: sprite_render_context.sprite_atlas_textures,
|
|
||||||
sprite_globals: renderer.bind_sprite_globals(
|
sprite_globals: renderer.bind_sprite_globals(
|
||||||
global_model,
|
global_model,
|
||||||
lod_data,
|
lod_data,
|
||||||
@ -1227,8 +1230,8 @@ impl<V: RectRasterableVol> Terrain<V> {
|
|||||||
|
|
||||||
// Queue the worker thread.
|
// Queue the worker thread.
|
||||||
let started_tick = todo.started_tick;
|
let started_tick = todo.started_tick;
|
||||||
let sprite_data = Arc::clone(&self.sprite_data);
|
let sprite_data = Arc::clone(&self.sprite_render_state.sprite_data);
|
||||||
let sprite_config = Arc::clone(&self.sprite_config);
|
let sprite_config = Arc::clone(&self.sprite_render_state.sprite_config);
|
||||||
let cnt = Arc::clone(&self.mesh_todos_active);
|
let cnt = Arc::clone(&self.mesh_todos_active);
|
||||||
cnt.fetch_add(1, Ordering::Relaxed);
|
cnt.fetch_add(1, Ordering::Relaxed);
|
||||||
scene_data
|
scene_data
|
||||||
|
Loading…
Reference in New Issue
Block a user