Skip to content

Fix the default 2d projection halving draws on 2x displays after a resize - #607

Merged
RandyGaul merged 2 commits into
masterfrom
hidpi-projection-points
Sep 11, 2026
Merged

Fix the default 2d projection halving draws on 2x displays after a resize#607
RandyGaul merged 2 commits into
masterfrom
hidpi-projection-points

Conversation

@RandyGaul

Copy link
Copy Markdown
Owner

The startup projection spans the window in points, but the canvas-recreation hook rebuilt it from the canvas's pixel size (window * pixel_scale). On a 2x display the first resize doubled the projection extent and every 2d draw rendered at half size from then on. This is the regression #575 and #579 set out to fix.

The fix is the hook reading app->w/h (points), plus refreshing the mvp under the current camera (mirroring cf_draw_projection) so a mid-frame cf_app_set_size lands immediately, and re-deriving the AA factor since pixel_scale may be what changed.

No API changes. The model stays: window sizes in points, canvas auto-recreated at points * pixel_scale, projection automatic, cf_app_get_pixel_scale read-only. Docs updated to say so, and to state that cf_app_get_display_scale is the OS UI-scale hint CF reports but never applies.

Test: forces pixel_scale = 2 on an owned app so 1x CI walks the 2x path, and checks cf_screen_to_world / cf_world_to_screen against point-space extents. Verified it fails with the old hook and passes with the new one. Full suite: 362/362 on Windows.

… a resize

cf_make_draw builds the default projection from the window size in points, but the
canvas-recreation hook rebuilt it from the canvas's pixel size (window * pixel_scale).
On a Retina-class display the first resize doubled the projection extent and every
2d draw rendered at half size from then on. 1x machines never saw it.

The hook now reads app->w/h (points) like startup does, refreshes the mvp under the
current camera the way cf_draw_projection does so a mid-frame cf_app_set_size takes
effect immediately, and re-derives the AA factor since pixel_scale may be what changed.

A test forces pixel_scale to 2 on an owned app so 1x CI exercises the 2x path, and
checks cf_screen_to_world / cf_world_to_screen against the point-space extents.

Docs: cf_make_app and cf_app_set_size sizes are points (a pixel unless the OS clusters
pixels); cf_app_get_display_scale is the OS UI-scale hint CF reports but never applies.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 146e4c7e1b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/cute_draw.cpp Outdated
Comment on lines +5328 to +5329
s_draw->projection = ortho_2d(0, 0, (float)app->w, (float)app->h);
CF_MUL_M32_M32(s_draw->mvp, s_draw->projection, s_draw->cam_stack.last());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Refresh saved default projections when resizing

When cf_app_set_size recreates the canvas inside a cf_draw_push scope, this updates only the active projection while projection_stack still contains the pre-resize projection. The newly added test validates the transform before cf_draw_pop, but that pop immediately restores the old dimensions; subsequent drawing, including later frames because reset_cam() preserves the projection, is scaled using the stale window size until another recreation. Update the saved default projection state as part of the resize, or otherwise prevent the pop from undoing this refresh.

Useful? React with 👍 / 👎.

…a resize

cf_app_set_canvas_size(w, h) now rebuilds the default projection to span w by h: a retro
320x180 target draws in its own pixels with no cf_draw_projection call, which is what such
apps already relied on when the hook was built from the canvas. The automatic recreation path
keeps passing the window size in points.

Codex's catch on #607: a resize from inside a cf_draw_push scope updated only the active
projection, and the pop restored the stale pre-resize one for every later frame. The hook now
tracks the default projection it last set and swaps the new one into any saved copies of it,
leaving a user's own saved projection alone. Tests cover both.
@RandyGaul
RandyGaul merged commit b20317a into master Sep 11, 2026
26 checks passed
@RandyGaul
RandyGaul deleted the hidpi-projection-points branch September 11, 2026 21:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant