webgpu improvements
This commit is contained in:
parent
5a75571ffd
commit
8347467e1e
18 changed files with 1932 additions and 153 deletions
|
|
@ -168,15 +168,25 @@ function setValue(cookie, valPtr, valLen) {
|
|||
// so removeEventListener can re-find it. C++-side handler id counters
|
||||
// are per-kind, so a per-kind suffix is what makes the keys unique.
|
||||
|
||||
// devicePixelRatio scaling factor. dom-webgpu.js sets window.crafter_dpr
|
||||
// during its canvas sync so this side and the GPU side agree on a single
|
||||
// physical-pixel coordinate space. Fallback to the live DPR if no GPU
|
||||
// bridge ran (pure-CppDOM apps); ultimately fallback to 1 so non-HiDPI
|
||||
// browsers behave as before.
|
||||
function __dpr() {
|
||||
return window.crafter_dpr || window.devicePixelRatio || 1;
|
||||
}
|
||||
|
||||
function __makeMouseListenerPair(kind, eventName, exportName) {
|
||||
return {
|
||||
add(cookie, id) {
|
||||
const el = __jsmemory.get(cookie);
|
||||
if (!el) return;
|
||||
const handler = (event) => {
|
||||
const s = __dpr();
|
||||
__wasm()[exportName](id,
|
||||
event.clientX, event.clientY,
|
||||
event.screenX, event.screenY,
|
||||
event.clientX * s, event.clientY * s,
|
||||
event.screenX * s, event.screenY * s,
|
||||
event.button, event.buttons,
|
||||
event.altKey, event.ctrlKey, event.shiftKey, event.metaKey);
|
||||
};
|
||||
|
|
@ -317,7 +327,10 @@ const __resizePair = {
|
|||
// Resize is window-global in CppDOM. Mirror that: attach to `window`
|
||||
// regardless of which element the C++ caller passed.
|
||||
add(cookie, id) {
|
||||
const handler = () => __wasm().ExecuteResizeHandler(id, window.innerWidth, window.innerHeight);
|
||||
const handler = () => {
|
||||
const s = __dpr();
|
||||
__wasm().ExecuteResizeHandler(id, window.innerWidth * s, window.innerHeight * s);
|
||||
};
|
||||
__listenerHandlers.set(`${cookie}-${id}-resize`, handler);
|
||||
window.addEventListener("resize", handler);
|
||||
},
|
||||
|
|
@ -345,9 +358,10 @@ const __wheelPair = {
|
|||
add(cookie, id) {
|
||||
const el = __jsmemory.get(cookie); if (!el) return;
|
||||
const handler = (event) => {
|
||||
const s = __dpr();
|
||||
__wasm().ExecuteWheelHandler(id,
|
||||
event.deltaX, event.deltaY, event.deltaZ, event.deltaMode,
|
||||
event.clientX, event.clientY, event.screenX, event.screenY,
|
||||
event.clientX * s, event.clientY * s, event.screenX * s, event.screenY * s,
|
||||
event.button, event.buttons,
|
||||
event.altKey, event.ctrlKey, event.shiftKey, event.metaKey);
|
||||
};
|
||||
|
|
@ -378,11 +392,97 @@ function domAttachWindow(windowHandle) {
|
|||
if (fn) fn(__windowAttachedHandle, ...args);
|
||||
};
|
||||
|
||||
__windowListeners.mousemove = (e) => fire("__crafterDom_mouseMove", [e.clientX, e.clientY]);
|
||||
__windowListeners.mousedown = (e) => fire("__crafterDom_mouseDown", [e.button]);
|
||||
__windowListeners.mouseup = (e) => fire("__crafterDom_mouseUp", [e.button]);
|
||||
// Synthetic absolute position for pointer-lock mode. While the
|
||||
// pointer is locked, browsers fire mousemove events with movementX/Y
|
||||
// deltas instead of meaningful clientX/Y, and the cursor is hidden +
|
||||
// captured by the canvas (no window-edge clamp). We accumulate the
|
||||
// deltas into a synthetic position and feed *that* to the C++ side,
|
||||
// so the existing `currentMousePos - lastMousePos` delta computation
|
||||
// keeps working unchanged. Initialised to the cursor position the
|
||||
// moment lock is acquired.
|
||||
let __ptrLockSyntheticX = 0;
|
||||
let __ptrLockSyntheticY = 0;
|
||||
const __isPointerLocked = () =>
|
||||
document.pointerLockElement !== null &&
|
||||
document.pointerLockElement !== undefined;
|
||||
|
||||
// pointermove (not mousemove) so we can pull sub-frame events out of
|
||||
// `getCoalescedEvents()`. Browsers normally collapse multiple raw
|
||||
// mouse events between paint frames into a single event you'd see
|
||||
// via `mousemove`; PointerEvent.getCoalescedEvents() returns the raw
|
||||
// pre-coalesced list. Summing those gives a higher-resolution delta
|
||||
// per frame than the single coalesced movementX/Y. PointerEvent also
|
||||
// delivers fractional movementX from high-precision mice on Chromium.
|
||||
__windowListeners.mousemove = (e) => {
|
||||
const s = __dpr();
|
||||
const locked = __isPointerLocked();
|
||||
if (locked) {
|
||||
// Accumulate over every sub-frame event the browser had
|
||||
// queued up. `getCoalescedEvents` is the spec-correct way
|
||||
// to access raw input between rAF ticks. Some browsers
|
||||
// return an empty list — fall back to the top-level event.
|
||||
let dx = 0, dy = 0;
|
||||
const sub = (typeof e.getCoalescedEvents === "function")
|
||||
? e.getCoalescedEvents() : null;
|
||||
if (sub && sub.length > 0) {
|
||||
for (let i = 0; i < sub.length; i++) {
|
||||
dx += sub[i].movementX;
|
||||
dy += sub[i].movementY;
|
||||
}
|
||||
} else {
|
||||
dx = e.movementX;
|
||||
dy = e.movementY;
|
||||
}
|
||||
// No DPR scaling in pointer-lock: position is synthetic and
|
||||
// there's no UI hit-test using it. DPR-scaling here only
|
||||
// rounds finer movements up to multiples of `dpr`, which is
|
||||
// pure quantization loss for aim controls.
|
||||
__ptrLockSyntheticX += dx;
|
||||
__ptrLockSyntheticY += dy;
|
||||
fire("__crafterDom_mouseMove",
|
||||
[__ptrLockSyntheticX, __ptrLockSyntheticY]);
|
||||
} else {
|
||||
fire("__crafterDom_mouseMove", [e.clientX * s, e.clientY * s]);
|
||||
}
|
||||
};
|
||||
__windowListeners.mousedown = (e) => {
|
||||
// Right-click holds engage pointer lock — typical FPS-camera
|
||||
// convention. Acquiring on any click (the previous policy) made
|
||||
// menus annoying: clicking a button hid the cursor mid-flow. Now
|
||||
// the cursor stays free for clicks/menus until the user holds
|
||||
// RMB to actively look around. Browsers require lock requests
|
||||
// from user gestures, which mousedown satisfies.
|
||||
if (e.button === 2 && !__isPointerLocked()) {
|
||||
const target = document.body;
|
||||
if (target && target.requestPointerLock) {
|
||||
target.requestPointerLock();
|
||||
// Seed the synthetic position from the click point so
|
||||
// there's no jump when the lock starts producing deltas.
|
||||
__ptrLockSyntheticX = e.clientX;
|
||||
__ptrLockSyntheticY = e.clientY;
|
||||
}
|
||||
}
|
||||
fire("__crafterDom_mouseDown", [e.button]);
|
||||
};
|
||||
__windowListeners.mouseup = (e) => {
|
||||
// Release lock on RMB up — cursor reappears at the seed point
|
||||
// for clicks/menus until the next RMB hold.
|
||||
if (e.button === 2 && __isPointerLocked()) {
|
||||
document.exitPointerLock();
|
||||
}
|
||||
fire("__crafterDom_mouseUp", [e.button]);
|
||||
};
|
||||
__windowListeners.wheel = (e) => fire("__crafterDom_wheel", [e.deltaY]);
|
||||
__windowListeners.contextmenu = (e) => { e.preventDefault(); };
|
||||
__windowListeners.pointerlockchange = () => {
|
||||
// Reset the synthetic accumulator when lock is released so the
|
||||
// next acquisition starts cleanly. The C++ side will see one
|
||||
// small jump back to the real cursor position on release.
|
||||
if (!__isPointerLocked()) {
|
||||
__ptrLockSyntheticX = 0;
|
||||
__ptrLockSyntheticY = 0;
|
||||
}
|
||||
};
|
||||
|
||||
// Keyboard events go through the document so they fire even when no
|
||||
// input element is focused. event.code is the layout-independent
|
||||
|
|
@ -400,16 +500,24 @@ function domAttachWindow(windowHandle) {
|
|||
__wasm().WasmFree(codePtr);
|
||||
};
|
||||
|
||||
__windowListeners.resize = () => fire("__crafterDom_resize", [window.innerWidth, window.innerHeight]);
|
||||
__windowListeners.resize = () => {
|
||||
const s = __dpr();
|
||||
fire("__crafterDom_resize", [window.innerWidth * s, window.innerHeight * s]);
|
||||
};
|
||||
__windowListeners.beforeunload = () => fire("__crafterDom_close", []);
|
||||
|
||||
document.addEventListener("mousemove", __windowListeners.mousemove);
|
||||
// pointermove (not mousemove) so the handler receives PointerEvents
|
||||
// and can use getCoalescedEvents() to recover sub-frame motion. The
|
||||
// handler's variable name stays "mousemove" — it's the same JS object,
|
||||
// just bound to a different event type.
|
||||
document.addEventListener("pointermove", __windowListeners.mousemove);
|
||||
document.addEventListener("mousedown", __windowListeners.mousedown);
|
||||
document.addEventListener("mouseup", __windowListeners.mouseup);
|
||||
document.addEventListener("wheel", __windowListeners.wheel);
|
||||
document.addEventListener("contextmenu", __windowListeners.contextmenu);
|
||||
document.addEventListener("keydown", __windowListeners.keydown);
|
||||
document.addEventListener("keyup", __windowListeners.keyup);
|
||||
document.addEventListener("pointerlockchange", __windowListeners.pointerlockchange);
|
||||
window .addEventListener("resize", __windowListeners.resize);
|
||||
window .addEventListener("beforeunload",__windowListeners.beforeunload);
|
||||
}
|
||||
|
|
@ -418,8 +526,8 @@ function domSetTitle(titlePtr, titleLen) {
|
|||
document.title = __readUtf8(titlePtr, titleLen);
|
||||
}
|
||||
|
||||
function domGetInnerWidth() { return window.innerWidth; }
|
||||
function domGetInnerHeight() { return window.innerHeight; }
|
||||
function domGetInnerWidth() { return Math.round(window.innerWidth * __dpr()); }
|
||||
function domGetInnerHeight() { return Math.round(window.innerHeight * __dpr()); }
|
||||
|
||||
// ─── requestAnimationFrame loop ───────────────────────────────────────
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue