diff --git a/voxygen/src/scene/figure/cache.rs b/voxygen/src/scene/figure/cache.rs index 7903b30d3c..66ae5f5f00 100644 --- a/voxygen/src/scene/figure/cache.rs +++ b/voxygen/src/scene/figure/cache.rs @@ -3,14 +3,18 @@ use crate::{ anim::{self, Skeleton}, render::{FigurePipeline, Mesh, Model, Renderer}, scene::camera::CameraMode, + mesh::Meshable, }; use common::{ + figure::Segment, assets::watch::ReloadIndicator, comp::{ item::{tool::ToolKind, ItemKind}, Body, CharacterState, Item, Loadout, }, + vol::BaseVol, }; +use vek::*; use hashbrown::{hash_map::Entry, HashMap}; use std::{ convert::TryInto, @@ -64,7 +68,7 @@ pub struct FigureModelCache where Skel: Skeleton, { - models: HashMap, Skel::Attr), u64)>, + models: HashMap; 3], Skel::Attr), u64)>, manifest_indicator: ReloadIndicator, } @@ -76,6 +80,479 @@ impl FigureModelCache { } } + fn bone_meshes( + body: Body, + loadout: Option<&Loadout>, + character_state: Option<&CharacterState>, + camera_mode: CameraMode, + manifest_indicator: &mut ReloadIndicator, + generate_mesh: fn(&Segment, Vec3) -> Mesh, + ) -> [Option>; 16] { + match body { + Body::Humanoid(body) => { + let humanoid_head_spec = + HumHeadSpec::load_watched(manifest_indicator); + let humanoid_armor_shoulder_spec = + HumArmorShoulderSpec::load_watched(manifest_indicator); + let humanoid_armor_chest_spec = + HumArmorChestSpec::load_watched(manifest_indicator); + let humanoid_armor_hand_spec = + HumArmorHandSpec::load_watched(manifest_indicator); + let humanoid_armor_belt_spec = + HumArmorBeltSpec::load_watched(manifest_indicator); + let humanoid_armor_back_spec = + HumArmorBackSpec::load_watched(manifest_indicator); + let humanoid_armor_lantern_spec = + HumArmorLanternSpec::load_watched(manifest_indicator); + let humanoid_armor_pants_spec = + HumArmorPantsSpec::load_watched(manifest_indicator); + let humanoid_armor_foot_spec = + HumArmorFootSpec::load_watched(manifest_indicator); + let humanoid_main_weapon_spec = + HumMainWeaponSpec::load_watched(manifest_indicator); + + // TODO: This is bad code, maybe this method should return Option<_> + let default_loadout = Loadout::default(); + let loadout = loadout.unwrap_or(&default_loadout); + + [ + match camera_mode { + CameraMode::ThirdPerson => { + Some(humanoid_head_spec.mesh_head( + body.race, + body.body_type, + body.hair_color, + body.hair_style, + body.beard, + body.eye_color, + body.skin, + body.eyebrows, + body.accessory, + generate_mesh, + )) + }, + CameraMode::FirstPerson => None, + }, + match camera_mode { + CameraMode::ThirdPerson => Some( + humanoid_armor_chest_spec.mesh_chest(&body, loadout, generate_mesh), + ), + CameraMode::FirstPerson => None, + }, + match camera_mode { + CameraMode::ThirdPerson => { + Some(humanoid_armor_belt_spec.mesh_belt(&body, loadout, generate_mesh)) + }, + CameraMode::FirstPerson => None, + }, + match camera_mode { + CameraMode::ThirdPerson => { + Some(humanoid_armor_back_spec.mesh_back(&body, loadout, generate_mesh)) + }, + CameraMode::FirstPerson => None, + }, + match camera_mode { + CameraMode::ThirdPerson => Some( + humanoid_armor_pants_spec.mesh_pants(&body, loadout, generate_mesh), + ), + CameraMode::FirstPerson => None, + }, + if camera_mode == CameraMode::FirstPerson + && character_state + .map(|cs| cs.is_dodge()) + .unwrap_or_default() + { + None + } else { + Some( + humanoid_armor_hand_spec.mesh_left_hand(&body, loadout, generate_mesh), + ) + }, + if character_state.map(|cs| cs.is_dodge()).unwrap_or_default() { + None + } else { + Some( + humanoid_armor_hand_spec + .mesh_right_hand(&body, loadout, generate_mesh), + ) + }, + match camera_mode { + CameraMode::ThirdPerson => Some( + humanoid_armor_foot_spec.mesh_left_foot(&body, loadout, generate_mesh), + ), + CameraMode::FirstPerson => None, + }, + match camera_mode { + CameraMode::ThirdPerson => Some( + humanoid_armor_foot_spec + .mesh_right_foot(&body, loadout, generate_mesh), + ), + CameraMode::FirstPerson => None, + }, + match camera_mode { + CameraMode::ThirdPerson => Some( + humanoid_armor_shoulder_spec + .mesh_left_shoulder(&body, loadout, generate_mesh), + ), + CameraMode::FirstPerson => None, + }, + match camera_mode { + CameraMode::ThirdPerson => Some( + humanoid_armor_shoulder_spec + .mesh_right_shoulder(&body, loadout, generate_mesh), + ), + CameraMode::FirstPerson => None, + }, + Some(mesh_glider(generate_mesh)), + if camera_mode != CameraMode::FirstPerson + || 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.active_item.as_ref().map(|i| &i.item.kind), + generate_mesh, + )) + } else { + None + }, + None, + Some(humanoid_armor_lantern_spec.mesh_lantern(&body, loadout, generate_mesh)), + None, + ] + }, + Body::QuadrupedSmall(body) => { + let quadruped_small_central_spec = + QuadrupedSmallCentralSpec::load_watched(manifest_indicator); + let quadruped_small_lateral_spec = + QuadrupedSmallLateralSpec::load_watched(manifest_indicator); + + [ + Some( + quadruped_small_central_spec + .mesh_head(body.species, body.body_type, generate_mesh), + ), + Some( + quadruped_small_central_spec + .mesh_chest(body.species, body.body_type, generate_mesh), + ), + Some( + quadruped_small_lateral_spec + .mesh_foot_lf(body.species, body.body_type, generate_mesh), + ), + Some( + quadruped_small_lateral_spec + .mesh_foot_rf(body.species, body.body_type, generate_mesh), + ), + Some( + quadruped_small_lateral_spec + .mesh_foot_lb(body.species, body.body_type, generate_mesh), + ), + Some( + quadruped_small_lateral_spec + .mesh_foot_rb(body.species, body.body_type, generate_mesh), + ), + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + ] + }, + Body::QuadrupedMedium(body) => { + let quadruped_medium_central_spec = + QuadrupedMediumCentralSpec::load_watched(manifest_indicator); + let quadruped_medium_lateral_spec = + QuadrupedMediumLateralSpec::load_watched(manifest_indicator); + + [ + Some( + quadruped_medium_central_spec + .mesh_head_upper(body.species, body.body_type, generate_mesh), + ), + Some( + quadruped_medium_central_spec + .mesh_head_lower(body.species, body.body_type, generate_mesh), + ), + Some( + quadruped_medium_central_spec + .mesh_jaw(body.species, body.body_type, generate_mesh), + ), + Some( + quadruped_medium_central_spec + .mesh_tail(body.species, body.body_type, generate_mesh), + ), + Some( + quadruped_medium_central_spec + .mesh_torso_f(body.species, body.body_type, generate_mesh), + ), + Some( + quadruped_medium_central_spec + .mesh_torso_b(body.species, body.body_type, generate_mesh), + ), + Some( + quadruped_medium_central_spec + .mesh_ears(body.species, body.body_type, generate_mesh), + ), + Some( + quadruped_medium_lateral_spec + .mesh_foot_lf(body.species, body.body_type, generate_mesh), + ), + Some( + quadruped_medium_lateral_spec + .mesh_foot_rf(body.species, body.body_type, generate_mesh), + ), + Some( + quadruped_medium_lateral_spec + .mesh_foot_lb(body.species, body.body_type, generate_mesh), + ), + Some( + quadruped_medium_lateral_spec + .mesh_foot_rb(body.species, body.body_type, generate_mesh), + ), + None, + None, + None, + None, + None, + ] + }, + Body::BirdMedium(body) => { + let bird_medium_center_spec = BirdMediumCenterSpec::load_watched(manifest_indicator); + let bird_medium_lateral_spec = BirdMediumLateralSpec::load_watched(manifest_indicator); + + [ + Some( + bird_medium_center_spec + .mesh_head(body.species, body.body_type, generate_mesh), + ), + Some( + bird_medium_center_spec + .mesh_torso(body.species, body.body_type, generate_mesh), + ), + Some( + bird_medium_center_spec + .mesh_tail(body.species, body.body_type, generate_mesh), + ), + Some( + bird_medium_lateral_spec + .mesh_wing_l(body.species, body.body_type, generate_mesh), + ), + Some( + bird_medium_lateral_spec + .mesh_wing_r(body.species, body.body_type, generate_mesh), + ), + Some( + bird_medium_lateral_spec + .mesh_foot_l(body.species, body.body_type, generate_mesh), + ), + Some( + bird_medium_lateral_spec + .mesh_foot_r(body.species, body.body_type, generate_mesh), + ), + None, + None, + None, + None, + None, + None, + None, + None, + None, + ] + }, + Body::FishMedium(body) => [ + Some(mesh_fish_medium_head(body.head, generate_mesh)), + Some(mesh_fish_medium_torso(body.torso, generate_mesh)), + Some(mesh_fish_medium_rear(body.rear, generate_mesh)), + Some(mesh_fish_medium_tail(body.tail, generate_mesh)), + Some(mesh_fish_medium_fin_l(body.fin_l, generate_mesh)), + Some(mesh_fish_medium_fin_r(body.fin_r, generate_mesh)), + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + ], + Body::Dragon(body) => [ + Some(mesh_dragon_head(body.head, generate_mesh)), + Some(mesh_dragon_chest_front(body.chest_front, generate_mesh)), + Some(mesh_dragon_chest_rear(body.chest_rear, generate_mesh)), + Some(mesh_dragon_tail_front(body.tail_front, generate_mesh)), + Some(mesh_dragon_tail_rear(body.tail_rear, generate_mesh)), + Some(mesh_dragon_wing_in_l(body.wing_in_l, generate_mesh)), + Some(mesh_dragon_wing_in_r(body.wing_in_r, generate_mesh)), + Some(mesh_dragon_wing_out_l(body.wing_out_l, generate_mesh)), + Some(mesh_dragon_wing_out_r(body.wing_out_r, generate_mesh)), + Some(mesh_dragon_foot_fl(body.foot_fl, generate_mesh)), + Some(mesh_dragon_foot_fr(body.foot_fr, generate_mesh)), + Some(mesh_dragon_foot_bl(body.foot_bl, generate_mesh)), + Some(mesh_dragon_foot_br(body.foot_br, generate_mesh)), + None, + None, + None, + ], + Body::BirdSmall(body) => [ + Some(mesh_bird_small_head(body.head, generate_mesh)), + Some(mesh_bird_small_torso(body.torso, generate_mesh)), + Some(mesh_bird_small_wing_l(body.wing_l, generate_mesh)), + Some(mesh_bird_small_wing_r(body.wing_r, generate_mesh)), + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + ], + Body::FishSmall(body) => [ + Some(mesh_fish_small_torso(body.torso, generate_mesh)), + Some(mesh_fish_small_tail(body.tail, generate_mesh)), + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + ], + Body::BipedLarge(body) => { + let biped_large_center_spec = BipedLargeCenterSpec::load_watched(manifest_indicator); + let biped_large_lateral_spec = BipedLargeLateralSpec::load_watched(manifest_indicator); + + [ + Some( + biped_large_center_spec + .mesh_head(body.species, body.body_type, generate_mesh), + ), + Some( + biped_large_center_spec + .mesh_torso_upper(body.species, body.body_type, generate_mesh), + ), + Some( + biped_large_center_spec + .mesh_torso_lower(body.species, body.body_type, generate_mesh), + ), + Some( + biped_large_lateral_spec + .mesh_shoulder_l(body.species, body.body_type, generate_mesh), + ), + Some( + biped_large_lateral_spec + .mesh_shoulder_r(body.species, body.body_type, generate_mesh), + ), + Some( + biped_large_lateral_spec + .mesh_hand_l(body.species, body.body_type, generate_mesh), + ), + Some( + biped_large_lateral_spec + .mesh_hand_r(body.species, body.body_type, generate_mesh), + ), + Some( + biped_large_lateral_spec + .mesh_leg_l(body.species, body.body_type, generate_mesh), + ), + Some( + biped_large_lateral_spec + .mesh_leg_r(body.species, body.body_type, generate_mesh), + ), + Some( + biped_large_lateral_spec + .mesh_foot_l(body.species, body.body_type, generate_mesh), + ), + Some( + biped_large_lateral_spec + .mesh_foot_r(body.species, body.body_type, generate_mesh), + ), + None, + None, + None, + None, + None, + ] + }, + Body::Critter(body) => { + let critter_center_spec = + CritterCenterSpec::load_watched(manifest_indicator); + + [ + Some( + critter_center_spec.mesh_head(body.species, body.body_type, generate_mesh), + ), + Some( + critter_center_spec + .mesh_chest(body.species, body.body_type, generate_mesh), + ), + Some( + critter_center_spec + .mesh_feet_f(body.species, body.body_type, generate_mesh), + ), + Some( + critter_center_spec + .mesh_feet_b(body.species, body.body_type, generate_mesh), + ), + Some( + critter_center_spec.mesh_tail(body.species, body.body_type, generate_mesh), + ), + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + ] + }, + Body::Object(object) => [ + Some(mesh_object(object, generate_mesh)), + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + ], + } + } + pub fn get_or_create_model( &mut self, renderer: &mut Renderer, @@ -84,7 +561,7 @@ impl FigureModelCache { tick: u64, camera_mode: CameraMode, character_state: Option<&CharacterState>, - ) -> &(Model, Skel::Attr) + ) -> &([Model; 3], Skel::Attr) where for<'a> &'a common::comp::Body: std::convert::TryInto, Skel::Attr: Default, @@ -108,501 +585,43 @@ impl FigureModelCache { Entry::Vacant(v) => { &v.insert(( { - let bone_meshes = match body { - Body::Humanoid(body) => { - let humanoid_head_spec = - HumHeadSpec::load_watched(&mut self.manifest_indicator); - let humanoid_armor_shoulder_spec = - HumArmorShoulderSpec::load_watched( - &mut self.manifest_indicator, - ); - let humanoid_armor_chest_spec = - HumArmorChestSpec::load_watched(&mut self.manifest_indicator); - let humanoid_armor_hand_spec = - HumArmorHandSpec::load_watched(&mut self.manifest_indicator); - let humanoid_armor_belt_spec = - HumArmorBeltSpec::load_watched(&mut self.manifest_indicator); - let humanoid_armor_back_spec = - HumArmorBackSpec::load_watched(&mut self.manifest_indicator); - let humanoid_armor_lantern_spec = - HumArmorLanternSpec::load_watched(&mut self.manifest_indicator); - let humanoid_armor_pants_spec = - HumArmorPantsSpec::load_watched(&mut self.manifest_indicator); - let humanoid_armor_foot_spec = - HumArmorFootSpec::load_watched(&mut self.manifest_indicator); - let humanoid_main_weapon_spec = - HumMainWeaponSpec::load_watched(&mut self.manifest_indicator); - - // TODO: This is bad code, maybe this method should return Option<_> - let default_loadout = Loadout::default(); - let loadout = loadout.unwrap_or(&default_loadout); - - [ - match camera_mode { - CameraMode::ThirdPerson => { - Some(humanoid_head_spec.mesh_head( - body.race, - body.body_type, - body.hair_color, - body.hair_style, - body.beard, - body.eye_color, - body.skin, - body.eyebrows, - body.accessory, - )) - }, - CameraMode::FirstPerson => None, - }, - match camera_mode { - CameraMode::ThirdPerson => Some( - humanoid_armor_chest_spec.mesh_chest(&body, loadout), - ), - CameraMode::FirstPerson => None, - }, - match camera_mode { - CameraMode::ThirdPerson => { - Some(humanoid_armor_belt_spec.mesh_belt(&body, loadout)) - }, - CameraMode::FirstPerson => None, - }, - match camera_mode { - CameraMode::ThirdPerson => { - Some(humanoid_armor_back_spec.mesh_back(&body, loadout)) - }, - CameraMode::FirstPerson => None, - }, - match camera_mode { - CameraMode::ThirdPerson => Some( - humanoid_armor_pants_spec.mesh_pants(&body, loadout), - ), - CameraMode::FirstPerson => None, - }, - if camera_mode == CameraMode::FirstPerson - && character_state - .map(|cs| cs.is_dodge()) - .unwrap_or_default() - { - None - } else { - Some( - humanoid_armor_hand_spec.mesh_left_hand(&body, loadout), - ) - }, - if character_state.map(|cs| cs.is_dodge()).unwrap_or_default() { - None - } else { - Some( - humanoid_armor_hand_spec - .mesh_right_hand(&body, loadout), - ) - }, - match camera_mode { - CameraMode::ThirdPerson => Some( - humanoid_armor_foot_spec.mesh_left_foot(&body, loadout), - ), - CameraMode::FirstPerson => None, - }, - match camera_mode { - CameraMode::ThirdPerson => Some( - humanoid_armor_foot_spec - .mesh_right_foot(&body, loadout), - ), - CameraMode::FirstPerson => None, - }, - match camera_mode { - CameraMode::ThirdPerson => Some( - humanoid_armor_shoulder_spec - .mesh_left_shoulder(&body, loadout), - ), - CameraMode::FirstPerson => None, - }, - match camera_mode { - CameraMode::ThirdPerson => Some( - humanoid_armor_shoulder_spec - .mesh_right_shoulder(&body, loadout), - ), - CameraMode::FirstPerson => None, - }, - Some(mesh_glider()), - if camera_mode != CameraMode::FirstPerson - || 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.active_item.as_ref().map(|i| &i.item.kind), - )) - } else { - None - }, - None, - Some(humanoid_armor_lantern_spec.mesh_lantern(&body, loadout)), - None, - ] - }, - Body::QuadrupedSmall(body) => { - let quadruped_small_central_spec = - QuadrupedSmallCentralSpec::load_watched( - &mut self.manifest_indicator, - ); - let quadruped_small_lateral_spec = - QuadrupedSmallLateralSpec::load_watched( - &mut self.manifest_indicator, - ); - - [ - Some( - quadruped_small_central_spec - .mesh_head(body.species, body.body_type), - ), - Some( - quadruped_small_central_spec - .mesh_chest(body.species, body.body_type), - ), - Some( - quadruped_small_lateral_spec - .mesh_foot_lf(body.species, body.body_type), - ), - Some( - quadruped_small_lateral_spec - .mesh_foot_rf(body.species, body.body_type), - ), - Some( - quadruped_small_lateral_spec - .mesh_foot_lb(body.species, body.body_type), - ), - Some( - quadruped_small_lateral_spec - .mesh_foot_rb(body.species, body.body_type), - ), - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - ] - }, - Body::QuadrupedMedium(body) => { - let quadruped_medium_central_spec = - QuadrupedMediumCentralSpec::load_watched( - &mut self.manifest_indicator, - ); - let quadruped_medium_lateral_spec = - QuadrupedMediumLateralSpec::load_watched( - &mut self.manifest_indicator, - ); - - [ - Some( - quadruped_medium_central_spec - .mesh_head_upper(body.species, body.body_type), - ), - Some( - quadruped_medium_central_spec - .mesh_head_lower(body.species, body.body_type), - ), - Some( - quadruped_medium_central_spec - .mesh_jaw(body.species, body.body_type), - ), - Some( - quadruped_medium_central_spec - .mesh_tail(body.species, body.body_type), - ), - Some( - quadruped_medium_central_spec - .mesh_torso_f(body.species, body.body_type), - ), - Some( - quadruped_medium_central_spec - .mesh_torso_b(body.species, body.body_type), - ), - Some( - quadruped_medium_central_spec - .mesh_ears(body.species, body.body_type), - ), - Some( - quadruped_medium_lateral_spec - .mesh_foot_lf(body.species, body.body_type), - ), - Some( - quadruped_medium_lateral_spec - .mesh_foot_rf(body.species, body.body_type), - ), - Some( - quadruped_medium_lateral_spec - .mesh_foot_lb(body.species, body.body_type), - ), - Some( - quadruped_medium_lateral_spec - .mesh_foot_rb(body.species, body.body_type), - ), - None, - None, - None, - None, - None, - ] - }, - Body::BirdMedium(body) => { - let bird_medium_center_spec = BirdMediumCenterSpec::load_watched( - &mut self.manifest_indicator, - ); - let bird_medium_lateral_spec = BirdMediumLateralSpec::load_watched( - &mut self.manifest_indicator, - ); - - [ - Some( - bird_medium_center_spec - .mesh_head(body.species, body.body_type), - ), - Some( - bird_medium_center_spec - .mesh_torso(body.species, body.body_type), - ), - Some( - bird_medium_center_spec - .mesh_tail(body.species, body.body_type), - ), - Some( - bird_medium_lateral_spec - .mesh_wing_l(body.species, body.body_type), - ), - Some( - bird_medium_lateral_spec - .mesh_wing_r(body.species, body.body_type), - ), - Some( - bird_medium_lateral_spec - .mesh_foot_l(body.species, body.body_type), - ), - Some( - bird_medium_lateral_spec - .mesh_foot_r(body.species, body.body_type), - ), - None, - None, - None, - None, - None, - None, - None, - None, - None, - ] - }, - Body::FishMedium(body) => [ - Some(mesh_fish_medium_head(body.head)), - Some(mesh_fish_medium_torso(body.torso)), - Some(mesh_fish_medium_rear(body.rear)), - Some(mesh_fish_medium_tail(body.tail)), - Some(mesh_fish_medium_fin_l(body.fin_l)), - Some(mesh_fish_medium_fin_r(body.fin_r)), - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - ], - Body::Dragon(body) => [ - Some(mesh_dragon_head(body.head)), - Some(mesh_dragon_chest_front(body.chest_front)), - Some(mesh_dragon_chest_rear(body.chest_rear)), - Some(mesh_dragon_tail_front(body.tail_front)), - Some(mesh_dragon_tail_rear(body.tail_rear)), - Some(mesh_dragon_wing_in_l(body.wing_in_l)), - Some(mesh_dragon_wing_in_r(body.wing_in_r)), - Some(mesh_dragon_wing_out_l(body.wing_out_l)), - Some(mesh_dragon_wing_out_r(body.wing_out_r)), - Some(mesh_dragon_foot_fl(body.foot_fl)), - Some(mesh_dragon_foot_fr(body.foot_fr)), - Some(mesh_dragon_foot_bl(body.foot_bl)), - Some(mesh_dragon_foot_br(body.foot_br)), - None, - None, - None, - ], - Body::BirdSmall(body) => [ - Some(mesh_bird_small_head(body.head)), - Some(mesh_bird_small_torso(body.torso)), - Some(mesh_bird_small_wing_l(body.wing_l)), - Some(mesh_bird_small_wing_r(body.wing_r)), - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - ], - Body::FishSmall(body) => [ - Some(mesh_fish_small_torso(body.torso)), - Some(mesh_fish_small_tail(body.tail)), - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - ], - Body::BipedLarge(body) => { - let biped_large_center_spec = BipedLargeCenterSpec::load_watched( - &mut self.manifest_indicator, - ); - let biped_large_lateral_spec = BipedLargeLateralSpec::load_watched( - &mut self.manifest_indicator, - ); - - [ - Some( - biped_large_center_spec - .mesh_head(body.species, body.body_type), - ), - Some( - biped_large_center_spec - .mesh_torso_upper(body.species, body.body_type), - ), - Some( - biped_large_center_spec - .mesh_torso_lower(body.species, body.body_type), - ), - Some( - biped_large_lateral_spec - .mesh_shoulder_l(body.species, body.body_type), - ), - Some( - biped_large_lateral_spec - .mesh_shoulder_r(body.species, body.body_type), - ), - Some( - biped_large_lateral_spec - .mesh_hand_l(body.species, body.body_type), - ), - Some( - biped_large_lateral_spec - .mesh_hand_r(body.species, body.body_type), - ), - Some( - biped_large_lateral_spec - .mesh_leg_l(body.species, body.body_type), - ), - Some( - biped_large_lateral_spec - .mesh_leg_r(body.species, body.body_type), - ), - Some( - biped_large_lateral_spec - .mesh_foot_l(body.species, body.body_type), - ), - Some( - biped_large_lateral_spec - .mesh_foot_r(body.species, body.body_type), - ), - None, - None, - None, - None, - None, - ] - }, - Body::Critter(body) => { - let critter_center_spec = - CritterCenterSpec::load_watched(&mut self.manifest_indicator); - - [ - Some( - critter_center_spec.mesh_head(body.species, body.body_type), - ), - Some( - critter_center_spec - .mesh_chest(body.species, body.body_type), - ), - Some( - critter_center_spec - .mesh_feet_f(body.species, body.body_type), - ), - Some( - critter_center_spec - .mesh_feet_b(body.species, body.body_type), - ), - Some( - critter_center_spec.mesh_tail(body.species, body.body_type), - ), - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - ] - }, - Body::Object(object) => [ - Some(mesh_object(object)), - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - ], - }; - let skeleton_attr = (&body) .try_into() .ok() .unwrap_or_else(::default); - let mut mesh = Mesh::new(); - bone_meshes - .iter() - .enumerate() - .filter_map(|(i, bm)| bm.as_ref().map(|bm| (i, bm))) - .for_each(|(i, bone_mesh)| { - mesh.push_mesh_map(bone_mesh, |vert| vert.with_bone_idx(i as u8)) - }); + let manifest_indicator = &mut self.manifest_indicator; + let mut make_model = |generate_mesh| { + let mut mesh = Mesh::new(); + Self::bone_meshes(body, loadout, character_state, camera_mode, manifest_indicator, generate_mesh) + .iter() + .enumerate() + .filter_map(|(i, bm)| bm.as_ref().map(|bm| (i, bm))) + .for_each(|(i, bone_mesh)| { + mesh.push_mesh_map(bone_mesh, |vert| vert.with_bone_idx(i as u8)) + }); + renderer.create_model(&mesh).unwrap() + }; - (renderer.create_model(&mesh).unwrap(), skeleton_attr) + fn generate_mesh(segment: &Segment, offset: Vec3) -> Mesh { + Meshable::::generate_mesh(segment, (offset, Vec3::one())).0 + } + + fn generate_mesh_lod_mid(segment: &Segment, offset: Vec3) -> Mesh { + let lod_scale = Vec3::broadcast(0.6); + Meshable::::generate_mesh(&segment.scaled_by(lod_scale), (offset * lod_scale, Vec3::one() / lod_scale)).0 + } + + fn generate_mesh_lod_low(segment: &Segment, offset: Vec3) -> Mesh { + let lod_scale = Vec3::broadcast(0.3); + Meshable::::generate_mesh(&segment.scaled_by(lod_scale), (offset * lod_scale, Vec3::one() / lod_scale)).0 + } + + ([ + make_model(generate_mesh), + make_model(generate_mesh_lod_mid), + make_model(generate_mesh_lod_low), + ], skeleton_attr) }, tick, )) diff --git a/voxygen/src/scene/figure/load.rs b/voxygen/src/scene/figure/load.rs index cfd6e86dc8..b19ab5e004 100644 --- a/voxygen/src/scene/figure/load.rs +++ b/voxygen/src/scene/figure/load.rs @@ -1,7 +1,4 @@ -use crate::{ - mesh::Meshable, - render::{FigurePipeline, Mesh}, -}; +use crate::render::{FigurePipeline, Mesh}; use common::{ assets::{self, watch::ReloadIndicator, Asset}, comp::{ @@ -54,11 +51,7 @@ fn graceful_load_mat_segment_flipped(mesh_name: &str) -> MatSegment { MatSegment::from_vox(graceful_load_vox(mesh_name).as_ref(), true) } -fn generate_mesh(segment: &Segment, offset: Vec3) -> Mesh { - Meshable::::generate_mesh(segment, (offset, Vec3::one())).0 -} - -pub fn load_mesh(mesh_name: &str, position: Vec3) -> Mesh { +pub fn load_mesh(mesh_name: &str, position: Vec3, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { generate_mesh(&load_segment(mesh_name), position) } @@ -159,6 +152,7 @@ impl HumHeadSpec { skin: u8, _eyebrows: Eyebrows, accessory: u8, + generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, ) -> Mesh { let spec = match self.0.get(&(race, body_type)) { Some(spec) => spec, @@ -167,7 +161,7 @@ impl HumHeadSpec { "No head specification exists for the combination of {:?} and {:?}", race, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; @@ -349,7 +343,7 @@ impl HumArmorShoulderSpec { .unwrap() } - fn mesh_shoulder(&self, body: &Body, loadout: &Loadout, flipped: bool) -> Mesh { + fn mesh_shoulder(&self, body: &Body, loadout: &Loadout, flipped: bool, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = if let Some(ItemKind::Armor { kind: Armor::Shoulder(shoulder), .. @@ -359,7 +353,7 @@ impl HumArmorShoulderSpec { Some(spec) => spec, None => { error!("No shoulder specification exists for {:?}", shoulder); - return load_mesh("not_found", Vec3::new(-3.0, -3.5, 0.1)); + return load_mesh("not_found", Vec3::new(-3.0, -3.5, 0.1), generate_mesh); }, } } else { @@ -391,12 +385,12 @@ impl HumArmorShoulderSpec { generate_mesh(&shoulder_segment, Vec3::from(offset)) } - pub fn mesh_left_shoulder(&self, body: &Body, loadout: &Loadout) -> Mesh { - self.mesh_shoulder(body, loadout, true) + pub fn mesh_left_shoulder(&self, body: &Body, loadout: &Loadout, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { + self.mesh_shoulder(body, loadout, true, generate_mesh) } - pub fn mesh_right_shoulder(&self, body: &Body, loadout: &Loadout) -> Mesh { - self.mesh_shoulder(body, loadout, false) + pub fn mesh_right_shoulder(&self, body: &Body, loadout: &Loadout, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { + self.mesh_shoulder(body, loadout, false, generate_mesh) } } // Chest @@ -406,7 +400,7 @@ impl HumArmorChestSpec { .unwrap() } - pub fn mesh_chest(&self, body: &Body, loadout: &Loadout) -> Mesh { + pub fn mesh_chest(&self, body: &Body, loadout: &Loadout, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = if let Some(ItemKind::Armor { kind: Armor::Chest(chest), .. @@ -416,7 +410,7 @@ impl HumArmorChestSpec { Some(spec) => spec, None => { error!("No chest specification exists for {:?}", loadout.chest); - return load_mesh("not_found", Vec3::new(-7.0, -3.5, 2.0)); + return load_mesh("not_found", Vec3::new(-7.0, -3.5, 2.0), generate_mesh); }, } } else { @@ -457,7 +451,7 @@ impl HumArmorHandSpec { .unwrap() } - fn mesh_hand(&self, body: &Body, loadout: &Loadout, flipped: bool) -> Mesh { + fn mesh_hand(&self, body: &Body, loadout: &Loadout, flipped: bool, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = if let Some(ItemKind::Armor { kind: Armor::Hand(hand), .. @@ -467,7 +461,7 @@ impl HumArmorHandSpec { Some(spec) => spec, None => { error!("No hand specification exists for {:?}", hand); - return load_mesh("not_found", Vec3::new(-1.5, -1.5, -7.0)); + return load_mesh("not_found", Vec3::new(-1.5, -1.5, -7.0), generate_mesh); }, } } else { @@ -494,12 +488,12 @@ impl HumArmorHandSpec { generate_mesh(&hand_segment, Vec3::from(offset)) } - pub fn mesh_left_hand(&self, body: &Body, loadout: &Loadout) -> Mesh { - self.mesh_hand(body, loadout, true) + pub fn mesh_left_hand(&self, body: &Body, loadout: &Loadout, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { + self.mesh_hand(body, loadout, true, generate_mesh) } - pub fn mesh_right_hand(&self, body: &Body, loadout: &Loadout) -> Mesh { - self.mesh_hand(body, loadout, false) + pub fn mesh_right_hand(&self, body: &Body, loadout: &Loadout, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { + self.mesh_hand(body, loadout, false, generate_mesh) } } // Belt @@ -509,7 +503,7 @@ impl HumArmorBeltSpec { .unwrap() } - pub fn mesh_belt(&self, body: &Body, loadout: &Loadout) -> Mesh { + pub fn mesh_belt(&self, body: &Body, loadout: &Loadout, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = if let Some(ItemKind::Armor { kind: Armor::Belt(belt), .. @@ -519,7 +513,7 @@ impl HumArmorBeltSpec { Some(spec) => spec, None => { error!("No belt specification exists for {:?}", belt); - return load_mesh("not_found", Vec3::new(-4.0, -3.5, 2.0)); + return load_mesh("not_found", Vec3::new(-4.0, -3.5, 2.0), generate_mesh); }, } } else { @@ -543,7 +537,7 @@ impl HumArmorBackSpec { .unwrap() } - pub fn mesh_back(&self, body: &Body, loadout: &Loadout) -> Mesh { + pub fn mesh_back(&self, body: &Body, loadout: &Loadout, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = if let Some(ItemKind::Armor { kind: Armor::Back(back), .. @@ -553,7 +547,7 @@ impl HumArmorBackSpec { Some(spec) => spec, None => { error!("No back specification exists for {:?}", back); - return load_mesh("not_found", Vec3::new(-4.0, -3.5, 2.0)); + return load_mesh("not_found", Vec3::new(-4.0, -3.5, 2.0), generate_mesh); }, } } else { @@ -577,7 +571,7 @@ impl HumArmorPantsSpec { .unwrap() } - pub fn mesh_pants(&self, body: &Body, loadout: &Loadout) -> Mesh { + pub fn mesh_pants(&self, body: &Body, loadout: &Loadout, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = if let Some(ItemKind::Armor { kind: Armor::Pants(pants), .. @@ -587,7 +581,7 @@ impl HumArmorPantsSpec { Some(spec) => spec, None => { error!("No pants specification exists for {:?}", pants); - return load_mesh("not_found", Vec3::new(-5.0, -3.5, 1.0)); + return load_mesh("not_found", Vec3::new(-5.0, -3.5, 1.0), generate_mesh); }, } } else { @@ -628,7 +622,7 @@ impl HumArmorFootSpec { .unwrap() } - fn mesh_foot(&self, body: &Body, loadout: &Loadout, flipped: bool) -> Mesh { + fn mesh_foot(&self, body: &Body, loadout: &Loadout, flipped: bool, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = if let Some(ItemKind::Armor { kind: Armor::Foot(foot), .. @@ -638,7 +632,7 @@ impl HumArmorFootSpec { Some(spec) => spec, None => { error!("No foot specification exists for {:?}", foot); - return load_mesh("not_found", Vec3::new(-2.5, -3.5, -9.0)); + return load_mesh("not_found", Vec3::new(-2.5, -3.5, -9.0), generate_mesh); }, } } else { @@ -659,12 +653,12 @@ impl HumArmorFootSpec { generate_mesh(&foot_segment, Vec3::from(spec.vox_spec.1)) } - pub fn mesh_left_foot(&self, body: &Body, loadout: &Loadout) -> Mesh { - self.mesh_foot(body, loadout, true) + pub fn mesh_left_foot(&self, body: &Body, loadout: &Loadout, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { + self.mesh_foot(body, loadout, true, generate_mesh) } - pub fn mesh_right_foot(&self, body: &Body, loadout: &Loadout) -> Mesh { - self.mesh_foot(body, loadout, false) + pub fn mesh_right_foot(&self, body: &Body, loadout: &Loadout, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { + self.mesh_foot(body, loadout, false, generate_mesh) } } @@ -674,7 +668,7 @@ impl HumMainWeaponSpec { .unwrap() } - pub fn mesh_main_weapon(&self, item_kind: Option<&ItemKind>) -> Mesh { + pub fn mesh_main_weapon(&self, item_kind: Option<&ItemKind>, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let tool_kind = if let Some(ItemKind::Tool(Tool { kind, .. })) = item_kind { kind } else { @@ -685,7 +679,7 @@ impl HumMainWeaponSpec { Some(spec) => spec, None => { error!("No hand specification exists for {:?}", tool_kind); - return load_mesh("not_found", Vec3::new(-1.5, -1.5, -7.0)); + return load_mesh("not_found", Vec3::new(-1.5, -1.5, -7.0), generate_mesh); }, }; @@ -699,14 +693,14 @@ impl HumArmorLanternSpec { assets::load_watched::("voxygen.voxel.humanoid_lantern_manifest", indicator).unwrap() } - pub fn mesh_lantern(&self, body: &Body, loadout: &Loadout) -> Mesh { + pub fn mesh_lantern(&self, body: &Body, loadout: &Loadout, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { 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)); + return load_mesh("not_found", Vec3::new(-4.0, -3.5, 2.0), generate_mesh); }, } } else { @@ -729,7 +723,7 @@ impl HumArmorHeadSpec { .unwrap() } - pub fn mesh_head(&self, body: &Body, loadout: &Loadout) -> Mesh { + pub fn mesh_head(&self, body: &Body, loadout: &Loadout, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = if let Some(ItemKind::Armor { kind: Armor::Head(head), .. @@ -739,7 +733,7 @@ impl HumArmorHeadSpec { Some(spec) => spec, None => { error!("No head specification exists for {:?}", head); - return load_mesh("not_found", Vec3::new(-5.0, -3.5, 1.0)); + return load_mesh("not_found", Vec3::new(-5.0, -3.5, 1.0), generate_mesh); }, } } else { @@ -779,7 +773,7 @@ impl HumArmorTabardSpec { .unwrap() } - pub fn mesh_tabard(&self, body: &Body, loadout: &Loadout) -> Mesh { + pub fn mesh_tabard(&self, body: &Body, loadout: &Loadout, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = if let Some(ItemKind::Armor { kind: Armor::Tabard(tabard), .. @@ -789,7 +783,7 @@ impl HumArmorTabardSpec { Some(spec) => spec, None => { error!("No tabard specification exists for {:?}", tabard); - return load_mesh("not_found", Vec3::new(-5.0, -3.5, 1.0)); + return load_mesh("not_found", Vec3::new(-5.0, -3.5, 1.0), generate_mesh); }, } } else { @@ -824,8 +818,8 @@ impl HumArmorTabardSpec { } } // TODO: Inventory -pub fn mesh_glider() -> Mesh { - load_mesh("object.glider", Vec3::new(-26.0, -26.0, -5.0)) +pub fn mesh_glider(generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { + load_mesh("object.glider", Vec3::new(-26.0, -26.0, -5.0), generate_mesh) } ///////// @@ -881,7 +875,7 @@ impl QuadrupedSmallCentralSpec { .unwrap() } - pub fn mesh_head(&self, species: QSSpecies, body_type: QSBodyType) -> Mesh { + pub fn mesh_head(&self, species: QSSpecies, body_type: QSBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -889,7 +883,7 @@ impl QuadrupedSmallCentralSpec { "No head specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let central = graceful_load_segment(&spec.head.central.0); @@ -897,7 +891,7 @@ impl QuadrupedSmallCentralSpec { generate_mesh(¢ral, Vec3::from(spec.head.offset)) } - pub fn mesh_chest(&self, species: QSSpecies, body_type: QSBodyType) -> Mesh { + pub fn mesh_chest(&self, species: QSSpecies, body_type: QSBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -905,7 +899,7 @@ impl QuadrupedSmallCentralSpec { "No chest specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let central = graceful_load_segment(&spec.chest.central.0); @@ -920,7 +914,7 @@ impl QuadrupedSmallLateralSpec { .unwrap() } - pub fn mesh_foot_lf(&self, species: QSSpecies, body_type: QSBodyType) -> Mesh { + pub fn mesh_foot_lf(&self, species: QSSpecies, body_type: QSBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -928,7 +922,7 @@ impl QuadrupedSmallLateralSpec { "No leg specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let lateral = graceful_load_segment(&spec.left_front.lateral.0); @@ -936,7 +930,7 @@ impl QuadrupedSmallLateralSpec { generate_mesh(&lateral, Vec3::from(spec.left_front.offset)) } - pub fn mesh_foot_rf(&self, species: QSSpecies, body_type: QSBodyType) -> Mesh { + pub fn mesh_foot_rf(&self, species: QSSpecies, body_type: QSBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -944,7 +938,7 @@ impl QuadrupedSmallLateralSpec { "No leg specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let lateral = graceful_load_segment(&spec.right_front.lateral.0); @@ -952,7 +946,7 @@ impl QuadrupedSmallLateralSpec { generate_mesh(&lateral, Vec3::from(spec.right_front.offset)) } - pub fn mesh_foot_lb(&self, species: QSSpecies, body_type: QSBodyType) -> Mesh { + pub fn mesh_foot_lb(&self, species: QSSpecies, body_type: QSBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -960,7 +954,7 @@ impl QuadrupedSmallLateralSpec { "No leg specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let lateral = graceful_load_segment(&spec.left_back.lateral.0); @@ -968,7 +962,7 @@ impl QuadrupedSmallLateralSpec { generate_mesh(&lateral, Vec3::from(spec.left_back.offset)) } - pub fn mesh_foot_rb(&self, species: QSSpecies, body_type: QSBodyType) -> Mesh { + pub fn mesh_foot_rb(&self, species: QSSpecies, body_type: QSBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -976,7 +970,7 @@ impl QuadrupedSmallLateralSpec { "No leg specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let lateral = graceful_load_segment(&spec.right_back.lateral.0); @@ -1046,6 +1040,7 @@ impl QuadrupedMediumCentralSpec { &self, species: QMSpecies, body_type: QMBodyType, + generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, ) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, @@ -1054,7 +1049,7 @@ impl QuadrupedMediumCentralSpec { "No upper head specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let central = graceful_load_segment(&spec.upper.central.0); @@ -1066,6 +1061,7 @@ impl QuadrupedMediumCentralSpec { &self, species: QMSpecies, body_type: QMBodyType, + generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, ) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, @@ -1074,7 +1070,7 @@ impl QuadrupedMediumCentralSpec { "No lower head specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let central = graceful_load_segment(&spec.lower.central.0); @@ -1082,7 +1078,7 @@ impl QuadrupedMediumCentralSpec { generate_mesh(¢ral, Vec3::from(spec.lower.offset)) } - pub fn mesh_jaw(&self, species: QMSpecies, body_type: QMBodyType) -> Mesh { + pub fn mesh_jaw(&self, species: QMSpecies, body_type: QMBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1090,7 +1086,7 @@ impl QuadrupedMediumCentralSpec { "No jaw specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let central = graceful_load_segment(&spec.jaw.central.0); @@ -1098,7 +1094,7 @@ impl QuadrupedMediumCentralSpec { generate_mesh(¢ral, Vec3::from(spec.jaw.offset)) } - pub fn mesh_ears(&self, species: QMSpecies, body_type: QMBodyType) -> Mesh { + pub fn mesh_ears(&self, species: QMSpecies, body_type: QMBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1106,7 +1102,7 @@ impl QuadrupedMediumCentralSpec { "No ears specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let central = graceful_load_segment(&spec.ears.central.0); @@ -1114,7 +1110,7 @@ impl QuadrupedMediumCentralSpec { generate_mesh(¢ral, Vec3::from(spec.ears.offset)) } - pub fn mesh_torso_f(&self, species: QMSpecies, body_type: QMBodyType) -> Mesh { + pub fn mesh_torso_f(&self, species: QMSpecies, body_type: QMBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1122,7 +1118,7 @@ impl QuadrupedMediumCentralSpec { "No torso specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let central = graceful_load_segment(&spec.torso_f.central.0); @@ -1130,7 +1126,7 @@ impl QuadrupedMediumCentralSpec { generate_mesh(¢ral, Vec3::from(spec.torso_f.offset)) } - pub fn mesh_torso_b(&self, species: QMSpecies, body_type: QMBodyType) -> Mesh { + pub fn mesh_torso_b(&self, species: QMSpecies, body_type: QMBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1138,7 +1134,7 @@ impl QuadrupedMediumCentralSpec { "No torso specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let central = graceful_load_segment(&spec.torso_b.central.0); @@ -1146,7 +1142,7 @@ impl QuadrupedMediumCentralSpec { generate_mesh(¢ral, Vec3::from(spec.torso_b.offset)) } - pub fn mesh_tail(&self, species: QMSpecies, body_type: QMBodyType) -> Mesh { + pub fn mesh_tail(&self, species: QMSpecies, body_type: QMBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1154,7 +1150,7 @@ impl QuadrupedMediumCentralSpec { "No tail specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let central = graceful_load_segment(&spec.tail.central.0); @@ -1169,7 +1165,7 @@ impl QuadrupedMediumLateralSpec { .unwrap() } - pub fn mesh_foot_lf(&self, species: QMSpecies, body_type: QMBodyType) -> Mesh { + pub fn mesh_foot_lf(&self, species: QMSpecies, body_type: QMBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1177,7 +1173,7 @@ impl QuadrupedMediumLateralSpec { "No foot specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let lateral = graceful_load_segment(&spec.left_front.lateral.0); @@ -1185,7 +1181,7 @@ impl QuadrupedMediumLateralSpec { generate_mesh(&lateral, Vec3::from(spec.left_front.offset)) } - pub fn mesh_foot_rf(&self, species: QMSpecies, body_type: QMBodyType) -> Mesh { + pub fn mesh_foot_rf(&self, species: QMSpecies, body_type: QMBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1193,7 +1189,7 @@ impl QuadrupedMediumLateralSpec { "No foot specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let lateral = graceful_load_segment(&spec.right_front.lateral.0); @@ -1201,7 +1197,7 @@ impl QuadrupedMediumLateralSpec { generate_mesh(&lateral, Vec3::from(spec.right_front.offset)) } - pub fn mesh_foot_lb(&self, species: QMSpecies, body_type: QMBodyType) -> Mesh { + pub fn mesh_foot_lb(&self, species: QMSpecies, body_type: QMBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1209,7 +1205,7 @@ impl QuadrupedMediumLateralSpec { "No foot specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let lateral = graceful_load_segment(&spec.left_back.lateral.0); @@ -1217,7 +1213,7 @@ impl QuadrupedMediumLateralSpec { generate_mesh(&lateral, Vec3::from(spec.left_back.offset)) } - pub fn mesh_foot_rb(&self, species: QMSpecies, body_type: QMBodyType) -> Mesh { + pub fn mesh_foot_rb(&self, species: QMSpecies, body_type: QMBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1225,7 +1221,7 @@ impl QuadrupedMediumLateralSpec { "No foot specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let lateral = graceful_load_segment(&spec.right_back.lateral.0); @@ -1288,7 +1284,7 @@ impl BirdMediumCenterSpec { .unwrap() } - pub fn mesh_head(&self, species: BMSpecies, body_type: BMBodyType) -> Mesh { + pub fn mesh_head(&self, species: BMSpecies, body_type: BMBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1296,7 +1292,7 @@ impl BirdMediumCenterSpec { "No head specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let center = graceful_load_segment(&spec.head.center.0); @@ -1304,7 +1300,7 @@ impl BirdMediumCenterSpec { generate_mesh(¢er, Vec3::from(spec.head.offset)) } - pub fn mesh_torso(&self, species: BMSpecies, body_type: BMBodyType) -> Mesh { + pub fn mesh_torso(&self, species: BMSpecies, body_type: BMBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1312,7 +1308,7 @@ impl BirdMediumCenterSpec { "No torso specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let center = graceful_load_segment(&spec.torso.center.0); @@ -1320,7 +1316,7 @@ impl BirdMediumCenterSpec { generate_mesh(¢er, Vec3::from(spec.torso.offset)) } - pub fn mesh_tail(&self, species: BMSpecies, body_type: BMBodyType) -> Mesh { + pub fn mesh_tail(&self, species: BMSpecies, body_type: BMBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1328,7 +1324,7 @@ impl BirdMediumCenterSpec { "No tail specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let center = graceful_load_segment(&spec.tail.center.0); @@ -1342,7 +1338,7 @@ impl BirdMediumLateralSpec { .unwrap() } - pub fn mesh_wing_l(&self, species: BMSpecies, body_type: BMBodyType) -> Mesh { + pub fn mesh_wing_l(&self, species: BMSpecies, body_type: BMBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1350,7 +1346,7 @@ impl BirdMediumLateralSpec { "No wing specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let lateral = graceful_load_segment(&spec.wing_l.lateral.0); @@ -1358,7 +1354,7 @@ impl BirdMediumLateralSpec { generate_mesh(&lateral, Vec3::from(spec.wing_l.offset)) } - pub fn mesh_wing_r(&self, species: BMSpecies, body_type: BMBodyType) -> Mesh { + pub fn mesh_wing_r(&self, species: BMSpecies, body_type: BMBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1366,7 +1362,7 @@ impl BirdMediumLateralSpec { "No wing specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let lateral = graceful_load_segment(&spec.wing_r.lateral.0); @@ -1374,7 +1370,7 @@ impl BirdMediumLateralSpec { generate_mesh(&lateral, Vec3::from(spec.wing_r.offset)) } - pub fn mesh_foot_l(&self, species: BMSpecies, body_type: BMBodyType) -> Mesh { + pub fn mesh_foot_l(&self, species: BMSpecies, body_type: BMBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1382,7 +1378,7 @@ impl BirdMediumLateralSpec { "No foot specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let lateral = graceful_load_segment(&spec.foot_l.lateral.0); @@ -1390,7 +1386,7 @@ impl BirdMediumLateralSpec { generate_mesh(&lateral, Vec3::from(spec.foot_l.offset)) } - pub fn mesh_foot_r(&self, species: BMSpecies, body_type: BMBodyType) -> Mesh { + pub fn mesh_foot_r(&self, species: BMSpecies, body_type: BMBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1398,7 +1394,7 @@ impl BirdMediumLateralSpec { "No foot specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let lateral = graceful_load_segment(&spec.foot_r.lateral.0); @@ -1437,7 +1433,7 @@ impl CritterCenterSpec { assets::load_watched::("voxygen.voxel.critter_center_manifest", indicator).unwrap() } - pub fn mesh_head(&self, species: CSpecies, body_type: CBodyType) -> Mesh { + pub fn mesh_head(&self, species: CSpecies, body_type: CBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1445,7 +1441,7 @@ impl CritterCenterSpec { "No head specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let center = graceful_load_segment(&spec.head.center.0); @@ -1453,7 +1449,7 @@ impl CritterCenterSpec { generate_mesh(¢er, Vec3::from(spec.head.offset)) } - pub fn mesh_chest(&self, species: CSpecies, body_type: CBodyType) -> Mesh { + pub fn mesh_chest(&self, species: CSpecies, body_type: CBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1461,7 +1457,7 @@ impl CritterCenterSpec { "No chest specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let center = graceful_load_segment(&spec.chest.center.0); @@ -1469,7 +1465,7 @@ impl CritterCenterSpec { generate_mesh(¢er, Vec3::from(spec.chest.offset)) } - pub fn mesh_feet_f(&self, species: CSpecies, body_type: CBodyType) -> Mesh { + pub fn mesh_feet_f(&self, species: CSpecies, body_type: CBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1477,7 +1473,7 @@ impl CritterCenterSpec { "No feet specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let center = graceful_load_segment(&spec.feet_f.center.0); @@ -1485,7 +1481,7 @@ impl CritterCenterSpec { generate_mesh(¢er, Vec3::from(spec.feet_f.offset)) } - pub fn mesh_feet_b(&self, species: CSpecies, body_type: CBodyType) -> Mesh { + pub fn mesh_feet_b(&self, species: CSpecies, body_type: CBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1493,7 +1489,7 @@ impl CritterCenterSpec { "No feet specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let center = graceful_load_segment(&spec.feet_b.center.0); @@ -1501,7 +1497,7 @@ impl CritterCenterSpec { generate_mesh(¢er, Vec3::from(spec.feet_b.offset)) } - pub fn mesh_tail(&self, species: CSpecies, body_type: CBodyType) -> Mesh { + pub fn mesh_tail(&self, species: CSpecies, body_type: CBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1509,7 +1505,7 @@ impl CritterCenterSpec { "No tail specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let center = graceful_load_segment(&spec.tail.center.0); @@ -1518,229 +1514,254 @@ impl CritterCenterSpec { } } //// -pub fn mesh_fish_medium_head(head: fish_medium::Head) -> Mesh { +pub fn mesh_fish_medium_head(head: fish_medium::Head, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { load_mesh( match head { fish_medium::Head::Default => "npc.marlin.head", }, Vec3::new(-7.0, -6.0, -6.0), + generate_mesh, ) } -pub fn mesh_fish_medium_torso(torso: fish_medium::Torso) -> Mesh { +pub fn mesh_fish_medium_torso(torso: fish_medium::Torso, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { load_mesh( match torso { fish_medium::Torso::Default => "npc.marlin.torso", }, Vec3::new(-7.0, -6.0, -6.0), + generate_mesh, ) } -pub fn mesh_fish_medium_rear(rear: fish_medium::Rear) -> Mesh { +pub fn mesh_fish_medium_rear(rear: fish_medium::Rear, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { load_mesh( match rear { fish_medium::Rear::Default => "npc.marlin.rear", }, Vec3::new(-7.0, -6.0, -6.0), + generate_mesh, ) } -pub fn mesh_fish_medium_tail(tail: fish_medium::Tail) -> Mesh { +pub fn mesh_fish_medium_tail(tail: fish_medium::Tail, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { load_mesh( match tail { fish_medium::Tail::Default => "npc.marlin.tail", }, Vec3::new(-7.0, -6.0, -6.0), + generate_mesh, ) } -pub fn mesh_fish_medium_fin_l(fin_l: fish_medium::FinL) -> Mesh { +pub fn mesh_fish_medium_fin_l(fin_l: fish_medium::FinL, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { load_mesh( match fin_l { fish_medium::FinL::Default => "npc.marlin.fin_l", }, Vec3::new(-7.0, -6.0, -6.0), + generate_mesh, ) } -pub fn mesh_fish_medium_fin_r(fin_r: fish_medium::FinR) -> Mesh { +pub fn mesh_fish_medium_fin_r(fin_r: fish_medium::FinR, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { load_mesh( match fin_r { fish_medium::FinR::Default => "npc.marlin.fin_r", }, Vec3::new(-7.0, -6.0, -6.0), + generate_mesh, ) } -pub fn mesh_dragon_head(head: dragon::Head) -> Mesh { +pub fn mesh_dragon_head(head: dragon::Head, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { load_mesh( match head { dragon::Head::Default => "npc.dragon.head", }, Vec3::new(-7.0, -6.0, -6.0), + generate_mesh, ) } -pub fn mesh_dragon_chest_front(chest_front: dragon::ChestFront) -> Mesh { +pub fn mesh_dragon_chest_front(chest_front: dragon::ChestFront, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { load_mesh( match chest_front { dragon::ChestFront::Default => "npc.dragon.chest_front", }, Vec3::new(-7.0, -6.0, -6.0), + generate_mesh, ) } -pub fn mesh_dragon_chest_rear(chest_rear: dragon::ChestRear) -> Mesh { +pub fn mesh_dragon_chest_rear(chest_rear: dragon::ChestRear, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { load_mesh( match chest_rear { dragon::ChestRear::Default => "npc.dragon.chest_rear", }, Vec3::new(-7.0, -6.0, -6.0), + generate_mesh, ) } -pub fn mesh_dragon_tail_front(tail_front: dragon::TailFront) -> Mesh { +pub fn mesh_dragon_tail_front(tail_front: dragon::TailFront, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { load_mesh( match tail_front { dragon::TailFront::Default => "npc.dragon.tail_front", }, Vec3::new(-7.0, -6.0, -6.0), + generate_mesh, ) } -pub fn mesh_dragon_tail_rear(tail_rear: dragon::TailRear) -> Mesh { +pub fn mesh_dragon_tail_rear(tail_rear: dragon::TailRear, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { load_mesh( match tail_rear { dragon::TailRear::Default => "npc.dragon.tail_rear", }, Vec3::new(-7.0, -6.0, -6.0), + generate_mesh, ) } -pub fn mesh_dragon_wing_in_l(wing_in_l: dragon::WingInL) -> Mesh { +pub fn mesh_dragon_wing_in_l(wing_in_l: dragon::WingInL, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { load_mesh( match wing_in_l { dragon::WingInL::Default => "npc.dragon.wing_in_l", }, Vec3::new(-7.0, -6.0, -6.0), + generate_mesh, ) } -pub fn mesh_dragon_wing_in_r(wing_in_r: dragon::WingInR) -> Mesh { +pub fn mesh_dragon_wing_in_r(wing_in_r: dragon::WingInR, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { load_mesh( match wing_in_r { dragon::WingInR::Default => "npc.dragon.wing_in_r", }, Vec3::new(-7.0, -6.0, -6.0), + generate_mesh, ) } -pub fn mesh_dragon_wing_out_l(wing_out_l: dragon::WingOutL) -> Mesh { +pub fn mesh_dragon_wing_out_l(wing_out_l: dragon::WingOutL, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { load_mesh( match wing_out_l { dragon::WingOutL::Default => "npc.dragon.wing_out_l", }, Vec3::new(-7.0, -6.0, -6.0), + generate_mesh, ) } -pub fn mesh_dragon_wing_out_r(wing_out_r: dragon::WingOutR) -> Mesh { +pub fn mesh_dragon_wing_out_r(wing_out_r: dragon::WingOutR, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { load_mesh( match wing_out_r { dragon::WingOutR::Default => "npc.dragon.wing_out_r", }, Vec3::new(-7.0, -6.0, -6.0), + generate_mesh, ) } -pub fn mesh_dragon_foot_fl(foot_fl: dragon::FootFL) -> Mesh { +pub fn mesh_dragon_foot_fl(foot_fl: dragon::FootFL, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { load_mesh( match foot_fl { dragon::FootFL::Default => "npc.dragon.foot_fl", }, Vec3::new(-7.0, -6.0, -6.0), + generate_mesh, ) } -pub fn mesh_dragon_foot_fr(foot_fr: dragon::FootFR) -> Mesh { +pub fn mesh_dragon_foot_fr(foot_fr: dragon::FootFR, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { load_mesh( match foot_fr { dragon::FootFR::Default => "npc.dragon.foot_fr", }, Vec3::new(-7.0, -6.0, -6.0), + generate_mesh, ) } -pub fn mesh_dragon_foot_bl(foot_bl: dragon::FootBL) -> Mesh { +pub fn mesh_dragon_foot_bl(foot_bl: dragon::FootBL, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { load_mesh( match foot_bl { dragon::FootBL::Default => "npc.dragon.foot_bl", }, Vec3::new(-7.0, -6.0, -6.0), + generate_mesh, ) } -pub fn mesh_dragon_foot_br(foot_br: dragon::FootBR) -> Mesh { +pub fn mesh_dragon_foot_br(foot_br: dragon::FootBR, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { load_mesh( match foot_br { dragon::FootBR::Default => "npc.dragon.foot_br", }, Vec3::new(-7.0, -6.0, -6.0), + generate_mesh, ) } //// -pub fn mesh_bird_small_head(head: bird_small::Head) -> Mesh { +pub fn mesh_bird_small_head(head: bird_small::Head, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { load_mesh( match head { bird_small::Head::Default => "npc.crow.head", }, Vec3::new(-7.0, -6.0, -6.0), + generate_mesh, ) } -pub fn mesh_bird_small_torso(torso: bird_small::Torso) -> Mesh { +pub fn mesh_bird_small_torso(torso: bird_small::Torso, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { load_mesh( match torso { bird_small::Torso::Default => "npc.crow.torso", }, Vec3::new(-7.0, -6.0, -6.0), + generate_mesh, ) } -pub fn mesh_bird_small_wing_l(wing_l: bird_small::WingL) -> Mesh { +pub fn mesh_bird_small_wing_l(wing_l: bird_small::WingL, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { load_mesh( match wing_l { bird_small::WingL::Default => "npc.crow.wing_l", }, Vec3::new(-7.0, -6.0, -6.0), + generate_mesh, ) } -pub fn mesh_bird_small_wing_r(wing_r: bird_small::WingR) -> Mesh { +pub fn mesh_bird_small_wing_r(wing_r: bird_small::WingR, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { load_mesh( match wing_r { bird_small::WingR::Default => "npc.crow.wing_r", }, Vec3::new(-7.0, -6.0, -6.0), + generate_mesh, ) } //// -pub fn mesh_fish_small_torso(torso: fish_small::Torso) -> Mesh { +pub fn mesh_fish_small_torso(torso: fish_small::Torso, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { load_mesh( match torso { fish_small::Torso::Default => "npc.cardinalfish.torso", }, Vec3::new(-7.0, -6.0, -6.0), + generate_mesh, ) } -pub fn mesh_fish_small_tail(tail: fish_small::Tail) -> Mesh { +pub fn mesh_fish_small_tail(tail: fish_small::Tail, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { load_mesh( match tail { fish_small::Tail::Default => "npc.cardinalfish.tail", }, Vec3::new(-7.0, -6.0, -6.0), + generate_mesh, ) } //// @@ -1801,7 +1822,7 @@ impl BipedLargeCenterSpec { .unwrap() } - pub fn mesh_head(&self, species: BLSpecies, body_type: BLBodyType) -> Mesh { + pub fn mesh_head(&self, species: BLSpecies, body_type: BLBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1809,7 +1830,7 @@ impl BipedLargeCenterSpec { "No head specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let center = graceful_load_segment(&spec.head.center.0); @@ -1821,6 +1842,7 @@ impl BipedLargeCenterSpec { &self, species: BLSpecies, body_type: BLBodyType, + generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, ) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, @@ -1829,7 +1851,7 @@ impl BipedLargeCenterSpec { "No torso upper specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let center = graceful_load_segment(&spec.torso_upper.center.0); @@ -1841,6 +1863,7 @@ impl BipedLargeCenterSpec { &self, species: BLSpecies, body_type: BLBodyType, + generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, ) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, @@ -1849,7 +1872,7 @@ impl BipedLargeCenterSpec { "No torso lower specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let center = graceful_load_segment(&spec.torso_lower.center.0); @@ -1867,6 +1890,7 @@ impl BipedLargeLateralSpec { &self, species: BLSpecies, body_type: BLBodyType, + generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, ) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, @@ -1875,7 +1899,7 @@ impl BipedLargeLateralSpec { "No shoulder specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let lateral = graceful_load_segment(&spec.shoulder_l.lateral.0); @@ -1887,6 +1911,7 @@ impl BipedLargeLateralSpec { &self, species: BLSpecies, body_type: BLBodyType, + generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, ) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, @@ -1895,7 +1920,7 @@ impl BipedLargeLateralSpec { "No shoulder specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let lateral = graceful_load_segment(&spec.shoulder_r.lateral.0); @@ -1903,7 +1928,7 @@ impl BipedLargeLateralSpec { generate_mesh(&lateral, Vec3::from(spec.shoulder_r.offset)) } - pub fn mesh_hand_l(&self, species: BLSpecies, body_type: BLBodyType) -> Mesh { + pub fn mesh_hand_l(&self, species: BLSpecies, body_type: BLBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1911,7 +1936,7 @@ impl BipedLargeLateralSpec { "No hand specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let lateral = graceful_load_segment(&spec.hand_l.lateral.0); @@ -1919,7 +1944,7 @@ impl BipedLargeLateralSpec { generate_mesh(&lateral, Vec3::from(spec.hand_l.offset)) } - pub fn mesh_hand_r(&self, species: BLSpecies, body_type: BLBodyType) -> Mesh { + pub fn mesh_hand_r(&self, species: BLSpecies, body_type: BLBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1927,7 +1952,7 @@ impl BipedLargeLateralSpec { "No hand specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let lateral = graceful_load_segment(&spec.hand_r.lateral.0); @@ -1935,7 +1960,7 @@ impl BipedLargeLateralSpec { generate_mesh(&lateral, Vec3::from(spec.hand_r.offset)) } - pub fn mesh_leg_l(&self, species: BLSpecies, body_type: BLBodyType) -> Mesh { + pub fn mesh_leg_l(&self, species: BLSpecies, body_type: BLBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1943,7 +1968,7 @@ impl BipedLargeLateralSpec { "No leg specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let lateral = graceful_load_segment(&spec.leg_l.lateral.0); @@ -1951,7 +1976,7 @@ impl BipedLargeLateralSpec { generate_mesh(&lateral, Vec3::from(spec.leg_l.offset)) } - pub fn mesh_leg_r(&self, species: BLSpecies, body_type: BLBodyType) -> Mesh { + pub fn mesh_leg_r(&self, species: BLSpecies, body_type: BLBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1959,7 +1984,7 @@ impl BipedLargeLateralSpec { "No leg specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let lateral = graceful_load_segment(&spec.leg_r.lateral.0); @@ -1967,7 +1992,7 @@ impl BipedLargeLateralSpec { generate_mesh(&lateral, Vec3::from(spec.leg_r.offset)) } - pub fn mesh_foot_l(&self, species: BLSpecies, body_type: BLBodyType) -> Mesh { + pub fn mesh_foot_l(&self, species: BLSpecies, body_type: BLBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1975,7 +2000,7 @@ impl BipedLargeLateralSpec { "No foot specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let lateral = graceful_load_segment(&spec.foot_l.lateral.0); @@ -1983,7 +2008,7 @@ impl BipedLargeLateralSpec { generate_mesh(&lateral, Vec3::from(spec.foot_l.offset)) } - pub fn mesh_foot_r(&self, species: BLSpecies, body_type: BLBodyType) -> Mesh { + pub fn mesh_foot_r(&self, species: BLSpecies, body_type: BLBodyType, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1991,7 +2016,7 @@ impl BipedLargeLateralSpec { "No foot specification exists for the combination of {:?} and {:?}", species, body_type ); - return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); }, }; let lateral = graceful_load_segment(&spec.foot_r.lateral.0); @@ -2000,7 +2025,7 @@ impl BipedLargeLateralSpec { } } //// -pub fn mesh_object(obj: object::Body) -> Mesh { +pub fn mesh_object(obj: object::Body, generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh) -> Mesh { use object::Body; let (name, offset) = match obj { @@ -2064,5 +2089,5 @@ pub fn mesh_object(obj: object::Body) -> Mesh { Body::BoltFire => ("weapon.projectile.fire-bolt-0", Vec3::new(-3.0, -5.5, -3.0)), Body::BoltFireBig => ("weapon.projectile.fire-bolt-1", Vec3::new(-6.0, -6.0, -6.0)), }; - load_mesh(name, offset) + load_mesh(name, offset, generate_mesh) } diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index 1686f091e6..fc48ded02c 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -117,7 +117,7 @@ impl FigureMgr { .get(scene_data.player_entity) .map_or(Vec3::zero(), |pos| pos.0); - for ( + for (i, ( entity, pos, interpolated, @@ -129,7 +129,7 @@ impl FigureMgr { physics, stats, loadout, - ) in ( + )) in ( &ecs.entities(), &ecs.read_storage::(), ecs.read_storage::().maybe(), @@ -143,7 +143,20 @@ impl FigureMgr { ecs.read_storage::().maybe(), ) .join() + .enumerate() { + // Maintaining figure data and sending new figure data to the GPU turns out to be a + // very expensive operation. We want to avoid doing it as much as possible, so we + // make the assumption that players don't care so much about the update *rate* for far + // away things. As the entity goes further and further away, we start to 'skip' update + // ticks. + // TODO: Investigate passing the velocity into the shader so we can at least + // interpolate motion + const MIN_PERFECT_RATE_DIST: f32 = 96.0; + if (i as u64 + tick) % 1 + ((pos.0.distance(camera.get_focus_pos()).powf(0.5) - MIN_PERFECT_RATE_DIST.powf(0.5)).max(0.0) / 5.0) as u64 != 0 { + continue; + } + let is_player = scene_data.player_entity == entity; let (pos, ori) = interpolated @@ -1385,7 +1398,7 @@ impl FigureMgr { let character_state_storage = state.read_storage::(); let character_state = character_state_storage.get(player_entity); - for (entity, _, _, body, _, loadout, _) in ( + for (entity, pos, _, body, _, loadout, _) in ( &ecs.entities(), &ecs.read_storage::(), ecs.read_storage::().maybe(), @@ -1413,6 +1426,7 @@ impl FigureMgr { body, loadout, false, + pos.0, ); } } @@ -1434,7 +1448,10 @@ impl FigureMgr { let character_state_storage = state.read_storage::(); let character_state = character_state_storage.get(player_entity); - if let Some(body) = ecs.read_storage::().get(player_entity) { + if let (Some(pos), Some(body)) = ( + ecs.read_storage::().get(player_entity), + ecs.read_storage::().get(player_entity), + ) { let stats_storage = state.read_storage::(); let stats = stats_storage.get(player_entity); @@ -1457,6 +1474,7 @@ impl FigureMgr { body, loadout, true, + pos.0, ); } } @@ -1474,6 +1492,7 @@ impl FigureMgr { body: &Body, loadout: Option<&Loadout>, is_player: bool, + pos: Vec3, ) { let player_camera_mode = if is_player { camera.get_mode() @@ -1686,6 +1705,17 @@ impl FigureMgr { ) }), } { + const FIGURE_LOD_LOW_DIST: f32 = 150.0; + const FIGURE_LOD_MID_DIST: f32 = 70.0; + + let model = if pos.distance_squared(camera.get_focus_pos()) > FIGURE_LOD_LOW_DIST.powf(2.0) { + &model[2] + } else if pos.distance_squared(camera.get_focus_pos()) > FIGURE_LOD_MID_DIST.powf(2.0) { + &model[1] + } else { + &model[0] + }; + if is_player { renderer.render_player(model, globals, locals, bone_consts, lights, shadows); renderer.render_player_shadow(model, globals, locals, bone_consts, lights, shadows); diff --git a/voxygen/src/scene/simple.rs b/voxygen/src/scene/simple.rs index 77c1dbcf0f..5727ad1aa5 100644 --- a/voxygen/src/scene/simple.rs +++ b/voxygen/src/scene/simple.rs @@ -7,17 +7,20 @@ use crate::{ render::{ create_pp_mesh, create_skybox_mesh, Consts, FigurePipeline, Globals, Light, Model, PostProcessLocals, PostProcessPipeline, Renderer, Shadow, SkyboxLocals, SkyboxPipeline, + Mesh, }, scene::{ camera::{self, Camera, CameraMode}, figure::{load_mesh, FigureModelCache, FigureState}, }, window::{Event, PressState}, + mesh::Meshable, }; use common::{ comp::{humanoid, Body, Loadout}, terrain::BlockKind, vol::{BaseVol, ReadVol, Vox}, + figure::Segment, }; use log::error; use vek::*; @@ -40,6 +43,10 @@ impl ReadVol for VoidVol { fn get<'a>(&'a self, _pos: Vec3) -> Result<&'a Self::Vox, Self::Error> { Ok(&VoidVox) } } +fn generate_mesh(segment: &Segment, offset: Vec3) -> Mesh { + Meshable::::generate_mesh(segment, (offset, Vec3::one())).0 +} + struct Skybox { model: Model, locals: Consts, @@ -107,7 +114,7 @@ impl Scene { backdrop: backdrop.map(|specifier| { ( renderer - .create_model(&load_mesh(specifier, Vec3::new(-55.0, -49.5, -2.0))) + .create_model(&load_mesh(specifier, Vec3::new(-55.0, -49.5, -2.0), generate_mesh)) .unwrap(), FigureState::new(renderer, FixtureSkeleton::new()), ) @@ -229,7 +236,7 @@ impl Scene { .0; renderer.render_figure( - model, + &model[0], &self.globals, self.figure_state.locals(), self.figure_state.bone_consts(),