#![allow(dead_code)]
#[derive(Debug, Clone, PartialEq)]
#[allow(dead_code)]
pub struct DecalInstance {
pub transform: [[f32; 4]; 4],
pub atlas_uv: [f32; 4],
pub opacity: f32,
pub layer: u32,
pub enabled: bool,
}
impl Default for DecalInstance {
fn default() -> Self {
Self {
transform: [
[1.0, 0.0, 0.0, 0.0],
[0.0, 1.0, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[0.0, 0.0, 0.0, 1.0],
],
atlas_uv: [0.0, 0.0, 1.0, 1.0],
opacity: 1.0,
layer: 0,
enabled: true,
}
}
}
#[derive(Debug, Clone, PartialEq)]
#[allow(dead_code)]
pub struct DecalBatchConfig {
pub max_per_batch: usize,
pub sort_by_layer: bool,
}
impl Default for DecalBatchConfig {
fn default() -> Self {
Self {
max_per_batch: 256,
sort_by_layer: true,
}
}
}
#[derive(Debug, Clone, Default)]
#[allow(dead_code)]
pub struct DecalBatch {
pub config: DecalBatchConfig,
pub instances: Vec<DecalInstance>,
}
#[allow(dead_code)]
pub fn new_decal_batch(cfg: DecalBatchConfig) -> DecalBatch {
DecalBatch {
config: cfg,
instances: Vec::new(),
}
}
#[allow(dead_code)]
pub fn add_decal_instance(b: &mut DecalBatch, inst: DecalInstance) -> Option<usize> {
if b.instances.len() >= b.config.max_per_batch {
return None;
}
let idx = b.instances.len();
b.instances.push(inst);
Some(idx)
}
#[allow(dead_code)]
pub fn remove_decal_instance(b: &mut DecalBatch, idx: usize) {
if idx < b.instances.len() {
b.instances.remove(idx);
}
}
#[allow(dead_code)]
pub fn decal_instance_count(b: &DecalBatch) -> usize {
b.instances.len()
}
#[allow(dead_code)]
pub fn enabled_decal_count(b: &DecalBatch) -> usize {
b.instances.iter().filter(|i| i.enabled).count()
}
#[allow(dead_code)]
pub fn sort_decals_by_layer(b: &mut DecalBatch) {
b.instances.sort_by_key(|i| i.layer);
}
#[allow(dead_code)]
pub fn sub_batch_count(b: &DecalBatch) -> usize {
if b.instances.is_empty() {
return 0;
}
b.instances.len().div_ceil(b.config.max_per_batch)
}
#[allow(dead_code)]
pub fn clear_decal_batch(b: &mut DecalBatch) {
b.instances.clear();
}
#[allow(dead_code)]
pub fn decal_batch_to_json(b: &DecalBatch) -> String {
format!(
r#"{{"count":{},"enabled":{}}}"#,
b.instances.len(),
enabled_decal_count(b)
)
}
#[allow(dead_code)]
pub fn decal_batch_memory_bytes(b: &DecalBatch) -> usize {
b.instances.len() * std::mem::size_of::<DecalInstance>()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_batch_empty() {
let b = new_decal_batch(DecalBatchConfig::default());
assert_eq!(decal_instance_count(&b), 0);
}
#[test]
fn add_instance() {
let mut b = new_decal_batch(DecalBatchConfig::default());
let idx = add_decal_instance(&mut b, DecalInstance::default());
assert_eq!(idx, Some(0));
}
#[test]
fn capacity_limit() {
let mut b = new_decal_batch(DecalBatchConfig {
max_per_batch: 2,
..Default::default()
});
add_decal_instance(&mut b, DecalInstance::default());
add_decal_instance(&mut b, DecalInstance::default());
let r = add_decal_instance(&mut b, DecalInstance::default());
assert!(r.is_none());
}
#[test]
fn remove_instance() {
let mut b = new_decal_batch(DecalBatchConfig::default());
add_decal_instance(&mut b, DecalInstance::default());
remove_decal_instance(&mut b, 0);
assert_eq!(decal_instance_count(&b), 0);
}
#[test]
fn enabled_count() {
let mut b = new_decal_batch(DecalBatchConfig::default());
add_decal_instance(
&mut b,
DecalInstance {
enabled: true,
..Default::default()
},
);
add_decal_instance(
&mut b,
DecalInstance {
enabled: false,
..Default::default()
},
);
assert_eq!(enabled_decal_count(&b), 1);
}
#[test]
fn sort_by_layer() {
let mut b = new_decal_batch(DecalBatchConfig::default());
add_decal_instance(
&mut b,
DecalInstance {
layer: 3,
..Default::default()
},
);
add_decal_instance(
&mut b,
DecalInstance {
layer: 1,
..Default::default()
},
);
sort_decals_by_layer(&mut b);
assert_eq!(b.instances[0].layer, 1);
}
#[test]
fn sub_batch_count_zero_when_empty() {
let b = new_decal_batch(DecalBatchConfig::default());
assert_eq!(sub_batch_count(&b), 0);
}
#[test]
fn memory_bytes_positive() {
let mut b = new_decal_batch(DecalBatchConfig::default());
add_decal_instance(&mut b, DecalInstance::default());
assert!(decal_batch_memory_bytes(&b) > 0);
}
#[test]
fn json_contains_count() {
let b = new_decal_batch(DecalBatchConfig::default());
assert!(decal_batch_to_json(&b).contains("count"));
}
#[test]
fn clear_empties() {
let mut b = new_decal_batch(DecalBatchConfig::default());
add_decal_instance(&mut b, DecalInstance::default());
clear_decal_batch(&mut b);
assert_eq!(decal_instance_count(&b), 0);
}
}