update
This commit is contained in:
44
mesh_import/Bundled/cube.obj
Normal file
44
mesh_import/Bundled/cube.obj
Normal file
@ -0,0 +1,44 @@
|
||||
# Blender v2.80 (sub 41) OBJ File: ''
|
||||
# www.blender.org
|
||||
o Cube
|
||||
v 1.000000 1.000000 -1.000000
|
||||
v 1.000000 -1.000000 -1.000000
|
||||
v 1.000000 1.000000 1.000000
|
||||
v 1.000000 -1.000000 1.000000
|
||||
v -1.000000 1.000000 -1.000000
|
||||
v -1.000000 -1.000000 -1.000000
|
||||
v -1.000000 1.000000 1.000000
|
||||
v -1.000000 -1.000000 1.000000
|
||||
vt 0.375000 0.000000
|
||||
vt 0.625000 0.000000
|
||||
vt 0.625000 0.250000
|
||||
vt 0.375000 0.250000
|
||||
vt 0.375000 0.250000
|
||||
vt 0.625000 0.250000
|
||||
vt 0.625000 0.500000
|
||||
vt 0.375000 0.500000
|
||||
vt 0.625000 0.750000
|
||||
vt 0.375000 0.750000
|
||||
vt 0.625000 0.750000
|
||||
vt 0.625000 1.000000
|
||||
vt 0.375000 1.000000
|
||||
vt 0.125000 0.500000
|
||||
vt 0.375000 0.500000
|
||||
vt 0.375000 0.750000
|
||||
vt 0.125000 0.750000
|
||||
vt 0.625000 0.500000
|
||||
vt 0.875000 0.500000
|
||||
vt 0.875000 0.750000
|
||||
vn 0.0000 1.0000 0.0000
|
||||
vn 0.0000 0.0000 1.0000
|
||||
vn -1.0000 0.0000 0.0000
|
||||
vn 0.0000 -1.0000 0.0000
|
||||
vn 1.0000 0.0000 0.0000
|
||||
vn 0.0000 0.0000 -1.0000
|
||||
s off
|
||||
f 1/1/1 5/2/1 7/3/1 3/4/1
|
||||
f 4/5/2 3/6/2 7/7/2 8/8/2
|
||||
f 8/8/3 7/7/3 5/9/3 6/10/3
|
||||
f 6/10/4 2/11/4 4/12/4 8/13/4
|
||||
f 2/14/5 1/15/5 3/16/5 4/17/5
|
||||
f 6/18/6 5/19/6 1/20/6 2/11/6
|
||||
67
mesh_import/Sources/lnx/ImportMesh.hx
Normal file
67
mesh_import/Sources/lnx/ImportMesh.hx
Normal file
@ -0,0 +1,67 @@
|
||||
package lnx;
|
||||
|
||||
import iron.Scene;
|
||||
import iron.data.SceneFormat;
|
||||
import iron.data.Data;
|
||||
import iron.data.MeshData;
|
||||
import iron.data.MaterialData;
|
||||
import iron.system.Input;
|
||||
|
||||
class ImportMesh extends iron.Trait {
|
||||
|
||||
var meshData:MeshData;
|
||||
var materials:haxe.ds.Vector<MaterialData>;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
|
||||
// Get raw blob
|
||||
Data.getBlob("cube.obj", function(blob:kha.Blob) {
|
||||
|
||||
// Parse obj file
|
||||
var mesh = new ObjParser(blob);
|
||||
|
||||
// Positions, normals and indices
|
||||
var pos:TVertexArray = { attrib: "pos", values: mesh.posa, data: "short4norm" };
|
||||
var nor:TVertexArray = { attrib: "nor", values: mesh.nora, data: "short2norm" };
|
||||
var ind:TIndexArray = { material: 0, values: mesh.inda };
|
||||
|
||||
var rawmeshData:TMeshData = {
|
||||
name: "BoxMesh",
|
||||
vertex_arrays: [pos, nor],
|
||||
index_arrays: [ind],
|
||||
// Usable to scale positions over the (-1, 1) range
|
||||
scale_pos: mesh.scalePos
|
||||
};
|
||||
|
||||
// Construct new mesh
|
||||
new MeshData(rawmeshData, function(data:MeshData) {
|
||||
meshData = data;
|
||||
meshData.geom.calculateAABB();
|
||||
|
||||
// Fetch material from scene data
|
||||
Data.getMaterial("Scene", "Material", function(data:MaterialData) {
|
||||
// Material loaded
|
||||
materials = haxe.ds.Vector.fromData([data]);
|
||||
notifyOnUpdate(update);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function update() {
|
||||
// Left mouse button was pressed / display touched
|
||||
var mouse = Input.getMouse();
|
||||
if (mouse.down()) {
|
||||
// Create new object in active scene
|
||||
var object = Scene.active.addMeshObject(meshData, materials);
|
||||
|
||||
// Just for testing, add rigid body trait
|
||||
var aabb = meshData.geom.aabb;
|
||||
object.transform.loc.set(Math.random() * 8 - 4, Math.random() * 8 - 4, 5);
|
||||
object.transform.buildMatrix();
|
||||
object.transform.dim.set(aabb.x, aabb.y, aabb.z);
|
||||
object.addTrait(new leenkx.trait.physics.RigidBody());
|
||||
}
|
||||
}
|
||||
}
|
||||
395
mesh_import/Sources/lnx/ObjParser.hx
Normal file
395
mesh_import/Sources/lnx/ObjParser.hx
Normal file
@ -0,0 +1,395 @@
|
||||
package lnx;
|
||||
|
||||
class ObjParser {
|
||||
|
||||
public static var splitCode = "o".code; // Object split, "g" for groups, "u"semtl for materials
|
||||
public var posa: kha.arrays.Int16Array = null;
|
||||
public var nora: kha.arrays.Int16Array = null;
|
||||
public var texa: kha.arrays.Int16Array = null;
|
||||
public var inda: kha.arrays.Uint32Array = null;
|
||||
public var udims: Array<kha.arrays.Uint32Array> = null; // Indices split per udim tile
|
||||
public var udimsU = 1; // Number of horizontal udim tiles
|
||||
public var scalePos = 1.0;
|
||||
public var scaleTex = 1.0;
|
||||
public var name = "";
|
||||
public var hasNext = false; // File contains multiple objects
|
||||
public var pos = 0;
|
||||
var posTemp: Array<Float>;
|
||||
var uvTemp: Array<Float>;
|
||||
var norTemp: Array<Float>;
|
||||
var va: kha.arrays.Uint32Array;
|
||||
var ua: kha.arrays.Uint32Array;
|
||||
var na: kha.arrays.Uint32Array;
|
||||
var vi = 0;
|
||||
var ui = 0;
|
||||
var ni = 0;
|
||||
var buf: haxe.io.UInt8Array = null;
|
||||
|
||||
static var vindOff = 0;
|
||||
static var tindOff = 0;
|
||||
static var nindOff = 0;
|
||||
static var bytes: haxe.io.Bytes = null;
|
||||
static var posFirst: Array<Float>;
|
||||
static var uvFirst: Array<Float>;
|
||||
static var norFirst: Array<Float>;
|
||||
|
||||
public function new(blob: kha.Blob, startPos = 0, udim = false) {
|
||||
pos = startPos;
|
||||
var posIndices: Array<Int> = [];
|
||||
var uvIndices: Array<Int> = [];
|
||||
var norIndices: Array<Int> = [];
|
||||
var readingFaces = false;
|
||||
var readingObject = false;
|
||||
var fullAttrib = false;
|
||||
bytes = blob.bytes;
|
||||
|
||||
posTemp = [];
|
||||
uvTemp = [];
|
||||
norTemp = [];
|
||||
va = new kha.arrays.Uint32Array(60);
|
||||
ua = new kha.arrays.Uint32Array(60);
|
||||
na = new kha.arrays.Uint32Array(60);
|
||||
buf = new haxe.io.UInt8Array(64);
|
||||
|
||||
if (splitCode == "u".code && startPos > 0) {
|
||||
posTemp = posFirst;
|
||||
norTemp = norFirst;
|
||||
uvTemp = uvFirst;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
if (pos >= bytes.length) break;
|
||||
|
||||
var c0 = bytes.get(pos++);
|
||||
if (readingObject && readingFaces && (c0 == "v".code || c0 == splitCode)) {
|
||||
pos--;
|
||||
hasNext = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (c0 == "v".code) {
|
||||
var c1 = bytes.get(pos++);
|
||||
if (c1 == " ".code) {
|
||||
// Some exporters put additional space directly after "v"
|
||||
if (bytes.get(pos) == " ".code) pos++;
|
||||
posTemp.push(readFloat());
|
||||
pos++; // Space
|
||||
posTemp.push(readFloat());
|
||||
pos++; // Space
|
||||
posTemp.push(readFloat());
|
||||
}
|
||||
else if (c1 == "t".code) {
|
||||
pos++; // Space
|
||||
uvTemp.push(readFloat());
|
||||
pos++; // Space
|
||||
uvTemp.push(readFloat());
|
||||
if (norTemp.length > 0) fullAttrib = true;
|
||||
}
|
||||
else if (c1 == "n".code) {
|
||||
pos++; // Space
|
||||
norTemp.push(readFloat());
|
||||
pos++; // Space
|
||||
norTemp.push(readFloat());
|
||||
pos++; // Space
|
||||
norTemp.push(readFloat());
|
||||
if (uvTemp.length > 0) fullAttrib = true;
|
||||
}
|
||||
}
|
||||
else if (c0 == "f".code) {
|
||||
pos++; // Space
|
||||
readingFaces = true;
|
||||
vi = 0;
|
||||
ui = 0;
|
||||
ni = 0;
|
||||
fullAttrib ? readFaceFast() : readFace();
|
||||
|
||||
posIndices.push(va[0]);
|
||||
posIndices.push(va[1]);
|
||||
posIndices.push(va[2]);
|
||||
for (i in 3...vi) {
|
||||
posIndices.push(va[0]);
|
||||
posIndices.push(va[i - 1]);
|
||||
posIndices.push(va[i]);
|
||||
}
|
||||
if (uvTemp.length > 0) {
|
||||
uvIndices.push(ua[0]);
|
||||
uvIndices.push(ua[1]);
|
||||
uvIndices.push(ua[2]);
|
||||
for (i in 3...ui) {
|
||||
uvIndices.push(ua[0]);
|
||||
uvIndices.push(ua[i - 1]);
|
||||
uvIndices.push(ua[i]);
|
||||
}
|
||||
}
|
||||
if (norTemp.length > 0) {
|
||||
norIndices.push(na[0]);
|
||||
norIndices.push(na[1]);
|
||||
norIndices.push(na[2]);
|
||||
for (i in 3...ni) {
|
||||
norIndices.push(na[0]);
|
||||
norIndices.push(na[i - 1]);
|
||||
norIndices.push(na[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (c0 == splitCode) {
|
||||
if (splitCode == "u".code) pos += 5; // "u"semtl
|
||||
pos++; // Space
|
||||
if (!udim) readingObject = true;
|
||||
name = readString();
|
||||
}
|
||||
nextLine();
|
||||
}
|
||||
|
||||
if (startPos > 0) {
|
||||
if (splitCode != "u".code) {
|
||||
for (i in 0...posIndices.length) posIndices[i] -= vindOff;
|
||||
for (i in 0...uvIndices.length) uvIndices[i] -= tindOff;
|
||||
for (i in 0...norIndices.length) norIndices[i] -= nindOff;
|
||||
}
|
||||
}
|
||||
else {
|
||||
vindOff = tindOff = nindOff = 0;
|
||||
|
||||
if (splitCode == "u".code) {
|
||||
posFirst = posTemp;
|
||||
norFirst = norTemp;
|
||||
uvFirst = uvTemp;
|
||||
}
|
||||
}
|
||||
vindOff += Std.int(posTemp.length / 3); // Assumes separate vertex data per object
|
||||
tindOff += Std.int(uvTemp.length / 2);
|
||||
nindOff += Std.int(norTemp.length / 3);
|
||||
|
||||
// Pack positions to (-1, 1) range
|
||||
scalePos = 0.0;
|
||||
for (i in 0...posTemp.length) {
|
||||
var f = Math.abs(posTemp[i]);
|
||||
if (scalePos < f) scalePos = f;
|
||||
}
|
||||
var inv = 32767 * (1 / scalePos);
|
||||
|
||||
posa = new kha.arrays.Int16Array(posIndices.length * 4);
|
||||
inda = new kha.arrays.Uint32Array(posIndices.length);
|
||||
for (i in 0...posIndices.length) {
|
||||
posa[i * 4 ] = Std.int( posTemp[posIndices[i] * 3 ] * inv);
|
||||
posa[i * 4 + 1] = Std.int(-posTemp[posIndices[i] * 3 + 2] * inv);
|
||||
posa[i * 4 + 2] = Std.int( posTemp[posIndices[i] * 3 + 1] * inv);
|
||||
inda[i] = i;
|
||||
}
|
||||
|
||||
if (norIndices.length > 0) {
|
||||
nora = new kha.arrays.Int16Array(norIndices.length * 2);
|
||||
for (i in 0...posIndices.length) {
|
||||
nora[i * 2 ] = Std.int( norTemp[norIndices[i] * 3 ] * 32767);
|
||||
nora[i * 2 + 1] = Std.int(-norTemp[norIndices[i] * 3 + 2] * 32767);
|
||||
posa[i * 4 + 3] = Std.int( norTemp[norIndices[i] * 3 + 1] * 32767);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Calc normals
|
||||
nora = new kha.arrays.Int16Array(inda.length * 2);
|
||||
var va = new iron.math.Vec4();
|
||||
var vb = new iron.math.Vec4();
|
||||
var vc = new iron.math.Vec4();
|
||||
var cb = new iron.math.Vec4();
|
||||
var ab = new iron.math.Vec4();
|
||||
for (i in 0...Std.int(inda.length / 3)) {
|
||||
var i1 = inda[i * 3 ];
|
||||
var i2 = inda[i * 3 + 1];
|
||||
var i3 = inda[i * 3 + 2];
|
||||
va.set(posa[i1 * 4], posa[i1 * 4 + 1], posa[i1 * 4 + 2]);
|
||||
vb.set(posa[i2 * 4], posa[i2 * 4 + 1], posa[i2 * 4 + 2]);
|
||||
vc.set(posa[i3 * 4], posa[i3 * 4 + 1], posa[i3 * 4 + 2]);
|
||||
cb.subvecs(vc, vb);
|
||||
ab.subvecs(va, vb);
|
||||
cb.cross(ab);
|
||||
cb.normalize();
|
||||
nora[i1 * 2 ] = Std.int(cb.x * 32767);
|
||||
nora[i1 * 2 + 1] = Std.int(cb.y * 32767);
|
||||
posa[i1 * 4 + 3] = Std.int(cb.z * 32767);
|
||||
nora[i2 * 2 ] = Std.int(cb.x * 32767);
|
||||
nora[i2 * 2 + 1] = Std.int(cb.y * 32767);
|
||||
posa[i2 * 4 + 3] = Std.int(cb.z * 32767);
|
||||
nora[i3 * 2 ] = Std.int(cb.x * 32767);
|
||||
nora[i3 * 2 + 1] = Std.int(cb.y * 32767);
|
||||
posa[i3 * 4 + 3] = Std.int(cb.z * 32767);
|
||||
}
|
||||
}
|
||||
|
||||
if (uvIndices.length > 0) {
|
||||
if (udim) {
|
||||
// Find number of tiles
|
||||
var tilesU = 1;
|
||||
var tilesV = 1;
|
||||
for (i in 0...Std.int(uvTemp.length / 2)) {
|
||||
while (uvTemp[i * 2 ] > tilesU) tilesU++;
|
||||
while (uvTemp[i * 2 + 1] > tilesV) tilesV++;
|
||||
}
|
||||
|
||||
function getTile(i1: Int, i2: Int, i3: Int): Int {
|
||||
var u1 = uvTemp[uvIndices[i1] * 2 ];
|
||||
var v1 = uvTemp[uvIndices[i1] * 2 + 1];
|
||||
var u2 = uvTemp[uvIndices[i2] * 2 ];
|
||||
var v2 = uvTemp[uvIndices[i2] * 2 + 1];
|
||||
var u3 = uvTemp[uvIndices[i3] * 2 ];
|
||||
var v3 = uvTemp[uvIndices[i3] * 2 + 1];
|
||||
var tileU = Std.int((u1 + u2 + u3) / 3);
|
||||
var tileV = Std.int((v1 + v2 + v3) / 3);
|
||||
return tileU + tileV * tilesU;
|
||||
}
|
||||
|
||||
// Amount of indices pre tile
|
||||
var num = new kha.arrays.Uint32Array(tilesU * tilesV);
|
||||
for (i in 0...Std.int(inda.length / 3)) {
|
||||
var tile = getTile(inda[i * 3], inda[i * 3 + 1], inda[i * 3 + 2]);
|
||||
num[tile] += 3;
|
||||
}
|
||||
|
||||
// Split indices per tile
|
||||
udims = [];
|
||||
udimsU = tilesU;
|
||||
for (i in 0...tilesU * tilesV) { udims.push(new kha.arrays.Uint32Array(num[i])); num[i] = 0; }
|
||||
|
||||
for (i in 0...Std.int(inda.length / 3)) {
|
||||
var i1 = inda[i * 3 ];
|
||||
var i2 = inda[i * 3 + 1];
|
||||
var i3 = inda[i * 3 + 2];
|
||||
var tile = getTile(i1, i2, i3);
|
||||
udims[tile][num[tile]++] = i1;
|
||||
udims[tile][num[tile]++] = i2;
|
||||
udims[tile][num[tile]++] = i3;
|
||||
}
|
||||
|
||||
// Normalize uvs to 0-1 range
|
||||
var uvtiles = new kha.arrays.Int16Array(uvTemp.length);
|
||||
for (i in 0...Std.int(inda.length / 3)) { // TODO: merge loops
|
||||
var i1 = inda[i * 3 ];
|
||||
var i2 = inda[i * 3 + 1];
|
||||
var i3 = inda[i * 3 + 2];
|
||||
var tile = getTile(i1, i2, i3);
|
||||
var tileU = tile % tilesU;
|
||||
var tileV = Std.int(tile / tilesU);
|
||||
uvtiles[uvIndices[i1] * 2 ] = tileU;
|
||||
uvtiles[uvIndices[i1] * 2 + 1] = tileV;
|
||||
uvtiles[uvIndices[i2] * 2 ] = tileU;
|
||||
uvtiles[uvIndices[i2] * 2 + 1] = tileV;
|
||||
uvtiles[uvIndices[i3] * 2 ] = tileU;
|
||||
uvtiles[uvIndices[i3] * 2 + 1] = tileV;
|
||||
}
|
||||
for (i in 0...uvtiles.length) uvTemp[i] -= uvtiles[i];
|
||||
}
|
||||
|
||||
texa = new kha.arrays.Int16Array(uvIndices.length * 2);
|
||||
for (i in 0...posIndices.length) {
|
||||
texa[i * 2 ] = Std.int( uvTemp[uvIndices[i] * 2 ] * 32767);
|
||||
texa[i * 2 + 1] = Std.int((1.0 - uvTemp[uvIndices[i] * 2 + 1]) * 32767);
|
||||
}
|
||||
}
|
||||
bytes = null;
|
||||
if (!hasNext) { posFirst = norFirst = uvFirst = null; }
|
||||
}
|
||||
|
||||
function readFaceFast() {
|
||||
while (true) {
|
||||
va[vi++] = readInt() - 1;
|
||||
pos++; // "/"
|
||||
ua[ui++] = readInt() - 1;
|
||||
pos++; // "/"
|
||||
na[ni++] = readInt() - 1;
|
||||
if (bytes.get(pos) == "\n".code || bytes.get(pos) == "\r".code) break;
|
||||
pos++; // " "
|
||||
// Some exporters put space at the end of "f" line
|
||||
if (vi >= 3 && (bytes.get(pos) == "\n".code || bytes.get(pos) == "\r".code)) break;
|
||||
}
|
||||
}
|
||||
|
||||
function readFace() {
|
||||
while (true) {
|
||||
va[vi++] = readInt() - 1;
|
||||
if (uvTemp.length > 0 || norTemp.length > 0) {
|
||||
pos++; // "/"
|
||||
}
|
||||
if (uvTemp.length > 0) {
|
||||
ua[ui++] = readInt() - 1;
|
||||
}
|
||||
if (norTemp.length > 0) {
|
||||
pos++; // "/"
|
||||
na[ni++] = readInt() - 1;
|
||||
}
|
||||
if (bytes.get(pos) == "\n".code || bytes.get(pos) == "\r".code) break;
|
||||
pos++; // " "
|
||||
// Some exporters put space at the end of "f" line
|
||||
if (vi >= 3 && (bytes.get(pos) == "\n".code || bytes.get(pos) == "\r".code)) break;
|
||||
}
|
||||
}
|
||||
|
||||
function readFloat(): Float {
|
||||
var bi = 0;
|
||||
while (true) { // Read into buffer
|
||||
var c = bytes.get(pos);
|
||||
if (c == " ".code || c == "\n".code || c == "\r".code) break;
|
||||
if (c == "E".code || c == "e".code) {
|
||||
while (true) {
|
||||
pos++;
|
||||
c = bytes.get(pos);
|
||||
if (c == " ".code || c == "\n".code || c == "\r".code) break;
|
||||
}
|
||||
return 0.0; // Assume number close to zero for now
|
||||
}
|
||||
pos++;
|
||||
buf[bi++] = c;
|
||||
}
|
||||
var res = 0.0; // Parse buffer into float
|
||||
var dot = 1;
|
||||
var dec = 1;
|
||||
var off = buf[0] == "-".code ? 1 : 0;
|
||||
var len = bi - 1;
|
||||
for (i in 0...bi - off) {
|
||||
var c = buf[len - i];
|
||||
if (c == ".".code) { dot = dec; continue; }
|
||||
res += (c - 48) * dec;
|
||||
dec *= 10;
|
||||
}
|
||||
off > 0 ? res /= -dot : res /= dot;
|
||||
return res;
|
||||
}
|
||||
|
||||
function readInt(): Int {
|
||||
var bi = 0;
|
||||
while (true) { // Read into buffer
|
||||
var c = bytes.get(pos);
|
||||
if (c == "/".code || c == "\n".code || c == "\r".code || c == " ".code) break;
|
||||
pos++;
|
||||
buf[bi++] = c;
|
||||
}
|
||||
var res = 0; // Parse buffer into int
|
||||
var dec = 1;
|
||||
var off = buf[0] == "-".code ? 1 : 0;
|
||||
var len = bi - 1;
|
||||
for (i in 0...bi - off) {
|
||||
res += (buf[len - i] - 48) * dec;
|
||||
dec *= 10;
|
||||
}
|
||||
if (off > 0) res *= -1;
|
||||
return res;
|
||||
}
|
||||
|
||||
function readString(): String {
|
||||
var s = "";
|
||||
while (true) {
|
||||
var c = bytes.get(pos);
|
||||
if (c == "\n".code || c == "\r".code || c == " ".code) break;
|
||||
pos++;
|
||||
s += String.fromCharCode(c);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
function nextLine() {
|
||||
while (true) {
|
||||
var c = bytes.get(pos++);
|
||||
if (c == "\n".code || pos >= bytes.length) break; // \n, \r\n
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
mesh_import/mesh_import.blend
Normal file
BIN
mesh_import/mesh_import.blend
Normal file
Binary file not shown.
Reference in New Issue
Block a user