fix(ui): the pointer in the renderer's pixels - macOS reports it in window points, so on Retina every hit landed at half the cursor's position

The old kit read Input.mouse_x() * gl_scale; ludic.ui read it raw against a layout sized in
drawable pixels. A backend says how many screen pixels one pointer unit is (pointer_scale);
render3d's is gl_pixel_scale(), 1 on Windows and headless.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-26 23:31:47 +03:00
parent 5df0747642
commit 40a91f39ed
3 changed files with 12 additions and 2 deletions

View file

@ -14,6 +14,7 @@ export property UiBackend {
clip: fn(float, float, float, float) -> void = null
unclip: fn() -> void = null
scale: fn() -> float = null # screen pixels per design pixel
pointer_scale: fn() -> float = null # screen pixels per unit of Input.mouse_x/y (2 on Retina)
translate: fn(string) -> string = null # the program's language, for every text a template shows
sound: fn(string) -> void = null # a control was used: "click", or its sound="..."
read: fn(string) -> string = null # a template file's text (else Fs.read_text)

View file

@ -37,8 +37,9 @@ function in_read(ui_st: mut UiState) -> void {
ui_st.in_last = ui_st.in_now
let i = new UiInput
if ui_st.ui_be != null and ui_st.ui_be.input {
i.x = float(Input.mouse_x())
i.y = float(Input.mouse_y())
let ps = in_pointer_scale(ui_st)
i.x = float(Input.mouse_x()) * ps
i.y = float(Input.mouse_y()) * ps
i.down = Input.mouse_down(0)
i.down_right = Input.mouse_down(1)
i.down_middle = Input.mouse_down(2)
@ -60,6 +61,12 @@ function in_read(ui_st: mut UiState) -> void {
in_repeat(ui_st, i)
ui_st.in_now = i
}
# the platform reports the pointer in window points and a renderer draws in pixels: on Retina the
# layout is twice the pointer's numbers, and every hit landed up and to the left of the cursor
function in_pointer_scale(ui_st: UiState) -> float {
if ui_st.ui_be.pointer_scale == null { return 1.0 }
return ui_st.ui_be.pointer_scale()
}
function in_any_key() -> int {
for k in 8 .. 167 {
if Input.key_pressed(k) { return k }

View file

@ -24,6 +24,7 @@ function r3u_make() -> UiBackend {
b.clip = fn r3u_clip
b.unclip = fn r3u_unclip
b.scale = fn r3u_scale
b.pointer_scale = fn r3u_pointer_scale
b.now = fn r3u_now
return b
}
@ -40,6 +41,7 @@ export function ui_atlas(ui_st: mut UiState, prefix: string, tex: int, cols: int
}
function r3u_now() -> float { return float(Time.now_us() / 1000) / 1000.0 }
function r3u_scale(ui_st: UiState) -> float { return float(gl_height()) / 1080.0 * ui_st.r3u_user }
function r3u_pointer_scale() -> float { return float(gl_pixel_scale()) }
function r3u_r(c: int) -> float { return float((c / 65536) % 256) / 255.0 }
function r3u_g(c: int) -> float { return float((c / 256) % 256) / 255.0 }
function r3u_b(c: int) -> float { return float(c % 256) / 255.0 }