-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Fix glutReshapeFunc not being called (closes #7133) #9835
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
Fix glutReshapeFunc not being called (closes #7133) #9835
Conversation
Thank you for submitting a pull request! If this is your first PR, make sure to add yourself to AUTHORS. |
Thanks @haberbyte ! Would be good to improve this code. At first glance this looks good, but I'll need to read this more carefully. First thing, though, can you see the test failures on CI here locally? Let me know if you need help debugging those. |
Ah yes I see the failures and will try to fix them over the weekend, thanks! Will ping you once i think this is in a good state. |
@kripken Ok CI is now passing. I removed the deprecated requestFullScreen and cancelFullScreen stuff as well. Not sure if that is ok to do, but i figured it would be since it is marked deprecated for years now. Let me know if you would rather have that in a separate PR. |
@haberbyte I think that should be in a separate PR, yes. While it's been deprecated for a while, some users will break by that change. We should at least have it in a separate commit so bisection is more clear. But thanks for doing it, it's a good idea! |
Not sure why I had to retrigger the build for it to pass, but the failure was unrelated to the changes here. I removed the deprecated functions in a separate PR here: #9861 |
src/library_glut.js
Outdated
window.addEventListener("mouseup", GLUT.onMouseButtonUp, true); | ||
// IE9, Chrome, Safari, Opera | ||
window.addEventListener("mousewheel", GLUT.onMouseWheel, true); | ||
window.addEventListener("mousewheel", GLUT.onMouseWheel, { passive: false }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this changes the capture property, doesn't it? shouldn't we add capture: true
to be backwards compatible? or is this part of the fix?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right. The "passive: false" change is not part of the fix. This is just to silence Chrome's warning about passive event listeners trying to preventDefault.
|
||
window.addEventListener("resize", GLUT.onResize, true); | ||
|
||
Browser.resizeListeners.push(function(width, height) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need both a resizeListener and a listener on the window itself? I'm not sure why the resizeListener isn't enough by itself. (If I'm missing something here, maybe adding a comment here would help other people reading the code in the future?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The bug i was hitting is that the reshape function would not be called.
I have a canvas element styled with CSS to 100% width/height, so a simple resizing of the window would update the size of the canvas element.
I am not too familiar with what the library_browser.js does out of the box, but it seems like it does not handle those resizes of the canvas.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, thanks.
Reading the existing code some more, it looks like none of the other input systems (sdl, etc.) listens for window resize events. And so this looks like a general issue, that maybe the resizeListeners should be called for.
And IIUC the CSS you describe, then your canvas spans the whole window, so I think a resize event should be fired on the canvas, if the window is resized. So listening on the canvas should be enough - but it looks like we don't do that either - we just look for fullscreen resizing.
In summary how about if in library_browser.js, in the init
function, we add an event listener for the resize event, at the very end to the canvas, that calls Browser.updateResizeListeners
(alongside the other events listened to in the block with if (canvas) {
. Would that fix your use case? If so I think it might be a more general fix.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would fix my case.
I will implement the more general fix then (within this PR I guess, so we can keep the discussion).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good! Yes, in this same PR is simplest and best, I think.
The deletion of the Re-opening and re-targeting to master. |
This issue has been automatically marked as stale because there has been no activity in the past year. It will be closed automatically if no further activity occurs in the next 30 days. Feel free to re-open at any time if this issue is still relevant. |
Any chance this could be re-based and landed still? |
Sorry for the force pushes, had some trouble getting this rebased right. But i think now it is correct. |
Thanks @haberbyte ! I think this fix is correct. But it's a little odd to me that we didn't have more bug reports on this, as the fix here is quite general - more than glut, it's basically a fix for all the UI APIs. That makes me wonder if I'm not missing something here - ? It would be good to add a test for this. It could be like |
I'm the author of the original issue (#7133 - sorry for disappearing!) and I'm also curious, why a general UI fix is needed here and the fix is not limited to GLUT. Maybe #7133 and #9835 are in fact different problems? In regards to #7133, I never encountered any window resizing issues with SDL+OGLES code. For example, https://erik-larsen.github.io/emscripten-sdl2-ogles2/hello_triangle.html works fine with window resizing by watching for SDL_WINDOWEVENT_SIZE_CHANGED and then updating the GL side with a glViewport call:
GLUT on the other hand, never receives any window resize event (not on window init, nor subsequent resizes). Part of the problem here may be that the html generated by
I did try the fix proposed by @haberbyte, but this still doesn't seem to fix my case of tests/hello_world_gles.c with the above resizable-canvas html. By the way, this is precisely the same HTML I'm using for SDL+OGLES code, which as mentioned above, works fine in getting resize events. I know @haberbyte you mentioned you weren't working with GLUT any more. I'd be glad to keep looking at this, at least for the case of getting window resize events into GLUT. |
Oof, please disregard my last wall of text. After more code research and re-reading this thread, I do believe @haberbyte has the right fix. It is consistent with this GLUT change from 2013. I just need to figure out why it is not working for my case. |
I figured out why my case is still not working. The fix here ( So, it seems an additional fix is needed here, that updates the canvas width and height on window resizing. |
So the following solves the problem completely for me (canvas = 100% window case), although I am not sure about other cases: library_glut.js:
library_browser.js:
|
When using GLUT and the window is resized with the canvas dependent upon it due to CSS scaling, the result is a stretched canvas with blocky pixel scaling. Here's a CSS scaling example: <style> canvas { position: fixed; width: 75%; height: 75%; } </style> <canvas id="canvas"></canvas> While position fixed isn't strictly necessary, it more readily shows the problem as it makes the canvas size directly dependent upon the browser window. For comparison, SDL behaves properly in this same scenario. ## Fix Three issues were found: 1. On window resize, glutReshapeFunc is never called. 2. Even with glutReshapeFunc working, the dimensions passed to it do not include CSS scaling. Specifically, the canvas width and height are never updated with the canvas clientWidth and clientHeight, which does include scaling. 3. On GLUT program startup, glutMainLoop calls glutReshapeWindow, which is slightly problematic for the case of loading the page while already in fullscreen. This is a problem because, while an initial resize is needed on startup, glutReshapeWindow also forces an exit from fullscreen mode. Here are the proposed fixes: 1. Register a new resize callback `GLUT.reshapeHandler` using `window.addEventListener`, replacing `Browser.resizeListeners.push`. Previous work in this area (see below) utilized `resizeListeners`, however this fix takes a different route that is self-contained and I think simpler: - Using `window.addEventListener` keeps the fix entirely within `libglut.js`, avoiding any `libbrowser.js` changes as in previous attempts. As well, `updateResizeListeners` doesn't pass CSS-scaled canvas dimensions, so changing `updateResizeListeners` implementation might be necessary and this could impact other non-GLUT clients, going beyond this GLUT-only fix. - Since `glutInit` already utilizes `window.addEventListener` for all other event handling, doing the same for the resize event seems consistent and simpler, as it avoids mixing event handling methods for GLUT. 2. Create a new resize callback function, `GLUT.reshapeHandler`, which does the following: - Updates `canvas` dimensions (via `Browser.setCanvasSize`) to `canvas.clientWidth` and `clientHeight`, so that CSS scaling is accounted for. If no CSS scaling is present, `clientWidth` and `clientHeight` match `canvas.width` and `height`, so these values are safe to use in all cases, scaling or not. - After updating the canvas size, pass `clientWidth` and `clientHeight` to `glutReshapeFunc`. This is needed so that GLUT reshape callbacks can properly update their viewport transform by calling `glViewport` with the actual canvas dimensions. 3. At GLUT startup in `glutMainLoop`, call `GLUT.reshapeHandler` instead of `glutReshapeWindow`. - As mentioned above, `glutReshapeWindow` has an unwanted side effect of always forcing an exit from fullscreen (and this is by design, according to the [GLUT API](https://www.opengl.org/resources/libraries/glut/spec3/node23.html)). ## Testing Manual testing: 1. Window resizing with no CSS, CSS scaling, CSS pixel dimensions, and a mix of these for canvas width and height. 2. Entering and exiting fullscreen, and loading a page while already in fullscreen. 3. No DPI testing done (window.devicePixelRatio != 1), as GLUT is not currently DPI aware and this fix does not address it. I did confirm on Retina Mac that this fix doesn't make this issue any better or worse. Automated tests: 1. Added test/browser/test_glut_resize.c, with tests to assert canvas size matches target size under various scenarios (no CSS, CSS scaling, CSS pixel dimensions, and a mix of these), as well as canvas size always matching canvas client size (clientWidth and clientHeight). 2. Since programmatic browser window resizing is not allowed for security reasons, these tests dispatch a resize event after each CSS style change as a workaround. 3. Also added tests to assert canvas size consistency after glutMainLoop and glutReshapeWindow API calls. ## Related work All the previous work in this area worked toward enabling GLUT resize callbacks via Emscripten’s built-in event handling (specifically `Browser.resizeListeners` and `updateResizeListeners`). As mentioned above, this fix takes a different approach that is entirely self-contained within `libglut.js`. This 2013 [commit](6d6490e) added `GLUT.reshapeFunc` to `Browser.resizeListeners`, presumably to handle window resizing. However there is no test code with that commit, and as of current Emscripten, `updateResizeListeners()` is never called on window resizing with GLUT programs, so this code is currently a no-op. [Issue 7133](#7133) (that I logged in 2018, hi again!) got part of the way on a fix, but used `glutReshapeWindow` which has the previously mentioned side effect of exiting fullscreen. This was closed unresolved. [PR 9835](#9835) proposed a fix for 7133. Also closed unresolved, this fix involved modifying `libbrowser.js` in order to get resize callbacks to GLUT via `resizeListeners`. While this got resize callbacks working, in my testing it didn’t pass CSS-scaled canvas size in the callback (the all-important clientWidth and clientHeight). I also looked at how SDL handles resizing, which uses `resizeEventListeners`, but decided the more straightforward fix was to use `addEventListener`. Last, I looked at [GLFW CSS scaling test](https://github.com/emscripten-core/emscripten/blob/main/test/browser/test_glfw3_css_scaling.c) which was helpful in writing the automated tests and also to confirm that no DPI ratio work is addressed by this fix. Fixes: #7133 --------- Co-authored-by: Sam Clegg <sbc@chromium.org>
This fixes the issue in #7133 for me and the reshape function callback is called on resize.
I also added { passive: false } to the mouse event listeners as Chrome is complaining about it.
I also noticed some quite old "requestFullScreen" deprecations, should i remove those methods as well? I would like to cleanup the glut library code a bit.