Amp-Thread-ID: https://ampcode.com/threads/T-01a01380-b478-77d0-84a0-102880a5c5ae Co-authored-by: Heaust Azure <heaust.azure@gmail.com>
135 lines
3.8 KiB
JavaScript
135 lines
3.8 KiB
JavaScript
import { YawnCore } from "@yawn/core";
|
|
import { GltfImporter } from "@yawn/gltf-import";
|
|
import {
|
|
CameraHandle,
|
|
MaterialHandles,
|
|
MeshHandles,
|
|
} from "@yawn/mesh-handles";
|
|
import { loadGraph, graphFromObject, RenderGraph, ref } from "@yawn/render-graph-js";
|
|
import {
|
|
createGraphAst,
|
|
reference,
|
|
serializeGraphAst,
|
|
} from "@yawn/render-graph-ast";
|
|
import { defaultPipelines } from "@yawn/default-pipelines";
|
|
import { loadDemoLoadout } from "../render-graph-studio/demo-loadouts.js";
|
|
import { culling } from "../render-graph-studio/render-graph/presets.js";
|
|
import { installCameraRenderDataControls } from "../shared/camera-controls.js";
|
|
import { createWorkerTransport } from "../shared/create-worker-transport.js";
|
|
|
|
const waitForFrame = (core, predicate, timeout = 30_000) =>
|
|
new Promise((resolve, reject) => {
|
|
const current = core.telemetry;
|
|
if (current && predicate(current)) {
|
|
resolve(current);
|
|
return;
|
|
}
|
|
const timer = setTimeout(() => {
|
|
core.removeEventListener("renderer-frame", frame);
|
|
reject(new Error("Renderer confirmation timed out"));
|
|
}, timeout);
|
|
const frame = (event) => {
|
|
if (!predicate(event.detail)) return;
|
|
clearTimeout(timer);
|
|
core.removeEventListener("renderer-frame", frame);
|
|
resolve(event.detail);
|
|
};
|
|
core.addEventListener("renderer-frame", frame);
|
|
});
|
|
|
|
export function rotationY(angle) {
|
|
const cosine = Math.cos(angle);
|
|
const sine = Math.sin(angle);
|
|
return [
|
|
cosine, 0, -sine, 0,
|
|
0, 1, 0, 0,
|
|
sine, 0, cosine, 0,
|
|
0, 0, 0, 1,
|
|
];
|
|
}
|
|
|
|
export function createPlaygroundRuntime(canvas, report) {
|
|
let activeScene;
|
|
const status = (message) => {
|
|
report(String(message));
|
|
};
|
|
|
|
async function createScene({ loadout = "cubes", graph = culling } = {}) {
|
|
activeScene?.dispose();
|
|
const core = new YawnCore(createWorkerTransport(canvas));
|
|
const handles = new MeshHandles(core);
|
|
const importer = new GltfImporter(core);
|
|
let stopControls = () => {};
|
|
try {
|
|
status("Starting render worker…");
|
|
await core.ready;
|
|
const compiled = await loadGraph(core, graph);
|
|
const targetRevision = (core.telemetry?.revision ?? 0) + 1;
|
|
const glb = await loadDemoLoadout(loadout);
|
|
const url = URL.createObjectURL(
|
|
new Blob([glb], { type: "model/gltf-binary" }),
|
|
);
|
|
let imported;
|
|
try {
|
|
imported = await importer.load(url);
|
|
} finally {
|
|
URL.revokeObjectURL(url);
|
|
}
|
|
const meshes = handles.fromImportedScene(imported);
|
|
const materials = new MaterialHandles(core).fromImportedScene(imported);
|
|
const camera = new CameraHandle(core);
|
|
stopControls = installCameraRenderDataControls(core, canvas);
|
|
await core.switchCompiledGraph(compiled.compiledId);
|
|
await waitForFrame(
|
|
core,
|
|
(frame) =>
|
|
frame.revision === targetRevision &&
|
|
frame.activeCompiledGraph === graph.id &&
|
|
frame.draws > 0 &&
|
|
frame.gpuError === false,
|
|
);
|
|
activeScene = {
|
|
core,
|
|
handles,
|
|
meshes,
|
|
materials,
|
|
camera,
|
|
compiled: { ...compiled, graphId: graph.id },
|
|
dispose() {
|
|
stopControls();
|
|
handles.dispose();
|
|
core.dispose();
|
|
activeScene = undefined;
|
|
},
|
|
};
|
|
return activeScene;
|
|
} catch (error) {
|
|
stopControls();
|
|
handles.dispose();
|
|
core.dispose();
|
|
throw error;
|
|
} finally {
|
|
importer.dispose();
|
|
}
|
|
}
|
|
|
|
return Object.freeze({
|
|
createScene,
|
|
status,
|
|
rotationY,
|
|
graphs: Object.freeze({ culling }),
|
|
packages: Object.freeze({
|
|
createGraphAst,
|
|
defaultPipelines,
|
|
graphFromObject,
|
|
reference,
|
|
ref,
|
|
RenderGraph,
|
|
serializeGraphAst,
|
|
}),
|
|
dispose() {
|
|
activeScene?.dispose();
|
|
},
|
|
});
|
|
}
|