diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index bd6505d208..ef80c752eb 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -170,6 +170,7 @@ widget_ids! { time, entity_count, num_chunks, + num_lights, num_figures, // Game Version @@ -235,6 +236,7 @@ pub struct DebugInfo { pub velocity: Option, pub ori: Option, pub num_chunks: u32, + pub num_lights: u32, pub num_visible_chunks: u32, pub num_shadow_chunks: u32, pub num_figures: u32, @@ -1404,13 +1406,21 @@ impl Hud { .font_size(self.fonts.cyri.scale(14)) .set(self.ids.num_chunks, ui_widgets); + // Number of lights + Text::new(&format!("Lights: {}", debug_info.num_lights,)) + .color(TEXT_COLOR) + .down_from(self.ids.num_chunks, 5.0) + .font_id(self.fonts.cyri.conrod_id) + .font_size(self.fonts.cyri.scale(14)) + .set(self.ids.num_lights, ui_widgets); + // Number of figures Text::new(&format!( "Figures: {} ({} visible)", debug_info.num_figures, debug_info.num_figures_visible, )) .color(TEXT_COLOR) - .down_from(self.ids.num_chunks, 5.0) + .down_from(self.ids.num_lights, 5.0) .font_id(self.fonts.cyri.conrod_id) .font_size(self.fonts.cyri.scale(14)) .set(self.ids.num_figures, ui_widgets); diff --git a/voxygen/src/render/consts.rs b/voxygen/src/render/consts.rs index 4c31cea86e..3d5d579f2c 100644 --- a/voxygen/src/render/consts.rs +++ b/voxygen/src/render/consts.rs @@ -34,8 +34,12 @@ impl Consts { vals: &[T], offset: usize, ) -> Result<(), RenderError> { - encoder - .update_buffer(&self.buf, vals, offset) - .map_err(RenderError::UpdateError) + if vals.len() > 0 { + encoder + .update_buffer(&self.buf, vals, offset) + .map_err(RenderError::UpdateError) + } else { + Ok(()) + } } } diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index 3484605a86..1faa428945 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -41,7 +41,7 @@ use core::{ }; use guillotiere::AtlasAllocator; use hashbrown::HashMap; -use specs::{Entity as EcsEntity, Join, WorldExt}; +use specs::{Entity as EcsEntity, Join, LazyUpdate, WorldExt}; use treeculler::{BVol, BoundingSphere}; use vek::*; @@ -365,6 +365,7 @@ impl FigureMgr { } } let dt = ecs.fetch::().0; + let updater = ecs.read_resource::(); for (entity, waypoint, light_emitter_opt, light_anim) in ( &ecs.entities(), ecs.read_storage::().maybe(), @@ -377,7 +378,7 @@ impl FigureMgr { if let Some(emitter) = light_emitter_opt { ( emitter.col, - if emitter.strength.is_finite() { + if emitter.strength.is_normal() { emitter.strength } else { 0.0 @@ -394,7 +395,7 @@ impl FigureMgr { if let Some(state) = self.states.character_states.get(&entity) { light_anim.offset = state.lantern_offset; } - if !light_anim.strength.is_finite() { + if !light_anim.strength.is_normal() { light_anim.strength = 0.0; } if animated { @@ -408,6 +409,18 @@ impl FigureMgr { light_anim.strength = target_strength; light_anim.col = target_col; } + // NOTE: We add `LIGHT_EPSILON` because if we wait for numbers to become + // equal to target (or even within a subnormal), it will take a minimum + // of 30 seconds for a light to fully turn off (for initial + // strength ≥ 1), which prevents optimizations (particularly those that + // can kick in with zero lights). + const LIGHT_EPSILON: f32 = 0.0001; + if (light_anim.strength - target_strength).abs() < LIGHT_EPSILON { + light_anim.strength = target_strength; + if light_anim.strength == 0.0 { + updater.remove::(entity); + } + } } } diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index 13de9eeaab..b2fdae596c 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -304,6 +304,9 @@ impl Scene { /// Get a reference to the scene's terrain. pub fn terrain(&self) -> &Terrain { &self.terrain } + /// Get a reference to the scene's lights. + pub fn lights(&self) -> &Vec { &self.light_data } + /// Get a reference to the scene's figure manager. pub fn figure_mgr(&self) -> &FigureMgr { &self.figure_mgr } @@ -466,9 +469,11 @@ impl Scene { .read_storage::(), ) .join() - .filter(|(pos, _, _, _)| { - (pos.0.distance_squared(player_pos) as f32) - < loaded_distance.powf(2.0) + LIGHT_DIST_RADIUS + .filter(|(pos, _, _, light_anim)| { + light_anim.col != Rgb::zero() + && light_anim.strength > 0.0 + && (pos.0.distance_squared(player_pos) as f32) + < loaded_distance.powf(2.0) + LIGHT_DIST_RADIUS }) .map(|(pos, ori, interpolated, light_anim)| { // Use interpolated values if they are available @@ -1435,8 +1440,10 @@ impl Scene { // would instead have this as an extension. if renderer.render_mode().shadow.is_map() && (is_daylight || self.light_data.len() > 0) { - // Set up shadow mapping. - renderer.start_shadows(); + if is_daylight { + // Set up shadow mapping. + renderer.start_shadows(); + } // Render terrain shadows. self.terrain.render_shadows( @@ -1462,8 +1469,10 @@ impl Scene { scene_data.figure_lod_render_distance, ); - // Flush shadows. - renderer.flush_shadows(); + if is_daylight { + // Flush shadows. + renderer.flush_shadows(); + } } let lod = self.lod.get_data(); diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index 8dff4d6335..2718d7c561 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -697,6 +697,7 @@ impl PlayState for SessionState { .get(self.client.borrow().entity()) .cloned(), num_chunks: self.scene.terrain().chunk_count() as u32, + num_lights: self.scene.lights().len() as u32, num_visible_chunks: self.scene.terrain().visible_chunk_count() as u32, num_shadow_chunks: self.scene.terrain().shadow_chunk_count() as u32, num_figures: self.scene.figure_mgr().figure_count() as u32,