1use crate::{
2 c::{c_void, spMeshAttachment_updateRegion},
3 BlendMode, Color, Skeleton, SkeletonClipping,
4};
5
6use super::{ColorSpace, CullDirection};
7
8#[allow(unused_imports)]
9use crate::extension;
10
11#[derive(Clone)]
13pub struct SimpleRenderable {
14 pub slot_index: usize,
16 pub vertices: Vec<[f32; 2]>,
18 pub uvs: Vec<[f32; 2]>,
20 pub indices: Vec<u16>,
22 pub color: Color,
24 pub dark_color: Color,
27 pub blend_mode: BlendMode,
29 pub attachment_renderer_object: Option<*const c_void>,
32}
33
34pub struct SimpleDrawer {
40 pub cull_direction: CullDirection,
42 pub premultiplied_alpha: bool,
44 pub color_space: ColorSpace,
46}
47
48impl SimpleDrawer {
49 pub fn draw(
59 &self,
60 skeleton: &mut Skeleton,
61 mut clipper: Option<&mut SkeletonClipping>,
62 ) -> Vec<SimpleRenderable> {
63 let mut renderables = vec![];
64 let mut world_vertices = vec![];
65 world_vertices.resize(1000, 0.);
66 for slot_index in 0..skeleton.slots_count() {
67 let Some(slot) = skeleton.draw_order_at_index(slot_index) else {
68 continue;
69 };
70 if !slot.bone().active() {
71 if let Some(clipper) = clipper.as_deref_mut() {
72 clipper.clip_end(&slot);
73 }
74 continue;
75 }
76
77 let mut vertices = vec![];
78 let mut indices = vec![];
79 let mut uvs = vec![];
80 let mut color;
81
82 if let Some(mesh_attachment) = slot.attachment().and_then(|a| a.as_mesh()) {
83 unsafe {
84 spMeshAttachment_updateRegion(mesh_attachment.c_ptr());
85 };
86 color = mesh_attachment.color();
87
88 unsafe {
89 mesh_attachment.compute_world_vertices(
90 &slot,
91 0,
92 mesh_attachment.world_vertices_length(),
93 &mut world_vertices,
94 0,
95 2,
96 );
97 }
98
99 vertices.reserve(mesh_attachment.world_vertices_length() as usize);
100 uvs.reserve(mesh_attachment.world_vertices_length() as usize);
101 uvs.resize(mesh_attachment.world_vertices_length() as usize, [0., 0.]);
102 for i in 0..mesh_attachment.world_vertices_length() {
103 vertices.push([
104 world_vertices[i as usize * 2],
105 world_vertices[i as usize * 2 + 1],
106 ]);
107 }
108
109 macro_rules! copy_uvs {
111 ($i:ident) => {
112 let index = *mesh_attachment.triangles().offset($i);
113 uvs[index as usize] = [
114 *mesh_attachment.c_ptr_mut().uvs.offset(index as isize * 2),
115 *mesh_attachment
116 .c_ptr_mut()
117 .uvs
118 .offset(index as isize * 2 + 1),
119 ];
120 let index = *mesh_attachment.triangles().offset($i + 1);
121 uvs[index as usize] = [
122 *mesh_attachment.c_ptr_mut().uvs.offset(index as isize * 2),
123 *mesh_attachment
124 .c_ptr_mut()
125 .uvs
126 .offset(index as isize * 2 + 1),
127 ];
128 let index = *mesh_attachment.triangles().offset($i + 2);
129 uvs[index as usize] = [
130 *mesh_attachment.c_ptr_mut().uvs.offset(index as isize * 2),
131 *mesh_attachment
132 .c_ptr_mut()
133 .uvs
134 .offset(index as isize * 2 + 1),
135 ];
136 };
137 }
138
139 indices.reserve(mesh_attachment.triangles_count() as usize);
140 if matches!(self.cull_direction, CullDirection::CounterClockwise) {
141 for i in (0..mesh_attachment.triangles_count() as isize).step_by(3) {
142 unsafe {
143 indices.push(*mesh_attachment.triangles().offset(i + 2));
144 indices.push(*mesh_attachment.triangles().offset(i + 1));
145 indices.push(*mesh_attachment.triangles().offset(i));
146 copy_uvs!(i);
147 }
148 }
149 } else {
150 for i in (0..mesh_attachment.triangles_count() as isize).step_by(3) {
151 unsafe {
152 indices.push(*mesh_attachment.triangles().offset(i));
153 indices.push(*mesh_attachment.triangles().offset(i + 1));
154 indices.push(*mesh_attachment.triangles().offset(i + 2));
155 copy_uvs!(i);
156 }
157 }
158 }
159 } else if let Some(region_attachment) = slot.attachment().and_then(|a| a.as_region()) {
160 color = region_attachment.color();
161
162 let mut world_vertices = vec![];
163 world_vertices.resize(1000, 0.);
164 unsafe {
165 region_attachment.compute_world_vertices(&slot, &mut world_vertices, 0, 2);
166 }
167
168 vertices.reserve(4);
169 uvs.reserve(4);
170 for i in 0..4 {
171 vertices.push([
172 world_vertices[i as usize * 2],
173 world_vertices[i as usize * 2 + 1],
174 ]);
175
176 uvs.push([
177 region_attachment.uvs()[i as usize * 2],
178 region_attachment.uvs()[i as usize * 2 + 1],
179 ]);
180 }
181
182 indices.reserve(6);
183 if matches!(self.cull_direction, CullDirection::CounterClockwise) {
184 indices.push(2);
185 indices.push(1);
186 indices.push(0);
187 indices.push(0);
188 indices.push(3);
189 indices.push(2);
190 } else {
191 indices.push(0);
192 indices.push(1);
193 indices.push(2);
194 indices.push(2);
195 indices.push(3);
196 indices.push(0);
197 }
198 } else if let Some(clipping_attachment) =
199 slot.attachment().and_then(|a| a.as_clipping())
200 {
201 if let Some(clipper) = clipper.as_deref_mut() {
202 clipper.clip_start(&slot, &clipping_attachment);
203 }
204 continue;
205 } else {
206 if let Some(clipper) = clipper.as_deref_mut() {
207 clipper.clip_end(&slot);
208 }
209 continue;
210 }
211
212 if let Some(clipper) = clipper.as_deref_mut() {
213 if clipper.is_clipping() {
214 unsafe {
215 clipper.clip_triangles(
216 vertices.as_mut_slice(),
217 indices.as_mut_slice(),
218 uvs.as_mut_slice(),
219 2,
220 );
221 let clipped_vertices_size =
222 (*clipper.c_ptr_ref().clippedVertices).size as usize;
223 vertices.resize(clipped_vertices_size / 2, [0., 0.]);
224 std::ptr::copy_nonoverlapping(
225 (*clipper.c_ptr_ref().clippedVertices).items,
226 vertices.as_mut_ptr().cast::<f32>(),
227 clipped_vertices_size,
228 );
229 let clipped_triangles_size =
230 (*clipper.c_ptr_ref().clippedTriangles).size as usize;
231 indices.resize(clipped_triangles_size, 0);
232 std::ptr::copy_nonoverlapping(
233 (*clipper.c_ptr_ref().clippedTriangles).items,
234 indices.as_mut_ptr(),
235 clipped_triangles_size,
236 );
237 let clipped_uvs_size = (*clipper.c_ptr_ref().clippedUVs).size as usize;
238 uvs.resize(clipped_uvs_size / 2, [0., 0.]);
239 std::ptr::copy_nonoverlapping(
240 (*clipper.c_ptr_ref().clippedUVs).items,
241 uvs.as_mut_ptr().cast::<f32>(),
242 clipped_uvs_size,
243 );
244 }
245 }
246 }
247
248 let attachment_renderer_object =
249 slot.attachment().and_then(|a| a.as_mesh()).map_or_else(
250 || {
251 slot.attachment().and_then(|a| a.as_region()).and_then(
252 |region_attachment| unsafe {
253 let attachment_renderer_object = region_attachment
254 .renderer_object()
255 .get_atlas_region()
256 .unwrap()
257 .page()
258 .c_ptr_ref()
259 .rendererObject
260 .cast_const();
261 if attachment_renderer_object.is_null() {
262 None
263 } else {
264 Some(attachment_renderer_object)
265 }
266 },
267 )
268 },
269 |mesh_attachment| unsafe {
270 let attachment_renderer_object = mesh_attachment
271 .renderer_object()
272 .get_atlas_region()
273 .unwrap()
274 .page()
275 .c_ptr_ref()
276 .rendererObject
277 .cast_const();
278 if attachment_renderer_object.is_null() {
279 None
280 } else {
281 Some(attachment_renderer_object)
282 }
283 },
284 );
285
286 color *= slot.color() * skeleton.color();
287 let mut dark_color = slot.dark_color().unwrap_or_default();
288 if self.premultiplied_alpha {
289 color.premultiply_alpha();
290 dark_color *= color.a;
291 dark_color.a = 1.0;
292 } else {
293 dark_color.a = 0.;
294 }
295 color = match self.color_space {
296 ColorSpace::SRGB => color,
297 ColorSpace::Linear => color.nonlinear_to_linear(),
298 };
299
300 dark_color = match self.color_space {
301 ColorSpace::SRGB => dark_color,
302 ColorSpace::Linear => dark_color.nonlinear_to_linear(),
303 };
304
305 renderables.push(SimpleRenderable {
306 slot_index,
307 vertices,
308 uvs,
309 indices,
310 color,
311 dark_color,
312 blend_mode: slot.data().blend_mode(),
313 attachment_renderer_object,
314 });
315 if let Some(clipper) = clipper.as_deref_mut() {
316 clipper.clip_end(&slot);
317 }
318 }
319
320 if let Some(clipper) = clipper {
321 clipper.clip_end2();
322 }
323 renderables
324 }
325}
326
327#[cfg(test)]
328mod test {
329 use crate::test::TestAsset;
330
331 use super::*;
332
333 #[test]
335 fn simple_drawer() {
336 for json in [true, false] {
337 for example_asset in TestAsset::all() {
338 let (mut skeleton, _) = example_asset.instance(json);
339 let drawer = SimpleDrawer {
340 cull_direction: CullDirection::Clockwise,
341 premultiplied_alpha: false,
342 color_space: ColorSpace::Linear,
343 };
344 let mut clipper = SkeletonClipping::new();
345 let renderables = drawer.draw(&mut skeleton, Some(&mut clipper));
346 assert!(!renderables.is_empty());
347 }
348 }
349 }
350}