1use crate::image_manager::ImageHandle;
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#[cfg(test)]
15mod tests {
16 use super::LayerManager;
17
18 #[test]
19 fn resetting_transient_effects_preserves_mesh_payload() {
20 let mut layers = LayerManager::new();
21 let layer_id = layers.create_layer();
22 let sprite_id = layers.layer_mut(layer_id).unwrap().create_sprite();
23 let sprite = layers
24 .layer_mut(layer_id)
25 .unwrap()
26 .sprite_mut(sprite_id)
27 .unwrap();
28 sprite.mesh_kind = 1;
29 sprite.mesh_file_name = Some("room.x".to_owned());
30 sprite.shadow_cast = true;
31 sprite.shadow_receive = true;
32
33 layers.reset_runtime_effects();
34
35 let sprite = layers.layer(layer_id).unwrap().sprite(sprite_id).unwrap();
36 assert_eq!(sprite.mesh_kind, 1);
37 assert_eq!(sprite.mesh_file_name.as_deref(), Some("room.x"));
38 assert!(sprite.shadow_cast);
39 assert!(sprite.shadow_receive);
40 }
41}
42
43#[derive(Debug, Copy, Clone, Eq, PartialEq)]
44pub struct ClipRect {
45 pub left: i32,
46 pub top: i32,
47 pub right: i32,
48 pub bottom: i32,
49}
50
51#[derive(Debug, Copy, Clone, Eq, PartialEq)]
52pub enum SpriteSizeMode {
53 Intrinsic,
55 Explicit { width: u32, height: u32 },
57}
58
59#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Default)]
60pub enum SpriteBlend {
61 #[default]
62 Normal,
63 Add,
64 Sub,
65 Mul,
66 Screen,
67 Overlay,
68}
69
70#[derive(Debug, Clone, Copy, PartialEq)]
71pub struct SpriteRuntimeLight {
72 pub id: i32,
73 pub kind: i32,
74 pub diffuse: [f32; 4],
75 pub ambient: [f32; 4],
76 pub specular: [f32; 4],
77 pub pos: [f32; 4],
78 pub dir: [f32; 4],
79 pub atten: [f32; 4],
80 pub cone: [f32; 4],
81}
82
83impl Default for SpriteRuntimeLight {
84 fn default() -> Self {
85 Self {
86 id: -1,
87 kind: -1,
88 diffuse: [0.0, 0.0, 0.0, 1.0],
89 ambient: [0.0, 0.0, 0.0, 1.0],
90 specular: [0.0, 0.0, 0.0, 1.0],
91 pos: [0.0, 0.0, 0.0, 1.0],
92 dir: [0.0, 0.0, -1.0, 0.0],
93 atten: [1.0, 0.0, 0.0, 5000.0],
94 cone: [0.0, 0.0, 1.0, 0.0],
95 }
96 }
97}
98impl SpriteBlend {
99 pub fn from_i64(v: i64) -> Self {
100 match v.clamp(0, 4) {
104 1 => SpriteBlend::Add,
105 2 => SpriteBlend::Sub,
106 3 => SpriteBlend::Mul,
107 4 => SpriteBlend::Screen,
108 _ => SpriteBlend::Normal,
109 }
110 }
111}
112
113#[derive(Debug, Clone)]
114pub struct Sprite {
115 pub image_id: Option<ImageHandle>,
116 pub emote_render: Option<std::sync::Arc<crate::emote::EmoteRenderPacket>>,
119 pub mask_image_id: Option<ImageHandle>,
120 pub mask_offset_x: i32,
121 pub mask_offset_y: i32,
122 pub tonecurve_image_id: Option<ImageHandle>,
123 pub tonecurve_row: f32,
124 pub tonecurve_sat: f32,
125 pub fit: SpriteFit,
126 pub size_mode: SpriteSizeMode,
127 pub visible: bool,
128 pub alpha: u8,
129 pub x: i32,
130 pub y: i32,
131 pub z: f32,
132 pub scale_x: f32,
133 pub scale_y: f32,
134 pub scale_z: f32,
135 pub rotate: f32,
136 pub rotate_x: f32,
137 pub rotate_y: f32,
138 pub pivot_x: f32,
139 pub pivot_y: f32,
140 pub pivot_z: f32,
141 pub object_anchor: bool,
146 pub texture_center_x: f32,
147 pub texture_center_y: f32,
148 pub camera_enabled: bool,
149 pub camera_eye: [f32; 3],
150 pub camera_target: [f32; 3],
151 pub camera_up: [f32; 3],
152 pub camera_view_angle_deg: f32,
153 pub culling: bool,
154 pub alpha_test: bool,
155 pub alpha_blend: bool,
156 pub fog_use: bool,
157 pub light_no: i32,
158 pub light_enabled: bool,
159 pub light_diffuse: [f32; 4],
160 pub light_ambient: [f32; 4],
161 pub light_specular: [f32; 4],
162 pub light_factor: f32,
163 pub light_kind: i32,
164 pub light_pos: [f32; 4],
165 pub light_dir: [f32; 4],
166 pub light_atten: [f32; 4],
167 pub light_cone: [f32; 4],
168 pub mesh_runtime_lights: Vec<SpriteRuntimeLight>,
169 pub fog_enabled: bool,
170 pub fog_color: [f32; 4],
171 pub fog_near: f32,
172 pub fog_far: f32,
173 pub fog_scroll_x: f32,
174 pub fog_texture_image_id: Option<ImageHandle>,
175 pub world_no: i32,
176 pub billboard: bool,
177 pub mesh_file_name: Option<String>,
178 pub mesh_animation: crate::mesh3d::MeshAnimationState,
179 pub mesh_kind: u8,
181 pub shadow_cast: bool,
182 pub shadow_receive: bool,
183 pub wipe_fx_mode: u8,
188 pub wipe_fx_params: [f32; 4],
189 pub wipe_src_image_id: Option<ImageHandle>,
191 pub tr: u8,
192 pub mono: u8,
193 pub reverse: u8,
194 pub bright: u8,
195 pub dark: u8,
196 pub color_rate: u8,
197 pub color_add_r: u8,
198 pub color_add_g: u8,
199 pub color_add_b: u8,
200 pub color_r: u8,
201 pub color_g: u8,
202 pub color_b: u8,
203 pub mask_mode: u8,
205 pub blend: SpriteBlend,
206 pub dst_clip: Option<ClipRect>,
207 pub src_clip: Option<ClipRect>,
208 pub order: i32,
210}
211
212impl Default for Sprite {
213 fn default() -> Self {
214 Self {
215 image_id: None,
216 emote_render: None,
217 mask_image_id: None,
218 mask_offset_x: 0,
219 mask_offset_y: 0,
220 tonecurve_image_id: None,
221 tonecurve_row: 0.0,
222 tonecurve_sat: 0.0,
223 fit: SpriteFit::PixelRect,
224 size_mode: SpriteSizeMode::Intrinsic,
225 visible: false,
226 alpha: 255,
227 x: 0,
228 y: 0,
229 z: 0.0,
230 scale_x: 1.0,
231 scale_y: 1.0,
232 scale_z: 1.0,
233 rotate: 0.0,
234 rotate_x: 0.0,
235 rotate_y: 0.0,
236 pivot_x: 0.0,
237 pivot_y: 0.0,
238 pivot_z: 0.0,
239 object_anchor: false,
240 texture_center_x: 0.0,
241 texture_center_y: 0.0,
242 camera_enabled: false,
243 camera_eye: [0.0, 0.0, -1000.0],
244 camera_target: [0.0, 0.0, 0.0],
245 camera_up: [0.0, 1.0, 0.0],
246 camera_view_angle_deg: 45.0,
247 culling: false,
248 alpha_test: false,
249 alpha_blend: true,
250 fog_use: false,
251 light_no: -1,
252 light_enabled: false,
253 light_diffuse: [1.0, 1.0, 1.0, 1.0],
254 light_ambient: [0.0, 0.0, 0.0, 1.0],
255 light_specular: [0.0, 0.0, 0.0, 1.0],
256 light_factor: 0.0,
257 light_kind: -1,
258 light_pos: [0.0, 0.0, 0.0, 0.0],
259 light_dir: [0.0, 0.0, -1.0, 0.0],
260 light_atten: [1.0, 0.0, 0.0, 5000.0],
261 light_cone: [0.0, 0.0, 1.0, 0.0],
262 mesh_runtime_lights: Vec::new(),
263 fog_enabled: false,
264 fog_color: [0.0, 0.0, 0.0, 1.0],
265 fog_near: 0.0,
266 fog_far: 0.0,
267 fog_scroll_x: 0.0,
268 fog_texture_image_id: None,
269 world_no: -1,
270 billboard: false,
271 mesh_file_name: None,
272 mesh_animation: crate::mesh3d::MeshAnimationState::default(),
273 mesh_kind: 0,
274 shadow_cast: false,
275 shadow_receive: false,
276 wipe_fx_mode: 0,
277 wipe_fx_params: [0.0; 4],
278 wipe_src_image_id: None,
279 tr: 255,
280 mono: 0,
281 reverse: 0,
282 bright: 0,
283 dark: 0,
284 color_rate: 0,
285 color_add_r: 0,
286 color_add_g: 0,
287 color_add_b: 0,
288 color_r: 0,
289 color_g: 0,
290 color_b: 0,
291 mask_mode: 0,
292 blend: SpriteBlend::Normal,
293 dst_clip: None,
294 src_clip: None,
295 order: 0,
296 }
297 }
298}
299
300#[derive(Debug, Clone)]
301pub struct Layer {
302 sprites: Vec<Sprite>,
303}
304
305impl Default for Layer {
306 fn default() -> Self {
307 Self::new()
308 }
309}
310
311impl Layer {
312 pub fn new() -> Self {
313 Self {
314 sprites: Vec::new(),
315 }
316 }
317
318 pub fn create_sprite(&mut self) -> SpriteId {
319 let id = self.sprites.len();
320 self.sprites.push(Sprite::default());
321 id
322 }
323
324 pub fn sprite(&self, id: SpriteId) -> Option<&Sprite> {
325 self.sprites.get(id)
326 }
327
328 pub fn sprite_mut(&mut self, id: SpriteId) -> Option<&mut Sprite> {
329 self.sprites.get_mut(id)
330 }
331
332 pub fn clear_all_sprites(&mut self) {
333 for s in &mut self.sprites {
335 s.image_id = None;
336 s.emote_render = None;
337 s.mask_image_id = None;
338 s.mask_offset_x = 0;
339 s.mask_offset_y = 0;
340 s.tonecurve_image_id = None;
341 s.tonecurve_row = 0.0;
342 s.tonecurve_sat = 0.0;
343 s.visible = false;
344 s.alpha = 255;
345 s.x = 0;
346 s.y = 0;
347 s.z = 0.0;
348 s.order = 0;
349 s.fit = SpriteFit::PixelRect;
350 s.size_mode = SpriteSizeMode::Intrinsic;
351 s.scale_x = 1.0;
352 s.scale_y = 1.0;
353 s.scale_z = 1.0;
354 s.rotate = 0.0;
355 s.rotate_x = 0.0;
356 s.rotate_y = 0.0;
357 s.pivot_x = 0.0;
358 s.pivot_y = 0.0;
359 s.pivot_z = 0.0;
360 s.camera_enabled = false;
361 s.camera_eye = [0.0, 0.0, -1000.0];
362 s.camera_target = [0.0, 0.0, 0.0];
363 s.camera_up = [0.0, 1.0, 0.0];
364 s.camera_view_angle_deg = 45.0;
365 s.culling = false;
366 s.alpha_test = false;
367 s.alpha_blend = true;
368 s.fog_use = false;
369 s.light_no = -1;
370 s.light_enabled = false;
371 s.light_diffuse = [1.0, 1.0, 1.0, 1.0];
372 s.light_ambient = [0.0, 0.0, 0.0, 1.0];
373 s.light_specular = [0.0, 0.0, 0.0, 1.0];
374 s.light_factor = 0.0;
375 s.light_kind = -1;
376 s.light_pos = [0.0, 0.0, 0.0, 0.0];
377 s.light_dir = [0.0, 0.0, -1.0, 0.0];
378 s.light_atten = [1.0, 0.0, 0.0, 5000.0];
379 s.light_cone = [0.0, 0.0, 1.0, 0.0];
380 s.mesh_runtime_lights.clear();
381 s.fog_enabled = false;
382 s.fog_color = [0.0, 0.0, 0.0, 1.0];
383 s.fog_near = 0.0;
384 s.fog_far = 0.0;
385 s.fog_scroll_x = 0.0;
386 s.fog_texture_image_id = None;
387 s.world_no = -1;
388 s.billboard = false;
389 s.mesh_kind = 0;
390 s.mesh_file_name = None;
391 s.mesh_animation = crate::mesh3d::MeshAnimationState::default();
392 s.shadow_cast = false;
393 s.shadow_receive = false;
394 s.wipe_fx_mode = 0;
395 s.wipe_fx_params = [0.0; 4];
396 s.wipe_src_image_id = None;
397 s.tr = 255;
398 s.mono = 0;
399 s.reverse = 0;
400 s.bright = 0;
401 s.dark = 0;
402 s.color_rate = 0;
403 s.color_add_r = 0;
404 s.color_add_g = 0;
405 s.color_add_b = 0;
406 s.color_r = 0;
407 s.color_g = 0;
408 s.color_b = 0;
409 s.blend = SpriteBlend::Normal;
410 s.dst_clip = None;
411 s.src_clip = None;
412 }
413 }
414
415 fn sprite_ids_sorted(&self) -> Vec<SpriteId> {
416 let mut ids: Vec<SpriteId> = (0..self.sprites.len()).collect();
417 ids.sort_by(|&a, &b| {
418 let oa = self.sprites[a].order;
419 let ob = self.sprites[b].order;
420 oa.cmp(&ob).then(a.cmp(&b))
421 });
422 ids
423 }
424}
425
426#[derive(Debug, Clone, Default)]
427pub struct RenderFrame {
428 pub sprites: Vec<RenderSprite>,
430 pub wipe: Option<WipeRenderPlan>,
432}
433
434impl RenderFrame {
435 pub fn ordinary(sprites: Vec<RenderSprite>) -> Self {
436 Self {
437 sprites,
438 wipe: None,
439 }
440 }
441
442 pub fn submitted_sprite_count(&self) -> usize {
443 self.wipe.as_ref().map_or(self.sprites.len(), |wipe| {
444 wipe.under.len() + wipe.current.len() + wipe.next.len() + wipe.over.len()
445 })
446 }
447
448 pub fn debug_flatten(&self) -> Vec<RenderSprite> {
450 if let Some(wipe) = self.wipe.as_ref() {
451 let mut out = Vec::with_capacity(self.submitted_sprite_count());
452 out.extend(wipe.under.iter().cloned());
453 out.extend(wipe.current.iter().cloned());
454 out.extend(wipe.next.iter().cloned());
455 out.extend(wipe.over.iter().cloned());
456 out
457 } else {
458 self.sprites.clone()
459 }
460 }
461}
462
463#[derive(Debug, Clone)]
464pub struct WipeRenderPlan {
465 pub under: Vec<RenderSprite>,
466 pub current: Vec<RenderSprite>,
467 pub next: Vec<RenderSprite>,
468 pub over: Vec<RenderSprite>,
469 pub wipe_type: i32,
470 pub option: Vec<i32>,
471 pub progress: f32,
472 pub mask_image_id: Option<ImageHandle>,
473 pub random_seed: u32,
475}
476
477#[derive(Debug, Clone)]
478pub struct RenderSprite {
479 pub layer_id: Option<LayerId>,
480 pub sprite_id: Option<SpriteId>,
481 pub sorter_order: i32,
486 pub sorter_layer: i32,
489 pub wipe_sorter_order: i32,
494 pub wipe_sorter_layer: i32,
495 pub stage_form_id: Option<u32>,
499 pub sprite: Sprite,
500}
501
502impl RenderSprite {
503 pub fn new(layer_id: Option<LayerId>, sprite_id: Option<SpriteId>, sprite: Sprite) -> Self {
504 let (sorter_order, sorter_layer) = unpack_sprite_order(sprite.order);
505 Self {
506 layer_id,
507 sprite_id,
508 sorter_order,
509 sorter_layer,
510 wipe_sorter_order: sorter_order,
511 wipe_sorter_layer: sorter_layer,
512 stage_form_id: None,
513 sprite,
514 }
515 }
516
517 pub fn with_sorter(
518 layer_id: Option<LayerId>,
519 sprite_id: Option<SpriteId>,
520 sorter_order: i32,
521 sorter_layer: i32,
522 sprite: Sprite,
523 ) -> Self {
524 Self {
525 layer_id,
526 sprite_id,
527 sorter_order,
528 sorter_layer,
529 wipe_sorter_order: sorter_order,
530 wipe_sorter_layer: sorter_layer,
531 stage_form_id: None,
532 sprite,
533 }
534 }
535
536 pub fn set_sorter(&mut self, order: i64, layer: i64) {
537 self.sorter_order = order.clamp(i32::MIN as i64, i32::MAX as i64) as i32;
538 self.sorter_layer = layer.clamp(i32::MIN as i64, i32::MAX as i64) as i32;
539 self.wipe_sorter_order = self.sorter_order;
540 self.wipe_sorter_layer = self.sorter_layer;
541 }
542
543 pub fn set_wipe_sorter(&mut self, order: i64, layer: i64) {
544 self.wipe_sorter_order = order.clamp(i32::MIN as i64, i32::MAX as i64) as i32;
545 self.wipe_sorter_layer = layer.clamp(i32::MIN as i64, i32::MAX as i64) as i32;
546 }
547
548 pub fn set_stage_form_owner(&mut self, form_id: u32) {
549 self.stage_form_id = Some(form_id);
550 }
551}
552
553fn unpack_sprite_order(order: i32) -> (i32, i32) {
554 if order.abs() >= 1024 {
555 (order.div_euclid(1024), order.rem_euclid(1024))
556 } else {
557 (0, order)
558 }
559}
560
561#[derive(Debug, Default)]
562pub struct LayerManager {
563 bg: Sprite,
564 layers: Vec<Layer>,
565}
566
567impl LayerManager {
568 pub fn new() -> Self {
569 Self::default()
570 }
571
572 pub fn bg_mut(&mut self) -> &mut Sprite {
573 &mut self.bg
574 }
575
576 pub fn set_bg_image(&mut self, image_id: ImageHandle) {
577 self.bg.image_id = Some(image_id);
578 self.bg.mask_image_id = None;
579 self.bg.mask_offset_x = 0;
580 self.bg.mask_offset_y = 0;
581 self.bg.tonecurve_image_id = None;
582 self.bg.tonecurve_row = 0.0;
583 self.bg.tonecurve_sat = 0.0;
584 self.bg.wipe_fx_mode = 0;
585 self.bg.wipe_fx_params = [0.0; 4];
586 self.bg.wipe_src_image_id = None;
587 self.bg.fit = SpriteFit::FullScreen;
588 self.bg.size_mode = SpriteSizeMode::Intrinsic;
589 self.bg.visible = true;
590 self.bg.order = i32::MIN;
591 self.bg.scale_x = 1.0;
592 self.bg.scale_y = 1.0;
593 self.bg.scale_z = 1.0;
594 self.bg.rotate = 0.0;
595 self.bg.rotate_x = 0.0;
596 self.bg.rotate_y = 0.0;
597 self.bg.pivot_x = 0.0;
598 self.bg.pivot_y = 0.0;
599 self.bg.pivot_z = 0.0;
600 self.bg.z = 0.0;
601 self.bg.camera_enabled = false;
602 self.bg.camera_eye = [0.0, 0.0, -1000.0];
603 self.bg.camera_target = [0.0, 0.0, 0.0];
604 self.bg.camera_up = [0.0, 1.0, 0.0];
605 self.bg.camera_view_angle_deg = 45.0;
606 self.bg.culling = false;
607 self.bg.alpha_test = false;
608 self.bg.alpha_blend = true;
609 self.bg.fog_use = false;
610 self.bg.light_no = -1;
611 self.bg.light_enabled = false;
612 self.bg.light_diffuse = [1.0, 1.0, 1.0, 1.0];
613 self.bg.light_ambient = [0.0, 0.0, 0.0, 1.0];
614 self.bg.light_specular = [0.0, 0.0, 0.0, 1.0];
615 self.bg.light_factor = 0.0;
616 self.bg.light_kind = -1;
617 self.bg.light_pos = [0.0, 0.0, 0.0, 0.0];
618 self.bg.light_dir = [0.0, 0.0, -1.0, 0.0];
619 self.bg.light_atten = [1.0, 0.0, 0.0, 5000.0];
620 self.bg.light_cone = [0.0, 0.0, 1.0, 0.0];
621 self.bg.mesh_runtime_lights.clear();
622 self.bg.fog_enabled = false;
623 self.bg.fog_color = [0.0, 0.0, 0.0, 1.0];
624 self.bg.fog_near = 0.0;
625 self.bg.fog_far = 0.0;
626 self.bg.fog_scroll_x = 0.0;
627 self.bg.fog_texture_image_id = None;
628 self.bg.world_no = -1;
629 self.bg.billboard = false;
630 self.bg.mesh_kind = 0;
631 self.bg.mesh_file_name = None;
632 self.bg.mesh_animation = crate::mesh3d::MeshAnimationState::default();
633 self.bg.shadow_cast = false;
634 self.bg.shadow_receive = false;
635 self.bg.wipe_fx_mode = 0;
636 self.bg.wipe_fx_params = [0.0; 4];
637 self.bg.wipe_src_image_id = None;
638 self.bg.tr = 255;
639 self.bg.mono = 0;
640 self.bg.reverse = 0;
641 self.bg.bright = 0;
642 self.bg.dark = 0;
643 self.bg.color_rate = 0;
644 self.bg.color_add_r = 0;
645 self.bg.color_add_g = 0;
646 self.bg.color_add_b = 0;
647 self.bg.color_r = 0;
648 self.bg.color_g = 0;
649 self.bg.color_b = 0;
650 self.bg.mask_mode = 0;
651 self.bg.blend = SpriteBlend::Normal;
652 self.bg.dst_clip = None;
653 self.bg.src_clip = None;
654 }
655
656 pub fn clear_bg(&mut self) {
657 self.bg.image_id = None;
658 self.bg.mask_image_id = None;
659 self.bg.mask_offset_x = 0;
660 self.bg.mask_offset_y = 0;
661 self.bg.tonecurve_image_id = None;
662 self.bg.tonecurve_row = 0.0;
663 self.bg.tonecurve_sat = 0.0;
664 self.bg.wipe_fx_mode = 0;
665 self.bg.wipe_fx_params = [0.0; 4];
666 self.bg.wipe_src_image_id = None;
667 self.bg.light_enabled = false;
668 self.bg.light_diffuse = [1.0, 1.0, 1.0, 1.0];
669 self.bg.light_ambient = [0.0, 0.0, 0.0, 1.0];
670 self.bg.light_specular = [0.0, 0.0, 0.0, 1.0];
671 self.bg.light_factor = 0.0;
672 self.bg.light_kind = -1;
673 self.bg.light_pos = [0.0, 0.0, 0.0, 0.0];
674 self.bg.light_dir = [0.0, 0.0, -1.0, 0.0];
675 self.bg.light_atten = [1.0, 0.0, 0.0, 5000.0];
676 self.bg.light_cone = [0.0, 0.0, 1.0, 0.0];
677 self.bg.mesh_runtime_lights.clear();
678 self.bg.fog_enabled = false;
679 self.bg.fog_color = [0.0, 0.0, 0.0, 1.0];
680 self.bg.fog_near = 0.0;
681 self.bg.fog_far = 0.0;
682 self.bg.fog_scroll_x = 0.0;
683 self.bg.fog_texture_image_id = None;
684 self.bg.mesh_kind = 0;
685 self.bg.mesh_file_name = None;
686 self.bg.mesh_animation = crate::mesh3d::MeshAnimationState::default();
687 self.bg.shadow_cast = false;
688 self.bg.shadow_receive = false;
689 self.bg.visible = false;
690 }
691
692 pub fn create_layer(&mut self) -> LayerId {
693 let id = self.layers.len();
694 self.layers.push(Layer::new());
695 id
696 }
697
698 pub fn layer(&self, id: LayerId) -> Option<&Layer> {
699 self.layers.get(id)
700 }
701
702 pub fn layer_mut(&mut self, id: LayerId) -> Option<&mut Layer> {
703 self.layers.get_mut(id)
704 }
705
706 pub fn clear_layer(&mut self, id: LayerId) {
707 if let Some(layer) = self.layers.get_mut(id) {
708 layer.clear_all_sprites();
709 }
710 }
711
712 pub fn clear_all(&mut self) {
713 self.clear_bg();
714 for layer in &mut self.layers {
715 layer.clear_all_sprites();
716 }
717 }
718
719 pub fn reset_runtime_effects(&mut self) {
720 self.bg.mask_image_id = None;
721 self.bg.mask_offset_x = 0;
722 self.bg.mask_offset_y = 0;
723 self.bg.tonecurve_image_id = None;
724 self.bg.tonecurve_row = 0.0;
725 self.bg.tonecurve_sat = 0.0;
726 self.bg.wipe_fx_mode = 0;
727 self.bg.wipe_fx_params = [0.0; 4];
728 self.bg.wipe_src_image_id = None;
729 self.bg.light_enabled = false;
730 self.bg.light_diffuse = [1.0, 1.0, 1.0, 1.0];
731 self.bg.light_ambient = [0.0, 0.0, 0.0, 1.0];
732 self.bg.light_specular = [0.0, 0.0, 0.0, 1.0];
733 self.bg.light_factor = 0.0;
734 self.bg.light_kind = -1;
735 self.bg.light_pos = [0.0, 0.0, 0.0, 0.0];
736 self.bg.light_dir = [0.0, 0.0, -1.0, 0.0];
737 self.bg.light_atten = [1.0, 0.0, 0.0, 5000.0];
738 self.bg.light_cone = [0.0, 0.0, 1.0, 0.0];
739 self.bg.mesh_runtime_lights.clear();
740 self.bg.fog_enabled = false;
741 self.bg.fog_color = [0.0, 0.0, 0.0, 1.0];
742 self.bg.fog_near = 0.0;
743 self.bg.fog_far = 0.0;
744 self.bg.fog_scroll_x = 0.0;
745 self.bg.fog_texture_image_id = None;
746 for layer in &mut self.layers {
747 for s in &mut layer.sprites {
748 s.mask_image_id = None;
749 s.mask_offset_x = 0;
750 s.mask_offset_y = 0;
751 s.tonecurve_image_id = None;
752 s.tonecurve_row = 0.0;
753 s.tonecurve_sat = 0.0;
754 s.wipe_fx_mode = 0;
755 s.wipe_fx_params = [0.0; 4];
756 s.wipe_src_image_id = None;
757 s.light_enabled = false;
758 s.light_diffuse = [1.0, 1.0, 1.0, 1.0];
759 s.light_ambient = [0.0, 0.0, 0.0, 1.0];
760 s.light_factor = 0.0;
761 s.fog_enabled = false;
762 s.fog_color = [0.0, 0.0, 0.0, 1.0];
763 s.fog_near = 0.0;
764 s.fog_far = 0.0;
765 s.fog_scroll_x = 0.0;
766 s.fog_texture_image_id = None;
767 }
768 }
769 }
770
771 pub fn render_list(&self) -> Vec<RenderSprite> {
772 self.render_list_excluding(|_, _| false)
773 }
774
775 pub fn render_list_excluding<F>(&self, mut exclude: F) -> Vec<RenderSprite>
780 where
781 F: FnMut(LayerId, SpriteId) -> bool,
782 {
783 let mut out = Vec::new();
784
785 if self.bg.visible
786 && self.bg.alpha > 0
787 && self.bg.tr > 0
788 && let Some(ref img) = self.bg.image_id
789 {
790 let mut bg = self.bg.clone();
791 bg.image_id = Some(img.clone());
792 out.push(RenderSprite::new(None, None, bg));
793 }
794
795 for (layer_id, layer) in self.layers.iter().enumerate() {
796 for sprite_id in layer.sprite_ids_sorted() {
797 if exclude(layer_id, sprite_id) {
798 continue;
799 }
800 let s = &layer.sprites[sprite_id];
801 if !s.visible {
802 continue;
803 }
804 if s.image_id.is_none() || s.alpha == 0 || s.tr == 0 {
805 continue;
806 }
807 out.push(RenderSprite::new(
808 Some(layer_id),
809 Some(sprite_id),
810 s.clone(),
811 ));
812 }
813 }
814
815 out
816 }
817}