DeerEngine/Tools/Blockbench/deer_engine_exporter.js

245 lines
6.8 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

let exporterAction;
function exportToDeerEngine() {
// Build your JSON structure and trigger download
var json = {
mesh: {
hasNormalData: true,
vertexPositions: [],
vertexNormals: [],
indices: [],
},
};
function addVertex(vector) {
json.mesh.vertexPositions.push({
x: Math.round((vector[0] / 16) * 256),
y: Math.round((vector[1] / 16) * 256),
z: Math.round((vector[2] / 16) * 256),
});
return json.mesh.vertexPositions.length - 1;
}
function addIndex(indexID) {
json.mesh.indices.push(indexID);
}
function addNormal(normal) {
json.mesh.vertexNormals.push({
x: Math.round(normal[0] * 64),
y: Math.round(normal[1] * 64),
z: Math.round(normal[2] * 64),
});
}
Mesh.all.forEach((mesh) => {
function getWorldPosition(v) {
const mat = mesh.mesh.matrixWorld; // mat4 (THREE.Matrix4)
const vec = new THREE.Vector3(v[0], v[1], v[2]);
vec.applyMatrix4(mat);
// Convert to your engines left-handed space: flip Y and Z
return [vec.x, vec.y, -vec.z];
}
for (const fkey in mesh.faces) {
const face = mesh.faces[fkey];
var verticesIDs = [];
for (const vKey of face.vertices) {
const position = getWorldPosition(mesh.vertices[vKey]);
verticesIDs.push(addVertex(position));
}
// DEER ENGINE IS CLOCK FACE
//for (var i = 0; i < verticesIDs.length; i++) {
// addIndex(verticesIDs[i]);
//}
if (verticesIDs.length == 3) {
addIndex(verticesIDs[0]);
addIndex(verticesIDs[2]);
addIndex(verticesIDs[1]);
} else if (verticesIDs.length == 4) {
addIndex(verticesIDs[0]);
addIndex(verticesIDs[2]);
addIndex(verticesIDs[1]);
addIndex(verticesIDs[1]);
addIndex(verticesIDs[2]);
addIndex(verticesIDs[3]);
}
// Normal calulation
var origin = getWorldPosition(mesh.vertices[face.vertices[0]]);
var dirBRef = getWorldPosition(mesh.vertices[face.vertices[1]]);
var dirARef = getWorldPosition(mesh.vertices[face.vertices[2]]);
var dirA = [0, 0, 0];
var dirB = [0, 0, 0];
for (var i = 0; i < 3; i++) {
dirB[i] = dirARef[i] - origin[i];
dirA[i] = dirBRef[i] - origin[i];
}
var normalDir = [0, 0, 0];
normalDir[0] = dirB[1] * dirA[2] - dirB[2] * dirA[1];
normalDir[1] = dirB[2] * dirA[0] - dirB[0] * dirA[2];
normalDir[2] = dirB[0] * dirA[1] - dirB[1] * dirA[0];
var normalMagnitude = Math.sqrt(
normalDir[0] * normalDir[0] +
normalDir[1] * normalDir[1] +
normalDir[2] * normalDir[2]
);
for (var i = 0; i < 3; i++) {
normalDir[i] = normalDir[i] / normalMagnitude;
}
for (var i = 0; i < verticesIDs.length; i++) {
addNormal(normalDir);
}
}
});
const face_corners = {
north: [5, 4, 7, 6],
east: [1, 5, 3, 7],
south: [0, 1, 2, 3],
west: [4, 0, 6, 2],
up: [2, 3, 6, 7],
down: [4, 5, 0, 1],
};
Cube.all.forEach((cube) => {
// Cubes are simpler: they have 6 faces and 8 vertices
const mat = cube.mesh.matrixWorld;
function getWorldPosition(v) {
const vec = new THREE.Vector3(v[0], v[1], v[2]);
vec.applyMatrix4(mat);
return [vec.x, vec.y, -vec.z]; // Flip Z to match left-handed
}
// cube.from and cube.to define the min and max corners
const from = cube.from; // [x, y, z]
const to = cube.to; // [x, y, z]
const corners = [
[from[0], from[1], from[2]],
[to[0], from[1], from[2]],
[from[0], to[1], from[2]],
[to[0], to[1], from[2]],
[from[0], from[1], to[2]],
[to[0], from[1], to[2]],
[from[0], to[1], to[2]],
[to[0], to[1], to[2]],
];
for (var i = 0; i < corners.length; i++) {
corners[i][0] -= cube.origin[0];
corners[i][1] -= cube.origin[1];
corners[i][2] -= cube.origin[2];
}
for (const fkey in cube.faces) {
const face = cube.faces[fkey];
const verticesIDs = [];
const corner_indices = face_corners[fkey]; // get the right 4 corner indices
if (!corner_indices) continue; // just in case
const face_vertices = corner_indices.map((i) => corners[i]);
for (const v of face_vertices) {
const position = getWorldPosition(v);
verticesIDs.push(addVertex(position));
}
if (verticesIDs.length == 4) {
addIndex(verticesIDs[0]);
addIndex(verticesIDs[1]);
addIndex(verticesIDs[2]);
addIndex(verticesIDs[1]);
addIndex(verticesIDs[3]);
addIndex(verticesIDs[2]);
}
// Calculate normal like in your mesh code
var origin = getWorldPosition(face_vertices[0]);
var dirBRef = getWorldPosition(face_vertices[1]);
var dirARef = getWorldPosition(face_vertices[2]);
var dirA = [0, 0, 0];
var dirB = [0, 0, 0];
for (var i = 0; i < 3; i++) {
dirA[i] = dirARef[i] - origin[i];
dirB[i] = dirBRef[i] - origin[i];
}
var normalDir = [0, 0, 0];
normalDir[0] = dirB[1] * dirA[2] - dirB[2] * dirA[1];
normalDir[1] = dirB[2] * dirA[0] - dirB[0] * dirA[2];
normalDir[2] = dirB[0] * dirA[1] - dirB[1] * dirA[0];
var normalMagnitude = Math.sqrt(
normalDir[0] * normalDir[0] +
normalDir[1] * normalDir[1] +
normalDir[2] * normalDir[2]
);
for (var i = 0; i < 3; i++) {
normalDir[i] = normalDir[i] / normalMagnitude;
}
for (var i = 0; i < verticesIDs.length; i++) {
addNormal(normalDir);
}
}
});
Blockbench.export({
type: "DeerMesh",
extensions: ["dmesh"],
name: Project.name,
content: autoStringify(json),
});
/*
Blockbench.showQuickMessage(
PathModule.join(folder, Project.name + ".dmesh"),
10000
);
Blockbench.writeFile(PathModule.join(folder, Project.name + ".dmesh"), {
content: autoStringify(json),
});*/
}
Plugin.register("deer_engine_exporter", {
title: "Deer Engine",
author: "Chewico",
description: "Utilities to work with Deer Engine",
icon: "export", // any valid Blockbench icon :contentReference[oaicite:5]{index=5}
version: "1.0.0",
variant: "both", // supports desktop & web
onload() {
// (1) Create the export action
exporterAction = new Action("export_deer_engine_json", {
name: "Export to Deer Engine Mesh Format",
icon: "export",
click() {
//visibleOverridesDialog.show();
exportToDeerEngine();
},
});
// (2) Add it under File → Export (top position)
MenuBar.addAction(exporterAction, "file.export.0"); // “export” submenu, index 0 :contentReference[oaicite:6]{index=6}
},
onunload() {
// Remove the action when plugin unloads
exporterAction.delete();
},
});