Files
blitzkit/src/core/blitz/extractArmor.ts
T

137 lines
4.7 KiB
TypeScript
Raw Normal View History

2024-01-09 13:07:27 -06:00
import { Accessor, Document, Node, Scene } from '@gltf-transform/core';
import { times } from 'lodash';
2024-02-04 17:55:48 -06:00
import { Hierarchy, Sc2ReadStream } from '../streams/sc2';
import { ScgReadStream } from '../streams/scg';
2024-01-08 18:34:04 -06:00
import { VertexAttribute } from '../streams/scpg';
2024-01-09 13:07:27 -06:00
import {
vertexAttributeGLTFName,
vertexAttributeGltfVectorSizes,
2024-03-12 23:36:56 -05:00
} from './extractModel/constants';
2024-01-08 18:34:04 -06:00
import { readDVPLFile } from './readDVPLFile';
2024-01-09 13:07:27 -06:00
export async function extractArmor(data: string, fileName: string) {
2024-01-08 18:34:04 -06:00
const sc2Path = `${data}/3d/Tanks/CollisionMeshes/${fileName}.sc2.dvpl`;
const scgPath = `${data}/3d/Tanks/CollisionMeshes/${fileName}.scg.dvpl`;
2024-02-18 16:17:00 -06:00
const sc2 = new Sc2ReadStream((await readDVPLFile(sc2Path)).buffer).sc2();
const scg = new ScgReadStream((await readDVPLFile(scgPath)).buffer).scg();
2024-01-08 18:34:04 -06:00
const document = new Document();
const scene = document.createScene();
const buffer = document.createBuffer();
function parseHierarchies(hierarchies: Hierarchy[], parent: Scene | Node) {
hierarchies.forEach((hierarchy) => {
const components = times(
hierarchy.components.count,
(index) => hierarchy.components[index.toString().padStart(4, '0')],
);
components.forEach((component) => {
switch (component['comp.typename']) {
2024-01-09 13:36:33 -06:00
case 'TransformComponent':
2024-01-08 18:34:04 -06:00
break;
case 'RenderComponent': {
2024-01-09 13:07:27 -06:00
const batch = component['rc.renderObj']['ro.batches']['0000'];
2024-01-08 18:34:04 -06:00
const polygonGroup = scg.get(batch['rb.datasource']);
if (!polygonGroup) {
console.warn(
`Missing polygon group ${batch['rb.datasource']} (${hierarchy.name}); skipping...`,
);
break;
}
2024-01-09 13:07:27 -06:00
const hardJointIndices = new Set<number>();
const vertexHardJointIndices = new Map<number, number>();
const attributes = new Map<VertexAttribute, number[][]>();
2024-01-08 18:34:04 -06:00
2024-01-09 13:07:27 -06:00
polygonGroup.vertices.forEach((vertex, index) => {
2024-01-08 18:34:04 -06:00
vertex.forEach(({ attribute, value }) => {
2024-01-09 13:07:27 -06:00
if (!attributes.has(attribute)) {
attributes.set(attribute, []);
2024-01-08 18:34:04 -06:00
}
2024-01-09 13:07:27 -06:00
attributes.get(attribute)!.push(value);
if (attribute === VertexAttribute.HARD_JOINTINDEX) {
2024-01-09 13:07:27 -06:00
hardJointIndices.add(value[0]);
vertexHardJointIndices.set(index, value[0]);
}
2024-01-08 18:34:04 -06:00
});
});
2024-01-09 13:07:27 -06:00
if (attributes.has(VertexAttribute.TANGENT)) {
attributes.set(
VertexAttribute.TANGENT,
attributes
.get(VertexAttribute.TANGENT)!
.map((tangent) => [...tangent, 1]),
);
2024-01-08 18:34:04 -06:00
}
2024-01-09 13:07:27 -06:00
const accessors = new Map<string, Accessor>();
2024-01-08 18:34:04 -06:00
2024-01-09 13:07:27 -06:00
attributes.forEach((value, attribute) => {
const name = vertexAttributeGLTFName[attribute];
if (!name || accessors.has(name)) return;
const vertexSize = vertexAttributeGltfVectorSizes[attribute];
const accessor = document
2024-01-08 18:34:04 -06:00
.createAccessor(name)
.setType(vertexSize === 1 ? 'SCALAR' : `VEC${vertexSize}`)
2024-01-09 13:07:27 -06:00
.setArray(new Float32Array(value.flat()))
2024-01-08 18:34:04 -06:00
.setBuffer(buffer);
2024-01-09 13:07:27 -06:00
accessors.set(name, accessor);
2024-01-08 18:34:04 -06:00
});
2024-01-09 13:07:27 -06:00
hardJointIndices.forEach((hardJointIndex) => {
2024-01-09 13:36:33 -06:00
const node = document.createNode(
`${hierarchy.name}_armor_${hardJointIndex}`,
2024-01-09 13:07:27 -06:00
);
const mesh = document.createMesh(batch['##name']);
const indicesAccessor = document
.createAccessor()
.setType('SCALAR')
.setArray(
new Uint16Array(
2024-01-12 19:58:02 -06:00
polygonGroup.indices.filter(
(index) =>
vertexHardJointIndices.get(index) === hardJointIndex,
),
2024-01-09 13:07:27 -06:00
),
)
.setBuffer(buffer);
const primitive = document
.createPrimitive()
.setIndices(indicesAccessor);
accessors.forEach((accessor, name) => {
primitive.setAttribute(name, accessor);
});
mesh.addPrimitive(primitive);
2024-01-09 13:36:33 -06:00
node.setMesh(mesh);
parent.addChild(node);
2024-01-09 13:07:27 -06:00
});
2024-01-08 18:34:04 -06:00
break;
}
default:
throw new TypeError(
`Unhandled component type: ${component['comp.typename']}`,
);
}
});
if (hierarchy['#hierarchy']) {
2024-01-09 13:36:33 -06:00
parseHierarchies(hierarchy['#hierarchy'], parent);
2024-01-08 18:34:04 -06:00
}
});
}
parseHierarchies(sc2['#hierarchy'], scene);
return document;
}