Skip to content

[rcore][web] Review resizable canvas on FLAG_WINDOW_RESIZABLE #4945

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

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

Moros1138
Copy link

@Moros1138 Moros1138 commented May 18, 2025

The problem

Basically, emscripten/glfw don't realize a change in size has occured and as such isn't adapting to the change. The problem manifests as a mismatch between the size of the canvas being presented and the input handling of the mouse when FLAG_WINDOW_RESIZABLE is set. It also manfests as mismatch positioning of the canvas when transitioning into and out of full screen mode.

See the following video demonstrating the problem.
https://github.com/user-attachments/assets/553f673b-b458-4369-beec-9f1136f03a69

This problem also has a history attached to it, from the emscripten side of things. I have personally tested emsdk versions between 3.1.56 and 4.0.8 and found that this problem was introduced (apparently it was a bug fix!) in emscripten version 3.1.72, as a fix to glfw and css scaling. This means that if you use an emscripten version prior to 3.1.72, everything works in the expected manner I detail below.

The expectation

DISCLAIMER: I realize some of this is my opinion and that my opinions are not the only ones.

The expected behavior of a resizable window in the context of the web platform is that the canvas should correctly adapt to the parent container's dimensions and such change should also be correctly reflected in the input handling. The mouse position reported should match the actual mouse position. The canvas should also gracefully resize when transitioning into and out of fullscreen mode.

See the following video demonstrating the fix.
https://github.com/user-attachments/assets/dcf403ad-1086-4f9d-bad3-b82d2e181fef

Furthermore, I have tested the fix in emscripten versions 3.1.56 and 4.0.8.

@Moros1138
Copy link
Author

Moros1138 commented May 18, 2025

To make it easier to verify I have hosted the fixed example. I hope it's helpful. Please note, i had to make changes to the shell in order to properly demonstrate the resizing as the current shell doesn't enforce layout for the canvas's parent element.

https://moros1138.com/raylib/core_input_mouse.html

@raysan5 raysan5 added the platform: Web Web platform label May 19, 2025
@raysan5
Copy link
Owner

raysan5 commented May 19, 2025

@Moros1138 Many thanks for working on this issue! Some questions:

  • Does it work with old emscripten versions?
  • Does it work as expected with canvas scaled by CSS (not resized)? (raylib web examples are compiled this way by default, keeping the 800x450 framebuffer but scaling canvas to full browser by CSS)
  • Does it work as expected on HighDPI monitors?

@Moros1138
Copy link
Author

Moros1138 commented May 19, 2025

@Moros1138 Many thanks for working on this issue! Some questions:

you're welcome

  • Does it work with old emscripten versions?

I tested it pre 3.1.72 and it works as demonstrated in the fix video

  • Does it work as expected with canvas scaled by CSS (not resized)? (raylib web examples are compiled this way by default, keeping the 800x450 framebuffer but scaling canvas to full browser by CSS)

Sure does! Didn't expect it to, but it does!
https://github.com/user-attachments/assets/00e74121-334e-4473-bc7e-c7c524fa0680

Edited to clarify: as the resize handler exits if the resizeable flag is not set, none of this affects code examples as they were originally compiled.

  • Does it work as expected on HighDPI monitors?

I have no way to test this on my end, attention Mac Users??

@Moros1138
Copy link
Author

I should really wait til i wake up to answer questions like this

  • Does it work as expected with canvas scaled by CSS (not resized)? (raylib web examples are compiled this way by default, keeping the 800x450 framebuffer but scaling canvas to full browser by CSS)

As what you're asking doesn't involve the resize handler, it's out of the scope of this PR, but if this is a problem you want fixed I'll gladly send an appropriate PR for that issue.

@Moros1138
Copy link
Author

Moros1138 commented May 19, 2025

Basically, if the example scaling was broken before this won't fix it because this fixes resizable windows, not fixed sized windows that fail to scale gracefully, separate issue.

@Moros1138
Copy link
Author

Moros1138 commented May 19, 2025

For example, we see in 3.1.56 the css scaling fails spectacularly

https://moros1138.com/raylib/emsdk-3.1.56/

But in 4.0.8 it fills the width of the browser (i assume this is your expectation)

https://moros1138.com/raylib/emsdk-4.0.8/

both of these are unmodified examples with your original shell.html ... my fix for resizable windows is irrelavent here because none of that code is called!

Anyways, like i said this is a separate issue that I'll gladly tackle, but it has nothing to do with the problem I solve in this PR.

@Moros1138 Moros1138 changed the title [rcore][web] make window resizing sane [rcore][web] make FLAG_WINDOW_RESIZEABLE sane May 19, 2025
@Moros1138 Moros1138 changed the title [rcore][web] make FLAG_WINDOW_RESIZEABLE sane [rcore][web] make FLAG_WINDOW_RESIZABLE sane May 19, 2025
@raysan5
Copy link
Owner

raysan5 commented May 19, 2025

@Moros1138 All examples have a shell that scales the 800x450 canvas to full browser and mouse is automatically reported by its framebuffer proportional position, not the scaled canvas: https://www.raylib.com/examples/core/core_2d_camera_mouse_zoom.html

Also, if the window was set as FLAG_WINDOW_RESIZABLE, the canvas get resized with the framebuffer and the mouse position was reported correctly.

