Skip to content

Instantly share code, notes, and snippets.

@mikolalysenko
Created October 23, 2017 10:18
Show Gist options
  • Save mikolalysenko/1b5c7485c4ab13145c1b3ce8436d4b22 to your computer and use it in GitHub Desktop.
Save mikolalysenko/1b5c7485c4ab13145c1b3ce8436d4b22 to your computer and use it in GitHub Desktop.
// install:
//
// npm install ndarray parse-magica-voxel
//
// usage:
//
// node vox-to-box.js my-file.vox > my-file.terrain
//
const parseMagicaVoxel = require('parse-magica-voxel')
const ndarray = require('ndarray')
const fs = require('fs')
function compress (voxels) {
const {
data,
shape: [nx, ny, nz],
stride: [sx, sy, sz],
offset,
} = voxels;
const rle = [];
let prevBlock = -1;
let runLength = 0;
let ptr = offset;
const stepi = sx;
const stepj = sy - sx * nx;
const stepk = sz - sy * ny;
for (let k = 0; k < nz; ++k) {
for (let j = 0; j < ny; ++j) {
for (let i = 0; i < nx; ++i) {
const b = data[ptr];
if (b !== prevBlock || runLength >= 65535) {
if (runLength) {
if (runLength >= 255) {
rle.push(
255,
runLength >> 8,
runLength & 0xff);
} else {
rle.push(runLength);
}
if (prevBlock >= 255) {
rle.push(
255,
prevBlock >> 8,
prevBlock & 0xff);
} else {
rle.push(prevBlock);
}
}
runLength = 0;
prevBlock = b;
}
runLength += 1;
ptr += stepi;
}
ptr += stepj;
}
ptr += stepk;
}
if (runLength >= 255) {
rle.push(
255,
runLength >> 8,
runLength & 0xff);
} else {
rle.push(runLength);
}
if (prevBlock >= 255) {
rle.push(
255,
prevBlock >> 8,
prevBlock & 0xff);
} else {
rle.push(prevBlock);
}
return rle;
}
function convertMagicaVoxelToBox (buffer) {
const data = parseMagicaVoxel(buffer)
if (!data.PACK) {
throw new Error('multiple chunks in file')
}
const shape = [
data.SIZE.x,
data.SIZE.y,
data.SIZE.z
]
const result = new ndarray(new Uint8Array(shape[0] * shape[1] * shape[2]), shape)
for (var k = 0; k < data.XYZI.length; ++k) {
const {x, y, z, c} = data.XYZI[k]
result.set(x, y, z, c | 0)
}
return result.transpose(1, 2, 0)
}
function patchBCMTemplate(rle, size) {
return JSON.stringify({
encoded: rle,
map_size: size,
"TERRAIN": "MagicaVoxel"
})
}
const data = fs.readFileSync(process.argv[2])
const voxels = convertMagicaVoxelToBox(data)
const rle = compress(voxels)
const result = patchBCMTemplate(rle, voxels.shape[0])
console.log(result)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment