1#![allow(dead_code)]
4
5#[allow(dead_code)]
9#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
10pub struct DrawSortKey(pub u64);
11
12#[allow(dead_code)]
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum SortStrategy {
16 FrontToBack,
18 BackToFront,
20 ByMaterial,
22}
23
24#[allow(dead_code)]
26#[derive(Debug, Clone)]
27pub struct DrawEntry {
28 pub id: u32,
29 pub material_id: u32,
30 pub depth: f32,
31 pub layer: u8,
32 pub transparent: bool,
33}
34
35#[allow(dead_code)]
36pub fn new_draw_entry(
37 id: u32,
38 material_id: u32,
39 depth: f32,
40 layer: u8,
41 transparent: bool,
42) -> DrawEntry {
43 DrawEntry {
44 id,
45 material_id,
46 depth,
47 layer,
48 transparent,
49 }
50}
51
52#[allow(dead_code)]
53pub fn dc_sort_key(entry: &DrawEntry, strategy: SortStrategy) -> DrawSortKey {
54 let depth_bits = entry.depth.to_bits();
55 let key = match strategy {
56 SortStrategy::FrontToBack => {
57 ((entry.layer as u64) << 56) | ((entry.material_id as u64) << 32) | depth_bits as u64
58 }
59 SortStrategy::BackToFront => {
60 ((entry.layer as u64) << 56) | ((!depth_bits) as u64 & 0x00FF_FFFF_FFFF_FFFF)
61 }
62 SortStrategy::ByMaterial => {
63 ((entry.layer as u64) << 56) | ((entry.material_id as u64) << 24)
64 }
65 };
66 DrawSortKey(key)
67}
68
69#[allow(dead_code)]
70pub fn dc_sort(entries: &mut [DrawEntry], strategy: SortStrategy) {
71 entries.sort_by_key(|e| dc_sort_key(e, strategy));
72}
73
74#[allow(dead_code)]
75pub fn dc_split_opaque_transparent(entries: &[DrawEntry]) -> (Vec<&DrawEntry>, Vec<&DrawEntry>) {
76 let opaque: Vec<&DrawEntry> = entries.iter().filter(|e| !e.transparent).collect();
77 let transparent: Vec<&DrawEntry> = entries.iter().filter(|e| e.transparent).collect();
78 (opaque, transparent)
79}
80
81#[allow(dead_code)]
82pub fn dc_count_by_material(entries: &[DrawEntry]) -> Vec<(u32, usize)> {
83 let mut counts: Vec<(u32, usize)> = Vec::new();
84 for e in entries {
85 if let Some(entry) = counts.iter_mut().find(|(mat, _)| *mat == e.material_id) {
86 entry.1 += 1;
87 } else {
88 counts.push((e.material_id, 1));
89 }
90 }
91 counts
92}
93
94#[allow(dead_code)]
95pub fn dc_batch_count(entries: &[DrawEntry]) -> usize {
96 if entries.is_empty() {
97 return 0;
98 }
99 let mut batches = 1usize;
100 for i in 1..entries.len() {
101 if entries[i].material_id != entries[i - 1].material_id {
102 batches += 1;
103 }
104 }
105 batches
106}
107
108#[allow(dead_code)]
109pub fn dc_to_json_summary(entries: &[DrawEntry]) -> String {
110 let (opaque, transparent) = dc_split_opaque_transparent(entries);
111 format!(
112 r#"{{"total":{},"opaque":{},"transparent":{}}}"#,
113 entries.len(),
114 opaque.len(),
115 transparent.len()
116 )
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122
123 #[test]
124 fn sort_by_material_groups() {
125 let mut entries = vec![
126 new_draw_entry(0, 2, 1.0, 0, false),
127 new_draw_entry(1, 1, 2.0, 0, false),
128 new_draw_entry(2, 2, 3.0, 0, false),
129 ];
130 dc_sort(&mut entries, SortStrategy::ByMaterial);
131 assert_eq!(entries[1].material_id, entries[2].material_id);
133 }
134
135 #[test]
136 fn sort_front_to_back_order() {
137 let mut entries = vec![
138 new_draw_entry(0, 0, 5.0, 0, false),
139 new_draw_entry(1, 0, 1.0, 0, false),
140 new_draw_entry(2, 0, 3.0, 0, false),
141 ];
142 dc_sort(&mut entries, SortStrategy::FrontToBack);
143 assert!(entries[0].depth <= entries[1].depth);
144 }
145
146 #[test]
147 fn split_opaque_transparent() {
148 let entries = vec![
149 new_draw_entry(0, 0, 1.0, 0, false),
150 new_draw_entry(1, 0, 2.0, 0, true),
151 new_draw_entry(2, 0, 3.0, 0, false),
152 ];
153 let (opaque, transparent) = dc_split_opaque_transparent(&entries);
154 assert_eq!(opaque.len(), 2);
155 assert_eq!(transparent.len(), 1);
156 }
157
158 #[test]
159 fn batch_count_single() {
160 let entries = vec![
161 new_draw_entry(0, 1, 1.0, 0, false),
162 new_draw_entry(1, 1, 2.0, 0, false),
163 ];
164 assert_eq!(dc_batch_count(&entries), 1);
165 }
166
167 #[test]
168 fn batch_count_multiple() {
169 let entries = vec![
170 new_draw_entry(0, 1, 1.0, 0, false),
171 new_draw_entry(1, 2, 2.0, 0, false),
172 ];
173 assert_eq!(dc_batch_count(&entries), 2);
174 }
175
176 #[test]
177 fn batch_count_empty() {
178 let entries: Vec<DrawEntry> = vec![];
179 assert_eq!(dc_batch_count(&entries), 0);
180 }
181
182 #[test]
183 fn count_by_material() {
184 let entries = vec![
185 new_draw_entry(0, 1, 1.0, 0, false),
186 new_draw_entry(1, 1, 2.0, 0, false),
187 new_draw_entry(2, 2, 3.0, 0, false),
188 ];
189 let counts = dc_count_by_material(&entries);
190 let mat1 = counts.iter().find(|(m, _)| *m == 1).map(|(_, c)| *c);
191 assert_eq!(mat1, Some(2));
192 }
193
194 #[test]
195 fn sort_key_layer_priority() {
196 let a = new_draw_entry(0, 0, 1.0, 0, false);
197 let b = new_draw_entry(1, 0, 1.0, 1, false);
198 let ka = dc_sort_key(&a, SortStrategy::ByMaterial);
199 let kb = dc_sort_key(&b, SortStrategy::ByMaterial);
200 assert!(kb > ka);
201 }
202
203 #[test]
204 fn to_json_summary() {
205 let entries = vec![new_draw_entry(0, 0, 1.0, 0, true)];
206 let j = dc_to_json_summary(&entries);
207 assert!(j.contains("transparent"));
208 }
209}