more performant cursor

This commit is contained in:
Zutatensuppe 2021-05-23 17:53:46 +02:00
parent 5be099c61c
commit 4b7741cf46
7 changed files with 37 additions and 20 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -4,9 +4,9 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>🧩 jigsaw.hyottoko.club</title> <title>🧩 jigsaw.hyottoko.club</title>
<script type="module" crossorigin src="/assets/index.3b46c827.js"></script> <script type="module" crossorigin src="/assets/index.47e2ba43.js"></script>
<link rel="modulepreload" href="/assets/vendor.b622ee49.js"> <link rel="modulepreload" href="/assets/vendor.b622ee49.js">
<link rel="stylesheet" href="/assets/index.f09d7623.css"> <link rel="stylesheet" href="/assets/index.f7304069.css">
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>

View file

@ -28,11 +28,11 @@ async function resizeBitmap (
return await createImageBitmap(c) return await createImageBitmap(c)
} }
async function colorize( function colorizedCanvas(
bitmap: ImageBitmap, bitmap: ImageBitmap,
mask: ImageBitmap, mask: ImageBitmap,
color: string color: string,
): Promise<ImageBitmap> { ): HTMLCanvasElement {
const c = createCanvas(bitmap.width, bitmap.height) const c = createCanvas(bitmap.width, bitmap.height)
const ctx = c.getContext('2d') as CanvasRenderingContext2D const ctx = c.getContext('2d') as CanvasRenderingContext2D
ctx.save() ctx.save()
@ -45,12 +45,12 @@ async function colorize(
ctx.globalCompositeOperation = "destination-over" ctx.globalCompositeOperation = "destination-over"
ctx.drawImage(bitmap, 0, 0) ctx.drawImage(bitmap, 0, 0)
ctx.restore() ctx.restore()
return await createImageBitmap(c) return c
} }
export default { export default {
createCanvas, createCanvas,
loadImageToBitmap, loadImageToBitmap,
resizeBitmap, resizeBitmap,
colorize, colorizedCanvas,
} }

View file

@ -222,7 +222,7 @@ export async function main(
) { ) {
if (typeof window.DEBUG === 'undefined') window.DEBUG = false if (typeof window.DEBUG === 'undefined') window.DEBUG = false
const shouldDrawPlayerText = (player: Player) => { const shouldDrawPlayer = (player: Player) => {
return MODE === MODE_REPLAY || player.id !== clientId return MODE === MODE_REPLAY || player.id !== clientId
} }
@ -244,7 +244,9 @@ export async function main(
const cursor = p.d ? cursorGrab : cursorHand const cursor = p.d ? cursorGrab : cursorHand
if (p.color) { if (p.color) {
const mask = p.d ? cursorGrabMask : cursorHandMask const mask = p.d ? cursorGrabMask : cursorHandMask
cursors[key] = await Graphics.colorize(cursor, mask, p.color) cursors[key] = await createImageBitmap(
Graphics.colorizedCanvas(cursor, mask, p.color)
)
} else { } else {
cursors[key] = cursor cursors[key] = cursor
} }
@ -376,6 +378,21 @@ export async function main(
|| 'anon') || 'anon')
} }
let cursorDown: string = ''
let cursor: string = ''
let cursorState: boolean = false
const updatePlayerCursorState = (d: boolean) => {
cursorState = d
const [url, fallback] = d ? [cursorDown, 'grab'] : [cursor, 'default']
canvas.style.cursor = `url('${url}') ${CURSOR_W_2} ${CURSOR_H_2}, ${fallback}`
}
const updatePlayerCursorColor = (color: string) => {
cursorDown = Graphics.colorizedCanvas(cursorGrab, cursorGrabMask, color).toDataURL()
cursor = Graphics.colorizedCanvas(cursorHand, cursorHandMask, color).toDataURL()
updatePlayerCursorState(cursorState)
}
updatePlayerCursorColor(playerColor())
const doSetSpeedStatus = () => { const doSetSpeedStatus = () => {
if (HUD.setReplaySpeed) { if (HUD.setReplaySpeed) {
HUD.setReplaySpeed(REPLAY.speeds[REPLAY.speedIdx]) HUD.setReplaySpeed(REPLAY.speeds[REPLAY.speedIdx])
@ -522,11 +539,15 @@ export async function main(
_last_mouse_down = mouse _last_mouse_down = mouse
} }
} else if (type === Protocol.INPUT_EV_PLAYER_COLOR) {
updatePlayerCursorColor(evt[1])
} else if (type === Protocol.INPUT_EV_MOUSE_DOWN) { } else if (type === Protocol.INPUT_EV_MOUSE_DOWN) {
const pos = { x: evt[1], y: evt[2] } const pos = { x: evt[1], y: evt[2] }
_last_mouse_down = viewport.worldToViewport(pos) _last_mouse_down = viewport.worldToViewport(pos)
updatePlayerCursorState(true)
} else if (type === Protocol.INPUT_EV_MOUSE_UP) { } else if (type === Protocol.INPUT_EV_MOUSE_UP) {
_last_mouse_down = null _last_mouse_down = null
updatePlayerCursorState(false)
} else if (type === Protocol.INPUT_EV_ZOOM_IN) { } else if (type === Protocol.INPUT_EV_ZOOM_IN) {
const pos = { x: evt[1], y: evt[2] } const pos = { x: evt[1], y: evt[2] }
RERENDER = true RERENDER = true
@ -654,10 +675,10 @@ export async function main(
const texts: Array<FixedLengthArray<[string, number, number]>> = [] const texts: Array<FixedLengthArray<[string, number, number]>> = []
// Cursors // Cursors
for (const p of Game.getActivePlayers(gameId, ts)) { for (const p of Game.getActivePlayers(gameId, ts)) {
bmp = await getPlayerCursor(p) if (shouldDrawPlayer(p)) {
pos = viewport.worldToViewport(p) bmp = await getPlayerCursor(p)
ctx.drawImage(bmp, pos.x - CURSOR_W_2, pos.y - CURSOR_H_2) pos = viewport.worldToViewport(p)
if (shouldDrawPlayerText(p)) { ctx.drawImage(bmp, pos.x - CURSOR_W_2, pos.y - CURSOR_H_2)
// performance: // performance:
// not drawing text directly here, to have less ctx // not drawing text directly here, to have less ctx
// switches between drawImage and fillTxt // switches between drawImage and fillTxt

View file

@ -189,10 +189,6 @@ input:focus {
cursor: pointer; cursor: pointer;
} }
canvas.loaded {
cursor: none;
}
kbd { kbd {
background-color: #eee; background-color: #eee;
border-radius: 3px; border-radius: 3px;
@ -312,4 +308,4 @@ html.view-game body { overflow: hidden; }
html.view-replay { overflow: hidden; } html.view-replay { overflow: hidden; }
html.view-replay body { overflow: hidden; } html.view-replay body { overflow: hidden; }
html.view-replay canvas { cursor: grab; }