Summarizing, everything worked as expected on raylib before this emscripten library_glfw.js update adding support for HighDPI and internally scaling the framebuffer.

It was further patched specifically to address canvas CSS scaling on raylib examples but the framebuffer resize option got broken...

I already reviewed this issue but I couldn't find a solution so I just reverted to a previous emscripten version... but I know that's not the solution... at this point I'm even considering avoiding library_glfw.js (lately renamed to libglfw) and create a custom implementation for raylib PLATFORM_WEB, specially after the last platforms split.

EDIT: Re-reading your last message, it seems emsdk 4.0.8 works as expected for canvas css scaling (probably due to the patch added at the time) but, does it work if canvas set as resizable? If I understand correctly, it doesn't because your patch in raylib side get circunvented by libglfw.js patch.

@Moros1138
Copy link
Author

Moros1138 commented May 19, 2025

We are talking past eachother and you're talking about CSS scaling.. I'm talking about the resizable flag and the fact that the canvas doesn't match the mouse when doing so...

EDIT:

but, does it work if canvas set as resizable? If I understand correctly, it doesn't because your patch in raylib side get circunvented by libglfw.js patch.

https://moros1138.com/raylib/core_input_mouse.html

i think so?

EDIT of the EDIT:

bear in mind the link above has a modified verison of both the example (obviously for the resize flag and visual cue) .. and a modified shell as the original shell didn't have a forced layout for the resizable canvas to confrom to.

@raysan5 raysan5 changed the title [rcore][web] make FLAG_WINDOW_RESIZABLE sane [rcore][web] Review resizable canvas on FLAG_WINDOW_RESIZABLE May 19, 2025
@raysan5
Copy link
Owner

raysan5 commented May 19, 2025

@Moros1138 Just to clarify, here we have 3 possible situations:

  1. raylib window set to 800x450, no FLAG_WINDOW_RESIZABLE, no canvas CSS width: 100%.

A 800x450 framebuffer is drawn on canvas, placed top-left or bottom-left of the browser. Mouse works as expected.

  1. raylib window set to 800x450, no FLAG_WINDOW_RESIZABLE, canvas CSS width: 100%.

A 800x450 framebuffer is drawn on canvas, canvas takes the 100% of the browser view width. Mouse works as expected, reported within the 800x450 framebuffer limits.

  1. raylib window set to FLAG_WINDOW_RESIZABLE, no canvas CSS width: 100%.

Framebuffer scales to canvas size, taking 100% of the browser view width. Mouse works as expected, reported within the framebuffer size limits, that match canvas size limits.

All 3 situations worked as reported before this emscripten library_glfw.js update but 2. didn't after that, a patch was added to support 2. but 3. was broken, reporting incorrect mouse coordinates.

@RealDoigt
Copy link
Contributor

I'm confused, what has that to do with the proposed fix?

@Moros1138
Copy link
Author

Moros1138 commented May 19, 2025

@raysan5 i'm truly at a loss to understand. i observed, documented, and provided evidence of the problem and solved it. I'm so confused right now how what you're talking about even relates to problem this PR seeks to solve.

@raysan5
Copy link
Owner

raysan5 commented May 24, 2025

NOTE: There has been further discussion about this issue for clarification on raylib Discord.

The problem is related to libglfw.js and the addition of auto-framebuffer-scaling to align with display DPI. To solve the issue with raylib resizable window (framebuffer/canvas), the following lines should be commented:

/*
      // getBoundingClientRect() returns dimension affected by CSS, so as a result:
      // - when CSS scaling is enabled, this will fix the mouse coordinates to match the width/height of the window
      // - otherwise the CSS width/height are forced to the width/height of the GLFW window (see updateCanvasDimensions),
      //   so there is no need to adjust the position
      if (GLFW.isCSSScalingEnabled() && GLFW.active) {
        adjustedX = adjustedX * (GLFW.active.width / rect.width);
        adjustedY = adjustedY * (GLFW.active.height / rect.height);
      }
*/

That addresses the mouse-offset issue with raylib when resizable-window enabled but I guess it could breaks something else for someone out there...

@Moros1138
Copy link
Author

Moros1138 commented May 24, 2025

On my end I am unable to reproduce the issue @raysan5 is having and it's frustrating beyond measure because this PR solves the problem as presented without modifying libglfw.js file.

I also created a comprehensive test, provided before and after results.

@Moros1138
Copy link
Author

Moros1138 commented May 25, 2025

Despite not being able to reproduce the problems you demonstrate and describe, I turned my efforts to picking apart the JS file you linked... I followed

GLFW.isCSSScalingEnabled()

back to it's implementation which leads to

    isCSSScalingEnabled() {
      return !GLFW.isHiDPIAware();
    },

which leads to

    isHiDPIAware() {
      if (GLFW.active)
        return GLFW.active.attributes[0x0002200C] > 0; // GLFW_SCALE_TO_MONITOR
      else
        return false;
    },

so if GLFW_SCALE_TO_MONITOR is false, isCSSScalingEnabled() returns true.

Setting GLFW_SCALE_TO_MONITOR to true will have the effect of isCSSScalingEnabled() returning false and bypassing the troublesome bits of javascript you mention.

Edit: also if for some reason this works for 3.1.72+ but not 3.1.71-, it's easy to macro that out as well.. As I've said I am no experiencing the issues you are experiencing so I can't verify the fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
platform: Web Web platform
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants