Equipped lanterns now provide an illumination effect.

This commit is contained in:
CapsizeGlimmer 2020-05-04 15:15:31 +00:00 committed by Monty Marz
parent 40ab94673e
commit 4e7f8c686a
52 changed files with 689 additions and 351 deletions

View File

@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Player now starts with a lantern. Equipping/unequipping a lantern has the same effect as the `/lantern` command
- Added music system
- Added zoomable and rotatable minimap
- Added rotating orientation marker to main-map

View File

@ -1,5 +1,12 @@
Item(
name: "Black Lantern",
description: "Used by city guards.",
kind: Lantern(Black0),
kind: Lantern(
(
kind: Black0,
color: (r: 255, g: 190, b: 75),
strength_thousandths: 3000,
flicker_thousandths: 300,
),
),
)

View File

@ -0,0 +1,12 @@
Item(
name: "Cool Blue Lantern",
description: "This lantern is surprisingly cold when lit.",
kind: Lantern(
(
kind: Blue0,
color: (r: 64, g: 127, b: 153),
strength_thousandths: 4000,
flicker_thousandths: 250,
),
),
)

View File

@ -1,5 +1,12 @@
Item(
name: "Lime Zest Lantern",
description: "It has an opening that could fit a ring...",
kind: Lantern(Green0),
kind: Lantern(
(
kind: Green0,
color: (r: 192, g: 255, b: 76),
strength_thousandths: 4000,
flicker_thousandths: 500,
),
),
)

View File

@ -0,0 +1,12 @@
Item(
name: "Red Lantern",
description: "Caution: contents hot",
kind: Lantern(
(
kind: Red0,
color: (r: 255, g: 127, b: 51),
strength_thousandths: 3500,
flicker_thousandths: 1000,
),
),
)

BIN
assets/voxygen/element/icons/lantern_blue-0.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
assets/voxygen/element/icons/lantern_red-0.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -316,6 +316,7 @@ Enjoy your stay in the World of Veloren."#,
"gameinput.climb": "Climb",
"gameinput.climbdown": "Climb Down",
"gameinput.wallleap": "Wall Leap",
"gameinput.togglelantern": "Toggle Lantern",
"gameinput.mount": "Mount",
"gameinput.enter": "Enter",
"gameinput.command": "Command",

View File

@ -61,6 +61,12 @@
Lantern(Green0): Png(
"element.icons.lantern_green-0",
),
Lantern(Blue0): Png(
"element.icons.lantern_blue-0",
),
Lantern(Red0): Png(
"element.icons.lantern_red-0",
),
// Farming Equipment
Tool(Farming(Broom)): VoxTrans(
"voxel.weapon.tool.broom-0",

BIN
assets/voxygen/voxel/armor/lantern/blue-0.vox (Stored with Git LFS) Normal file

Binary file not shown.

BIN
assets/voxygen/voxel/armor/lantern/red-0.vox (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -12,5 +12,13 @@
vox_spec: ("armor.lantern.black-0", (-2.0, -2.0, -7.0)),
color: None
),
Red0: (
vox_spec: ("armor.lantern.red-0", (-2.0, -2.0, -7.0)),
color: None
),
Blue0: (
vox_spec: ("armor.lantern.blue-0", (-2.0, -2.0, -7.0)),
color: None
),
},
))

View File

