support for hollow voxels ty zesterer

This commit is contained in:
jshipsey
2021-09-24 00:28:17 -04:00
parent 5cc54b34bd
commit 3915aa7aac
3 changed files with 35 additions and 14 deletions

View File

@ -5,24 +5,28 @@ use vek::*;
const GLOWY: u8 = 1 << 1; const GLOWY: u8 = 1 << 1;
const SHINY: u8 = 1 << 2; const SHINY: u8 = 1 << 2;
const HOLLOW: u8 = 1 << 3;
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct CellData { pub struct CellData {
pub col: Rgb<u8>, pub col: Rgb<u8>,
pub attr: NonZeroU8, // 1 = glowy, 2 = shiny pub attr: NonZeroU8, // 1 = glowy, 2 = shiny, 3 = hollow
} }
impl CellData { impl CellData {
pub(super) fn new(col: Rgb<u8>, glowy: bool, shiny: bool) -> Self { pub(super) fn new(col: Rgb<u8>, glowy: bool, shiny: bool, hollow: bool) -> Self {
CellData { CellData {
col, col,
attr: NonZeroU8::new(1 + glowy as u8 * GLOWY + shiny as u8 * SHINY).unwrap(), attr: NonZeroU8::new(
1 + glowy as u8 * GLOWY + shiny as u8 * SHINY + hollow as u8 * HOLLOW,
)
.unwrap(),
} }
} }
} }
impl Default for CellData { impl Default for CellData {
fn default() -> Self { Self::new(Rgb::broadcast(255), false, false) } fn default() -> Self { Self::new(Rgb::broadcast(255), false, false, false) }
} }
/// A type representing a single voxel in a figure. /// A type representing a single voxel in a figure.
@ -33,8 +37,8 @@ pub enum Cell {
} }
impl Cell { impl Cell {
pub fn new(col: Rgb<u8>, glowy: bool, shiny: bool) -> Self { pub fn new(col: Rgb<u8>, glowy: bool, shiny: bool, hollow: bool) -> Self {
Cell::Filled(CellData::new(col, glowy, shiny)) Cell::Filled(CellData::new(col, glowy, shiny, hollow))
} }
pub fn get_color(&self) -> Option<Rgb<u8>> { pub fn get_color(&self) -> Option<Rgb<u8>> {
@ -57,6 +61,13 @@ impl Cell {
Cell::Empty => false, Cell::Empty => false,
} }
} }
pub fn is_hollow(&self) -> bool {
match self {
Cell::Filled(data) => data.attr.get() & HOLLOW != 0,
Cell::Empty => false,
}
}
} }
impl Vox for Cell { impl Vox for Cell {

View File

@ -67,6 +67,7 @@ impl Segment {
color, color,
(13..16).contains(&voxel.i), // Glowy (13..16).contains(&voxel.i), // Glowy
(8..13).contains(&voxel.i), // Shiny (8..13).contains(&voxel.i), // Shiny
voxel.i == 16, // Hollow
), ),
) )
.unwrap(); .unwrap();
@ -93,8 +94,14 @@ impl Segment {
/// Transform cell colors /// Transform cell colors
pub fn map_rgb(self, transform: impl Fn(Rgb<u8>) -> Rgb<u8>) -> Self { pub fn map_rgb(self, transform: impl Fn(Rgb<u8>) -> Rgb<u8>) -> Self {
self.map(|cell| { self.map(|cell| {
cell.get_color() cell.get_color().map(|rgb| {
.map(|rgb| Cell::new(transform(rgb), cell.is_glowy(), cell.is_shiny())) Cell::new(
transform(rgb),
cell.is_glowy(),
cell.is_shiny(),
cell.is_hollow(),
)
})
}) })
} }
} }
@ -119,7 +126,9 @@ impl<V: Vox + Copy> DynaUnionizer<V> {
} }
} }
pub fn unify(self) -> (Dyna<V, ()>, Vec3<i32>) { pub fn unify(self) -> (Dyna<V, ()>, Vec3<i32>) { self.unify_with(|v| v) }
pub fn unify_with(self, mut f: impl FnMut(V) -> V) -> (Dyna<V, ()>, Vec3<i32>) {
if self.0.is_empty() { if self.0.is_empty() {
return (Dyna::filled(Vec3::zero(), V::empty(), ()), Vec3::zero()); return (Dyna::filled(Vec3::zero(), V::empty(), ()), Vec3::zero());
} }
@ -140,7 +149,7 @@ impl<V: Vox + Copy> DynaUnionizer<V> {
for (dyna, offset) in self.0 { for (dyna, offset) in self.0 {
for (pos, vox) in dyna.full_vol_iter() { for (pos, vox) in dyna.full_vol_iter() {
if !vox.is_empty() { if !vox.is_empty() {
combined.set(origin + offset + pos, *vox).unwrap(); combined.set(origin + offset + pos, f(*vox)).unwrap();
} }
} }
} }
@ -157,7 +166,7 @@ impl MatSegment {
for (pos, vox) in self.full_vol_iter() { for (pos, vox) in self.full_vol_iter() {
let data = match vox { let data = match vox {
MatCell::None => continue, MatCell::None => continue,
MatCell::Mat(mat) => CellData::new(map(*mat), false, false), MatCell::Mat(mat) => CellData::new(map(*mat), false, false, false),
MatCell::Normal(data) => *data, MatCell::Normal(data) => *data,
}; };
vol.set(pos, Cell::Filled(data)).unwrap(); vol.set(pos, Cell::Filled(data)).unwrap();
@ -221,6 +230,7 @@ impl MatSegment {
color, color,
(13..16).contains(&index), (13..16).contains(&index),
(8..13).contains(&index), (8..13).contains(&index),
index == 16, // Hollow
)) ))
}, },
}; };

View File

@ -22,7 +22,8 @@ use common::{
}, },
theropod::{self, BodyType as TBodyType, Species as TSpecies}, theropod::{self, BodyType as TBodyType, Species as TSpecies},
}, },
figure::{DynaUnionizer, MatSegment, Material, Segment}, figure::{Cell, DynaUnionizer, MatSegment, Material, Segment},
vol::Vox,
}; };
use hashbrown::HashMap; use hashbrown::HashMap;
use serde::Deserialize; use serde::Deserialize;
@ -317,8 +318,7 @@ impl HumHeadSpec {
.maybe_add(beard) .maybe_add(beard)
.maybe_add(accessory) .maybe_add(accessory)
.maybe_add(helmet) .maybe_add(helmet)
.unify(); .unify_with(|v| if v.is_hollow() { Cell::empty() } else { v });
( (
head, head,
Vec3::from(spec.offset) + origin_offset.map(|e| e as f32 * -1.0), Vec3::from(spec.offset) + origin_offset.map(|e| e as f32 * -1.0),