use bitreader::{BitReader, BitReaderError};
use metaverse_messages::udp::environment::layer_data::{LayerData, LayerType};
use crate::{
cloud::Cloud,
constants::{build_copy_matrix16, build_dequantize_table16, idct_column16, idct_line16},
error::PatchError,
land::Land,
water::Water,
wind::Wind,
};
use glam::{u16, u32, usize, U16Vec2};
static COPY_MATRIX_16: [usize; 256] = build_copy_matrix16();
static DEQUANTIZE_TABLE_16: [f32; 256] = build_dequantize_table16();
pub const END_OF_PATCHES: u8 = 97;
pub enum PatchLayer {
Land(Vec<Land>),
Wind(Vec<Wind>),
Water(Vec<Water>),
Cloud(Vec<Cloud>),
}
pub fn parse_layer_data(data: &LayerData) -> Result<PatchLayer, PatchError> {
match data.layer_type {
LayerType::Land | LayerType::LandExtended => {
let extended = matches!(data.layer_type, LayerType::LandExtended);
let result = Land::from_packet(data, extended)?;
Ok(PatchLayer::Land(result))
}
LayerType::Wind | LayerType::WindExtended => {
let extended = matches!(data.layer_type, LayerType::WindExtended);
let result = Wind::from_packet(data, extended)?;
Ok(PatchLayer::Wind(result))
}
LayerType::Water | LayerType::WaterExtended => {
let extended = matches!(data.layer_type, LayerType::WaterExtended);
let result = Water::from_packet(data, extended)?;
Ok(PatchLayer::Water(result))
}
LayerType::Cloud | LayerType::CloudExtended | LayerType::Unknown => {
let extended = !matches!(data.layer_type, LayerType::Cloud);
let result = Cloud::from_packet(data, extended)?;
Ok(PatchLayer::Cloud(result))
}
}
}
pub trait PatchData: Sized {
fn from_packet(packet: &LayerData, extended: bool) -> Result<Vec<Self>, PatchError>;
}
#[derive(Debug, Clone)]
pub struct TerrainHeader {
pub quantized_world_bits: u8,
pub dc_offset: f32,
pub range: u16,
pub extended_region: bool,
pub world_bits: u32,
pub location: U16Vec2,
pub stride: u16,
pub patch_size: u8,
pub filename: String,
}
impl TerrainHeader {
pub fn from_bytes(
reader: &mut BitReader,
extended_region: bool,
) -> Result<Self, BitReaderError> {
let quantized_world_bits = reader.read_u8(8)?;
if quantized_world_bits == END_OF_PATCHES {
return Ok(TerrainHeader {
quantized_world_bits,
dc_offset: 0.0,
range: 0,
extended_region: false,
world_bits: 0,
location: U16Vec2 { x: 0, y: 0 },
patch_size: 0,
stride: 0,
filename: "".to_string(),
});
}
let dc_offset_bits = reader.read_u32(32)?.swap_bytes();
let dc_offset = f32::from_bits(dc_offset_bits);
let range = reader.read_u16(16)?.swap_bytes();
let patch_ids = if extended_region {
read_bits(reader, 32)?
} else {
read_bits(reader, 10)?
};
let patch_decoded = bits_to_big_endian(&patch_ids, 8);
let x = if extended_region {
patch_decoded.checked_shr(16).unwrap_or(0)
} else {
patch_decoded.checked_shr(5).unwrap_or(0)
};
let y = if extended_region {
patch_decoded & 0xFFFF
} else {
patch_decoded & 0x1F
};
let world_bits = ((quantized_world_bits & 0x0f) + 2) as u32;
Ok(TerrainHeader {
quantized_world_bits,
dc_offset,
range,
extended_region,
world_bits,
location: U16Vec2 {
x: x as u16,
y: y as u16,
},
patch_size: 0,
stride: 0,
filename: "".to_string(),
})
}
}
pub fn decompress_patch(terrain_header: &TerrainHeader, patch: &[f32]) -> Vec<f32> {
let patch_size = terrain_header.patch_size as usize;
let mut block: Vec<f32> = vec![0.0; patch_size * patch_size];
let mut output: Vec<f32> = vec![0.0; patch_size * patch_size];
let prequant = (terrain_header.quantized_world_bits >> 4) + 2;
let prequant = if prequant > 0 { prequant } else { 1 };
let quantize = 1 << prequant;
let ooq = 1.0f32 / quantize as f32;
let mult = ooq * terrain_header.range as f32;
let addval = mult * (1 << (prequant - 1)) as f32 + terrain_header.dc_offset;
if terrain_header.patch_size == 16 {
for i in 0..block.len() {
block[i] = patch[COPY_MATRIX_16[i]] * DEQUANTIZE_TABLE_16[i];
}
let mut temp: Vec<f32> = vec![0.0; 16 * 16];
for i in 0..16 {
idct_column16(&block, &mut temp, i);
}
for i in 0..16 {
idct_line16(&temp, &mut block, i);
}
} else {
println!("patch size unsupported")
}
for i in 0..block.len() {
output[i] = block[i] * mult + addval;
}
output
}
pub fn bits_to_big_endian(bits: &[u32], chunk_size: usize) -> u32 {
let mut value: u32 = 0;
for chunk in bits.chunks(chunk_size).rev() {
for &bit in chunk {
value = (value << 1) | bit
}
}
value
}
pub fn read_bits(reader: &mut BitReader, bit_count: u32) -> Result<Vec<u32>, BitReaderError> {
let mut bits = Vec::with_capacity(bit_count as usize);
for _ in 0..bit_count {
let bit = reader.read_bool()?; bits.push(if bit { 1 } else { 0 });
}
Ok(bits)
}