mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'static_entities' into 'master'
Static entities and lights See merge request veloren/veloren!352
This commit is contained in:
commit
35191c1bdb
BIN
assets/voxygen/voxel/object/bomb.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/object/bomb.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/object/chest_vines.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/object/chest_vines.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/object/pumpkin.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/object/pumpkin.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/object/scarecrow.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/object/scarecrow.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -403,7 +403,9 @@ impl Client {
|
||||
self.state.write_component(entity, pos);
|
||||
self.state.write_component(entity, vel);
|
||||
self.state.write_component(entity, ori);
|
||||
self.state.write_component(entity, action_state);
|
||||
if let Some(a_s) = action_state {
|
||||
self.state.write_component(entity, a_s);
|
||||
}
|
||||
}
|
||||
}
|
||||
ServerMsg::TerrainChunkUpdate { key, chunk } => {
|
||||
|
@ -1,4 +1,5 @@
|
||||
pub mod humanoid;
|
||||
pub mod object;
|
||||
pub mod quadruped;
|
||||
pub mod quadruped_medium;
|
||||
|
||||
@ -9,6 +10,7 @@ pub enum Body {
|
||||
Humanoid(humanoid::Body),
|
||||
Quadruped(quadruped::Body),
|
||||
QuadrupedMedium(quadruped_medium::Body),
|
||||
Object(object::Body),
|
||||
}
|
||||
|
||||
impl Component for Body {
|
||||
|
18
common/src/comp/body/object.rs
Normal file
18
common/src/comp/body/object.rs
Normal file
@ -0,0 +1,18 @@
|
||||
use rand::{seq::SliceRandom, thread_rng};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum Body {
|
||||
Bomb,
|
||||
Scarecrow,
|
||||
Chest,
|
||||
Pumpkin,
|
||||
}
|
||||
|
||||
impl Body {
|
||||
pub fn random() -> Self {
|
||||
let mut rng = thread_rng();
|
||||
*(&ALL_OBJECTS).choose(&mut rng).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
const ALL_OBJECTS: [Body; 4] = [Body::Bomb, Body::Scarecrow, Body::Chest, Body::Pumpkin];
|
@ -8,12 +8,13 @@ mod inventory;
|
||||
mod phys;
|
||||
mod player;
|
||||
mod stats;
|
||||
mod visual;
|
||||
|
||||
// Reexports
|
||||
pub use action_state::ActionState;
|
||||
pub use agent::Agent;
|
||||
pub use animation::{Animation, AnimationInfo};
|
||||
pub use body::{humanoid, quadruped, quadruped_medium, Body};
|
||||
pub use body::{humanoid, object, quadruped, quadruped_medium, Body};
|
||||
pub use controller::Controller;
|
||||
pub use inputs::{
|
||||
Attacking, CanBuild, Gliding, Jumping, MoveDir, OnGround, Respawning, Rolling, Wielding,
|
||||
@ -22,3 +23,4 @@ pub use inventory::{item, Inventory};
|
||||
pub use phys::{ForceUpdate, Ori, Pos, Vel};
|
||||
pub use player::Player;
|
||||
pub use stats::{Dying, HealthSource, Stats};
|
||||
pub use visual::LightEmitter;
|
||||
|
21
common/src/comp/visual.rs
Normal file
21
common/src/comp/visual.rs
Normal file
@ -0,0 +1,21 @@
|
||||
use specs::{Component, FlaggedStorage, VecStorage};
|
||||
use vek::*;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct LightEmitter {
|
||||
pub col: Rgb<f32>,
|
||||
pub strength: f32,
|
||||
}
|
||||
|
||||
impl Default for LightEmitter {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
col: Rgb::one(),
|
||||
strength: 250.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for LightEmitter {
|
||||
type Storage = FlaggedStorage<Self, VecStorage<Self>>;
|
||||
}
|
@ -24,6 +24,7 @@ sphynx::sum_type! {
|
||||
Player(comp::Player),
|
||||
CanBuild(comp::CanBuild),
|
||||
Stats(comp::Stats),
|
||||
LightEmitter(comp::LightEmitter),
|
||||
}
|
||||
}
|
||||
// Automatically derive From<T> for EcsCompPhantom
|
||||
@ -38,6 +39,7 @@ sphynx::sum_type! {
|
||||
Player(PhantomData<comp::Player>),
|
||||
CanBuild(PhantomData<comp::CanBuild>),
|
||||
Stats(PhantomData<comp::Stats>),
|
||||
LightEmitter(PhantomData<comp::LightEmitter>),
|
||||
}
|
||||
}
|
||||
impl sphynx::CompPacket for EcsCompPacket {
|
||||
|
@ -40,7 +40,7 @@ pub enum ServerMsg {
|
||||
pos: comp::Pos,
|
||||
vel: comp::Vel,
|
||||
ori: comp::Ori,
|
||||
action_state: comp::ActionState,
|
||||
action_state: Option<comp::ActionState>,
|
||||
},
|
||||
TerrainChunkUpdate {
|
||||
key: Vec2<i32>,
|
||||
|
@ -130,6 +130,7 @@ impl State {
|
||||
ecs.register_synced::<comp::Player>();
|
||||
ecs.register_synced::<comp::Stats>();
|
||||
ecs.register_synced::<comp::CanBuild>();
|
||||
ecs.register_synced::<comp::LightEmitter>();
|
||||
|
||||
// Register components synced by other means
|
||||
ecs.register::<comp::Pos>();
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
comp::{ActionState, Attacking, Controller, Gliding, OnGround, Rolling, Vel, Wielding},
|
||||
sys::phys::MOVEMENT_THRESHOLD_VEL,
|
||||
sys::movement::MOVEMENT_THRESHOLD_VEL,
|
||||
};
|
||||
use specs::{Entities, Join, ReadStorage, System, WriteStorage};
|
||||
|
||||
|
@ -9,7 +9,7 @@ pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
Entities<'a>,
|
||||
ReadStorage<'a, Controller>,
|
||||
WriteStorage<'a, Controller>,
|
||||
ReadStorage<'a, Stats>,
|
||||
ReadStorage<'a, Vel>,
|
||||
WriteStorage<'a, ActionState>,
|
||||
@ -26,7 +26,7 @@ impl<'a> System<'a> for Sys {
|
||||
&mut self,
|
||||
(
|
||||
entities,
|
||||
controllers,
|
||||
mut controllers,
|
||||
stats,
|
||||
velocities,
|
||||
mut action_states,
|
||||
@ -41,7 +41,7 @@ impl<'a> System<'a> for Sys {
|
||||
) {
|
||||
for (entity, controller, stats, vel, mut a) in (
|
||||
&entities,
|
||||
&controllers,
|
||||
&mut controllers,
|
||||
&stats,
|
||||
&velocities,
|
||||
// Although this is changed, it is only kept for this system
|
||||
@ -113,6 +113,9 @@ impl<'a> System<'a> for Sys {
|
||||
let _ = jumpings.insert(entity, Jumping);
|
||||
a.on_ground = false;
|
||||
}
|
||||
|
||||
// Reset the controller ready for the next tick
|
||||
*controller = Controller::default();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ pub mod agent;
|
||||
pub mod animation;
|
||||
pub mod combat;
|
||||
pub mod controller;
|
||||
pub mod movement;
|
||||
pub mod phys;
|
||||
mod stats;
|
||||
|
||||
@ -14,6 +15,7 @@ const AGENT_SYS: &str = "agent_sys";
|
||||
const CONTROLLER_SYS: &str = "controller_sys";
|
||||
const ACTION_STATE_SYS: &str = "action_state_sys";
|
||||
const PHYS_SYS: &str = "phys_sys";
|
||||
const MOVEMENT_SYS: &str = "movement_sys";
|
||||
const COMBAT_SYS: &str = "combat_sys";
|
||||
const ANIMATION_SYS: &str = "animation_sys";
|
||||
const STATS_SYS: &str = "stats_sys";
|
||||
@ -22,6 +24,7 @@ pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) {
|
||||
dispatch_builder.add(agent::Sys, AGENT_SYS, &[]);
|
||||
dispatch_builder.add(controller::Sys, CONTROLLER_SYS, &[AGENT_SYS]);
|
||||
dispatch_builder.add(phys::Sys, PHYS_SYS, &[CONTROLLER_SYS]);
|
||||
dispatch_builder.add(movement::Sys, MOVEMENT_SYS, &[PHYS_SYS]);
|
||||
dispatch_builder.add(
|
||||
action_state::Sys,
|
||||
ACTION_STATE_SYS,
|
||||
|
138
common/src/sys/movement.rs
Normal file
138
common/src/sys/movement.rs
Normal file
@ -0,0 +1,138 @@
|
||||
use crate::{
|
||||
comp::{ActionState, Jumping, MoveDir, OnGround, Ori, Pos, Rolling, Stats, Vel, Wielding},
|
||||
state::DeltaTime,
|
||||
terrain::TerrainMap,
|
||||
vol::{ReadVol, Vox},
|
||||
};
|
||||
use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, WriteStorage};
|
||||
use vek::*;
|
||||
|
||||
const HUMANOID_ACCEL: f32 = 70.0;
|
||||
const HUMANOID_SPEED: f32 = 120.0;
|
||||
const HUMANOID_AIR_ACCEL: f32 = 10.0;
|
||||
const HUMANOID_AIR_SPEED: f32 = 100.0;
|
||||
const HUMANOID_JUMP_ACCEL: f32 = 16.5;
|
||||
const ROLL_ACCEL: f32 = 120.0;
|
||||
const ROLL_SPEED: f32 = 550.0;
|
||||
const GLIDE_ACCEL: f32 = 15.0;
|
||||
const GLIDE_SPEED: f32 = 45.0;
|
||||
// Gravity is 9.81 * 4, so this makes gravity equal to .15
|
||||
const GLIDE_ANTIGRAV: f32 = 9.81 * 3.95;
|
||||
|
||||
pub const MOVEMENT_THRESHOLD_VEL: f32 = 3.0;
|
||||
|
||||
/// This system applies forces and calculates new positions and velocities.
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
Entities<'a>,
|
||||
ReadExpect<'a, TerrainMap>,
|
||||
Read<'a, DeltaTime>,
|
||||
ReadStorage<'a, MoveDir>,
|
||||
ReadStorage<'a, Stats>,
|
||||
ReadStorage<'a, ActionState>,
|
||||
WriteStorage<'a, Jumping>,
|
||||
WriteStorage<'a, Wielding>,
|
||||
WriteStorage<'a, Rolling>,
|
||||
WriteStorage<'a, OnGround>,
|
||||
WriteStorage<'a, Pos>,
|
||||
WriteStorage<'a, Vel>,
|
||||
WriteStorage<'a, Ori>,
|
||||
);
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
(
|
||||
entities,
|
||||
terrain,
|
||||
dt,
|
||||
move_dirs,
|
||||
stats,
|
||||
action_states,
|
||||
mut jumpings,
|
||||
mut wieldings,
|
||||
mut rollings,
|
||||
mut on_grounds,
|
||||
mut positions,
|
||||
mut velocities,
|
||||
mut orientations,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
// Apply movement inputs
|
||||
for (entity, stats, a, move_dir, mut pos, mut vel, mut ori) in (
|
||||
&entities,
|
||||
&stats,
|
||||
&action_states,
|
||||
move_dirs.maybe(),
|
||||
&mut positions,
|
||||
&mut velocities,
|
||||
&mut orientations,
|
||||
)
|
||||
.join()
|
||||
{
|
||||
// Disable while dead TODO: Replace with client states?
|
||||
if stats.is_dead {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Move player according to move_dir
|
||||
if let Some(move_dir) = move_dir {
|
||||
vel.0 += Vec2::broadcast(dt.0)
|
||||
* move_dir.0
|
||||
* match (a.on_ground, a.gliding, a.rolling) {
|
||||
(true, false, false)
|
||||
if vel.0.magnitude_squared() < HUMANOID_SPEED.powf(2.0) =>
|
||||
{
|
||||
HUMANOID_ACCEL
|
||||
}
|
||||
(false, true, false)
|
||||
if vel.0.magnitude_squared() < GLIDE_SPEED.powf(2.0) =>
|
||||
{
|
||||
GLIDE_ACCEL
|
||||
}
|
||||
(false, false, false)
|
||||
if vel.0.magnitude_squared() < HUMANOID_AIR_SPEED.powf(2.0) =>
|
||||
{
|
||||
HUMANOID_AIR_ACCEL
|
||||
}
|
||||
(true, false, true) if vel.0.magnitude_squared() < ROLL_SPEED.powf(2.0) => {
|
||||
ROLL_ACCEL
|
||||
}
|
||||
|
||||
_ => 0.0,
|
||||
};
|
||||
}
|
||||
|
||||
// Jump
|
||||
if jumpings.get(entity).is_some() {
|
||||
vel.0.z = HUMANOID_JUMP_ACCEL;
|
||||
jumpings.remove(entity);
|
||||
}
|
||||
|
||||
// Glide
|
||||
if a.gliding && vel.0.magnitude_squared() < GLIDE_SPEED.powf(2.0) && vel.0.z < 0.0 {
|
||||
let _ = wieldings.remove(entity);
|
||||
let lift = GLIDE_ANTIGRAV + vel.0.z.powf(2.0) * 0.2;
|
||||
vel.0.z += dt.0 * lift * Vec2::<f32>::from(vel.0 * 0.15).magnitude().min(1.0);
|
||||
}
|
||||
|
||||
// Roll
|
||||
if let Some(time) = rollings.get_mut(entity).map(|r| &mut r.time) {
|
||||
let _ = wieldings.remove(entity);
|
||||
*time += dt.0;
|
||||
if *time > 0.55 || !a.moving {
|
||||
rollings.remove(entity);
|
||||
}
|
||||
}
|
||||
|
||||
// Set direction based on velocity when on the ground
|
||||
if Vec2::<f32>::from(vel.0).magnitude_squared() > 0.1 {
|
||||
ori.0 = Lerp::lerp(
|
||||
ori.0,
|
||||
vel.0.normalized() * Vec3::new(1.0, 1.0, 0.0),
|
||||
10.0 * dt.0,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -10,19 +10,6 @@ use vek::*;
|
||||
const GRAVITY: f32 = 9.81 * 4.0;
|
||||
const FRIC_GROUND: f32 = 0.15;
|
||||
const FRIC_AIR: f32 = 0.015;
|
||||
const HUMANOID_ACCEL: f32 = 70.0;
|
||||
const HUMANOID_SPEED: f32 = 120.0;
|
||||
const HUMANOID_AIR_ACCEL: f32 = 10.0;
|
||||
const HUMANOID_AIR_SPEED: f32 = 100.0;
|
||||
const HUMANOID_JUMP_ACCEL: f32 = 16.5;
|
||||
const ROLL_ACCEL: f32 = 120.0;
|
||||
const ROLL_SPEED: f32 = 550.0;
|
||||
const GLIDE_ACCEL: f32 = 15.0;
|
||||
const GLIDE_SPEED: f32 = 45.0;
|
||||
// Gravity is 9.81 * 4, so this makes gravity equal to .15
|
||||
const GLIDE_ANTIGRAV: f32 = 9.81 * 3.95;
|
||||
|
||||
pub const MOVEMENT_THRESHOLD_VEL: f32 = 3.0;
|
||||
|
||||
// Integrates forces, calculates the new velocity based off of the old velocity
|
||||
// dt = delta time
|
||||
@ -44,12 +31,7 @@ impl<'a> System<'a> for Sys {
|
||||
Entities<'a>,
|
||||
ReadExpect<'a, TerrainMap>,
|
||||
Read<'a, DeltaTime>,
|
||||
ReadStorage<'a, MoveDir>,
|
||||
ReadStorage<'a, Stats>,
|
||||
ReadStorage<'a, ActionState>,
|
||||
WriteStorage<'a, Jumping>,
|
||||
WriteStorage<'a, Wielding>,
|
||||
WriteStorage<'a, Rolling>,
|
||||
WriteStorage<'a, OnGround>,
|
||||
WriteStorage<'a, Pos>,
|
||||
WriteStorage<'a, Vel>,
|
||||
@ -62,12 +44,7 @@ impl<'a> System<'a> for Sys {
|
||||
entities,
|
||||
terrain,
|
||||
dt,
|
||||
move_dirs,
|
||||
stats,
|
||||
action_states,
|
||||
mut jumpings,
|
||||
mut wieldings,
|
||||
mut rollings,
|
||||
mut on_grounds,
|
||||
mut positions,
|
||||
mut velocities,
|
||||
@ -75,81 +52,15 @@ impl<'a> System<'a> for Sys {
|
||||
): Self::SystemData,
|
||||
) {
|
||||
// Apply movement inputs
|
||||
for (entity, stats, a, move_dir, mut pos, mut vel, mut ori) in (
|
||||
for (entity, a, mut pos, mut vel, mut ori) in (
|
||||
&entities,
|
||||
&stats,
|
||||
&action_states,
|
||||
move_dirs.maybe(),
|
||||
&mut positions,
|
||||
&mut velocities,
|
||||
&mut orientations,
|
||||
)
|
||||
.join()
|
||||
{
|
||||
// Disable while dead TODO: Replace with client states?
|
||||
if stats.is_dead {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Move player according to move_dir
|
||||
if let Some(move_dir) = move_dir {
|
||||
vel.0 += Vec2::broadcast(dt.0)
|
||||
* move_dir.0
|
||||
* match (a.on_ground, a.gliding, a.rolling) {
|
||||
(true, false, false)
|
||||
if vel.0.magnitude_squared() < HUMANOID_SPEED.powf(2.0) =>
|
||||
{
|
||||
HUMANOID_ACCEL
|
||||
}
|
||||
(false, true, false)
|
||||
if vel.0.magnitude_squared() < GLIDE_SPEED.powf(2.0) =>
|
||||
{
|
||||
GLIDE_ACCEL
|
||||
}
|
||||
(false, false, false)
|
||||
if vel.0.magnitude_squared() < HUMANOID_AIR_SPEED.powf(2.0) =>
|
||||
{
|
||||
HUMANOID_AIR_ACCEL
|
||||
}
|
||||
(true, false, true) if vel.0.magnitude_squared() < ROLL_SPEED.powf(2.0) => {
|
||||
ROLL_ACCEL
|
||||
}
|
||||
|
||||
_ => 0.0,
|
||||
};
|
||||
}
|
||||
|
||||
// Jump
|
||||
if jumpings.get(entity).is_some() {
|
||||
vel.0.z = HUMANOID_JUMP_ACCEL;
|
||||
jumpings.remove(entity);
|
||||
}
|
||||
|
||||
// Glide
|
||||
if a.gliding && vel.0.magnitude_squared() < GLIDE_SPEED.powf(2.0) && vel.0.z < 0.0 {
|
||||
let _ = wieldings.remove(entity);
|
||||
let lift = GLIDE_ANTIGRAV + vel.0.z.powf(2.0) * 0.2;
|
||||
vel.0.z += dt.0 * lift * Vec2::<f32>::from(vel.0 * 0.15).magnitude().min(1.0);
|
||||
}
|
||||
|
||||
// Roll
|
||||
if let Some(time) = rollings.get_mut(entity).map(|r| &mut r.time) {
|
||||
let _ = wieldings.remove(entity);
|
||||
*time += dt.0;
|
||||
if *time > 0.55 || !a.moving {
|
||||
rollings.remove(entity);
|
||||
}
|
||||
}
|
||||
|
||||
// Set direction based on velocity when on the ground
|
||||
if Vec2::<f32>::from(vel.0).magnitude_squared() > 0.1 {
|
||||
ori.0 = Lerp::lerp(
|
||||
ori.0,
|
||||
vel.0.normalized() * Vec3::new(1.0, 1.0, 0.0),
|
||||
10.0 * dt.0,
|
||||
);
|
||||
}
|
||||
|
||||
// Integrate forces
|
||||
// Friction is assumed to be a constant dependent on location
|
||||
let friction = 50.0 * if a.on_ground { FRIC_GROUND } else { FRIC_AIR };
|
||||
|
@ -130,7 +130,13 @@ lazy_static! {
|
||||
"{}",
|
||||
"/killnpcs : Kill the NPCs",
|
||||
handle_killnpcs,
|
||||
),
|
||||
),
|
||||
ChatCommand::new(
|
||||
"object",
|
||||
"{}",
|
||||
"/object : Spawn a random object",
|
||||
handle_object,
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
@ -444,6 +450,27 @@ fn handle_killnpcs(server: &mut Server, entity: EcsEntity, _args: String, _actio
|
||||
server.clients.notify(entity, ServerMsg::Chat(text));
|
||||
}
|
||||
|
||||
fn handle_object(server: &mut Server, entity: EcsEntity, _args: String, _action: &ChatCommand) {
|
||||
let pos = server
|
||||
.state
|
||||
.ecs()
|
||||
.read_storage::<comp::Pos>()
|
||||
.get(entity)
|
||||
.copied();
|
||||
if let Some(pos) = pos {
|
||||
server
|
||||
.create_object(pos, comp::object::Body::random())
|
||||
.build();
|
||||
server
|
||||
.clients
|
||||
.notify(entity, ServerMsg::Chat(format!("Spawned object.")));
|
||||
} else {
|
||||
server
|
||||
.clients
|
||||
.notify(entity, ServerMsg::Chat(format!("You have no position!")));
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_tell(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
|
||||
let opt_alias = scan_fmt!(&args, action.arg_fmt, String);
|
||||
match opt_alias {
|
||||
|
@ -158,6 +158,25 @@ impl Server {
|
||||
.with(comp::ForceUpdate)
|
||||
}
|
||||
|
||||
/// Build a static object entity
|
||||
#[allow(dead_code)]
|
||||
pub fn create_object(
|
||||
&mut self,
|
||||
pos: comp::Pos,
|
||||
object: comp::object::Body,
|
||||
) -> EcsEntityBuilder {
|
||||
self.state
|
||||
.ecs_mut()
|
||||
.create_entity_synced()
|
||||
.with(pos)
|
||||
.with(comp::Vel(Vec3::zero()))
|
||||
.with(comp::Ori(Vec3::unit_y()))
|
||||
.with(comp::Body::Object(object))
|
||||
.with(comp::LightEmitter::default())
|
||||
.with(comp::ActionState::default())
|
||||
.with(comp::ForceUpdate)
|
||||
}
|
||||
|
||||
pub fn create_player_character(
|
||||
state: &mut State,
|
||||
entity: EcsEntity,
|
||||
@ -645,12 +664,12 @@ impl Server {
|
||||
state.write_component(entity, player);
|
||||
|
||||
// Sync physics
|
||||
for (&uid, &pos, &vel, &ori, &action_state) in (
|
||||
for (&uid, &pos, &vel, &ori, action_state) in (
|
||||
&state.ecs().read_storage::<Uid>(),
|
||||
&state.ecs().read_storage::<comp::Pos>(),
|
||||
&state.ecs().read_storage::<comp::Vel>(),
|
||||
&state.ecs().read_storage::<comp::Ori>(),
|
||||
&state.ecs().read_storage::<comp::ActionState>(),
|
||||
state.ecs().read_storage::<comp::ActionState>().maybe(),
|
||||
)
|
||||
.join()
|
||||
{
|
||||
@ -659,7 +678,7 @@ impl Server {
|
||||
pos,
|
||||
vel,
|
||||
ori,
|
||||
action_state,
|
||||
action_state: action_state.copied(),
|
||||
});
|
||||
}
|
||||
|
||||
@ -743,13 +762,13 @@ impl Server {
|
||||
}
|
||||
|
||||
// Sync physics
|
||||
for (entity, &uid, &pos, &vel, &ori, &action_state, force_update) in (
|
||||
for (entity, &uid, &pos, &vel, &ori, action_state, force_update) in (
|
||||
&self.state.ecs().entities(),
|
||||
&self.state.ecs().read_storage::<Uid>(),
|
||||
&self.state.ecs().read_storage::<comp::Pos>(),
|
||||
&self.state.ecs().read_storage::<comp::Vel>(),
|
||||
&self.state.ecs().read_storage::<comp::Ori>(),
|
||||
&self.state.ecs().read_storage::<comp::ActionState>(),
|
||||
self.state.ecs().read_storage::<comp::ActionState>().maybe(),
|
||||
self.state.ecs().read_storage::<comp::ForceUpdate>().maybe(),
|
||||
)
|
||||
.join()
|
||||
@ -759,7 +778,7 @@ impl Server {
|
||||
pos,
|
||||
vel,
|
||||
ori,
|
||||
action_state,
|
||||
action_state: action_state.copied(),
|
||||
};
|
||||
|
||||
let state = &self.state;
|
||||
|
@ -1,7 +1,6 @@
|
||||
#version 330 core
|
||||
|
||||
#include <globals.glsl>
|
||||
#include <sky.glsl>
|
||||
|
||||
in vec3 f_pos;
|
||||
in vec3 f_norm;
|
||||
@ -23,6 +22,9 @@ uniform u_bones {
|
||||
BoneData bones[16];
|
||||
};
|
||||
|
||||
#include <sky.glsl>
|
||||
#include <light.glsl>
|
||||
|
||||
out vec4 tgt_color;
|
||||
|
||||
void main() {
|
||||
@ -32,7 +34,7 @@ void main() {
|
||||
vec4(f_norm, 0.0)
|
||||
).xyz;
|
||||
|
||||
vec3 light = get_sun_diffuse(world_norm, time_of_day.x);
|
||||
vec3 light = get_sun_diffuse(world_norm, time_of_day.x) + light_at(f_pos, f_norm);
|
||||
vec3 surf_color = model_col.rgb * f_col * 2.0 * light;
|
||||
|
||||
float fog_level = fog(f_pos.xy, focus_pos.xy);
|
||||
|
@ -8,4 +8,5 @@ uniform u_globals {
|
||||
vec4 time_of_day;
|
||||
vec4 tick;
|
||||
vec4 screen_res;
|
||||
uvec4 light_count;
|
||||
};
|
||||
|
32
voxygen/shaders/include/light.glsl
Normal file
32
voxygen/shaders/include/light.glsl
Normal file
@ -0,0 +1,32 @@
|
||||
struct Light {
|
||||
vec4 light_pos;
|
||||
vec4 light_col;
|
||||
};
|
||||
|
||||
layout (std140)
|
||||
uniform u_lights {
|
||||
Light lights[32];
|
||||
};
|
||||
|
||||
float attenuation_strength(vec3 rpos) {
|
||||
return 1.0 / (rpos.x * rpos.x + rpos.y * rpos.y + rpos.z * rpos.z);
|
||||
}
|
||||
|
||||
vec3 light_at(vec3 wpos, vec3 wnorm) {
|
||||
const float LIGHT_AMBIENCE = 0.1;
|
||||
|
||||
vec3 light = vec3(0);
|
||||
for (uint i = 0u; i < light_count.x; i ++) {
|
||||
vec3 light_pos = lights[i].light_pos.xyz;
|
||||
float strength = attenuation_strength(wpos - light_pos);
|
||||
|
||||
if (strength < 0.001) {
|
||||
continue;
|
||||
}
|
||||
|
||||
light += strength
|
||||
* lights[i].light_col.rgb
|
||||
* clamp(dot(normalize(light_pos - wpos), wnorm), LIGHT_AMBIENCE, 1.0);
|
||||
}
|
||||
return light;
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
#version 330 core
|
||||
|
||||
#include <globals.glsl>
|
||||
#include <sky.glsl>
|
||||
|
||||
in vec3 f_pos;
|
||||
flat in uint f_pos_norm;
|
||||
@ -15,6 +14,9 @@ uniform u_locals {
|
||||
|
||||
out vec4 tgt_color;
|
||||
|
||||
#include <sky.glsl>
|
||||
#include <light.glsl>
|
||||
|
||||
void main() {
|
||||
// Calculate normal from packed data
|
||||
vec3 f_norm;
|
||||
@ -28,7 +30,7 @@ void main() {
|
||||
f_norm = vec3(0.0, 0.0, 1.0) * norm_dir;
|
||||
}
|
||||
|
||||
vec3 light = get_sun_diffuse(f_norm, time_of_day.x) * f_light;
|
||||
vec3 light = get_sun_diffuse(f_norm, time_of_day.x) * f_light + light_at(f_pos, f_norm);
|
||||
vec3 surf_color = f_col * light;
|
||||
|
||||
float fog_level = fog(f_pos.xy, focus_pos.xy);
|
||||
|
@ -1,6 +1,7 @@
|
||||
use super::Skeleton;
|
||||
use crate::render::FigureBoneData;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FixtureSkeleton;
|
||||
|
||||
impl FixtureSkeleton {
|
||||
|
@ -1,5 +1,6 @@
|
||||
pub mod character;
|
||||
pub mod fixture;
|
||||
pub mod object;
|
||||
pub mod quadruped;
|
||||
pub mod quadrupedmedium;
|
||||
|
||||
|
39
voxygen/src/anim/object/mod.rs
Normal file
39
voxygen/src/anim/object/mod.rs
Normal file
@ -0,0 +1,39 @@
|
||||
use super::Skeleton;
|
||||
use crate::render::FigureBoneData;
|
||||
use vek::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ObjectSkeleton;
|
||||
|
||||
impl ObjectSkeleton {
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
const SCALE: f32 = 1.0 / 11.0;
|
||||
|
||||
impl Skeleton for ObjectSkeleton {
|
||||
fn compute_matrices(&self) -> [FigureBoneData; 16] {
|
||||
[
|
||||
FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))),
|
||||
FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))),
|
||||
FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))),
|
||||
FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))),
|
||||
FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))),
|
||||
FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))),
|
||||
FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))),
|
||||
FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))),
|
||||
FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))),
|
||||
FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))),
|
||||
FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))),
|
||||
FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))),
|
||||
FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))),
|
||||
FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))),
|
||||
FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))),
|
||||
FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))),
|
||||
]
|
||||
}
|
||||
|
||||
fn interpolate(&mut self, _target: &Self, _dt: f32) {}
|
||||
}
|
@ -5,7 +5,7 @@ use crate::{
|
||||
Animation, Skeleton, SkeletonAttr,
|
||||
},
|
||||
render::{
|
||||
create_pp_mesh, create_skybox_mesh, Consts, FigurePipeline, Globals, Model,
|
||||
create_pp_mesh, create_skybox_mesh, Consts, FigurePipeline, Globals, Light, Model,
|
||||
PostProcessLocals, PostProcessPipeline, Renderer, SkyboxLocals, SkyboxPipeline,
|
||||
},
|
||||
scene::{
|
||||
@ -33,6 +33,7 @@ struct PostProcess {
|
||||
|
||||
pub struct Scene {
|
||||
globals: Consts<Globals>,
|
||||
lights: Consts<Light>,
|
||||
camera: Camera,
|
||||
|
||||
skybox: Skybox,
|
||||
@ -50,6 +51,7 @@ impl Scene {
|
||||
|
||||
Self {
|
||||
globals: renderer.create_consts(&[Globals::default()]).unwrap(),
|
||||
lights: renderer.create_consts(&[Light::default(); 32]).unwrap(),
|
||||
camera: Camera::new(resolution.x / resolution.y),
|
||||
|
||||
skybox: Skybox {
|
||||
@ -99,6 +101,7 @@ impl Scene {
|
||||
55800.0,
|
||||
client.state().get_time(),
|
||||
renderer.get_resolution(),
|
||||
0,
|
||||
)],
|
||||
) {
|
||||
error!("Renderer failed to update: {:?}", err);
|
||||
@ -139,6 +142,7 @@ impl Scene {
|
||||
&self.globals,
|
||||
self.figure_state.locals(),
|
||||
self.figure_state.bone_consts(),
|
||||
&self.lights,
|
||||
);
|
||||
|
||||
renderer.render_figure(
|
||||
@ -146,6 +150,7 @@ impl Scene {
|
||||
&self.globals,
|
||||
self.backdrop_state.locals(),
|
||||
self.backdrop_state.bone_consts(),
|
||||
&self.lights,
|
||||
);
|
||||
|
||||
renderer.render_post_process(
|
||||
|
@ -22,7 +22,7 @@ pub use self::{
|
||||
create_quad as create_ui_quad, create_tri as create_ui_tri, Locals as UiLocals,
|
||||
Mode as UiMode, UiPipeline,
|
||||
},
|
||||
Globals,
|
||||
Globals, Light,
|
||||
},
|
||||
renderer::{Renderer, TgtColorFmt, TgtDepthFmt, WinColorFmt, WinDepthFmt},
|
||||
texture::Texture,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::{
|
||||
super::{util::arr_to_mat, Pipeline, TgtColorFmt, TgtDepthFmt},
|
||||
Globals,
|
||||
Globals, Light,
|
||||
};
|
||||
use gfx::{
|
||||
self,
|
||||
@ -37,6 +37,7 @@ gfx_defines! {
|
||||
locals: gfx::ConstantBuffer<Locals> = "u_locals",
|
||||
globals: gfx::ConstantBuffer<Globals> = "u_globals",
|
||||
bones: gfx::ConstantBuffer<BoneData> = "u_bones",
|
||||
lights: gfx::ConstantBuffer<Light> = "u_lights",
|
||||
|
||||
tgt_color: gfx::RenderTarget<TgtColorFmt> = "tgt_color",
|
||||
tgt_depth: gfx::DepthTarget<TgtDepthFmt> = gfx::preset::depth::LESS_EQUAL_WRITE,
|
||||
|
@ -25,24 +25,16 @@ gfx_defines! {
|
||||
time_of_day: [f32; 4] = "time_of_day", // TODO: Make this f64.
|
||||
tick: [f32; 4] = "tick",
|
||||
screen_res: [f32; 4] = "screen_res",
|
||||
light_count: [u32; 4] = "light_count",
|
||||
}
|
||||
|
||||
constant Light {
|
||||
pos: [f32; 4] = "light_pos",
|
||||
col: [f32; 4] = "light_col",
|
||||
}
|
||||
}
|
||||
|
||||
impl Globals {
|
||||
/// Create global consts with default values.
|
||||
pub fn default() -> Self {
|
||||
Self {
|
||||
view_mat: arr_to_mat(Mat4::identity().into_col_array()),
|
||||
proj_mat: arr_to_mat(Mat4::identity().into_col_array()),
|
||||
cam_pos: [0.0; 4],
|
||||
focus_pos: [0.0; 4],
|
||||
view_distance: [0.0; 4],
|
||||
time_of_day: [0.0; 4],
|
||||
tick: [0.0; 4],
|
||||
screen_res: [800.0, 500.0, 0.0, 0.0],
|
||||
}
|
||||
}
|
||||
|
||||
/// Create global consts from the provided parameters.
|
||||
pub fn new(
|
||||
view_mat: Mat4<f32>,
|
||||
@ -53,6 +45,7 @@ impl Globals {
|
||||
time_of_day: f64,
|
||||
tick: f64,
|
||||
screen_res: Vec2<u16>,
|
||||
light_count: usize,
|
||||
) -> Self {
|
||||
Self {
|
||||
view_mat: arr_to_mat(view_mat.into_col_array()),
|
||||
@ -63,6 +56,38 @@ impl Globals {
|
||||
time_of_day: [time_of_day as f32; 4],
|
||||
tick: [tick as f32; 4],
|
||||
screen_res: Vec4::from(screen_res.map(|e| e as f32)).into_array(),
|
||||
light_count: [light_count as u32; 4],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Globals {
|
||||
fn default() -> Self {
|
||||
Self::new(
|
||||
Mat4::identity(),
|
||||
Mat4::identity(),
|
||||
Vec3::zero(),
|
||||
Vec3::zero(),
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
Vec2::new(800, 500),
|
||||
0,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Light {
|
||||
pub fn new(pos: Vec3<f32>, col: Rgb<f32>, strength: f32) -> Self {
|
||||
Self {
|
||||
pos: Vec4::from(pos).into_array(),
|
||||
col: Rgba::new(col.r, col.g, col.b, strength).into_array(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Light {
|
||||
fn default() -> Self {
|
||||
Self::new(Vec3::zero(), Rgb::zero(), 0.0)
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::{
|
||||
super::{Pipeline, TgtColorFmt, TgtDepthFmt},
|
||||
Globals,
|
||||
Globals, Light,
|
||||
};
|
||||
use gfx::{
|
||||
self,
|
||||
@ -30,6 +30,7 @@ gfx_defines! {
|
||||
|
||||
locals: gfx::ConstantBuffer<Locals> = "u_locals",
|
||||
globals: gfx::ConstantBuffer<Globals> = "u_globals",
|
||||
lights: gfx::ConstantBuffer<Light> = "u_lights",
|
||||
|
||||
tgt_color: gfx::RenderTarget<TgtColorFmt> = "tgt_color",
|
||||
tgt_depth: gfx::DepthTarget<TgtDepthFmt> = gfx::preset::depth::LESS_EQUAL_WRITE,
|
||||
|
@ -3,7 +3,7 @@ use super::{
|
||||
gfx_backend,
|
||||
mesh::Mesh,
|
||||
model::{DynamicModel, Model},
|
||||
pipelines::{figure, postprocess, skybox, terrain, ui, Globals},
|
||||
pipelines::{figure, postprocess, skybox, terrain, ui, Globals, Light},
|
||||
texture::Texture,
|
||||
Pipeline, RenderError,
|
||||
};
|
||||
@ -82,10 +82,15 @@ impl Renderer {
|
||||
env!("CARGO_MANIFEST_DIR"),
|
||||
"/shaders/include/sky.glsl"
|
||||
));
|
||||
let light = include_str!(concat!(
|
||||
env!("CARGO_MANIFEST_DIR"),
|
||||
"/shaders/include/light.glsl"
|
||||
));
|
||||
|
||||
let mut include_ctx = IncludeContext::new();
|
||||
include_ctx.include("globals.glsl", globals);
|
||||
include_ctx.include("sky.glsl", sky);
|
||||
include_ctx.include("light.glsl", light);
|
||||
|
||||
// Construct a pipeline for rendering skyboxes
|
||||
let skybox_pipeline = create_pipeline(
|
||||
@ -389,6 +394,7 @@ impl Renderer {
|
||||
globals: &Consts<Globals>,
|
||||
locals: &Consts<figure::Locals>,
|
||||
bones: &Consts<figure::BoneData>,
|
||||
lights: &Consts<Light>,
|
||||
) {
|
||||
self.encoder.draw(
|
||||
&model.slice,
|
||||
@ -398,6 +404,7 @@ impl Renderer {
|
||||
locals: locals.buf.clone(),
|
||||
globals: globals.buf.clone(),
|
||||
bones: bones.buf.clone(),
|
||||
lights: lights.buf.clone(),
|
||||
tgt_color: self.tgt_color_view.clone(),
|
||||
tgt_depth: self.tgt_depth_view.clone(),
|
||||
},
|
||||
@ -410,6 +417,7 @@ impl Renderer {
|
||||
model: &Model<terrain::TerrainPipeline>,
|
||||
globals: &Consts<Globals>,
|
||||
locals: &Consts<terrain::Locals>,
|
||||
lights: &Consts<Light>,
|
||||
) {
|
||||
self.encoder.draw(
|
||||
&model.slice,
|
||||
@ -418,6 +426,7 @@ impl Renderer {
|
||||
vbuf: model.vbuf.clone(),
|
||||
locals: locals.buf.clone(),
|
||||
globals: globals.buf.clone(),
|
||||
lights: lights.buf.clone(),
|
||||
tgt_color: self.tgt_color_view.clone(),
|
||||
tgt_depth: self.tgt_depth_view.clone(),
|
||||
},
|
||||
|
@ -1,17 +1,17 @@
|
||||
use crate::{
|
||||
anim::{
|
||||
self, character::CharacterSkeleton, quadruped::QuadrupedSkeleton,
|
||||
self, character::CharacterSkeleton, object::ObjectSkeleton, quadruped::QuadrupedSkeleton,
|
||||
quadrupedmedium::QuadrupedMediumSkeleton, Animation, Skeleton, SkeletonAttr,
|
||||
},
|
||||
mesh::Meshable,
|
||||
render::{
|
||||
Consts, FigureBoneData, FigureLocals, FigurePipeline, Globals, Mesh, Model, Renderer,
|
||||
Consts, FigureBoneData, FigureLocals, FigurePipeline, Globals, Light, Mesh, Model, Renderer,
|
||||
},
|
||||
};
|
||||
use client::Client;
|
||||
use common::{
|
||||
assets,
|
||||
comp::{self, humanoid, item::Weapon, quadruped, quadruped_medium, Body},
|
||||
comp::{self, humanoid, item::Weapon, object, quadruped, quadruped_medium, Body},
|
||||
figure::Segment,
|
||||
terrain::TerrainChunkSize,
|
||||
vol::VolSize,
|
||||
@ -105,6 +105,24 @@ impl FigureModelCache {
|
||||
None,
|
||||
None,
|
||||
],
|
||||
Body::Object(object) => [
|
||||
Some(Self::load_object(object)),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
],
|
||||
};
|
||||
|
||||
let skeleton_attr = match body {
|
||||
@ -493,6 +511,18 @@ impl FigureModelCache {
|
||||
Vec3::new(-2.5, -4.0, -2.5),
|
||||
)
|
||||
}
|
||||
|
||||
fn load_object(obj: object::Body) -> Mesh<FigurePipeline> {
|
||||
Self::load_mesh(
|
||||
match obj {
|
||||
object::Body::Bomb => "object/bomb.vox",
|
||||
object::Body::Scarecrow => "object/scarecrow.vox",
|
||||
object::Body::Chest => "object/chest_vines.vox",
|
||||
object::Body::Pumpkin => "object/pumpkin.vox",
|
||||
},
|
||||
Vec3::new(-3.5, -3.5, 0.0),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FigureMgr {
|
||||
@ -500,6 +530,7 @@ pub struct FigureMgr {
|
||||
character_states: HashMap<EcsEntity, FigureState<CharacterSkeleton>>,
|
||||
quadruped_states: HashMap<EcsEntity, FigureState<QuadrupedSkeleton>>,
|
||||
quadruped_medium_states: HashMap<EcsEntity, FigureState<QuadrupedMediumSkeleton>>,
|
||||
object_states: HashMap<EcsEntity, FigureState<ObjectSkeleton>>,
|
||||
}
|
||||
|
||||
impl FigureMgr {
|
||||
@ -509,6 +540,7 @@ impl FigureMgr {
|
||||
character_states: HashMap::new(),
|
||||
quadruped_states: HashMap::new(),
|
||||
quadruped_medium_states: HashMap::new(),
|
||||
object_states: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -534,7 +566,7 @@ impl FigureMgr {
|
||||
&ecs.read_storage::<comp::Vel>(),
|
||||
&ecs.read_storage::<comp::Ori>(),
|
||||
&ecs.read_storage::<comp::Body>(),
|
||||
&ecs.read_storage::<comp::AnimationInfo>(),
|
||||
ecs.read_storage::<comp::AnimationInfo>().maybe(),
|
||||
ecs.read_storage::<comp::Stats>().maybe(),
|
||||
)
|
||||
.join()
|
||||
@ -556,6 +588,9 @@ impl FigureMgr {
|
||||
Body::QuadrupedMedium(_) => {
|
||||
self.quadruped_medium_states.remove(&entity);
|
||||
}
|
||||
Body::Object(_) => {
|
||||
self.object_states.remove(&entity);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
} else if vd_frac > 1.0 {
|
||||
@ -584,6 +619,11 @@ impl FigureMgr {
|
||||
.entry(entity)
|
||||
.or_insert_with(|| FigureState::new(renderer, CharacterSkeleton::new()));
|
||||
|
||||
let animation_info = match animation_info {
|
||||
Some(a_i) => a_i,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
let target_skeleton = match animation_info.animation {
|
||||
comp::Animation::Idle => anim::character::IdleAnimation::update_skeleton(
|
||||
state.skeleton_mut(),
|
||||
@ -654,6 +694,11 @@ impl FigureMgr {
|
||||
.entry(entity)
|
||||
.or_insert_with(|| FigureState::new(renderer, QuadrupedSkeleton::new()));
|
||||
|
||||
let animation_info = match animation_info {
|
||||
Some(a_i) => a_i,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
let target_skeleton = match animation_info.animation {
|
||||
comp::Animation::Run => anim::quadruped::RunAnimation::update_skeleton(
|
||||
state.skeleton_mut(),
|
||||
@ -689,6 +734,11 @@ impl FigureMgr {
|
||||
FigureState::new(renderer, QuadrupedMediumSkeleton::new())
|
||||
});
|
||||
|
||||
let animation_info = match animation_info {
|
||||
Some(a_i) => a_i,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
let target_skeleton = match animation_info.animation {
|
||||
comp::Animation::Run => {
|
||||
anim::quadrupedmedium::RunAnimation::update_skeleton(
|
||||
@ -722,6 +772,15 @@ impl FigureMgr {
|
||||
state.skeleton.interpolate(&target_skeleton, dt);
|
||||
state.update(renderer, pos.0, ori.0, col, dt);
|
||||
}
|
||||
Body::Object(_) => {
|
||||
let state = self
|
||||
.object_states
|
||||
.entry(entity)
|
||||
.or_insert_with(|| FigureState::new(renderer, ObjectSkeleton::new()));
|
||||
|
||||
state.skeleton = state.skeleton_mut().clone();
|
||||
state.update(renderer, pos.0, ori.0, col, dt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -732,6 +791,8 @@ impl FigureMgr {
|
||||
.retain(|entity, _| ecs.entities().is_alive(*entity));
|
||||
self.quadruped_medium_states
|
||||
.retain(|entity, _| ecs.entities().is_alive(*entity));
|
||||
self.object_states
|
||||
.retain(|entity, _| ecs.entities().is_alive(*entity));
|
||||
}
|
||||
|
||||
pub fn render(
|
||||
@ -739,6 +800,7 @@ impl FigureMgr {
|
||||
renderer: &mut Renderer,
|
||||
client: &mut Client,
|
||||
globals: &Consts<Globals>,
|
||||
lights: &Consts<Light>,
|
||||
) {
|
||||
let tick = client.get_tick();
|
||||
let ecs = client.state().ecs();
|
||||
@ -752,25 +814,24 @@ impl FigureMgr {
|
||||
.get(client.entity())
|
||||
.map_or(Vec3::zero(), |pos| pos.0);
|
||||
|
||||
for (entity, _, _, _, body, _, _) in (
|
||||
for (entity, _, _, _, body, _) in (
|
||||
&ecs.entities(),
|
||||
&ecs.read_storage::<comp::Pos>(),
|
||||
&ecs.read_storage::<comp::Vel>(),
|
||||
&ecs.read_storage::<comp::Ori>(),
|
||||
&ecs.read_storage::<comp::Body>(),
|
||||
&ecs.read_storage::<comp::AnimationInfo>(),
|
||||
ecs.read_storage::<comp::Stats>().maybe(),
|
||||
)
|
||||
.join()
|
||||
// Don't render figures outside the vd
|
||||
.filter(|(_, pos, _, _, _, _, _)| {
|
||||
.filter(|(_, pos, _, _, _, _)| {
|
||||
(pos.0 - player_pos)
|
||||
.map2(TerrainChunkSize::SIZE, |d, sz| d.abs() as f32 / sz as f32)
|
||||
.magnitude()
|
||||
< view_distance as f32
|
||||
})
|
||||
// Don't render dead entities
|
||||
.filter(|(_, _, _, _, _, _, stats)| stats.map_or(true, |s| !s.is_dead))
|
||||
.filter(|(_, _, _, _, _, stats)| stats.map_or(true, |s| !s.is_dead))
|
||||
{
|
||||
if let Some((locals, bone_consts)) = match body {
|
||||
Body::Humanoid(_) => self
|
||||
@ -785,13 +846,17 @@ impl FigureMgr {
|
||||
.quadruped_medium_states
|
||||
.get(&entity)
|
||||
.map(|state| (state.locals(), state.bone_consts())),
|
||||
Body::Object(_) => self
|
||||
.object_states
|
||||
.get(&entity)
|
||||
.map(|state| (state.locals(), state.bone_consts())),
|
||||
} {
|
||||
let model = &self
|
||||
.model_cache
|
||||
.get_or_create_model(renderer, *body, tick)
|
||||
.0;
|
||||
|
||||
renderer.render_figure(model, globals, locals, bone_consts);
|
||||
renderer.render_figure(model, globals, locals, bone_consts, lights);
|
||||
} else {
|
||||
warn!("Body has no saved figure");
|
||||
}
|
||||
|
@ -5,18 +5,22 @@ pub mod terrain;
|
||||
use self::{camera::Camera, figure::FigureMgr, terrain::Terrain};
|
||||
use crate::{
|
||||
render::{
|
||||
create_pp_mesh, create_skybox_mesh, Consts, Globals, Model, PostProcessLocals,
|
||||
create_pp_mesh, create_skybox_mesh, Consts, Globals, Light, Model, PostProcessLocals,
|
||||
PostProcessPipeline, Renderer, SkyboxLocals, SkyboxPipeline,
|
||||
},
|
||||
window::Event,
|
||||
};
|
||||
use client::Client;
|
||||
use common::comp;
|
||||
use specs::Join;
|
||||
use vek::*;
|
||||
|
||||
// TODO: Don't hard-code this.
|
||||
const CURSOR_PAN_SCALE: f32 = 0.005;
|
||||
|
||||
const MAX_LIGHT_COUNT: usize = 32;
|
||||
const LIGHT_DIST_RADIUS: f32 = 64.0; // The distance beyond which lights may not be visible
|
||||
|
||||
struct Skybox {
|
||||
model: Model<SkyboxPipeline>,
|
||||
locals: Consts<SkyboxLocals>,
|
||||
@ -29,6 +33,7 @@ struct PostProcess {
|
||||
|
||||
pub struct Scene {
|
||||
globals: Consts<Globals>,
|
||||
lights: Consts<Light>,
|
||||
camera: Camera,
|
||||
|
||||
skybox: Skybox,
|
||||
@ -46,6 +51,7 @@ impl Scene {
|
||||
|
||||
Self {
|
||||
globals: renderer.create_consts(&[Globals::default()]).unwrap(),
|
||||
lights: renderer.create_consts(&[Light::default(); 32]).unwrap(),
|
||||
camera: Camera::new(resolution.x / resolution.y),
|
||||
|
||||
skybox: Skybox {
|
||||
@ -117,8 +123,9 @@ impl Scene {
|
||||
// Alter camera position to match player.
|
||||
let tilt = self.camera.get_orientation().y;
|
||||
let dist = self.camera.get_distance();
|
||||
self.camera
|
||||
.set_focus_pos(player_pos + Vec3::unit_z() * (3.0 - tilt.min(0.0) * dist * 0.75));
|
||||
self.camera.set_focus_pos(
|
||||
player_pos + Vec3::unit_z() * (1.2 + dist * 0.15 - tilt.min(0.0) * dist * 0.75),
|
||||
);
|
||||
|
||||
// Tick camera for interpolation.
|
||||
self.camera.update(client.state().get_time());
|
||||
@ -127,9 +134,35 @@ impl Scene {
|
||||
let (view_mat, proj_mat, cam_pos) = self.camera.compute_dependents(client);
|
||||
|
||||
// Update chunk loaded distance smoothly for nice shader fog
|
||||
let loaded_distance = client.loaded_distance().unwrap_or(0) as f32 * 32.0;
|
||||
let loaded_distance = client.loaded_distance().unwrap_or(0) as f32 * 32.0; // TODO: No magic!
|
||||
self.loaded_distance = (0.98 * self.loaded_distance + 0.02 * loaded_distance).max(0.01);
|
||||
|
||||
// Update light constants
|
||||
let mut lights = (
|
||||
&client.state().ecs().read_storage::<comp::Pos>(),
|
||||
&client.state().ecs().read_storage::<comp::LightEmitter>(),
|
||||
)
|
||||
.join()
|
||||
.filter(|(pos, _)| {
|
||||
(pos.0.distance_squared(player_pos) as f32)
|
||||
< self.loaded_distance.powf(2.0) + LIGHT_DIST_RADIUS
|
||||
})
|
||||
.map(|(pos, light_emitter)| {
|
||||
Light::new(
|
||||
pos.0 + Vec3::unit_z(),
|
||||
light_emitter.col,
|
||||
light_emitter.strength,
|
||||
)
|
||||
}) // TODO: Don't add 1 to z!
|
||||
.collect::<Vec<_>>();
|
||||
lights.sort_by_key(|light| {
|
||||
Vec3::from(Vec4::from(light.pos)).distance_squared(player_pos) as i32
|
||||
});
|
||||
lights.truncate(MAX_LIGHT_COUNT);
|
||||
renderer
|
||||
.update_consts(&mut self.lights, &lights)
|
||||
.expect("Failed to update light constants");
|
||||
|
||||
// Update global constants.
|
||||
renderer
|
||||
.update_consts(
|
||||
@ -143,6 +176,7 @@ impl Scene {
|
||||
client.state().get_time_of_day(),
|
||||
client.state().get_time(),
|
||||
renderer.get_resolution(),
|
||||
lights.len(),
|
||||
)],
|
||||
)
|
||||
.expect("Failed to update global constants");
|
||||
@ -170,8 +204,9 @@ impl Scene {
|
||||
renderer.render_skybox(&self.skybox.model, &self.globals, &self.skybox.locals);
|
||||
|
||||
// Render terrain and figures.
|
||||
self.terrain.render(renderer, &self.globals);
|
||||
self.figure_mgr.render(renderer, client, &self.globals);
|
||||
self.terrain.render(renderer, &self.globals, &self.lights);
|
||||
self.figure_mgr
|
||||
.render(renderer, client, &self.globals, &self.lights);
|
||||
|
||||
renderer.render_post_process(
|
||||
&self.postprocess.model,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
mesh::Meshable,
|
||||
render::{Consts, Globals, Mesh, Model, Renderer, TerrainLocals, TerrainPipeline},
|
||||
render::{Consts, Globals, Light, Mesh, Model, Renderer, TerrainLocals, TerrainPipeline},
|
||||
};
|
||||
use client::Client;
|
||||
use common::{
|
||||
@ -327,10 +327,15 @@ impl Terrain {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(&self, renderer: &mut Renderer, globals: &Consts<Globals>) {
|
||||
pub fn render(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
globals: &Consts<Globals>,
|
||||
lights: &Consts<Light>,
|
||||
) {
|
||||
for (_pos, chunk) in &self.chunks {
|
||||
if chunk.visible {
|
||||
renderer.render_terrain_chunk(&chunk.model, globals, &chunk.locals);
|
||||
renderer.render_terrain_chunk(&chunk.model, globals, &chunk.locals, lights);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user