Merge branch 'master' into 'master'

Rendering on character selection screen, minor raycasting fix and pets

See merge request veloren/veloren!126

Former-commit-id: a83b7c55dfda634a2e9d928135598bb1a461a32f
This commit is contained in:
Joshua Barretto 2019-05-12 13:50:59 +00:00
commit 189f5f0fd9
14 changed files with 358 additions and 73 deletions

View File

@ -1,16 +1,20 @@
use specs::{Component, VecStorage};
use specs::{Component, VecStorage, Entity as EcsEntity};
use vek::*;
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
#[derive(Copy, Clone, Debug)]
pub enum Agent {
Wanderer(Vec2<f32>),
Pet {
target: EcsEntity,
offset: Vec2<f32>,
},
}
impl Component for Agent {
type Storage = VecStorage<Self>;
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
#[derive(Copy, Clone, Debug)]
pub struct Control {
pub move_dir: Vec2<f32>,
pub jumping: bool,

View File

@ -116,6 +116,16 @@ pub struct AnimationHistory {
pub time: f64,
}
impl AnimationHistory {
pub fn new(animation: Animation) -> Self {
Self {
last: None,
current: animation,
time: 0.0,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Animation {
Idle,

View File

@ -9,6 +9,7 @@ pub struct Ray<'a, V: ReadVol, F: RayUntil<V::Vox>> {
to: Vec3<f32>,
until: F,
max_iter: usize,
ignore_error: bool,
}
impl<'a, V: ReadVol, F: RayUntil<V::Vox>> Ray<'a, V, F> {
@ -19,6 +20,7 @@ impl<'a, V: ReadVol, F: RayUntil<V::Vox>> Ray<'a, V, F> {
to,
until,
max_iter: 100,
ignore_error: false,
}
}
@ -31,6 +33,11 @@ impl<'a, V: ReadVol, F: RayUntil<V::Vox>> Ray<'a, V, F> {
self
}
pub fn ignore_error(mut self) -> Self {
self.ignore_error = true;
self
}
pub fn cast(mut self) -> (f32, Result<Option<&'a V::Vox>, V::Err>) {
// TODO: Fully test this!
@ -49,8 +56,8 @@ impl<'a, V: ReadVol, F: RayUntil<V::Vox>> Ray<'a, V, F> {
match self.vol.get(ipos).map(|vox| (vox, (self.until)(vox))) {
Ok((vox, true)) => return (dist, Ok(Some(vox))),
Ok((_, false)) => {}
Err(err) => return (dist, Err(err)),
Err(err) if !self.ignore_error => return (dist, Err(err)),
_ => {}
}
// Allow one iteration above max

View File

@ -36,7 +36,7 @@ pub struct DeltaTime(pub f32);
/// too fast, we'd skip important physics events like collisions. This constant determines what
/// the upper limit is. If delta time exceeds this value, the game's physics will begin to produce
/// time lag. Ideally, we'd avoid such a situation.
const MAX_DELTA_TIME: f32 = 0.2;
const MAX_DELTA_TIME: f32 = 0.05;
pub struct Changes {
pub new_chunks: HashSet<Vec3<i32>>,

View File

@ -15,13 +15,13 @@ impl<'a> System<'a> for Sys {
WriteStorage<'a, Control>,
);
fn run(&mut self, (mut agents, pos, mut controls): Self::SystemData) {
for (mut agent, pos, mut control) in (&mut agents, &pos, &mut controls).join() {
fn run(&mut self, (mut agents, positions, mut controls): Self::SystemData) {
for (mut agent, pos, mut control) in (&mut agents, &positions, &mut controls).join() {
match agent {
Agent::Wanderer(bearing) => {
*bearing += Vec2::new(
rand::random::<f32>().fract() - 0.5,
rand::random::<f32>().fract() - 0.5,
rand::random::<f32>() - 0.5,
rand::random::<f32>() - 0.5,
) * 0.1
- *bearing * 0.01
- pos.0 * 0.0002;
@ -29,7 +29,37 @@ impl<'a> System<'a> for Sys {
if bearing.magnitude_squared() != 0.0 {
control.move_dir = bearing.normalized();
}
}
},
Agent::Pet { target, offset } => {
// Run towards target
match positions.get(*target) {
Some(tgt_pos) => {
let tgt_pos = tgt_pos.0 + *offset;
// Jump with target
control.jumping = tgt_pos.z > pos.0.z + 1.0;
// Move towards the target
let dist = tgt_pos.distance(pos.0);
control.move_dir = if dist > 5.0 {
Vec2::from(tgt_pos - pos.0).normalized()
} else if dist < 1.5 && pos.0 != tgt_pos {
Vec2::from(pos.0 - tgt_pos).normalized()
} else {
Vec2::zero()
};
},
_ => control.move_dir = Vec2::zero(),
}
// Change offset occasionally
if rand::random::<f32>() < 0.003 {
*offset = Vec2::new(
rand::random::<f32>() - 0.5,
rand::random::<f32>() - 0.5,
) * 10.0;
}
},
}
}
}

View File

@ -4,7 +4,11 @@
use crate::Server;
use common::{comp, msg::ServerMsg};
use specs::{join::Join, Entity as EcsEntity};
use specs::{
Join,
Entity as EcsEntity,
Builder,
};
use vek::*;
use lazy_static::lazy_static;
@ -72,9 +76,15 @@ lazy_static! {
ChatCommand::new(
"tp",
"{}",
"/tp <alias>: Teleport to another player",
"/tp <alias> : Teleport to another player",
handle_tp
),
ChatCommand::new(
"pet",
"{}",
"/pet : Spawn a test pet NPC",
handle_pet
),
ChatCommand::new("help", "", "/help: Display this message", handle_help)
];
}
@ -179,6 +189,23 @@ fn handle_tp(server: &mut Server, entity: EcsEntity, args: String, action: &Chat
}
}
fn handle_pet(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
match server
.state
.read_component_cloned::<comp::phys::Pos>(entity)
{
Some(pos) => {
server.create_npc(comp::Character::random())
.with(comp::Control::default())
.with(comp::Agent::Pet{ target: entity, offset: Vec2::zero() })
.with(pos)
.build();
server.clients.notify(entity, ServerMsg::Chat("Pet spawned!".to_owned()));
},
None => server.clients.notify(entity, ServerMsg::Chat("You have no position!".to_owned())),
}
}
fn handle_help(server: &mut Server, entity: EcsEntity, _args: String, _action: &ChatCommand) {
for cmd in CHAT_COMMANDS.iter() {
server

View File

@ -82,8 +82,8 @@ impl Server {
for i in 0..4 {
this.create_npc(comp::Character::random())
.with(comp::Agent::Wanderer(Vec2::zero()))
.with(comp::Control::default())
.with(comp::Agent::Wanderer(Vec2::zero()))
.build();
}
@ -121,6 +121,7 @@ impl Server {
.with(comp::phys::Pos(Vec3::new(0.0, 0.0, 64.0)))
.with(comp::phys::Vel(Vec3::zero()))
.with(comp::phys::Dir(Vec3::unit_y()))
.with(comp::AnimationHistory::new(Animation::Idle))
.with(character)
}
@ -140,11 +141,7 @@ impl Server {
// Set initial animation
state.write_component(
entity,
comp::AnimationHistory {
last: None,
current: Animation::Idle,
time: 0.0,
},
comp::AnimationHistory::new(Animation::Idle),
);
// Tell the client his request was successful
@ -230,7 +227,7 @@ impl Server {
.join()
{
let chunk_pos = self.state.terrain().pos_key(pos.0.map(|e| e as i32));
let dist = (chunk_pos - key).map(|e| e.abs()).reduce_max();
let dist = Vec2::from(chunk_pos - key).map(|e: i32| e.abs()).reduce_max();
min_dist = min_dist.min(dist);
}
@ -272,7 +269,7 @@ impl Server {
// (All components Sphynx tracks)
client.notify(ServerMsg::InitialSync {
ecs_state: self.state.ecs().gen_state_package(),
entity_uid: self.state.ecs().uid_from_entity(entity).unwrap().into(),
entity_uid: self.state.ecs().uid_from_entity(entity).unwrap().into(), // Can't fail
});
self.clients.add(entity, client);

View File

@ -136,7 +136,7 @@ Voxygen has logged information about the problem (including this message) to the
The information below is intended for developers and testers.
Panic Payload: {:?}
PanicInfo: {:?}", settings_clone.log.file, reason, panic_info);
PanicInfo: {}", settings_clone.log.file, reason, panic_info);
log::error!("VOXYGEN HAS PANICKED\n\n{}", msg);

View File

@ -1,4 +1,5 @@
mod ui;
mod scene;
use crate::{
session::SessionState,
@ -9,6 +10,7 @@ use client::{self, Client};
use common::{clock::Clock, msg::ClientMsg};
use std::{cell::RefCell, rc::Rc, time::Duration};
use ui::CharSelectionUi;
use scene::Scene;
use vek::*;
const FPS: u64 = 60;
@ -16,6 +18,7 @@ const FPS: u64 = 60;
pub struct CharSelectionState {
char_selection_ui: CharSelectionUi,
client: Rc<RefCell<Client>>,
scene: Scene,
}
impl CharSelectionState {
@ -24,6 +27,7 @@ impl CharSelectionState {
Self {
char_selection_ui: CharSelectionUi::new(window),
client,
scene: Scene::new(window.renderer_mut()),
}
}
}
@ -82,6 +86,12 @@ impl PlayState for CharSelectionState {
}
}
// Maintain the scene
self.scene.maintain(global_state.window.renderer_mut(), &self.client.borrow());
// Render the scene
self.scene.render(global_state.window.renderer_mut(), &self.client.borrow());
// Draw the UI to the screen
self.char_selection_ui
.render(global_state.window.renderer_mut());

View File

@ -0,0 +1,150 @@
use vek::*;
use client::Client;
use common::{
comp::Character,
figure::Segment,
};
use crate::{
render::{
Renderer,
Consts,
Globals,
Model,
SkyboxLocals,
SkyboxPipeline,
create_skybox_mesh,
PostProcessLocals,
PostProcessPipeline,
create_pp_mesh,
FigurePipeline,
},
scene::{
camera::Camera,
figure::{FigureModelCache, FigureState},
},
anim::{
Skeleton,
Animation,
character::{
CharacterSkeleton,
IdleAnimation,
},
},
};
struct Skybox {
model: Model<SkyboxPipeline>,
locals: Consts<SkyboxLocals>,
}
struct PostProcess {
model: Model<PostProcessPipeline>,
locals: Consts<PostProcessLocals>,
}
pub struct Scene {
globals: Consts<Globals>,
camera: Camera,
skybox: Skybox,
postprocess: PostProcess,
backdrop_model: Model<FigurePipeline>,
backdrop_state: FigureState<CharacterSkeleton>,
figure_model_cache: FigureModelCache,
figure_state: FigureState<CharacterSkeleton>,
}
impl Scene {
pub fn new(renderer: &mut Renderer) -> Self {
let resolution = renderer.get_resolution().map(|e| e as f32);
Self {
globals: renderer.create_consts(&[Globals::default()]).unwrap(),
camera: Camera::new(resolution.x / resolution.y),
skybox: Skybox {
model: renderer.create_model(&create_skybox_mesh()).unwrap(),
locals: renderer.create_consts(&[SkyboxLocals::default()]).unwrap(),
},
postprocess: PostProcess {
model: renderer.create_model(&create_pp_mesh()).unwrap(),
locals: renderer
.create_consts(&[PostProcessLocals::default()])
.unwrap(),
},
figure_model_cache: FigureModelCache::new(),
figure_state: FigureState::new(renderer, CharacterSkeleton::new()),
backdrop_model: renderer.create_model(&FigureModelCache::load_mesh("knight.vox", Vec3::zero())).unwrap(),
backdrop_state: FigureState::new(renderer, CharacterSkeleton::new()),
}
}
pub fn maintain(&mut self, renderer: &mut Renderer, client: &Client) {
self.camera.set_focus_pos(Vec3::unit_z() * 1.75);
self.camera.update(client.state().get_time());
self.camera.set_distance(4.0);
self.camera.set_orientation(Vec3::new(
client.state().get_time() as f32 * 0.2,
0.3,
0.0,
));
let (view_mat, proj_mat, cam_pos) = self.camera.compute_dependents(client);
renderer.update_consts(
&mut self.globals,
&[Globals::new(
view_mat,
proj_mat,
cam_pos,
self.camera.get_focus_pos(),
100.0,
client.state().get_time_of_day(),
client.state().get_time(),
renderer.get_resolution(),
)],
);
self.figure_model_cache.clean(client.get_tick());
let tgt_skeleton = IdleAnimation::update_skeleton(
self.figure_state.skeleton_mut(),
client.state().get_time(),
client.state().get_time(),
);
self.figure_state.skeleton_mut().interpolate(&tgt_skeleton);
self.figure_state.update(renderer, Vec3::zero(), -Vec3::unit_y());
}
pub fn render(&mut self, renderer: &mut Renderer, client: &Client) {
renderer.render_skybox(&self.skybox.model, &self.globals, &self.skybox.locals);
let model = self.figure_model_cache.get_or_create_model(
renderer,
Character::random(),
client.get_tick(),
);
renderer.render_figure(
model,
&self.globals,
self.figure_state.locals(),
self.figure_state.bone_consts(),
);
renderer.render_figure(
&self.backdrop_model,
&self.globals,
self.backdrop_state.locals(),
self.backdrop_state.bone_consts(),
);
renderer.render_post_process(
&self.postprocess.model,
&self.globals,
&self.postprocess.locals,
);
}
}

View File

@ -155,7 +155,6 @@ widget_ids! {
warpaint_slider_indicator,
warpaint_slider_range,
warpaint_slider_text,
}
}
@ -316,13 +315,13 @@ impl CharSelectionUi {
// Background Image
if !self.character_creation {
Image::new(self.imgs.bg_selection)
.middle_of(ui_widgets.window)
.set(self.ids.bg_selection, ui_widgets);
//Image::new(self.imgs.bg_selection)
// .middle_of(ui_widgets.window)
// .set(self.ids.bg_selection, ui_widgets);
// Logout_Button
if Button::image(self.imgs.button)
.bottom_left_with_margins_on(self.ids.bg_selection, 10.0, 10.0)
.bottom_left_with_margins_on(ui_widgets.window, 10.0, 10.0)
.w_h(150.0, 40.0)
.hover_image(self.imgs.button_hover)
.press_image(self.imgs.button_press)
@ -338,7 +337,7 @@ impl CharSelectionUi {
// Create Character Button
if Button::image(self.imgs.button)
.mid_bottom_with_margin_on(self.ids.bg_selection, 10.0)
.mid_bottom_with_margin_on(ui_widgets.window, 10.0)
.w_h(270.0, 50.0)
.hover_image(self.imgs.button_hover)
.press_image(self.imgs.button_press)
@ -354,7 +353,7 @@ impl CharSelectionUi {
}
// Test Characters
if Button::image(self.imgs.test_char_l_button)
.bottom_left_with_margins_on(self.ids.bg_selection, 395.0, 716.0)
.bottom_left_with_margins_on(ui_widgets.window, 395.0, 716.0)
.w_h(95.0, 130.0)
.hover_image(self.imgs.test_char_l_button)
.press_image(self.imgs.test_char_l_button)
@ -376,7 +375,7 @@ impl CharSelectionUi {
.set(self.ids.version, ui_widgets);
// Click Character to Login <-- Temporary!
Image::new(self.imgs.window_frame_2)
.mid_top_with_margin_on(self.ids.bg_selection, 60.0)
.mid_top_with_margin_on(ui_widgets.window, 60.0)
.w_h(700.0, 70.0)
.set(self.ids.help_text_bg, ui_widgets);
Text::new("Click character to select it")
@ -446,12 +445,13 @@ impl CharSelectionUi {
// Character_Creation //////////////
else {
// Background
Image::new(self.imgs.bg_creation)
.middle_of(ui_widgets.window)
.set(self.ids.bg_creation, ui_widgets);
//Image::new(self.imgs.bg_creation)
// .middle_of(ui_widgets.window)
// .set(self.ids.bg_creation, ui_widgets);
// Back Button
if Button::image(self.imgs.button)
.bottom_left_with_margins_on(self.ids.bg_creation, 10.0, 10.0)
.bottom_left_with_margins_on(ui_widgets.window, 10.0, 10.0)
.w_h(150.0, 40.0)
.hover_image(self.imgs.button_hover)
.press_image(self.imgs.button_press)
@ -466,7 +466,7 @@ impl CharSelectionUi {
}
// Create Button
if Button::image(self.imgs.button)
.bottom_right_with_margins_on(self.ids.bg_creation, 10.0, 10.0)
.bottom_right_with_margins_on(ui_widgets.window, 10.0, 10.0)
.w_h(150.0, 40.0)
.hover_image(self.imgs.button_hover)
.press_image(self.imgs.button_press)
@ -482,7 +482,7 @@ impl CharSelectionUi {
}
// Character Name Input
Rectangle::fill_with([320.0, 50.0], color::rgba(0.0, 0.0, 0.0, 0.99))
.mid_bottom_with_margin_on(self.ids.bg_creation, 20.0)
.mid_bottom_with_margin_on(ui_widgets.window, 20.0)
.set(self.ids.name_input_bg, ui_widgets);
Button::image(self.imgs.name_input)
.w_h(337.0, 67.0)
@ -514,7 +514,7 @@ impl CharSelectionUi {
self.imgs.creation_window
})
.w_h(628.0, 814.0)
.top_left_with_margins_on(self.ids.bg_creation, 60.0, 30.0)
.top_left_with_margins_on(ui_widgets.window, 60.0, 30.0)
.set(self.ids.creation_window, ui_widgets);
// Arrows

View File

@ -54,7 +54,14 @@ impl Camera {
) * self.dist),
);
match client.state().terrain().ray(start, end).cast() {
match client
.state()
.terrain()
.ray(start, end)
.ignore_error()
.max_iter(500)
.cast()
{
(d, Ok(Some(_))) => f32::min(d - 1.0, self.dist),
(_, Ok(None)) => self.dist,
(_, Err(_)) => self.dist,
@ -88,12 +95,27 @@ impl Camera {
self.ori.z = (self.ori.z + delta.z) % (2.0 * PI);
}
/// Set the orientation of the camera about its focus
pub fn set_orientation(&mut self, orientation: Vec3<f32>) {
// Wrap camera yaw
self.ori.x = orientation.x % (2.0 * PI);
// Clamp camera pitch to the vertical limits
self.ori.y = orientation.y.min(PI / 2.0).max(-PI / 2.0);
// Wrap camera roll
self.ori.z = orientation.z % (2.0 * PI);
}
/// Zoom the camera by the given delta, limiting the input accordingly.
pub fn zoom_by(&mut self, delta: f32) {
// Clamp camera dist to the 0 <= x <= infinity range
self.tgt_dist = (self.tgt_dist + delta).max(0.0);
}
/// Set the distance of the camera from the target (i.e: zoom)
pub fn set_distance(&mut self, dist: f32) {
self.tgt_dist = dist;
}
pub fn update(&mut self, time: f64) {
// This is horribly frame time dependent, but so is most of the game
let delta = self.last_time.replace(time).map_or(0.0, |t| time - t);

View File

@ -24,31 +24,29 @@ use specs::{Component, Entity as EcsEntity, Join, VecStorage};
use std::{collections::HashMap, f32};
use vek::*;
pub struct FigureCache {
pub struct FigureModelCache {
models: HashMap<Character, (Model<FigurePipeline>, u64)>,
states: HashMap<EcsEntity, FigureState<CharacterSkeleton>>,
}
impl FigureCache {
impl FigureModelCache {
pub fn new() -> Self {
Self {
models: HashMap::new(),
states: HashMap::new(),
}
}
pub fn get_or_create_model<'a>(
models: &'a mut HashMap<Character, (Model<FigurePipeline>, u64)>,
pub fn get_or_create_model(
&mut self,
renderer: &mut Renderer,
tick: u64,
character: Character,
) -> &'a (Model<FigurePipeline>, u64) {
match models.get_mut(&character) {
tick: u64,
) -> &Model<FigurePipeline> {
match self.models.get_mut(&character) {
Some((model, last_used)) => {
*last_used = tick;
}
None => {
models.insert(
self.models.insert(
character,
(
{
@ -90,7 +88,7 @@ impl FigureCache {
}
}
&models[&character]
&self.models[&character].0
}
pub fn clean(&mut self, tick: u64) {
@ -99,7 +97,8 @@ impl FigureCache {
.retain(|_, (_, last_used)| *last_used + 60 > tick);
}
fn load_mesh(filename: &str, position: Vec3<f32>) -> Mesh<FigurePipeline> {
// TODO: Don't make this public
pub fn load_mesh(filename: &str, position: Vec3<f32>) -> Mesh<FigurePipeline> {
let fullpath: String = ["/voxygen/voxel/", filename].concat();
Segment::from(assets::load_expect::<DotVoxData>(fullpath.as_str()).as_ref())
.generate_mesh(position)
@ -187,10 +186,28 @@ impl FigureCache {
Vec3::new(0.0, 0.0, -4.0),
)
}
}
pub fn maintain(&mut self, renderer: &mut Renderer, client: &mut Client) {
pub struct FigureMgr {
model_cache: FigureModelCache,
states: HashMap<EcsEntity, FigureState<CharacterSkeleton>>,
}
impl FigureMgr {
pub fn new() -> Self {
Self {
model_cache: FigureModelCache::new(),
states: HashMap::new(),
}
}
pub fn clean(&mut self, tick: u64) {
self.model_cache.clean(tick);
}
pub fn maintain(&mut self, renderer: &mut Renderer, client: &Client) {
let time = client.state().get_time();
let ecs = client.state_mut().ecs_mut();
let ecs = client.state().ecs();
for (entity, pos, vel, dir, character, animation_history) in (
&ecs.entities(),
&ecs.read_storage::<comp::phys::Pos>(),
@ -208,17 +225,17 @@ impl FigureCache {
let target_skeleton = match animation_history.current {
comp::character::Animation::Idle => IdleAnimation::update_skeleton(
&mut state.skeleton,
state.skeleton_mut(),
time,
animation_history.time,
),
comp::character::Animation::Run => RunAnimation::update_skeleton(
&mut state.skeleton,
state.skeleton_mut(),
(vel.0.magnitude(), time),
animation_history.time,
),
comp::character::Animation::Jump => JumpAnimation::update_skeleton(
&mut state.skeleton,
state.skeleton_mut(),
time,
animation_history.time,
),
@ -229,8 +246,7 @@ impl FigureCache {
state.update(renderer, pos.0, dir.0);
}
self.states
.retain(|entity, _| ecs.entities().is_alive(*entity));
self.states.retain(|entity, _| ecs.entities().is_alive(*entity));
}
pub fn render(
@ -241,13 +257,13 @@ impl FigureCache {
) {
let tick = client.get_tick();
let ecs = client.state().ecs();
let models = &mut self.models;
for (entity, &character) in (&ecs.entities(), &ecs.read_storage::<comp::Character>()).join()
{
let model = Self::get_or_create_model(models, renderer, tick, character);
let state = self.states.get(&entity).unwrap();
renderer.render_figure(&model.0, globals, &state.locals, &state.bone_consts);
if let Some(state) = self.states.get(&entity) {
let model = self.model_cache.get_or_create_model(renderer, character, tick);
renderer.render_figure(model, globals, &state.locals(), state.bone_consts());
}
}
}
}
@ -269,7 +285,7 @@ impl<S: Skeleton> FigureState<S> {
}
}
fn update(&mut self, renderer: &mut Renderer, pos: Vec3<f32>, dir: Vec3<f32>) {
pub fn update(&mut self, renderer: &mut Renderer, pos: Vec3<f32>, dir: Vec3<f32>) {
let mat = Mat4::<f32>::identity()
* Mat4::translation_3d(pos)
* Mat4::rotation_z(-dir.x.atan2(dir.y)); // + f32::consts::PI / 2.0);
@ -281,4 +297,16 @@ impl<S: Skeleton> FigureState<S> {
.update_consts(&mut self.bone_consts, &self.skeleton.compute_matrices())
.unwrap();
}
pub fn locals(&self) -> &Consts<FigureLocals> {
&self.locals
}
pub fn bone_consts(&self) -> &Consts<FigureBoneData> {
&self.bone_consts
}
pub fn skeleton_mut(&mut self) -> &mut S {
&mut self.skeleton
}
}

View File

@ -2,7 +2,10 @@ pub mod camera;
pub mod figure;
pub mod terrain;
use self::{camera::Camera, figure::FigureCache, terrain::Terrain};
use dot_vox;
use vek::*;
use common::{comp, figure::Segment};
use client::Client;
use crate::{
anim::{
character::{CharacterSkeleton, RunAnimation},
@ -15,10 +18,7 @@ use crate::{
},
window::Event,
};
use client::Client;
use common::{comp, figure::Segment};
use dot_vox;
use vek::*;
use self::{camera::Camera, figure::FigureMgr, terrain::Terrain};
// TODO: Don't hard-code this
const CURSOR_PAN_SCALE: f32 = 0.005;
@ -41,7 +41,7 @@ pub struct Scene {
postprocess: PostProcess,
terrain: Terrain,
figure_cache: FigureCache,
figure_mgr: FigureMgr,
}
impl Scene {
@ -64,7 +64,7 @@ impl Scene {
.unwrap(),
},
terrain: Terrain::new(),
figure_cache: FigureCache::new(),
figure_mgr: FigureMgr::new(),
}
}
@ -104,7 +104,7 @@ impl Scene {
}
/// Maintain data such as GPU constant buffers, models, etc. To be called once per tick.
pub fn maintain(&mut self, renderer: &mut Renderer, client: &mut Client) {
pub fn maintain(&mut self, renderer: &mut Renderer, client: &Client) {
// Get player position
let player_pos = client
.state()
@ -144,10 +144,10 @@ impl Scene {
self.terrain.maintain(renderer, client);
// Maintain the figures
self.figure_cache.maintain(renderer, client);
self.figure_mgr.maintain(renderer, client);
// Remove unused figures
self.figure_cache.clean(client.get_tick());
self.figure_mgr.clean(client.get_tick());
}
/// Render the scene using the provided `Renderer`
@ -157,7 +157,7 @@ impl Scene {
// Render terrain and figures
self.terrain.render(renderer, &self.globals);
self.figure_cache.render(renderer, client, &self.globals);
self.figure_mgr.render(renderer, client, &self.globals);
renderer.render_post_process(
&self.postprocess.model,