1use anyhow::{Context, Result, bail};
7use std::collections::HashMap;
8
9use crate::image_manager::{ImageHandle, ImageManager};
10use crate::layer::{
11 ClipRect, LayerId, LayerManager, Sprite, SpriteBlend, SpriteFit, SpriteId, SpriteSizeMode,
12};
13
14fn sg_cgm_coord_trace_enabled() -> bool {
15 env_is_set!("SG_DEBUG")
16}
17
18macro_rules! sg_cgm_coord_trace {
21 ($($arg:tt)*) => {
22 if sg_cgm_coord_trace_enabled() {
23 eprintln!("[SG_DEBUG][CGM_COORD_TRACE][GFX] {}", format!($($arg)*));
24 }
25 };
26}
27
28fn cgm_file_interesting(file: Option<&str>) -> bool {
29 file.map(|name| name.to_ascii_lowercase().contains("cgm_"))
30 .unwrap_or(false)
31}
32
33#[derive(Debug, Clone)]
34struct ObjectState {
35 layer_id: Option<LayerId>,
37 sprite_id: Option<SpriteId>,
38
39 is_mesh: bool,
41 file: Option<String>,
42 patno: i64,
43 bound_file: Option<String>,
47 bound_patno: i64,
48 disp: bool,
49 x: i64,
50 y: i64,
51 layer_no: i64,
52 order: i64,
53 alpha: i64,
54 z: i64,
56 center_x: i64,
57 center_y: i64,
58 scale_x: i64,
59 scale_y: i64,
60 rotate_z: i64,
61 clip_use: i64,
62 clip_left: i64,
63 clip_top: i64,
64 clip_right: i64,
65 clip_bottom: i64,
66 src_clip_use: i64,
67 src_clip_left: i64,
68 src_clip_top: i64,
69 src_clip_right: i64,
70 src_clip_bottom: i64,
71 tr: i64,
72 mono: i64,
73 reverse: i64,
74 bright: i64,
75 dark: i64,
76 color_rate: i64,
77 color_add_r: i64,
78 color_add_g: i64,
79 color_add_b: i64,
80 color_r: i64,
81 color_g: i64,
82 color_b: i64,
83 blend: i64,
84 light_no: i64,
85 fog_use: i64,
86}
87
88impl Default for ObjectState {
89 fn default() -> Self {
90 Self {
91 layer_id: None,
92 sprite_id: None,
93 is_mesh: false,
94 file: None,
95 patno: 0,
96 bound_file: None,
97 bound_patno: -1,
98 disp: false,
99 x: 0,
100 y: 0,
101 layer_no: 0,
102 order: 0,
103 alpha: 255,
104 z: 0,
105 center_x: 0,
106 center_y: 0,
107 scale_x: 1000,
108 scale_y: 1000,
109 rotate_z: 0,
110 clip_use: 0,
111 clip_left: 0,
112 clip_top: 0,
113 clip_right: 0,
114 clip_bottom: 0,
115 src_clip_use: 0,
116 src_clip_left: 0,
117 src_clip_top: 0,
118 src_clip_right: 0,
119 src_clip_bottom: 0,
120 tr: 255,
121 mono: 0,
122 reverse: 0,
123 bright: 0,
124 dark: 0,
125 color_rate: 0,
126 color_add_r: 0,
127 color_add_g: 0,
128 color_add_b: 0,
129 color_r: 0,
130 color_g: 0,
131 color_b: 0,
132 blend: 0,
133 light_no: -1,
134 fog_use: 0,
135 }
136 }
137}
138
139#[derive(Debug, Clone)]
140pub struct DebugObjectSpriteBinding {
141 pub stage: usize,
142 pub obj_idx: usize,
143 pub is_bg: bool,
144 pub layer_id: Option<LayerId>,
145 pub sprite_id: Option<SpriteId>,
146 pub file: Option<String>,
147 pub patno: i64,
148 pub disp: bool,
149 pub x: i64,
150 pub y: i64,
151 pub layer_no: i64,
152 pub order: i64,
153 pub alpha: i64,
154 pub z: i64,
155 pub tr: i64,
156 pub clip_use: i64,
157 pub clip_left: i64,
158 pub clip_top: i64,
159 pub clip_right: i64,
160 pub clip_bottom: i64,
161 pub scale_x: i64,
162 pub scale_y: i64,
163 pub rotate_z: i64,
164}
165
166#[derive(Debug, Clone, Default)]
167struct StageState {
168 layer_id: Option<LayerId>,
169 objects: HashMap<usize, ObjectState>,
170}
171
172#[derive(Debug, Default)]
173pub struct GfxRuntime {
174 pub current_layer: i32,
177 stages: [StageState; 3],
178}
179
180impl GfxRuntime {
181 pub fn new() -> Self {
182 Self::default()
183 }
184
185 fn ensure_stage(&mut self, stage: usize) -> &mut StageState {
186 &mut self.stages[stage]
187 }
188
189 fn ensure_stage_layer(&mut self, layers: &mut LayerManager, stage: usize) -> LayerId {
190 let st = self.ensure_stage(stage);
191 if let Some(id) = st.layer_id {
192 return id;
193 }
194 let id = layers.create_layer();
195 st.layer_id = Some(id);
196 id
197 }
198
199 pub fn ensure_stage_layer_id(
201 &mut self,
202 layers: &mut LayerManager,
203 stage: i64,
204 ) -> Option<LayerId> {
205 if !(0..=2).contains(&stage) {
206 return None;
207 }
208 Some(self.ensure_stage_layer(layers, stage as usize))
209 }
210
211 fn ensure_object_mut(&mut self, stage: usize, obj_idx: usize) -> &mut ObjectState {
212 self.ensure_stage(stage).objects.entry(obj_idx).or_default()
213 }
214
215 fn object(&self, stage: usize, obj_idx: usize) -> Option<&ObjectState> {
216 self.stages.get(stage)?.objects.get(&obj_idx)
217 }
218
219 fn reset_object_for_create(&mut self, layers: &mut LayerManager, stage: usize, obj_idx: usize) {
220 let (layer_id, sprite_id) = {
221 let obj = self.ensure_object_mut(stage, obj_idx);
222 (obj.layer_id, obj.sprite_id)
223 };
224
225 {
226 let obj = self.ensure_object_mut(stage, obj_idx);
227 *obj = ObjectState::default();
228 obj.layer_id = layer_id;
229 obj.sprite_id = sprite_id;
230 }
231
232 if let (Some(lid), Some(sid)) = (layer_id, sprite_id)
233 && let Some(sprite) = layers
234 .layer_mut(lid)
235 .and_then(|layer| layer.sprite_mut(sid))
236 {
237 *sprite = Sprite::default();
238 }
239 }
240
241 pub fn debug_object_snapshot(
242 &self,
243 stage: usize,
244 obj_idx: usize,
245 ) -> Option<DebugObjectSpriteBinding> {
246 let obj = self.object(stage, obj_idx)?;
247 Some(DebugObjectSpriteBinding {
248 stage,
249 obj_idx,
250 is_bg: false,
253 layer_id: obj.layer_id,
254 sprite_id: obj.sprite_id,
255 file: obj.file.clone(),
256 patno: obj.patno,
257 disp: obj.disp,
258 x: obj.x,
259 y: obj.y,
260 layer_no: obj.layer_no,
261 order: obj.order,
262 alpha: obj.alpha,
263 z: obj.z,
264 tr: obj.tr,
265 clip_use: obj.clip_use,
266 clip_left: obj.clip_left,
267 clip_top: obj.clip_top,
268 clip_right: obj.clip_right,
269 clip_bottom: obj.clip_bottom,
270 scale_x: obj.scale_x,
271 scale_y: obj.scale_y,
272 rotate_z: obj.rotate_z,
273 })
274 }
275
276 pub fn object_sprite_binding(&self, stage: i64, obj_idx: i64) -> Option<(LayerId, SpriteId)> {
277 let stage_i = stage as isize;
278 if !(0..3).contains(&stage_i) || obj_idx < 0 {
279 return None;
280 }
281 let obj = self.object(stage_i as usize, obj_idx as usize)?;
282 match (obj.layer_id, obj.sprite_id) {
283 (Some(lid), Some(sid)) => Some((lid, sid)),
284 _ => None,
285 }
286 }
287
288 pub fn has_missing_bound_object_image(&self, layers: &LayerManager) -> bool {
296 self.stages.iter().any(|stage| {
297 stage.objects.values().any(|obj| {
298 let Some(file) = obj.file.as_deref() else {
299 return false;
300 };
301 if obj.is_mesh || file.is_empty() {
302 return false;
303 }
304 let (Some(layer_id), Some(sprite_id)) = (obj.layer_id, obj.sprite_id) else {
305 return false;
306 };
307 layers
308 .layer(layer_id)
309 .and_then(|layer| layer.sprite(sprite_id))
310 .is_some_and(|sprite| sprite.image_id.is_none())
311 })
312 })
313 }
314
315 fn load_any_image(images: &mut ImageManager, file: &str, patno: i64) -> Result<ImageHandle> {
316 if file.contains('|') {
320 if patno != 0 {
321 bail!("composed g00 has one texture; invalid pattern {patno}");
322 }
323 return images
324 .load_g00_composed(file)
325 .with_context(|| format!("failed to load composed g00: {file}"));
326 }
327
328 let pat_u32 = if patno < 0 { 0 } else { patno as u32 };
330 match images.load_g00(file, pat_u32) {
331 Ok(id) => Ok(id),
332 Err(_) => images
333 .load_bg(file)
334 .with_context(|| format!("failed to load image as g00/bg: {file}")),
335 }
336 }
337
338 fn ensure_bound_sprite(
339 &mut self,
340 layers: &mut LayerManager,
341 stage: usize,
342 obj_idx: usize,
343 ) -> Result<(LayerId, SpriteId)> {
344 let st_layer = self.ensure_stage_layer(layers, stage);
345 let obj = self.ensure_object_mut(stage, obj_idx);
346
347 if let (Some(lid), Some(sid)) = (obj.layer_id, obj.sprite_id) {
348 return Ok((lid, sid));
349 }
350
351 let sid = {
352 let layer = layers
353 .layer_mut(st_layer)
354 .context("stage layer not found")?;
355 layer.create_sprite()
356 };
357
358 if let Some(layer) = layers.layer_mut(st_layer)
360 && let Some(sprite) = layer.sprite_mut(sid)
361 {
362 sprite.visible = true;
363 sprite.alpha = 255;
364 sprite.fit = SpriteFit::PixelRect;
365 sprite.size_mode = SpriteSizeMode::Intrinsic;
366 sprite.x = 0;
367 sprite.y = 0;
368 sprite.order = 0;
369 }
370
371 obj.layer_id = Some(st_layer);
372 obj.sprite_id = Some(sid);
373 Ok((st_layer, sid))
374 }
375
376 fn sync_object_sprite(
377 &mut self,
378 images: &mut ImageManager,
379 layers: &mut LayerManager,
380 stage: usize,
381 obj_idx: usize,
382 ) -> Result<()> {
383 self.ensure_object_mut(stage, obj_idx);
386 let (lid, sid) = self.ensure_bound_sprite(layers, stage, obj_idx)?;
387 let obj = self.object(stage, obj_idx).context("object not found")?;
388 let sprite = layers
389 .layer_mut(lid)
390 .and_then(|l| l.sprite_mut(sid))
391 .context("sprite not found")?;
392
393 sprite.visible = obj.disp;
394 sprite.x = obj.x as i32;
395 sprite.y = obj.y as i32;
396 sprite.alpha = obj.alpha.clamp(0, 255) as u8;
397 sprite.scale_x = obj.scale_x as f32 / 1000.0;
398 sprite.scale_y = obj.scale_y as f32 / 1000.0;
399 sprite.rotate = obj.rotate_z as f32 * std::f32::consts::PI / 1800.0;
400 sprite.pivot_x = obj.center_x as f32;
401 sprite.pivot_y = obj.center_y as f32;
402 sprite.dst_clip = clip_rect(
403 obj.clip_use,
404 obj.clip_left,
405 obj.clip_top,
406 obj.clip_right,
407 obj.clip_bottom,
408 );
409 sprite.src_clip = clip_rect(
410 obj.src_clip_use,
411 obj.src_clip_left,
412 obj.src_clip_top,
413 obj.src_clip_right,
414 obj.src_clip_bottom,
415 );
416 sprite.tr = obj.tr.clamp(0, 255) as u8;
417 sprite.mono = obj.mono.clamp(0, 255) as u8;
418 sprite.reverse = obj.reverse.clamp(0, 255) as u8;
419 sprite.bright = obj.bright.clamp(0, 255) as u8;
420 sprite.dark = obj.dark.clamp(0, 255) as u8;
421 sprite.color_rate = obj.color_rate.clamp(0, 255) as u8;
422 sprite.color_add_r = obj.color_add_r.clamp(0, 255) as u8;
423 sprite.color_add_g = obj.color_add_g.clamp(0, 255) as u8;
424 sprite.color_add_b = obj.color_add_b.clamp(0, 255) as u8;
425 sprite.color_r = obj.color_r.clamp(0, 255) as u8;
426 sprite.color_g = obj.color_g.clamp(0, 255) as u8;
427 sprite.color_b = obj.color_b.clamp(0, 255) as u8;
428 sprite.blend = SpriteBlend::from_i64(obj.blend);
429 sprite.light_no = obj.light_no as i32;
430 sprite.fog_use = obj.fog_use != 0;
431
432 let coarse = obj.layer_no.clamp(-10000, 10000) as i32;
434 let fine = obj.order.clamp(-100000, 100000) as i32;
435 sprite.order = coarse.saturating_mul(1000).saturating_add(fine);
436
437 if obj.is_mesh {
438 sprite.image_id = None;
439 sprite.mesh_file_name = obj.file.clone();
440 sprite.mesh_kind = 1;
441 sprite.camera_enabled = true;
442 sprite.shadow_cast = true;
443 sprite.shadow_receive = true;
444 sprite.object_anchor = false;
445 sprite.texture_center_x = 0.0;
446 sprite.texture_center_y = 0.0;
447 let (file, patno) = (obj.file.clone(), obj.patno);
448 let state = self.ensure_object_mut(stage, obj_idx);
449 state.bound_file = file;
450 state.bound_patno = patno;
451 return Ok(());
452 }
453
454 let Some(file) = obj.file.as_deref() else {
455 return Ok(());
456 };
457
458 let same_file = obj.bound_file.as_deref() == Some(file);
464 if same_file && obj.bound_patno == obj.patno && sprite.image_id.is_some() {
465 return Ok(());
466 }
467
468 let next_image = if same_file {
469 sprite.image_id.as_ref().and_then(|image| {
470 usize::try_from(obj.patno)
471 .ok()
472 .and_then(|cut| image.album_cut(cut))
473 })
474 } else {
475 None
476 };
477
478 let image_id = match next_image {
479 Some(image_id) => image_id,
480 None => match Self::load_any_image(images, file, obj.patno) {
481 Ok(image_id) => image_id,
482 Err(err) if is_probable_mesh_path(file) => {
483 let _ = err;
484 sprite.image_id = None;
485 sprite.object_anchor = false;
486 sprite.texture_center_x = 0.0;
487 sprite.texture_center_y = 0.0;
488 return Ok(());
489 }
490 Err(err) => return Err(err),
491 },
492 };
493 set_object_sprite_image(sprite, images, image_id);
494 let (file, patno) = (file.to_string(), obj.patno);
495 let state = self.ensure_object_mut(stage, obj_idx);
496 state.bound_file = Some(file);
497 state.bound_patno = patno;
498
499 Ok(())
500 }
501
502 pub fn object_set_center(
503 &mut self,
504 images: &mut ImageManager,
505 layers: &mut LayerManager,
506 stage: i64,
507 obj_idx: i64,
508 x: i64,
509 y: i64,
510 ) -> Result<()> {
511 let stage_i = stage as isize;
512 if !(0..3).contains(&stage_i) || obj_idx < 0 {
513 return Ok(());
514 }
515 let stage_u = stage_i as usize;
516 let obj_u = obj_idx as usize;
517 {
518 let obj = self.ensure_object_mut(stage_u, obj_u);
519 obj.center_x = x;
520 obj.center_y = y;
521 }
522 self.sync_object_sprite(images, layers, stage_u, obj_u)
523 }
524
525 pub fn object_set_scale(
526 &mut self,
527 images: &mut ImageManager,
528 layers: &mut LayerManager,
529 stage: i64,
530 obj_idx: i64,
531 x: i64,
532 y: i64,
533 ) -> Result<()> {
534 let stage_i = stage as isize;
535 if !(0..3).contains(&stage_i) || obj_idx < 0 {
536 return Ok(());
537 }
538 let stage_u = stage_i as usize;
539 let obj_u = obj_idx as usize;
540 {
541 let obj = self.ensure_object_mut(stage_u, obj_u);
542 obj.scale_x = x;
543 obj.scale_y = y;
544 }
545 self.sync_object_sprite(images, layers, stage_u, obj_u)
546 }
547
548 pub fn object_set_rotate(
549 &mut self,
550 images: &mut ImageManager,
551 layers: &mut LayerManager,
552 stage: i64,
553 obj_idx: i64,
554 z: i64,
555 ) -> Result<()> {
556 let stage_i = stage as isize;
557 if !(0..3).contains(&stage_i) || obj_idx < 0 {
558 return Ok(());
559 }
560 let stage_u = stage_i as usize;
561 let obj_u = obj_idx as usize;
562 {
563 let obj = self.ensure_object_mut(stage_u, obj_u);
564 obj.rotate_z = z;
565 }
566 self.sync_object_sprite(images, layers, stage_u, obj_u)
567 }
568
569 pub fn object_set_clip(
570 &mut self,
571 images: &mut ImageManager,
572 layers: &mut LayerManager,
573 stage: i64,
574 obj_idx: i64,
575 use_flag: i64,
576 left: i64,
577 top: i64,
578 right: i64,
579 bottom: i64,
580 ) -> Result<()> {
581 let stage_i = stage as isize;
582 if !(0..3).contains(&stage_i) || obj_idx < 0 {
583 return Ok(());
584 }
585 let stage_u = stage_i as usize;
586 let obj_u = obj_idx as usize;
587 {
588 let obj = self.ensure_object_mut(stage_u, obj_u);
589 obj.clip_use = use_flag;
590 obj.clip_left = left;
591 obj.clip_top = top;
592 obj.clip_right = right;
593 obj.clip_bottom = bottom;
594 }
595 self.sync_object_sprite(images, layers, stage_u, obj_u)
596 }
597
598 pub fn object_set_src_clip(
599 &mut self,
600 images: &mut ImageManager,
601 layers: &mut LayerManager,
602 stage: i64,
603 obj_idx: i64,
604 use_flag: i64,
605 left: i64,
606 top: i64,
607 right: i64,
608 bottom: i64,
609 ) -> Result<()> {
610 let stage_i = stage as isize;
611 if !(0..3).contains(&stage_i) || obj_idx < 0 {
612 return Ok(());
613 }
614 let stage_u = stage_i as usize;
615 let obj_u = obj_idx as usize;
616 {
617 let obj = self.ensure_object_mut(stage_u, obj_u);
618 obj.src_clip_use = use_flag;
619 obj.src_clip_left = left;
620 obj.src_clip_top = top;
621 obj.src_clip_right = right;
622 obj.src_clip_bottom = bottom;
623 }
624 self.sync_object_sprite(images, layers, stage_u, obj_u)
625 }
626
627 pub fn stage_clear(
628 &mut self,
629 images: &mut ImageManager,
630 layers: &mut LayerManager,
631 stage: i64,
632 ) -> Result<()> {
633 let stage_i = stage as isize;
634 if !(0..3).contains(&stage_i) {
635 return Ok(());
636 }
637 let stage_u = stage_i as usize;
638 let mut indices: Vec<usize> = self.stages[stage_u].objects.keys().copied().collect();
639 indices.sort_unstable();
640 for idx in indices {
641 {
642 let obj = self.ensure_object_mut(stage_u, idx);
643 obj.disp = false;
644 }
645 let _ = self.sync_object_sprite(images, layers, stage_u, idx);
646 }
647 Ok(())
648 }
649
650 fn object_create_impl(
651 &mut self,
652 images: &mut ImageManager,
653 layers: &mut LayerManager,
654 stage: i64,
655 obj_idx: i64,
656 file: &str,
657 disp: i64,
658 x: i64,
659 y: i64,
660 patno: i64,
661 reinit: bool,
662 ) -> Result<()> {
663 let stage_i = stage as isize;
664 if !(0..3).contains(&stage_i) {
665 bail!("invalid stage: {stage}");
666 }
667 if obj_idx < 0 {
668 bail!("invalid obj idx: {obj_idx}");
669 }
670
671 let stage_u = stage_i as usize;
672 let obj_u = obj_idx as usize;
673 let current_layer = self.current_layer;
674
675 if reinit {
676 self.reset_object_for_create(layers, stage_u, obj_u);
677 }
678
679 {
680 let obj = self.ensure_object_mut(stage_u, obj_u);
681 obj.is_mesh = false;
682 obj.file = Some(file.to_string());
683 obj.patno = patno;
684 obj.disp = disp != 0;
685 obj.x = x;
686 obj.y = y;
687
688 if obj.layer_no == 0 {
690 obj.layer_no = current_layer as i64;
691 }
692 }
693
694 let _ = self.ensure_bound_sprite(layers, stage_u, obj_u)?;
697
698 if cgm_file_interesting(Some(file)) || (30..=59).contains(&obj_u) {
699 let obj = self.object(stage_u, obj_u);
700 sg_cgm_coord_trace!(
701 "object_create stage={} obj={} file={} disp={} x={} y={} patno={} reinit={} layer_no={:?} binding={:?}/{:?}",
702 stage,
703 obj_idx,
704 file,
705 disp,
706 x,
707 y,
708 patno,
709 reinit,
710 obj.map(|o| o.layer_no),
711 obj.and_then(|o| o.layer_id),
712 obj.and_then(|o| o.sprite_id)
713 );
714 }
715
716 self.sync_object_sprite(images, layers, stage_u, obj_u)
717 }
718
719 pub fn object_create(
720 &mut self,
721 images: &mut ImageManager,
722 layers: &mut LayerManager,
723 stage: i64,
724 obj_idx: i64,
725 file: &str,
726 disp: i64,
727 x: i64,
728 y: i64,
729 patno: i64,
730 ) -> Result<()> {
731 self.object_create_impl(
732 images, layers, stage, obj_idx, file, disp, x, y, patno, true,
733 )
734 }
735
736 pub fn object_create_billboard(
737 &mut self,
738 images: &mut ImageManager,
739 layers: &mut LayerManager,
740 stage: i64,
741 obj_idx: i64,
742 file: &str,
743 disp: i64,
744 x: i64,
745 y: i64,
746 patno: i64,
747 ) -> Result<()> {
748 let result = self.object_create_impl(
749 images, layers, stage, obj_idx, file, disp, x, y, patno, true,
750 );
751 if let Some((lid, sid)) = self.object_sprite_binding(stage, obj_idx)
752 && let Some(sprite) = layers
753 .layer_mut(lid)
754 .and_then(|layer| layer.sprite_mut(sid))
755 {
756 sprite.billboard = true;
757 sprite.camera_enabled = true;
758 }
759 result
760 }
761
762 pub fn restore_gfx_object_from_globals(
774 &mut self,
775 images: &mut ImageManager,
776 layers: &mut LayerManager,
777 stage: i64,
778 obj_idx: i64,
779 src: &crate::runtime::globals::ObjectState,
780 ) -> Result<()> {
781 let stage_i = stage as isize;
782 if !(0..3).contains(&stage_i) || obj_idx < 0 {
783 return Ok(());
784 }
785 let file = match src.file_name.as_deref() {
786 Some(f) if !f.is_empty() => f.to_string(),
787 _ => return Ok(()),
788 };
789 let stage_u = stage_i as usize;
790 let obj_u = obj_idx as usize;
791
792 let current_layer = self.current_layer;
793 self.reset_object_for_create(layers, stage_u, obj_u);
794 {
795 let pe = &src.runtime.prop_events;
796 let dst = self.ensure_object_mut(stage_u, obj_u);
797 dst.is_mesh = false;
798 dst.file = Some(file);
799 dst.patno = src.base.patno;
800 dst.disp = src.base.disp != 0;
801 dst.x = pe.x.get_total_value() as i64;
802 dst.y = pe.y.get_total_value() as i64;
803 dst.z = pe.z.get_total_value() as i64;
804 dst.layer_no = src.base.layer;
805 dst.order = src.base.order;
806 dst.center_x = pe.center_x.get_total_value() as i64;
807 dst.center_y = pe.center_y.get_total_value() as i64;
808 dst.scale_x = pe.scale_x.get_total_value() as i64;
809 dst.scale_y = pe.scale_y.get_total_value() as i64;
810 dst.rotate_z = pe.rotate_z.get_total_value() as i64;
811 dst.clip_use = src.base.clip_use;
812 dst.clip_left = pe.clip_left.get_total_value() as i64;
813 dst.clip_top = pe.clip_top.get_total_value() as i64;
814 dst.clip_right = pe.clip_right.get_total_value() as i64;
815 dst.clip_bottom = pe.clip_bottom.get_total_value() as i64;
816 dst.src_clip_use = src.base.src_clip_use;
817 dst.src_clip_left = pe.src_clip_left.get_total_value() as i64;
818 dst.src_clip_top = pe.src_clip_top.get_total_value() as i64;
819 dst.src_clip_right = pe.src_clip_right.get_total_value() as i64;
820 dst.src_clip_bottom = pe.src_clip_bottom.get_total_value() as i64;
821 let tr = pe.tr.get_total_value() as i64;
822 dst.alpha = tr;
823 dst.tr = tr;
824 dst.mono = pe.mono.get_total_value() as i64;
825 dst.reverse = pe.reverse.get_total_value() as i64;
826 dst.bright = pe.bright.get_total_value() as i64;
827 dst.dark = pe.dark.get_total_value() as i64;
828 dst.color_rate = pe.color_rate.get_total_value() as i64;
829 dst.color_add_r = pe.color_add_r.get_total_value() as i64;
830 dst.color_add_g = pe.color_add_g.get_total_value() as i64;
831 dst.color_add_b = pe.color_add_b.get_total_value() as i64;
832 dst.color_r = pe.color_r.get_total_value() as i64;
833 dst.color_g = pe.color_g.get_total_value() as i64;
834 dst.color_b = pe.color_b.get_total_value() as i64;
835 dst.blend = src.base.blend;
836 dst.light_no = src.base.light_no;
837 dst.fog_use = src.base.fog_use;
838 if dst.layer_no == 0 {
839 dst.layer_no = current_layer as i64;
840 }
841 }
842
843 let _ = self.ensure_bound_sprite(layers, stage_u, obj_u)?;
844 self.sync_object_sprite(images, layers, stage_u, obj_u)
845 }
846
847 pub fn object_release_type_backing(
851 &mut self,
852 layers: &mut LayerManager,
853 stage: i64,
854 obj_idx: i64,
855 ) -> Result<()> {
856 let stage_i = stage as isize;
857 if !(0..3).contains(&stage_i) || obj_idx < 0 {
858 return Ok(());
859 }
860 let stage_u = stage_i as usize;
861 let obj_u = obj_idx as usize;
862 let (layer_id, sprite_id) = {
863 let obj = self.ensure_object_mut(stage_u, obj_u);
864 obj.file = None;
865 obj.is_mesh = false;
866 obj.bound_file = None;
867 obj.bound_patno = -1;
868 (obj.layer_id, obj.sprite_id)
869 };
870
871 if let (Some(lid), Some(sid)) = (layer_id, sprite_id)
872 && let Some(sprite) = layers
873 .layer_mut(lid)
874 .and_then(|layer| layer.sprite_mut(sid))
875 {
876 sprite.image_id = None;
877 sprite.mesh_file_name = None;
878 sprite.mesh_kind = 0;
879 sprite.billboard = false;
880 sprite.emote_render = None;
881 }
882 Ok(())
883 }
884
885 pub fn object_change_file(
886 &mut self,
887 images: &mut ImageManager,
888 layers: &mut LayerManager,
889 stage: i64,
890 obj_idx: i64,
891 file: &str,
892 disp: i64,
893 x: i64,
894 y: i64,
895 patno: i64,
896 ) -> Result<()> {
897 self.object_create_impl(
898 images, layers, stage, obj_idx, file, disp, x, y, patno, false,
899 )
900 }
901
902 pub fn object_create_mesh(
903 &mut self,
904 layers: &mut LayerManager,
905 stage: i64,
906 obj_idx: i64,
907 file: &str,
908 disp: i64,
909 x: i64,
910 y: i64,
911 patno: i64,
912 ) -> Result<()> {
913 let stage_i = stage as isize;
914 if !(0..3).contains(&stage_i) {
915 bail!("invalid stage: {stage}");
916 }
917 if obj_idx < 0 {
918 bail!("invalid obj idx: {obj_idx}");
919 }
920
921 let stage_u = stage_i as usize;
922 let obj_u = obj_idx as usize;
923 let current_layer = self.current_layer;
924
925 self.reset_object_for_create(layers, stage_u, obj_u);
926
927 {
928 let obj = self.ensure_object_mut(stage_u, obj_u);
929 obj.is_mesh = true;
930 obj.file = Some(file.to_string());
931 obj.patno = patno;
932 obj.disp = disp != 0;
933 obj.x = x;
934 obj.y = y;
935 if obj.layer_no == 0 {
936 obj.layer_no = current_layer as i64;
937 }
938 }
939
940 if cgm_file_interesting(Some(file)) || (30..=59).contains(&obj_u) {
941 sg_cgm_coord_trace!(
942 "object_create_mesh stage={} obj={} file={} disp={} x={} y={} patno={}",
943 stage,
944 obj_idx,
945 file,
946 disp,
947 x,
948 y,
949 patno
950 );
951 }
952
953 let (lid, sid) = self.ensure_bound_sprite(layers, stage_u, obj_u)?;
954 let sprite = layers
955 .layer_mut(lid)
956 .and_then(|l| l.sprite_mut(sid))
957 .context("mesh sprite not found")?;
958 sprite.visible = disp != 0;
959 sprite.image_id = None;
960 sprite.x = x as i32;
961 sprite.y = y as i32;
962 sprite.alpha = 255;
963 sprite.tr = 255;
964 sprite.fit = SpriteFit::PixelRect;
965 sprite.size_mode = SpriteSizeMode::Intrinsic;
966 sprite.mesh_file_name = Some(file.to_string());
967 sprite.mesh_kind = 1;
968 sprite.camera_enabled = true;
969 sprite.shadow_cast = true;
970 sprite.shadow_receive = true;
971
972 Ok(())
973 }
974
975 pub fn object_change_mesh_file(
978 &mut self,
979 layers: &mut LayerManager,
980 stage: i64,
981 obj_idx: i64,
982 file: &str,
983 disp: i64,
984 x: i64,
985 y: i64,
986 patno: i64,
987 ) -> Result<()> {
988 let stage_i = stage as isize;
989 if !(0..3).contains(&stage_i) {
990 bail!("invalid stage: {stage}");
991 }
992 if obj_idx < 0 {
993 bail!("invalid obj idx: {obj_idx}");
994 }
995 let stage_u = stage_i as usize;
996 let obj_u = obj_idx as usize;
997 let current_layer = self.current_layer;
998
999 {
1000 let obj = self.ensure_object_mut(stage_u, obj_u);
1001 obj.is_mesh = true;
1002 obj.file = Some(file.to_string());
1003 obj.patno = patno;
1004 obj.disp = disp != 0;
1005 obj.x = x;
1006 obj.y = y;
1007 if obj.layer_no == 0 {
1008 obj.layer_no = current_layer as i64;
1009 }
1010 }
1011
1012 let (lid, sid) = self.ensure_bound_sprite(layers, stage_u, obj_u)?;
1013 let sprite = layers
1014 .layer_mut(lid)
1015 .and_then(|l| l.sprite_mut(sid))
1016 .context("mesh sprite not found")?;
1017 sprite.visible = disp != 0;
1018 sprite.image_id = None;
1019 sprite.x = x as i32;
1020 sprite.y = y as i32;
1021 sprite.fit = SpriteFit::PixelRect;
1022 sprite.size_mode = SpriteSizeMode::Intrinsic;
1023 sprite.mesh_file_name = Some(file.to_string());
1024 sprite.mesh_kind = 1;
1025 sprite.billboard = false;
1026 sprite.camera_enabled = true;
1027 sprite.shadow_cast = true;
1028 sprite.shadow_receive = true;
1029 Ok(())
1030 }
1031
1032 pub fn object_set_disp(
1033 &mut self,
1034 images: &mut ImageManager,
1035 layers: &mut LayerManager,
1036 stage: i64,
1037 obj_idx: i64,
1038 disp: i64,
1039 ) -> Result<()> {
1040 let stage_i = stage as isize;
1041 if !(0..3).contains(&stage_i) || obj_idx < 0 {
1042 return Ok(());
1043 }
1044 let stage_u = stage_i as usize;
1045 let obj_u = obj_idx as usize;
1046 {
1047 let obj = self.ensure_object_mut(stage_u, obj_u);
1048 obj.disp = disp != 0;
1049 }
1050 self.sync_object_sprite(images, layers, stage_u, obj_u)
1051 }
1052
1053 pub fn object_set_pos(
1054 &mut self,
1055 images: &mut ImageManager,
1056 layers: &mut LayerManager,
1057 stage: i64,
1058 obj_idx: i64,
1059 x: i64,
1060 y: i64,
1061 ) -> Result<()> {
1062 let stage_i = stage as isize;
1063 if !(0..3).contains(&stage_i) || obj_idx < 0 {
1064 return Ok(());
1065 }
1066 let stage_u = stage_i as usize;
1067 let obj_u = obj_idx as usize;
1068 let current_layer = self.current_layer;
1069 {
1070 let obj = self.ensure_object_mut(stage_u, obj_u);
1071 obj.x = x;
1072 obj.y = y;
1073 if obj.layer_no == 0 {
1074 obj.layer_no = current_layer as i64;
1075 }
1076 }
1077 if let Some(obj) = self.object(stage_u, obj_u)
1078 && (cgm_file_interesting(obj.file.as_deref()) || (30..=59).contains(&obj_u))
1079 {
1080 sg_cgm_coord_trace!(
1081 "object_set_pos stage={} obj={} file={:?} x={} y={} layer_no={} binding={:?}/{:?}",
1082 stage,
1083 obj_idx,
1084 obj.file.as_deref(),
1085 x,
1086 y,
1087 obj.layer_no,
1088 obj.layer_id,
1089 obj.sprite_id
1090 );
1091 }
1092 self.sync_object_sprite(images, layers, stage_u, obj_u)
1093 }
1094
1095 pub fn object_set_x(
1096 &mut self,
1097 images: &mut ImageManager,
1098 layers: &mut LayerManager,
1099 stage: i64,
1100 obj_idx: i64,
1101 x: i64,
1102 ) -> Result<()> {
1103 let stage_i = stage as isize;
1104 if !(0..3).contains(&stage_i) || obj_idx < 0 {
1105 return Ok(());
1106 }
1107 let stage_u = stage_i as usize;
1108 let obj_u = obj_idx as usize;
1109 {
1110 let obj = self.ensure_object_mut(stage_u, obj_u);
1111 obj.x = x;
1112 }
1113 self.sync_object_sprite(images, layers, stage_u, obj_u)
1114 }
1115
1116 pub fn object_set_y(
1117 &mut self,
1118 images: &mut ImageManager,
1119 layers: &mut LayerManager,
1120 stage: i64,
1121 obj_idx: i64,
1122 y: i64,
1123 ) -> Result<()> {
1124 let stage_i = stage as isize;
1125 if !(0..3).contains(&stage_i) || obj_idx < 0 {
1126 return Ok(());
1127 }
1128 let stage_u = stage_i as usize;
1129 let obj_u = obj_idx as usize;
1130 {
1131 let obj = self.ensure_object_mut(stage_u, obj_u);
1132 obj.y = y;
1133 }
1134 self.sync_object_sprite(images, layers, stage_u, obj_u)
1135 }
1136
1137 pub fn object_set_patno(
1138 &mut self,
1139 images: &mut ImageManager,
1140 layers: &mut LayerManager,
1141 stage: i64,
1142 obj_idx: i64,
1143 patno: i64,
1144 ) -> Result<()> {
1145 let stage_i = stage as isize;
1146 if !(0..3).contains(&stage_i) || obj_idx < 0 {
1147 return Ok(());
1148 }
1149 let stage_u = stage_i as usize;
1150 let obj_u = obj_idx as usize;
1151 {
1152 let obj = self.ensure_object_mut(stage_u, obj_u);
1153 obj.patno = patno;
1154 }
1155 self.sync_object_sprite(images, layers, stage_u, obj_u)
1156 }
1157
1158 pub fn object_set_layer(
1159 &mut self,
1160 images: &mut ImageManager,
1161 layers: &mut LayerManager,
1162 stage: i64,
1163 obj_idx: i64,
1164 layer_no: i64,
1165 ) -> Result<()> {
1166 let stage_i = stage as isize;
1167 if !(0..3).contains(&stage_i) || obj_idx < 0 {
1168 return Ok(());
1169 }
1170 let stage_u = stage_i as usize;
1171 let obj_u = obj_idx as usize;
1172 {
1173 let obj = self.ensure_object_mut(stage_u, obj_u);
1174 obj.layer_no = layer_no;
1175 }
1176 self.sync_object_sprite(images, layers, stage_u, obj_u)
1177 }
1178
1179 pub fn object_set_order(
1180 &mut self,
1181 images: &mut ImageManager,
1182 layers: &mut LayerManager,
1183 stage: i64,
1184 obj_idx: i64,
1185 order: i64,
1186 ) -> Result<()> {
1187 let stage_i = stage as isize;
1188 if !(0..3).contains(&stage_i) || obj_idx < 0 {
1189 return Ok(());
1190 }
1191 let stage_u = stage_i as usize;
1192 let obj_u = obj_idx as usize;
1193 {
1194 let obj = self.ensure_object_mut(stage_u, obj_u);
1195 obj.order = order;
1196 }
1197 self.sync_object_sprite(images, layers, stage_u, obj_u)
1198 }
1199
1200 pub fn object_set_alpha(
1201 &mut self,
1202 images: &mut ImageManager,
1203 layers: &mut LayerManager,
1204 stage: i64,
1205 obj_idx: i64,
1206 alpha: i64,
1207 ) -> Result<()> {
1208 let stage_i = stage as isize;
1209 if !(0..3).contains(&stage_i) || obj_idx < 0 {
1210 return Ok(());
1211 }
1212 let stage_u = stage_i as usize;
1213 let obj_u = obj_idx as usize;
1214 {
1215 let obj = self.ensure_object_mut(stage_u, obj_u);
1216 obj.alpha = alpha;
1217 }
1218 self.sync_object_sprite(images, layers, stage_u, obj_u)
1219 }
1220
1221 pub fn object_set_tr(
1222 &mut self,
1223 images: &mut ImageManager,
1224 layers: &mut LayerManager,
1225 stage: i64,
1226 obj_idx: i64,
1227 tr: i64,
1228 ) -> Result<()> {
1229 let stage_i = stage as isize;
1230 if !(0..3).contains(&stage_i) || obj_idx < 0 {
1231 return Ok(());
1232 }
1233 let stage_u = stage_i as usize;
1234 let obj_u = obj_idx as usize;
1235 {
1236 let obj = self.ensure_object_mut(stage_u, obj_u);
1237 obj.tr = tr;
1238 }
1239 self.sync_object_sprite(images, layers, stage_u, obj_u)
1240 }
1241
1242 pub fn object_set_mono(
1243 &mut self,
1244 images: &mut ImageManager,
1245 layers: &mut LayerManager,
1246 stage: i64,
1247 obj_idx: i64,
1248 mono: i64,
1249 ) -> Result<()> {
1250 let stage_i = stage as isize;
1251 if !(0..3).contains(&stage_i) || obj_idx < 0 {
1252 return Ok(());
1253 }
1254 let stage_u = stage_i as usize;
1255 let obj_u = obj_idx as usize;
1256 {
1257 let obj = self.ensure_object_mut(stage_u, obj_u);
1258 obj.mono = mono;
1259 }
1260 self.sync_object_sprite(images, layers, stage_u, obj_u)
1261 }
1262
1263 pub fn object_set_reverse(
1264 &mut self,
1265 images: &mut ImageManager,
1266 layers: &mut LayerManager,
1267 stage: i64,
1268 obj_idx: i64,
1269 reverse: i64,
1270 ) -> Result<()> {
1271 let stage_i = stage as isize;
1272 if !(0..3).contains(&stage_i) || obj_idx < 0 {
1273 return Ok(());
1274 }
1275 let stage_u = stage_i as usize;
1276 let obj_u = obj_idx as usize;
1277 {
1278 let obj = self.ensure_object_mut(stage_u, obj_u);
1279 obj.reverse = reverse;
1280 }
1281 self.sync_object_sprite(images, layers, stage_u, obj_u)
1282 }
1283
1284 pub fn object_set_bright(
1285 &mut self,
1286 images: &mut ImageManager,
1287 layers: &mut LayerManager,
1288 stage: i64,
1289 obj_idx: i64,
1290 bright: i64,
1291 ) -> Result<()> {
1292 let stage_i = stage as isize;
1293 if !(0..3).contains(&stage_i) || obj_idx < 0 {
1294 return Ok(());
1295 }
1296 let stage_u = stage_i as usize;
1297 let obj_u = obj_idx as usize;
1298 {
1299 let obj = self.ensure_object_mut(stage_u, obj_u);
1300 obj.bright = bright;
1301 }
1302 self.sync_object_sprite(images, layers, stage_u, obj_u)
1303 }
1304
1305 pub fn object_set_dark(
1306 &mut self,
1307 images: &mut ImageManager,
1308 layers: &mut LayerManager,
1309 stage: i64,
1310 obj_idx: i64,
1311 dark: i64,
1312 ) -> Result<()> {
1313 let stage_i = stage as isize;
1314 if !(0..3).contains(&stage_i) || obj_idx < 0 {
1315 return Ok(());
1316 }
1317 let stage_u = stage_i as usize;
1318 let obj_u = obj_idx as usize;
1319 {
1320 let obj = self.ensure_object_mut(stage_u, obj_u);
1321 obj.dark = dark;
1322 }
1323 self.sync_object_sprite(images, layers, stage_u, obj_u)
1324 }
1325
1326 pub fn object_set_color_rate(
1327 &mut self,
1328 images: &mut ImageManager,
1329 layers: &mut LayerManager,
1330 stage: i64,
1331 obj_idx: i64,
1332 rate: i64,
1333 ) -> Result<()> {
1334 let stage_i = stage as isize;
1335 if !(0..3).contains(&stage_i) || obj_idx < 0 {
1336 return Ok(());
1337 }
1338 let stage_u = stage_i as usize;
1339 let obj_u = obj_idx as usize;
1340 {
1341 let obj = self.ensure_object_mut(stage_u, obj_u);
1342 obj.color_rate = rate;
1343 }
1344 self.sync_object_sprite(images, layers, stage_u, obj_u)
1345 }
1346
1347 pub fn object_set_color_add(
1348 &mut self,
1349 images: &mut ImageManager,
1350 layers: &mut LayerManager,
1351 stage: i64,
1352 obj_idx: i64,
1353 r: i64,
1354 g: i64,
1355 b: i64,
1356 ) -> Result<()> {
1357 let stage_i = stage as isize;
1358 if !(0..3).contains(&stage_i) || obj_idx < 0 {
1359 return Ok(());
1360 }
1361 let stage_u = stage_i as usize;
1362 let obj_u = obj_idx as usize;
1363 {
1364 let obj = self.ensure_object_mut(stage_u, obj_u);
1365 obj.color_add_r = r;
1366 obj.color_add_g = g;
1367 obj.color_add_b = b;
1368 }
1369 self.sync_object_sprite(images, layers, stage_u, obj_u)
1370 }
1371
1372 pub fn object_set_color(
1373 &mut self,
1374 images: &mut ImageManager,
1375 layers: &mut LayerManager,
1376 stage: i64,
1377 obj_idx: i64,
1378 r: i64,
1379 g: i64,
1380 b: i64,
1381 ) -> Result<()> {
1382 let stage_i = stage as isize;
1383 if !(0..3).contains(&stage_i) || obj_idx < 0 {
1384 return Ok(());
1385 }
1386 let stage_u = stage_i as usize;
1387 let obj_u = obj_idx as usize;
1388 {
1389 let obj = self.ensure_object_mut(stage_u, obj_u);
1390 obj.color_r = r;
1391 obj.color_g = g;
1392 obj.color_b = b;
1393 }
1394 self.sync_object_sprite(images, layers, stage_u, obj_u)
1395 }
1396
1397 pub fn object_set_blend(
1398 &mut self,
1399 images: &mut ImageManager,
1400 layers: &mut LayerManager,
1401 stage: i64,
1402 obj_idx: i64,
1403 blend: i64,
1404 ) -> Result<()> {
1405 let stage_i = stage as isize;
1406 if !(0..3).contains(&stage_i) || obj_idx < 0 {
1407 return Ok(());
1408 }
1409 let stage_u = stage_i as usize;
1410 let obj_u = obj_idx as usize;
1411 {
1412 let obj = self.ensure_object_mut(stage_u, obj_u);
1413 obj.blend = blend;
1414 }
1415 self.sync_object_sprite(images, layers, stage_u, obj_u)
1416 }
1417
1418 pub fn object_set_light_no(
1419 &mut self,
1420 images: &mut ImageManager,
1421 layers: &mut LayerManager,
1422 stage: i64,
1423 obj_idx: i64,
1424 light_no: i64,
1425 ) -> Result<()> {
1426 let stage_i = stage as isize;
1427 if !(0..3).contains(&stage_i) || obj_idx < 0 {
1428 return Ok(());
1429 }
1430 let stage_u = stage_i as usize;
1431 let obj_u = obj_idx as usize;
1432 {
1433 let obj = self.ensure_object_mut(stage_u, obj_u);
1434 obj.light_no = light_no;
1435 }
1436 self.sync_object_sprite(images, layers, stage_u, obj_u)
1437 }
1438
1439 pub fn object_set_fog_use(
1440 &mut self,
1441 images: &mut ImageManager,
1442 layers: &mut LayerManager,
1443 stage: i64,
1444 obj_idx: i64,
1445 fog_use: i64,
1446 ) -> Result<()> {
1447 let stage_i = stage as isize;
1448 if !(0..3).contains(&stage_i) || obj_idx < 0 {
1449 return Ok(());
1450 }
1451 let stage_u = stage_i as usize;
1452 let obj_u = obj_idx as usize;
1453 {
1454 let obj = self.ensure_object_mut(stage_u, obj_u);
1455 obj.fog_use = fog_use;
1456 }
1457 self.sync_object_sprite(images, layers, stage_u, obj_u)
1458 }
1459
1460 pub fn object_set_z(&mut self, stage: i64, obj_idx: i64, z: i64) -> Result<()> {
1461 let stage_i = stage as isize;
1462 if !(0..3).contains(&stage_i) || obj_idx < 0 {
1463 return Ok(());
1464 }
1465 let stage_u = stage_i as usize;
1466 let obj_u = obj_idx as usize;
1467 let obj = self.ensure_object_mut(stage_u, obj_u);
1468 obj.z = z;
1469 Ok(())
1470 }
1471
1472 pub fn object_clear(
1473 &mut self,
1474 images: &mut ImageManager,
1475 layers: &mut LayerManager,
1476 stage: i64,
1477 obj_idx: i64,
1478 ) -> Result<()> {
1479 let stage_i = stage as isize;
1480 if !(0..3).contains(&stage_i) || obj_idx < 0 {
1481 return Ok(());
1482 }
1483 let stage_u = stage_i as usize;
1484 let obj_u = obj_idx as usize;
1485 let (layer_id, sprite_id) = {
1486 let obj = self.ensure_object_mut(stage_u, obj_u);
1487 obj.file = None;
1488 obj.patno = 0;
1489 obj.bound_file = None;
1490 obj.bound_patno = -1;
1491 obj.disp = false;
1492 obj.alpha = 255;
1493 (obj.layer_id, obj.sprite_id)
1494 };
1495
1496 if let (Some(lid), Some(sid)) = (layer_id, sprite_id)
1501 && let Some(sprite) = layers
1502 .layer_mut(lid)
1503 .and_then(|layer| layer.sprite_mut(sid))
1504 {
1505 *sprite = Sprite::default();
1506 }
1507
1508 let _ = images;
1511 Ok(())
1512 }
1513
1514 pub fn clear_objects_in_layer_no(
1515 &mut self,
1516 images: &mut ImageManager,
1517 layers: &mut LayerManager,
1518 layer_no: i64,
1519 ) -> Result<()> {
1520 for stage in 0..3usize {
1521 let mut indices: Vec<usize> = self.stages[stage].objects.keys().copied().collect();
1522 indices.sort_unstable();
1523 for obj_idx in indices {
1524 let matches = self
1525 .object(stage, obj_idx)
1526 .map(|o| o.layer_no == layer_no)
1527 .unwrap_or(false);
1528 if !matches {
1529 continue;
1530 }
1531 {
1532 let obj = self.ensure_object_mut(stage, obj_idx);
1533 obj.disp = false;
1534 }
1535 let _ = self.sync_object_sprite(images, layers, stage, obj_idx);
1536 }
1537 }
1538 Ok(())
1539 }
1540
1541 pub fn object_get_pos(&self, stage: i64, obj_idx: i64) -> Option<(i64, i64)> {
1542 self.object_peek_pos(stage, obj_idx)
1543 }
1544
1545 pub fn object_get_disp(&self, stage: i64, obj_idx: i64) -> Option<bool> {
1546 self.object_peek_disp(stage, obj_idx).map(|v| v != 0)
1547 }
1548
1549 pub fn object_get_patno(&self, stage: i64, obj_idx: i64) -> Option<i64> {
1550 self.object_peek_patno(stage, obj_idx)
1551 }
1552
1553 pub fn object_get_layer(&self, stage: i64, obj_idx: i64) -> Option<i64> {
1554 self.object_peek_layer(stage, obj_idx)
1555 }
1556
1557 pub fn object_get_order(&self, stage: i64, obj_idx: i64) -> Option<i64> {
1558 self.object_peek_order(stage, obj_idx)
1559 }
1560
1561 pub fn object_get_alpha(&self, stage: i64, obj_idx: i64) -> Option<i64> {
1562 self.object_peek_alpha(stage, obj_idx)
1563 }
1564
1565 pub fn object_set_pat_no(
1566 &mut self,
1567 images: &mut ImageManager,
1568 layers: &mut LayerManager,
1569 stage: i64,
1570 obj_idx: i64,
1571 patno: i64,
1572 ) -> Result<()> {
1573 self.object_set_patno(images, layers, stage, obj_idx, patno)
1574 }
1575
1576 pub fn object_peek_pos(&self, stage: i64, obj_idx: i64) -> Option<(i64, i64)> {
1577 let stage_i = stage as isize;
1578 if !(0..3).contains(&stage_i) || obj_idx < 0 {
1579 return None;
1580 }
1581 let stage_u = stage_i as usize;
1582 let obj_u = obj_idx as usize;
1583 let obj = self.object(stage_u, obj_u)?;
1584 Some((obj.x, obj.y))
1585 }
1586
1587 pub fn object_peek_disp(&self, stage: i64, obj_idx: i64) -> Option<i64> {
1588 let stage_i = stage as isize;
1589 if !(0..3).contains(&stage_i) || obj_idx < 0 {
1590 return None;
1591 }
1592 let stage_u = stage_i as usize;
1593 let obj_u = obj_idx as usize;
1594 let obj = self.object(stage_u, obj_u)?;
1595 Some(if obj.disp { 1 } else { 0 })
1596 }
1597
1598 pub fn object_peek_patno(&self, stage: i64, obj_idx: i64) -> Option<i64> {
1599 let stage_i = stage as isize;
1600 if !(0..3).contains(&stage_i) || obj_idx < 0 {
1601 return None;
1602 }
1603 let stage_u = stage_i as usize;
1604 let obj_u = obj_idx as usize;
1605 let obj = self.object(stage_u, obj_u)?;
1606 Some(obj.patno)
1607 }
1608
1609 pub fn object_peek_layer(&self, stage: i64, obj_idx: i64) -> Option<i64> {
1610 let stage_i = stage as isize;
1611 if !(0..3).contains(&stage_i) || obj_idx < 0 {
1612 return None;
1613 }
1614 let stage_u = stage_i as usize;
1615 let obj_u = obj_idx as usize;
1616 let obj = self.object(stage_u, obj_u)?;
1617 Some(obj.layer_no)
1618 }
1619
1620 pub fn object_peek_order(&self, stage: i64, obj_idx: i64) -> Option<i64> {
1621 let stage_i = stage as isize;
1622 if !(0..3).contains(&stage_i) || obj_idx < 0 {
1623 return None;
1624 }
1625 let stage_u = stage_i as usize;
1626 let obj_u = obj_idx as usize;
1627 let obj = self.object(stage_u, obj_u)?;
1628 Some(obj.order)
1629 }
1630
1631 pub fn object_peek_alpha(&self, stage: i64, obj_idx: i64) -> Option<i64> {
1632 let stage_i = stage as isize;
1633 if !(0..3).contains(&stage_i) || obj_idx < 0 {
1634 return None;
1635 }
1636 let stage_u = stage_i as usize;
1637 let obj_u = obj_idx as usize;
1638 let obj = self.object(stage_u, obj_u)?;
1639 Some(obj.alpha)
1640 }
1641
1642 pub fn object_peek_file(&self, stage: i64, obj_idx: i64) -> Option<String> {
1643 let stage_i = stage as isize;
1644 if !(0..3).contains(&stage_i) || obj_idx < 0 {
1645 return None;
1646 }
1647 let stage_u = stage_i as usize;
1648 let obj_u = obj_idx as usize;
1649 let obj = self.object(stage_u, obj_u)?;
1650 obj.file.clone()
1651 }
1652}
1653
1654fn is_probable_mesh_path(file: &str) -> bool {
1655 let lower = file.to_ascii_lowercase();
1656 lower.ends_with(".x")
1657 || lower.ends_with(".obj")
1658 || lower.ends_with(".fbx")
1659 || lower.ends_with(".gltf")
1660 || lower.ends_with(".glb")
1661}
1662
1663fn set_object_sprite_image(sprite: &mut Sprite, images: &ImageManager, image_id: ImageHandle) {
1664 sprite.image_id = Some(image_id.clone());
1665 if let Some(img) = images.get(&image_id) {
1666 sprite.object_anchor = true;
1667 sprite.texture_center_x = img.center_x as f32;
1668 sprite.texture_center_y = img.center_y as f32;
1669 } else {
1670 sprite.object_anchor = false;
1671 sprite.texture_center_x = 0.0;
1672 sprite.texture_center_y = 0.0;
1673 }
1674}
1675
1676fn clip_rect(use_flag: i64, left: i64, top: i64, right: i64, bottom: i64) -> Option<ClipRect> {
1677 if use_flag == 0 {
1678 return None;
1679 }
1680 Some(ClipRect {
1681 left: left as i32,
1682 top: top as i32,
1683 right: right as i32,
1684 bottom: bottom as i32,
1685 })
1686}
1687
1688#[cfg(test)]
1689mod tests {
1690 use super::GfxRuntime;
1691 use crate::layer::LayerManager;
1692
1693 #[test]
1694 fn front_object_zero_mesh_gets_an_ordinary_sprite_binding() {
1695 let mut gfx = GfxRuntime::new();
1696 let mut layers = LayerManager::new();
1697
1698 gfx.object_create_mesh(&mut layers, 1, 0, "room.x", 1, 10, 20, 0)
1699 .unwrap();
1700
1701 let (layer_id, sprite_id) = gfx.object_sprite_binding(1, 0).unwrap();
1702 let sprite = layers.layer(layer_id).unwrap().sprite(sprite_id).unwrap();
1703 assert_eq!(sprite.mesh_kind, 1);
1704 assert_eq!(sprite.mesh_file_name.as_deref(), Some("room.x"));
1705 assert!(!gfx.has_missing_bound_object_image(&layers));
1706 }
1707
1708 #[test]
1709 fn back_object_zero_pct_gets_an_ordinary_sprite_binding() {
1710 let project_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
1711 let mut gfx = GfxRuntime::new();
1712 let mut images = crate::image_manager::ImageManager::new(project_dir);
1713 let mut layers = LayerManager::new();
1714
1715 let _ = gfx.object_create(&mut images, &mut layers, 0, 0, "missing.g00", 1, 10, 20, 0);
1719
1720 let (layer_id, sprite_id) = gfx.object_sprite_binding(0, 0).unwrap();
1721 let sprite = layers.layer(layer_id).unwrap().sprite(sprite_id).unwrap();
1722 assert!(!gfx.debug_object_snapshot(0, 0).unwrap().is_bg);
1723 assert!(!sprite.billboard);
1724 }
1725
1726 #[test]
1727 fn back_object_zero_billboard_is_not_misclassified_as_background() {
1728 let project_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
1729 let mut gfx = GfxRuntime::new();
1730 let mut images = crate::image_manager::ImageManager::new(project_dir);
1731 let mut layers = LayerManager::new();
1732
1733 let _ = gfx.object_create_billboard(
1736 &mut images,
1737 &mut layers,
1738 0,
1739 0,
1740 "missing.g00",
1741 1,
1742 10,
1743 20,
1744 0,
1745 );
1746
1747 let (layer_id, sprite_id) = gfx.object_sprite_binding(0, 0).unwrap();
1748 let sprite = layers.layer(layer_id).unwrap().sprite(sprite_id).unwrap();
1749 assert!(!gfx.debug_object_snapshot(0, 0).unwrap().is_bg);
1750 assert!(sprite.billboard);
1751 }
1752}