diff options
Diffstat (limited to 'examples/vulkan/shared/objconvert.js')
-rw-r--r-- | examples/vulkan/shared/objconvert.js | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/examples/vulkan/shared/objconvert.js b/examples/vulkan/shared/objconvert.js new file mode 100644 index 0000000000..9b49e3cdac --- /dev/null +++ b/examples/vulkan/shared/objconvert.js @@ -0,0 +1,241 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +var fs = require('fs'); + +var metadata = { + vertexCount: 0, + aabb: [[null, null], [null, null], [null, null]], + emitVertex: function(v) { + ++metadata.vertexCount; + var aabb = metadata.aabb; + if (aabb[0][0] === null || v[0] < aabb[0][0]) // min x + aabb[0][0] = v[0]; + if (aabb[0][1] === null || v[0] > aabb[0][1]) // max x + aabb[0][1] = v[0]; + if (aabb[1][0] === null || v[1] < aabb[1][0]) // min y + aabb[1][0] = v[1]; + if (aabb[1][1] === null || v[1] > aabb[1][1]) // max y + aabb[1][1] = v[1]; + if (aabb[2][0] === null || v[2] < aabb[2][0]) // min z + aabb[2][0] = v[2]; + if (aabb[2][1] === null || v[2] > aabb[2][1]) // max z + aabb[2][1] = v[2]; + }, + getBuffer: function() { + var aabb = metadata.aabb; + console.log(metadata.vertexCount + " vertices"); + console.log("AABB: " + aabb[0][0] + ".." + aabb[0][1] + + ", " + aabb[1][0] + ".." + aabb[1][1] + + ", " + aabb[2][0] + ".." + aabb[2][1]); + var buf = new Buffer((2 + 6) * 4); + var format = 1, p = 0; + buf.writeUInt32LE(format, p++); + buf.writeUInt32LE(metadata.vertexCount, p++ * 4); + for (var i = 0; i < 3; ++i) { + buf.writeFloatLE(aabb[i][0], p++ * 4); + buf.writeFloatLE(aabb[i][1], p++ * 4); + } + return buf; + } +}; + +function makeVec(s, n) { + var v = []; + s.split(' ').forEach(function (coordStr) { + var coord = parseFloat(coordStr); + if (!isNaN(coord)) + v.push(coord); + }); + if (v.length != n) { + console.error("Wrong vector size, expected " + n + ", got " + v.length); + process.exit(); + } + return v; +} + +function parseObj(filename, callback) { + fs.readFile(filename, "ascii", function (err, data) { + if (err) + throw err; + var groupCount = 0; + var parsed = { 'vertices': [], 'normals': [], 'texcoords': [], 'links': [] }; + var missingTexCount = 0, missingNormCount = 0; + data.split('\n').forEach(function (line) { + var s = line.trim(); + if (!s.length || groupCount > 1) + return; + if (s[0] === '#') + return; + if (s[0] === 'g') { + ++groupCount; + } else if (s.substr(0, 2) === "v ") { + parsed.vertices.push(makeVec(s, 3)); + } else if (s.substr(0, 3) === "vn ") { + parsed.normals.push(makeVec(s, 3)); + } else if (s.substr(0, 3) === "vt ") { + parsed.texcoords.push(makeVec(s, 2)); + } else if (s.substr(0, 2) === "f ") { + var refs = s.split(' '); + var vertCount = refs.length - 1; + if (vertCount != 3) + console.warn("Face " + parsed.links.length / 3 + " has " + vertCount + " vertices! (not triangulated?)"); + for (var i = 1, ie = Math.min(4, refs.length); i < ie; ++i) { + var refComps = refs[i].split('/'); + var vertIndex = parseInt(refComps[0]) - 1; + var texIndex = -1; + if (refComps.length >= 2 && refComps[1].length) + texIndex = parseInt(refComps[1]) - 1; + var normIndex = -1; + if (refComps.length >= 3 && refComps[2].length) + normIndex = parseInt(refComps[2]) - 1; + parsed.links.push([vertIndex, texIndex, normIndex]); + if (texIndex == -1) + ++missingTexCount; + if (normIndex == -1) + ++missingNormCount; + } + } + }); + console.log(missingTexCount + " missing texture coordinates, " + missingNormCount + " missing normals"); + callback(parsed); + }); +} + +function fillVert(src, index, dst, elemCount, isVertexCoord) { + var vertex = []; + if (index >= 0) { + for (var i = 0; i < elemCount; ++i) { + var elem = src[index][i]; + if (isVertexCoord) + vertex.push(elem); + dst.buf.writeFloatLE(elem, dst.bufptr++ * 4); + } + if (vertex.length == 3) + metadata.emitVertex(vertex); + } else { + if (isVertexCoord) { + console.error("Missing vertex"); + process.exit(); + } + for (var i = 0; i < elemCount; ++i) + dst.buf.writeFloatLE(0, dst.bufptr++ * 4); + } + return vertex; +} + +function normalize(v) { + var len = v[0] * v[0] + v[1] * v[1] + v[2] * v[2]; + if (len == 0.0 || len == 1.0) + return; + len = Math.sqrt(len); + return [ v[0] / len, v[1] / len, v[2] / len ]; +} + +function surfaceNormal(a, b, c) { + var u = [ b[0] - a[0], b[1] - a[1], b[2] - a[2] ]; + var v = [ c[0] - a[0], c[1] - a[1], c[2] - a[2] ]; + var result = [ u[1] * v[2] - u[2] * v[1], + u[2] * v[0] - u[0] * v[2], + u[0] * v[1] - u[1] * v[0] ]; + return normalize(result); +} + +function objDataToBuf(parsed) { + var floatCount = parsed.links.length * (3 + 2 + 3); + var buf = new Buffer(floatCount * 4); + var dst = { 'buf': buf, 'bufptr': 0 }; + var tri = []; + var genNormals = false; + var genNormCount = 0; + for (var i = 0; i < parsed.links.length; ++i) { + var link = parsed.links[i]; + var vertIndex = link[0], texIndex = link[1], normIndex = link[2]; + tri.push(fillVert(parsed.vertices, vertIndex, dst, 3, true)); + fillVert(parsed.texcoords, texIndex, dst, 2); + fillVert(parsed.normals, normIndex, dst, 3); + if (normIndex == -1) + genNormals = true; + if (tri.length == 3) { + if (genNormals) { + var norm = surfaceNormal(tri[0], tri[1], tri[2]); + for (var nvIdx = 0; nvIdx < 3; ++nvIdx) { + dst.buf.writeFloatLE(norm[0], (dst.bufptr - 3 - nvIdx * 8) * 4); + dst.buf.writeFloatLE(norm[1], (dst.bufptr - 2 - nvIdx * 8) * 4); + dst.buf.writeFloatLE(norm[2], (dst.bufptr - 1 - nvIdx * 8) * 4); + } + genNormCount += 3; + } + tri = []; + } + } + if (genNormCount) + console.log("Generated " + genNormCount + " normals"); + return buf; +} + +var inFilename = process.argv[2]; +var outFilename = process.argv[3]; + +if (process.argv.length < 4) { + console.log("Usage: objconvert file.obj file.buf"); + process.exit(); +} + +parseObj(inFilename, function (parsed) { + var buf = objDataToBuf(parsed); + var f = fs.createWriteStream(outFilename); + f.on("error", function (e) { console.error(e); }); + f.write(metadata.getBuffer()); + f.write(buf); + f.end(); + console.log("Written to " + outFilename + ", format is:"); + console.log(" uint32 version, uint32 vertex_count, float32 aabb[6], vertex_count * (float32 vertex[3], float32 texcoord[2], float32 normal[3])"); +}); |