diff --git a/platform/macos/display_server_macos_embedded.h b/platform/macos/display_server_macos_embedded.h index 3e91d58f09..5574887aae 100644 --- a/platform/macos/display_server_macos_embedded.h +++ b/platform/macos/display_server_macos_embedded.h @@ -97,6 +97,10 @@ class DisplayServerMacOSEmbedded : public DisplayServerMacOSBase { Point2i ime_last_position; + // Convert source pixel size to render pixel size, accounting for the + // difference between display scale and render scale when hiDPI is disabled. + Size2i _source_to_render_size(const Size2i &p_source_size) const; + void _mouse_apply_mode(DisplayServerEnums::MouseMode p_prev_mode, DisplayServerEnums::MouseMode p_new_mode) override; struct Joy { diff --git a/platform/macos/display_server_macos_embedded.mm b/platform/macos/display_server_macos_embedded.mm index c63cbdefe7..3551ddd9b5 100644 --- a/platform/macos/display_server_macos_embedded.mm +++ b/platform/macos/display_server_macos_embedded.mm @@ -136,7 +136,8 @@ DisplayServerMacOSEmbedded::DisplayServerMacOSEmbedded(const String &p_rendering layer.anchorPoint = CGPointMake(0, 0); layer.transform = CATransform3DMakeScale(1.0, -1.0, 1.0); - Error err = gl_manager->window_create(window_id_counter, layer, p_resolution.width, p_resolution.height); + Size2i render_size = _source_to_render_size(p_resolution); + Error err = gl_manager->window_create(window_id_counter, layer, render_size.width, render_size.height); if (err != OK) { ERR_FAIL_MSG("Could not create OpenGL context."); } @@ -170,8 +171,8 @@ DisplayServerMacOSEmbedded::DisplayServerMacOSEmbedded(const String &p_rendering Error err = rendering_context->window_create(window_id_counter, &wpd); ERR_FAIL_COND_MSG(err != OK, vformat("Can't create a %s context", rendering_driver)); - // The rendering context is always in pixels - rendering_context->window_set_size(window_id_counter, p_resolution.width, p_resolution.height); + Size2i render_size = _source_to_render_size(p_resolution); + rendering_context->window_set_size(window_id_counter, render_size.width, render_size.height); rendering_context->window_set_vsync_mode(window_id_counter, p_vsync_mode); } #endif @@ -194,8 +195,9 @@ DisplayServerMacOSEmbedded::DisplayServerMacOSEmbedded(const String &p_rendering } #endif - CGFloat scale = screen_get_max_scale(); - layer.contentsScale = scale; + CGFloat display_scale = state.screen_max_scale; + CGFloat render_scale = screen_get_max_scale(); + layer.contentsScale = render_scale; layer.magnificationFilter = kCAFilterNearest; layer.minificationFilter = kCAFilterNearest; transparent = ((p_flags & DisplayServerEnums::WINDOW_FLAG_TRANSPARENT_BIT) == DisplayServerEnums::WINDOW_FLAG_TRANSPARENT_BIT); @@ -203,7 +205,7 @@ DisplayServerMacOSEmbedded::DisplayServerMacOSEmbedded(const String &p_rendering layer.actions = @{ @"contents" : [NSNull null] }; // Disable implicit animations for contents. // AppKit frames, bounds and positions are always in points. CGRect bounds = CGRectMake(0, 0, p_resolution.width, p_resolution.height); - bounds = CGRectApplyAffineTransform(bounds, CGAffineTransformInvert(CGAffineTransformMakeScale(scale, scale))); + bounds = CGRectApplyAffineTransform(bounds, CGAffineTransformInvert(CGAffineTransformMakeScale(display_scale, display_scale))); layer.bounds = bounds; CGSConnectionID connection_id = CGSMainConnectionID(); @@ -277,7 +279,9 @@ void DisplayServerMacOSEmbedded::_mouse_apply_mode(DisplayServerEnums::MouseMode void DisplayServerMacOSEmbedded::warp_mouse(const Point2i &p_position) { _THREAD_SAFE_METHOD_ Input::get_singleton()->set_mouse_position(p_position); - EngineDebugger::get_singleton()->send_message("game_view:warp_mouse", { p_position }); + // Convert from game pixels to points for the editor. + float inv_scale = 1.0f / screen_get_max_scale(); + EngineDebugger::get_singleton()->send_message("game_view:warp_mouse", { Point2i(inv_scale * p_position) }); } Point2i DisplayServerMacOSEmbedded::mouse_get_position() const { @@ -474,6 +478,10 @@ int DisplayServerMacOSEmbedded::screen_get_dpi(int p_screen) const { float DisplayServerMacOSEmbedded::screen_get_scale(int p_screen) const { _THREAD_SAFE_METHOD_ + if (!OS::get_singleton()->is_hidpi_allowed()) { + return 1.0f; + } + switch (p_screen) { case DisplayServerEnums::SCREEN_WITH_MOUSE_FOCUS: case DisplayServerEnums::SCREEN_WITH_KEYBOARD_FOCUS: @@ -482,7 +490,7 @@ float DisplayServerMacOSEmbedded::screen_get_scale(int p_screen) const { case 0: return state.screen_window_scale; default: - return 1.0; + return 1.0f; } } @@ -559,27 +567,29 @@ void DisplayServerMacOSEmbedded::_window_set_size(const Size2i p_size, DisplaySe [CATransaction begin]; [CATransaction setDisableActions:YES]; - CGFloat scale = screen_get_max_scale(); + CGFloat display_scale = state.screen_max_scale; + CGFloat render_scale = screen_get_max_scale(); CGRect bounds = CGRectMake(0, 0, p_size.width, p_size.height); - bounds = CGRectApplyAffineTransform(bounds, CGAffineTransformInvert(CGAffineTransformMakeScale(scale, scale))); + bounds = CGRectApplyAffineTransform(bounds, CGAffineTransformInvert(CGAffineTransformMakeScale(display_scale, display_scale))); layer.bounds = bounds; - layer.contentsScale = scale; + layer.contentsScale = render_scale; + Size2i render_size = _source_to_render_size(p_size); #if defined(RD_ENABLED) if (rendering_context) { - rendering_context->window_set_size(p_window, p_size.width, p_size.height); + rendering_context->window_set_size(p_window, render_size.width, render_size.height); } #endif #if defined(GLES3_ENABLED) if (gl_manager) { - gl_manager->window_resize(p_window, p_size.width, p_size.height); + gl_manager->window_resize(p_window, render_size.width, render_size.height); } #endif [CATransaction commit]; Callable *cb = window_resize_callbacks.getptr(p_window); if (cb) { - Variant resize_rect = Rect2i(Point2i(), p_size); + Variant resize_rect = Rect2i(Point2i(), render_size); _window_callback(window_resize_callbacks[p_window], resize_rect); } } @@ -653,9 +663,19 @@ bool DisplayServerMacOSEmbedded::window_is_focused(DisplayServerEnums::WindowID } float DisplayServerMacOSEmbedded::screen_get_max_scale() const { + if (!OS::get_singleton()->is_hidpi_allowed()) { + return 1.0f; + } return state.screen_max_scale; } +Size2i DisplayServerMacOSEmbedded::_source_to_render_size(const Size2i &p_source_size) const { + CGFloat display_scale = state.screen_max_scale; + CGFloat render_scale = screen_get_max_scale(); + return Size2i((int)(p_source_size.width / display_scale * render_scale), + (int)(p_source_size.height / display_scale * render_scale)); +} + bool DisplayServerMacOSEmbedded::window_can_draw(DisplayServerEnums::WindowID p_window) const { return true; } @@ -715,6 +735,7 @@ void DisplayServerMacOSEmbedded::set_state(const DisplayServerMacOSEmbeddedState } uint32_t old_display_id = state.display_id; + float old_scale = state.screen_max_scale; state = p_state; @@ -725,6 +746,12 @@ void DisplayServerMacOSEmbedded::set_state(const DisplayServerMacOSEmbeddedState } #endif } + if (state.screen_max_scale != old_scale) { + // Recover source pixel size from current bounds using the old display scale. + CGSize bounds_size = layer.bounds.size; + Size2i source_size((int)(bounds_size.width * old_scale), (int)(bounds_size.height * old_scale)); + _window_set_size(source_size, DisplayServerEnums::MAIN_WINDOW_ID); + } if (hdr_output.requested) { _update_hdr_output(DisplayServerEnums::MAIN_WINDOW_ID, hdr_output); } diff --git a/platform/macos/editor/embedded_game_view_plugin.mm b/platform/macos/editor/embedded_game_view_plugin.mm index 611cf28fe1..1afbd10658 100644 --- a/platform/macos/editor/embedded_game_view_plugin.mm +++ b/platform/macos/editor/embedded_game_view_plugin.mm @@ -123,8 +123,10 @@ bool GameViewDebuggerMacOS::_msg_joy_stop(const Array &p_args) { bool GameViewDebuggerMacOS::_msg_warp_mouse(const Array &p_args) { ERR_FAIL_COND_V_MSG(p_args.size() != 1, false, "warp_mouse: invalid number of arguments."); + // Position arrives in points; convert to editor pixels. Vector2i pos = p_args[0]; - embedded_process->get_layer_host()->warp_mouse(pos); + float scale = DisplayServer::get_singleton()->screen_get_max_scale(); + embedded_process->get_layer_host()->warp_mouse(Vector2i(scale * pos)); return true; } diff --git a/platform/macos/editor/embedded_process_macos.mm b/platform/macos/editor/embedded_process_macos.mm index ec61a2fdd7..d83fd84786 100644 --- a/platform/macos/editor/embedded_process_macos.mm +++ b/platform/macos/editor/embedded_process_macos.mm @@ -353,8 +353,35 @@ void LayerHost::gui_input(const Ref &p_event) { return; } + // Convert from editor pixels to points for the game. + float inv_scale = 1.0f / DisplayServer::get_singleton()->screen_get_max_scale(); + Ref event = p_event; + + { + Ref e = p_event; + if (e.is_valid()) { + e = e->duplicate(); + e->set_position(e->get_position() * inv_scale); + e->set_global_position(e->get_global_position() * inv_scale); + Ref mm = e; + if (mm.is_valid()) { + mm->set_relative(mm->get_relative() * inv_scale); + } + event = e; + } + } + + { + Ref e = p_event; + if (e.is_valid()) { + e = e->duplicate(); + e->set_position(e->get_position() * inv_scale); + event = e; + } + } + PackedByteArray data; - if (encode_input_event(p_event, data)) { + if (encode_input_event(event, data)) { if (script_debugger != nullptr) { script_debugger->send_message("embed:event", { data }); } diff --git a/platform/macos/embedded_debugger.mm b/platform/macos/embedded_debugger.mm index 21f6ac28b5..2687919402 100644 --- a/platform/macos/embedded_debugger.mm +++ b/platform/macos/embedded_debugger.mm @@ -108,9 +108,19 @@ Error EmbeddedDebugger::_msg_event(const Array &p_args) { Ref event; decode_input_event(data, event); + // Events arrive in points (normalized by the editor). Scale to the + // game's pixel coordinate space. + float scale = ds->screen_get_max_scale(); + { Ref e = event; if (e.is_valid()) { + e->set_position(e->get_position() * scale); + e->set_global_position(e->get_global_position() * scale); + Ref mm = e; + if (mm.is_valid()) { + mm->set_relative(mm->get_relative() * scale); + } input->set_mouse_position(e->get_position()); } } @@ -118,6 +128,7 @@ Error EmbeddedDebugger::_msg_event(const Array &p_args) { { Ref e = event; if (e.is_valid()) { + e->set_position(e->get_position() * scale); input->set_mouse_position(e->get_position()); } } @@ -125,6 +136,7 @@ Error EmbeddedDebugger::_msg_event(const Array &p_args) { { Ref e = event; if (e.is_valid()) { + e->set_position(e->get_position() * scale); input->set_mouse_position(e->get_position()); } }