mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-26 03:59:53 +01:00
feat: attempting textures
This commit is contained in:
1 parent
6d2bb7b131
commit
f61725a021
6 files changed
+281
-145
No files matched your search
Vendored
+3
@@ -8,6 +8,7 @@
|
|||||||
"atgm",
|
"atgm",
|
||||||
"bepaint",
|
"bepaint",
|
||||||
"BINORMAL",
|
"BINORMAL",
|
||||||
|
"Binormals",
|
||||||
"blitzstars",
|
"blitzstars",
|
||||||
"classname",
|
"classname",
|
||||||
"cleandist",
|
"cleandist",
|
||||||
@@ -27,6 +28,7 @@
|
|||||||
"fullstats",
|
"fullstats",
|
||||||
"fuzzysort",
|
"fuzzysort",
|
||||||
"gamemode",
|
"gamemode",
|
||||||
|
"GLTF",
|
||||||
"immer",
|
"immer",
|
||||||
"JOINTINDEX",
|
"JOINTINDEX",
|
||||||
"JOINTWEIGHT",
|
"JOINTWEIGHT",
|
||||||
@@ -43,6 +45,7 @@
|
|||||||
"ownedtanks",
|
"ownedtanks",
|
||||||
"playerachievements",
|
"playerachievements",
|
||||||
"playerinfo",
|
"playerinfo",
|
||||||
|
"pngjs",
|
||||||
"ratingsleaderboard",
|
"ratingsleaderboard",
|
||||||
"ratingsplot",
|
"ratingsplot",
|
||||||
"researchable",
|
"researchable",
|
||||||
|
|||||||
@@ -53,6 +53,8 @@
|
|||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"markdown-escape": "^2.0.0",
|
"markdown-escape": "^2.0.0",
|
||||||
"next": "^14.0.3",
|
"next": "^14.0.3",
|
||||||
|
"parse-dds": "^1.2.1",
|
||||||
|
"pngjs": "^7.0.0",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-fuzzysort": "^1.0.1",
|
"react-fuzzysort": "^1.0.1",
|
||||||
@@ -75,6 +77,8 @@
|
|||||||
"@types/lz4": "^0.6.4",
|
"@types/lz4": "^0.6.4",
|
||||||
"@types/markdown-escape": "^1.1.0",
|
"@types/markdown-escape": "^1.1.0",
|
||||||
"@types/node": "^20.6.5",
|
"@types/node": "^20.6.5",
|
||||||
|
"@types/parse-dds": "^1.0.3",
|
||||||
|
"@types/pngjs": "^6.0.4",
|
||||||
"@types/react": "^18.2.22",
|
"@types/react": "^18.2.22",
|
||||||
"@types/three": "^0.159.0",
|
"@types/three": "^0.159.0",
|
||||||
"@vanilla-extract/next-plugin": "^2.3.1",
|
"@vanilla-extract/next-plugin": "^2.3.1",
|
||||||
|
|||||||
+187
-88
@@ -1,14 +1,18 @@
|
|||||||
import { Document, Node, NodeIO, Scene } from '@gltf-transform/core';
|
import { Document, Material, Node, NodeIO, Scene } from '@gltf-transform/core';
|
||||||
import { config } from 'dotenv';
|
import { config } from 'dotenv';
|
||||||
import { existsSync, writeFileSync } from 'fs';
|
import { existsSync, writeFileSync } from 'fs';
|
||||||
import { mkdir, readdir, rm } from 'fs/promises';
|
import { mkdir, readFile, readdir, rm } from 'fs/promises';
|
||||||
import { times } from 'lodash';
|
import { range, times } from 'lodash';
|
||||||
import { argv } from 'process';
|
import { argv } from 'process';
|
||||||
import sharp from 'sharp';
|
import sharp from 'sharp';
|
||||||
import { Matrix4, Quaternion, Vector3, Vector4Tuple } from 'three';
|
import { Matrix4, Quaternion, Vector3, Vector4Tuple } from 'three';
|
||||||
import { TankType } from '../src/components/Tanks';
|
import { TankType } from '../src/components/Tanks';
|
||||||
import { NATION_IDS } from '../src/constants/nations';
|
import { NATION_IDS } from '../src/constants/nations';
|
||||||
import { SCPGStream, VertexType } from '../src/core/blitz/SCPGStream';
|
import {
|
||||||
|
SCPGStream,
|
||||||
|
VertexAttribute,
|
||||||
|
vertexAttributeVectorSizes,
|
||||||
|
} from '../src/core/blitz/SCPGStream';
|
||||||
import { readBase64DVPL } from '../src/core/blitz/readBase64DVPL';
|
import { readBase64DVPL } from '../src/core/blitz/readBase64DVPL';
|
||||||
import { readDVPLFile } from '../src/core/blitz/readDVPLFile';
|
import { readDVPLFile } from '../src/core/blitz/readDVPLFile';
|
||||||
import { readStringDVPL } from '../src/core/blitz/readStringDVPL';
|
import { readStringDVPL } from '../src/core/blitz/readStringDVPL';
|
||||||
@@ -29,6 +33,19 @@ import {
|
|||||||
} from '../src/core/blitzkrieg/tankDefinitions';
|
} from '../src/core/blitzkrieg/tankDefinitions';
|
||||||
import { Hierarchy } from '../src/types/sc2';
|
import { Hierarchy } from '../src/types/sc2';
|
||||||
|
|
||||||
|
const vertexTypeGLTFName: Partial<Record<VertexAttribute, string>> = {
|
||||||
|
[VertexAttribute.VERTEX]: 'POSITION',
|
||||||
|
[VertexAttribute.NORMAL]: 'NORMAL',
|
||||||
|
[VertexAttribute.COLOR]: 'COLOR_0',
|
||||||
|
[VertexAttribute.TEXCOORD0]: 'TEXCOORD_0',
|
||||||
|
[VertexAttribute.TEXCOORD1]: 'TEXCOORD_0',
|
||||||
|
[VertexAttribute.TEXCOORD2]: 'TEXCOORD_0',
|
||||||
|
[VertexAttribute.TEXCOORD3]: 'TEXCOORD_0',
|
||||||
|
[VertexAttribute.TANGENT]: 'TANGENT',
|
||||||
|
[VertexAttribute.JOINTINDEX]: 'JOINT_0',
|
||||||
|
[VertexAttribute.JOINTWEIGHT]: 'WEIGHT_0',
|
||||||
|
};
|
||||||
|
|
||||||
(BigInt.prototype as any).toJSON = function () {
|
(BigInt.prototype as any).toJSON = function () {
|
||||||
return this.toString();
|
return this.toString();
|
||||||
};
|
};
|
||||||
@@ -533,6 +550,30 @@ if (allTargets || targets?.includes('tankModels')) {
|
|||||||
const document = new Document();
|
const document = new Document();
|
||||||
const scene = document.createScene();
|
const scene = document.createScene();
|
||||||
const buffer = document.createBuffer();
|
const buffer = document.createBuffer();
|
||||||
|
const materials: Record<string, Material> = {};
|
||||||
|
|
||||||
|
// writeFileSync(
|
||||||
|
// 'test.txt',
|
||||||
|
// scg
|
||||||
|
// .map((group) =>
|
||||||
|
// group.vertices
|
||||||
|
// .map((vertex) =>
|
||||||
|
// vertex
|
||||||
|
// .map(
|
||||||
|
// (vertexProperty) =>
|
||||||
|
// `${VertexAttribute[vertexProperty.type].padEnd(
|
||||||
|
// 14,
|
||||||
|
// ' ',
|
||||||
|
// )} ${vertexProperty.value
|
||||||
|
// .map((value) => value.toString().padEnd(25, ' '))
|
||||||
|
// .join(' ')}`,
|
||||||
|
// )
|
||||||
|
// .join('\n'),
|
||||||
|
// )
|
||||||
|
// .join('\n\n'),
|
||||||
|
// )
|
||||||
|
// .join('\n\n#######\n\n'),
|
||||||
|
// );
|
||||||
|
|
||||||
function parseHierarchies(
|
function parseHierarchies(
|
||||||
hierarchies: Hierarchy[],
|
hierarchies: Hierarchy[],
|
||||||
@@ -598,68 +639,95 @@ if (allTargets || targets?.includes('tankModels')) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case 'RenderComponent': {
|
case 'RenderComponent': {
|
||||||
times(
|
const batchIds = range(
|
||||||
component['rc.renderObj']['ro.batchCount'],
|
component['rc.renderObj']['ro.batchCount'],
|
||||||
(index) =>
|
);
|
||||||
component['rc.renderObj']['ro.batches'][
|
let minLODIndex = Infinity;
|
||||||
index.toString().padStart(4, '0')
|
let minLODBatchId = Infinity;
|
||||||
],
|
|
||||||
).map((batch) => {
|
|
||||||
const polygonGroup = scg.find(
|
|
||||||
(group) => group.id === batch['rb.datasource'],
|
|
||||||
);
|
|
||||||
const unpackedVertices: number[] = [];
|
|
||||||
|
|
||||||
if (!polygonGroup)
|
batchIds.forEach((batchId) => {
|
||||||
throw new Error(
|
const thisLODIndex =
|
||||||
`Missing polygon group ${batch['rb.datasource']}`,
|
component['rc.renderObj'][`rb${batchId}.lodIndex`];
|
||||||
);
|
|
||||||
|
|
||||||
polygonGroup.vertices.forEach((vertex) => {
|
if (thisLODIndex <= minLODIndex) {
|
||||||
vertex.map((vertexItem) => {
|
minLODIndex = thisLODIndex;
|
||||||
switch (vertexItem.type) {
|
minLODBatchId = batchId;
|
||||||
case VertexType.VERTEX: {
|
}
|
||||||
unpackedVertices.push(...vertexItem.value);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// default:
|
|
||||||
// throw new TypeError(
|
|
||||||
// `Unhandled vertex type: ${
|
|
||||||
// VertexType[vertexItem.type]
|
|
||||||
// } (${vertexItem.type})`,
|
|
||||||
// );
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const vertexAccessor = document
|
|
||||||
.createAccessor()
|
|
||||||
.setType('VEC3')
|
|
||||||
.setArray(new Float32Array(unpackedVertices))
|
|
||||||
.setBuffer(buffer);
|
|
||||||
const indexAccessor = document
|
|
||||||
.createAccessor()
|
|
||||||
.setType('SCALAR')
|
|
||||||
.setArray(new Uint16Array(polygonGroup.indices))
|
|
||||||
.setBuffer(buffer);
|
|
||||||
|
|
||||||
const primitive = document
|
|
||||||
.createPrimitive()
|
|
||||||
.setIndices(indexAccessor)
|
|
||||||
.setAttribute('POSITION', vertexAccessor);
|
|
||||||
|
|
||||||
const mesh = document
|
|
||||||
.createMesh(batch['##name'])
|
|
||||||
.addPrimitive(primitive);
|
|
||||||
|
|
||||||
const polygons = document
|
|
||||||
.createNode(batch['##name'])
|
|
||||||
.setMesh(mesh);
|
|
||||||
|
|
||||||
node.addChild(polygons);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const batch =
|
||||||
|
component['rc.renderObj']['ro.batches'][
|
||||||
|
minLODBatchId.toString().padStart(4, '0')
|
||||||
|
];
|
||||||
|
const polygonGroup = scg.find(
|
||||||
|
(group) => group.id === batch['rb.datasource'],
|
||||||
|
);
|
||||||
|
const material = materials[batch['rb.nmatname']];
|
||||||
|
|
||||||
|
if (!polygonGroup) {
|
||||||
|
throw new Error(
|
||||||
|
`Missing polygon group ${batch['rb.datasource']}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const indexedVertexTypes: VertexAttribute[] = [];
|
||||||
|
const unpackedVertices: Partial<
|
||||||
|
Record<VertexAttribute, number[]>
|
||||||
|
> = {};
|
||||||
|
|
||||||
|
polygonGroup.vertices.forEach((vertex) => {
|
||||||
|
vertex.map((vertexItem) => {
|
||||||
|
if (!(vertexItem.type in unpackedVertices)) {
|
||||||
|
unpackedVertices[vertexItem.type] = [];
|
||||||
|
indexedVertexTypes.push(vertexItem.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
unpackedVertices[vertexItem.type]!.push(
|
||||||
|
...vertexItem.value,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const indexAccessor = document
|
||||||
|
.createAccessor()
|
||||||
|
.setType('SCALAR')
|
||||||
|
.setArray(new Uint16Array(polygonGroup.indices))
|
||||||
|
.setBuffer(buffer);
|
||||||
|
const primitive = document
|
||||||
|
.createPrimitive()
|
||||||
|
.setIndices(indexAccessor)
|
||||||
|
.setMaterial(material);
|
||||||
|
|
||||||
|
indexedVertexTypes.forEach((type) => {
|
||||||
|
if (!(type in vertexTypeGLTFName)) {
|
||||||
|
return;
|
||||||
|
// throw new TypeError(
|
||||||
|
// `Unhandled vertex type GLTF name: ${VertexType[type]} (${type})`,
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
|
||||||
|
const vertexSize = vertexAttributeVectorSizes[type];
|
||||||
|
|
||||||
|
if (!primitive.getAttribute(vertexTypeGLTFName[type]!)) {
|
||||||
|
primitive.setAttribute(
|
||||||
|
vertexTypeGLTFName[type]!,
|
||||||
|
document
|
||||||
|
.createAccessor()
|
||||||
|
.setType(
|
||||||
|
vertexSize === 1 ? 'SCALAR' : `VEC${vertexSize}`,
|
||||||
|
)
|
||||||
|
.setArray(new Float32Array(unpackedVertices[type]!))
|
||||||
|
.setBuffer(buffer),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const mesh = document
|
||||||
|
.createMesh(batch['##name'])
|
||||||
|
.addPrimitive(primitive);
|
||||||
|
|
||||||
|
node.setMesh(mesh);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -678,35 +746,66 @@ if (allTargets || targets?.includes('tankModels')) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
sc2['#dataNodes'].map(async (node) => {
|
||||||
|
const material = document.createMaterial(node.materialName);
|
||||||
|
|
||||||
|
// if (typeof node.configCount === 'number') {
|
||||||
|
// try {
|
||||||
|
// const config = node.configArchive_0;
|
||||||
|
// const texturePath = `${DATA}/${DOI['3d']}/${dirname(
|
||||||
|
// parameters.resourcesPath.blitzModelPath,
|
||||||
|
// )}/${config.textures.albedo.replace(
|
||||||
|
// /\.tex$/,
|
||||||
|
// '.dx11.dds.dvpl',
|
||||||
|
// )}`;
|
||||||
|
// console.log(texturePath);
|
||||||
|
// const dds = await readDVPLFile(texturePath);
|
||||||
|
// const image = parseDDS(dds).images[0];
|
||||||
|
// const textureArray = new Uint8Array(
|
||||||
|
// dds,
|
||||||
|
// image.offset,
|
||||||
|
// image.length,
|
||||||
|
// );
|
||||||
|
// const png = new PNG({
|
||||||
|
// width: image.shape[0],
|
||||||
|
// height: image.shape[1],
|
||||||
|
// });
|
||||||
|
|
||||||
|
// for (var index = 0; index < textureArray.length; index += 4) {
|
||||||
|
// png.data[index] = textureArray[index];
|
||||||
|
// png.data[index + 1] = textureArray[index + 1];
|
||||||
|
// png.data[index + 2] = textureArray[index + 2];
|
||||||
|
// png.data[index + 3] = textureArray[index + 3];
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const pngBuffer = PNG.sync.write(png);
|
||||||
|
// const texture = document
|
||||||
|
// .createTexture(config.configName)
|
||||||
|
// .setImage(await readFile('C:/Users/coola/Downloads/33e.jpg'));
|
||||||
|
|
||||||
|
// material.setBaseColorTexture(texture);
|
||||||
|
// } catch (error) {
|
||||||
|
// // console.log(error);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (node.configCount) {
|
||||||
|
console.log('uhhh');
|
||||||
|
const config = node.configArchive_0;
|
||||||
|
const texturePath = 'C:/Users/coola/Downloads/33e.jpg';
|
||||||
|
const textureBuffer = await readFile(texturePath);
|
||||||
|
const texture = document.createTexture(config?.configName);
|
||||||
|
|
||||||
|
texture.setImage(textureBuffer);
|
||||||
|
material.setBaseColorTexture(texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
materials[node['#id'].readBigUInt64LE().toString()] = material;
|
||||||
|
}),
|
||||||
|
);
|
||||||
parseHierarchies(sc2['#hierarchy'], scene);
|
parseHierarchies(sc2['#hierarchy'], scene);
|
||||||
writeFileSync('test.glb', await new NodeIO().writeBinary(document));
|
writeFileSync('test.glb', await new NodeIO().writeBinary(document));
|
||||||
|
|
||||||
// sc2['#hierarchy'][0]['#hierarchy']!.forEach((hierarchy) => {
|
|
||||||
// times(
|
|
||||||
// hierarchy.components.count,
|
|
||||||
// (index) => hierarchy.components[index.toString().padStart(4, '0')],
|
|
||||||
// ).forEach((component) => {
|
|
||||||
// if (component['comp.typename'] !== 'RenderComponent') return;
|
|
||||||
|
|
||||||
// hierarchy.name,
|
|
||||||
// times(
|
|
||||||
// component['rc.renderObj']['ro.batchCount'],
|
|
||||||
// (index) =>
|
|
||||||
// component['rc.renderObj']['ro.batches'][
|
|
||||||
// index.toString().padStart(4, '0')
|
|
||||||
// ],
|
|
||||||
// ).map((batch) => {
|
|
||||||
// const polygonGroup = scg.find(
|
|
||||||
// (group) => group.id === batch['rb.datasource'],
|
|
||||||
// );
|
|
||||||
|
|
||||||
// console.log(batch['rb.datasource'], polygonGroup !== undefined);
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
// writeFile('test.sc2.json', JSON.stringify(sc2, null, 2));
|
|
||||||
// writeFile('test.scg.json', JSON.stringify(scg, null, 2));
|
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ enum KAType {
|
|||||||
UNCONFIRMED_TRANSFORM = 29,
|
UNCONFIRMED_TRANSFORM = 29,
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum VertexType {
|
export enum VertexAttribute {
|
||||||
VERTEX,
|
VERTEX,
|
||||||
NORMAL,
|
NORMAL,
|
||||||
COLOR,
|
COLOR,
|
||||||
@@ -46,6 +46,7 @@ export enum VertexType {
|
|||||||
BINORMAL,
|
BINORMAL,
|
||||||
HARD_JOINTINDEX,
|
HARD_JOINTINDEX,
|
||||||
PIVOT4,
|
PIVOT4,
|
||||||
|
PIVOT_DEPRECATED,
|
||||||
FLEXIBILITY,
|
FLEXIBILITY,
|
||||||
ANGLE_SIN_COS,
|
ANGLE_SIN_COS,
|
||||||
JOINTINDEX,
|
JOINTINDEX,
|
||||||
@@ -56,6 +57,29 @@ export enum VertexType {
|
|||||||
CUBETEXCOORD3,
|
CUBETEXCOORD3,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
interface PolygonGroupRaw {
|
interface PolygonGroupRaw {
|
||||||
'##name': 'PolygonGroup';
|
'##name': 'PolygonGroup';
|
||||||
'#id': Buffer;
|
'#id': Buffer;
|
||||||
@@ -71,39 +95,13 @@ interface PolygonGroupRaw {
|
|||||||
vertexFormat: number;
|
vertexFormat: number;
|
||||||
vertices: Buffer;
|
vertices: Buffer;
|
||||||
}
|
}
|
||||||
type BlitzkriegVertex = { type: VertexType; value: number[] }[];
|
type BlitzkriegVertex = { type: VertexAttribute; value: number[] }[];
|
||||||
interface BlitzkriegPolygonGroup {
|
interface BlitzkriegPolygonGroup {
|
||||||
id: bigint;
|
id: bigint;
|
||||||
vertices: BlitzkriegVertex[];
|
vertices: BlitzkriegVertex[];
|
||||||
indices: number[];
|
indices: number[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const VECTOR_SIZES = [
|
|
||||||
[VertexType.COLOR, VertexType.FLEXIBILITY, VertexType.HARD_JOINTINDEX],
|
|
||||||
[
|
|
||||||
VertexType.TEXCOORD0,
|
|
||||||
VertexType.TEXCOORD1,
|
|
||||||
VertexType.TEXCOORD2,
|
|
||||||
VertexType.TEXCOORD3,
|
|
||||||
VertexType.ANGLE_SIN_COS,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
VertexType.VERTEX,
|
|
||||||
VertexType.NORMAL,
|
|
||||||
VertexType.BINORMAL,
|
|
||||||
VertexType.CUBETEXCOORD0,
|
|
||||||
VertexType.CUBETEXCOORD1,
|
|
||||||
VertexType.CUBETEXCOORD2,
|
|
||||||
VertexType.CUBETEXCOORD3,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
VertexType.PIVOT4,
|
|
||||||
VertexType.JOINTINDEX,
|
|
||||||
VertexType.JOINTWEIGHT,
|
|
||||||
VertexType.TANGENT,
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
||||||
export class SCPGStream {
|
export class SCPGStream {
|
||||||
public index = 0;
|
public index = 0;
|
||||||
constructor(public buffer: Buffer) {}
|
constructor(public buffer: Buffer) {}
|
||||||
@@ -197,6 +195,21 @@ export class SCPGStream {
|
|||||||
return this.consumeMatrixN(4);
|
return this.consumeMatrixN(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getVertexStride(vertexFormat: number) {
|
||||||
|
const flags = vertexFormat.toString(2);
|
||||||
|
|
||||||
|
return Object.values(VertexAttribute)
|
||||||
|
.filter((value) => typeof value === 'number')
|
||||||
|
.reduce(
|
||||||
|
(accumulator, attribute) =>
|
||||||
|
flags[attribute as VertexAttribute] === '1'
|
||||||
|
? accumulator +
|
||||||
|
vertexAttributeVectorSizes[attribute as VertexAttribute] * 4
|
||||||
|
: accumulator,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
consumeSCGHeader() {
|
consumeSCGHeader() {
|
||||||
return {
|
return {
|
||||||
name: this.consumeAscii(4),
|
name: this.consumeAscii(4),
|
||||||
@@ -228,36 +241,25 @@ export class SCPGStream {
|
|||||||
|
|
||||||
const verticesStream = new SCPGStream(polygonGroupRaw.vertices);
|
const verticesStream = new SCPGStream(polygonGroupRaw.vertices);
|
||||||
const vertices: BlitzkriegVertex[] = [];
|
const vertices: BlitzkriegVertex[] = [];
|
||||||
const vertexFormatBuffer = Buffer.alloc(4);
|
|
||||||
vertexFormatBuffer.writeUInt32LE(polygonGroupRaw.vertexFormat, 0);
|
const vertexFormat = (
|
||||||
const vertexFormat = [...vertexFormatBuffer]
|
polygonGroupRaw.vertexFormat
|
||||||
.map((number) => number.toString(2))
|
.toString(2)
|
||||||
.join('')
|
.split('')
|
||||||
.split('')
|
.map((bitString, index) =>
|
||||||
.map((bitString, index) => (bitString === '1' ? index : null))
|
bitString === '1' ? index : null,
|
||||||
.filter((type) => type !== null) as VertexType[];
|
) as VertexAttribute[]
|
||||||
|
).filter((type) => type !== null);
|
||||||
|
|
||||||
for (let index = 0; index < polygonGroupRaw.vertexCount; index++) {
|
for (let index = 0; index < polygonGroupRaw.vertexCount; index++) {
|
||||||
vertexFormat.forEach((type) => {
|
vertices[index] = vertexFormat.map((type) => ({
|
||||||
const resolved = VECTOR_SIZES.some((types, size) => {
|
type,
|
||||||
if (types.includes(type)) {
|
value: verticesStream.consumeVectorN(
|
||||||
if (!(index in vertices)) vertices[index] = [];
|
vertexAttributeVectorSizes[type],
|
||||||
vertices[index].push({
|
),
|
||||||
type,
|
}));
|
||||||
value: verticesStream.consumeVectorN(size + 1),
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!resolved) {
|
|
||||||
throw new TypeError(`Unknown vertex type: ${type}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(verticesStream.readRemaining().length);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: polygonGroupRaw['#id'].readBigUInt64LE(),
|
id: polygonGroupRaw['#id'].readBigUInt64LE(),
|
||||||
vertices,
|
vertices,
|
||||||
|
|||||||
+9
-3
@@ -11,10 +11,16 @@ type DataNode = {
|
|||||||
'#id': Buffer;
|
'#id': Buffer;
|
||||||
materialName: string;
|
materialName: string;
|
||||||
parentMaterialKey?: string;
|
parentMaterialKey?: string;
|
||||||
configCount?: number;
|
|
||||||
qualityGroup?: string;
|
qualityGroup?: string;
|
||||||
fxName?: string;
|
fxName?: string;
|
||||||
} & Record<`configArchive_${number}`, ConfigArchive>;
|
} & (
|
||||||
|
| ({
|
||||||
|
configCount: number;
|
||||||
|
} & Record<`configArchive_${number}`, ConfigArchive>)
|
||||||
|
| {
|
||||||
|
configCount: undefined;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
interface ConfigArchive {
|
interface ConfigArchive {
|
||||||
configName: string;
|
configName: string;
|
||||||
@@ -103,7 +109,7 @@ interface RbAabbox {
|
|||||||
maximum: number[];
|
maximum: number[];
|
||||||
}
|
}
|
||||||
|
|
||||||
type Component =
|
export type Component =
|
||||||
| {
|
| {
|
||||||
'comp.typename': 'TransformComponent';
|
'comp.typename': 'TransformComponent';
|
||||||
'tc.localRotation': Vector4Tuple;
|
'tc.localRotation': Vector4Tuple;
|
||||||
|
|||||||
@@ -2387,6 +2387,18 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz#90267db13f64d6e9ccb5ae3eac92786a7c77a516"
|
resolved "https://registry.yarnpkg.com/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz#90267db13f64d6e9ccb5ae3eac92786a7c77a516"
|
||||||
integrity sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==
|
integrity sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==
|
||||||
|
|
||||||
|
"@types/parse-dds@^1.0.3":
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/parse-dds/-/parse-dds-1.0.3.tgz#a1bb00421906094510d88c64af978564d3c35c9b"
|
||||||
|
integrity sha512-LD9BruIpfP6Z9aAJ488h+PwtSwLzM0NO+Rs1l/zjcPLBTqR31OnIGmAvJYhGiHhbOn7R0YXw1gL5bImNiK6HNw==
|
||||||
|
|
||||||
|
"@types/pngjs@^6.0.4":
|
||||||
|
version "6.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/pngjs/-/pngjs-6.0.4.tgz#9a457aebabd944efde1a773a0fa1d74933e8021b"
|
||||||
|
integrity sha512-atAK9xLKOnxiuArxcHovmnOUUGBZOQ3f0vCf43FnoKs6XnqiambT1kkJWmdo71IR+BoXSh+CueeFR0GfH3dTlQ==
|
||||||
|
dependencies:
|
||||||
|
"@types/node" "*"
|
||||||
|
|
||||||
"@types/prop-types@*":
|
"@types/prop-types@*":
|
||||||
version "15.7.11"
|
version "15.7.11"
|
||||||
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.11.tgz#2596fb352ee96a1379c657734d4b913a613ad563"
|
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.11.tgz#2596fb352ee96a1379c657734d4b913a613ad563"
|
||||||
@@ -4907,6 +4919,11 @@ parse-css-color@^0.2.1:
|
|||||||
color-name "^1.1.4"
|
color-name "^1.1.4"
|
||||||
hex-rgb "^4.1.0"
|
hex-rgb "^4.1.0"
|
||||||
|
|
||||||
|
parse-dds@^1.2.1:
|
||||||
|
version "1.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/parse-dds/-/parse-dds-1.2.1.tgz#b16533e00c4db91178b3460271361df4cb328164"
|
||||||
|
integrity sha512-oE88N8mzUi9d26tAaKVc0clxi6AjeTSWpLwgtcEVjXTYY1MW58w8FctmM9gGgvFd6YGu1/eFFYVeDVnlMsKBtA==
|
||||||
|
|
||||||
parse-json@^5.0.0:
|
parse-json@^5.0.0:
|
||||||
version "5.2.0"
|
version "5.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
|
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
|
||||||
@@ -5032,6 +5049,11 @@ pkg-types@^1.0.3:
|
|||||||
mlly "^1.2.0"
|
mlly "^1.2.0"
|
||||||
pathe "^1.1.0"
|
pathe "^1.1.0"
|
||||||
|
|
||||||
|
pngjs@^7.0.0:
|
||||||
|
version "7.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-7.0.0.tgz#a8b7446020ebbc6ac739db6c5415a65d17090e26"
|
||||||
|
integrity sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==
|
||||||
|
|
||||||
postcss-value-parser@^4.0.2, postcss-value-parser@^4.2.0:
|
postcss-value-parser@^4.0.2, postcss-value-parser@^4.2.0:
|
||||||
version "4.2.0"
|
version "4.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
|
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
|
||||||
|
|||||||
Reference in new issue
Block a user