In order to build a file converter with gltf/glb being the starting file type, i need input the data of the glb file first. When tring to do that, I encountered a negative arry error given the fact it tried to read the JSON part of the glb file
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.file.Files;
import java.nio.file.Paths;
public class glTFConverter implements ActionListener {
private static final String[] SUPPORTED_FILE_EXTENSIONS = {"gltf", "glb"};
private static final String[] SUPPORTED_OUTPUT_FORMATS = {"obj"};
private JFrame frame;
private JFileChooser fileChooser;
private JCheckBox keepOriginalCheckBox;
public glTFConverter() {
frame = new JFrame("GLTF to OBJ Converter");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 200);
frame.setLayout(new FlowLayout());
fileChooser = new JFileChooser();
FileNameExtensionFilter filter = new FileNameExtensionFilter("GLTF Files", SUPPORTED_FILE_EXTENSIONS);
fileChooser.setFileFilter(filter);
fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
JButton selectButton = new JButton("Select File or Folder");
selectButton.addActionListener(this);
keepOriginalCheckBox = new JCheckBox("Keep Original Files", true);
frame.add(selectButton);
frame.add(keepOriginalCheckBox);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("Select File or Folder")) {
int result = fileChooser.showOpenDialog(frame);
if (result == JFileChooser.APPROVE_OPTION) {
File selectedFile = fileChooser.getSelectedFile();
if (selectedFile.isDirectory()) {
convertFolder(selectedFile.getAbsolutePath());
} else {
convertFile(selectedFile.getAbsolutePath());
}
}
}
}
public void convertFolder(String folderPath) {
File folder = new File(folderPath);
if (!folder.exists() || !folder.isDirectory()) {
System.out.println("Invalid folder path: " + folderPath);
return;
}
File[] files = folder.listFiles();
if (files != null) {
for (File file : files) {
if (file.isFile()) {
convertFile(file.getAbsolutePath());
}
}
}
}
public void convertFile(String filePath) {
String fileExtension = getFileExtension(filePath);
if (fileExtension != null && isSupportedFileExtension(fileExtension)) {
String outputFormat = SUPPORTED_OUTPUT_FORMATS[0];
String outputFilePath = convertGLTFToOutputFormat(filePath, outputFormat);
if (outputFilePath != null) {
System.out.println("Converted file: " + outputFilePath);
// Delete the original file if required
if (!keepOriginalCheckBox.isSelected()) {
File originalFile = new File(filePath);
originalFile.delete();
}
}
} else {
System.out.println("Unsupported file extension: " + fileExtension);
}
}
private String convertGLTFToOutputFormat(String filePath, String outputFormat) {
String fileExtension = getFileExtension(filePath);
if (fileExtension.equalsIgnoreCase("gltf")) {
if (outputFormat.equalsIgnoreCase("obj")) {
return convertGLTFToOBJ(filePath);
} else {
System.out.println("Unsupported output format: " + outputFormat);
}
} else if (fileExtension.equalsIgnoreCase("glb")) {
if (outputFormat.equalsIgnoreCase("obj")) {
return convertGLBToOBJ(filePath);
} else {
System.out.println("Unsupported output format: " + outputFormat);
}
} else {
System.out.println("Unsupported file extension: " + fileExtension);
}
return null;
}
private String convertGLBToOBJ(String glbFilePath) {
try (DataInputStream dataInputStream = new DataInputStream(new FileInputStream(glbFilePath))) {
byte[] magic = new byte[4];
dataInputStream.readFully(magic);
if (!new String(magic).equals("glTF")) {
System.out.println("Invalid GLB file format: " + glbFilePath);
return null;
}
dataInputStream.skipBytes(8);
int jsonChunkLength = dataInputStream.readInt();
System.out.println("JSON Chunk Length: " + jsonChunkLength);
int jsonChunkType = dataInputStream.readInt();
System.out.println("JSON Chunk Type: " + jsonChunkType);
byte[] jsonChunkBytes = new byte[jsonChunkLength];
dataInputStream.readFully(jsonChunkBytes);
String jsonString = new String(jsonChunkBytes);
System.out.println("JSON String: " + jsonString);
String tempGLTFFilePath = convertGLBToGLTF(glbFilePath);
if (tempGLTFFilePath != null) {
JSONObject gltfJson = readGLTFFile(tempGLTFFilePath);
if (gltfJson != null) {
JSONArray gltfMeshes;
if (gltfJson.has("meshes")) {
Object meshes = gltfJson.get("meshes");
if (meshes instanceof JSONArray) {
gltfMeshes = (JSONArray) meshes;
} else {
gltfMeshes = new JSONArray().put(meshes);
}
} else {
gltfMeshes = new JSONArray();
}
JSONArray gltfNodes;
if (gltfJson.has("nodes")) {
Object nodes = gltfJson.get("nodes");
if (nodes instanceof JSONArray) {
gltfNodes = (JSONArray) nodes;
} else {
gltfNodes = new JSONArray().put(nodes);
}
} else {
gltfNodes = new JSONArray();
}
JSONObject gltfAccessors;
if (gltfJson.has("accessors") && gltfJson.get("accessors") instanceof JSONObject) {
gltfAccessors = gltfJson.getJSONObject("accessors");
} else {
gltfAccessors = new JSONObject();
}
String objFilePath = glbFilePath.replace(".glb", ".obj");
try (FileWriter fileWriter = new FileWriter(objFilePath);
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter)) {
bufferedWriter.write("# OBJ file");
bufferedWriter.newLine();
JSONArray positions = gltfAccessors.getJSONArray("POSITION");
for (int i = 0; i < positions.length(); i += 3) {
double x = positions.getJSONArray(i).getDouble(0);
double y = positions.getJSONArray(i + 1).getDouble(0);
double z = positions.getJSONArray(i + 2).getDouble(0);
bufferedWriter.write("v " + x + " " + y + " " + z);
bufferedWriter.newLine();
}
for (int i = 0; i < gltfMeshes.length(); i++) {
JSONObject mesh = gltfMeshes.getJSONObject(i);
JSONArray primitives = mesh.getJSONArray("primitives");
for (int j = 0; j < primitives.length(); j++) {
JSONObject primitive = primitives.getJSONObject(j);
JSONObject indicesObject = primitive.getJSONObject("indices");
JSONArray indicesArray = gltfAccessors.getJSONArray(indicesObject.getString("accessor"));
for (int k = 0; k < indicesArray.length(); k += 3) {
int index1 = indicesArray.getJSONArray(k).getInt(0) + 1;
int index2 = indicesArray.getJSONArray(k + 1).getInt(0) + 1;
int index3 = indicesArray.getJSONArray(k + 2).getInt(0) + 1;
bufferedWriter.write("f " + index1 + " " + index2 + " " + index3);
bufferedWriter.newLine();
}
}
}
}
return objFilePath;
}
}
} catch (EOFException e) {
System.out.println("Unexpected end of file encountered: " + glbFilePath);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private JSONObject readGLTFFile(String filePath) throws IOException {
byte[] bytes = Files.readAllBytes(Paths.get(filePath));
String jsonString = new String(bytes);
try {
return new JSONObject(jsonString);
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
private String getFileExtension(String filePath) {
int dotIndex = filePath.lastIndexOf(".");
if (dotIndex > 0 && dotIndex < filePath.length() - 1) {
return filePath.substring(dotIndex + 1).toLowerCase();
}
return null;
}
private boolean isSupportedFileExtension(String extension) {
for (String supportedExtension : SUPPORTED_FILE_EXTENSIONS) {
if (extension.equalsIgnoreCase(supportedExtension)) {
return true;
}
}
return false;
}
public static void main(String[] args) {
new glTFConverter();
}
}
Exception in thread "AWT-EventQueue-0" java.lang.NegativeArraySizeException
at glTFConverter.convertGLBToOBJ(glTFConverter.java:184)
at glTFConverter.convertGLTFToOutputFormat(glTFConverter.java:106)
JSON Chunk Length: -133890048
JSON Chunk Type: 1246973774
tried to work around that error with turning the negtive value positive and also in using a different start point when reading the JSON part of the file