@threlte/gltf 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.js ADDED
@@ -0,0 +1,76 @@
1
+ import 'jsdom-global'
2
+ import fs from 'fs'
3
+ import path from 'path'
4
+ import transform from './utils/transform.js'
5
+
6
+ import prettier from 'prettier'
7
+ import THREE from 'three'
8
+ global.THREE = THREE
9
+
10
+ import './bin/GLTFLoader.js'
11
+ import DracoLoader from './bin/DRACOLoader.js'
12
+ THREE.DRACOLoader.getDecoderModule = () => {}
13
+ import parse from './utils/parser.js'
14
+
15
+ const gltfLoader = new THREE.GLTFLoader()
16
+ gltfLoader.setDRACOLoader(new DracoLoader())
17
+
18
+ function toArrayBuffer(buf) {
19
+ var ab = new ArrayBuffer(buf.length)
20
+ var view = new Uint8Array(ab)
21
+ for (var i = 0; i < buf.length; ++i) view[i] = buf[i]
22
+ return ab
23
+ }
24
+
25
+ export default function (file, output, options) {
26
+ function getRelativeFilePath(file) {
27
+ const filePath = path.resolve(file)
28
+ const rootPath = options.root ? path.resolve(options.root) : path.dirname(file)
29
+ const relativePath = path.relative(rootPath, filePath) || ''
30
+ if (process.platform === 'win32') return relativePath.replace(/\\/g, '/')
31
+ return relativePath
32
+ }
33
+
34
+ return new Promise((resolve, reject) => {
35
+ const stream = fs.createWriteStream(output)
36
+ stream.once('open', async (fd) => {
37
+ if (!fs.existsSync(file)) {
38
+ reject(file + ' does not exist.')
39
+ } else {
40
+ // Process GLTF
41
+ if (options.transform || options.instance || options.instanceall) {
42
+ const { name } = path.parse(file)
43
+ const transformOut = path.join(name + '-transformed.glb')
44
+ await transform(file, transformOut, options)
45
+ file = transformOut
46
+ }
47
+ resolve()
48
+
49
+ const filePath = getRelativeFilePath(file)
50
+ const data = fs.readFileSync(file)
51
+ const arrayBuffer = toArrayBuffer(data)
52
+ gltfLoader.parse(
53
+ arrayBuffer,
54
+ '',
55
+ (gltf) => {
56
+ const raw = parse(filePath, gltf, options)
57
+ const prettiered = prettier.format(raw, {
58
+ semi: false,
59
+ bracketSameLine: true,
60
+ svelteBracketNewLine: false,
61
+ printWidth: options.printwidth || 120,
62
+ svelteBracketNewLine: true,
63
+ singleQuote: true,
64
+ parser: 'svelte',
65
+ plugins: ['prettier-plugin-svelte']
66
+ })
67
+ stream.write(prettiered)
68
+ stream.end()
69
+ resolve()
70
+ },
71
+ reject
72
+ )
73
+ }
74
+ })
75
+ })
76
+ }
@@ -0,0 +1,5 @@
1
+ import parse from './parser'
2
+ import transform from './transform'
3
+ import GLTFStructureLoader from './glftLoader'
4
+
5
+ export { transform, parse, GLTFStructureLoader }
@@ -0,0 +1,4 @@
1
+ const THREE = (global.THREE = require('three'))
2
+ require('../bin/GLTFLoader')
3
+
4
+ module.exports = THREE.GLTFLoader
@@ -0,0 +1,10 @@
1
+ const isVarName = (str) => {
2
+ // eslint-disable-next-line no-misleading-character-class
3
+ const regex = new RegExp(
4
+ // eslint-disable-next-line no-misleading-character-class
5
+ /^(?!(?:do|if|in|for|let|new|try|var|case|else|enum|eval|null|this|true|void|with|await|break|catch|class|const|false|super|throw|while|yield|delete|export|import|public|return|static|switch|typeof|default|extends|finally|package|private|continue|debugger|function|arguments|interface|protected|implements|instanceof)$)(?:[$A-Z_a-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0560-\u0588\u05D0-\u05EA\u05EF-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u08A0-\u08B4\u08B6-\u08BD\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1878\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1C80-\u1C88\u1C90-\u1CBA\u1CBD-\u1CBF\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309B-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312F\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FEF\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7B9\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA8FE\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF2D-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE35\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2\uDD00-\uDD23\uDF00-\uDF1C\uDF27\uDF30-\uDF45]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD44\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDF00-\uDF1A]|\uD806[\uDC00-\uDC2B\uDCA0-\uDCDF\uDCFF\uDE00\uDE0B-\uDE32\uDE3A\uDE50\uDE5C-\uDE83\uDE86-\uDE89\uDE9D\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC72-\uDC8F\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD30\uDD46\uDD60-\uDD65\uDD67\uDD68\uDD6A-\uDD89\uDD98\uDEE0-\uDEF2]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDE40-\uDE7F\uDF00-\uDF44\uDF50\uDF93-\uDF9F\uDFE0\uDFE1]|\uD821[\uDC00-\uDFF1]|\uD822[\uDC00-\uDEF2]|\uD82C[\uDC00-\uDD1E\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4\uDD00-\uDD43]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D])(?:[\\$0-9A-Z_a-z\xAA\xB5\xB7\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0560-\u0588\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05EF-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u07FD\u0800-\u082D\u0840-\u085B\u0860-\u086A\u08A0-\u08B4\u08B6-\u08BD\u08D3-\u08E1\u08E3-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u09FC\u09FE\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0AF9-\u0AFF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58-\u0C5A\u0C60-\u0C63\u0C66-\u0C6F\u0C80-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D00-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D54-\u0D57\u0D5F-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1369-\u1371\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1878\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1C80-\u1C88\u1C90-\u1CBA\u1CBD-\u1CBF\u1CD0-\u1CD2\u1CD4-\u1CF9\u1D00-\u1DF9\u1DFB-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312F\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FEF\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA7B9\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C5\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA8FD-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2F\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDDFD\uDE80-\uDE9C\uDEA0-\uDED0\uDEE0\uDF00-\uDF1F\uDF2D-\uDF4A\uDF50-\uDF7A\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00-\uDE03\uDE05\uDE06\uDE0C-\uDE13\uDE15-\uDE17\uDE19-\uDE35\uDE38-\uDE3A\uDE3F\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE6\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2\uDD00-\uDD27\uDD30-\uDD39\uDF00-\uDF1C\uDF27\uDF30-\uDF50]|\uD804[\uDC00-\uDC46\uDC66-\uDC6F\uDC7F-\uDCBA\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD00-\uDD34\uDD36-\uDD3F\uDD44-\uDD46\uDD50-\uDD73\uDD76\uDD80-\uDDC4\uDDC9-\uDDCC\uDDD0-\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE37\uDE3E\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEEA\uDEF0-\uDEF9\uDF00-\uDF03\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3B-\uDF44\uDF47\uDF48\uDF4B-\uDF4D\uDF50\uDF57\uDF5D-\uDF63\uDF66-\uDF6C\uDF70-\uDF74]|\uD805[\uDC00-\uDC4A\uDC50-\uDC59\uDC5E\uDC80-\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDB5\uDDB8-\uDDC0\uDDD8-\uDDDD\uDE00-\uDE40\uDE44\uDE50-\uDE59\uDE80-\uDEB7\uDEC0-\uDEC9\uDF00-\uDF1A\uDF1D-\uDF2B\uDF30-\uDF39]|\uD806[\uDC00-\uDC3A\uDCA0-\uDCE9\uDCFF\uDE00-\uDE3E\uDE47\uDE50-\uDE83\uDE86-\uDE99\uDE9D\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC36\uDC38-\uDC40\uDC50-\uDC59\uDC72-\uDC8F\uDC92-\uDCA7\uDCA9-\uDCB6\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD36\uDD3A\uDD3C\uDD3D\uDD3F-\uDD47\uDD50-\uDD59\uDD60-\uDD65\uDD67\uDD68\uDD6A-\uDD8E\uDD90\uDD91\uDD93-\uDD98\uDDA0-\uDDA9\uDEE0-\uDEF6]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDEF0-\uDEF4\uDF00-\uDF36\uDF40-\uDF43\uDF50-\uDF59\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDE40-\uDE7F\uDF00-\uDF44\uDF50-\uDF7E\uDF8F-\uDF9F\uDFE0\uDFE1]|\uD821[\uDC00-\uDFF1]|\uD822[\uDC00-\uDEF2]|\uD82C[\uDC00-\uDD1E\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99\uDC9D\uDC9E]|\uD834[\uDD65-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD836[\uDE00-\uDE36\uDE3B-\uDE6C\uDE75\uDE84\uDE9B-\uDE9F\uDEA1-\uDEAF]|\uD838[\uDC00-\uDC06\uDC08-\uDC18\uDC1B-\uDC21\uDC23\uDC24\uDC26-\uDC2A]|\uD83A[\uDC00-\uDCC4\uDCD0-\uDCD6\uDD00-\uDD4A\uDD50-\uDD59]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]|\uDB40[\uDD00-\uDDEF])*$/
6
+ )
7
+ return regex.test(str)
8
+ }
9
+
10
+ export default isVarName
@@ -0,0 +1,516 @@
1
+ import THREE from 'three'
2
+ import isVarName from './isVarName.js'
3
+
4
+ function parse(fileName, gltf, options = {}) {
5
+ const url = (fileName.toLowerCase().startsWith('http') ? '' : '/') + fileName
6
+ const animations = gltf.animations
7
+ const hasAnimations = animations.length > 0
8
+
9
+ // Collect all objects
10
+ const objects = []
11
+ gltf.scene.traverse((child) => objects.push(child))
12
+
13
+ // Browse for duplicates
14
+ const duplicates = {
15
+ names: {},
16
+ materials: {},
17
+ geometries: {}
18
+ }
19
+
20
+ function uniqueName(attempt, index = 0) {
21
+ const newAttempt = index > 0 ? attempt + index : attempt
22
+ if (Object.values(duplicates.geometries).find(({ name }) => name === newAttempt) === undefined)
23
+ return newAttempt
24
+ else return uniqueName(attempt, index + 1)
25
+ }
26
+
27
+ gltf.scene.traverse((child) => {
28
+ if (child.isMesh) {
29
+ if (child.material) {
30
+ if (!duplicates.materials[child.material.name]) {
31
+ duplicates.materials[child.material.name] = 1
32
+ } else {
33
+ duplicates.materials[child.material.name]++
34
+ }
35
+ }
36
+ }
37
+ })
38
+
39
+ gltf.scene.traverse((child) => {
40
+ if (child.isMesh) {
41
+ if (child.geometry) {
42
+ const key = child.geometry.uuid + child.material?.name ?? ''
43
+ if (!duplicates.geometries[key]) {
44
+ let name = (child.name || 'Part').replace(/[^a-zA-Z]/g, '')
45
+ name = name.charAt(0).toUpperCase() + name.slice(1)
46
+ duplicates.geometries[key] = {
47
+ count: 1,
48
+ name: uniqueName(name),
49
+ node: 'nodes' + sanitizeName(child.name)
50
+ }
51
+ } else {
52
+ duplicates.geometries[key].count++
53
+ }
54
+ }
55
+ }
56
+ })
57
+
58
+ // Prune duplicate geometries
59
+ for (let key of Object.keys(duplicates.geometries)) {
60
+ const duplicate = duplicates.geometries[key]
61
+ if (duplicate.count === 1) delete duplicates.geometries[key]
62
+ }
63
+
64
+ function sanitizeName(name) {
65
+ return isVarName(name) ? `.${name}` : `['${name}']`
66
+ }
67
+
68
+ const rNbr = (number) => {
69
+ return parseFloat(number.toFixed(Math.round(options.precision || 2)))
70
+ }
71
+
72
+ const rDeg = (number) => {
73
+ const abs = Math.abs(Math.round(parseFloat(number) * 100000))
74
+ for (let i = 1; i <= 10; i++) {
75
+ if (abs === Math.round(parseFloat(Math.PI / i) * 100000))
76
+ return `${number < 0 ? '-' : ''}Math.PI${i > 1 ? ' / ' + i : ''}`
77
+ }
78
+ for (let i = 1; i <= 10; i++) {
79
+ if (abs === Math.round(parseFloat(Math.PI * i) * 100000))
80
+ return `${number < 0 ? '-' : ''}Math.PI${i > 1 ? ' * ' + i : ''}`
81
+ }
82
+ return rNbr(number)
83
+ }
84
+
85
+ function printThrelteTypes(objects, animations) {
86
+ let meshes = objects.filter((o) => o.isMesh && o.__removed === undefined)
87
+ let bones = objects.filter(
88
+ (o) => o.isBone && !(o.parent && o.parent.isBone) && o.__removed === undefined
89
+ )
90
+ let materials = [
91
+ ...new Set(objects.filter((o) => o.material && o.material.name).map((o) => o.material))
92
+ ]
93
+
94
+ /** @type {string[]} */
95
+ const types = []
96
+
97
+ if (animations.length) {
98
+ types.push(`type ActionName = ${animations.map((clip, i) => `"${clip.name}"`).join(' | ')};`)
99
+ }
100
+
101
+ types.push(`type GLTFResult = {
102
+ nodes: {
103
+ ${meshes
104
+ .map(({ name, type }) => (isVarName(name) ? name : `['${name}']`) + ': THREE.' + type)
105
+ .join(',')}
106
+ ${bones
107
+ .map(({ name, type }) => (isVarName(name) ? name : `['${name}']`) + ': THREE.' + type)
108
+ .join(',')}
109
+ }
110
+ materials: {
111
+ ${materials
112
+ .map(({ name, type }) => (isVarName(name) ? name : `['${name}']`) + ': THREE.' + type)
113
+ .join(',')}
114
+ }
115
+ }`)
116
+
117
+ return types.join('\n')
118
+ }
119
+
120
+ function getType(obj) {
121
+ let type = obj.type.charAt(0).toLowerCase() + obj.type.slice(1)
122
+ // Turn object3d's into groups, it should be faster according to the threejs docs
123
+ if (type === 'object3D') type = 'group'
124
+ if (type === 'perspectiveCamera') type = 'PerspectiveCamera'
125
+ if (type === 'orthographicCamera') type = 'OrthographicCamera'
126
+ return type
127
+ }
128
+
129
+ function handleThrelteProps(obj) {
130
+ let { type, node, instanced } = getInfo(obj)
131
+
132
+ let result = ''
133
+ let isCamera = type === 'PerspectiveCamera' || type === 'OrthographicCamera'
134
+ // Handle cameras
135
+ if (isCamera) {
136
+ result += `makeDefault={false} `
137
+ if (obj.zoom !== 1) result += `zoom={${rNbr(obj.zoom)}} `
138
+ if (obj.far !== 2000) result += `far={${rNbr(obj.far)}} `
139
+ if (obj.near !== 0.1) result += `near={${rNbr(obj.near)}} `
140
+ }
141
+ if (type === 'PerspectiveCamera') {
142
+ if (obj.fov !== 50) result += `fov={${rNbr(obj.fov)}} `
143
+ }
144
+
145
+ if (!instanced) {
146
+ // Shadows
147
+ if ((type === 'mesh' || type === 'skinnedMesh') && options.shadows)
148
+ result += `castShadow receiveShadow `
149
+
150
+ // Write out geometry first
151
+ if (obj.geometry) {
152
+ result += `geometry={$gltf.${node}.geometry} `
153
+ }
154
+
155
+ // Write out materials
156
+ if (obj.material) {
157
+ if (obj.material.name)
158
+ result += `material={$gltf.materials${sanitizeName(obj.material.name)}} `
159
+ else result += `material={$gltf.${node}.material} `
160
+ }
161
+
162
+ if (obj.skeleton) result += `skeleton={$gltf.${node}.skeleton} `
163
+ if (obj.visible === false) result += `visible={false} `
164
+ if (obj.castShadow === true) result += `castShadow `
165
+ if (obj.receiveShadow === true) result += `receiveShadow `
166
+ if (obj.morphTargetDictionary)
167
+ result += `morphTargetDictionary={$gltf.${node}.morphTargetDictionary} `
168
+ if (obj.morphTargetInfluences)
169
+ result += `morphTargetInfluences={$gltf.${node}.morphTargetInfluences} `
170
+ if (obj.intensity && rNbr(obj.intensity)) result += `intensity={${rNbr(obj.intensity)}} `
171
+ //if (obj.power && obj.power !== 4 * Math.PI) result += `power={${rNbr(obj.power)}} `
172
+ if (obj.angle && obj.angle !== Math.PI / 3) result += `angle={${rDeg(obj.angle)}} `
173
+ if (obj.penumbra && rNbr(obj.penumbra) !== 0) result += `penumbra={${rNbr(obj.penumbra)}} `
174
+ if (obj.decay && rNbr(obj.decay) !== 1) result += `decay={${rNbr(obj.decay)}} `
175
+ if (obj.distance && rNbr(obj.distance) !== 0) result += `distance={${rNbr(obj.distance)}} `
176
+ if (obj.up && obj.up.isVector3 && !obj.up.equals(new THREE.Vector3(0, 1, 0)))
177
+ result += `up={[${rNbr(obj.up.x)}, ${rNbr(obj.up.y)}, ${rNbr(obj.up.z)},]} `
178
+ }
179
+
180
+ if (obj.color && obj.color.getHexString() !== 'ffffff')
181
+ result += `color="#${obj.color.getHexString()}" `
182
+ if (obj.position && obj.position.isVector3 && rNbr(obj.position.length()))
183
+ result += `position={[${rNbr(obj.position.x)}, ${rNbr(obj.position.y)}, ${rNbr(
184
+ obj.position.z
185
+ )},]} `
186
+ if (obj.rotation && obj.rotation.isEuler && rNbr(obj.rotation.toVector3().length()))
187
+ result += `rotation={[${rDeg(obj.rotation.x)}, ${rDeg(obj.rotation.y)}, ${rDeg(
188
+ obj.rotation.z
189
+ )},]} `
190
+ if (
191
+ obj.scale &&
192
+ obj.scale.isVector3 &&
193
+ !(rNbr(obj.scale.x) === 1 && rNbr(obj.scale.y) === 1 && rNbr(obj.scale.z) === 1)
194
+ ) {
195
+ const rX = rNbr(obj.scale.x)
196
+ const rY = rNbr(obj.scale.y)
197
+ const rZ = rNbr(obj.scale.z)
198
+ if (rX === rY && rX === rZ) {
199
+ result += `scale={${rX}} `
200
+ } else {
201
+ result += `scale={[${rX}, ${rY}, ${rZ},]} `
202
+ }
203
+ }
204
+ if (options.meta && obj.userData && Object.keys(obj.userData).length)
205
+ result += `userData={${JSON.stringify(obj.userData)}} `
206
+
207
+ return result
208
+ }
209
+
210
+ function getInfo(obj) {
211
+ let type = getType(obj)
212
+ let node = 'nodes' + sanitizeName(obj.name)
213
+
214
+ // TODO: @threlte/gltf does not support instancing yet
215
+ let instanced = false
216
+ let animated = gltf.animations && gltf.animations.length > 0
217
+ return { type, node, instanced, animated }
218
+ }
219
+
220
+ function equalOrNegated(a, b) {
221
+ return (
222
+ (a.x === b.x || a.x === -b.x) &&
223
+ (a.y === b.y || a.y === -b.y) &&
224
+ (a.z === b.z || a.z === -b.z)
225
+ )
226
+ }
227
+
228
+ function prune(obj, children, result, oldResult, silent) {
229
+ let { type, animated } = getInfo(obj)
230
+ // Prune ...
231
+ if (
232
+ !obj.__removed &&
233
+ !options.keepgroups &&
234
+ !animated &&
235
+ (type === 'group' || type === 'scene')
236
+ ) {
237
+ /** Empty or no-property groups
238
+ * <T.Group>
239
+ * <T.Mesh geometry={nodes.foo} material={materials.bar} />
240
+ * Solution:
241
+ * <T.Mesh geometry={nodes.foo} material={materials.bar} />
242
+ */
243
+ if (result === oldResult || obj.children.length === 0) {
244
+ if (!silent) console.log(`group ${obj.name} removed (empty)`)
245
+ obj.__removed = true
246
+ return children
247
+ }
248
+
249
+ // More aggressive removal strategies ...
250
+ const first = obj.children[0]
251
+ const firstProps = handleThrelteProps(first)
252
+ const regex = /([a-z-A-Z]*)={([a-zA-Z0-9\.\[\]\-\,\ \/]*)}/g
253
+ const keys1 = [...result.matchAll(regex)].map(([, match]) => match)
254
+ const values1 = [...result.matchAll(regex)].map(([, , match]) => match)
255
+ const keys2 = [...firstProps.matchAll(regex)].map(([, match]) => match)
256
+
257
+ /** Double negative rotations
258
+ * <T.Group rotation={[-Math.PI / 2, 0, 0]}>
259
+ * <T.Group rotation={[Math.PI / 2, 0, 0]}>
260
+ * <T.Mesh geometry={nodes.foo} material={materials.bar} />
261
+ * Solution:
262
+ * <T.Mesh geometry={nodes.foo} material={materials.bar} />
263
+ */
264
+ if (
265
+ obj.children.length === 1 &&
266
+ getType(first) === type &&
267
+ equalOrNegated(obj.rotation, first.rotation)
268
+ ) {
269
+ if (
270
+ keys1.length === 1 &&
271
+ keys2.length === 1 &&
272
+ keys1[0] === 'rotation' &&
273
+ keys2[0] === 'rotation'
274
+ ) {
275
+ if (!silent)
276
+ console.log(`group ${obj.name} removed (aggressive: double negative rotation)`)
277
+ obj.__removed = first.__removed = true
278
+ children = ''
279
+ if (first.children)
280
+ first.children.forEach((child) => (children += printThrelte(child, true)))
281
+ return children
282
+ }
283
+ }
284
+
285
+ /** Double negative rotations w/ props
286
+ * <T.Group rotation={[-Math.PI / 2, 0, 0]}>
287
+ * <T.Group rotation={[Math.PI / 2, 0, 0]} scale={0.01}>
288
+ * <T.Mesh geometry={nodes.foo} material={materials.bar} />
289
+ * Solution:
290
+ * <T.Group scale={0.01}>
291
+ * <T.Mesh geometry={nodes.foo} material={materials.bar} />
292
+ */
293
+ if (
294
+ obj.children.length === 1 &&
295
+ getType(first) === type &&
296
+ equalOrNegated(obj.rotation, first.rotation)
297
+ ) {
298
+ if (
299
+ keys1.length === 1 &&
300
+ keys2.length > 1 &&
301
+ keys1[0] === 'rotation' &&
302
+ keys2.includes('rotation')
303
+ ) {
304
+ if (!silent)
305
+ console.log(`group ${obj.name} removed (aggressive: double negative rotation w/ props)`)
306
+ obj.__removed = true
307
+ // Remove rotation from first child
308
+ first.rotation.set(0, 0, 0)
309
+ children = printThrelte(first, true)
310
+ return children
311
+ }
312
+ }
313
+
314
+ /** Transform overlap
315
+ * <T.Group position={[10, 0, 0]} scale={2} rotation={[-Math.PI / 2, 0, 0]}>
316
+ * <T.Mesh geometry={nodes.foo} material={materials.bar} />
317
+ * Solution:
318
+ * <T.Mesh geometry={nodes.foo} material={materials.bar} position={[10, 0, 0]} scale={2} rotation={[-Math.PI / 2, 0, 0]} />
319
+ */
320
+ const isChildTransformed =
321
+ keys2.includes('position') || keys2.includes('rotation') || keys2.includes('scale')
322
+ const hasOtherProps = keys1.some((key) => !['position', 'scale', 'rotation'].includes(key))
323
+ if (obj.children.length === 1 && !first.__removed && !isChildTransformed && !hasOtherProps) {
324
+ if (!silent)
325
+ console.log(`group ${obj.name} removed (aggressive: ${keys1.join(' ')} overlap)`)
326
+ // Move props over from the to-be-deleted object to the child
327
+ // This ensures that the child will have the correct transform when pruning is being repeated
328
+ keys1.forEach((key) => obj.children[0][key].copy(obj[key]))
329
+ // Insert the props into the result string
330
+ children = printThrelte(first, true)
331
+ obj.__removed = true
332
+ return children
333
+ }
334
+
335
+ /** Lack of content
336
+ * <T.Group position={[10, 0, 0]} scale={2} rotation={[-Math.PI / 2, 0, 0]}>
337
+ * <T.Group position={[10, 0, 0]} scale={2} rotation={[-Math.PI / 2, 0, 0]}>
338
+ * <T.Group position={[10, 0, 0]} scale={2} rotation={[-Math.PI / 2, 0, 0]} />
339
+ * Solution:
340
+ * (delete the whole sub graph)
341
+ */
342
+ const empty = []
343
+ obj.traverse((o) => {
344
+ const type = getType(o)
345
+ if (type !== 'group' && type !== 'object3D') empty.push(o)
346
+ })
347
+ if (!empty.length) {
348
+ if (!silent) console.log(`group ${obj.name} removed (aggressive: lack of content)`)
349
+ empty.forEach((child) => (child.__removed = true))
350
+ return ''
351
+ }
352
+ }
353
+ }
354
+
355
+ /**
356
+ * Transforms a type like "mesh" into "T.Mesh".
357
+ * @param {string} type
358
+ * @returns
359
+ */
360
+ function getThrelteComponentName(type) {
361
+ return `T.${type[0].toUpperCase()}${type.slice(1)}`
362
+ }
363
+
364
+ function printThrelte(obj, silent = false) {
365
+ let result = ''
366
+ let children = ''
367
+ let { type, node, animated } = getInfo(obj)
368
+
369
+ // Check if the root node is useless
370
+ if (obj.__removed && obj.children.length) {
371
+ obj.children.forEach((child) => (result += printThrelte(child)))
372
+ return result
373
+ }
374
+
375
+ // Bail out on lights and bones
376
+ if (type === 'bone') {
377
+ return `<Three type={$gltf.${node}} />\n`
378
+ }
379
+
380
+ // Collect children
381
+ if (obj.children) obj.children.forEach((child) => (children += printThrelte(child)))
382
+
383
+ // TODO: Instances are currently not supported for Threlte components
384
+
385
+ result = `<${getThrelteComponentName(type)} `
386
+
387
+ // Include names when output is uncompressed or morphTargetDictionaries are present
388
+ if (obj.name.length && (options.keepnames || obj.morphTargetDictionary || animated))
389
+ result += `name="${obj.name}" `
390
+
391
+ const oldResult = result
392
+ result += handleThrelteProps(obj)
393
+
394
+ const pruned = prune(obj, children, result, oldResult, silent)
395
+ // Bail out if the object was pruned
396
+ if (pruned !== undefined) return pruned
397
+
398
+ // Close tag
399
+ result += `${children.length ? '>' : '/>'}\n`
400
+
401
+ // Add children and return
402
+ if (children.length) result += children + `\n</${getThrelteComponentName(type)}>\n`
403
+ return result
404
+ }
405
+
406
+ function parseExtras(extras) {
407
+ if (extras) {
408
+ return (
409
+ Object.keys(extras)
410
+ .map((key) => `${key.charAt(0).toUpperCase() + key.slice(1)}: ${extras[key]}`)
411
+ .join('\n') + '\n'
412
+ )
413
+ } else return ''
414
+ }
415
+
416
+ function p(obj, line) {
417
+ console.log(
418
+ [...new Array(line * 2)].map(() => ' ').join(''),
419
+ obj.type,
420
+ obj.name,
421
+ 'pos:',
422
+ obj.position.toArray().map(rNbr),
423
+ 'scale:',
424
+ obj.scale.toArray().map(rNbr),
425
+ 'rot:',
426
+ [obj.rotation.x, obj.rotation.y, obj.rotation.z].map(rNbr),
427
+ 'mat:',
428
+ obj.material ? `${obj.material.name}-${obj.material.uuid.substring(0, 8)}` : ''
429
+ )
430
+ obj.children.forEach((o) => p(o, line + 1))
431
+ }
432
+
433
+ if (options.debug) p(gltf.scene, 0)
434
+
435
+ if (!options.keepgroups) {
436
+ // Dry run to prune graph
437
+ printThrelte(gltf.scene)
438
+
439
+ // Move children of deleted objects to their new parents
440
+ objects.forEach((o) => {
441
+ if (o.__removed) {
442
+ let parent = o.parent
443
+ // Making sure we don't add to a removed parent
444
+ while (parent && parent.__removed) parent = parent.parent
445
+ // If no parent was found it must be the root node
446
+ if (!parent) parent = gltf.scene
447
+ o.children.slice().forEach((child) => parent.add(child))
448
+ }
449
+ })
450
+ // Remove deleted objects
451
+ objects.forEach((o) => {
452
+ if (o.__removed && o.parent) o.parent.remove(o)
453
+ })
454
+ }
455
+
456
+ // 2nd pass to eliminate hard to swat left-overs
457
+ const scene = printThrelte(gltf.scene)
458
+
459
+ // Output
460
+ return `
461
+ <!--
462
+ ${
463
+ options.header
464
+ ? options.header
465
+ : 'Auto-generated by: https://github.com/threlte/threlte/tree/main/packages/gltf'
466
+ }
467
+ ${parseExtras(gltf.parser.json.asset && gltf.parser.json.asset.extras)}-->
468
+
469
+ <script${options.types ? ' lang="ts"' : ''}>
470
+
471
+
472
+ ${options.types ? `\nimport type * as THREE from 'three'` : ''}
473
+ import { Group } from 'three'
474
+ import { ${['T', 'Three', options.types ? 'type Props, type Events, type Slots' : ''].join(
475
+ ', '
476
+ )} } from '@threlte/core'
477
+ import { ${['useGltf', hasAnimations ? 'useGltfAnimations' : ''].join(
478
+ ', '
479
+ )} } from '@threlte/extras'
480
+
481
+ ${options.types ? 'type $$Props = Props<THREE.Group>' : ''}
482
+ ${options.types ? 'type $$Events = Events<THREE.Group>' : ''}
483
+ ${options.types ? 'type $$Slots = Slots<THREE.Group>' : ''}
484
+
485
+ export const ref = new Group()
486
+
487
+ ${options.types ? printThrelteTypes(objects, animations) : ''}
488
+
489
+ const { gltf } = useGltf${options.types ? '<GLTFResult>' : ''}('${url}'${
490
+ options.draco
491
+ ? `, {
492
+ useDraco: ${JSON.stringify(options.draco)},
493
+ }`
494
+ : ''
495
+ })
496
+ ${
497
+ hasAnimations
498
+ ? `export const { actions, mixer } = useGltfAnimations${
499
+ options.types ? '<ActionName>' : ''
500
+ }(gltf, ref)`
501
+ : ''
502
+ }
503
+
504
+ </script>
505
+
506
+ {#if $gltf}
507
+ <Three type={ref} {...$$restProps}>
508
+ ${scene}
509
+
510
+ <slot {ref} />
511
+ </Three>
512
+ {/if}
513
+ `
514
+ }
515
+
516
+ export default parse