Moved figure rendering to a better place

Former-commit-id: 51ca948e131c20151c97f9f8454c80c47a9154b0
This commit is contained in:
Joshua Barretto 2019-04-10 22:51:14 +01:00
parent 62b91eb01b
commit 11630877e3
6 changed files with 119 additions and 118 deletions

View File

@ -67,7 +67,6 @@ impl Client {
// Wait for handshake from server // Wait for handshake from server
let (state, player) = match postbox.next_message() { let (state, player) = match postbox.next_message() {
Some(ServerMsg::Handshake { ecs_state, player_entity }) => { Some(ServerMsg::Handshake { ecs_state, player_entity }) => {
println!("STATE PACKAGE! {:?}", ecs_state);
let mut state = State::from_state_package(ecs_state); let mut state = State::from_state_package(ecs_state);
let player_entity = state.ecs().entity_from_uid(player_entity); let player_entity = state.ecs().entity_from_uid(player_entity);
(state, player_entity) (state, player_entity)
@ -99,12 +98,6 @@ impl Client {
#[allow(dead_code)] #[allow(dead_code)]
pub fn thread_pool(&self) -> &threadpool::ThreadPool { &self.thread_pool } pub fn thread_pool(&self) -> &threadpool::ThreadPool { &self.thread_pool }
// TODO: Get rid of this
pub fn with_test_state(mut self) -> Self {
self.chunk = Some(self.world.generate_chunk(Vec3::zero()));
self
}
/// Get a reference to the client's game state. /// Get a reference to the client's game state.
#[allow(dead_code)] #[allow(dead_code)]
pub fn state(&self) -> &State { &self.state } pub fn state(&self) -> &State { &self.state }
@ -158,6 +151,9 @@ impl Client {
const PLAYER_VELOCITY: f32 = 100.0; const PLAYER_VELOCITY: f32 = 100.0;
// TODO: Set acceleration instead // TODO: Set acceleration instead
self.state.write_component(ecs_entity, comp::phys::Vel(Vec3::from(input.move_dir * PLAYER_VELOCITY))); self.state.write_component(ecs_entity, comp::phys::Vel(Vec3::from(input.move_dir * PLAYER_VELOCITY)));
if input.move_dir.magnitude() > 0.01 {
self.state.write_component(ecs_entity, comp::phys::Dir(input.move_dir.normalized().into()));
}
} }
// Tick the client's LocalState (step 3) // Tick the client's LocalState (step 3)
@ -207,10 +203,7 @@ impl Client {
ServerMsg::Pong => {}, ServerMsg::Pong => {},
ServerMsg::Chat(msg) => frontend_events.push(Event::Chat(msg)), ServerMsg::Chat(msg) => frontend_events.push(Event::Chat(msg)),
ServerMsg::SetPlayerEntity(uid) => self.player = Some(self.state.ecs().entity_from_uid(uid).unwrap()), // TODO: Don't unwrap here! ServerMsg::SetPlayerEntity(uid) => self.player = Some(self.state.ecs().entity_from_uid(uid).unwrap()), // TODO: Don't unwrap here!
ServerMsg::EcsSync(sync_package) => { ServerMsg::EcsSync(sync_package) => self.state.ecs_mut().sync_with_package(sync_package),
println!("SYNC PACKAGE! {:?}", sync_package);
self.state.ecs_mut().sync_with_package(sync_package)
},
} }
} }
} else if let Some(err) = self.postbox.error() { } else if let Some(err) = self.postbox.error() {

View File

@ -182,6 +182,9 @@ impl Server {
// Write client components // Write client components
state.write_component(client.entity, player); state.write_component(client.entity, player);
state.write_component(client.entity, comp::phys::Pos(Vec3::zero()));
state.write_component(client.entity, comp::phys::Vel(Vec3::zero()));
state.write_component(client.entity, comp::phys::Dir(Vec3::unit_y()));
if let Some(character) = character { if let Some(character) = character {
state.write_component(client.entity, character); state.write_component(client.entity, character);
} }

View File

@ -25,7 +25,7 @@ impl Bone {
} }
} }
pub trait Skeleton { pub trait Skeleton: Send + Sync + 'static {
fn compute_matrices(&self) -> [FigureBoneData; 16]; fn compute_matrices(&self) -> [FigureBoneData; 16];
} }

