Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions integration-tests/template.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
body {
display: grid;
grid-template-columns: 100px minmax(0, 1fr);
overscroll-behavior: none;
}

canvas {
Expand Down
8 changes: 3 additions & 5 deletions src/WebGPU/pick.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,11 @@ export default class PickManager {
}

createMatrix(canvas: HTMLCanvasElement, canvasMatrix: Float32Array) {
const { clientWidth, clientHeight } = canvas

const tx = -(2 * (pointer.x / clientWidth) - 1)
const ty = 2 * (pointer.y / clientHeight) - 1
const tx = -(2 * (pointer.x / canvas.width) - 1)
const ty = 2 * (pointer.y / canvas.height) - 1

const pickMatrix = [
mat4.scaling([clientWidth, clientHeight, 0]), // scale to 1px convers whole shader output
mat4.scaling([canvas.width, canvas.height, 0]), // scale to 1px convers whole shader output
mat4.translation([tx, ty, 0]),
canvasMatrix,
].reduce(
Expand Down
118 changes: 113 additions & 5 deletions src/WebGPU/pointer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,25 @@ import {
on_pointer_down,
on_pointer_up,
} from '../logic/index.zig'
import clamp from '../utils/clamp'

const OUTSIDE_CANVAS = -1

enum CameraMode {
Pan,
Zoom,
None,
}

let cameraMode = CameraMode.None
let panCameraStart: Point | null = null

export const camera = {
x: 0,
y: 0,
zoom: 1,
}

export const pointer = {
x: 0,
y: 0,
Expand All @@ -20,19 +36,29 @@ export const pointer = {

export default function initMouseController(
canvas: HTMLCanvasElement,
onZoom: VoidFunction,
onStartProcessing: VoidFunction
) {
pointer.x = OUTSIDE_CANVAS
pointer.y = OUTSIDE_CANVAS

function getZigAbsolutePointer(): [number, number] {
return [
(pointer.x - camera.x) / camera.zoom,
(canvas.height - pointer.y - camera.y) / camera.zoom,
]
}

function updatePointer(e: MouseEvent) {
const rect = canvas.getBoundingClientRect()
pointer.x = e.clientX - rect.left
pointer.y = e.clientY - rect.top
const scale = canvas.width / rect.width
pointer.x = (e.clientX - rect.left) * scale
pointer.y = (e.clientY - rect.top) * scale
}

canvas.addEventListener('mouseleave', () => {
onStartProcessing()
canvas.style.cursor = 'default'

const update = () => {
pointer.x = OUTSIDE_CANVAS
Expand All @@ -50,11 +76,19 @@ export default function initMouseController(
})

canvas.addEventListener('mousemove', (e) => {
if (panCameraStart) {
updatePointer(e)

camera.x = pointer.x - panCameraStart.x
camera.y = -(pointer.y - panCameraStart.y)
return
}

onStartProcessing()

const move = () => {
updatePointer(e)
on_pointer_move(pointer.x, canvas.clientHeight - pointer.y)
on_pointer_move(...getZigAbsolutePointer())
}
if (pointer.afterPickEventsQueue.length > 0) {
pointer.afterPickEventsQueue.push({
Expand All @@ -67,16 +101,31 @@ export default function initMouseController(
})

canvas.addEventListener('mousedown', (e) => {
if (cameraMode === CameraMode.Pan) {
updatePointer(e)
panCameraStart = {
x: pointer.x - camera.x,
y: pointer.y + camera.y,
}
canvas.style.cursor = 'grabbing'
return
}
panCameraStart = null

onStartProcessing()

updatePointer(e)
pointer.afterPickEventsQueue.push({
requireNewPick: true,
cb: on_pointer_down.bind(null, pointer.x, canvas.clientHeight - pointer.y),
cb: on_pointer_down.bind(null, ...getZigAbsolutePointer()),
})
})

canvas.addEventListener('mouseup', () => {
cameraMode = CameraMode.None
panCameraStart = null
canvas.style.cursor = 'default'

onStartProcessing()

if (pointer.afterPickEventsQueue.length > 0) {
Expand All @@ -89,7 +138,66 @@ export default function initMouseController(
}
})

/* panning , supports both scroll and touch, expect Safari */
canvas.addEventListener('wheel', (event) => {
console.log(event.deltaY)
event.preventDefault()
if (cameraMode === CameraMode.Zoom) {
const oldZoom = camera.zoom
camera.zoom = clamp(camera.zoom - event.deltaY * 0.005, 0.1, 20)
onZoom()

const zoomFactor = camera.zoom / oldZoom

camera.x = pointer.x - (pointer.x - camera.x) * zoomFactor
const realY = canvas.height - pointer.y
camera.y = realY - (realY - camera.y) * zoomFactor
} else {
camera.x -= event.deltaX
camera.y += event.deltaY
}
})
// pointer.zoom = clamp(pointer.zoom + event.deltaY * 0.01, 0.1, 100)

document.body.addEventListener('keydown', (event) => {
if (event.code === 'Space') {
event.preventDefault()
if (cameraMode !== CameraMode.Pan) {
canvas.style.cursor = 'grab'
cameraMode = CameraMode.Pan
}
} else if (event.key === 'Alt') {
event.preventDefault()
cameraMode = CameraMode.Zoom
}
})
document.body.addEventListener('keyup', (event) => {
if (event.code === 'Space' || event.key === 'Alt') {
cameraMode = CameraMode.None
}
if (event.code === 'Space' && panCameraStart === null) {
canvas.style.cursor = 'default'
}
})

let lastTouchY: number

canvas.addEventListener('touchstart', (event) => {
if (event.touches.length === 2) {
event.preventDefault()

lastTouchY = event.touches[0].clientY
}
})

canvas.addEventListener('touchmove', (event) => {
if (event.touches.length === 2) {
event.preventDefault()

const delta = lastTouchY - event.touches[0].clientY
lastTouchY = event.touches[0].clientY

camera.zoom = clamp(camera.zoom - delta * 0.01, 0.1, 20)
onZoom()
}
})
}
7 changes: 6 additions & 1 deletion src/getCanvasMatrix.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import mat4 from 'utils/mat4'
import { camera } from 'WebGPU/pointer'

export default function getCanvasMatrix(canvas: HTMLCanvasElement) {
const matrix = mat4.ortho(
const ortho = mat4.ortho(
0, // left
canvas.width, // right
0, // bottom
canvas.height, // top
1, // near
-1 // far
)
// when we implement zoom, it might be actually easier to scale our controls/icons down and this matrix up
// instead of implement zoom for every signle effect I guess
const translated = mat4.translate(ortho, [camera.x, camera.y, 0])
const matrix = mat4.scale(translated, [camera.zoom, camera.zoom, 1])

return matrix
}
25 changes: 20 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ import {
connect_on_asset_selection_callback,
destroy_state,
import_icons,
update_render_scale,
} from './logic/index.zig'
import initMouseController from 'WebGPU/pointer'
import initMouseController, { camera } from 'WebGPU/pointer'
import IconsPng from '../msdf/output/icons.png'
import IconsJson from '../msdf/output/icons.json'
import getDefaultPoints from 'utils/getDefaultPoints'
Expand Down Expand Up @@ -58,7 +59,11 @@ export default async function initCreator(
updateProcessing()
})

init_state(canvas.clientWidth, canvas.clientHeight)
const projectWidth = canvas.clientWidth / 2
const projectHeight = canvas.clientHeight / 2

init_state(projectWidth, projectHeight)
// rotation doesnt work
const context = canvas.getContext('webgpu')
if (!context) throw Error('WebGPU from canvas needs to be always provided')

Expand All @@ -70,13 +75,23 @@ export default async function initCreator(
// will copy out of the swapchain texture.
})

function updateRenderScale() {
update_render_scale(canvas.width / (canvas.clientWidth * camera.zoom))
}

let wasInitialOffsetSet = false
canvasSizeObserver(canvas, device, () => {
// state.needsRefresh = true
if (wasInitialOffsetSet === false) {
camera.x = (canvas.width - projectWidth) / 2
camera.y = (canvas.height - projectHeight) / 2
wasInitialOffsetSet = true
}
updateRenderScale()
})

initPrograms(device, presentationFormat)

initMouseController(canvas, () => {
initMouseController(canvas, updateRenderScale, () => {
isMouseEventProcessing = true
updateProcessing()
})
Expand All @@ -100,7 +115,7 @@ export default async function initCreator(

const addImage: CreatorAPI['addImage'] = (url) => {
const textureId = Textures.add(url, (width, height) => {
const points = getDefaultPoints(width, height, canvas.clientWidth, canvas.clientHeight)
const points = getDefaultPoints(width, height, projectWidth, projectHeight)
add_asset(0 /* no id yet, needs to be generated */, points, textureId)
})
}
Expand Down
1 change: 1 addition & 0 deletions src/logic/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ declare module '*.zig' {
export const on_pointer_up: () => void
export const on_pointer_move: (x: number, y: number) => void
export const on_pointer_leave: VoidFunction
export const update_render_scale: (render_scale: number) => void

export const connect_web_gpu_programs: (programs: {
draw_texture: (vertexData: ZigF32Array, texture_id: number) => void
Expand Down
Loading