cityjson_types/resources/mapping/
textures.rs1use crate::resources::handles::TextureHandle;
2use crate::resources::id::{ResourceId, ResourceId32};
3use crate::v2_0::vertex::{VertexIndex, VertexRef};
4
5#[repr(C)]
6#[derive(Clone, Debug, Default, Hash, Ord, PartialOrd, Eq, PartialEq)]
7pub(crate) struct TextureMapCore<VR: VertexRef, RR: ResourceId> {
8 vertices: Vec<Option<VertexIndex<VR>>>,
9 rings: Vec<VertexIndex<VR>>,
10 ring_textures: Vec<Option<RR>>,
11 }
13
14impl<VR: VertexRef, RR: ResourceId> TextureMapCore<VR, RR> {
15 pub(crate) fn is_empty(&self) -> bool {
16 self.vertices.is_empty() && self.rings.is_empty() && self.ring_textures.is_empty()
17 }
18
19 pub(crate) fn add_vertex(&mut self, vertex: Option<VertexIndex<VR>>) {
20 self.vertices.push(vertex);
21 }
22
23 pub(crate) fn add_ring(&mut self, ring_start: VertexIndex<VR>) {
24 self.rings.push(ring_start);
25 }
26
27 pub(crate) fn add_ring_texture(&mut self, texture: Option<RR>) {
28 self.ring_textures.push(texture);
29 }
30
31 pub(crate) fn vertices(&self) -> &[Option<VertexIndex<VR>>] {
32 &self.vertices
33 }
34
35 pub(crate) fn vertices_mut(&mut self) -> &mut [Option<VertexIndex<VR>>] {
36 &mut self.vertices
37 }
38
39 pub(crate) fn rings(&self) -> &[VertexIndex<VR>] {
40 &self.rings
41 }
42
43 pub(crate) fn rings_mut(&mut self) -> &mut [VertexIndex<VR>] {
44 &mut self.rings
45 }
46
47 pub(crate) fn ring_textures(&self) -> &[Option<RR>] {
48 &self.ring_textures
49 }
50
51 pub(crate) fn ring_textures_mut(&mut self) -> &mut [Option<RR>] {
52 &mut self.ring_textures
53 }
54}
55
56#[repr(C)]
57#[derive(Clone, Debug, Default, Hash, Ord, PartialOrd, Eq, PartialEq)]
58pub struct TextureMap<VR: VertexRef> {
59 inner: TextureMapCore<VR, ResourceId32>,
60}
61
62impl<VR: VertexRef> TextureMap<VR> {
63 #[must_use]
64 pub fn new() -> Self {
65 Self::default()
66 }
67
68 #[must_use]
69 pub fn is_empty(&self) -> bool {
70 self.inner.is_empty()
71 }
72
73 pub fn add_vertex(&mut self, vertex: Option<VertexIndex<VR>>) {
74 self.inner.add_vertex(vertex);
75 }
76
77 pub fn add_ring(&mut self, ring_start: VertexIndex<VR>) {
78 self.inner.add_ring(ring_start);
79 }
80
81 pub fn add_ring_texture(&mut self, texture: Option<TextureHandle>) {
82 self.inner
83 .add_ring_texture(texture.map(super::super::handles::TextureHandle::to_raw));
84 }
85
86 #[must_use]
87 pub fn vertices(&self) -> &[Option<VertexIndex<VR>>] {
88 self.inner.vertices()
89 }
90
91 pub fn vertices_mut(&mut self) -> &mut [Option<VertexIndex<VR>>] {
92 self.inner.vertices_mut()
93 }
94
95 #[must_use]
96 pub fn rings(&self) -> &[VertexIndex<VR>] {
97 self.inner.rings()
98 }
99
100 pub fn rings_mut(&mut self) -> &mut [VertexIndex<VR>] {
101 self.inner.rings_mut()
102 }
103
104 #[must_use]
105 pub fn ring_textures(&self) -> Vec<Option<TextureHandle>> {
106 self.inner
107 .ring_textures()
108 .iter()
109 .copied()
110 .map(|r| r.map(TextureHandle::from_raw))
111 .collect()
112 }
113
114 pub fn set_ring_texture(&mut self, ring_index: usize, texture: Option<TextureHandle>) -> bool {
115 let Some(slot) = self.inner.ring_textures_mut().get_mut(ring_index) else {
116 return false;
117 };
118 *slot = texture.map(super::super::handles::TextureHandle::to_raw);
119 true
120 }
121
122 #[allow(dead_code)]
123 pub(crate) fn from_raw(inner: TextureMapCore<VR, ResourceId32>) -> Self {
124 Self { inner }
125 }
126
127 #[allow(dead_code)]
128 pub(crate) fn into_raw(self) -> TextureMapCore<VR, ResourceId32> {
129 self.inner
130 }
131
132 #[allow(dead_code)]
133 pub(crate) fn to_raw(&self) -> &TextureMapCore<VR, ResourceId32> {
134 &self.inner
135 }
136}
137
138#[cfg(test)]
145mod texture_map {
146 use super::*;
147 use crate::resources::id::ResourceId32;
148
149 type Core = TextureMapCore<u32, ResourceId32>;
150
151 fn make_tex_id(index: u32) -> ResourceId32 {
152 ResourceId32::new(index, 0)
153 }
154
155 fn vi(n: u32) -> VertexIndex<u32> {
156 VertexIndex::new(n)
157 }
158
159 #[test]
164 fn ring_count_matches_uv_vertex_count() {
165 let mut core = Core::default();
167 core.add_vertex(Some(vi(0)));
168 core.add_vertex(Some(vi(1)));
169 core.add_vertex(Some(vi(2)));
170 core.add_ring(vi(0));
171 core.add_ring_texture(Some(make_tex_id(0)));
172
173 assert_eq!(core.vertices().len(), 3);
174 assert_eq!(core.rings().len(), 1);
175 assert_eq!(core.ring_textures().len(), 1);
176 }
177
178 #[test]
179 fn ring_texture_can_be_none() {
180 let mut core = Core::default();
181 core.add_vertex(Some(vi(0)));
182 core.add_ring(vi(0));
183 core.add_ring_texture(None);
184
185 assert!(core.ring_textures()[0].is_none());
186 }
187
188 #[test]
189 fn multi_ring_multi_texture() {
190 let mut core = Core::default();
192 core.add_vertex(Some(vi(0)));
194 core.add_vertex(Some(vi(1)));
195 core.add_vertex(Some(vi(2)));
196 core.add_ring(vi(0));
197 core.add_ring_texture(Some(make_tex_id(0)));
198 core.add_vertex(Some(vi(0)));
200 core.add_vertex(Some(vi(2)));
201 core.add_vertex(Some(vi(3)));
202 core.add_ring(vi(3));
203 core.add_ring_texture(Some(make_tex_id(1)));
204
205 assert_eq!(core.vertices().len(), 6);
206 assert_eq!(core.rings().len(), 2);
207 assert_eq!(core.ring_textures().len(), 2);
208 assert_eq!(core.ring_textures()[0], Some(make_tex_id(0)));
209 assert_eq!(core.ring_textures()[1], Some(make_tex_id(1)));
210 }
211
212 #[test]
218 fn vertex_reuse_different_uvs_per_ring() {
219 let mut core = Core::default();
223 core.add_vertex(Some(vi(0))); core.add_vertex(Some(vi(1))); core.add_ring(vi(0));
227 core.add_ring_texture(Some(make_tex_id(0)));
228 core.add_vertex(Some(vi(0))); core.add_vertex(Some(vi(1))); core.add_ring(vi(2));
232 core.add_ring_texture(Some(make_tex_id(0)));
233
234 assert_eq!(core.vertices().len(), 4, "4 uv-vertex slots (2 per ring)");
235 assert_eq!(core.vertices()[0], core.vertices()[2]);
237 assert_ne!(
239 core.rings()[0],
240 core.rings()[1],
241 "rings start at different uv-vertex offsets"
242 );
243 }
244}