View File

@ -1,5 +1,14 @@
use specs::{Component, VecStorage}; use std::{
collections::HashMap,
f32,
};
use specs::{Entity as EcsEntity, Component, VecStorage, Join};
use vek::*; use vek::*;
use client::Client;
use common::{
comp,
figure::Segment,
};
use crate::{ use crate::{
Error, Error,
render::{ render::{
@ -12,42 +21,50 @@ use crate::{
FigureBoneData, FigureBoneData,
FigureLocals, FigureLocals,
}, },
anim::Skeleton, anim::{
Animation,
Skeleton,
character::{
CharacterSkeleton,
RunAnimation,
},
},
mesh::Meshable,
}; };
pub struct Figure<S: Skeleton> { pub struct Figures {
// GPU data test_model: Model<FigurePipeline>,
model: Model<FigurePipeline>, states: HashMap<EcsEntity, FigureState<CharacterSkeleton>>,
bone_consts: Consts<FigureBoneData>,
locals: Consts<FigureLocals>,
// CPU data
bone_meshes: [Option<Mesh<FigurePipeline>>; 16],
pub skeleton: S,
} }
impl<S: Skeleton> Figure<S> { impl Figures {
pub fn new( pub fn new(renderer: &mut Renderer) -> Self {
renderer: &mut Renderer, // TODO: Make a proper asset loading system
bone_meshes: [Option<Mesh<FigurePipeline>>; 16], fn load_segment(filename: &'static str) -> Segment {
skeleton: S, Segment::from(dot_vox::load(&(concat!(env!("CARGO_MANIFEST_DIR"), "/../assets/voxygen/voxel/").to_string() + filename)).unwrap())
) -> Result<Self, Error> {
let mut this = Self {
model: renderer.create_model(&Mesh::new())?,
bone_consts: renderer.create_consts(&skeleton.compute_matrices())?,
locals: renderer.create_consts(&[FigureLocals::default()])?,
bone_meshes,
skeleton,
};
this.update_model(renderer)?;
Ok(this)
} }
pub fn update_model(&mut self, renderer: &mut Renderer) -> Result<(), Error> { let bone_meshes = [
let mut mesh = Mesh::new(); Some(load_segment("head.vox").generate_mesh(Vec3::new(-7.0, -6.5, -6.0))),
Some(load_segment("chest.vox").generate_mesh(Vec3::new(-6.0, -3.0, 0.0))),
Some(load_segment("belt.vox").generate_mesh(Vec3::new(-5.0, -3.0, 0.0))),
Some(load_segment("pants.vox").generate_mesh(Vec3::new(-5.0, -3.0, 0.0))),
Some(load_segment("hand.vox").generate_mesh(Vec3::new(-2.0, -2.0, -1.0))),
Some(load_segment("hand.vox").generate_mesh(Vec3::new(-2.0, -2.0, -1.0))),
Some(load_segment("foot.vox").generate_mesh(Vec3::new(-2.5, -3.0, -2.0))),
Some(load_segment("foot.vox").generate_mesh(Vec3::new(-2.5, -3.0, -2.0))),
Some(load_segment("sword.vox").generate_mesh(Vec3::new(-6.5, -1.0, 0.0))),
None,
None,
None,
None,
None,
None,
None,
];
self.bone_meshes let mut mesh = Mesh::new();
bone_meshes
.iter() .iter()
.enumerate() .enumerate()
.filter_map(|(i, bm)| bm.as_ref().map(|bm| (i, bm))) .filter_map(|(i, bm)| bm.as_ref().map(|bm| (i, bm)))
@ -55,39 +72,69 @@ impl<S: Skeleton> Figure<S> {
mesh.push_mesh_map(bone_mesh, |vert| vert.with_bone_idx(i as u8)) mesh.push_mesh_map(bone_mesh, |vert| vert.with_bone_idx(i as u8))
}); });
self.model = renderer.create_model(&mesh)?; Self {
Ok(()) test_model: renderer.create_model(&mesh).unwrap(),
states: HashMap::new(),
}
} }
pub fn update_skeleton(&mut self, renderer: &mut Renderer) -> Result<(), Error> { pub fn maintain(&mut self, renderer: &mut Renderer, client: &mut Client) {
renderer.update_consts(&mut self.bone_consts, &self.skeleton.compute_matrices())?; let time = client.state().get_time();
Ok(()) let ecs = client.state_mut().ecs_mut().internal_mut();
for (entity, pos, dir, character) in (
&ecs.entities(),
&ecs.read_storage::<comp::phys::Pos>(),
&ecs.read_storage::<comp::phys::Dir>(),
&ecs.read_storage::<comp::Character>(),
).join() {
let state = self.states
.entry(entity)
.or_insert_with(|| FigureState::new(renderer, CharacterSkeleton::new()));
state.update(renderer, pos.0, dir.0);
RunAnimation::update_skeleton(&mut state.skeleton, time);
} }
pub fn update_locals(&mut self, renderer: &mut Renderer, locals: FigureLocals) -> Result<(), Error> { self.states.retain(|entity, _| ecs.entities().is_alive(*entity));
renderer.update_consts(&mut self.locals, &[locals])?;
Ok(())
} }
pub fn render(&self, renderer: &mut Renderer, globals: &Consts<Globals>) { pub fn render(&self, renderer: &mut Renderer, client: &Client, globals: &Consts<Globals>) {
for state in self.states.values() {
renderer.render_figure( renderer.render_figure(
&self.model, &self.test_model,
globals, globals,
&self.locals, &state.locals,
&self.bone_consts, &state.bone_consts,
); );
} }
}
} }
/* pub struct FigureState<S: Skeleton> {
#[derive(Copy, Clone, Debug)]
pub struct Figure<S: Skeleton> {
bone_consts: Consts<FigureBoneData>, bone_consts: Consts<FigureBoneData>,
locals: Consts<FigureLocals>, locals: Consts<FigureLocals>,
skeleton: S, skeleton: S,
} }
impl<S: Skeleton> Component for Figure<S> { impl<S: Skeleton> FigureState<S> {
type Storage = VecStorage<Self>; pub fn new(renderer: &mut Renderer, skeleton: S) -> Self {
Self {
bone_consts: renderer.create_consts(&skeleton.compute_matrices()).unwrap(),
locals: renderer.create_consts(&[FigureLocals::default()]).unwrap(),
skeleton,
}
}
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.y.atan2(dir.x) + f32::consts::PI / 2.0);
let locals = FigureLocals::new(mat);
renderer.update_consts(&mut self.locals, &[locals]).unwrap();
renderer.update_consts(&mut self.bone_consts, &self.skeleton.compute_matrices()).unwrap();
}
} }
*/

