package com.vitco.importer;
import com.vitco.util.file.FileIn;
import com.vitco.util.file.FileTools;
import com.vitco.util.file.RandomAccessFileIn;
import com.vitco.util.misc.NumberTools;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
public class VoxImporter extends AbstractImporter {
// constructor
public VoxImporter(File file, String name) throws IOException {
super(file, name);
}
private static final int[] voxColors = new int[] {
-1, -52, -103, -154, -205, -256, -13057, -13108, -13159, -13210, -13261, -13312, -26113, -26164, -26215, -26266,
-26317, -26368, -39169, -39220, -39271, -39322, -39373, -39424, -52225, -52276, -52327, -52378, -52429, -52480, -65281,
-65332, -65383, -65434, -65485, -65536, -3342337, -3342388, -3342439, -3342490, -3342541, -3342592, -3355393, -3355444,
-3355495, -3355546, -3355597, -3355648, -3368449, -3368500, -3368551, -3368602, -3368653, -3368704, -3381505, -3381556,
-3381607, -3381658, -3381709, -3381760, -3394561, -3394612, -3394663, -3394714, -3394765, -3394816, -3407617, -3407668,
-3407719, -3407770, -3407821, -3407872, -6684673, -6684724, -6684775, -6684826, -6684877, -6684928, -6697729, -6697780,
-6697831, -6697882, -6697933, -6697984, -6710785, -6710836, -6710887, -6710938, -6710989, -6711040, -6723841, -6723892,
-6723943, -6723994, -6724045, -6724096, -6736897, -6736948, -6736999, -6737050, -6737101, -6737152, -6749953, -6750004,
-6750055, -6750106, -6750157, -6750208, -10027009, -10027060, -10027111, -10027162, -10027213, -10027264, -10040065,
-10040116, -10040167, -10040218, -10040269, -10040320, -10053121, -10053172, -10053223, -10053274, -10053325, -10053376,
-10066177, -10066228, -10066279, -10066330, -10066381, -10066432, -10079233, -10079284, -10079335, -10079386, -10079437,
-10079488, -10092289, -10092340, -10092391, -10092442, -10092493, -10092544, -13369345, -13369396, -13369447, -13369498,
-13369549, -13369600, -13382401, -13382452, -13382503, -13382554, -13382605, -13382656, -13395457, -13395508, -13395559,
-13395610, -13395661, -13395712, -13408513, -13408564, -13408615, -13408666, -13408717, -13408768, -13421569, -13421620,
-13421671, -13421722, -13421773, -13421824, -13434625, -13434676, -13434727, -13434778, -13434829, -13434880, -16711681,
-16711732, -16711783, -16711834, -16711885, -16711936, -16724737, -16724788, -16724839, -16724890, -16724941, -16724992,
-16737793, -16737844, -16737895, -16737946, -16737997, -16738048, -16750849, -16750900, -16750951, -16751002, -16751053,
-16751104, -16763905, -16763956, -16764007, -16764058, -16764109, -16764160, -16776961, -16777012, -16777063, -16777114,
-16777165, -1179648, -2293760, -4521984, -5636096, -7864320, -8978432, -11206656, -12320768, -14548992, -15663104, -16716288,
-16720640, -16729344, -16733696, -16742400, -16746752, -16755456, -16759808, -16768512, -16772864, -16776978, -16776995,
-16777029, -16777046, -16777080, -16777097, -16777131, -16777148, -16777182, -16777199, -1118482, -2236963, -4473925,
-5592406, -7829368, -8947849, -11184811, -12303292, -14540254, -15658735, -16777216
};
// read file - returns true if file has loaded correctly
@Override
protected boolean read(FileIn fileIn, RandomAccessFileIn raf) throws IOException {
// check magic number
byte[] check = new byte[4];
raf.read(check);
String checkSum = new String(check, "ASCII");
if (!checkSum.equals("VOX ")) {
// this might be the voxel format from the voxlap engine (slab6)
raf.seek(0);
int sx = Integer.reverseBytes(raf.readInt());
int sy = Integer.reverseBytes(raf.readInt());
int sz = Integer.reverseBytes(raf.readInt());
if (sx > 512 || sy > 512 || sz > 512 || sx <= 0 || sy <= 0 || sz <= 0) {
// =====================
// vox-game.com format (voxel and config file)
// =====================
String[] line = fileIn.readLine().split(" ");
if (line.length == 3) {
sx = NumberTools.parseInt(line[0], 0);
sy = NumberTools.parseInt(line[1], 0);
sz = NumberTools.parseInt(line[2], 0);
} else if (line.length == 2) {
// check if this is a config file
if (line[0].equals("skeletonScale:")) {
float scale = NumberTools.parseFloat(line[1], 1);
// sanity check
if (!fileIn.readLine().equals("")) {
return false;
}
// read
String scaleLine;
float offx = 0, offy = 0, offz = 0;
while ((scaleLine = fileIn.readLine()) != null) {
if (scaleLine.length() > 8 && scaleLine.contains("Scale: ")) {
// extract name
String name = scaleLine.substring(0, scaleLine.indexOf(" ") - 6);
// extract offsets
String[] strOffx = fileIn.readLine().split(" ");
if (strOffx.length == 2) {
offx = NumberTools.parseFloat(strOffx[1], 0)/(10 * scale);
}
String[] strOffy = fileIn.readLine().split(" ");
if (strOffy.length == 2) {
offy = NumberTools.parseFloat(strOffy[1], 0)/(0.13f * scale);
}
String[] strOffz = fileIn.readLine().split(" ");
if (strOffz.length == 2) {
offz = NumberTools.parseFloat(strOffz[1], 0)/(0.05f * scale);
}
//System.out.println(offx + " " + offy + " " + offz);
// read the file and import voxel
if (name.equals("feet")) {
name = "foot";
} else if (name.equals("hands")) {
name = "hand";
}
File partFile = new File(FileTools.ensureTrailingSeparator(fileIn.getInternalFile().getParent()) + name + ".vox");
if (partFile.exists()) {
VoxImporter voxImporter = new VoxImporter(partFile, name);
if (voxImporter.hasLoaded()) {
for (Layer layer : voxImporter.getVoxel()) {
addLayer(layer.name);
for (int[] vox; layer.hasNext();) {
vox = layer.next();
// no need to rotate this (already rotated)
addVoxel(vox[0] - Math.round(offx), vox[1] - Math.round(offy), vox[2] + Math.round(offz), vox[3]);
}
}
}
}
}
}
return true;
}
}
// sanity check
if (sx > 512 || sy > 512 || sz > 512 || sx <= 0 || sy <= 0 || sz <= 0) {
return false;
}
// check that this line is empty
if (!fileIn.readLine().equals("")) {
return false;
}
// read to next space
for (int y = 0; y < sy; y++) {
for (int x = 0; x < sx; x++) {
for (int z = 0; z < sz; z++) {
int visible = NumberTools.parseInt(fileIn.readSpaceString(), 0);
int r = Math.round(NumberTools.parseFloat(fileIn.readSpaceString(), 0f) * 255);
int g = Math.round(NumberTools.parseFloat(fileIn.readSpaceString(), 0f) * 255);
int b = Math.round(NumberTools.parseFloat(fileIn.readSpaceString(), 0f) * 255);
if (visible == 1) {
addVoxel(-x,-y,z, new Color(r,g,b).getRGB());
}
}
}
}
return true;
} else {
// read over integer values
fileIn.skipBytes(12);
}
// =====================
// VOXLAP ENGINE *.vox FORMAT
// =====================
// Read the color palette (always at the end of the file)
raf.seek(raf.length() - 768);
int[] colPalette = new int[256];
for (int i = 0; i < 256; i++) {
int r = Math.min(255,Math.max(0,Math.round((raf.read() * 255)/63f)));
int g = Math.min(255,Math.max(0,Math.round((raf.read() * 255)/63f)));
int b = Math.min(255,Math.max(0,Math.round((raf.read() * 255)/63f)));
colPalette[i] = new Color(r, g, b).getRGB();
}
// read the voxel
for (int x = 0; x < sx; x++) {
for (int y = 0; y < sy; y++) {
for (int z = 0; z < sz; z++) {
int paletteEntry = fileIn.readByteUnsigned();
if (paletteEntry != 255) {
//noinspection SuspiciousNameCombination
addVoxel(x, z, -y, colPalette[paletteEntry]);
}
}
}
}
return true;
} else {
// skip over chechsum
fileIn.skipBytes(4);
}
// =====================
// MagicaVoxel *.vox FORMAT
// =====================
// check version number
int version = fileIn.readIntRev();
if (version < 150) {
return false;
}
// check main chunk identifier
if (!fileIn.readASCIIString(4).equals("MAIN")) {
return false;
}
int mainContentSize = fileIn.readIntRev();
int totalChildrenSize = fileIn.readIntRev();
// skip over the main content
if (!fileIn.skipBytes(mainContentSize)) {
return false;
}
ArrayList<Integer> voxels = new ArrayList<Integer>();
int[] palette = voxColors;
for (int i = 0; i < totalChildrenSize;) {
// each chunk has an ID, size and child chunks
String chunkName = fileIn.readASCIIString(4);
int chunkSize = fileIn.readIntRev();
fileIn.readIntRev();//int childChunks = fileIn.readIntRev();
if (chunkName.equals("SIZE")) {
// read x,y,z
fileIn.readIntRev();
fileIn.readIntRev();
fileIn.readIntRev();
} else if (chunkName.equals("XYZI")) {
int numVoxels = fileIn.readIntRev();
if (numVoxels < 0) { // sanity check
return false;
}
for (int j = 0; j < numVoxels; j += 1) {
voxels.add(fileIn.readInt());
}
} else if (chunkName.equals("RGBA")) {
// use custom color palette
palette = new int[256];
for (int j = 0; j < 256; j++) {
int r = fileIn.readByteUnsigned();
int g = fileIn.readByteUnsigned();
int b = fileIn.readByteUnsigned();
fileIn.readByteUnsigned();//int a = fileIn.readByteUnsigned();
palette[j] = new Color(r,g,b).getRGB();
}
} else {
fileIn.skipBytes(chunkSize);
}
i += 12 + chunkSize;
}
ByteBuffer buf = ByteBuffer.allocate(4);
for (Integer voxel : voxels) {
buf.position(0);
buf.putInt(voxel);
addVoxel(-(buf.get(0) & 0xFF), -(buf.get(2) & 0xFF), buf.get(1) & 0xFF, palette[(buf.get(3) & 0xFF) - 1]);
}
return true;
}
}