#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct DisplacementMapExport {
pub width: u32,
pub height: u32,
pub data: Vec<f32>,
pub scale: f32,
}
#[allow(dead_code)]
impl DisplacementMapExport {
pub fn flat(width: u32, height: u32) -> Self {
Self {
width,
height,
data: vec![0.0; (width * height) as usize],
scale: 1.0,
}
}
pub fn from_data(width: u32, height: u32, data: Vec<f32>, scale: f32) -> Self {
Self {
width,
height,
data,
scale,
}
}
pub fn pixel_count(&self) -> usize {
(self.width * self.height) as usize
}
pub fn get(&self, x: u32, y: u32) -> f32 {
self.data[(y * self.width + x) as usize] * self.scale
}
pub fn set(&mut self, x: u32, y: u32, value: f32) {
self.data[(y * self.width + x) as usize] = value;
}
pub fn range(&self) -> (f32, f32) {
let min = self.data.iter().cloned().fold(f32::MAX, f32::min);
let max = self.data.iter().cloned().fold(f32::MIN, f32::max);
(min * self.scale, max * self.scale)
}
pub fn to_u16_bytes(&self) -> Vec<u8> {
let (min, max) = self.range();
let range = (max - min).max(1e-10);
let mut bytes = Vec::new();
bytes.extend_from_slice(&self.width.to_le_bytes());
bytes.extend_from_slice(&self.height.to_le_bytes());
for &v in &self.data {
let norm = ((v * self.scale - min) / range * 65535.0) as u16;
bytes.extend_from_slice(&norm.to_le_bytes());
}
bytes
}
pub fn u16_byte_size(&self) -> usize {
8 + self.pixel_count() * 2
}
}
#[allow(dead_code)]
pub fn displacement_map_to_json(map: &DisplacementMapExport) -> String {
let (min, max) = map.range();
format!(
"{{\"width\":{},\"height\":{},\"scale\":{},\"min\":{},\"max\":{}}}",
map.width, map.height, map.scale, min, max
)
}
#[allow(dead_code)]
pub fn validate_displacement_map(map: &DisplacementMapExport) -> bool {
map.data.len() == map.pixel_count() && map.data.iter().all(|v| v.is_finite())
}
pub struct DisplacementMap {
pub width: u32,
pub height: u32,
pub data: Vec<f32>,
pub midlevel: f32,
pub strength: f32,
}
pub fn new_displacement_map(w: u32, h: u32) -> DisplacementMap {
DisplacementMap {
width: w,
height: h,
data: vec![0.0; (w * h) as usize],
midlevel: 0.5,
strength: 1.0,
}
}
pub fn disp_set(m: &mut DisplacementMap, x: u32, y: u32, v: f32) {
if x < m.width && y < m.height {
m.data[(y * m.width + x) as usize] = v;
}
}
pub fn disp_get(m: &DisplacementMap, x: u32, y: u32) -> f32 {
if x < m.width && y < m.height {
m.data[(y * m.width + x) as usize]
} else {
0.0
}
}
pub fn disp_to_u16(m: &DisplacementMap) -> Vec<u16> {
m.data
.iter()
.map(|&v| {
let norm = ((v - m.midlevel) * m.strength * 0.5 + 0.5).clamp(0.0, 1.0);
(norm * 65535.0) as u16
})
.collect()
}
pub fn disp_max_height(m: &DisplacementMap) -> f32 {
m.data.iter().cloned().fold(f32::NEG_INFINITY, f32::max)
}
pub fn disp_to_bytes(m: &DisplacementMap) -> Vec<u8> {
let mut b = Vec::new();
b.extend_from_slice(&m.width.to_le_bytes());
b.extend_from_slice(&m.height.to_le_bytes());
for &v in &m.data {
b.extend_from_slice(&v.to_le_bytes());
}
b
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_flat() {
let m = DisplacementMapExport::flat(4, 4);
assert_eq!(m.pixel_count(), 16);
}
#[test]
fn test_get_set() {
let mut m = DisplacementMapExport::flat(2, 2);
m.set(0, 0, 0.5);
assert!((m.get(0, 0) - 0.5).abs() < 1e-5);
}
#[test]
fn test_range() {
let m = DisplacementMapExport::from_data(2, 1, vec![0.0, 1.0], 2.0);
let (min, max) = m.range();
assert!((min).abs() < 1e-5);
assert!((max - 2.0).abs() < 1e-5);
}
#[test]
fn test_to_u16_bytes() {
let m = DisplacementMapExport::flat(2, 2);
let bytes = m.to_u16_bytes();
assert_eq!(bytes.len(), m.u16_byte_size());
}
#[test]
fn test_validate() {
let m = DisplacementMapExport::flat(2, 2);
assert!(validate_displacement_map(&m));
}
#[test]
fn test_to_json() {
let m = DisplacementMapExport::flat(2, 2);
let json = displacement_map_to_json(&m);
assert!(json.contains("width"));
}
#[test]
fn test_custom_scale() {
let m = DisplacementMapExport::from_data(1, 1, vec![1.0], 3.0);
assert!((m.get(0, 0) - 3.0).abs() < 1e-5);
}
#[test]
fn test_invalid() {
let m = DisplacementMapExport {
width: 2,
height: 2,
data: vec![0.0],
scale: 1.0,
};
assert!(!validate_displacement_map(&m));
}
#[test]
fn test_pixel_count() {
let m = DisplacementMapExport::flat(3, 5);
assert_eq!(m.pixel_count(), 15);
}
#[test]
fn test_u16_byte_size() {
let m = DisplacementMapExport::flat(4, 4);
assert_eq!(m.u16_byte_size(), 8 + 32);
}
}