oxihuman_viewer/
light_map.rs1#![allow(dead_code)]
4
5#[allow(dead_code)]
9#[derive(Clone, Copy, Debug, PartialEq, Eq)]
10pub enum LightMapEncoding {
11 Linear,
12 Rgbm,
13 LogLuv,
14}
15
16#[allow(dead_code)]
18#[derive(Clone, Debug)]
19pub struct LightMapEntry {
20 pub mesh_id: u32,
21 pub uv_offset: [f32; 2],
22 pub uv_scale: [f32; 2],
23 pub atlas_page: u32,
24}
25
26#[allow(dead_code)]
28#[derive(Clone, Debug)]
29pub struct LightMapAtlas {
30 pub page_size: u32,
31 pub page_count: u32,
32 pub encoding: LightMapEncoding,
33 pub entries: Vec<LightMapEntry>,
34}
35
36impl Default for LightMapAtlas {
37 fn default() -> Self {
38 Self {
39 page_size: 1024,
40 page_count: 1,
41 encoding: LightMapEncoding::Linear,
42 entries: Vec::new(),
43 }
44 }
45}
46
47#[allow(dead_code)]
48pub fn new_lightmap_atlas() -> LightMapAtlas {
49 LightMapAtlas::default()
50}
51
52#[allow(dead_code)]
53pub fn lm_add_entry(
54 atlas: &mut LightMapAtlas,
55 mesh_id: u32,
56 uv_offset: [f32; 2],
57 uv_scale: [f32; 2],
58 page: u32,
59) {
60 atlas.entries.push(LightMapEntry {
61 mesh_id,
62 uv_offset,
63 uv_scale,
64 atlas_page: page,
65 });
66}
67
68#[allow(dead_code)]
69pub fn lm_remove_entry(atlas: &mut LightMapAtlas, mesh_id: u32) {
70 atlas.entries.retain(|e| e.mesh_id != mesh_id);
71}
72
73#[allow(dead_code)]
74pub fn lm_entry_count(atlas: &LightMapAtlas) -> usize {
75 atlas.entries.len()
76}
77
78#[allow(dead_code)]
79pub fn lm_get_entry(atlas: &LightMapAtlas, mesh_id: u32) -> Option<&LightMapEntry> {
80 atlas.entries.iter().find(|e| e.mesh_id == mesh_id)
81}
82
83#[allow(dead_code)]
84pub fn lm_encoding_name(enc: LightMapEncoding) -> &'static str {
85 match enc {
86 LightMapEncoding::Linear => "linear",
87 LightMapEncoding::Rgbm => "rgbm",
88 LightMapEncoding::LogLuv => "logluv",
89 }
90}
91
92#[allow(dead_code)]
93pub fn lm_memory_bytes(atlas: &LightMapAtlas) -> u64 {
94 let bytes_per_texel: u64 = match atlas.encoding {
95 LightMapEncoding::Linear => 8,
96 LightMapEncoding::Rgbm => 4,
97 LightMapEncoding::LogLuv => 4,
98 };
99 atlas.page_count as u64 * atlas.page_size as u64 * atlas.page_size as u64 * bytes_per_texel
100}
101
102#[allow(dead_code)]
103pub fn lm_clear(atlas: &mut LightMapAtlas) {
104 atlas.entries.clear();
105}
106
107#[allow(dead_code)]
108pub fn lm_to_json(atlas: &LightMapAtlas) -> String {
109 format!(
110 "{{\"page_size\":{},\"pages\":{},\"encoding\":\"{}\",\"entries\":{}}}",
111 atlas.page_size,
112 atlas.page_count,
113 lm_encoding_name(atlas.encoding),
114 atlas.entries.len()
115 )
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121
122 #[test]
123 fn new_empty_entries() {
124 assert_eq!(lm_entry_count(&new_lightmap_atlas()), 0);
125 }
126
127 #[test]
128 fn add_entry() {
129 let mut a = new_lightmap_atlas();
130 lm_add_entry(&mut a, 1, [0.0, 0.0], [0.5, 0.5], 0);
131 assert_eq!(lm_entry_count(&a), 1);
132 }
133
134 #[test]
135 fn get_entry() {
136 let mut a = new_lightmap_atlas();
137 lm_add_entry(&mut a, 42, [0.25, 0.25], [0.25, 0.25], 0);
138 assert!(lm_get_entry(&a, 42).is_some());
139 }
140
141 #[test]
142 fn remove_entry() {
143 let mut a = new_lightmap_atlas();
144 lm_add_entry(&mut a, 1, [0.0, 0.0], [1.0, 1.0], 0);
145 lm_remove_entry(&mut a, 1);
146 assert_eq!(lm_entry_count(&a), 0);
147 }
148
149 #[test]
150 fn encoding_name_rgbm() {
151 assert_eq!(lm_encoding_name(LightMapEncoding::Rgbm), "rgbm");
152 }
153
154 #[test]
155 fn memory_bytes_positive() {
156 assert!(lm_memory_bytes(&new_lightmap_atlas()) > 0);
157 }
158
159 #[test]
160 fn clear_empty() {
161 let mut a = new_lightmap_atlas();
162 lm_add_entry(&mut a, 1, [0.0, 0.0], [1.0, 1.0], 0);
163 lm_clear(&mut a);
164 assert_eq!(lm_entry_count(&a), 0);
165 }
166
167 #[test]
168 fn json_has_page_size() {
169 assert!(lm_to_json(&new_lightmap_atlas()).contains("page_size"));
170 }
171
172 #[test]
173 fn get_missing_is_none() {
174 assert!(lm_get_entry(&new_lightmap_atlas(), 99).is_none());
175 }
176
177 #[test]
178 fn uv_scale_stored() {
179 let mut a = new_lightmap_atlas();
180 lm_add_entry(&mut a, 5, [0.1, 0.2], [0.3, 0.4], 0);
181 let e = lm_get_entry(&a, 5).expect("should succeed");
182 assert!((e.uv_scale[0] - 0.3).abs() < 1e-5);
183 }
184}