Files
blitzkit/packages/core/src/streams/scg.ts
T

132 lines
3.7 KiB
TypeScript
Raw Normal View History

2026-09-30 19:00:25 -05:00
import { ScpgReadStream, VertexAttribute } from "./scpg";
2023-12-25 12:37:37 -06:00
interface PolygonGroupRaw {
2026-09-30 19:00:25 -05:00
"##name": "PolygonGroup";
"#id": ArrayBuffer;
2023-12-25 12:37:37 -06:00
cubeTextureCoordCount: number;
indexCount: number;
indexFormat: 0 | 1;
2024-02-18 16:17:00 -06:00
indices: ArrayBuffer;
2023-12-25 12:37:37 -06:00
packing: 0 | 1;
primitiveCount: number;
rhi_primitiveType: 1 | 2 | 10;
textureCoordCount: number;
vertexCount: number;
vertexFormat: number;
2024-02-18 16:17:00 -06:00
vertices: ArrayBuffer;
2023-12-25 12:37:37 -06:00
}
2024-04-23 10:19:32 -05:00
type BlitzkitVertex = { attribute: VertexAttribute; value: number[] }[];
2023-12-25 12:37:37 -06:00
2024-04-23 10:19:32 -05:00
interface BlitzkitPolygonGroup {
vertices: BlitzkitVertex[];
2023-12-25 12:37:37 -06:00
indices: number[];
}
2024-01-09 13:07:27 -06:00
const vertexAttributesArray = Object.values(VertexAttribute).filter(
2026-09-30 19:00:25 -05:00
(value) => typeof value === "number",
2024-01-09 13:07:27 -06:00
);
2023-12-25 12:37:37 -06:00
export const vertexAttributeVectorSizes = {
[VertexAttribute.VERTEX]: 3,
[VertexAttribute.NORMAL]: 3,
[VertexAttribute.COLOR]: 1,
[VertexAttribute.TEXCOORD0]: 2,
[VertexAttribute.TEXCOORD1]: 2,
[VertexAttribute.TEXCOORD2]: 2,
[VertexAttribute.TEXCOORD3]: 2,
[VertexAttribute.TANGENT]: 3,
[VertexAttribute.BINORMAL]: 3,
[VertexAttribute.HARD_JOINTINDEX]: 1,
[VertexAttribute.CUBETEXCOORD0]: 3,
[VertexAttribute.CUBETEXCOORD1]: 3,
[VertexAttribute.CUBETEXCOORD2]: 3,
[VertexAttribute.CUBETEXCOORD3]: 3,
[VertexAttribute.PIVOT4]: 4,
[VertexAttribute.PIVOT_DEPRECATED]: 3,
[VertexAttribute.FLEXIBILITY]: 1,
[VertexAttribute.ANGLE_SIN_COS]: 2,
[VertexAttribute.JOINTINDEX]: 4,
[VertexAttribute.JOINTWEIGHT]: 4,
} as const;
2024-02-04 17:55:48 -06:00
export class ScgReadStream extends ScpgReadStream {
2023-12-25 12:37:37 -06:00
header() {
return {
2023-12-25 16:49:40 -06:00
name: this.ascii(4),
2023-12-25 12:37:37 -06:00
version: this.uint32(),
nodeCount: this.uint32(),
nodeCount2: this.uint32(),
};
}
scg() {
const header = this.header();
const polygonGroupsRaw: PolygonGroupRaw[] = [];
2024-04-23 10:19:32 -05:00
const polygonGroups = new Map<bigint, BlitzkitPolygonGroup>();
2023-12-25 12:37:37 -06:00
for (let index = 0; index < header.nodeCount; index++) {
const polygonGroupRaw = this.ka() as PolygonGroupRaw;
polygonGroupsRaw.push(polygonGroupRaw);
}
polygonGroupsRaw.forEach((polygonGroupRaw) => {
2024-02-04 17:55:48 -06:00
const indicesStream = new ScpgReadStream(polygonGroupRaw.indices);
2023-12-25 12:37:37 -06:00
const indices: number[] = [];
for (let index = 0; index < polygonGroupRaw.indexCount; index++) {
indices.push(
polygonGroupRaw.indexFormat === 0
? indicesStream.uint16()
: indicesStream.uint32(),
);
}
2024-02-04 17:55:48 -06:00
const verticesStream = new ScpgReadStream(polygonGroupRaw.vertices);
2024-04-23 10:19:32 -05:00
const vertices: BlitzkitVertex[] = [];
2024-02-04 17:55:48 -06:00
const { format, stride } = ScgReadStream.parseVertexFormat(
2024-01-08 19:13:54 -06:00
polygonGroupRaw.vertexFormat,
);
const strideBasedSize = stride * polygonGroupRaw.vertexCount;
2023-12-25 12:37:37 -06:00
2024-02-07 10:34:13 -06:00
if (verticesStream.buffer.byteLength !== strideBasedSize) {
2023-12-25 12:37:37 -06:00
console.warn(
2024-02-07 10:34:13 -06:00
`Vertex stride mismatch; expected ${strideBasedSize}, got ${verticesStream.buffer.byteLength}; skipping...`,
2023-12-25 12:37:37 -06:00
);
return;
}
for (let index = 0; index < polygonGroupRaw.vertexCount; index++) {
2024-01-09 13:07:27 -06:00
vertices[index] = format.map((attribute) => ({
attribute,
value: verticesStream.vectorN(vertexAttributeVectorSizes[attribute]),
}));
2023-12-25 12:37:37 -06:00
}
2024-02-18 16:17:00 -06:00
polygonGroups.set(
2026-09-30 19:00:25 -05:00
new DataView(polygonGroupRaw["#id"]).getBigUint64(0, true),
{ vertices, indices },
2024-02-18 16:17:00 -06:00
);
2023-12-25 12:37:37 -06:00
});
return polygonGroups;
}
2024-01-08 19:13:54 -06:00
static parseVertexFormat(formatInt: number) {
const format: VertexAttribute[] = [];
let stride = 0;
2023-12-25 12:37:37 -06:00
2024-01-09 13:07:27 -06:00
vertexAttributesArray.forEach((attributeUntyped) => {
const attribute = attributeUntyped as VertexAttribute;
const mask = 1 << attribute;
2024-01-08 19:13:54 -06:00
2024-01-09 13:07:27 -06:00
if (formatInt & mask) {
format.push(attribute);
stride += vertexAttributeVectorSizes[attribute] * 4;
}
});
2024-01-08 19:13:54 -06:00
return { format, stride };
2023-12-25 12:37:37 -06:00
}
}