blob: 5da8424639a64f1c77ec19ed3d3beef5a8163994 [file] [log] [blame]
<canvas id="canvas" style="width:960; height:540" width=1920 height=1080></canvas>
<script src="rive.js"></script>
<script src="webgpu_player.js"></script>
<script>
async function loadRiveAsset(args)
{
const file = RiveLoadFile(await download(args.url));
let artboard;
if (args.artboard) {
artboard = file.artboardNamed(args.artboard);
} else {
artboard = file.artboardDefault();
}
let asset;
if (args.stateMachine) {
asset = artboard.stateMachineNamed(args.stateMachine);
} else if (args.animation) {
asset = artboard.animationNamed(args.animation);
} else {
asset = artboard.defaultStateMachine();
}
asset.artboard = artboard;
asset.file = file;
return asset;
}
const data = {};
const assets = {};
async function wgpuDataInitialize(wgpu, canvas, adapter, device)
{
data.device = device;
data.queue = device.queue;
data.width = canvas.width;
data.height = canvas.height;
data.wgpu = wgpu;
// Rive has to be initialized before loading assets.
const invertY = false
RiveInitialize(data.device, data.queue, data.width, data.height, invertY, RIVE_PLS_TYPE_NONE);
assets.skills = await loadRiveAsset({url:"skills_demov1.riv", stateMachine:"Motion"});
assets.santa = await loadRiveAsset({url:"Santa_Claus.riv"});
assets.coffee = await loadRiveAsset({url:"Coffee_Cup.riv", animation:"Timeline 1"});
assets.skull = await loadRiveAsset({url:"skull_404.riv"});
assets.octopus = await loadRiveAsset({url:"octopus_loop.riv"});
assets.mercury = await loadRiveAsset({url:"planets.riv", artboard:"Mercury",
animation:"MercuryIdle"});
assets.timer = await loadRiveAsset({url:"Timer.riv", animation:"Esample"});
assets.adventureTime = await loadRiveAsset({url:"adventuretime_marceline-pb.riv",
artboard:"AdventureTime_FtMarcelinePB",
stateMachine:"State Machine 1"});
setInterval(function() {
// Simulate a mouse click on assets.adventureTime every 2.5 seconds.
assets.adventureTime.pointerDown(200, 200);
assets.adventureTime.pointerUp(200, 200);
}, 2500);
assets.towers = await loadRiveAsset({url:"towersDemo.riv"});
}
const fps = new function() {
this.frames = 0;
this.seconds = 0;
this.tick = function(elapsed) {
++this.frames;
this.seconds += elapsed;
if (this.seconds >= 2) {
console.log((this.frames / this.seconds).toFixed(2) + " FPS");
this.frames = 0;
this.seconds = 0;
}
};
};
let lastTimestamp = 0;
let totalElapsed = 0;
async function wgpuRender(args)
{
const elapsed = lastTimestamp ? (args.timestamp - lastTimestamp) / 1000 : 0;
lastTimestamp = args.timestamp;
for (asset in assets) {
assets[asset].advanceAndApply(elapsed);
}
const targetTextureView = data.wgpu.getCurrentTexture().createView();
const renderer = RiveBeginRendering(targetTextureView, RIVE_LOAD_ACTION_CLEAR, 0xff8030ff);
const middleFrame = [0, data.height * .25, data.width, data.height * .67];
const dock = [0, data.height * .75, data.width, data.height * .97];
renderer.save();
assets.skills.artboard.align(renderer, middleFrame, RIVE_FIT_FIT_HEIGHT, [.38, 0]);
renderer.transform(1.5, 0, 0, 1.5, 0, -250);
assets.skills.draw(renderer);
renderer.restore();
renderer.save();
assets.santa.artboard.align(renderer, middleFrame, RIVE_FIT_FIT_HEIGHT, [-.5, 0]);
assets.santa.draw(renderer);
renderer.restore();
renderer.save();
assets.coffee.artboard.align(renderer, dock, RIVE_FIT_FIT_HEIGHT, RIVE_ALIGNMENT_BOTTOM_CENTER);
renderer.transform(2, 0, 0, 2, -40, -600);
assets.coffee.draw(renderer);
renderer.restore();
renderer.save();
assets.skull.artboard.align(renderer, dock, RIVE_FIT_FIT_HEIGHT, [.565, 1]);
assets.skull.draw(renderer);
renderer.restore();
renderer.save();
assets.octopus.artboard.align(renderer, dock, RIVE_FIT_FIT_HEIGHT, RIVE_ALIGNMENT_BOTTOM_LEFT);
renderer.transform(1.7, 0, 0, 1.7, 90, -240);
assets.octopus.draw(renderer);
renderer.restore();
renderer.save();
assets.mercury.artboard.align(renderer, dock, RIVE_FIT_FIT_HEIGHT, [-.62, 1]);
const mercuryCenterX = assets.mercury.artboard.width() / 2;
const mercuryCenterY = assets.mercury.artboard.height() / 2;
renderer.translate(mercuryCenterX, mercuryCenterY);
const cx = Math.cos(totalElapsed) * .7;
const sx = Math.sin(totalElapsed) * .7;
renderer.transform(cx, sx, -sx, cx, 0, 0);
renderer.translate(-mercuryCenterX, -mercuryCenterY);
assets.mercury.draw(renderer);
renderer.restore();
renderer.save();
assets.timer.artboard.align(renderer, dock, RIVE_FIT_FIT_HEIGHT, [.31, 1]);
renderer.translate(0, -assets.timer.artboard.height() * .125);
assets.timer.draw(renderer);
renderer.restore();
renderer.save();
assets.adventureTime.artboard.align(
renderer, dock, RIVE_FIT_FIT_HEIGHT, RIVE_ALIGNMENT_BOTTOM_RIGHT);
renderer.translate(-160, 0);
assets.adventureTime.draw(renderer);
renderer.restore();
renderer.save();
assets.towers.artboard.align(renderer, dock, RIVE_FIT_FIT_HEIGHT, [-.28, 1]);
renderer.transform(.85, 0, 0, .85, 0, 20);
assets.towers.draw(renderer);
renderer.restore();
RiveFlushRendering();
totalElapsed += elapsed;
fps.tick(elapsed);
}
function download(url)
{
return new Promise(function (resolve, reject) {
let xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.responseType = "arraybuffer";
xhr.onload = function () {
if (this.status >= 200 && this.status < 300) {
resolve(new Uint8Array(xhr.response));
} else {
reject({
status: this.status,
statusText: xhr.statusText
});
}
};
xhr.onerror = function () {
reject({
status: this.status,
statusText: xhr.statusText
});
};
xhr.send();
});
}
async function main()
{
const canvas = document.getElementById("canvas");
const wgpu = canvas.getContext("webgpu");
const adapter = await navigator.gpu.requestAdapter();
if (!adapter) {
throw new Error("No appropriate GPUAdapter found.");
}
const device = await adapter.requestDevice();
const canvasFormat = navigator.gpu.getPreferredCanvasFormat();
wgpu.configure({
device: device,
format: canvasFormat,
});
await wgpuDataInitialize(wgpu, canvas, adapter, device);
const mainLoop = async () => {
await wgpuRender({timestamp:performance.now()});
requestAnimationFrame(mainLoop);
};
requestAnimationFrame(mainLoop);
}
if (Module.calledRun) {
main();
} else {
Module.onRuntimeInitialized = main;
}
</script>