diff --git a/assets/voxygen/voxel/npc/horse/male/neck.vox b/assets/voxygen/voxel/npc/horse/male/neck.vox index 39c2b17862..8d7171dccb 100644 --- a/assets/voxygen/voxel/npc/horse/male/neck.vox +++ b/assets/voxygen/voxel/npc/horse/male/neck.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e6d847ffad7224ecc9c5dbfa39ca09449fedeccecec98e1cc64d3065391f91ae -size 2740 +oid sha256:3ff70352d9478827afbdf71564864ab9cdc9a7fa2c1626635416d3e1086d419e +size 28334 diff --git a/assets/voxygen/voxel/npc/horse/male/torso_back.vox b/assets/voxygen/voxel/npc/horse/male/torso_back.vox index ff6803b738..0a8b412006 100644 --- a/assets/voxygen/voxel/npc/horse/male/torso_back.vox +++ b/assets/voxygen/voxel/npc/horse/male/torso_back.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fdb53488f036cdf8ac2ac0b8a74529e8c8cf4a642f783477cedb9cd87ce8fe4d -size 3392 +oid sha256:9232ffcedd21c03ee12e1bab9424c4398a4ad0d27bf191e26be54438596cf19f +size 28986 diff --git a/assets/voxygen/voxel/npc/horse/male/torso_front.vox b/assets/voxygen/voxel/npc/horse/male/torso_front.vox index 13723afc29..7fc5dfb978 100644 --- a/assets/voxygen/voxel/npc/horse/male/torso_front.vox +++ b/assets/voxygen/voxel/npc/horse/male/torso_front.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b066ee1fb84a613b5cf1d0c8e23bab0e345ccac78b5cbbc231dc05ae453a411a -size 3944 +oid sha256:f225589fb4db6c1caed483a3369956d6354a0ce3e8c745dfa5e3b04616f32dc2 +size 29538 diff --git a/assets/voxygen/voxel/quadruped_medium_color_manifest.ron b/assets/voxygen/voxel/quadruped_medium_color_manifest.ron new file mode 100644 index 0000000000..da904f43e1 --- /dev/null +++ b/assets/voxygen/voxel/quadruped_medium_color_manifest.ron @@ -0,0 +1,22 @@ +#![enable(unwrap_newtypes)] + +( + skin_colors_plain: ( + HorseOne: (255, 5, 5), + HorseTwo: (255, 5, 255), + HorseThree: (255, 255, 5), + HorseFour: (133, 255, 255), + ), + skin_colors_light: ( + HorseOne: (255, 0, 0), + HorseTwo: (255, 0, 255), + HorseThree: (255, 255, 0), + HorseFour: (128, 255, 255), + ), + skin_colors_dark: ( + HorseOne: (255, 10, 10), + HorseTwo: (255, 10, 255), + HorseThree: (255, 255, 10), + HorseFour: (138, 255, 255), + ), +) diff --git a/common/src/comp/body/quadruped_medium.rs b/common/src/comp/body/quadruped_medium.rs index c657d289ce..a39fa70324 100644 --- a/common/src/comp/body/quadruped_medium.rs +++ b/common/src/comp/body/quadruped_medium.rs @@ -1,6 +1,7 @@ use crate::{make_case_elim, make_proj_elim}; use rand::{seq::SliceRandom, thread_rng}; use serde::{Deserialize, Serialize}; +use serde_repr::{Deserialize_repr, Serialize_repr}; make_proj_elim!( body, @@ -8,6 +9,8 @@ make_proj_elim!( pub struct Body { pub species: Species, pub body_type: BodyType, + #[typed(pure)] + pub skin: u8, } ); @@ -21,7 +24,11 @@ impl Body { #[inline] pub fn random_with(rng: &mut impl rand::Rng, &species: &Species) -> Self { let body_type = *(&ALL_BODY_TYPES).choose(rng).unwrap(); - Self { species, body_type } + Self { + species, + body_type, + skin: rng.gen_range(0..species.num_skin_colors()), + } } } @@ -152,3 +159,41 @@ make_case_elim!( ); pub const ALL_BODY_TYPES: [BodyType; 2] = [BodyType::Female, BodyType::Male]; + +// Skin colors +pub const HORSE_COLORS: [Skin; 4] = [ + Skin::HorseOne, + Skin::HorseTwo, + Skin::HorseThree, + Skin::HorseFour, +]; + +impl Species { + fn skin_colors(self) -> &'static [Skin] { + match self { + Species::Horse => &HORSE_COLORS, + _ => &HORSE_COLORS, + } + } + + pub fn skin_color(self, val: u8) -> Skin { + self.skin_colors() + .get(val as usize) + .copied() + .unwrap_or(Skin::HorseOne) + } + + pub fn num_skin_colors(self) -> u8 { self.skin_colors().len() as u8 } +} + +make_case_elim!( + skin, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize_repr, Deserialize_repr)] + #[repr(u32)] + pub enum Skin { + HorseOne = 0, + HorseTwo = 1, + HorseThree = 2, + HorseFour = 3, + } +); diff --git a/voxygen/src/scene/figure/load.rs b/voxygen/src/scene/figure/load.rs index 089c216c86..f7a9fbd5fa 100644 --- a/voxygen/src/scene/figure/load.rs +++ b/voxygen/src/scene/figure/load.rs @@ -12,7 +12,9 @@ use common::{ humanoid::{self, Body, BodyType, EyeColor, Skin, Species}, object, quadruped_low::{self, BodyType as QLBodyType, Species as QLSpecies}, - quadruped_medium::{self, BodyType as QMBodyType, Species as QMSpecies}, + quadruped_medium::{ + self, Body as QMBody, BodyType as QMBodyType, Skin as QMSkins, Species as QMSpecies, + }, quadruped_small::{self, BodyType as QSBodyType, Species as QSSpecies}, theropod::{self, BodyType as TBodyType, Species as TSpecies}, }, @@ -196,6 +198,29 @@ impl HumColorSpec { } } +/// Color information not found in voxels, for misc creatures. +#[derive(Deserialize)] +struct MiscColorSpec { + skin_colors_plain: quadruped_medium::skin::PureCases<(u8, u8, u8)>, + skin_colors_light: quadruped_medium::skin::PureCases<(u8, u8, u8)>, + skin_colors_dark: quadruped_medium::skin::PureCases<(u8, u8, u8)>, +} + +impl MiscColorSpec { + fn color_segment(&self, mat_segment: MatSegment, skin: QMSkins) -> Segment { + // TODO move some of the colors to common + mat_segment.to_segment(|mat| { + match mat { + Material::Skin => *skin.elim_case_pure(&self.skin_colors_plain), + Material::SkinDark => *skin.elim_case_pure(&self.skin_colors_dark), + Material::SkinLight => *skin.elim_case_pure(&self.skin_colors_light), + _ => *skin.elim_case_pure(&self.skin_colors_plain), + } + .into() + }) + } +} + // All reliant on humanoid::Species and humanoid::BodyType #[derive(Deserialize)] struct HumHeadSubSpec { @@ -1262,68 +1287,100 @@ make_vox_spec!( struct QuadrupedMediumSpec { central: QuadrupedMediumCentralSpec = "voxygen.voxel.quadruped_medium_central_manifest", lateral: QuadrupedMediumLateralSpec = "voxygen.voxel.quadruped_medium_lateral_manifest", + color: MiscColorSpec = "voxygen.voxel.quadruped_medium_color_manifest", }, |FigureKey { body, .. }, spec| { + let color = &spec.color.read().0; [ Some(spec.central.read().0.mesh_head( + body, body.species, body.body_type, + color, )), Some(spec.central.read().0.mesh_neck( + body, body.species, body.body_type, + color, )), Some(spec.central.read().0.mesh_jaw( + body, body.species, body.body_type, + color, )), Some(spec.central.read().0.mesh_tail( + body, body.species, body.body_type, + color, )), Some(spec.central.read().0.mesh_torso_front( + body, body.species, body.body_type, + color, )), Some(spec.central.read().0.mesh_torso_back( + body, body.species, body.body_type, + color, )), Some(spec.central.read().0.mesh_ears( + body, body.species, body.body_type, + color, )), Some(spec.lateral.read().0.mesh_leg_fl( + body, body.species, body.body_type, + color, )), Some(spec.lateral.read().0.mesh_leg_fr( + body, body.species, body.body_type, + color, )), Some(spec.lateral.read().0.mesh_leg_bl( + body, body.species, body.body_type, + color, )), Some(spec.lateral.read().0.mesh_leg_br( + body, body.species, body.body_type, + color, )), Some(spec.lateral.read().0.mesh_foot_fl( + body, body.species, body.body_type, + color, )), Some(spec.lateral.read().0.mesh_foot_fr( + body, body.species, body.body_type, + color, )), Some(spec.lateral.read().0.mesh_foot_bl( + body, body.species, body.body_type, + color, )), Some(spec.lateral.read().0.mesh_foot_br( + body, body.species, body.body_type, + color, )), None, ] @@ -1331,7 +1388,13 @@ make_vox_spec!( ); impl QuadrupedMediumCentralSpec { - fn mesh_head(&self, species: QMSpecies, body_type: QMBodyType) -> BoneMeshes { + fn mesh_head( + &self, + body: &QMBody, + species: QMSpecies, + body_type: QMBodyType, + color_spec: &MiscColorSpec, + ) -> BoneMeshes { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1342,12 +1405,20 @@ impl QuadrupedMediumCentralSpec { return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); }, }; - let central = graceful_load_segment(&spec.head.central.0); - + let central = color_spec.color_segment( + graceful_load_mat_segment(&spec.head.central.0), + species.skin_color(body.skin), + ); (central, Vec3::from(spec.head.offset)) } - fn mesh_neck(&self, species: QMSpecies, body_type: QMBodyType) -> BoneMeshes { + fn mesh_neck( + &self, + body: &QMBody, + species: QMSpecies, + body_type: QMBodyType, + color_spec: &MiscColorSpec, + ) -> BoneMeshes { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1358,12 +1429,21 @@ impl QuadrupedMediumCentralSpec { return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); }, }; - let central = graceful_load_segment(&spec.neck.central.0); + let central = color_spec.color_segment( + graceful_load_mat_segment(&spec.neck.central.0), + species.skin_color(body.skin), + ); (central, Vec3::from(spec.neck.offset)) } - fn mesh_jaw(&self, species: QMSpecies, body_type: QMBodyType) -> BoneMeshes { + fn mesh_jaw( + &self, + body: &QMBody, + species: QMSpecies, + body_type: QMBodyType, + color_spec: &MiscColorSpec, + ) -> BoneMeshes { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1374,12 +1454,21 @@ impl QuadrupedMediumCentralSpec { return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); }, }; - let central = graceful_load_segment(&spec.jaw.central.0); + let central = color_spec.color_segment( + graceful_load_mat_segment(&spec.jaw.central.0), + species.skin_color(body.skin), + ); (central, Vec3::from(spec.jaw.offset)) } - fn mesh_ears(&self, species: QMSpecies, body_type: QMBodyType) -> BoneMeshes { + fn mesh_ears( + &self, + body: &QMBody, + species: QMSpecies, + body_type: QMBodyType, + color_spec: &MiscColorSpec, + ) -> BoneMeshes { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1390,12 +1479,21 @@ impl QuadrupedMediumCentralSpec { return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); }, }; - let central = graceful_load_segment(&spec.ears.central.0); + let central = color_spec.color_segment( + graceful_load_mat_segment(&spec.ears.central.0), + species.skin_color(body.skin), + ); (central, Vec3::from(spec.ears.offset)) } - fn mesh_torso_front(&self, species: QMSpecies, body_type: QMBodyType) -> BoneMeshes { + fn mesh_torso_front( + &self, + body: &QMBody, + species: QMSpecies, + body_type: QMBodyType, + color_spec: &MiscColorSpec, + ) -> BoneMeshes { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1406,12 +1504,21 @@ impl QuadrupedMediumCentralSpec { return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); }, }; - let central = graceful_load_segment(&spec.torso_front.central.0); + let central = color_spec.color_segment( + graceful_load_mat_segment(&spec.torso_front.central.0), + species.skin_color(body.skin), + ); (central, Vec3::from(spec.torso_front.offset)) } - fn mesh_torso_back(&self, species: QMSpecies, body_type: QMBodyType) -> BoneMeshes { + fn mesh_torso_back( + &self, + body: &QMBody, + species: QMSpecies, + body_type: QMBodyType, + color_spec: &MiscColorSpec, + ) -> BoneMeshes { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1422,12 +1529,21 @@ impl QuadrupedMediumCentralSpec { return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); }, }; - let central = graceful_load_segment(&spec.torso_back.central.0); + let central = color_spec.color_segment( + graceful_load_mat_segment(&spec.torso_back.central.0), + species.skin_color(body.skin), + ); (central, Vec3::from(spec.torso_back.offset)) } - fn mesh_tail(&self, species: QMSpecies, body_type: QMBodyType) -> BoneMeshes { + fn mesh_tail( + &self, + body: &QMBody, + species: QMSpecies, + body_type: QMBodyType, + color_spec: &MiscColorSpec, + ) -> BoneMeshes { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1438,14 +1554,23 @@ impl QuadrupedMediumCentralSpec { return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); }, }; - let central = graceful_load_segment(&spec.tail.central.0); + let central = color_spec.color_segment( + graceful_load_mat_segment(&spec.tail.central.0), + species.skin_color(body.skin), + ); (central, Vec3::from(spec.tail.offset)) } } impl QuadrupedMediumLateralSpec { - fn mesh_leg_fl(&self, species: QMSpecies, body_type: QMBodyType) -> BoneMeshes { + fn mesh_leg_fl( + &self, + body: &QMBody, + species: QMSpecies, + body_type: QMBodyType, + color_spec: &MiscColorSpec, + ) -> BoneMeshes { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1456,12 +1581,21 @@ impl QuadrupedMediumLateralSpec { return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); }, }; - let lateral = graceful_load_segment(&spec.leg_fl.lateral.0); + let lateral = color_spec.color_segment( + graceful_load_mat_segment(&spec.leg_fl.lateral.0), + species.skin_color(body.skin), + ); (lateral, Vec3::from(spec.leg_fl.offset)) } - fn mesh_leg_fr(&self, species: QMSpecies, body_type: QMBodyType) -> BoneMeshes { + fn mesh_leg_fr( + &self, + body: &QMBody, + species: QMSpecies, + body_type: QMBodyType, + color_spec: &MiscColorSpec, + ) -> BoneMeshes { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1472,12 +1606,21 @@ impl QuadrupedMediumLateralSpec { return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); }, }; - let lateral = graceful_load_segment(&spec.leg_fr.lateral.0); + let lateral = color_spec.color_segment( + graceful_load_mat_segment(&spec.leg_fr.lateral.0), + species.skin_color(body.skin), + ); (lateral, Vec3::from(spec.leg_fr.offset)) } - fn mesh_leg_bl(&self, species: QMSpecies, body_type: QMBodyType) -> BoneMeshes { + fn mesh_leg_bl( + &self, + body: &QMBody, + species: QMSpecies, + body_type: QMBodyType, + color_spec: &MiscColorSpec, + ) -> BoneMeshes { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1488,12 +1631,21 @@ impl QuadrupedMediumLateralSpec { return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); }, }; - let lateral = graceful_load_segment(&spec.leg_bl.lateral.0); + let lateral = color_spec.color_segment( + graceful_load_mat_segment(&spec.leg_bl.lateral.0), + species.skin_color(body.skin), + ); (lateral, Vec3::from(spec.leg_bl.offset)) } - fn mesh_leg_br(&self, species: QMSpecies, body_type: QMBodyType) -> BoneMeshes { + fn mesh_leg_br( + &self, + body: &QMBody, + species: QMSpecies, + body_type: QMBodyType, + color_spec: &MiscColorSpec, + ) -> BoneMeshes { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1504,12 +1656,21 @@ impl QuadrupedMediumLateralSpec { return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); }, }; - let lateral = graceful_load_segment(&spec.leg_br.lateral.0); + let lateral = color_spec.color_segment( + graceful_load_mat_segment(&spec.leg_br.lateral.0), + species.skin_color(body.skin), + ); (lateral, Vec3::from(spec.leg_br.offset)) } - fn mesh_foot_fl(&self, species: QMSpecies, body_type: QMBodyType) -> BoneMeshes { + fn mesh_foot_fl( + &self, + body: &QMBody, + species: QMSpecies, + body_type: QMBodyType, + color_spec: &MiscColorSpec, + ) -> BoneMeshes { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1520,12 +1681,21 @@ impl QuadrupedMediumLateralSpec { return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); }, }; - let lateral = graceful_load_segment(&spec.foot_fl.lateral.0); + let lateral = color_spec.color_segment( + graceful_load_mat_segment(&spec.foot_fl.lateral.0), + species.skin_color(body.skin), + ); (lateral, Vec3::from(spec.foot_fl.offset)) } - fn mesh_foot_fr(&self, species: QMSpecies, body_type: QMBodyType) -> BoneMeshes { + fn mesh_foot_fr( + &self, + body: &QMBody, + species: QMSpecies, + body_type: QMBodyType, + color_spec: &MiscColorSpec, + ) -> BoneMeshes { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1536,12 +1706,21 @@ impl QuadrupedMediumLateralSpec { return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); }, }; - let lateral = graceful_load_segment(&spec.foot_fr.lateral.0); + let lateral = color_spec.color_segment( + graceful_load_mat_segment(&spec.foot_fr.lateral.0), + species.skin_color(body.skin), + ); (lateral, Vec3::from(spec.foot_fr.offset)) } - fn mesh_foot_bl(&self, species: QMSpecies, body_type: QMBodyType) -> BoneMeshes { + fn mesh_foot_bl( + &self, + body: &QMBody, + species: QMSpecies, + body_type: QMBodyType, + color_spec: &MiscColorSpec, + ) -> BoneMeshes { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1552,12 +1731,21 @@ impl QuadrupedMediumLateralSpec { return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); }, }; - let lateral = graceful_load_segment(&spec.foot_bl.lateral.0); + let lateral = color_spec.color_segment( + graceful_load_mat_segment(&spec.foot_bl.lateral.0), + species.skin_color(body.skin), + ); (lateral, Vec3::from(spec.foot_bl.offset)) } - fn mesh_foot_br(&self, species: QMSpecies, body_type: QMBodyType) -> BoneMeshes { + fn mesh_foot_br( + &self, + body: &QMBody, + species: QMSpecies, + body_type: QMBodyType, + color_spec: &MiscColorSpec, + ) -> BoneMeshes { let spec = match self.0.get(&(species, body_type)) { Some(spec) => spec, None => { @@ -1568,7 +1756,10 @@ impl QuadrupedMediumLateralSpec { return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); }, }; - let lateral = graceful_load_segment(&spec.foot_br.lateral.0); + let lateral = color_spec.color_segment( + graceful_load_mat_segment(&spec.foot_br.lateral.0), + species.skin_color(body.skin), + ); (lateral, Vec3::from(spec.foot_br.offset)) } diff --git a/world/src/layer/wildlife.rs b/world/src/layer/wildlife.rs index 49b7c1644e..fc20539b60 100644 --- a/world/src/layer/wildlife.rs +++ b/world/src/layer/wildlife.rs @@ -53,6 +53,7 @@ pub fn apply_wildlife_supplement<'a, R: Rng>( _ => quadruped_medium::Body { species: quadruped_medium::Species::Roshwalr, body_type: quadruped_medium::BodyType::Male, + skin: 0, } .into(), }) @@ -726,6 +727,7 @@ pub fn apply_wildlife_supplement<'a, R: Rng>( quadruped_medium::Body { species: quadruped_medium::Species::Roshwalr, body_type: quadruped_medium::BodyType::Female, + skin: 0, } .into(), )