1use crate::image_manager::ImageId;
2
3pub type LayerId = usize;
4pub type SpriteId = usize;
5
6#[derive(Debug, Copy, Clone, Eq, PartialEq)]
7pub enum SpriteFit {
8 FullScreen,
10 PixelRect,
12}
13
14#[derive(Debug, Copy, Clone, Eq, PartialEq)]
15pub struct ClipRect {
16 pub left: i32,
17 pub top: i32,
18 pub right: i32,
19 pub bottom: i32,
20}
21
22#[derive(Debug, Copy, Clone, Eq, PartialEq)]
23pub enum SpriteSizeMode {
24 Intrinsic,
26 Explicit { width: u32, height: u32 },
28}
29
30#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
31pub enum SpriteBlend {
32 Normal,
33 Add,
34 Sub,
35 Mul,
36 Screen,
37 Overlay,
38}
39
40impl Default for SpriteBlend {
41 fn default() -> Self {
42 Self::Normal
43 }
44}
45
46#[derive(Debug, Clone, Copy, PartialEq)]
47pub struct SpriteRuntimeLight {
48 pub id: i32,
49 pub kind: i32,
50 pub diffuse: [f32; 4],
51 pub ambient: [f32; 4],
52 pub specular: [f32; 4],
53 pub pos: [f32; 4],
54 pub dir: [f32; 4],
55 pub atten: [f32; 4],
56 pub cone: [f32; 4],
57}
58
59impl Default for SpriteRuntimeLight {
60 fn default() -> Self {
61 Self {
62 id: -1,
63 kind: -1,
64 diffuse: [0.0, 0.0, 0.0, 1.0],
65 ambient: [0.0, 0.0, 0.0, 1.0],
66 specular: [0.0, 0.0, 0.0, 1.0],
67 pos: [0.0, 0.0, 0.0, 1.0],
68 dir: [0.0, 0.0, -1.0, 0.0],
69 atten: [1.0, 0.0, 0.0, 5000.0],
70 cone: [0.0, 0.0, 1.0, 0.0],
71 }
72 }
73}
74impl SpriteBlend {
75 pub fn from_i64(v: i64) -> Self {
76 match v {
77 1 => SpriteBlend::Add,
78 2 => SpriteBlend::Sub,
79 3 => SpriteBlend::Mul,
80 4 => SpriteBlend::Screen,
81 5 => SpriteBlend::Overlay,
82 _ => SpriteBlend::Normal,
83 }
84 }
85}
86
87#[derive(Debug, Clone)]
88pub struct Sprite {
89 pub image_id: Option<ImageId>,
90 pub mask_image_id: Option<ImageId>,
91 pub mask_offset_x: i32,
92 pub mask_offset_y: i32,
93 pub tonecurve_image_id: Option<ImageId>,
94 pub tonecurve_row: f32,
95 pub tonecurve_sat: f32,
96 pub fit: SpriteFit,
97 pub size_mode: SpriteSizeMode,
98 pub visible: bool,
99 pub alpha: u8,
100 pub x: i32,
101 pub y: i32,
102 pub z: f32,
103 pub scale_x: f32,
104 pub scale_y: f32,
105 pub scale_z: f32,
106 pub rotate: f32,
107 pub rotate_x: f32,
108 pub rotate_y: f32,
109 pub pivot_x: f32,
110 pub pivot_y: f32,
111 pub pivot_z: f32,
112 pub object_anchor: bool,
117 pub texture_center_x: f32,
118 pub texture_center_y: f32,
119 pub camera_enabled: bool,
120 pub camera_eye: [f32; 3],
121 pub camera_target: [f32; 3],
122 pub camera_up: [f32; 3],
123 pub camera_view_angle_deg: f32,
124 pub culling: bool,
125 pub alpha_test: bool,
126 pub alpha_blend: bool,
127 pub fog_use: bool,
128 pub light_no: i32,
129 pub light_enabled: bool,
130 pub light_diffuse: [f32; 4],
131 pub light_ambient: [f32; 4],
132 pub light_specular: [f32; 4],
133 pub light_factor: f32,
134 pub light_kind: i32,
135 pub light_pos: [f32; 4],
136 pub light_dir: [f32; 4],
137 pub light_atten: [f32; 4],
138 pub light_cone: [f32; 4],
139 pub mesh_runtime_lights: Vec<SpriteRuntimeLight>,
140 pub fog_enabled: bool,
141 pub fog_color: [f32; 4],
142 pub fog_near: f32,
143 pub fog_far: f32,
144 pub fog_scroll_x: f32,
145 pub fog_texture_image_id: Option<ImageId>,
146 pub world_no: i32,
147 pub billboard: bool,
148 pub mesh_file_name: Option<String>,
149 pub mesh_animation: crate::mesh3d::MeshAnimationState,
150 pub mesh_kind: u8,
152 pub shadow_cast: bool,
153 pub shadow_receive: bool,
154 pub wipe_fx_mode: u8,
159 pub wipe_fx_params: [f32; 4],
160 pub wipe_src_image_id: Option<ImageId>,
162 pub tr: u8,
163 pub mono: u8,
164 pub reverse: u8,
165 pub bright: u8,
166 pub dark: u8,
167 pub color_rate: u8,
168 pub color_add_r: u8,
169 pub color_add_g: u8,
170 pub color_add_b: u8,
171 pub color_r: u8,
172 pub color_g: u8,
173 pub color_b: u8,
174 pub mask_mode: u8,
176 pub blend: SpriteBlend,
177 pub dst_clip: Option<ClipRect>,
178 pub src_clip: Option<ClipRect>,
179 pub order: i32,
181}
182
183impl Default for Sprite {
184 fn default() -> Self {
185 Self {
186 image_id: None,
187 mask_image_id: None,
188 mask_offset_x: 0,
189 mask_offset_y: 0,
190 tonecurve_image_id: None,
191 tonecurve_row: 0.0,
192 tonecurve_sat: 0.0,
193 fit: SpriteFit::PixelRect,
194 size_mode: SpriteSizeMode::Intrinsic,
195 visible: false,
196 alpha: 255,
197 x: 0,
198 y: 0,
199 z: 0.0,
200 scale_x: 1.0,
201 scale_y: 1.0,
202 scale_z: 1.0,
203 rotate: 0.0,
204 rotate_x: 0.0,
205 rotate_y: 0.0,
206 pivot_x: 0.0,
207 pivot_y: 0.0,
208 pivot_z: 0.0,
209 object_anchor: false,
210 texture_center_x: 0.0,
211 texture_center_y: 0.0,
212 camera_enabled: false,
213 camera_eye: [0.0, 0.0, -1000.0],
214 camera_target: [0.0, 0.0, 0.0],
215 camera_up: [0.0, 1.0, 0.0],
216 camera_view_angle_deg: 45.0,
217 culling: false,
218 alpha_test: false,
219 alpha_blend: true,
220 fog_use: false,
221 light_no: -1,
222 light_enabled: false,
223 light_diffuse: [1.0, 1.0, 1.0, 1.0],
224 light_ambient: [0.0, 0.0, 0.0, 1.0],
225 light_specular: [0.0, 0.0, 0.0, 1.0],
226 light_factor: 0.0,
227 light_kind: -1,
228 light_pos: [0.0, 0.0, 0.0, 0.0],
229 light_dir: [0.0, 0.0, -1.0, 0.0],
230 light_atten: [1.0, 0.0, 0.0, 5000.0],
231 light_cone: [0.0, 0.0, 1.0, 0.0],
232 mesh_runtime_lights: Vec::new(),
233 fog_enabled: false,
234 fog_color: [0.0, 0.0, 0.0, 1.0],
235 fog_near: 0.0,
236 fog_far: 0.0,
237 fog_scroll_x: 0.0,
238 fog_texture_image_id: None,
239 world_no: -1,
240 billboard: false,
241 mesh_file_name: None,
242 mesh_animation: crate::mesh3d::MeshAnimationState::default(),
243 mesh_kind: 0,
244 shadow_cast: false,
245 shadow_receive: false,
246 wipe_fx_mode: 0,
247 wipe_fx_params: [0.0; 4],
248 wipe_src_image_id: None,
249 tr: 255,
250 mono: 0,
251 reverse: 0,
252 bright: 0,
253 dark: 0,
254 color_rate: 0,
255 color_add_r: 0,
256 color_add_g: 0,
257 color_add_b: 0,
258 color_r: 0,
259 color_g: 0,
260 color_b: 0,
261 mask_mode: 0,
262 blend: SpriteBlend::Normal,
263 dst_clip: None,
264 src_clip: None,
265 order: 0,
266 }
267 }
268}
269
270#[derive(Debug, Clone)]
271pub struct Layer {
272 sprites: Vec<Sprite>,
273}
274
275impl Layer {
276 pub fn new() -> Self {
277 Self {
278 sprites: Vec::new(),
279 }
280 }
281
282 pub fn create_sprite(&mut self) -> SpriteId {
283 let id = self.sprites.len();
284 self.sprites.push(Sprite::default());
285 id
286 }
287
288 pub fn sprite(&self, id: SpriteId) -> Option<&Sprite> {
289 self.sprites.get(id)
290 }
291
292 pub fn sprite_mut(&mut self, id: SpriteId) -> Option<&mut Sprite> {
293 self.sprites.get_mut(id)
294 }
295
296 pub fn clear_all_sprites(&mut self) {
297 for s in &mut self.sprites {
299 s.image_id = None;
300 s.mask_image_id = None;
301 s.mask_offset_x = 0;
302 s.mask_offset_y = 0;
303 s.tonecurve_image_id = None;
304 s.tonecurve_row = 0.0;
305 s.tonecurve_sat = 0.0;
306 s.visible = false;
307 s.alpha = 255;
308 s.x = 0;
309 s.y = 0;
310 s.z = 0.0;
311 s.order = 0;
312 s.fit = SpriteFit::PixelRect;
313 s.size_mode = SpriteSizeMode::Intrinsic;
314 s.scale_x = 1.0;
315 s.scale_y = 1.0;
316 s.scale_z = 1.0;
317 s.rotate = 0.0;
318 s.rotate_x = 0.0;
319 s.rotate_y = 0.0;
320 s.pivot_x = 0.0;
321 s.pivot_y = 0.0;
322 s.pivot_z = 0.0;
323 s.camera_enabled = false;
324 s.camera_eye = [0.0, 0.0, -1000.0];
325 s.camera_target = [0.0, 0.0, 0.0];
326 s.camera_up = [0.0, 1.0, 0.0];
327 s.camera_view_angle_deg = 45.0;
328 s.culling = false;
329 s.alpha_test = false;
330 s.alpha_blend = true;
331 s.fog_use = false;
332 s.light_no = -1;
333 s.light_enabled = false;
334 s.light_diffuse = [1.0, 1.0, 1.0, 1.0];
335 s.light_ambient = [0.0, 0.0, 0.0, 1.0];
336 s.light_specular = [0.0, 0.0, 0.0, 1.0];
337 s.light_factor = 0.0;
338 s.light_kind = -1;
339 s.light_pos = [0.0, 0.0, 0.0, 0.0];
340 s.light_dir = [0.0, 0.0, -1.0, 0.0];
341 s.light_atten = [1.0, 0.0, 0.0, 5000.0];
342 s.light_cone = [0.0, 0.0, 1.0, 0.0];
343 s.mesh_runtime_lights.clear();
344 s.fog_enabled = false;
345 s.fog_color = [0.0, 0.0, 0.0, 1.0];
346 s.fog_near = 0.0;
347 s.fog_far = 0.0;
348 s.fog_scroll_x = 0.0;
349 s.fog_texture_image_id = None;
350 s.world_no = -1;
351 s.billboard = false;
352 s.mesh_kind = 0;
353 s.mesh_file_name = None;
354 s.mesh_animation = crate::mesh3d::MeshAnimationState::default();
355 s.shadow_cast = false;
356 s.shadow_receive = false;
357 s.wipe_fx_mode = 0;
358 s.wipe_fx_params = [0.0; 4];
359 s.wipe_src_image_id = None;
360 s.tr = 255;
361 s.mono = 0;
362 s.reverse = 0;
363 s.bright = 0;
364 s.dark = 0;
365 s.color_rate = 0;
366 s.color_add_r = 0;
367 s.color_add_g = 0;
368 s.color_add_b = 0;
369 s.color_r = 0;
370 s.color_g = 0;
371 s.color_b = 0;
372 s.blend = SpriteBlend::Normal;
373 s.dst_clip = None;
374 s.src_clip = None;
375 }
376 }
377
378 fn sprite_ids_sorted(&self) -> Vec<SpriteId> {
379 let mut ids: Vec<SpriteId> = (0..self.sprites.len()).collect();
380 ids.sort_by(|&a, &b| {
381 let oa = self.sprites[a].order;
382 let ob = self.sprites[b].order;
383 oa.cmp(&ob).then(a.cmp(&b))
384 });
385 ids
386 }
387}
388
389#[derive(Debug, Clone)]
390pub struct RenderSprite {
391 pub layer_id: Option<LayerId>,
392 pub sprite_id: Option<SpriteId>,
393 pub sorter_order: i32,
398 pub sorter_layer: i32,
401 pub sprite: Sprite,
402}
403
404impl RenderSprite {
405 pub fn new(layer_id: Option<LayerId>, sprite_id: Option<SpriteId>, sprite: Sprite) -> Self {
406 let (sorter_order, sorter_layer) = unpack_sprite_order(sprite.order);
407 Self {
408 layer_id,
409 sprite_id,
410 sorter_order,
411 sorter_layer,
412 sprite,
413 }
414 }
415
416 pub fn with_sorter(
417 layer_id: Option<LayerId>,
418 sprite_id: Option<SpriteId>,
419 sorter_order: i32,
420 sorter_layer: i32,
421 sprite: Sprite,
422 ) -> Self {
423 Self {
424 layer_id,
425 sprite_id,
426 sorter_order,
427 sorter_layer,
428 sprite,
429 }
430 }
431
432 pub fn set_sorter(&mut self, order: i64, layer: i64) {
433 self.sorter_order = order.clamp(i32::MIN as i64, i32::MAX as i64) as i32;
434 self.sorter_layer = layer.clamp(i32::MIN as i64, i32::MAX as i64) as i32;
435 }
436}
437
438fn unpack_sprite_order(order: i32) -> (i32, i32) {
439 if order.abs() >= 1024 {
440 (order.div_euclid(1024), order.rem_euclid(1024))
441 } else {
442 (0, order)
443 }
444}
445
446#[derive(Debug, Default)]
447pub struct LayerManager {
448 bg: Sprite,
449 layers: Vec<Layer>,
450}
451
452impl LayerManager {
453 pub fn new() -> Self {
454 Self::default()
455 }
456
457 pub fn bg_mut(&mut self) -> &mut Sprite {
458 &mut self.bg
459 }
460
461 pub fn set_bg_image(&mut self, image_id: ImageId) {
462 self.bg.image_id = Some(image_id);
463 self.bg.mask_image_id = None;
464 self.bg.mask_offset_x = 0;
465 self.bg.mask_offset_y = 0;
466 self.bg.tonecurve_image_id = None;
467 self.bg.tonecurve_row = 0.0;
468 self.bg.tonecurve_sat = 0.0;
469 self.bg.wipe_fx_mode = 0;
470 self.bg.wipe_fx_params = [0.0; 4];
471 self.bg.wipe_src_image_id = None;
472 self.bg.fit = SpriteFit::FullScreen;
473 self.bg.size_mode = SpriteSizeMode::Intrinsic;
474 self.bg.visible = true;
475 self.bg.order = i32::MIN;
476 self.bg.scale_x = 1.0;
477 self.bg.scale_y = 1.0;
478 self.bg.scale_z = 1.0;
479 self.bg.rotate = 0.0;
480 self.bg.rotate_x = 0.0;
481 self.bg.rotate_y = 0.0;
482 self.bg.pivot_x = 0.0;
483 self.bg.pivot_y = 0.0;
484 self.bg.pivot_z = 0.0;
485 self.bg.z = 0.0;
486 self.bg.camera_enabled = false;
487 self.bg.camera_eye = [0.0, 0.0, -1000.0];
488 self.bg.camera_target = [0.0, 0.0, 0.0];
489 self.bg.camera_up = [0.0, 1.0, 0.0];
490 self.bg.camera_view_angle_deg = 45.0;
491 self.bg.culling = false;
492 self.bg.alpha_test = false;
493 self.bg.alpha_blend = true;
494 self.bg.fog_use = false;
495 self.bg.light_no = -1;
496 self.bg.light_enabled = false;
497 self.bg.light_diffuse = [1.0, 1.0, 1.0, 1.0];
498 self.bg.light_ambient = [0.0, 0.0, 0.0, 1.0];
499 self.bg.light_specular = [0.0, 0.0, 0.0, 1.0];
500 self.bg.light_factor = 0.0;
501 self.bg.light_kind = -1;
502 self.bg.light_pos = [0.0, 0.0, 0.0, 0.0];
503 self.bg.light_dir = [0.0, 0.0, -1.0, 0.0];
504 self.bg.light_atten = [1.0, 0.0, 0.0, 5000.0];
505 self.bg.light_cone = [0.0, 0.0, 1.0, 0.0];
506 self.bg.mesh_runtime_lights.clear();
507 self.bg.fog_enabled = false;
508 self.bg.fog_color = [0.0, 0.0, 0.0, 1.0];
509 self.bg.fog_near = 0.0;
510 self.bg.fog_far = 0.0;
511 self.bg.fog_scroll_x = 0.0;
512 self.bg.fog_texture_image_id = None;
513 self.bg.world_no = -1;
514 self.bg.billboard = false;
515 self.bg.mesh_kind = 0;
516 self.bg.mesh_file_name = None;
517 self.bg.mesh_animation = crate::mesh3d::MeshAnimationState::default();
518 self.bg.shadow_cast = false;
519 self.bg.shadow_receive = false;
520 self.bg.wipe_fx_mode = 0;
521 self.bg.wipe_fx_params = [0.0; 4];
522 self.bg.wipe_src_image_id = None;
523 self.bg.tr = 255;
524 self.bg.mono = 0;
525 self.bg.reverse = 0;
526 self.bg.bright = 0;
527 self.bg.dark = 0;
528 self.bg.color_rate = 0;
529 self.bg.color_add_r = 0;
530 self.bg.color_add_g = 0;
531 self.bg.color_add_b = 0;
532 self.bg.color_r = 0;
533 self.bg.color_g = 0;
534 self.bg.color_b = 0;
535 self.bg.mask_mode = 0;
536 self.bg.blend = SpriteBlend::Normal;
537 self.bg.dst_clip = None;
538 self.bg.src_clip = None;
539 }
540
541 pub fn clear_bg(&mut self) {
542 self.bg.image_id = None;
543 self.bg.mask_image_id = None;
544 self.bg.mask_offset_x = 0;
545 self.bg.mask_offset_y = 0;
546 self.bg.tonecurve_image_id = None;
547 self.bg.tonecurve_row = 0.0;
548 self.bg.tonecurve_sat = 0.0;
549 self.bg.wipe_fx_mode = 0;
550 self.bg.wipe_fx_params = [0.0; 4];
551 self.bg.wipe_src_image_id = None;
552 self.bg.light_enabled = false;
553 self.bg.light_diffuse = [1.0, 1.0, 1.0, 1.0];
554 self.bg.light_ambient = [0.0, 0.0, 0.0, 1.0];
555 self.bg.light_specular = [0.0, 0.0, 0.0, 1.0];
556 self.bg.light_factor = 0.0;
557 self.bg.light_kind = -1;
558 self.bg.light_pos = [0.0, 0.0, 0.0, 0.0];
559 self.bg.light_dir = [0.0, 0.0, -1.0, 0.0];
560 self.bg.light_atten = [1.0, 0.0, 0.0, 5000.0];
561 self.bg.light_cone = [0.0, 0.0, 1.0, 0.0];
562 self.bg.mesh_runtime_lights.clear();
563 self.bg.fog_enabled = false;
564 self.bg.fog_color = [0.0, 0.0, 0.0, 1.0];
565 self.bg.fog_near = 0.0;
566 self.bg.fog_far = 0.0;
567 self.bg.fog_scroll_x = 0.0;
568 self.bg.fog_texture_image_id = None;
569 self.bg.mesh_kind = 0;
570 self.bg.mesh_file_name = None;
571 self.bg.mesh_animation = crate::mesh3d::MeshAnimationState::default();
572 self.bg.shadow_cast = false;
573 self.bg.shadow_receive = false;
574 self.bg.visible = false;
575 }
576
577 pub fn create_layer(&mut self) -> LayerId {
578 let id = self.layers.len();
579 self.layers.push(Layer::new());
580 id
581 }
582
583 pub fn layer(&self, id: LayerId) -> Option<&Layer> {
584 self.layers.get(id)
585 }
586
587 pub fn layer_mut(&mut self, id: LayerId) -> Option<&mut Layer> {
588 self.layers.get_mut(id)
589 }
590
591 pub fn clear_layer(&mut self, id: LayerId) {
592 if let Some(layer) = self.layers.get_mut(id) {
593 layer.clear_all_sprites();
594 }
595 }
596
597 pub fn clear_all(&mut self) {
598 self.clear_bg();
599 for layer in &mut self.layers {
600 layer.clear_all_sprites();
601 }
602 }
603
604 pub fn reset_runtime_effects(&mut self) {
605 self.bg.mask_image_id = None;
606 self.bg.mask_offset_x = 0;
607 self.bg.mask_offset_y = 0;
608 self.bg.tonecurve_image_id = None;
609 self.bg.tonecurve_row = 0.0;
610 self.bg.tonecurve_sat = 0.0;
611 self.bg.wipe_fx_mode = 0;
612 self.bg.wipe_fx_params = [0.0; 4];
613 self.bg.wipe_src_image_id = None;
614 self.bg.light_enabled = false;
615 self.bg.light_diffuse = [1.0, 1.0, 1.0, 1.0];
616 self.bg.light_ambient = [0.0, 0.0, 0.0, 1.0];
617 self.bg.light_specular = [0.0, 0.0, 0.0, 1.0];
618 self.bg.light_factor = 0.0;
619 self.bg.light_kind = -1;
620 self.bg.light_pos = [0.0, 0.0, 0.0, 0.0];
621 self.bg.light_dir = [0.0, 0.0, -1.0, 0.0];
622 self.bg.light_atten = [1.0, 0.0, 0.0, 5000.0];
623 self.bg.light_cone = [0.0, 0.0, 1.0, 0.0];
624 self.bg.mesh_runtime_lights.clear();
625 self.bg.fog_enabled = false;
626 self.bg.fog_color = [0.0, 0.0, 0.0, 1.0];
627 self.bg.fog_near = 0.0;
628 self.bg.fog_far = 0.0;
629 self.bg.fog_scroll_x = 0.0;
630 self.bg.fog_texture_image_id = None;
631 for layer in &mut self.layers {
632 for s in &mut layer.sprites {
633 s.mask_image_id = None;
634 s.mask_offset_x = 0;
635 s.mask_offset_y = 0;
636 s.tonecurve_image_id = None;
637 s.tonecurve_row = 0.0;
638 s.tonecurve_sat = 0.0;
639 s.wipe_fx_mode = 0;
640 s.wipe_fx_params = [0.0; 4];
641 s.wipe_src_image_id = None;
642 s.light_enabled = false;
643 s.light_diffuse = [1.0, 1.0, 1.0, 1.0];
644 s.light_ambient = [0.0, 0.0, 0.0, 1.0];
645 s.light_factor = 0.0;
646 s.fog_enabled = false;
647 s.fog_color = [0.0, 0.0, 0.0, 1.0];
648 s.fog_near = 0.0;
649 s.fog_far = 0.0;
650 s.fog_scroll_x = 0.0;
651 s.fog_texture_image_id = None;
652 s.mesh_kind = 0;
653 s.mesh_file_name = None;
654 s.shadow_cast = false;
655 s.shadow_receive = false;
656 }
657 }
658 }
659
660 pub fn render_list(&self) -> Vec<RenderSprite> {
661 let mut out = Vec::new();
662
663 if self.bg.visible && self.bg.alpha > 0 && self.bg.tr > 0 {
664 if let Some(img) = self.bg.image_id {
665 let mut bg = self.bg.clone();
666 bg.image_id = Some(img);
667 out.push(RenderSprite::new(None, None, bg));
668 }
669 }
670
671 for (layer_id, layer) in self.layers.iter().enumerate() {
672 for sprite_id in layer.sprite_ids_sorted() {
673 let s = &layer.sprites[sprite_id];
674 if !s.visible {
675 continue;
676 }
677 if s.image_id.is_none() || s.alpha == 0 || s.tr == 0 {
678 continue;
679 }
680 out.push(RenderSprite::new(Some(layer_id), Some(sprite_id), s.clone()));
681 }
682 }
683
684 out
685 }
686}