init
This commit is contained in:
commit
c6863f2bfc
34 files changed
+6909
No files matched your search
@@ -0,0 +1,86 @@
|
||||
import type { Asset, Scene } from '@/types/scene'
|
||||
import { sampleLayer } from './interpolate'
|
||||
|
||||
export async function loadSceneImages(scene: Scene): Promise<Record<string, HTMLImageElement>> {
|
||||
const result: Record<string, HTMLImageElement> = {}
|
||||
const images = scene.assets.filter(
|
||||
(a): a is Extract<Asset, { kind: 'image' }> => a.kind === 'image',
|
||||
)
|
||||
await Promise.all(
|
||||
images.map(
|
||||
(a) =>
|
||||
new Promise<void>((resolve) => {
|
||||
const img = new Image()
|
||||
img.crossOrigin = 'anonymous'
|
||||
img.onload = () => {
|
||||
result[a.id] = img
|
||||
resolve()
|
||||
}
|
||||
img.onerror = () => resolve()
|
||||
img.src = a.src
|
||||
}),
|
||||
),
|
||||
)
|
||||
return result
|
||||
}
|
||||
|
||||
export function drawSceneFrame(
|
||||
ctx: CanvasRenderingContext2D,
|
||||
scene: Scene,
|
||||
time: number,
|
||||
images: Record<string, HTMLImageElement>,
|
||||
) {
|
||||
const lw = scene.canvas.width
|
||||
const lh = scene.canvas.height
|
||||
|
||||
ctx.save()
|
||||
ctx.beginPath()
|
||||
ctx.rect(0, 0, lw, lh)
|
||||
ctx.clip()
|
||||
ctx.fillStyle = scene.canvas.background
|
||||
ctx.fillRect(0, 0, lw, lh)
|
||||
|
||||
const assetMap = new Map<string, Asset>()
|
||||
for (const a of scene.assets) assetMap.set(a.id, a)
|
||||
|
||||
for (const layer of scene.layers) {
|
||||
if (!layer.visible) continue
|
||||
const asset = assetMap.get(layer.assetId)
|
||||
if (!asset) continue
|
||||
const p = sampleLayer(layer, time)
|
||||
|
||||
ctx.save()
|
||||
ctx.globalAlpha *= p.opacity
|
||||
ctx.translate(p.x, p.y)
|
||||
ctx.rotate((p.rotation * Math.PI) / 180)
|
||||
ctx.scale(p.scaleX, p.scaleY)
|
||||
|
||||
if (asset.kind === 'rect') {
|
||||
const offX = layer.offsetX ?? asset.width / 2
|
||||
const offY = layer.offsetY ?? asset.height / 2
|
||||
ctx.fillStyle = p.fill ?? asset.fill
|
||||
ctx.fillRect(-offX, -offY, asset.width, asset.height)
|
||||
} else if (asset.kind === 'circle') {
|
||||
ctx.fillStyle = p.fill ?? asset.fill
|
||||
ctx.beginPath()
|
||||
ctx.arc(0, 0, asset.radius, 0, Math.PI * 2)
|
||||
ctx.fill()
|
||||
} else if (asset.kind === 'text') {
|
||||
ctx.fillStyle = p.fill ?? asset.fill
|
||||
ctx.font = `${asset.fontSize}px sans-serif`
|
||||
ctx.textBaseline = 'top'
|
||||
ctx.fillText(asset.text, 0, 0)
|
||||
} else if (asset.kind === 'image') {
|
||||
const img = images[asset.id]
|
||||
if (img) {
|
||||
const offX = layer.offsetX ?? asset.width / 2
|
||||
const offY = layer.offsetY ?? asset.height / 2
|
||||
ctx.drawImage(img, -offX, -offY, asset.width, asset.height)
|
||||
}
|
||||
}
|
||||
|
||||
ctx.restore()
|
||||
}
|
||||
|
||||
ctx.restore()
|
||||
}
|
||||
Reference in new issue
Block a user