@ -274,6 +274,11 @@ impl Client {
}
}
pub fn toggle_lantern(&mut self) {
self.postbox
.send_message(ClientMsg::ControlEvent(ControlEvent::ToggleLantern));
}
pub fn is_mounted(&self) -> bool {
self.state
.ecs()

View File

@ -167,7 +167,7 @@ pub fn load_cloned<A: Asset + Clone + 'static>(specifier: &str) -> Result<A, Err
pub fn load_expect<A: Asset + 'static>(specifier: &str) -> Arc<A> {
load(specifier).unwrap_or_else(|err| {
panic!(
"Failed loading essential asset: {} (error={})",
"Failed loading essential asset: {} (error={:?})",
specifier, err
)
})

View File

@ -18,6 +18,7 @@ pub enum InventoryManip {
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum ControlEvent {
ToggleLantern,
Mount(Uid),
Unmount,
InventoryManip(InventoryManip),

View File

@ -13,6 +13,7 @@ use rand::seq::SliceRandom;
use specs::{Component, FlaggedStorage};
use specs_idvs::IDVStorage;
use std::{fs::File, io::BufReader};
use vek::Rgb;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Consumable {
@ -39,11 +40,33 @@ pub enum Ingredient {
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Lantern {
pub enum LanternKind {
Black0 = 1,
Green0 = 2,
Red0 = 3,
Blue0 = 4,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Lantern {
pub kind: LanternKind,
color: Rgb<u32>,
strength_thousandths: u32,
flicker_thousandths: u32,
}
pub const ALL_LANTERNS: [LanternKind; 4] = [
LanternKind::Black0,
LanternKind::Green0,
LanternKind::Red0,
LanternKind::Blue0,
];
impl Lantern {
pub fn strength(&self) -> f32 { self.strength_thousandths as f32 / 1000_f32 }
pub fn color(&self) -> Rgb<f32> { self.color.map(|c| c as f32 / 255.0) }
}
pub const ALL_LANTERNS: [Lantern; 2] = [Lantern::Black0, Lantern::Green0];
fn default_amount() -> u32 { 1 }

View File

@ -3,6 +3,7 @@ pub mod slot;
use crate::assets;
use item::{Consumable, Item, ItemKind};
use rand::{seq::SliceRandom, thread_rng};
use specs::{Component, FlaggedStorage, HashMapStorage};
use specs_idvs::IDVStorage;
use std::ops::Not;
@ -304,6 +305,15 @@ impl Default for Inventory {
};
inventory.push(assets::load_expect_cloned("common.items.cheese"));
inventory.push(assets::load_expect_cloned("common.items.apple"));
let mut rng = thread_rng();
let starter_lantern = [
"common.items.lantern.black_0",
"common.items.lantern.red_0",
"common.items.lantern.blue_0",
]
.choose(&mut rng)
.unwrap();
inventory.push(assets::load_expect_cloned(starter_lantern));
inventory
}
}

View File

@ -6,9 +6,9 @@ lazy_static! {
assets::load_expect_cloned("common.items.debug.possess")
];
}
/// The `Default` inventory should contain two items
/// The `Default` inventory should contain 3 items: cheese, apple, lantern
#[test]
fn create_default_count() { assert_eq!(Inventory::default().count(), 2) }
fn create_default_count() { assert_eq!(Inventory::default().count(), 3) }
/// Attempting to push into a full inventory should return the same item.
#[test]

View File

@ -39,4 +39,4 @@ pub use phys::{Collider, ForceUpdate, Gravity, Mass, Ori, PhysicsState, Pos, Sca
pub use player::Player;
pub use projectile::Projectile;
pub use stats::{Exp, HealthChange, HealthSource, Level, Stats};
pub use visual::LightEmitter;
pub use visual::{LightAnimation, LightEmitter};

View File

@ -4,17 +4,19 @@ use vek::*;
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct LightEmitter {
pub offset: Vec3<f32>,
pub col: Rgb<f32>,
pub strength: f32,
pub flicker: f32,
pub animated: bool,
}
impl Default for LightEmitter {
fn default() -> Self {
Self {
offset: Vec3::zero(),
col: Rgb::one(),
strength: 1.0,
flicker: 0.0,
animated: false,
}
}
}
@ -22,3 +24,24 @@ impl Default for LightEmitter {
impl Component for LightEmitter {
type Storage = FlaggedStorage<Self, IDVStorage<Self>>;
}
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct LightAnimation {
pub offset: Vec3<f32>,
pub col: Rgb<f32>,
pub strength: f32,
}
impl Default for LightAnimation {
fn default() -> Self {
Self {
offset: Vec3::zero(),
col: Rgb::zero(),
strength: 0.0,
}
}
}
impl Component for LightAnimation {
type Storage = FlaggedStorage<Self, IDVStorage<Self>>;
}

View File

@ -86,6 +86,7 @@ pub enum ServerEvent {
entity: EcsEntity,
vel: Vec3<f32>,
},
ToggleLantern(EcsEntity),
Mount(EcsEntity, EcsEntity),
Unmount(EcsEntity),
Possess(Uid, Uid),

View File

@ -135,6 +135,10 @@ impl State {
ecs.register::<comp::Ori>();
ecs.register::<comp::Inventory>();
// Register client-local components
// TODO: only register on the client
ecs.register::<comp::LightAnimation>();
// Register server-local components
// TODO: only register on the server
ecs.register::<comp::Last<comp::Pos>>();

View File

@ -74,6 +74,9 @@ impl<'a> System<'a> for Sys {
}
},
ControlEvent::Unmount => server_emitter.emit(ServerEvent::Unmount(entity)),
ControlEvent::ToggleLantern => {
server_emitter.emit(ServerEvent::ToggleLantern(entity))
},
ControlEvent::InventoryManip(manip) => {
*character_state = CharacterState::Idle;
server_emitter.emit(ServerEvent::InventoryManip(entity, manip))

View File

@ -202,9 +202,9 @@ lazy_static! {
),
ChatCommand::new(
"lantern",
"{}",
"/lantern : adds/remove light near player",
false,
"{} {} {} {}",
"/lantern <strength> [<r> <g> <b>]: Change your lantern's strength and color",
true,
handle_lantern,
),
ChatCommand::new(
@ -847,6 +847,7 @@ fn handle_light(
scan_fmt_some!(&args, action.arg_fmt, f32, f32, f32, f32, f32, f32, f32);
let mut light_emitter = comp::LightEmitter::default();
let mut light_offset_opt = None;
if let (Some(r), Some(g), Some(b)) = (opt_r, opt_g, opt_b) {
let r = r.max(0.0).min(1.0);
@ -855,7 +856,11 @@ fn handle_light(
light_emitter.col = Rgb::new(r, g, b)
};
if let (Some(x), Some(y), Some(z)) = (opt_x, opt_y, opt_z) {
light_emitter.offset = Vec3::new(x, y, z)
light_offset_opt = Some(comp::LightAnimation {
offset: Vec3::new(x, y, z),
col: light_emitter.col,
strength: 0.0,
})
};
if let Some(s) = opt_s {
light_emitter.strength = s.max(0.0)
@ -867,14 +872,18 @@ fn handle_light(
.get(target)
.copied();
if let Some(pos) = pos {
server
let builder = server
.state
.ecs_mut()
.create_entity_synced()
.with(pos)
.with(comp::ForceUpdate)
.with(light_emitter)
.build();
.with(light_emitter);
if let Some(light_offset) = light_offset_opt {
builder.with(light_offset).build();
} else {
builder.build();
}
server.notify_client(client, ServerMsg::private(format!("Spawned object.")));
} else {
server.notify_client(client, ServerMsg::private(format!("You have no position!")));
@ -888,57 +897,39 @@ fn handle_lantern(
args: String,
action: &ChatCommand,
) {
let opt_s = scan_fmt_some!(&args, action.arg_fmt, f32);
if server
.state
.read_storage::<comp::LightEmitter>()
.get(target)
.is_some()
{
if let Some(s) = opt_s {
if let Some(light) = server
.state
.ecs()
.write_storage::<comp::LightEmitter>()
.get_mut(target)
{
light.strength = s.max(0.1).min(10.0);
if let (Some(s), r, g, b) = scan_fmt_some!(&args, action.arg_fmt, f32, f32, f32, f32) {
if let Some(light) = server
.state
.ecs()
.write_storage::<comp::LightEmitter>()
.get_mut(target)
{
light.strength = s.max(0.1).min(10.0);
if let (Some(r), Some(g), Some(b)) = (r, g, b) {
light.col = (
r.max(0.0).min(1.0),
g.max(0.0).min(1.0),
b.max(0.0).min(1.0),
)
.into();
server.notify_client(
client,
ServerMsg::private(String::from("You adjusted flame strength and color.")),
);
} else {
server.notify_client(
client,
ServerMsg::private(String::from("You adjusted flame strength.")),
);
}
} else {
server
.state
.ecs()
.write_storage::<comp::LightEmitter>()
.remove(target);
server.notify_client(
client,
ServerMsg::private(String::from("You put out the lantern.")),
ServerMsg::private(String::from("Please equip a lantern first")),
);
}
} else {
let _ = server
.state
.ecs()
.write_storage::<comp::LightEmitter>()
.insert(target, comp::LightEmitter {
offset: Vec3::new(0.5, 0.2, 0.8),
col: Rgb::new(1.0, 0.75, 0.3),
strength: if let Some(s) = opt_s {
s.max(0.0).min(10.0)
} else {
3.0
},
});
server.notify_client(
client,
ServerMsg::private(String::from("You lit your lantern.")),
);
server.notify_client(client, ServerMsg::private(String::from(action.help_string)));
}
}

View File

@ -79,9 +79,10 @@ pub fn handle_create_waypoint(server: &mut Server, pos: Vec3<f32>) {
.state
.create_object(Pos(pos), comp::object::Body::CampfireLit)
.with(LightEmitter {
offset: Vec3::unit_z() * 0.5,
col: Rgb::new(1.0, 0.65, 0.2),
strength: 2.0,
flicker: 1.0,
animated: true,
})
.with(WaypointArea::default())
.build();

View File

@ -86,6 +86,10 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc
.insert(entity, comp::ForceUpdate)
.err()
.map(|err| error!("Failed to insert ForceUpdate on dead client: {:?}", err));
state
.ecs()
.write_storage::<comp::LightEmitter>()
.remove(entity);
state
.ecs()
.write_storage::<comp::Energy>()

View File

@ -11,6 +11,43 @@ use common::{
use log::error;
use specs::{world::WorldExt, Entity as EcsEntity};
pub fn handle_lantern(server: &mut Server, entity: EcsEntity) {
let ecs = server.state_mut().ecs();
if ecs
.read_storage::<comp::LightEmitter>()
.get(entity)
.map_or(false, |light| light.strength > 0.0)
{
server
.state_mut()
.ecs()
.write_storage::<comp::LightEmitter>()
.remove(entity);
} else {
let lantern_opt = ecs
.read_storage::<comp::Loadout>()
.get(entity)
.and_then(|loadout| loadout.lantern.as_ref())
.and_then(|item| {
if let comp::item::ItemKind::Lantern(l) = item.kind {
Some(l)
} else {
None
}
});
if let Some(lantern) = lantern_opt {
let _ = ecs
.write_storage::<comp::LightEmitter>()
.insert(entity, comp::LightEmitter {
col: lantern.color(),
strength: lantern.strength(),
flicker: 1.0,
animated: true,
});
}
}
}
pub fn handle_mount(server: &mut Server, mounter: EcsEntity, mountee: EcsEntity) {
let state = server.state_mut();

View File

@ -11,9 +11,24 @@ use common::{
};
use log::error;
use rand::Rng;
use specs::{join::Join, world::WorldExt, Builder, Entity as EcsEntity};
use specs::{join::Join, world::WorldExt, Builder, Entity as EcsEntity, WriteStorage};
use vek::Vec3;
pub fn swap_lantern(
storage: &mut WriteStorage<comp::LightEmitter>,
entity: EcsEntity,
lantern: &item::Lantern,
) {
if let Some(light) = storage.get_mut(entity) {
light.strength = lantern.strength();
light.col = lantern.color();
}
}
pub fn snuff_lantern(storage: &mut WriteStorage<comp::LightEmitter>, entity: EcsEntity) {
storage.remove(entity);
}
pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::InventoryManip) {
let state = server.state_mut();
let mut dropped_items = Vec::new();
@ -101,12 +116,19 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
let event = match slot {
Slot::Inventory(slot) => {
use item::ItemKind;
// Check if item is equipable
if inventory.get(slot).map_or(false, |i| match &i.kind {
ItemKind::Tool(_) | ItemKind::Armor { .. } | ItemKind::Lantern(_) => true,
_ => false,
}) {
let (is_equippable, lantern_opt) =
inventory
.get(slot)
.map_or((false, None), |i| match &i.kind {
ItemKind::Tool(_) | ItemKind::Armor { .. } => (true, None),
ItemKind::Lantern(lantern) => (true, Some(lantern)),
_ => (false, None),
});
if is_equippable {
if let Some(loadout) = state.ecs().write_storage().get_mut(entity) {
if let Some(lantern) = lantern_opt {
swap_lantern(&mut state.ecs().write_storage(), entity, lantern);
}
slot::equip(slot, inventory, loadout);
Some(comp::InventoryUpdateEvent::Used)
} else {
@ -191,6 +213,9 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
},
Slot::Equip(slot) => {
if let Some(loadout) = state.ecs().write_storage().get_mut(entity) {
if slot == slot::EquipSlot::Lantern {
snuff_lantern(&mut state.ecs().write_storage(), entity);
}
slot::unequip(slot, inventory, loadout);
Some(comp::InventoryUpdateEvent::Used)
} else {

View File

@ -6,7 +6,7 @@ use entity_creation::{
use entity_manipulation::{
handle_damage, handle_destroy, handle_explosion, handle_land_on_ground, handle_respawn,
};
use interaction::{handle_mount, handle_possess, handle_unmount};
use interaction::{handle_lantern, handle_mount, handle_possess, handle_unmount};
use inventory_manip::handle_inventory;
use player::{handle_client_disconnect, handle_exit_ingame};
use specs::{Entity as EcsEntity, WorldExt};
@ -63,6 +63,7 @@ impl Server {
ServerEvent::LandOnGround { entity, vel } => {
handle_land_on_ground(&self, entity, vel)
},
ServerEvent::ToggleLantern(entity) => handle_lantern(self, entity),
ServerEvent::Mount(mounter, mountee) => handle_mount(self, mounter, mountee),
ServerEvent::Unmount(mounter) => handle_unmount(self, mounter),
ServerEvent::Possess(possessor_uid, possesse_uid) => {

View File

@ -127,7 +127,6 @@ impl StateExt for State {
z_max: 0.9,
})
.with(comp::Gravity(1.0))
//.with(comp::LightEmitter::default())
}
/// Build a projectile

View File

@ -8,6 +8,7 @@ pub use self::{idle::IdleAnimation, jump::JumpAnimation, run::RunAnimation};
use super::{Bone, Skeleton};
use crate::render::FigureBoneData;
use common::comp::{self};
use vek::Vec3;
#[derive(Clone)]
pub struct BipedLargeSkeleton {
@ -49,7 +50,7 @@ impl Skeleton for BipedLargeSkeleton {
fn bone_count(&self) -> usize { 11 }
fn compute_matrices(&self) -> [FigureBoneData; 16] {
fn compute_matrices(&self) -> ([FigureBoneData; 16], Vec3<f32>) {
let upper_torso_mat = self.upper_torso.compute_base_matrix();
let shoulder_l_mat = self.shoulder_l.compute_base_matrix();
let shoulder_r_mat = self.shoulder_r.compute_base_matrix();
@ -57,26 +58,33 @@ impl Skeleton for BipedLargeSkeleton {
let leg_r_mat = self.leg_r.compute_base_matrix();
let torso_mat = self.torso.compute_base_matrix();
[
FigureBoneData::new(torso_mat * upper_torso_mat * self.head.compute_base_matrix()),
FigureBoneData::new(torso_mat * upper_torso_mat),
FigureBoneData::new(
torso_mat * upper_torso_mat * self.lower_torso.compute_base_matrix(),
),
FigureBoneData::new(torso_mat * upper_torso_mat * shoulder_l_mat),
FigureBoneData::new(torso_mat * upper_torso_mat * shoulder_r_mat),
FigureBoneData::new(torso_mat * upper_torso_mat * self.hand_l.compute_base_matrix()),
FigureBoneData::new(torso_mat * upper_torso_mat * self.hand_r.compute_base_matrix()),
FigureBoneData::new(torso_mat * upper_torso_mat * leg_l_mat),
FigureBoneData::new(torso_mat * upper_torso_mat * leg_r_mat),
FigureBoneData::new(self.foot_l.compute_base_matrix()),
FigureBoneData::new(self.foot_r.compute_base_matrix()),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
]
(
[
FigureBoneData::new(torso_mat * upper_torso_mat * self.head.compute_base_matrix()),
FigureBoneData::new(torso_mat * upper_torso_mat),
FigureBoneData::new(
torso_mat * upper_torso_mat * self.lower_torso.compute_base_matrix(),
),
FigureBoneData::new(torso_mat * upper_torso_mat * shoulder_l_mat),
FigureBoneData::new(torso_mat * upper_torso_mat * shoulder_r_mat),
FigureBoneData::new(
torso_mat * upper_torso_mat * self.hand_l.compute_base_matrix(),
),
FigureBoneData::new(
torso_mat * upper_torso_mat * self.hand_r.compute_base_matrix(),
),
FigureBoneData::new(torso_mat * upper_torso_mat * leg_l_mat),
FigureBoneData::new(torso_mat * upper_torso_mat * leg_r_mat),
FigureBoneData::new(self.foot_l.compute_base_matrix()),
FigureBoneData::new(self.foot_r.compute_base_matrix()),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
],
Vec3::default(),
)
}
fn interpolate(&mut self, target: &Self, dt: f32) {

View File

@ -8,6 +8,7 @@ pub use self::{fly::FlyAnimation, idle::IdleAnimation, run::RunAnimation};
use super::{Bone, Skeleton};
use crate::render::FigureBoneData;
use common::comp::{self};
use vek::Vec3;
#[derive(Clone, Default)]
pub struct BirdMediumSkeleton {
@ -29,27 +30,30 @@ impl Skeleton for BirdMediumSkeleton {
fn bone_count(&self) -> usize { 7 }
fn compute_matrices(&self) -> [FigureBoneData; 16] {
fn compute_matrices(&self) -> ([FigureBoneData; 16], Vec3<f32>) {
let torso_mat = self.torso.compute_base_matrix();
[
FigureBoneData::new(torso_mat * self.head.compute_base_matrix()),
FigureBoneData::new(torso_mat),
FigureBoneData::new(torso_mat * self.tail.compute_base_matrix()),
FigureBoneData::new(torso_mat * self.wing_l.compute_base_matrix()),
FigureBoneData::new(torso_mat * self.wing_r.compute_base_matrix()),
FigureBoneData::new(self.leg_l.compute_base_matrix()),
FigureBoneData::new(self.leg_r.compute_base_matrix()),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
]
(
[
FigureBoneData::new(torso_mat * self.head.compute_base_matrix()),
FigureBoneData::new(torso_mat),
FigureBoneData::new(torso_mat * self.tail.compute_base_matrix()),
FigureBoneData::new(torso_mat * self.wing_l.compute_base_matrix()),
FigureBoneData::new(torso_mat * self.wing_r.compute_base_matrix()),
FigureBoneData::new(self.leg_l.compute_base_matrix()),
FigureBoneData::new(self.leg_r.compute_base_matrix()),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
],
Vec3::default(),
)
}
fn interpolate(&mut self, target: &Self, dt: f32) {

View File

@ -8,6 +8,7 @@ pub use self::{idle::IdleAnimation, jump::JumpAnimation, run::RunAnimation};
use super::{Bone, Skeleton};
use crate::render::FigureBoneData;
use common::comp::{self};
use vek::Vec3;
#[derive(Clone)]
pub struct BirdSmallSkeleton {
@ -33,27 +34,30 @@ impl Skeleton for BirdSmallSkeleton {
fn bone_count(&self) -> usize { 4 }
fn compute_matrices(&self) -> [FigureBoneData; 16] {
fn compute_matrices(&self) -> ([FigureBoneData; 16], Vec3<f32>) {
let torso_mat = self.torso.compute_base_matrix();
[
FigureBoneData::new(self.head.compute_base_matrix() * torso_mat),
FigureBoneData::new(torso_mat),
FigureBoneData::new(self.wing_l.compute_base_matrix() * torso_mat),
FigureBoneData::new(self.wing_r.compute_base_matrix() * torso_mat),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
]
(
[
FigureBoneData::new(self.head.compute_base_matrix() * torso_mat),
FigureBoneData::new(torso_mat),
FigureBoneData::new(self.wing_l.compute_base_matrix() * torso_mat),
FigureBoneData::new(self.wing_r.compute_base_matrix() * torso_mat),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
],
Vec3::default(),
)
}
fn interpolate(&mut self, target: &Self, dt: f32) {

View File

@ -31,6 +31,7 @@ pub use self::{
use super::{Bone, Skeleton};
use crate::render::FigureBoneData;
use common::comp;
use vek::{Vec3, Vec4};
#[derive(Clone, Default)]
pub struct CharacterSkeleton {
@ -64,7 +65,7 @@ impl Skeleton for CharacterSkeleton {
fn bone_count(&self) -> usize { 15 }
fn compute_matrices(&self) -> [FigureBoneData; 16] {
fn compute_matrices(&self) -> ([FigureBoneData; 16], Vec3<f32>) {
let chest_mat = self.chest.compute_base_matrix();
let torso_mat = self.torso.compute_base_matrix();
let l_hand_mat = self.l_hand.compute_base_matrix();
@ -76,26 +77,37 @@ impl Skeleton for CharacterSkeleton {
let second_mat = self.second.compute_base_matrix();
let shorts_mat = self.shorts.compute_base_matrix();
let head_mat = self.head.compute_base_matrix();
[
FigureBoneData::new(torso_mat * chest_mat * head_mat),
FigureBoneData::new(torso_mat * chest_mat),
FigureBoneData::new(torso_mat * chest_mat * self.belt.compute_base_matrix()),
FigureBoneData::new(torso_mat * chest_mat * self.back.compute_base_matrix()),
FigureBoneData::new(torso_mat * chest_mat * shorts_mat),
FigureBoneData::new(torso_mat * chest_mat * control_mat * l_control_mat * l_hand_mat),
FigureBoneData::new(torso_mat * chest_mat * control_mat * r_control_mat * r_hand_mat),
FigureBoneData::new(torso_mat * self.l_foot.compute_base_matrix()),
FigureBoneData::new(torso_mat * self.r_foot.compute_base_matrix()),
FigureBoneData::new(torso_mat * chest_mat * self.l_shoulder.compute_base_matrix()),
FigureBoneData::new(torso_mat * chest_mat * self.r_shoulder.compute_base_matrix()),
FigureBoneData::new(torso_mat * self.glider.compute_base_matrix()),
FigureBoneData::new(torso_mat * chest_mat * control_mat * l_control_mat * main_mat),
FigureBoneData::new(torso_mat * chest_mat * control_mat * r_control_mat * second_mat),
FigureBoneData::new(
torso_mat * chest_mat * shorts_mat * self.lantern.compute_base_matrix(),
),
FigureBoneData::default(),
]
let lantern_final_mat =
torso_mat * chest_mat * shorts_mat * self.lantern.compute_base_matrix();
(
[
FigureBoneData::new(torso_mat * chest_mat * head_mat),
FigureBoneData::new(torso_mat * chest_mat),
FigureBoneData::new(torso_mat * chest_mat * self.belt.compute_base_matrix()),
FigureBoneData::new(torso_mat * chest_mat * self.back.compute_base_matrix()),
FigureBoneData::new(torso_mat * chest_mat * shorts_mat),
FigureBoneData::new(
torso_mat * chest_mat * control_mat * l_control_mat * l_hand_mat,
),
FigureBoneData::new(
torso_mat * chest_mat * control_mat * r_control_mat * r_hand_mat,
),
FigureBoneData::new(torso_mat * self.l_foot.compute_base_matrix()),
FigureBoneData::new(torso_mat * self.r_foot.compute_base_matrix()),
FigureBoneData::new(torso_mat * chest_mat * self.l_shoulder.compute_base_matrix()),
FigureBoneData::new(torso_mat * chest_mat * self.r_shoulder.compute_base_matrix()),
FigureBoneData::new(torso_mat * self.glider.compute_base_matrix()),
FigureBoneData::new(torso_mat * chest_mat * control_mat * l_control_mat * main_mat),
FigureBoneData::new(
torso_mat * chest_mat * control_mat * r_control_mat * second_mat,
),
FigureBoneData::new(lantern_final_mat),
FigureBoneData::default(),
],
(lantern_final_mat * Vec4::new(0.0, 0.0, 0.0, 1.0)).xyz(),
)
}
fn interpolate(&mut self, target: &Self, dt: f32) {

View File

@ -8,6 +8,7 @@ pub use self::{idle::IdleAnimation, jump::JumpAnimation, run::RunAnimation};
use super::{Bone, Skeleton};
use crate::render::FigureBoneData;
use common::comp::{self};
use vek::Vec3;
#[derive(Clone, Default)]
pub struct CritterSkeleton {
@ -34,25 +35,28 @@ impl Skeleton for CritterSkeleton {
fn bone_count(&self) -> usize { 5 }
fn compute_matrices(&self) -> [FigureBoneData; 16] {
[
FigureBoneData::new(self.head.compute_base_matrix()),
FigureBoneData::new(self.chest.compute_base_matrix()),
FigureBoneData::new(self.feet_f.compute_base_matrix()),
FigureBoneData::new(self.feet_b.compute_base_matrix()),
FigureBoneData::new(self.tail.compute_base_matrix()),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
]
fn compute_matrices(&self) -> ([FigureBoneData; 16], Vec3<f32>) {
(
[
FigureBoneData::new(self.head.compute_base_matrix()),
FigureBoneData::new(self.chest.compute_base_matrix()),
FigureBoneData::new(self.feet_f.compute_base_matrix()),
FigureBoneData::new(self.feet_b.compute_base_matrix()),
FigureBoneData::new(self.tail.compute_base_matrix()),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
],
Vec3::default(),
)
}
fn interpolate(&mut self, target: &Self, dt: f32) {

View File

@ -8,6 +8,7 @@ pub use self::{idle::IdleAnimation, jump::JumpAnimation, run::RunAnimation};
use super::{Bone, Skeleton};
use crate::render::FigureBoneData;
use common::comp::{self};
use vek::Vec3;
#[derive(Clone)]
pub struct DragonSkeleton {
@ -51,30 +52,33 @@ impl Skeleton for DragonSkeleton {
fn bone_count(&self) -> usize { 13 }
fn compute_matrices(&self) -> [FigureBoneData; 16] {
fn compute_matrices(&self) -> ([FigureBoneData; 16], Vec3<f32>) {
let chest_front_mat = self.chest_front.compute_base_matrix();
let wing_in_l_mat = self.wing_in_l.compute_base_matrix();
let wing_in_r_mat = self.wing_in_r.compute_base_matrix();
let tail_front_mat = self.tail_front.compute_base_matrix();
[
FigureBoneData::new(self.head.compute_base_matrix() * chest_front_mat),
FigureBoneData::new(chest_front_mat),
FigureBoneData::new(self.chest_rear.compute_base_matrix() * chest_front_mat),
FigureBoneData::new(tail_front_mat),
FigureBoneData::new(self.tail_rear.compute_base_matrix() * tail_front_mat),
FigureBoneData::new(wing_in_l_mat),
FigureBoneData::new(wing_in_r_mat),
FigureBoneData::new(self.wing_out_l.compute_base_matrix() * wing_in_l_mat),
FigureBoneData::new(self.wing_out_r.compute_base_matrix() * wing_in_r_mat),
FigureBoneData::new(self.foot_fl.compute_base_matrix()),
FigureBoneData::new(self.foot_fr.compute_base_matrix()),
FigureBoneData::new(self.foot_bl.compute_base_matrix()),
FigureBoneData::new(self.foot_br.compute_base_matrix()),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
]
(
[
FigureBoneData::new(self.head.compute_base_matrix() * chest_front_mat),
FigureBoneData::new(chest_front_mat),
FigureBoneData::new(self.chest_rear.compute_base_matrix() * chest_front_mat),
FigureBoneData::new(tail_front_mat),
FigureBoneData::new(self.tail_rear.compute_base_matrix() * tail_front_mat),
FigureBoneData::new(wing_in_l_mat),
FigureBoneData::new(wing_in_r_mat),
FigureBoneData::new(self.wing_out_l.compute_base_matrix() * wing_in_l_mat),
FigureBoneData::new(self.wing_out_r.compute_base_matrix() * wing_in_r_mat),
FigureBoneData::new(self.foot_fl.compute_base_matrix()),
FigureBoneData::new(self.foot_fr.compute_base_matrix()),
FigureBoneData::new(self.foot_bl.compute_base_matrix()),
FigureBoneData::new(self.foot_br.compute_base_matrix()),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
],
Vec3::default(),
)
}
fn interpolate(&mut self, target: &Self, dt: f32) {

View File

@ -8,6 +8,7 @@ pub use self::{idle::IdleAnimation, jump::JumpAnimation, run::RunAnimation};
use super::{Bone, Skeleton};
use crate::render::FigureBoneData;
use common::comp::{self};
use vek::Vec3;
#[derive(Clone)]
pub struct FishMediumSkeleton {
@ -37,28 +38,31 @@ impl Skeleton for FishMediumSkeleton {
fn bone_count(&self) -> usize { 6 }
fn compute_matrices(&self) -> [FigureBoneData; 16] {
fn compute_matrices(&self) -> ([FigureBoneData; 16], Vec3<f32>) {
let torso_mat = self.torso.compute_base_matrix();
let rear_mat = self.rear.compute_base_matrix();
[
FigureBoneData::new(self.head.compute_base_matrix() * torso_mat),
FigureBoneData::new(torso_mat),
FigureBoneData::new(rear_mat * torso_mat),
FigureBoneData::new(self.tail.compute_base_matrix() * rear_mat),
FigureBoneData::new(self.fin_l.compute_base_matrix() * rear_mat),
FigureBoneData::new(self.fin_r.compute_base_matrix() * rear_mat),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
]
(
[
FigureBoneData::new(self.head.compute_base_matrix() * torso_mat),
FigureBoneData::new(torso_mat),
FigureBoneData::new(rear_mat * torso_mat),
FigureBoneData::new(self.tail.compute_base_matrix() * rear_mat),
FigureBoneData::new(self.fin_l.compute_base_matrix() * rear_mat),
FigureBoneData::new(self.fin_r.compute_base_matrix() * rear_mat),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
],
Vec3::default(),
)
}
fn interpolate(&mut self, target: &Self, dt: f32) {

View File

@ -8,6 +8,7 @@ pub use self::{idle::IdleAnimation, jump::JumpAnimation, run::RunAnimation};
use super::{Bone, Skeleton};
use crate::render::FigureBoneData;
use common::comp::{self};
use vek::Vec3;
#[derive(Clone)]
pub struct FishSmallSkeleton {
@ -29,27 +30,30 @@ impl Skeleton for FishSmallSkeleton {
fn bone_count(&self) -> usize { 2 }
fn compute_matrices(&self) -> [FigureBoneData; 16] {
fn compute_matrices(&self) -> ([FigureBoneData; 16], Vec3<f32>) {
let torso_mat = self.torso.compute_base_matrix();
[
FigureBoneData::new(torso_mat),
FigureBoneData::new(self.tail.compute_base_matrix() * torso_mat),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
]
(
[
FigureBoneData::new(torso_mat),
FigureBoneData::new(self.tail.compute_base_matrix() * torso_mat),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
],
Vec3::default(),
)
}
fn interpolate(&mut self, target: &Self, dt: f32) {

View File

@ -1,5 +1,6 @@
use super::Skeleton;
use crate::render::FigureBoneData;
use vek::Vec3;
#[derive(Clone)]
pub struct FixtureSkeleton;
@ -15,25 +16,28 @@ impl Skeleton for FixtureSkeleton {
fn bone_count(&self) -> usize { 1 }
fn compute_matrices(&self) -> [FigureBoneData; 16] {
[
FigureBoneData::new(vek::Mat4::identity()), // <-- This is actually a bone!
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
]
fn compute_matrices(&self) -> ([FigureBoneData; 16], Vec3<f32>) {
(
[
FigureBoneData::new(vek::Mat4::identity()), // <-- This is actually a bone!
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
],
Vec3::default(),
)
}
fn interpolate(&mut self, _target: &Self, _dt: f32) {}

View File

@ -8,6 +8,7 @@ pub use self::{idle::IdleAnimation, jump::JumpAnimation, run::RunAnimation};
use super::{Bone, Skeleton};
use crate::render::FigureBoneData;
use common::comp::{self};
use vek::Vec3;
#[derive(Clone)]
pub struct GolemSkeleton {
@ -45,7 +46,7 @@ impl GolemSkeleton {
impl Skeleton for GolemSkeleton {
type Attr = SkeletonAttr;
fn compute_matrices(&self) -> [FigureBoneData; 16] {
fn compute_matrices(&self) -> ([FigureBoneData; 16], Vec3<f32>) {
let upper_torso_mat = self.upper_torso.compute_base_matrix();
let shoulder_l_mat = self.shoulder_l.compute_base_matrix();
let shoulder_r_mat = self.shoulder_r.compute_base_matrix();
@ -54,24 +55,31 @@ impl Skeleton for GolemSkeleton {
let torso_mat = self.torso.compute_base_matrix();
let foot_l_mat = self.foot_l.compute_base_matrix();
let foot_r_mat = self.foot_r.compute_base_matrix();
[
FigureBoneData::new(torso_mat * upper_torso_mat * self.head.compute_base_matrix()),
FigureBoneData::new(torso_mat * upper_torso_mat),
FigureBoneData::new(torso_mat * upper_torso_mat * shoulder_l_mat),
FigureBoneData::new(torso_mat * upper_torso_mat * shoulder_r_mat),
FigureBoneData::new(torso_mat * upper_torso_mat * self.hand_l.compute_base_matrix()),
FigureBoneData::new(torso_mat * upper_torso_mat * self.hand_r.compute_base_matrix()),
FigureBoneData::new(foot_l_mat * leg_l_mat),
FigureBoneData::new(foot_r_mat * leg_r_mat),
FigureBoneData::new(foot_l_mat),
FigureBoneData::new(foot_r_mat),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
]
(
[
FigureBoneData::new(torso_mat * upper_torso_mat * self.head.compute_base_matrix()),
FigureBoneData::new(torso_mat * upper_torso_mat),
FigureBoneData::new(torso_mat * upper_torso_mat * shoulder_l_mat),
FigureBoneData::new(torso_mat * upper_torso_mat * shoulder_r_mat),
FigureBoneData::new(
torso_mat * upper_torso_mat * self.hand_l.compute_base_matrix(),
),
FigureBoneData::new(
torso_mat * upper_torso_mat * self.hand_r.compute_base_matrix(),
),
FigureBoneData::new(foot_l_mat * leg_l_mat),
FigureBoneData::new(foot_r_mat * leg_r_mat),
FigureBoneData::new(foot_l_mat),
FigureBoneData::new(foot_r_mat),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
],
Vec3::default(),
)
}
fn interpolate(&mut self, target: &Self, dt: f32) {

View File

@ -54,7 +54,7 @@ pub trait Skeleton: Send + Sync + 'static {
fn bone_count(&self) -> usize { 16 }
fn compute_matrices(&self) -> [FigureBoneData; 16];
fn compute_matrices(&self) -> ([FigureBoneData; 16], Vec3<f32>);
/// Change the current skeleton to be more like `target`.
fn interpolate(&mut self, target: &Self, dt: f32);

View File

@ -17,25 +17,28 @@ impl Skeleton for ObjectSkeleton {
fn bone_count(&self) -> usize { 1 }
fn compute_matrices(&self) -> [FigureBoneData; 16] {
[
FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
]
fn compute_matrices(&self) -> ([FigureBoneData; 16], Vec3<f32>) {
(
[
FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
],
Vec3::default(),
)
}
fn interpolate(&mut self, _target: &Self, _dt: f32) {}

View File

@ -8,6 +8,7 @@ pub use self::{idle::IdleAnimation, jump::JumpAnimation, run::RunAnimation};
use super::{Bone, Skeleton};
use crate::render::FigureBoneData;
use common::comp::{self};
use vek::Vec3;
#[derive(Clone, Default)]
pub struct QuadrupedMediumSkeleton {
@ -33,29 +34,32 @@ impl Skeleton for QuadrupedMediumSkeleton {
fn bone_count(&self) -> usize { 11 }
fn compute_matrices(&self) -> [FigureBoneData; 16] {
fn compute_matrices(&self) -> ([FigureBoneData; 16], Vec3<f32>) {
let ears_mat = self.ears.compute_base_matrix();
let head_upper_mat = self.head_upper.compute_base_matrix();
let head_lower_mat = self.head_lower.compute_base_matrix();
let torso_mid_mat = self.torso_mid.compute_base_matrix();
[
FigureBoneData::new(head_upper_mat),
FigureBoneData::new(head_upper_mat * head_lower_mat),
FigureBoneData::new(head_upper_mat * self.jaw.compute_base_matrix()),
FigureBoneData::new(torso_mid_mat * self.tail.compute_base_matrix()),
FigureBoneData::new(self.torso_back.compute_base_matrix()),
FigureBoneData::new(torso_mid_mat),
FigureBoneData::new(head_upper_mat * ears_mat),
FigureBoneData::new(self.foot_lf.compute_base_matrix()),
FigureBoneData::new(self.foot_rf.compute_base_matrix()),
FigureBoneData::new(self.foot_lb.compute_base_matrix()),
FigureBoneData::new(self.foot_rb.compute_base_matrix()),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
]
(
[
FigureBoneData::new(head_upper_mat),
FigureBoneData::new(head_upper_mat * head_lower_mat),
FigureBoneData::new(head_upper_mat * self.jaw.compute_base_matrix()),
FigureBoneData::new(torso_mid_mat * self.tail.compute_base_matrix()),
FigureBoneData::new(self.torso_back.compute_base_matrix()),
FigureBoneData::new(torso_mid_mat),
FigureBoneData::new(head_upper_mat * ears_mat),
FigureBoneData::new(self.foot_lf.compute_base_matrix()),
FigureBoneData::new(self.foot_rf.compute_base_matrix()),
FigureBoneData::new(self.foot_lb.compute_base_matrix()),
FigureBoneData::new(self.foot_rb.compute_base_matrix()),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
],
Vec3::default(),
)
}
fn interpolate(&mut self, target: &Self, dt: f32) {

View File

@ -8,6 +8,7 @@ pub use self::{idle::IdleAnimation, jump::JumpAnimation, run::RunAnimation};
use super::{Bone, Skeleton};
use crate::render::FigureBoneData;
use common::comp::{self};
use vek::Vec3;
#[derive(Clone, Default)]
pub struct QuadrupedSmallSkeleton {
@ -28,25 +29,28 @@ impl Skeleton for QuadrupedSmallSkeleton {
fn bone_count(&self) -> usize { 6 }
fn compute_matrices(&self) -> [FigureBoneData; 16] {
[
FigureBoneData::new(self.head.compute_base_matrix()),
FigureBoneData::new(self.chest.compute_base_matrix()),
FigureBoneData::new(self.leg_lf.compute_base_matrix()),
FigureBoneData::new(self.leg_rf.compute_base_matrix()),
FigureBoneData::new(self.leg_lb.compute_base_matrix()),
FigureBoneData::new(self.leg_rb.compute_base_matrix()),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
]
fn compute_matrices(&self) -> ([FigureBoneData; 16], Vec3<f32>) {
(
[
FigureBoneData::new(self.head.compute_base_matrix()),
FigureBoneData::new(self.chest.compute_base_matrix()),
FigureBoneData::new(self.leg_lf.compute_base_matrix()),
FigureBoneData::new(self.leg_rf.compute_base_matrix()),
FigureBoneData::new(self.leg_lb.compute_base_matrix()),
FigureBoneData::new(self.leg_rb.compute_base_matrix()),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
],
Vec3::default(),
)
}
fn interpolate(&mut self, target: &Self, dt: f32) {

View File

@ -106,6 +106,9 @@ impl From<&crate::settings::GamepadSettings> for ControllerSettings {
/*map.entry(settings.game_buttons.wall_leap)
.or_default()
.push(GameInput::WallLeap);*/
map.entry(settings.game_buttons.toggle_lantern)
.or_default()
.push(GameInput::ToggleLantern);
map.entry(settings.game_buttons.mount)
.or_default()
.push(GameInput::Mount);

View File

@ -4,7 +4,7 @@ use common::{
comp::item::{
armor::Armor,
tool::{Tool, ToolKind},
Consumable, Ingredient, Item, ItemKind, Lantern, Utility,
Consumable, Ingredient, Item, ItemKind, Lantern, LanternKind, Utility,
},
figure::Segment,
};
@ -20,7 +20,7 @@ use vek::*;
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ItemKey {
Tool(ToolKind),
Lantern(Lantern),
Lantern(LanternKind),
Armor(Armor),
Utility(Utility),
Consumable(Consumable),
@ -31,7 +31,7 @@ impl From<&Item> for ItemKey {
fn from(item: &Item) -> Self {
match &item.kind {
ItemKind::Tool(Tool { kind, .. }) => ItemKey::Tool(kind.clone()),
ItemKind::Lantern(kind) => ItemKey::Lantern(kind.clone()),
ItemKind::Lantern(Lantern { kind, .. }) => ItemKey::Lantern(kind.clone()),
ItemKind::Armor { kind, .. } => ItemKey::Armor(kind.clone()),
ItemKind::Utility { kind, .. } => ItemKey::Utility(kind.clone()),
ItemKind::Consumable { kind, .. } => ItemKey::Consumable(kind.clone()),

View File

@ -12,7 +12,7 @@ use common::{
item::{
armor::{Armor, Back, Belt, Chest, Foot, Hand, Head, Pants, Shoulder, Tabard},
tool::{Tool, ToolKind},
ItemKind, Lantern,
ItemKind, Lantern, LanternKind,
},
object,
quadruped_medium::{BodyType as QMBodyType, Species as QMSpecies},
@ -259,7 +259,7 @@ pub struct HumArmorFootSpec(ArmorVoxSpecMap<Foot, ArmorVoxSpec>);
#[derive(Serialize, Deserialize)]
pub struct HumMainWeaponSpec(HashMap<ToolKind, ArmorVoxSpec>);
#[derive(Serialize, Deserialize)]
pub struct HumArmorLanternSpec(ArmorVoxSpecMap<Lantern, ArmorVoxSpec>);
pub struct HumArmorLanternSpec(ArmorVoxSpecMap<LanternKind, ArmorVoxSpec>);
#[derive(Serialize, Deserialize)]
pub struct HumArmorHeadSpec(ArmorVoxSpecMap<Head, ArmorVoxSpec>);
#[derive(Serialize, Deserialize)]
@ -810,18 +810,19 @@ impl HumArmorLanternSpec {
loadout: &Loadout,
generate_mesh: impl FnOnce(&Segment, Vec3<f32>) -> Mesh<FigurePipeline>,
) -> Mesh<FigurePipeline> {
let spec =
if let Some(ItemKind::Lantern(lantern)) = loadout.lantern.as_ref().map(|i| &i.kind) {
match self.0.map.get(&lantern) {
Some(spec) => spec,
None => {
error!("No lantern specification exists for {:?}", lantern);
return load_mesh("not_found", Vec3::new(-4.0, -3.5, 2.0), generate_mesh);
},
}
} else {
&self.0.default
};
let spec = if let Some(ItemKind::Lantern(Lantern { kind, .. })) =
loadout.lantern.as_ref().map(|i| &i.kind)
{
match self.0.map.get(&kind) {
Some(spec) => spec,
None => {
error!("No lantern specification exists for {:?}", kind);
return load_mesh("not_found", Vec3::new(-4.0, -3.5, 2.0), generate_mesh);
},
}
} else {
&self.0.default
};
let mut lantern_segment = color_segment(
graceful_load_mat_segment(&spec.vox_spec.0),

View File

@ -21,10 +21,10 @@ use crate::{
};
use common::{
comp::{
item::ItemKind, Body, CharacterState, Last, Loadout, Ori, PhysicsState, Pos, Scale, Stats,
Vel,
item::ItemKind, Body, CharacterState, Last, LightAnimation, LightEmitter, Loadout, Ori,
PhysicsState, Pos, Scale, Stats, Vel,
},
state::State,
state::{DeltaTime, State},
states::triple_strike,
terrain::TerrainChunk,
vol::RectRasterableVol,
@ -108,6 +108,61 @@ impl FigureMgr {
self.golem_model_cache.clean(tick);
}
pub fn update_lighting(&mut self, scene_data: &SceneData) {
let ecs = scene_data.state.ecs();
for (entity, light_emitter) in (&ecs.entities(), &ecs.read_storage::<LightEmitter>()).join()
{
// Add LightAnimation for objects with a LightEmitter
let mut anim_storage = ecs.write_storage::<LightAnimation>();
if let None = anim_storage.get_mut(entity) {
let anim = LightAnimation {
offset: Vec3::zero(),
col: light_emitter.col,
strength: 0.0,
};
let _ = anim_storage.insert(entity, anim);
}
}
let dt = ecs.fetch::<DeltaTime>().0;
for (entity, waypoint, light_emitter_opt, light_anim) in (
&ecs.entities(),
ecs.read_storage::<common::comp::Waypoint>().maybe(),
ecs.read_storage::<LightEmitter>().maybe(),
&mut ecs.write_storage::<LightAnimation>(),
)
.join()
{
let (target_col, target_strength, flicker, animated) =
if let Some(emitter) = light_emitter_opt {
(
emitter.col,
emitter.strength,
emitter.flicker,
emitter.animated,
)
} else {
(Rgb::zero(), 0.0, 0.0, true)
};
if let Some(_) = waypoint {
light_anim.offset = Vec3::unit_z() * 0.5;
}
if let Some(state) = self.character_states.get(&entity) {
light_anim.offset = state.lantern_offset;
}
if animated {
let flicker = (rand::random::<f32>() - 0.5) * flicker / dt.sqrt();
// Close gap between current and target strength by 95% per second
let delta = 0.05_f32.powf(dt);
light_anim.strength =
light_anim.strength * delta + (target_strength + flicker) * (1.0 - delta);
light_anim.col = light_anim.col * delta + target_col * (1.0 - delta)
} else {
light_anim.strength = target_strength;
light_anim.col = target_col;
}
}
}
pub fn maintain(&mut self, renderer: &mut Renderer, scene_data: &SceneData, camera: &Camera) {
let state = scene_data.state;
let time = state.get_time();
@ -1463,6 +1518,9 @@ impl FigureMgr {
}
}
// Update lighting (lanterns) for figures
self.update_lighting(scene_data);
// Clear states that have deleted entities.
self.character_states
.retain(|entity, _| ecs.entities().is_alive(*entity));
@ -1932,6 +1990,7 @@ impl FigureMgr {
pub struct FigureState<S: Skeleton> {
bone_consts: Consts<FigureBoneData>,
locals: Consts<FigureLocals>,
lantern_offset: Vec3<f32>,
state_time: f64,
skeleton: S,
last_ori: Vec3<f32>,
@ -1941,11 +2000,11 @@ pub struct FigureState<S: Skeleton> {
impl<S: Skeleton> FigureState<S> {
pub fn new(renderer: &mut Renderer, skeleton: S) -> Self {
let (bone_consts, lantern_offset) = skeleton.compute_matrices();
Self {
bone_consts: renderer
.create_consts(&skeleton.compute_matrices())
.unwrap(),
bone_consts: renderer.create_consts(&bone_consts).unwrap(),
locals: renderer.create_consts(&[FigureLocals::default()]).unwrap(),
lantern_offset,
state_time: 0.0,
skeleton,
last_ori: Vec3::zero(),
@ -1984,12 +2043,14 @@ impl<S: Skeleton> FigureState<S> {
let locals = FigureLocals::new(mat, col, is_player);
renderer.update_consts(&mut self.locals, &[locals]).unwrap();
let (new_bone_consts, lantern_offset) = self.skeleton.compute_matrices();
renderer
.update_consts(
&mut self.bone_consts,
&self.skeleton.compute_matrices()[0..self.skeleton.bone_count()],
&new_bone_consts[0..self.skeleton.bone_count()],
)
.unwrap();
self.lantern_offset = lantern_offset;
}
pub fn locals(&self) -> &Consts<FigureLocals> { &self.locals }

View File

@ -270,14 +270,17 @@ impl Scene {
.ecs()
.read_storage::<crate::ecs::comp::Interpolated>()
.maybe(),
&scene_data.state.ecs().read_storage::<comp::LightEmitter>(),
&scene_data
.state
.ecs()
.read_storage::<comp::LightAnimation>(),
)
.join()
.filter(|(pos, _, _, _)| {
(pos.0.distance_squared(player_pos) as f32)
< self.loaded_distance.powf(2.0) + LIGHT_DIST_RADIUS
})
.map(|(pos, ori, interpolated, light_emitter)| {
.map(|(pos, ori, interpolated, light_anim)| {
// Use interpolated values if they are available
let (pos, ori) =
interpolated.map_or((pos.0, ori.map(|o| o.0)), |i| (i.pos, Some(i.ori)));
@ -289,9 +292,9 @@ impl Scene {
}
};
Light::new(
pos + (rot * light_emitter.offset),
light_emitter.col,
light_emitter.strength,
pos + (rot * light_anim.offset),
light_anim.col,
light_anim.strength,
)
})
.collect::<Vec<_>>();

View File

@ -331,6 +331,9 @@ impl PlayState for SessionState {
self.client.borrow_mut().swap_loadout();
}
}
Event::InputUpdate(GameInput::ToggleLantern, true) => {
self.client.borrow_mut().toggle_lantern();
},
Event::InputUpdate(GameInput::Mount, true) => {
let mut client = self.client.borrow_mut();
if client.is_mounted() {

View File

@ -120,6 +120,7 @@ impl ControlSettings {
GameInput::Climb => KeyMouse::Key(VirtualKeyCode::Space),
GameInput::ClimbDown => KeyMouse::Key(VirtualKeyCode::LControl),
//GameInput::WallLeap => MIDDLE_CLICK_KEY,
GameInput::ToggleLantern => KeyMouse::Key(VirtualKeyCode::G),
GameInput::Mount => KeyMouse::Key(VirtualKeyCode::F),
GameInput::Map => KeyMouse::Key(VirtualKeyCode::M),
GameInput::Bag => KeyMouse::Key(VirtualKeyCode::B),
@ -175,6 +176,7 @@ impl Default for ControlSettings {
GameInput::Climb,
GameInput::ClimbDown,
//GameInput::WallLeap,
GameInput::ToggleLantern,
GameInput::Mount,
GameInput::Enter,
GameInput::Command,
@ -275,6 +277,7 @@ pub mod con_settings {
pub climb: Button,
pub climb_down: Button,
//pub wall_leap: Button,
pub toggle_lantern: Button,
pub mount: Button,
pub map: Button,
pub bag: Button,
@ -361,6 +364,7 @@ pub mod con_settings {
climb: Button::Simple(GilButton::South),
climb_down: Button::Simple(GilButton::Unknown),
//wall_leap: Button::Simple(GilButton::Unknown),
toggle_lantern: Button::Simple(GilButton::East),
mount: Button::Simple(GilButton::North),
map: Button::Simple(GilButton::DPadRight),
bag: Button::Simple(GilButton::DPadDown),

View File

@ -38,6 +38,7 @@ pub enum GameInput {
Climb,
ClimbDown,
//WallLeap,
ToggleLantern,
Mount,
Enter,
Command,
@ -78,6 +79,7 @@ impl GameInput {
GameInput::Climb => "gameinput.climb",
GameInput::ClimbDown => "gameinput.climbdown",
//GameInput::WallLeap => "gameinput.wallleap",
GameInput::ToggleLantern => "gameinput.togglelantern",
GameInput::Mount => "gameinput.mount",
GameInput::Enter => "gameinput.enter",
GameInput::Command => "gameinput.command",