-
Notifications
You must be signed in to change notification settings - Fork 3
/
QBToAOVerts.js
121 lines (98 loc) · 4.1 KB
/
QBToAOVerts.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
var ndarray = require("ndarray");
var createAOMesh = require("ao-mesher");
var parseQubicle = require('parse-qubicle');
var paddVoxelNDArray = require('./paddVoxelNDArray.js');
var fs = require('fs');
var argv = require('minimist')(process.argv.slice(2));
var mechSniperActions = require('../src/assets/mechsniper-actions.json');
//Convert Blender JointNames to match Qubicle Chunk names Foot.R -> FootR
Object.keys(mechSniperActions.joint_index).forEach((jointName) => {
if (jointName.match(/\./)) {
var newName = jointName.replace('.', '');
mechSniperActions.joint_index[newName] = mechSniperActions.joint_index[jointName];
delete mechSniperActions.joint_index[jointName]
}
});
const filepath = argv._[0];
const pathChunks = filepath.split('/')
const fileName = pathChunks[pathChunks.length - 1].split('.')[0];
const outputDir = './public/assets/';
const paletteMap = {};
function qbToNDArray(qbMatrix) {
const x = qbMatrix.sizeX
const y = qbMatrix.sizeY
const z = qbMatrix.sizeZ
const n = ndarray(
new Int32Array(x * y * z),
[x, y, z]
);
var jointId = mechSniperActions.joint_index[qbMatrix.name];
const weaponRegEx = /(Gun|Sword)(L|R)/g;
if (!jointId) {
const capture = weaponRegEx.exec(qbMatrix.name)
if (capture) {
jointId = mechSniperActions.joint_index[`Hand${capture[2]}`];
} else {
jointId = mechSniperActions.joint_index['Chest'];
}
}
qbMatrix.matrix.forEach(function (voxel, index) {
const colorKey = [voxel.r, voxel.g, voxel.b].join('|');
if (typeof paletteMap[colorKey] === 'undefined') {
paletteMap[colorKey] = Object.keys(paletteMap).length;
}
//This is a trick
// The joint and palette indexs are packed in to a single byte 255 max
// because joint can be > 15 we can't use two, 4bit numbers
// joint is always <= 25 and palette is always <= 5
// so we glue them together into an 8bit number
// joint=25 + palette=5 = combo=255
// joint=12 + palette=3 = combo = 123
// they are seperated at runtime by digits place
// 134 = joint=14, palette=4
if (jointId > 25) throw `Overflow error on ${qbMatrix.name} jontId > 25`;
if (paletteMap[colorKey] > 9) throw `Overflow error on ${qbMatrix.name} palette > 9 `;
if (jointId === 25 && paletteMap[colorKey] > 5) throw `Overflow error on ${qbMatrix.name} jointId == 25 palete `;
const jointAndPaletteDecmialCombo = Number(String(jointId) + String(paletteMap[colorKey]));
if (jointAndPaletteDecmialCombo > 255) throw "Overflow on joint and palette index";
console.log(`${qbMatrix.name}: voxel: ${index} joinId ${jointId} + palette ${paletteMap[colorKey]} = `, jointAndPaletteDecmialCombo);
n.set(
voxel.x,
voxel.y,
voxel.z,
jointAndPaletteDecmialCombo,
);
});
return n;
};
const getQBFile = (err, data) => {
var qbMatrix = parseQubicle(data);
qbMatrix.matrixList.forEach((matrix, index) => {
var ndvoxels = qbToNDArray(matrix, index);
var voxelsWithPadding = paddVoxelNDArray(ndvoxels);
var aoMesh = createAOMesh(voxelsWithPadding);
//Qubicle comes in layers offset from the center of a world model
//The voxels are converted to verts in condensed local voxel space
//This loses the world offset value
//This offset has to be added to the ndarray for the space size
//Additional, this offset then needs to be applied to individual voxels
//I can't bump the verts here because some of the offsets are negative and
//This offsets them from 0,0,0 origin. They are then centered in code at import time
var i = 0;
while (i < aoMesh.length) {
aoMesh[i] += matrix.posX;
aoMesh[i + 1] += matrix.posY;
aoMesh[i + 2] += matrix.posZ;
// we pack two values in to the last byte.
// the tex_id/palette index and the joint index
//aoMesh[i+7]
i += 8;
}
console.log('palette:', paletteMap);
fs.writeFile(`${outputDir}${fileName}-${matrix.name}.aoverts`, aoMesh, (err) => {
if (err) throw err;
console.log(`${outputDir}${fileName}-${matrix.name}.aoverts `, aoMesh.byteLength);
});
});
};
fs.readFile(filepath, getQBFile);