View File

@ -29,7 +29,7 @@ use crate::{
}; };
use self::{ use self::{
camera::Camera, camera::Camera,
figure::Figure, figure::Figures,
terrain::Terrain, terrain::Terrain,
}; };
@ -47,13 +47,7 @@ pub struct Scene {
skybox: Skybox, skybox: Skybox,
terrain: Terrain, terrain: Terrain,
figures: Figures,
test_figure: Figure<CharacterSkeleton>,
}
// TODO: Make a proper asset loading system
fn load_segment(filename: &'static str) -> Segment {
Segment::from(dot_vox::load(&(concat!(env!("CARGO_MANIFEST_DIR"), "/../assets/voxygen/voxel/").to_string() + filename)).unwrap())
} }
impl Scene { impl Scene {
@ -74,30 +68,7 @@ impl Scene {
.unwrap(), .unwrap(),
}, },
terrain: Terrain::new(), terrain: Terrain::new(),
figures: Figures::new(renderer),
test_figure: Figure::new(
renderer,
[
Some(load_segment("head.vox").generate_mesh(Vec3::new(-7.0, -6.5, -6.0))),
Some(load_segment("chest.vox").generate_mesh(Vec3::new(-6.0, -3.0, 0.0))),
Some(load_segment("belt.vox").generate_mesh(Vec3::new(-5.0, -3.0, 0.0))),
Some(load_segment("pants.vox").generate_mesh(Vec3::new(-5.0, -3.0, 0.0))),
Some(load_segment("hand.vox").generate_mesh(Vec3::new(-2.0, -2.0, -1.0))),
Some(load_segment("hand.vox").generate_mesh(Vec3::new(-2.0, -2.0, -1.0))),
Some(load_segment("foot.vox").generate_mesh(Vec3::new(-2.5, -3.0, -2.0))),
Some(load_segment("foot.vox").generate_mesh(Vec3::new(-2.5, -3.0, -2.0))),
Some(load_segment("sword.vox").generate_mesh(Vec3::new(-6.5, -1.0, 0.0))),
None,
None,
None,
None,
None,
None,
None,
],
CharacterSkeleton::new(),
)
.unwrap(),
} }
} }
@ -133,7 +104,7 @@ impl Scene {
} }
/// Maintain data such as GPU constant buffers, models, etc. To be called once per tick. /// Maintain data such as GPU constant buffers, models, etc. To be called once per tick.
pub fn maintain(&mut self, renderer: &mut Renderer, client: &Client) { pub fn maintain(&mut self, renderer: &mut Renderer, client: &mut Client) {
// Get player position // Get player position
let player_pos = client let player_pos = client
.player() .player()
@ -165,24 +136,13 @@ impl Scene {
)]) )])
.expect("Failed to update global constants"); .expect("Failed to update global constants");
// Maintain the terrain // Maintain the terrain and figures
self.terrain.maintain(renderer, client); self.terrain.maintain(renderer, client);
self.figures.maintain(renderer, client);
// TODO: Don't do this here
RunAnimation::update_skeleton(
&mut self.test_figure.skeleton,
client.state().get_time(),
);
// Calculate player model matrix
let model_mat = Mat4::<f32>::translation_3d(player_pos);
self.test_figure.update_locals(renderer, FigureLocals::new(model_mat)).unwrap();
self.test_figure.update_skeleton(renderer).unwrap();
} }
/// Render the scene using the provided `Renderer` /// Render the scene using the provided `Renderer`
pub fn render_to(&self, renderer: &mut Renderer) { pub fn render(&self, renderer: &mut Renderer, client: &Client) {
// Render the skybox first (it appears over everything else so must be rendered first) // Render the skybox first (it appears over everything else so must be rendered first)
renderer.render_skybox( renderer.render_skybox(
&self.skybox.model, &self.skybox.model,
@ -190,10 +150,8 @@ impl Scene {
&self.skybox.locals, &self.skybox.locals,
); );
// Render terrain // Render terrain and figures
self.terrain.render(renderer, &self.globals); self.terrain.render(renderer, &self.globals);
self.figures.render(renderer, client, &self.globals);
// Render the test figure
self.test_figure.render(renderer, &self.globals);
} }
} }

View File

@ -87,7 +87,7 @@ impl SessionState {
renderer.clear(BG_COLOR); renderer.clear(BG_COLOR);
// Render the screen using the global renderer // Render the screen using the global renderer
self.scene.render_to(renderer); self.scene.render(renderer, &self.client.borrow());
// Draw the UI to the screen // Draw the UI to the screen
self.hud.render(renderer); self.hud.render(renderer);
@ -157,7 +157,7 @@ impl PlayState for SessionState {
.expect("Failed to tick the scene"); .expect("Failed to tick the scene");
// Maintain the scene // Maintain the scene
self.scene.maintain(global_state.window.renderer_mut(), &self.client.borrow()); self.scene.maintain(global_state.window.renderer_mut(), &mut self.client.borrow_mut());
// Maintain the UI // Maintain the UI
for event in self.hud.maintain(global_state.window.renderer_mut()) { for event in self.hud.maintain(global_state.window.renderer_mut()) {
match event { match event {