mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Cache figures more intelligently.
Cache figures for longer, and don't cache character states for the player except where they actually affect the rendered model.
This commit is contained in:
parent
0ed801d540
commit
c6251a956a
@ -8,80 +8,159 @@ use anim::Skeleton;
|
|||||||
use common::{
|
use common::{
|
||||||
assets::watch::ReloadIndicator,
|
assets::watch::ReloadIndicator,
|
||||||
comp::{
|
comp::{
|
||||||
item::{armor::ArmorKind, tool::ToolKind, ItemKind},
|
item::{
|
||||||
|
armor::{Armor, ArmorKind},
|
||||||
|
tool::ToolKind,
|
||||||
|
ItemKind,
|
||||||
|
},
|
||||||
Body, CharacterState, Loadout,
|
Body, CharacterState, Loadout,
|
||||||
},
|
},
|
||||||
figure::Segment,
|
figure::Segment,
|
||||||
vol::BaseVol,
|
vol::BaseVol,
|
||||||
};
|
};
|
||||||
|
use core::convert::TryInto;
|
||||||
use hashbrown::{hash_map::Entry, HashMap};
|
use hashbrown::{hash_map::Entry, HashMap};
|
||||||
use std::{
|
|
||||||
convert::TryInto,
|
|
||||||
mem::{discriminant, Discriminant},
|
|
||||||
};
|
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
pub type FigureModelEntry = [FigureModel; 3];
|
pub type FigureModelEntry = [FigureModel; 3];
|
||||||
|
|
||||||
#[allow(clippy::large_enum_variant)] // TODO: Pending review in #587
|
#[derive(Eq, Hash, PartialEq)]
|
||||||
#[derive(PartialEq, Eq, Hash, Clone)]
|
struct FigureKey {
|
||||||
enum FigureKey {
|
/// Body pointed to by this key.
|
||||||
Simple(Body),
|
body: Body,
|
||||||
Complex(Body, CameraMode, CharacterCacheKey),
|
/// Extra state.
|
||||||
|
extra: Option<Box<CharacterCacheKey>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Hash, Clone)]
|
/// Character data that should be visible when tools are visible (i.e. in third
|
||||||
|
/// person or when the character is in a tool-using state).
|
||||||
|
#[derive(Eq, Hash, PartialEq)]
|
||||||
|
pub struct CharacterToolKey {
|
||||||
|
active: Option<ToolKind>,
|
||||||
|
second: Option<ToolKind>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Character data that exists in third person only.
|
||||||
|
#[derive(Eq, Hash, PartialEq)]
|
||||||
|
struct CharacterThirdPersonKey {
|
||||||
|
shoulder: Option<String>,
|
||||||
|
chest: Option<String>,
|
||||||
|
belt: Option<String>,
|
||||||
|
back: Option<String>,
|
||||||
|
pants: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, Hash, PartialEq)]
|
||||||
|
/// NOTE: To avoid spamming the character cache with player models, we try to
|
||||||
|
/// store only the minimum information required to correctly update the model.
|
||||||
|
///
|
||||||
|
/// TODO: Memoize, etc.
|
||||||
struct CharacterCacheKey {
|
struct CharacterCacheKey {
|
||||||
state: Option<Discriminant<CharacterState>>, // TODO: Can this be simplified?
|
/// Character state that is only visible in third person.
|
||||||
active_tool: Option<ToolKind>,
|
third_person: Option<CharacterThirdPersonKey>,
|
||||||
second_tool: Option<ToolKind>,
|
/// Tool state should be present when a character is either in third person,
|
||||||
shoulder: Option<ArmorKind>,
|
/// or is in first person and the character state is tool-using.
|
||||||
chest: Option<ArmorKind>,
|
///
|
||||||
belt: Option<ArmorKind>,
|
/// NOTE: This representation could be tightened in various ways to
|
||||||
back: Option<ArmorKind>,
|
/// eliminate incorrect states, e.g. setting active_tool to None when no
|
||||||
|
/// tools are equipped, but currently we are more focused on the big
|
||||||
|
/// performance impact of recreating the whole model whenever the character
|
||||||
|
/// state changes, so for now we don't bother with this.
|
||||||
|
tool: Option<CharacterToolKey>,
|
||||||
lantern: Option<String>,
|
lantern: Option<String>,
|
||||||
hand: Option<ArmorKind>,
|
hand: Option<String>,
|
||||||
pants: Option<ArmorKind>,
|
foot: Option<String>,
|
||||||
foot: Option<ArmorKind>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CharacterCacheKey {
|
impl CharacterCacheKey {
|
||||||
fn from(cs: Option<&CharacterState>, loadout: &Loadout) -> Self {
|
fn from(cs: Option<&CharacterState>, camera_mode: CameraMode, loadout: &Loadout) -> Self {
|
||||||
|
let is_first_person = match camera_mode {
|
||||||
|
CameraMode::FirstPerson => true,
|
||||||
|
CameraMode::ThirdPerson | CameraMode::Freefly => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Third person tools are only modeled when the camera is either not first
|
||||||
|
// person, or the camera is first person and we are in a tool-using
|
||||||
|
// state.
|
||||||
|
let are_tools_visible = !is_first_person
|
||||||
|
|| cs
|
||||||
|
.map(|cs| cs.is_attack() || cs.is_block() || cs.is_wield())
|
||||||
|
// If there's no provided character state but we're still somehow in first person,
|
||||||
|
// We currently assume there's no need to visually model tools.
|
||||||
|
//
|
||||||
|
// TODO: Figure out what to do here, and/or refactor how this works.
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
state: cs.map(|cs| discriminant(cs)),
|
// Third person armor is only modeled when the camera mode is not first person.
|
||||||
active_tool: if let Some(ItemKind::Tool(tool)) =
|
third_person: if is_first_person {
|
||||||
loadout.active_item.as_ref().map(|i| &i.item.kind)
|
|
||||||
{
|
|
||||||
Some(tool.kind.clone())
|
|
||||||
} else {
|
|
||||||
None
|
None
|
||||||
},
|
|
||||||
second_tool: if let Some(ItemKind::Tool(tool)) =
|
|
||||||
loadout.second_item.as_ref().map(|i| &i.item.kind)
|
|
||||||
{
|
|
||||||
Some(tool.kind.clone())
|
|
||||||
} else {
|
} else {
|
||||||
None
|
Some(CharacterThirdPersonKey {
|
||||||
|
shoulder: if let Some(ItemKind::Armor(Armor {
|
||||||
|
kind: ArmorKind::Shoulder(armor),
|
||||||
|
..
|
||||||
|
})) = loadout.shoulder.as_ref().map(|i| &i.kind)
|
||||||
|
{
|
||||||
|
Some(armor.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
|
chest: if let Some(ItemKind::Armor(Armor {
|
||||||
|
kind: ArmorKind::Chest(armor),
|
||||||
|
..
|
||||||
|
})) = loadout.chest.as_ref().map(|i| &i.kind)
|
||||||
|
{
|
||||||
|
Some(armor.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
|
belt: if let Some(ItemKind::Armor(Armor {
|
||||||
|
kind: ArmorKind::Belt(armor),
|
||||||
|
..
|
||||||
|
})) = loadout.belt.as_ref().map(|i| &i.kind)
|
||||||
|
{
|
||||||
|
Some(armor.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
|
back: if let Some(ItemKind::Armor(Armor {
|
||||||
|
kind: ArmorKind::Back(armor),
|
||||||
|
..
|
||||||
|
})) = loadout.back.as_ref().map(|i| &i.kind)
|
||||||
|
{
|
||||||
|
Some(armor.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
|
pants: if let Some(ItemKind::Armor(Armor {
|
||||||
|
kind: ArmorKind::Pants(armor),
|
||||||
|
..
|
||||||
|
})) = loadout.pants.as_ref().map(|i| &i.kind)
|
||||||
|
{
|
||||||
|
Some(armor.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
|
})
|
||||||
},
|
},
|
||||||
shoulder: if let Some(ItemKind::Armor(armor)) =
|
tool: if are_tools_visible {
|
||||||
loadout.shoulder.as_ref().map(|i| &i.kind)
|
Some(CharacterToolKey {
|
||||||
{
|
active: if let Some(ItemKind::Tool(tool)) =
|
||||||
Some(armor.kind.clone())
|
loadout.active_item.as_ref().map(|i| &i.item.kind)
|
||||||
} else {
|
{
|
||||||
None
|
Some(tool.kind.clone())
|
||||||
},
|
} else {
|
||||||
chest: if let Some(ItemKind::Armor(armor)) = loadout.chest.as_ref().map(|i| &i.kind) {
|
None
|
||||||
Some(armor.kind.clone())
|
},
|
||||||
} else {
|
second: if let Some(ItemKind::Tool(tool)) =
|
||||||
None
|
loadout.second_item.as_ref().map(|i| &i.item.kind)
|
||||||
},
|
{
|
||||||
belt: if let Some(ItemKind::Armor(armor)) = loadout.belt.as_ref().map(|i| &i.kind) {
|
Some(tool.kind.clone())
|
||||||
Some(armor.kind.clone())
|
} else {
|
||||||
} else {
|
None
|
||||||
None
|
},
|
||||||
},
|
})
|
||||||
back: if let Some(ItemKind::Armor(armor)) = loadout.back.as_ref().map(|i| &i.kind) {
|
|
||||||
Some(armor.kind.clone())
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
@ -92,18 +171,21 @@ impl CharacterCacheKey {
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
hand: if let Some(ItemKind::Armor(armor)) = loadout.hand.as_ref().map(|i| &i.kind) {
|
hand: if let Some(ItemKind::Armor(Armor {
|
||||||
Some(armor.kind.clone())
|
kind: ArmorKind::Hand(armor),
|
||||||
|
..
|
||||||
|
})) = loadout.hand.as_ref().map(|i| &i.kind)
|
||||||
|
{
|
||||||
|
Some(armor.clone())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
pants: if let Some(ItemKind::Armor(armor)) = loadout.pants.as_ref().map(|i| &i.kind) {
|
foot: if let Some(ItemKind::Armor(Armor {
|
||||||
Some(armor.kind.clone())
|
kind: ArmorKind::Foot(armor),
|
||||||
} else {
|
..
|
||||||
None
|
})) = loadout.foot.as_ref().map(|i| &i.kind)
|
||||||
},
|
{
|
||||||
foot: if let Some(ItemKind::Armor(armor)) = loadout.foot.as_ref().map(|i| &i.kind) {
|
Some(armor.clone())
|
||||||
Some(armor.kind.clone())
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
@ -129,11 +211,12 @@ impl<Skel: Skeleton> FigureModelCache<Skel> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// NOTE: We deliberately call this function with only the key into the
|
||||||
|
/// cache, to enforce that the cached state only depends on the key. We
|
||||||
|
/// may end up using different from this cache eventually, in which case
|
||||||
|
/// this strategy might change.
|
||||||
fn bone_meshes(
|
fn bone_meshes(
|
||||||
body: Body,
|
FigureKey { body, extra }: &FigureKey,
|
||||||
loadout: Option<&Loadout>,
|
|
||||||
character_state: Option<&CharacterState>,
|
|
||||||
camera_mode: CameraMode,
|
|
||||||
manifest_indicator: &mut ReloadIndicator,
|
manifest_indicator: &mut ReloadIndicator,
|
||||||
mut generate_mesh: impl FnMut(Segment, Vec3<f32>) -> BoneMeshes,
|
mut generate_mesh: impl FnMut(Segment, Vec3<f32>) -> BoneMeshes,
|
||||||
) -> [Option<BoneMeshes>; 16] {
|
) -> [Option<BoneMeshes>; 16] {
|
||||||
@ -152,130 +235,109 @@ impl<Skel: Skeleton> FigureModelCache<Skel> {
|
|||||||
let humanoid_armor_foot_spec = HumArmorFootSpec::load_watched(manifest_indicator);
|
let humanoid_armor_foot_spec = HumArmorFootSpec::load_watched(manifest_indicator);
|
||||||
let humanoid_main_weapon_spec = HumMainWeaponSpec::load_watched(manifest_indicator);
|
let humanoid_main_weapon_spec = HumMainWeaponSpec::load_watched(manifest_indicator);
|
||||||
|
|
||||||
|
const DEFAULT_LOADOUT: CharacterCacheKey = CharacterCacheKey {
|
||||||
|
third_person: None,
|
||||||
|
tool: None,
|
||||||
|
lantern: None,
|
||||||
|
hand: None,
|
||||||
|
foot: None,
|
||||||
|
};
|
||||||
|
|
||||||
// TODO: This is bad code, maybe this method should return Option<_>
|
// TODO: This is bad code, maybe this method should return Option<_>
|
||||||
let default_loadout = Loadout::default();
|
let loadout = extra.as_deref().unwrap_or(&DEFAULT_LOADOUT);
|
||||||
let loadout = loadout.unwrap_or(&default_loadout);
|
let third_person = loadout.third_person.as_ref();
|
||||||
|
let tool = loadout.tool.as_ref();
|
||||||
|
let lantern = loadout.lantern.as_deref();
|
||||||
|
let hand = loadout.hand.as_deref();
|
||||||
|
let foot = loadout.foot.as_deref();
|
||||||
|
|
||||||
[
|
[
|
||||||
match camera_mode {
|
third_person.map(|_| {
|
||||||
CameraMode::ThirdPerson | CameraMode::Freefly => Some(
|
humanoid_head_spec
|
||||||
humanoid_head_spec
|
.mesh_head(body, |segment, offset| generate_mesh(segment, offset))
|
||||||
.mesh_head(&body, |segment, offset| generate_mesh(segment, offset)),
|
}),
|
||||||
),
|
third_person.map(|loadout| {
|
||||||
CameraMode::FirstPerson => None,
|
humanoid_armor_chest_spec.mesh_chest(
|
||||||
},
|
body,
|
||||||
match camera_mode {
|
loadout.chest.as_deref(),
|
||||||
CameraMode::ThirdPerson | CameraMode::Freefly => {
|
|segment, offset| generate_mesh(segment, offset),
|
||||||
Some(humanoid_armor_chest_spec.mesh_chest(
|
)
|
||||||
&body,
|
}),
|
||||||
loadout,
|
third_person.map(|loadout| {
|
||||||
|segment, offset| generate_mesh(segment, offset),
|
humanoid_armor_belt_spec.mesh_belt(
|
||||||
))
|
body,
|
||||||
},
|
loadout.belt.as_deref(),
|
||||||
CameraMode::FirstPerson => None,
|
|segment, offset| generate_mesh(segment, offset),
|
||||||
},
|
)
|
||||||
match camera_mode {
|
}),
|
||||||
CameraMode::ThirdPerson | CameraMode::Freefly => {
|
third_person.map(|loadout| {
|
||||||
Some(humanoid_armor_belt_spec.mesh_belt(
|
humanoid_armor_back_spec.mesh_back(
|
||||||
&body,
|
body,
|
||||||
loadout,
|
loadout.back.as_deref(),
|
||||||
|segment, offset| generate_mesh(segment, offset),
|
|segment, offset| generate_mesh(segment, offset),
|
||||||
))
|
)
|
||||||
},
|
}),
|
||||||
CameraMode::FirstPerson => None,
|
third_person.map(|loadout| {
|
||||||
},
|
humanoid_armor_pants_spec.mesh_pants(
|
||||||
match camera_mode {
|
body,
|
||||||
CameraMode::ThirdPerson | CameraMode::Freefly => {
|
loadout.pants.as_deref(),
|
||||||
Some(humanoid_armor_back_spec.mesh_back(
|
|segment, offset| generate_mesh(segment, offset),
|
||||||
&body,
|
)
|
||||||
loadout,
|
}),
|
||||||
|segment, offset| generate_mesh(segment, offset),
|
Some(
|
||||||
))
|
humanoid_armor_hand_spec.mesh_left_hand(body, hand, |segment, offset| {
|
||||||
},
|
generate_mesh(segment, offset)
|
||||||
CameraMode::FirstPerson => None,
|
}),
|
||||||
},
|
),
|
||||||
match camera_mode {
|
|
||||||
CameraMode::ThirdPerson | CameraMode::Freefly => {
|
|
||||||
Some(humanoid_armor_pants_spec.mesh_pants(
|
|
||||||
&body,
|
|
||||||
loadout,
|
|
||||||
|segment, offset| generate_mesh(segment, offset),
|
|
||||||
))
|
|
||||||
},
|
|
||||||
CameraMode::FirstPerson => None,
|
|
||||||
},
|
|
||||||
Some(humanoid_armor_hand_spec.mesh_left_hand(
|
|
||||||
&body,
|
|
||||||
loadout,
|
|
||||||
|segment, offset| generate_mesh(segment, offset),
|
|
||||||
)),
|
|
||||||
Some(humanoid_armor_hand_spec.mesh_right_hand(
|
Some(humanoid_armor_hand_spec.mesh_right_hand(
|
||||||
&body,
|
body,
|
||||||
loadout,
|
hand,
|
||||||
|segment, offset| generate_mesh(segment, offset),
|
|
||||||
)),
|
|
||||||
Some(humanoid_armor_foot_spec.mesh_left_foot(
|
|
||||||
&body,
|
|
||||||
loadout,
|
|
||||||
|segment, offset| generate_mesh(segment, offset),
|
|segment, offset| generate_mesh(segment, offset),
|
||||||
)),
|
)),
|
||||||
|
Some(
|
||||||
|
humanoid_armor_foot_spec.mesh_left_foot(body, foot, |segment, offset| {
|
||||||
|
generate_mesh(segment, offset)
|
||||||
|
}),
|
||||||
|
),
|
||||||
Some(humanoid_armor_foot_spec.mesh_right_foot(
|
Some(humanoid_armor_foot_spec.mesh_right_foot(
|
||||||
&body,
|
body,
|
||||||
loadout,
|
foot,
|
||||||
|segment, offset| generate_mesh(segment, offset),
|
|segment, offset| generate_mesh(segment, offset),
|
||||||
)),
|
)),
|
||||||
match camera_mode {
|
third_person.map(|loadout| {
|
||||||
CameraMode::ThirdPerson | CameraMode::Freefly => {
|
humanoid_armor_shoulder_spec.mesh_left_shoulder(
|
||||||
Some(humanoid_armor_shoulder_spec.mesh_left_shoulder(
|
body,
|
||||||
&body,
|
loadout.shoulder.as_deref(),
|
||||||
loadout,
|
|segment, offset| generate_mesh(segment, offset),
|
||||||
|segment, offset| generate_mesh(segment, offset),
|
)
|
||||||
))
|
}),
|
||||||
},
|
third_person.map(|loadout| {
|
||||||
CameraMode::FirstPerson => None,
|
humanoid_armor_shoulder_spec.mesh_right_shoulder(
|
||||||
},
|
body,
|
||||||
match camera_mode {
|
loadout.shoulder.as_deref(),
|
||||||
CameraMode::ThirdPerson | CameraMode::Freefly => {
|
|segment, offset| generate_mesh(segment, offset),
|
||||||
Some(humanoid_armor_shoulder_spec.mesh_right_shoulder(
|
)
|
||||||
&body,
|
}),
|
||||||
loadout,
|
|
||||||
|segment, offset| generate_mesh(segment, offset),
|
|
||||||
))
|
|
||||||
},
|
|
||||||
CameraMode::FirstPerson => None,
|
|
||||||
},
|
|
||||||
Some(mesh_glider(|segment, offset| {
|
Some(mesh_glider(|segment, offset| {
|
||||||
generate_mesh(segment, offset)
|
generate_mesh(segment, offset)
|
||||||
})),
|
})),
|
||||||
if camera_mode != CameraMode::FirstPerson
|
tool.map(|tool| {
|
||||||
|| character_state
|
humanoid_main_weapon_spec.mesh_main_weapon(
|
||||||
.map(|cs| cs.is_attack() || cs.is_block() || cs.is_wield())
|
tool.active.as_ref(),
|
||||||
.unwrap_or_default()
|
|
||||||
{
|
|
||||||
Some(humanoid_main_weapon_spec.mesh_main_weapon(
|
|
||||||
loadout.active_item.as_ref().map(|i| &i.item.kind),
|
|
||||||
false,
|
false,
|
||||||
|segment, offset| generate_mesh(segment, offset),
|
|segment, offset| generate_mesh(segment, offset),
|
||||||
))
|
)
|
||||||
} else {
|
}),
|
||||||
None
|
tool.map(|tool| {
|
||||||
},
|
humanoid_main_weapon_spec.mesh_main_weapon(
|
||||||
if camera_mode != CameraMode::FirstPerson
|
tool.second.as_ref(),
|
||||||
|| character_state
|
|
||||||
.map(|cs| cs.is_attack() || cs.is_block() || cs.is_wield())
|
|
||||||
.unwrap_or_default()
|
|
||||||
{
|
|
||||||
Some(humanoid_main_weapon_spec.mesh_main_weapon(
|
|
||||||
loadout.second_item.as_ref().map(|i| &i.item.kind),
|
|
||||||
true,
|
true,
|
||||||
|segment, offset| generate_mesh(segment, offset),
|
|segment, offset| generate_mesh(segment, offset),
|
||||||
))
|
)
|
||||||
} else {
|
}),
|
||||||
None
|
|
||||||
},
|
|
||||||
Some(humanoid_armor_lantern_spec.mesh_lantern(
|
Some(humanoid_armor_lantern_spec.mesh_lantern(
|
||||||
&body,
|
body,
|
||||||
loadout,
|
lantern,
|
||||||
|segment, offset| generate_mesh(segment, offset),
|
|segment, offset| generate_mesh(segment, offset),
|
||||||
)),
|
)),
|
||||||
Some(mesh_hold(|segment, offset| generate_mesh(segment, offset))),
|
Some(mesh_hold(|segment, offset| generate_mesh(segment, offset))),
|
||||||
@ -923,14 +985,15 @@ impl<Skel: Skeleton> FigureModelCache<Skel> {
|
|||||||
for<'a> &'a common::comp::Body: std::convert::TryInto<Skel::Attr>,
|
for<'a> &'a common::comp::Body: std::convert::TryInto<Skel::Attr>,
|
||||||
Skel::Attr: Default,
|
Skel::Attr: Default,
|
||||||
{
|
{
|
||||||
let key = if let Some(loadout) = loadout {
|
let key = FigureKey {
|
||||||
FigureKey::Complex(
|
body,
|
||||||
body,
|
extra: loadout.map(|loadout| {
|
||||||
camera_mode,
|
Box::new(CharacterCacheKey::from(
|
||||||
CharacterCacheKey::from(character_state, loadout),
|
character_state,
|
||||||
)
|
camera_mode,
|
||||||
} else {
|
loadout,
|
||||||
FigureKey::Simple(body)
|
))
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
match self.models.entry(key) {
|
match self.models.entry(key) {
|
||||||
@ -940,100 +1003,90 @@ impl<Skel: Skeleton> FigureModelCache<Skel> {
|
|||||||
model
|
model
|
||||||
},
|
},
|
||||||
Entry::Vacant(v) => {
|
Entry::Vacant(v) => {
|
||||||
&v.insert((
|
let key = v.key();
|
||||||
{
|
let model = {
|
||||||
let skeleton_attr = (&body)
|
let skeleton_attr = (&body)
|
||||||
.try_into()
|
.try_into()
|
||||||
.ok()
|
.ok()
|
||||||
.unwrap_or_else(<Skel::Attr as Default>::default);
|
.unwrap_or_else(<Skel::Attr as Default>::default);
|
||||||
|
|
||||||
let manifest_indicator = &mut self.manifest_indicator;
|
let manifest_indicator = &mut self.manifest_indicator;
|
||||||
let mut make_model =
|
let mut make_model =
|
||||||
|generate_mesh: for<'a> fn(&mut GreedyMesh<'a>, _, _) -> _| {
|
|generate_mesh: for<'a> fn(&mut GreedyMesh<'a>, _, _) -> _| {
|
||||||
let mut greedy = FigureModel::make_greedy();
|
let mut greedy = FigureModel::make_greedy();
|
||||||
let mut opaque = Mesh::new();
|
let mut opaque = Mesh::new();
|
||||||
let mut figure_bounds = Aabb {
|
let mut figure_bounds = Aabb {
|
||||||
min: Vec3::zero(),
|
min: Vec3::zero(),
|
||||||
max: Vec3::zero(),
|
max: Vec3::zero(),
|
||||||
};
|
|
||||||
Self::bone_meshes(
|
|
||||||
body,
|
|
||||||
loadout,
|
|
||||||
character_state,
|
|
||||||
camera_mode,
|
|
||||||
manifest_indicator,
|
|
||||||
|segment, offset| generate_mesh(&mut greedy, segment, offset),
|
|
||||||
)
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.filter_map(|(i, bm)| bm.as_ref().map(|bm| (i, bm)))
|
|
||||||
.for_each(
|
|
||||||
|(i, (opaque_mesh, bounds))| {
|
|
||||||
opaque.push_mesh_map(opaque_mesh, |vert| {
|
|
||||||
vert.with_bone_idx(i as u8)
|
|
||||||
});
|
|
||||||
figure_bounds.expand_to_contain(*bounds);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
col_lights
|
|
||||||
.create_figure(renderer, greedy, (opaque, figure_bounds))
|
|
||||||
.unwrap()
|
|
||||||
};
|
};
|
||||||
|
Self::bone_meshes(key, manifest_indicator, |segment, offset| {
|
||||||
|
generate_mesh(&mut greedy, segment, offset)
|
||||||
|
})
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter_map(|(i, bm)| bm.as_ref().map(|bm| (i, bm)))
|
||||||
|
.for_each(|(i, (opaque_mesh, bounds))| {
|
||||||
|
opaque
|
||||||
|
.push_mesh_map(opaque_mesh, |vert| vert.with_bone_idx(i as u8));
|
||||||
|
figure_bounds.expand_to_contain(*bounds);
|
||||||
|
});
|
||||||
|
col_lights
|
||||||
|
.create_figure(renderer, greedy, (opaque, figure_bounds))
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
fn generate_mesh<'a>(
|
fn generate_mesh<'a>(
|
||||||
greedy: &mut GreedyMesh<'a>,
|
greedy: &mut GreedyMesh<'a>,
|
||||||
segment: Segment,
|
segment: Segment,
|
||||||
offset: Vec3<f32>,
|
offset: Vec3<f32>,
|
||||||
) -> BoneMeshes {
|
) -> BoneMeshes {
|
||||||
let (opaque, _, _, bounds) =
|
let (opaque, _, _, bounds) =
|
||||||
Meshable::<FigurePipeline, &mut GreedyMesh>::generate_mesh(
|
Meshable::<FigurePipeline, &mut GreedyMesh>::generate_mesh(
|
||||||
segment,
|
segment,
|
||||||
(greedy, offset, Vec3::one()),
|
(greedy, offset, Vec3::one()),
|
||||||
);
|
);
|
||||||
(opaque, bounds)
|
(opaque, bounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_mesh_lod_mid<'a>(
|
fn generate_mesh_lod_mid<'a>(
|
||||||
greedy: &mut GreedyMesh<'a>,
|
greedy: &mut GreedyMesh<'a>,
|
||||||
segment: Segment,
|
segment: Segment,
|
||||||
offset: Vec3<f32>,
|
offset: Vec3<f32>,
|
||||||
) -> BoneMeshes {
|
) -> BoneMeshes {
|
||||||
let lod_scale = Vec3::broadcast(0.6);
|
let lod_scale = Vec3::broadcast(0.6);
|
||||||
let (opaque, _, _, bounds) =
|
let (opaque, _, _, bounds) =
|
||||||
Meshable::<FigurePipeline, &mut GreedyMesh>::generate_mesh(
|
Meshable::<FigurePipeline, &mut GreedyMesh>::generate_mesh(
|
||||||
segment.scaled_by(lod_scale),
|
segment.scaled_by(lod_scale),
|
||||||
(greedy, offset * lod_scale, Vec3::one() / lod_scale),
|
(greedy, offset * lod_scale, Vec3::one() / lod_scale),
|
||||||
);
|
);
|
||||||
(opaque, bounds)
|
(opaque, bounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_mesh_lod_low<'a>(
|
fn generate_mesh_lod_low<'a>(
|
||||||
greedy: &mut GreedyMesh<'a>,
|
greedy: &mut GreedyMesh<'a>,
|
||||||
segment: Segment,
|
segment: Segment,
|
||||||
offset: Vec3<f32>,
|
offset: Vec3<f32>,
|
||||||
) -> BoneMeshes {
|
) -> BoneMeshes {
|
||||||
let lod_scale = Vec3::broadcast(0.3);
|
let lod_scale = Vec3::broadcast(0.3);
|
||||||
let segment = segment.scaled_by(lod_scale);
|
let segment = segment.scaled_by(lod_scale);
|
||||||
let (opaque, _, _, bounds) =
|
let (opaque, _, _, bounds) =
|
||||||
Meshable::<FigurePipeline, &mut GreedyMesh>::generate_mesh(
|
Meshable::<FigurePipeline, &mut GreedyMesh>::generate_mesh(
|
||||||
segment,
|
segment,
|
||||||
(greedy, offset * lod_scale, Vec3::one() / lod_scale),
|
(greedy, offset * lod_scale, Vec3::one() / lod_scale),
|
||||||
);
|
);
|
||||||
(opaque, bounds)
|
(opaque, bounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
(
|
(
|
||||||
[
|
[
|
||||||
make_model(generate_mesh),
|
make_model(generate_mesh),
|
||||||
make_model(generate_mesh_lod_mid),
|
make_model(generate_mesh_lod_mid),
|
||||||
make_model(generate_mesh_lod_low),
|
make_model(generate_mesh_lod_low),
|
||||||
],
|
],
|
||||||
skeleton_attr,
|
skeleton_attr,
|
||||||
)
|
)
|
||||||
},
|
};
|
||||||
tick,
|
&v.insert((model, tick)).0
|
||||||
))
|
|
||||||
.0
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1048,7 +1101,9 @@ impl<Skel: Skeleton> FigureModelCache<Skel> {
|
|||||||
// TODO: Don't hard-code this.
|
// TODO: Don't hard-code this.
|
||||||
if tick % 60 == 0 {
|
if tick % 60 == 0 {
|
||||||
self.models.retain(|_, ((models, _), last_used)| {
|
self.models.retain(|_, ((models, _), last_used)| {
|
||||||
let alive = *last_used + 60 > tick;
|
// Wait about a minute at 60 fps before invalidating old models.
|
||||||
|
let delta = 60 * 60;
|
||||||
|
let alive = *last_used + delta > tick;
|
||||||
if !alive {
|
if !alive {
|
||||||
models.iter().for_each(|model| {
|
models.iter().for_each(|model| {
|
||||||
col_lights.atlas.deallocate(model.allocation.id);
|
col_lights.atlas.deallocate(model.allocation.id);
|
||||||
|
@ -10,16 +10,11 @@ use common::{
|
|||||||
fish_medium, fish_small,
|
fish_medium, fish_small,
|
||||||
golem::{BodyType as GBodyType, Species as GSpecies},
|
golem::{BodyType as GBodyType, Species as GSpecies},
|
||||||
humanoid::{Body, BodyType, EyeColor, Skin, Species},
|
humanoid::{Body, BodyType, EyeColor, Skin, Species},
|
||||||
item::{
|
item::tool::ToolKind,
|
||||||
armor::{Armor, ArmorKind},
|
|
||||||
tool::{Tool, ToolKind},
|
|
||||||
ItemKind, Lantern,
|
|
||||||
},
|
|
||||||
object,
|
object,
|
||||||
quadruped_low::{BodyType as QLBodyType, Species as QLSpecies},
|
quadruped_low::{BodyType as QLBodyType, Species as QLSpecies},
|
||||||
quadruped_medium::{BodyType as QMBodyType, Species as QMSpecies},
|
quadruped_medium::{BodyType as QMBodyType, Species as QMSpecies},
|
||||||
quadruped_small::{BodyType as QSBodyType, Species as QSSpecies},
|
quadruped_small::{BodyType as QSBodyType, Species as QSSpecies},
|
||||||
Loadout,
|
|
||||||
},
|
},
|
||||||
figure::{DynaUnionizer, MatSegment, Material, Segment},
|
figure::{DynaUnionizer, MatSegment, Material, Segment},
|
||||||
};
|
};
|
||||||
@ -361,15 +356,11 @@ impl HumArmorShoulderSpec {
|
|||||||
fn mesh_shoulder(
|
fn mesh_shoulder(
|
||||||
&self,
|
&self,
|
||||||
body: &Body,
|
body: &Body,
|
||||||
loadout: &Loadout,
|
shoulder: Option<&str>,
|
||||||
flipped: bool,
|
flipped: bool,
|
||||||
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
||||||
) -> BoneMeshes {
|
) -> BoneMeshes {
|
||||||
let spec = if let Some(ItemKind::Armor(Armor {
|
let spec = if let Some(shoulder) = shoulder {
|
||||||
kind: ArmorKind::Shoulder(shoulder),
|
|
||||||
..
|
|
||||||
})) = loadout.shoulder.as_ref().map(|i| &i.kind)
|
|
||||||
{
|
|
||||||
match self.0.map.get(shoulder) {
|
match self.0.map.get(shoulder) {
|
||||||
Some(spec) => spec,
|
Some(spec) => spec,
|
||||||
None => {
|
None => {
|
||||||
@ -419,19 +410,19 @@ impl HumArmorShoulderSpec {
|
|||||||
pub fn mesh_left_shoulder(
|
pub fn mesh_left_shoulder(
|
||||||
&self,
|
&self,
|
||||||
body: &Body,
|
body: &Body,
|
||||||
loadout: &Loadout,
|
shoulder: Option<&str>,
|
||||||
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
||||||
) -> BoneMeshes {
|
) -> BoneMeshes {
|
||||||
self.mesh_shoulder(body, loadout, true, generate_mesh)
|
self.mesh_shoulder(body, shoulder, true, generate_mesh)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mesh_right_shoulder(
|
pub fn mesh_right_shoulder(
|
||||||
&self,
|
&self,
|
||||||
body: &Body,
|
body: &Body,
|
||||||
loadout: &Loadout,
|
shoulder: Option<&str>,
|
||||||
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
||||||
) -> BoneMeshes {
|
) -> BoneMeshes {
|
||||||
self.mesh_shoulder(body, loadout, false, generate_mesh)
|
self.mesh_shoulder(body, shoulder, false, generate_mesh)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Chest
|
// Chest
|
||||||
@ -444,18 +435,14 @@ impl HumArmorChestSpec {
|
|||||||
pub fn mesh_chest(
|
pub fn mesh_chest(
|
||||||
&self,
|
&self,
|
||||||
body: &Body,
|
body: &Body,
|
||||||
loadout: &Loadout,
|
chest: Option<&str>,
|
||||||
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
||||||
) -> BoneMeshes {
|
) -> BoneMeshes {
|
||||||
let spec = if let Some(ItemKind::Armor(Armor {
|
let spec = if let Some(chest) = chest {
|
||||||
kind: ArmorKind::Chest(chest),
|
|
||||||
..
|
|
||||||
})) = loadout.chest.as_ref().map(|i| &i.kind)
|
|
||||||
{
|
|
||||||
match self.0.map.get(chest) {
|
match self.0.map.get(chest) {
|
||||||
Some(spec) => spec,
|
Some(spec) => spec,
|
||||||
None => {
|
None => {
|
||||||
error!(?loadout.chest, "No chest specification exists");
|
error!(?chest, "No chest specification exists");
|
||||||
return load_mesh("not_found", Vec3::new(-7.0, -3.5, 2.0), generate_mesh);
|
return load_mesh("not_found", Vec3::new(-7.0, -3.5, 2.0), generate_mesh);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -500,15 +487,11 @@ impl HumArmorHandSpec {
|
|||||||
fn mesh_hand(
|
fn mesh_hand(
|
||||||
&self,
|
&self,
|
||||||
body: &Body,
|
body: &Body,
|
||||||
loadout: &Loadout,
|
hand: Option<&str>,
|
||||||
flipped: bool,
|
flipped: bool,
|
||||||
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
||||||
) -> BoneMeshes {
|
) -> BoneMeshes {
|
||||||
let spec = if let Some(ItemKind::Armor(Armor {
|
let spec = if let Some(hand) = hand {
|
||||||
kind: ArmorKind::Hand(hand),
|
|
||||||
..
|
|
||||||
})) = loadout.hand.as_ref().map(|i| &i.kind)
|
|
||||||
{
|
|
||||||
match self.0.map.get(hand) {
|
match self.0.map.get(hand) {
|
||||||
Some(spec) => spec,
|
Some(spec) => spec,
|
||||||
None => {
|
None => {
|
||||||
@ -552,19 +535,19 @@ impl HumArmorHandSpec {
|
|||||||
pub fn mesh_left_hand(
|
pub fn mesh_left_hand(
|
||||||
&self,
|
&self,
|
||||||
body: &Body,
|
body: &Body,
|
||||||
loadout: &Loadout,
|
hand: Option<&str>,
|
||||||
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
||||||
) -> BoneMeshes {
|
) -> BoneMeshes {
|
||||||
self.mesh_hand(body, loadout, true, generate_mesh)
|
self.mesh_hand(body, hand, true, generate_mesh)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mesh_right_hand(
|
pub fn mesh_right_hand(
|
||||||
&self,
|
&self,
|
||||||
body: &Body,
|
body: &Body,
|
||||||
loadout: &Loadout,
|
hand: Option<&str>,
|
||||||
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
||||||
) -> BoneMeshes {
|
) -> BoneMeshes {
|
||||||
self.mesh_hand(body, loadout, false, generate_mesh)
|
self.mesh_hand(body, hand, false, generate_mesh)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Belt
|
// Belt
|
||||||
@ -577,14 +560,10 @@ impl HumArmorBeltSpec {
|
|||||||
pub fn mesh_belt(
|
pub fn mesh_belt(
|
||||||
&self,
|
&self,
|
||||||
body: &Body,
|
body: &Body,
|
||||||
loadout: &Loadout,
|
belt: Option<&str>,
|
||||||
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
||||||
) -> BoneMeshes {
|
) -> BoneMeshes {
|
||||||
let spec = if let Some(ItemKind::Armor(Armor {
|
let spec = if let Some(belt) = belt {
|
||||||
kind: ArmorKind::Belt(belt),
|
|
||||||
..
|
|
||||||
})) = loadout.belt.as_ref().map(|i| &i.kind)
|
|
||||||
{
|
|
||||||
match self.0.map.get(belt) {
|
match self.0.map.get(belt) {
|
||||||
Some(spec) => spec,
|
Some(spec) => spec,
|
||||||
None => {
|
None => {
|
||||||
@ -621,14 +600,10 @@ impl HumArmorBackSpec {
|
|||||||
pub fn mesh_back(
|
pub fn mesh_back(
|
||||||
&self,
|
&self,
|
||||||
body: &Body,
|
body: &Body,
|
||||||
loadout: &Loadout,
|
back: Option<&str>,
|
||||||
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
||||||
) -> BoneMeshes {
|
) -> BoneMeshes {
|
||||||
let spec = if let Some(ItemKind::Armor(Armor {
|
let spec = if let Some(back) = back {
|
||||||
kind: ArmorKind::Back(back),
|
|
||||||
..
|
|
||||||
})) = loadout.back.as_ref().map(|i| &i.kind)
|
|
||||||
{
|
|
||||||
match self.0.map.get(back) {
|
match self.0.map.get(back) {
|
||||||
Some(spec) => spec,
|
Some(spec) => spec,
|
||||||
None => {
|
None => {
|
||||||
@ -664,14 +639,10 @@ impl HumArmorPantsSpec {
|
|||||||
pub fn mesh_pants(
|
pub fn mesh_pants(
|
||||||
&self,
|
&self,
|
||||||
body: &Body,
|
body: &Body,
|
||||||
loadout: &Loadout,
|
pants: Option<&str>,
|
||||||
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
||||||
) -> BoneMeshes {
|
) -> BoneMeshes {
|
||||||
let spec = if let Some(ItemKind::Armor(Armor {
|
let spec = if let Some(pants) = pants {
|
||||||
kind: ArmorKind::Pants(pants),
|
|
||||||
..
|
|
||||||
})) = loadout.pants.as_ref().map(|i| &i.kind)
|
|
||||||
{
|
|
||||||
match self.0.map.get(pants) {
|
match self.0.map.get(pants) {
|
||||||
Some(spec) => spec,
|
Some(spec) => spec,
|
||||||
None => {
|
None => {
|
||||||
@ -720,15 +691,11 @@ impl HumArmorFootSpec {
|
|||||||
fn mesh_foot(
|
fn mesh_foot(
|
||||||
&self,
|
&self,
|
||||||
body: &Body,
|
body: &Body,
|
||||||
loadout: &Loadout,
|
foot: Option<&str>,
|
||||||
flipped: bool,
|
flipped: bool,
|
||||||
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
||||||
) -> BoneMeshes {
|
) -> BoneMeshes {
|
||||||
let spec = if let Some(ItemKind::Armor(Armor {
|
let spec = if let Some(foot) = foot {
|
||||||
kind: ArmorKind::Foot(foot),
|
|
||||||
..
|
|
||||||
})) = loadout.foot.as_ref().map(|i| &i.kind)
|
|
||||||
{
|
|
||||||
match self.0.map.get(foot) {
|
match self.0.map.get(foot) {
|
||||||
Some(spec) => spec,
|
Some(spec) => spec,
|
||||||
None => {
|
None => {
|
||||||
@ -762,19 +729,19 @@ impl HumArmorFootSpec {
|
|||||||
pub fn mesh_left_foot(
|
pub fn mesh_left_foot(
|
||||||
&self,
|
&self,
|
||||||
body: &Body,
|
body: &Body,
|
||||||
loadout: &Loadout,
|
foot: Option<&str>,
|
||||||
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
||||||
) -> BoneMeshes {
|
) -> BoneMeshes {
|
||||||
self.mesh_foot(body, loadout, true, generate_mesh)
|
self.mesh_foot(body, foot, true, generate_mesh)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mesh_right_foot(
|
pub fn mesh_right_foot(
|
||||||
&self,
|
&self,
|
||||||
body: &Body,
|
body: &Body,
|
||||||
loadout: &Loadout,
|
foot: Option<&str>,
|
||||||
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
||||||
) -> BoneMeshes {
|
) -> BoneMeshes {
|
||||||
self.mesh_foot(body, loadout, false, generate_mesh)
|
self.mesh_foot(body, foot, false, generate_mesh)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -786,11 +753,11 @@ impl HumMainWeaponSpec {
|
|||||||
|
|
||||||
pub fn mesh_main_weapon(
|
pub fn mesh_main_weapon(
|
||||||
&self,
|
&self,
|
||||||
item_kind: Option<&ItemKind>,
|
tool_kind: Option<&ToolKind>,
|
||||||
flipped: bool,
|
flipped: bool,
|
||||||
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
||||||
) -> BoneMeshes {
|
) -> BoneMeshes {
|
||||||
let tool_kind = if let Some(ItemKind::Tool(Tool { kind, .. })) = item_kind {
|
let tool_kind = if let Some(kind) = tool_kind {
|
||||||
kind
|
kind
|
||||||
} else {
|
} else {
|
||||||
return (Mesh::new(), Aabb::default());
|
return (Mesh::new(), Aabb::default());
|
||||||
@ -835,12 +802,10 @@ impl HumArmorLanternSpec {
|
|||||||
pub fn mesh_lantern(
|
pub fn mesh_lantern(
|
||||||
&self,
|
&self,
|
||||||
body: &Body,
|
body: &Body,
|
||||||
loadout: &Loadout,
|
lantern: Option<&str>,
|
||||||
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
||||||
) -> BoneMeshes {
|
) -> BoneMeshes {
|
||||||
let spec = if let Some(ItemKind::Lantern(Lantern { kind, .. })) =
|
let spec = if let Some(kind) = lantern {
|
||||||
loadout.lantern.as_ref().map(|i| &i.kind)
|
|
||||||
{
|
|
||||||
match self.0.map.get(kind) {
|
match self.0.map.get(kind) {
|
||||||
Some(spec) => spec,
|
Some(spec) => spec,
|
||||||
None => {
|
None => {
|
||||||
@ -876,14 +841,10 @@ impl HumArmorHeadSpec {
|
|||||||
pub fn mesh_head(
|
pub fn mesh_head(
|
||||||
&self,
|
&self,
|
||||||
body: &Body,
|
body: &Body,
|
||||||
loadout: &Loadout,
|
head: Option<&str>,
|
||||||
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
||||||
) -> BoneMeshes {
|
) -> BoneMeshes {
|
||||||
let spec = if let Some(ItemKind::Armor(Armor {
|
let spec = if let Some(head) = head {
|
||||||
kind: ArmorKind::Head(head),
|
|
||||||
..
|
|
||||||
})) = loadout.head.as_ref().map(|i| &i.kind)
|
|
||||||
{
|
|
||||||
match self.0.map.get(head) {
|
match self.0.map.get(head) {
|
||||||
Some(spec) => spec,
|
Some(spec) => spec,
|
||||||
None => {
|
None => {
|
||||||
@ -931,14 +892,10 @@ impl HumArmorTabardSpec {
|
|||||||
pub fn mesh_tabard(
|
pub fn mesh_tabard(
|
||||||
&self,
|
&self,
|
||||||
body: &Body,
|
body: &Body,
|
||||||
loadout: &Loadout,
|
tabard: Option<&str>,
|
||||||
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
||||||
) -> BoneMeshes {
|
) -> BoneMeshes {
|
||||||
let spec = if let Some(ItemKind::Armor(Armor {
|
let spec = if let Some(tabard) = tabard {
|
||||||
kind: ArmorKind::Tabard(tabard),
|
|
||||||
..
|
|
||||||
})) = loadout.tabard.as_ref().map(|i| &i.kind)
|
|
||||||
{
|
|
||||||
match self.0.map.get(tabard) {
|
match self.0.map.get(tabard) {
|
||||||
Some(spec) => spec,
|
Some(spec) => spec,
|
||||||
None => {
|
None => {
|
||||||
@ -3403,7 +3360,7 @@ impl QuadrupedLowLateralSpec {
|
|||||||
///
|
///
|
||||||
|
|
||||||
pub fn mesh_object(
|
pub fn mesh_object(
|
||||||
obj: object::Body,
|
obj: &object::Body,
|
||||||
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
generate_mesh: impl FnOnce(Segment, Vec3<f32>) -> BoneMeshes,
|
||||||
) -> BoneMeshes {
|
) -> BoneMeshes {
|
||||||
use object::Body;
|
use object::Body;
|
||||||
|
@ -481,6 +481,9 @@ impl FigureMgr {
|
|||||||
min: player_pos - 2.0,
|
min: player_pos - 2.0,
|
||||||
max: player_pos + 2.0,
|
max: player_pos + 2.0,
|
||||||
};
|
};
|
||||||
|
let camera_mode = camera.get_mode();
|
||||||
|
let character_state_storage = state.read_storage::<common::comp::CharacterState>();
|
||||||
|
let character_state = character_state_storage.get(scene_data.player_entity);
|
||||||
|
|
||||||
let focus_pos = anim::vek::Vec3::<f32>::from(camera.get_focus_pos());
|
let focus_pos = anim::vek::Vec3::<f32>::from(camera.get_focus_pos());
|
||||||
|
|
||||||
@ -521,6 +524,13 @@ impl FigureMgr {
|
|||||||
{
|
{
|
||||||
let vel = (anim::vek::Vec3::<f32>::from(vel.0),);
|
let vel = (anim::vek::Vec3::<f32>::from(vel.0),);
|
||||||
let is_player = scene_data.player_entity == entity;
|
let is_player = scene_data.player_entity == entity;
|
||||||
|
let player_camera_mode = if is_player {
|
||||||
|
camera_mode
|
||||||
|
} else {
|
||||||
|
CameraMode::default()
|
||||||
|
};
|
||||||
|
let player_character_state = if is_player { character_state } else { None };
|
||||||
|
|
||||||
let (pos, ori) = interpolated
|
let (pos, ori) = interpolated
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
(
|
(
|
||||||
@ -654,8 +664,8 @@ impl FigureMgr {
|
|||||||
*body,
|
*body,
|
||||||
loadout,
|
loadout,
|
||||||
tick,
|
tick,
|
||||||
CameraMode::default(),
|
player_camera_mode,
|
||||||
None,
|
player_character_state,
|
||||||
);
|
);
|
||||||
|
|
||||||
let state = self
|
let state = self
|
||||||
@ -1024,8 +1034,8 @@ impl FigureMgr {
|
|||||||
*body,
|
*body,
|
||||||
loadout,
|
loadout,
|
||||||
tick,
|
tick,
|
||||||
CameraMode::default(),
|
player_camera_mode,
|
||||||
None,
|
player_character_state,
|
||||||
);
|
);
|
||||||
|
|
||||||
let state = self
|
let state = self
|
||||||
@ -1125,8 +1135,8 @@ impl FigureMgr {
|
|||||||
*body,
|
*body,
|
||||||
loadout,
|
loadout,
|
||||||
tick,
|
tick,
|
||||||
CameraMode::default(),
|
player_camera_mode,
|
||||||
None,
|
player_character_state,
|
||||||
);
|
);
|
||||||
|
|
||||||
let state = self
|
let state = self
|
||||||
@ -1226,8 +1236,8 @@ impl FigureMgr {
|
|||||||
*body,
|
*body,
|
||||||
loadout,
|
loadout,
|
||||||
tick,
|
tick,
|
||||||
CameraMode::default(),
|
player_camera_mode,
|
||||||
None,
|
player_character_state,
|
||||||
);
|
);
|
||||||
|
|
||||||
let state = self
|
let state = self
|
||||||
@ -1324,8 +1334,8 @@ impl FigureMgr {
|
|||||||
*body,
|
*body,
|
||||||
loadout,
|
loadout,
|
||||||
tick,
|
tick,
|
||||||
CameraMode::default(),
|
player_camera_mode,
|
||||||
None,
|
player_character_state,
|
||||||
);
|
);
|
||||||
|
|
||||||
let state = self
|
let state = self
|
||||||
@ -1420,8 +1430,8 @@ impl FigureMgr {
|
|||||||
*body,
|
*body,
|
||||||
loadout,
|
loadout,
|
||||||
tick,
|
tick,
|
||||||
CameraMode::default(),
|
player_camera_mode,
|
||||||
None,
|
player_character_state,
|
||||||
);
|
);
|
||||||
|
|
||||||
let state = self
|
let state = self
|
||||||
@ -1499,8 +1509,8 @@ impl FigureMgr {
|
|||||||
*body,
|
*body,
|
||||||
loadout,
|
loadout,
|
||||||
tick,
|
tick,
|
||||||
CameraMode::default(),
|
player_camera_mode,
|
||||||
None,
|
player_character_state,
|
||||||
);
|
);
|
||||||
|
|
||||||
let state =
|
let state =
|
||||||
@ -1574,8 +1584,8 @@ impl FigureMgr {
|
|||||||
*body,
|
*body,
|
||||||
loadout,
|
loadout,
|
||||||
tick,
|
tick,
|
||||||
CameraMode::default(),
|
player_camera_mode,
|
||||||
None,
|
player_character_state,
|
||||||
);
|
);
|
||||||
|
|
||||||
let state =
|
let state =
|
||||||
@ -1650,8 +1660,8 @@ impl FigureMgr {
|
|||||||
*body,
|
*body,
|
||||||
loadout,
|
loadout,
|
||||||
tick,
|
tick,
|
||||||
CameraMode::default(),
|
player_camera_mode,
|
||||||
None,
|
player_character_state,
|
||||||
);
|
);
|
||||||
|
|
||||||
let state = self
|
let state = self
|
||||||
@ -1729,8 +1739,8 @@ impl FigureMgr {
|
|||||||
*body,
|
*body,
|
||||||
loadout,
|
loadout,
|
||||||
tick,
|
tick,
|
||||||
CameraMode::default(),
|
player_camera_mode,
|
||||||
None,
|
player_character_state,
|
||||||
);
|
);
|
||||||
|
|
||||||
let state = self
|
let state = self
|
||||||
@ -1808,8 +1818,8 @@ impl FigureMgr {
|
|||||||
*body,
|
*body,
|
||||||
loadout,
|
loadout,
|
||||||
tick,
|
tick,
|
||||||
CameraMode::default(),
|
player_camera_mode,
|
||||||
None,
|
player_character_state,
|
||||||
);
|
);
|
||||||
|
|
||||||
let state = self
|
let state = self
|
||||||
@ -1904,8 +1914,8 @@ impl FigureMgr {
|
|||||||
*body,
|
*body,
|
||||||
loadout,
|
loadout,
|
||||||
tick,
|
tick,
|
||||||
CameraMode::default(),
|
player_camera_mode,
|
||||||
None,
|
player_character_state,
|
||||||
);
|
);
|
||||||
|
|
||||||
let state =
|
let state =
|
||||||
@ -1980,8 +1990,8 @@ impl FigureMgr {
|
|||||||
*body,
|
*body,
|
||||||
loadout,
|
loadout,
|
||||||
tick,
|
tick,
|
||||||
CameraMode::default(),
|
player_camera_mode,
|
||||||
None,
|
player_character_state,
|
||||||
);
|
);
|
||||||
|
|
||||||
let state =
|
let state =
|
||||||
|
Loading…
Reference in New Issue
Block a user