(_width: f64, _height: f64, title_ptr: *const u8, _fullscreen: f64)
| 651 | |
| 652 | #[no_mangle] |
| 653 | pub extern "C" fn bloom_init_window(_width: f64, _height: f64, title_ptr: *const u8, _fullscreen: f64) { |
| 654 | let _title = str_from_header(title_ptr); |
| 655 | |
| 656 | // Set orientation mask based on requested dimensions |
| 657 | // width > height → landscape, otherwise all orientations |
| 658 | if _width > _height { |
| 659 | unsafe { ORIENTATION_MASK = 0x18; } // UIInterfaceOrientationMaskLandscape |
| 660 | } |
| 661 | |
| 662 | // Register ObjC classes for the scene delegate (window/view creation) |
| 663 | register_metal_view_class(); |
| 664 | register_view_controller_class(); |
| 665 | register_scene_delegate(); |
| 666 | |
| 667 | // Signal the main thread that our ObjC classes are ready. |
| 668 | // UIApplicationMain (on main thread) waits for this before starting. |
| 669 | extern "C" { fn perry_ios_classes_registered(); } |
| 670 | unsafe { perry_ios_classes_registered(); } |
| 671 | |
| 672 | // Debug: write marker to confirm we reached this point |
| 673 | let _ = std::fs::write("/tmp/bloom_checkpoint_1.txt", "classes registered\n"); |
| 674 | |
| 675 | // Get app bundle path for resolving relative asset paths |
| 676 | unsafe { |
| 677 | let bundle_cls = AnyClass::get(c"NSBundle").unwrap(); |
| 678 | let main_bundle: Retained<AnyObject> = msg_send![bundle_cls, mainBundle]; |
| 679 | let resource_path: *const AnyObject = msg_send![&*main_bundle, resourcePath]; |
| 680 | if !resource_path.is_null() { |
| 681 | let utf8: *const u8 = msg_send![&*resource_path, UTF8String]; |
| 682 | if !utf8.is_null() { |
| 683 | let cstr = std::ffi::CStr::from_ptr(utf8 as *const i8); |
| 684 | if let Ok(s) = cstr.to_str() { |
| 685 | BUNDLE_PATH = Some(s.to_string()); |
| 686 | } |
| 687 | } |
| 688 | } |
| 689 | } |
| 690 | |
| 691 | // With --features ios-game-loop, this function runs on the game thread. |
| 692 | // UIApplicationMain runs on the main thread. The runtime's scene delegate |
| 693 | // calls perry_scene_will_connect() which creates the window, view, wgpu |
| 694 | // surface, and ENGINE — all on the main thread. We just wait for it. |
| 695 | unsafe { |
| 696 | for _ in 0..1000 { |
| 697 | if ENGINE.get().is_some() { break; } |
| 698 | std::thread::sleep(std::time::Duration::from_millis(10)); |
| 699 | } |
| 700 | } |
| 701 | |
| 702 | if unsafe { ENGINE.get().is_none() } { |
| 703 | panic!("[bloom-ios] Engine not initialized after 10s. \ |
| 704 | Compile with: perry compile --target ios-simulator --features ios-game-loop"); |
| 705 | } |
| 706 | } |
| 707 | |
| 708 | #[no_mangle] |
| 709 | pub extern "C" fn bloom_close_window() { |
no test coverage detected