use binrw::{BinRead, BinWrite};
use super::instance::LiquidVertexFormat;
#[derive(Debug, Clone, Copy, Default, BinRead, BinWrite)]
#[brw(little)]
pub struct UvMapEntry {
pub u: u16,
pub v: u16,
}
impl UvMapEntry {
pub fn to_normalized(self) -> (f32, f32) {
(f32::from(self.u) / 255.0, f32::from(self.v) / 255.0)
}
pub fn from_normalized(u: f32, v: f32) -> Self {
Self {
u: (u * 255.0) as u16,
v: (v * 255.0) as u16,
}
}
}
#[derive(Debug, Clone, Copy, Default, BinRead, BinWrite)]
#[brw(little)]
pub struct HeightDepthVertex {
pub height: f32,
pub depth: u8,
}
impl HeightDepthVertex {
pub const SIZE: usize = 5;
pub fn absolute_height(self, min_height: f32) -> f32 {
min_height + self.height
}
pub fn normalized_depth(self) -> f32 {
f32::from(self.depth) / 255.0
}
}
#[derive(Debug, Clone, Copy, Default, BinRead, BinWrite)]
#[brw(little)]
pub struct HeightUvVertex {
pub height: f32,
pub uv: UvMapEntry,
}
impl HeightUvVertex {
pub const SIZE: usize = 8;
pub fn absolute_height(self, min_height: f32) -> f32 {
min_height + self.height
}
pub fn normalized_uv(self) -> (f32, f32) {
self.uv.to_normalized()
}
}
#[derive(Debug, Clone, Copy, Default, BinRead, BinWrite)]
#[brw(little)]
pub struct DepthOnlyVertex {
pub depth: u8,
}
impl DepthOnlyVertex {
pub const SIZE: usize = 1;
pub fn normalized_depth(self) -> f32 {
f32::from(self.depth) / 255.0
}
}
#[derive(Debug, Clone, Copy, Default, BinRead, BinWrite)]
#[brw(little)]
pub struct HeightUvDepthVertex {
pub height: f32,
pub uv: UvMapEntry,
pub depth: u8,
}
impl HeightUvDepthVertex {
pub const SIZE: usize = 9;
pub fn absolute_height(self, min_height: f32) -> f32 {
min_height + self.height
}
pub fn normalized_uv(self) -> (f32, f32) {
self.uv.to_normalized()
}
pub fn normalized_depth(self) -> f32 {
f32::from(self.depth) / 255.0
}
}
#[derive(Debug, Clone)]
pub enum VertexDataArray {
HeightDepth(Box<[Option<HeightDepthVertex>; 81]>),
HeightUv(Box<[Option<HeightUvVertex>; 81]>),
DepthOnly(Box<[Option<DepthOnlyVertex>; 81]>),
HeightUvDepth(Box<[Option<HeightUvDepthVertex>; 81]>),
}
impl VertexDataArray {
pub fn len(&self) -> usize {
match self {
Self::HeightDepth(v) => v.as_ref().iter().filter(|v| v.is_some()).count(),
Self::HeightUv(v) => v.as_ref().iter().filter(|v| v.is_some()).count(),
Self::DepthOnly(v) => v.as_ref().iter().filter(|v| v.is_some()).count(),
Self::HeightUvDepth(v) => v.as_ref().iter().filter(|v| v.is_some()).count(),
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn format(&self) -> LiquidVertexFormat {
match self {
Self::HeightDepth(_) => LiquidVertexFormat::HeightDepth,
Self::HeightUv(_) => LiquidVertexFormat::HeightUv,
Self::DepthOnly(_) => LiquidVertexFormat::DepthOnly,
Self::HeightUvDepth(_) => LiquidVertexFormat::HeightUvDepth,
}
}
pub fn byte_size(&self) -> usize {
self.len() * self.format().bytes_per_vertex()
}
pub fn get(&self, x: usize, z: usize) -> Option<&dyn std::any::Any> {
if x > 8 || z > 8 {
return None;
}
let idx = z * 9 + x;
match self {
Self::HeightDepth(v) => v[idx].as_ref().map(|v| v as &dyn std::any::Any),
Self::HeightUv(v) => v[idx].as_ref().map(|v| v as &dyn std::any::Any),
Self::DepthOnly(v) => v[idx].as_ref().map(|v| v as &dyn std::any::Any),
Self::HeightUvDepth(v) => v[idx].as_ref().map(|v| v as &dyn std::any::Any),
}
}
pub fn validate_coverage(&self, x_offset: u8, y_offset: u8, width: u8, height: u8) -> bool {
for z in y_offset..=y_offset + height {
for x in x_offset..=x_offset + width {
if self.get(x as usize, z as usize).is_none() {
return false;
}
}
}
true
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Cursor;
#[test]
fn test_uv_map_entry_size() {
assert_eq!(std::mem::size_of::<UvMapEntry>(), 4);
}
#[test]
fn test_uv_map_entry_normalization() {
let uv = UvMapEntry { u: 255, v: 128 };
let (u, v) = uv.to_normalized();
assert!((u - 1.0).abs() < 0.001); assert!((v - 0.502).abs() < 0.01); }
#[test]
fn test_uv_map_entry_from_normalized() {
let uv = UvMapEntry::from_normalized(1.0, 0.5);
assert_eq!(uv.u, 255); assert_eq!(uv.v, 127); }
#[test]
fn test_uv_map_entry_round_trip() {
let original = UvMapEntry { u: 200, v: 100 };
let (u, v) = original.to_normalized();
let reconstructed = UvMapEntry::from_normalized(u, v);
assert_eq!(original.u, reconstructed.u);
assert_eq!(original.v, reconstructed.v);
}
#[test]
fn test_uv_map_entry_parse() {
let data = [0x00u8, 0x01, 0x80, 0x00]; let mut cursor = Cursor::new(&data);
let uv = UvMapEntry::read_le(&mut cursor).unwrap();
assert_eq!(uv.u, 256);
assert_eq!(uv.v, 128);
}
#[test]
fn test_height_depth_vertex_size() {
assert_eq!(HeightDepthVertex::SIZE, 5);
assert!(std::mem::size_of::<HeightDepthVertex>() >= 5);
}
#[test]
fn test_height_depth_vertex_parse() {
let data = [
0x00, 0x00, 0x80, 0x3F, 0x80, ];
let mut cursor = Cursor::new(&data);
let vertex = HeightDepthVertex::read_le(&mut cursor).unwrap();
assert_eq!(vertex.height, 1.0);
assert_eq!(vertex.depth, 128);
}
#[test]
fn test_height_depth_vertex_absolute_height() {
let vertex = HeightDepthVertex {
height: 5.0,
depth: 255,
};
let absolute = vertex.absolute_height(100.0);
assert_eq!(absolute, 105.0);
}
#[test]
fn test_height_depth_vertex_normalized_depth() {
let vertex = HeightDepthVertex {
height: 0.0,
depth: 128,
};
let normalized = vertex.normalized_depth();
assert!((normalized - 0.502).abs() < 0.01); }
#[test]
fn test_height_depth_vertex_round_trip() {
let original = HeightDepthVertex {
height: 2.5,
depth: 200,
};
let mut buffer = Cursor::new(Vec::new());
original.write_le(&mut buffer).unwrap();
let data = buffer.into_inner();
let mut cursor = Cursor::new(data);
let parsed = HeightDepthVertex::read_le(&mut cursor).unwrap();
assert_eq!(original.height, parsed.height);
assert_eq!(original.depth, parsed.depth);
}
#[test]
fn test_height_uv_vertex_size() {
assert_eq!(std::mem::size_of::<HeightUvVertex>(), 8);
assert_eq!(HeightUvVertex::SIZE, 8);
}
#[test]
fn test_height_uv_vertex_parse() {
let data = [
0x00, 0x00, 0x40, 0x40, 0x00, 0x01, 0x80, 0x00, ];
let mut cursor = Cursor::new(&data);
let vertex = HeightUvVertex::read_le(&mut cursor).unwrap();
assert_eq!(vertex.height, 3.0);
assert_eq!(vertex.uv.u, 256);
assert_eq!(vertex.uv.v, 128);
}
#[test]
fn test_height_uv_vertex_absolute_height() {
let vertex = HeightUvVertex {
height: 10.0,
uv: UvMapEntry { u: 0, v: 0 },
};
let absolute = vertex.absolute_height(50.0);
assert_eq!(absolute, 60.0);
}
#[test]
fn test_height_uv_vertex_normalized_uv() {
let vertex = HeightUvVertex {
height: 0.0,
uv: UvMapEntry { u: 255, v: 128 },
};
let (u, v) = vertex.normalized_uv();
assert!((u - 1.0).abs() < 0.001); assert!((v - 0.502).abs() < 0.01); }
#[test]
fn test_height_uv_vertex_round_trip() {
let original = HeightUvVertex {
height: 7.5,
uv: UvMapEntry { u: 200, v: 150 },
};
let mut buffer = Cursor::new(Vec::new());
original.write_le(&mut buffer).unwrap();
let data = buffer.into_inner();
let mut cursor = Cursor::new(data);
let parsed = HeightUvVertex::read_le(&mut cursor).unwrap();
assert_eq!(original.height, parsed.height);
assert_eq!(original.uv.u, parsed.uv.u);
assert_eq!(original.uv.v, parsed.uv.v);
}
#[test]
fn test_depth_only_vertex_size() {
assert_eq!(std::mem::size_of::<DepthOnlyVertex>(), 1);
assert_eq!(DepthOnlyVertex::SIZE, 1);
}
#[test]
fn test_depth_only_vertex_parse() {
let data = [0xFFu8]; let mut cursor = Cursor::new(&data);
let vertex = DepthOnlyVertex::read_le(&mut cursor).unwrap();
assert_eq!(vertex.depth, 255);
}
#[test]
fn test_depth_only_vertex_normalized_depth() {
let vertex = DepthOnlyVertex { depth: 127 };
let normalized = vertex.normalized_depth();
assert!((normalized - 0.498).abs() < 0.01); }
#[test]
fn test_depth_only_vertex_round_trip() {
let original = DepthOnlyVertex { depth: 100 };
let mut buffer = Cursor::new(Vec::new());
original.write_le(&mut buffer).unwrap();
let data = buffer.into_inner();
let mut cursor = Cursor::new(data);
let parsed = DepthOnlyVertex::read_le(&mut cursor).unwrap();
assert_eq!(original.depth, parsed.depth);
}
#[test]
fn test_height_uv_depth_vertex_size() {
assert_eq!(HeightUvDepthVertex::SIZE, 9);
assert!(std::mem::size_of::<HeightUvDepthVertex>() >= 9);
}
#[test]
fn test_height_uv_depth_vertex_parse() {
let data = [
0x00, 0x00, 0x00, 0x40, 0x00, 0x01, 0x80, 0x00, 0x64, ];
let mut cursor = Cursor::new(&data);
let vertex = HeightUvDepthVertex::read_le(&mut cursor).unwrap();
assert_eq!(vertex.height, 2.0);
assert_eq!(vertex.uv.u, 256);
assert_eq!(vertex.uv.v, 128);
assert_eq!(vertex.depth, 100);
}
#[test]
fn test_height_uv_depth_vertex_absolute_height() {
let vertex = HeightUvDepthVertex {
height: 15.0,
uv: UvMapEntry { u: 0, v: 0 },
depth: 0,
};
let absolute = vertex.absolute_height(85.0);
assert_eq!(absolute, 100.0);
}
#[test]
fn test_height_uv_depth_vertex_normalized_uv() {
let vertex = HeightUvDepthVertex {
height: 0.0,
uv: UvMapEntry { u: 255, v: 128 },
depth: 0,
};
let (u, v) = vertex.normalized_uv();
assert!((u - 1.0).abs() < 0.001); assert!((v - 0.502).abs() < 0.01); }
#[test]
fn test_height_uv_depth_vertex_normalized_depth() {
let vertex = HeightUvDepthVertex {
height: 0.0,
uv: UvMapEntry { u: 0, v: 0 },
depth: 255,
};
let normalized = vertex.normalized_depth();
assert_eq!(normalized, 1.0);
}
#[test]
fn test_height_uv_depth_vertex_round_trip() {
let original = HeightUvDepthVertex {
height: 12.5,
uv: UvMapEntry { u: 200, v: 150 },
depth: 180,
};
let mut buffer = Cursor::new(Vec::new());
original.write_le(&mut buffer).unwrap();
let data = buffer.into_inner();
let mut cursor = Cursor::new(data);
let parsed = HeightUvDepthVertex::read_le(&mut cursor).unwrap();
assert_eq!(original.height, parsed.height);
assert_eq!(original.uv.u, parsed.uv.u);
assert_eq!(original.uv.v, parsed.uv.v);
assert_eq!(original.depth, parsed.depth);
}
#[test]
fn test_all_vertex_formats_have_correct_sizes() {
assert_eq!(HeightDepthVertex::SIZE, 5);
assert_eq!(HeightUvVertex::SIZE, 8);
assert_eq!(DepthOnlyVertex::SIZE, 1);
assert_eq!(HeightUvDepthVertex::SIZE, 9);
}
}