-
Notifications
You must be signed in to change notification settings - Fork 31
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: respect device screen DPI #49
base: main
Are you sure you want to change the base?
Conversation
|
@RobLoach #31 seems more like a hack rather than a solution. Basically, here is a situation identical to what occurs in legacy apps in Windows with HiDPI displays. Browser renders canvas at its original size and then upscales it to a DPI value and this produces a blurry image. The problem becomes much worse with fractional scaling. This PR basically adds HiDPI support as per common guidelines. |
Just tried it out locally, and it certainly looks nicer. Great work. I much prefer this solution over the other. |
I definitely agree that it looks better than #31 :) in some cases but Also.. if you started on zoomed out screen and then zoom in, its even more blurred So I'm not sure if rendering at a higher resolution is the right solution |
@adaxiik regarding zooming issue - although this looks like an edge case, probably this can be solved by tracking DPI changes. Right now, size and scaling are applied only once but this can be addressed in the next PR. Thanks for pointing out |
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 think always using hidpi is not a good idea, as that requires significant processing power on some devices for some examples (i.e. phone with the tsoding_snake example). Therefore I would suggest adding a toggle to the index.html. Also I think fixing the zoom issue could be fixed in this PR as well.
What phone do you mean as a minimal requirement? Galaxy S10 which is quite an old phone model should run that demo easily, especially considering the simplicity of that demo. Usually games have different configurations depending on a target but IMHO this is out of scope of the PR.
I would suggest adopting a responsive design in that case to improve support of mobile devices as well.
I'll do that. |
I am using a Pixel 7 Pro and get about 6 FPS in the Also, I tried to help by using the "propose change" feature, but I guess I am bad at GitHub, so here is a patch if that helps you: Patchdiff --git a/index.html b/index.html
index 960a2cd..223f18c 100644
--- a/index.html
+++ b/index.html
@@ -64,6 +64,8 @@
<select id="raylib-example-select" onchange="startRaylib(this.value)">
<!-- This is populated by js -->
</select>
+ <label for="raylib-hidpi">HiDPI:</label>
+ <input type="checkbox" id="raylib-hidpi" onchange="setHiDpi(this.checked)">
<canvas id="game"></canvas>
<script>
const wasmPaths = {
@@ -88,7 +90,13 @@
const { protocol } = window.location;
const isHosted = protocol !== "file:";
let raylibJs = undefined;
-
+ let hidpi = false;
+ function setHiDpi(newHidpi) {
+ hidpi = newHidpi;
+ if (raylibJs !== undefined) {
+ raylibJs.hidpi = hidpi;
+ }
+ }
function startRaylib(selectedWasm){
var queryParams = new URLSearchParams(window.location.search);
queryParams.set("example", selectedWasm);
@@ -100,6 +108,7 @@
raylibJs.stop();
}
raylibJs = new RaylibJs();
+ raylibJs.hidpi = hidpi;
raylibJs.start({
wasmPath: `wasm/${selectedWasm}.wasm`,
canvasId: "game",
diff --git a/raylib.js b/raylib.js
index 49f31a0..5a51335 100644
--- a/raylib.js
+++ b/raylib.js
@@ -30,11 +30,13 @@ class RaylibJs {
//
// It would be nice to have a better approach...
#FONT_SCALE_MAGIC = 0.65;
+ #dpi = 1;
+ #hidpi = false;
+ #removeDpiListener = () => {};
#reset() {
this.height = 0;
this.width = 0;
- this.dpi = window.devicePixelRatio || 1;
this.previous = undefined;
this.wasm = undefined;
this.ctx = undefined;
@@ -48,6 +50,33 @@ class RaylibJs {
this.images = [];
this.quit = false;
}
+
+ set dpi(dpi) {
+ this.#dpi = dpi;
+ this.#resize();
+ }
+
+ get dpi() {
+ return this.#dpi;
+ }
+
+ set hidpi(hidpi) {
+ this.#hidpi = hidpi;
+ this.#resize();
+ }
+
+ get hidpi() {
+ return this.#hidpi;
+ }
+
+ #resize() {
+ if (this.ctx) {
+ const scale = this.hidpi ? this.dpi : 1;
+ this.ctx.canvas.height = this.height * scale;
+ this.ctx.canvas.width = this.width * scale;
+ this.ctx.setTransform(scale, 0, 0, scale, 0, 0);
+ }
+ }
constructor() {
this.#reset();
@@ -55,6 +84,7 @@ class RaylibJs {
stop() {
this.quit = true;
+ this.#removeDpiListener();
}
async start({ wasmPath, canvasId }) {
@@ -65,6 +95,9 @@ class RaylibJs {
const canvas = document.getElementById(canvasId);
this.ctx = canvas.getContext("2d");
+ this.#removeDpiListener = onPixelRatio((dpi) => {
+ this.dpi = dpi;
+ });
if (this.ctx === null) {
throw new Error("Could not create 2d canvas context");
}
@@ -112,18 +145,15 @@ class RaylibJs {
InitWindow(width, height, title_ptr) {
// Adjust viewport size according to screen DPI for HiDPI screens.
// see: https://web.dev/articles/canvas-hidipi
- const { canvas } = this.ctx;
- canvas.height = height * this.dpi;
- canvas.width = width * this.dpi;
- canvas.style.height = `${height}px`;
- canvas.style.width = `${width}px`;
- this.ctx.scale(this.dpi, this.dpi);
+ this.ctx.canvas.style.height = `${height}px`;
+ this.ctx.canvas.style.width = `${width}px`;
// Store original size for GetScreenWidth and GetScreenHeight calls.
// Necessary as some platforms allow fractional scaling (e.g 1.3)
// and dividing canvas size by DPR can cause rounding issues.
this.height = height;
this.width = width;
+ this.#resize();
const buffer = this.wasm.instance.exports.memory.buffer;
document.title = cstr_by_ptr(buffer, title_ptr);
@@ -525,3 +555,19 @@ function getColorFromMemory(buffer, color_ptr) {
const [r, g, b, a] = new Uint8Array(buffer, color_ptr, 4);
return color_hex_unpacked(r, g, b, a);
}
+
+function onPixelRatio(fn) {
+ let remove = () => {};
+ function update() {
+ remove();
+ const mqString = `(resolution: ${window.devicePixelRatio}dppx)`;
+ const media = matchMedia(mqString);
+ media.addEventListener("change", update);
+ remove = () => {
+ media.removeEventListener("change", update);
+ }
+ fn(window.devicePixelRatio);
+ }
+ update();
+ return () => remove();
+}
|
This small PR fixes the blurness issue on HiDPI screens by upscaling a canvas to match a display DPI.
This affects mobile devices and laptops with a resolution above 1080p.
See: https://web.dev/articles/canvas-hidipi
Closes: #50
Demo
Before
Blurred text issue example on a HiDPI screen
After
Canvas respects screen DPI