-
Notifications
You must be signed in to change notification settings - Fork 911
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Change the way you get a window #33
Comments
I agree with this, because this is a bit of an issue for An approach would be to let For My issue here, if the game engine works that way, then it's going to be tricky to integrate with the rest of the platform. If you need to present other views or deal with In App Purchase transactions then the current I am not asking to change the current approach, because there's a lot of value in that. |
I did a small proof of concept of getting Winit to work as a PS, I haven no clue how the jump stuff works or if they are necessary. pub struct Window {
_events_queue: Arc<RefCell<VecDeque<Event>>>,
delegate_state: Box<DelegateState>,
}
unsafe impl Send for Window {}
unsafe impl Sync for Window {}
#[derive(Debug)]
struct DelegateState {
window: id,
size: LogicalSize,
scale: f64,
}
impl DelegateState {
fn new(window: id, size: LogicalSize, scale: f64) -> DelegateState {
DelegateState {
window,
size,
scale,
}
}
}
pub struct EventsLoop {
events_queue: Arc<RefCell<VecDeque<Event>>>,
}
#[derive(Clone)]
pub struct EventsLoopProxy;
impl EventsLoop {
pub fn new() -> EventsLoop {
// unsafe {
// if !msg_send![class!(NSThread), isMainThread] {
// panic!("`EventsLoop` can only be created on the main thread on iOS");
// }
// }
EventsLoop {
events_queue: Default::default(),
}
}
pub fn poll_events<F>(&mut self, mut callback: F)
where
F: FnMut(::Event),
{
if let Some(event) = self.events_queue.borrow_mut().pop_front() {
callback(event);
return;
}
unsafe {
// jump hack, so we won't quit on willTerminate event before processing it
// assert!(
// JMPBUF.is_some(),
// "`EventsLoop::poll_events` must be called after window creation on iOS"
// );
// if setjmp(mem::transmute_copy(&mut JMPBUF)) != 0 {
if let Some(event) = self.events_queue.borrow_mut().pop_front() {
callback(event);
return;
// }
}
}
unsafe {
// run runloop
let seconds: CFTimeInterval = 0.000002;
while CFRunLoopRunInMode(kCFRunLoopDefaultMode, seconds, 1)
== kCFRunLoopRunHandledSource
{}
}
if let Some(event) = self.events_queue.borrow_mut().pop_front() {
callback(event)
}
}
#[derive(Clone)]
pub struct PlatformSpecificWindowBuilderAttributes {
pub root_view_class: &'static Class,
}
impl Default for PlatformSpecificWindowBuilderAttributes {
fn default() -> Self {
PlatformSpecificWindowBuilderAttributes {
root_view_class: class!(UIView),
}
}
}
extern fn handle_touches(this: &Object, _: Sel, touches: id, _:id) {
unsafe {
let events_queue: *mut c_void = *this.get_ivar("eventsQueue");
let events_queue = &*(events_queue as *const RefCell<VecDeque<Event>>);
let touches_enum: id = msg_send![touches, objectEnumerator];
loop {
let touch: id = msg_send![touches_enum, nextObject];
if touch == nil {
break
}
let location: CGPoint = msg_send![touch, locationInView:nil];
let touch_id = touch as u64;
let phase: i32 = msg_send![touch, phase];
events_queue.borrow_mut().push_back(Event::WindowEvent {
window_id: RootEventId(WindowId),
event: WindowEvent::Touch(Touch {
device_id: DEVICE_ID,
id: touch_id,
location: (location.x as f64, location.y as f64).into(),
phase: match phase {
0 => TouchPhase::Started,
1 => TouchPhase::Moved,
// 2 is UITouchPhaseStationary and is not expected here
3 => TouchPhase::Ended,
4 => TouchPhase::Cancelled,
_ => panic!("unexpected touch phase: {:?}", phase)
}
}),
});
}
}
}
impl Window {
pub fn new(
ev: &EventsLoop,
_attributes: WindowAttributes,
pl_attributes: PlatformSpecificWindowBuilderAttributes,
) -> Result<Window, CreationError> {
unsafe {
// debug_assert!(mem::size_of_val(&JMPBUF) == mem::size_of::<Box<JmpBuf>>());
// assert!(
// mem::replace(&mut JMPBUF, Some(Box::new([0; JBLEN]))).is_none(),
// "Only one `Window` is supported on iOS"
// );
let screen_class = class!(UIScreen);
let window_class = class!(UIWindow);
let controller_class = class!(UIViewController);
let color_class = class!(UIColor);
let green_color: id = msg_send![color_class, greenColor];
let main_screen: id = msg_send![screen_class, mainScreen];
let bounds: CGRect = msg_send![main_screen, bounds];
let scale: CGFloat = msg_send![main_screen, nativeScale];
let mut decl = ClassDecl::new("MyController", controller_class).expect("Failed to declare class `controller_class`");
decl.add_method(sel!(touchesBegan:withEvent:),
handle_touches as extern fn(this: &Object, _: Sel, _: id, _:id));
decl.add_ivar::<*mut c_void>("eventsQueue");
let decl = decl.register();
let view_controller: id = msg_send![decl, alloc];
let view_controller: id = msg_send![view_controller, init];
let events_queue = &*ev.events_queue;
(&mut *view_controller).set_ivar("eventsQueue", mem::transmute::<_, *mut c_void>(events_queue));
let view: id = msg_send![view_controller, view];
let _: () = msg_send![view, setBackgroundColor: green_color];
let size = (bounds.size.width as f64, bounds.size.height as f64).into();
let delegate_state = Box::new(DelegateState::new(view_controller, size, scale as f64));
return Ok(Window {
_events_queue: ev.events_queue.clone(),
delegate_state,
});
}
// }
// }
// // create_delegate_class();
// // start_app();
// panic!("Couldn't create `UIApplication`!")
}
#[inline]
pub fn get_uiwindow(&self) -> id {
self.delegate_state.window
}
#[inline]
pub fn get_uiview(&self) -> id {
self.delegate_state.window
}
} The client pub struct GodObject {
window: winit::Window,
events_loop: winit::EventsLoop,
}
#[no_mangle]
pub extern fn run() -> *mut GodObject {
let mut events_loop = winit::EventsLoop::new();
let window = winit::Window::new(&events_loop).unwrap();
// events_loop.run_forever(|event| {
// ControlFlow::Continue
// });
let x = Box::new(GodObject { window, events_loop }) ;
Box::into_raw(x)
}
#[no_mangle]
pub extern fn get_window(god_object: *const GodObject) -> *mut c_void {
let god_object = unsafe { &*god_object };
use winit::os::ios::WindowExt;
god_object.window.get_uiwindow()
}
#[no_mangle]
pub extern fn start_event_block(god_object: *mut GodObject) {
let mut god_object = unsafe { &mut *god_object };
use winit::os::ios::WindowExt;
let mut events_loop = &mut god_object.events_loop;
events_loop.poll_events(|event| {
println!("{:?}", event);
//ControlFlow::Continue
});
} And the Swift counter part import UIKit
public class GameViewController: UIViewController {
let game: OpaquePointer
var displayLink: CADisplayLink? = nil
public init() {
self.game = run()!
super.init(nibName: nil, bundle: nil)
}
@objc func tick(step: CADisplayLink) {
start_event_block(self.game)
print(step)
}
override public func viewDidLoad() {
super.viewDidLoad()
self.displayLink = CADisplayLink(target: self, selector: #selector(self.tick(step:)))
let gameView = Unmanaged<UIViewController>.fromOpaque(get_window(self.game)!).takeRetainedValue()
self.addChild(gameView)
self.view.addSubview(gameView.view)
gameView.didMove(toParent: self)
}
public override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) }
public override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.displayLink?.add(to: .current, forMode: .default)
}
public override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.displayLink?.invalidate()
}
public override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated)}
override public var shouldAutorotate: Bool { return true }
override public var prefersStatusBarHidden: Bool { return true }
override public var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if UIDevice.current.userInterfaceIdiom == .phone { return .all } else { return .all }
}
} |
This is exactly my use case. I want |
enable early Z for SVG. Additionally, this switches the B-quad patches for XCAA to be convex hulls instead of bounding boxes, reducing fragment shader load. This is a large speedup for the Ghostscript tiger demo: 5x or more. Closes rust-windowing#33.
I think the ideal pattern here would be to have |
Actually, I think that a better API would be to have a |
On Android it should be possible to have multiple windows "open" within a single process (those are called On my phone a new |
Original: rust-windowing/glutin#175
The text was updated successfully, but these errors were encountered: