Files
forma-engine/tests/fixtures.ts
T

156 lines
4.4 KiB
TypeScript

export function node(
id: string,
parentId: string | null = null,
components: Record<string, any> = {},
) {
return {
id,
name: id,
parentId,
enabled: true,
transform: { position: [0, 0, 0], rotation: [0, 0, 0], scale: [1, 1, 1] },
components,
};
}
export function project(nodes: any[] = []) {
return {
format: "forma",
version: 1,
id: "test_project",
name: "Regression fixture",
revision: 0,
activeSceneId: "scene_main",
scenes: [{ id: "scene_main", name: "Main", entities: nodes }],
assets: [],
scripts: [],
settings: {
background: "#f3f0eb",
ambient: 0.8,
shadows: false,
renderScale: 1,
},
} as any;
}
export function scene(p: any) {
return p.scenes.find((s: any) => s.id === p.activeSceneId);
}
export function findNode(p: any, id: string) {
return scene(p).entities.find((e: any) => e.id === id);
}
/** A generated triangle, optionally skinned and animated; no game assets. */
export function triangleGlb(animated = false): Buffer {
const chunks: Buffer[] = [];
const views: any[] = [];
const accessors: any[] = [];
let length = 0;
const add = (
data: Float32Array | Uint16Array,
type: string,
count: number,
bounds: Record<string, any> = {},
) => {
const bytes = Buffer.from(data.buffer, data.byteOffset, data.byteLength);
views.push({ buffer: 0, byteOffset: length, byteLength: bytes.length });
chunks.push(bytes);
length += bytes.length;
const padding = (4 - (length % 4)) % 4;
if (padding) {
chunks.push(Buffer.alloc(padding));
length += padding;
}
accessors.push({
bufferView: views.length - 1,
componentType: data instanceof Float32Array ? 5126 : 5123,
count,
type,
...bounds,
});
return accessors.length - 1;
};
const position = add(
new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]),
"VEC3",
3,
{ min: [0, 0, 0], max: [1, 1, 0] },
);
const normal = add(new Float32Array([0, 0, 1, 0, 0, 1, 0, 0, 1]), "VEC3", 3);
const indices = add(new Uint16Array([0, 1, 2]), "SCALAR", 3);
const attributes: Record<string, number> = {
POSITION: position,
NORMAL: normal,
};
const document: any = {
asset: { version: "2.0", generator: "Forma test fixture" },
scene: 0,
scenes: [{ nodes: animated ? [0, 1] : [0] }],
nodes: [{ name: "Triangle", mesh: 0 }],
meshes: [{ primitives: [{ attributes, indices }] }],
};
if (animated) {
attributes.JOINTS_0 = add(new Uint16Array(12), "VEC4", 3);
attributes.WEIGHTS_0 = add(
new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0]),
"VEC4",
3,
);
const inverseBindMatrices = add(
new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]),
"MAT4",
1,
);
const input = add(new Float32Array([0, 1]), "SCALAR", 2, {
min: [0],
max: [1],
});
const output = add(new Float32Array([0, 0, 0, 0, 0.2, 0]), "VEC3", 2);
document.nodes[0].skin = 0;
document.nodes.push({ name: "Joint" });
document.skins = [{ joints: [1], inverseBindMatrices }];
document.animations = [
{
name: "Translate",
samplers: [{ input, output, interpolation: "LINEAR" }],
channels: [{ sampler: 0, target: { node: 1, path: "translation" } }],
},
];
}
Object.assign(document, {
buffers: [{ byteLength: length }],
bufferViews: views,
accessors,
});
const json = Buffer.from(JSON.stringify(document));
const jsonPadding = Buffer.alloc((4 - (json.length % 4)) % 4, 0x20);
const body = Buffer.concat(chunks);
const header = Buffer.alloc(12);
header.writeUInt32LE(0x46546c67, 0);
header.writeUInt32LE(2, 4);
header.writeUInt32LE(
12 + 8 + json.length + jsonPadding.length + 8 + body.length,
8,
);
const jsonHeader = Buffer.alloc(8);
jsonHeader.writeUInt32LE(json.length + jsonPadding.length, 0);
jsonHeader.writeUInt32LE(0x4e4f534a, 4);
const bodyHeader = Buffer.alloc(8);
bodyHeader.writeUInt32LE(body.length, 0);
bodyHeader.writeUInt32LE(0x004e4942, 4);
return Buffer.concat([
header,
jsonHeader,
json,
jsonPadding,
bodyHeader,
body,
]);
}
export const triangleAsset = (animated = false) => ({
id: "asset_triangle",
name: "Triangle.glb",
kind: "model" as const,
uri:
"data:model/gltf-binary;base64," + triangleGlb(animated).toString("base64"),
});