cleanup, gltf output, readme
This commit is contained in:
parent
573c3e8f67
commit
a7c1a6199f
17
LICENSE.txt
Normal file
17
LICENSE.txt
Normal file
@ -0,0 +1,17 @@
|
||||
ISC License
|
||||
|
||||
Copyright 2024 Evert "Diamond" Prants <evert@lunasqu.ee>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
|
||||
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
22
README.md
22
README.md
@ -1,13 +1,21 @@
|
||||
# Mson -> THREE
|
||||
|
||||
WIP do not use
|
||||
|
||||
Parse [Mson](https://github.com/MineLittlePony/Mson).
|
||||
Convert [Mson](https://github.com/MineLittlePony/Mson) models to THREE.js object JSON or GLTF.
|
||||
|
||||
## Setup
|
||||
|
||||
1. copy the folder at https://github.com/MineLittlePony/Mson/tree/1.20.2/src/main/resources/assets/mson/models/entity as `inputs/mson`
|
||||
2. build `npm run build`
|
||||
3. export `node lib/test-node.js`
|
||||
1. Clone and `npm install`. Optional dependencies are required when using this on Node.js (see implementation notes below).
|
||||
2. copy the folder at https://github.com/MineLittlePony/Mson/tree/1.20.2/src/main/resources/assets/mson/models/entity as `inputs/mson`
|
||||
3. build `npm run build`
|
||||
4. run `node lib/cli.js export <model name>`
|
||||
|
||||
THREE object will be placed in `outputs`
|
||||
Output will be placed in `outputs`. For more options run `node lib/cli.js export -h`.
|
||||
|
||||
## Implementation notes
|
||||
|
||||
1. Mson models seem to have the X and Y coordinates inverse of what THREE.js uses (and Minecraft for that matter, lol).
|
||||
2. Many Mson example models do not work. They seem to be all either outdated or just outright broken. Mine Little Pony works fine, though.
|
||||
3. Most of the code here makes a lot of assumptions. This project is a reverse engineering of the format, not a Java to JavaScript port of Mson's rendering engine. It should not be used in any serious capacity, as it was only made as an experiment.
|
||||
4. THREE.js GLTF exporter does not support Node.js by default, so some extra junk was included to support it. You can omit pretty much the entire `optionalDependencies` array of items (and `src/cli.ts` + `src/node`) to use this library on the browser.
|
||||
5. The parser and object generator by themselves have no dependencies except for THREE.js, of course.
|
||||
6. Output could be further optimized by merging composite objects into a single geometry, but this is not yet done.
|
||||
|
776
package-lock.json
generated
776
package-lock.json
generated
@ -8,14 +8,37 @@
|
||||
"name": "mson-three",
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"three": "^0.161.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.11.19",
|
||||
"@types/three": "^0.161.2",
|
||||
"prettier": "^3.2.5",
|
||||
"typescript": "^5.3.3"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"buffer": "^6.0.3",
|
||||
"canvas": "^2.11.2",
|
||||
"commander": "^12.0.0",
|
||||
"three": "^0.161.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@mapbox/node-pre-gyp": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz",
|
||||
"integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"detect-libc": "^2.0.0",
|
||||
"https-proxy-agent": "^5.0.0",
|
||||
"make-dir": "^3.1.0",
|
||||
"node-fetch": "^2.6.7",
|
||||
"nopt": "^5.0.0",
|
||||
"npmlog": "^5.0.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"semver": "^7.3.5",
|
||||
"tar": "^6.1.11"
|
||||
},
|
||||
"bin": {
|
||||
"node-pre-gyp": "bin/node-pre-gyp"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
@ -51,18 +74,554 @@
|
||||
"integrity": "sha512-UEMMm/Xn3DtEa+gpzUrOcDj+SJS1tk5YodjwOxcqStNhCfPcwgyC5Srg2ToVKyg2Fhq16Ffpb0UWUQHqoT9AMA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/abbrev": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/agent-base": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
||||
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"debug": "4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/aproba": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz",
|
||||
"integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/are-we-there-yet": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz",
|
||||
"integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"delegates": "^1.0.0",
|
||||
"readable-stream": "^3.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
||||
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/canvas": {
|
||||
"version": "2.11.2",
|
||||
"resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz",
|
||||
"integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==",
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@mapbox/node-pre-gyp": "^1.0.0",
|
||||
"nan": "^2.17.0",
|
||||
"simple-get": "^3.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/chownr": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
|
||||
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/color-support": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
|
||||
"integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
|
||||
"optional": true,
|
||||
"bin": {
|
||||
"color-support": "bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/commander": {
|
||||
"version": "12.0.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-12.0.0.tgz",
|
||||
"integrity": "sha512-MwVNWlYjDTtOjX5PiD7o5pK0UrFU/OYgcJfjjK4RaHZETNtjJqrZa9Y9ds88+A+f+d5lv+561eZ+yCKoS3gbAA==",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
|
||||
"integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/decompress-response": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz",
|
||||
"integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"mimic-response": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/delegates": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
|
||||
"integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/detect-libc": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
|
||||
"integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/fflate": {
|
||||
"version": "0.6.10",
|
||||
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.6.10.tgz",
|
||||
"integrity": "sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/fs-minipass": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
|
||||
"integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"minipass": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/fs-minipass/node_modules/minipass": {
|
||||
"version": "3.3.6",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
|
||||
"integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/gauge": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz",
|
||||
"integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"aproba": "^1.0.3 || ^2.0.0",
|
||||
"color-support": "^1.1.2",
|
||||
"console-control-strings": "^1.0.0",
|
||||
"has-unicode": "^2.0.1",
|
||||
"object-assign": "^4.1.1",
|
||||
"signal-exit": "^3.0.0",
|
||||
"string-width": "^4.2.3",
|
||||
"strip-ansi": "^6.0.1",
|
||||
"wide-align": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/glob": {
|
||||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
||||
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.1.1",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/has-unicode": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
|
||||
"integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/https-proxy-agent": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
|
||||
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"agent-base": "6",
|
||||
"debug": "4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/ieee754": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/inflight": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"once": "^1.3.0",
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/make-dir": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
|
||||
"integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"semver": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/make-dir/node_modules/semver": {
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"optional": true,
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/meshoptimizer": {
|
||||
"version": "0.18.1",
|
||||
"resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-0.18.1.tgz",
|
||||
"integrity": "sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/mimic-response": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz",
|
||||
"integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/minipass": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
|
||||
"integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/minizlib": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
|
||||
"integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"minipass": "^3.0.0",
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/minizlib/node_modules/minipass": {
|
||||
"version": "3.3.6",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
|
||||
"integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/mkdirp": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
|
||||
"optional": true,
|
||||
"bin": {
|
||||
"mkdirp": "bin/cmd.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/nan": {
|
||||
"version": "2.19.0",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.19.0.tgz",
|
||||
"integrity": "sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"encoding": "^0.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"encoding": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/nopt": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
|
||||
"integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"abbrev": "1"
|
||||
},
|
||||
"bin": {
|
||||
"nopt": "bin/nopt.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/npmlog": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz",
|
||||
"integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"are-we-there-yet": "^2.0.0",
|
||||
"console-control-strings": "^1.1.0",
|
||||
"gauge": "^3.0.0",
|
||||
"set-blocking": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "3.2.5",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz",
|
||||
@ -78,10 +637,176 @@
|
||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/readable-stream": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/rimraf": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
||||
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"glob": "^7.1.3"
|
||||
},
|
||||
"bin": {
|
||||
"rimraf": "bin.js"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
|
||||
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/set-blocking": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
|
||||
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/signal-exit": {
|
||||
"version": "3.0.7",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
||||
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/simple-concat": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
|
||||
"integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/simple-get": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz",
|
||||
"integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"decompress-response": "^4.2.0",
|
||||
"once": "^1.3.1",
|
||||
"simple-concat": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/tar": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
|
||||
"integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"chownr": "^2.0.0",
|
||||
"fs-minipass": "^2.0.0",
|
||||
"minipass": "^5.0.0",
|
||||
"minizlib": "^2.1.1",
|
||||
"mkdirp": "^1.0.3",
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/three": {
|
||||
"version": "0.161.0",
|
||||
"resolved": "https://registry.npmjs.org/three/-/three-0.161.0.tgz",
|
||||
"integrity": "sha512-LC28VFtjbOyEu5b93K0bNRLw1rQlMJ85lilKsYj6dgTu+7i17W+JCCEbvrpmNHF1F3NAUqDSWq50UD7w9H2xQw=="
|
||||
"integrity": "sha512-LC28VFtjbOyEu5b93K0bNRLw1rQlMJ85lilKsYj6dgTu+7i17W+JCCEbvrpmNHF1F3NAUqDSWq50UD7w9H2xQw==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.3.3",
|
||||
@ -101,6 +826,49 @@
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wide-align": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz",
|
||||
"integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"string-width": "^1.0.2 || 2 || 3 || 4"
|
||||
}
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,11 @@
|
||||
"prettier": "^3.2.5",
|
||||
"typescript": "^5.3.3"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"buffer": "^6.0.3",
|
||||
"canvas": "^2.11.2",
|
||||
"commander": "^12.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"three": "^0.161.0"
|
||||
}
|
||||
|
87
src/cli.ts
Normal file
87
src/cli.ts
Normal file
@ -0,0 +1,87 @@
|
||||
import { resolve } from 'path';
|
||||
import { ModelStore, MsonEvaluate } from './mson';
|
||||
import { fillStoreFromFilesystem, saveGeometry, saveModel } from './node';
|
||||
import { ThreeBuilder } from './three';
|
||||
import { MeshStandardMaterial } from 'three';
|
||||
import { Command } from 'commander';
|
||||
import { saveGLTF } from './node';
|
||||
|
||||
interface CliOptions {
|
||||
format: string;
|
||||
evaluated?: boolean;
|
||||
store: string;
|
||||
target: string;
|
||||
}
|
||||
|
||||
const store = new ModelStore();
|
||||
const evaluate = new MsonEvaluate(store);
|
||||
|
||||
const exportModel = async (model: string, options: CliOptions) => {
|
||||
console.log(`\nStarting to evaluate model ${model}`);
|
||||
console.log(` ... Evaluating Mson model`);
|
||||
const evaluated = evaluate.evaluateModel(model);
|
||||
|
||||
console.log(` ... Building geometry`);
|
||||
const mat = new MeshStandardMaterial();
|
||||
const builder = new ThreeBuilder(mat);
|
||||
const geometry = builder.buildGeometry(evaluated);
|
||||
|
||||
const outputName = model.replace(/[:\/]/g, '-');
|
||||
console.log(`Saving as ${outputName}.${options.format}`);
|
||||
|
||||
const outputs = resolve(process.cwd(), options.target || 'outputs');
|
||||
if (options.evaluated) {
|
||||
await saveModel(outputs, outputName, evaluated);
|
||||
}
|
||||
|
||||
switch (options.format) {
|
||||
case 'json':
|
||||
await saveGeometry(outputs, outputName, geometry);
|
||||
break;
|
||||
case 'gltf':
|
||||
case 'glb':
|
||||
await saveGLTF(outputs, outputName, geometry, options.format === 'glb');
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unexpected format ${options.format}`);
|
||||
}
|
||||
};
|
||||
|
||||
const program = new Command();
|
||||
program
|
||||
.name('mson-three')
|
||||
.description('Convert Mson models to THREE.js models (and others)')
|
||||
.version('0.0.1');
|
||||
|
||||
program
|
||||
.command('export')
|
||||
.description('Export a Mson model')
|
||||
.argument('models...', 'Model(s) to export')
|
||||
.option(
|
||||
'-f, --format <name>',
|
||||
'Output format, one of: json, gltf, glb',
|
||||
'json',
|
||||
)
|
||||
.option('-e, --evaluated', 'Save the evaluated final Mson json file as well')
|
||||
.option('-s, --store <path>', 'Path containing Mson models', 'inputs')
|
||||
.option('-t, --target <path>', 'Path to place outputs into', 'outputs')
|
||||
.action(async (models: string[], options: CliOptions) => {
|
||||
console.log(` ... Reading Mson resources`);
|
||||
await fillStoreFromFilesystem(
|
||||
store,
|
||||
resolve(process.cwd(), options.store || 'inputs'),
|
||||
);
|
||||
|
||||
for (const model of models) {
|
||||
try {
|
||||
await exportModel(model, options);
|
||||
} catch (error: any) {
|
||||
console.error(
|
||||
` !!! Model "${model}" failed: ${error.message}`,
|
||||
error.stack,
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
program.parse();
|
@ -1 +1,2 @@
|
||||
export * from './mson';
|
||||
export * from './three';
|
||||
|
23
src/node/gltf.ts
Normal file
23
src/node/gltf.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { Object3D } from 'three';
|
||||
|
||||
export class GLTF {
|
||||
static async export<BoolValue = true>(
|
||||
input: Object3D,
|
||||
binary: BoolValue,
|
||||
): Promise<ArrayBuffer>;
|
||||
static async export<BoolValue = false>(
|
||||
input: Object3D,
|
||||
binary: BoolValue,
|
||||
): Promise<{ [x: string]: any }>;
|
||||
static async export<BoolValue extends boolean>(
|
||||
input: Object3D,
|
||||
binary?: BoolValue,
|
||||
) {
|
||||
return import('three/examples/jsm/exporters/GLTFExporter.js').then(
|
||||
({ GLTFExporter }) =>
|
||||
new GLTFExporter().parseAsync(input, {
|
||||
binary,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,3 +1,7 @@
|
||||
// Browser API mocks in node.js
|
||||
import './vendor';
|
||||
// ...
|
||||
import { GLTF } from './gltf';
|
||||
import { ModelStore, MsonEvaluatedModel } from '../mson';
|
||||
import { promises as fs } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
@ -55,6 +59,19 @@ export const saveGeometry = async (
|
||||
JSON.stringify(object.toJSON()),
|
||||
);
|
||||
|
||||
export const saveGLTF = async (
|
||||
root: string,
|
||||
name: string,
|
||||
object: Object3D,
|
||||
binary = false,
|
||||
) => {
|
||||
const model = await GLTF.export(object, binary);
|
||||
await fs.writeFile(
|
||||
join(root, `${name}.${binary ? 'glb' : 'gltf'}`),
|
||||
binary ? Buffer.from(model) : JSON.stringify(model),
|
||||
);
|
||||
};
|
||||
|
||||
export const saveModel = async (
|
||||
root: string,
|
||||
name: string,
|
87
src/node/vendor/eventtarget.ts
vendored
Normal file
87
src/node/vendor/eventtarget.ts
vendored
Normal file
@ -0,0 +1,87 @@
|
||||
//
|
||||
// None of the following code was written for mson-three explicity.
|
||||
// attribution is provided where necessary.
|
||||
//
|
||||
// all of this junk was copied from abandoned npm modules which mimic browser
|
||||
// APIs in Node.js in order to make GLTFExporter work.
|
||||
//
|
||||
// this is taken from abandoned npm module "eventtarget" by Jesús Leganés Combarro "Piranna"
|
||||
//
|
||||
export class EventTarget {
|
||||
listeners: any = {};
|
||||
|
||||
addEventListener(type: string | number, listener: any) {
|
||||
if (!listener) return;
|
||||
|
||||
var listeners_type = this.listeners[type];
|
||||
if (listeners_type === undefined)
|
||||
this.listeners[type] = listeners_type = [];
|
||||
|
||||
for (var i = 0, l; (l = listeners_type[i]); i++) if (l === listener) return;
|
||||
|
||||
listeners_type.push(listener);
|
||||
}
|
||||
|
||||
dispatchEvent(event: {
|
||||
type: any;
|
||||
message?: any;
|
||||
_dispatched?: any;
|
||||
cancelable?: any;
|
||||
defaultPrevented?: any;
|
||||
isTrusted?: any;
|
||||
preventDefault?: any;
|
||||
stopImmediatePropagation?: any;
|
||||
target?: any;
|
||||
timeStamp?: any;
|
||||
}) {
|
||||
if (event._dispatched) throw 'InvalidStateError';
|
||||
event._dispatched = true;
|
||||
|
||||
var type = event.type;
|
||||
if (type == undefined || type == '') throw 'UNSPECIFIED_EVENT_TYPE_ERR';
|
||||
|
||||
var listenerArray = this.listeners[type] || [];
|
||||
|
||||
var dummyListener = (this as any)['on' + type];
|
||||
if (typeof dummyListener == 'function')
|
||||
listenerArray = listenerArray.concat(dummyListener);
|
||||
|
||||
var stopImmediatePropagation = false;
|
||||
|
||||
// [ToDo] Use read-only properties instead of attributes when availables
|
||||
event.cancelable = true;
|
||||
event.defaultPrevented = false;
|
||||
event.isTrusted = false;
|
||||
event.preventDefault = function () {
|
||||
if (this.cancelable) this.defaultPrevented = true;
|
||||
};
|
||||
event.stopImmediatePropagation = function () {
|
||||
stopImmediatePropagation = true;
|
||||
};
|
||||
event.target = this;
|
||||
event.timeStamp = new Date().getTime();
|
||||
|
||||
for (var i = 0, listener; (listener = listenerArray[i]); i++) {
|
||||
if (stopImmediatePropagation) break;
|
||||
|
||||
listener.call(this, event);
|
||||
}
|
||||
|
||||
return !event.defaultPrevented;
|
||||
}
|
||||
|
||||
removeEventListener(type: string | number, listener: any) {
|
||||
if (!listener) return;
|
||||
|
||||
var listeners_type = this.listeners[type];
|
||||
if (listeners_type === undefined) return;
|
||||
|
||||
for (var i = 0, l; (l = listeners_type[i]); i++)
|
||||
if (l === listener) {
|
||||
listeners_type.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!listeners_type.length) delete this.listeners[type];
|
||||
}
|
||||
}
|
18
src/node/vendor/index.ts
vendored
Normal file
18
src/node/vendor/index.ts
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
import { Canvas } from 'canvas';
|
||||
import { Blob, FileReader } from './vblob';
|
||||
|
||||
// Patch global scope to imitate browser environment.
|
||||
global.Blob = Blob as any;
|
||||
global.FileReader = FileReader as any;
|
||||
global.document = {
|
||||
createElement: (nodeName: string) => {
|
||||
if (nodeName !== 'canvas')
|
||||
throw new Error(`Cannot create node ${nodeName}`);
|
||||
const canvas = new Canvas(256, 256);
|
||||
// This isn't working — currently need to avoid toBlob(), so export to embedded .gltf not .glb.
|
||||
// canvas.toBlob = function () {
|
||||
// return new Blob([this.toBuffer()]);
|
||||
// };
|
||||
return canvas;
|
||||
},
|
||||
} as any;
|
438
src/node/vendor/vblob.ts
vendored
Normal file
438
src/node/vendor/vblob.ts
vendored
Normal file
@ -0,0 +1,438 @@
|
||||
//
|
||||
// None of the following code was written for mson-three explicity.
|
||||
// attribution is provided where necessary.
|
||||
//
|
||||
// all of this junk was copied from abandoned npm modules which mimic browser
|
||||
// APIs in Node.js in order to make GLTFExporter work.
|
||||
//
|
||||
// this code is taken from npm package "vblob" by karikera
|
||||
|
||||
import * as fs from 'fs';
|
||||
import { randomBytes } from 'crypto';
|
||||
import { tmpdir } from 'os';
|
||||
import { join } from 'path';
|
||||
import { Blob as NodeBlob } from 'buffer';
|
||||
import { EventTarget } from './eventtarget';
|
||||
|
||||
interface EventBeforeDispatch {
|
||||
[key: string]: any;
|
||||
type: string;
|
||||
}
|
||||
|
||||
interface Event {
|
||||
readonly cancelable: boolean;
|
||||
readonly defaultPrevented: boolean;
|
||||
readonly isTrusted: boolean;
|
||||
readonly target: EventTarget | null;
|
||||
readonly timeStamp: number;
|
||||
readonly bubbles: boolean;
|
||||
/** @deprecated */
|
||||
cancelBubble: boolean;
|
||||
readonly composed: boolean;
|
||||
readonly currentTarget: EventTarget | null;
|
||||
readonly eventPhase: number;
|
||||
/** @deprecated */
|
||||
returnValue: boolean;
|
||||
/** @deprecated */
|
||||
readonly srcElement: EventTarget | null;
|
||||
readonly type: string;
|
||||
|
||||
preventDefault(): void;
|
||||
stopPropagation(): void;
|
||||
stopImmediatePropagation(): void;
|
||||
composedPath(): EventTarget[];
|
||||
/** @deprecated */
|
||||
initEvent(type: string, bubbles: boolean, cancelable: boolean): void;
|
||||
|
||||
readonly NONE: number;
|
||||
readonly CAPTURING_PHASE: number;
|
||||
readonly AT_TARGET: number;
|
||||
readonly BUBBLING_PHASE: number;
|
||||
}
|
||||
|
||||
interface ProgressEvent<T extends EventTarget = EventTarget> extends Event {
|
||||
readonly lengthComputable: boolean;
|
||||
readonly loaded: number;
|
||||
readonly target: T | null;
|
||||
readonly total: number;
|
||||
}
|
||||
|
||||
interface EventTargetConstructor {
|
||||
new (): EventTarget;
|
||||
}
|
||||
|
||||
interface FileReaderEvent extends Event {}
|
||||
|
||||
function getTempPath(): Promise<string> {
|
||||
const file = `vblob-${randomBytes(4).readUInt32LE(0)}`;
|
||||
const path = join(tmpdir(), file);
|
||||
tempFiles.add(path);
|
||||
return Promise.resolve(path);
|
||||
}
|
||||
|
||||
function fdopen(path: string, flags: string): Promise<number> {
|
||||
return new Promise<number>((resolve, reject) =>
|
||||
fs.open(path, flags, (err, fd) => {
|
||||
if (err) reject(err);
|
||||
else resolve(fd);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
function fdclose(fd: number): Promise<void> {
|
||||
return new Promise((resolve, reject) =>
|
||||
fs.close(fd, (err) => {
|
||||
if (err) reject(err);
|
||||
else resolve();
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
function fdwriteFile(fd: number, path: string): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const writer = fs.createWriteStream(<any>null, { fd });
|
||||
const reader = fs.createReadStream(path);
|
||||
reader.on('error', reject);
|
||||
reader.on('end', resolve);
|
||||
writer.on('error', reject);
|
||||
reader.pipe(writer, { end: false });
|
||||
});
|
||||
}
|
||||
|
||||
function fdwrite(fd: number, str: string | Uint8Array): Promise<void> {
|
||||
return new Promise((resolve, reject) =>
|
||||
fs.write(fd, str as any, (err) => {
|
||||
if (err) reject(err);
|
||||
else resolve();
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
function fdread(fd: number, size: number, position: number): Promise<Buffer> {
|
||||
const buffer = Buffer.alloc(size);
|
||||
return new Promise<Buffer>((resolve, reject) =>
|
||||
fs.read(fd, buffer, 0, size, position, (err) => {
|
||||
if (err) reject(err);
|
||||
else resolve(buffer);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
const tempFiles: Set<string> = new Set();
|
||||
|
||||
const onExit: Array<() => void> = [];
|
||||
|
||||
process.on('exit', (code) => {
|
||||
for (const cb of onExit) cb();
|
||||
process.exit(code);
|
||||
});
|
||||
|
||||
onExit.push(() => {
|
||||
for (const file of tempFiles) {
|
||||
fs.unlinkSync(file);
|
||||
}
|
||||
});
|
||||
|
||||
interface BlobPropertyBag {
|
||||
type?: string;
|
||||
ending?: 'transparent' | 'native';
|
||||
}
|
||||
|
||||
export interface Blob {
|
||||
readonly size: number;
|
||||
readonly type: string;
|
||||
slice(start?: number, end?: number, contentType?: string): Blob;
|
||||
}
|
||||
|
||||
export interface FileReader extends EventTarget {
|
||||
readonly error: any | null;
|
||||
readonly readyState: number;
|
||||
readonly result: any;
|
||||
readonly EMPTY: number;
|
||||
readonly LOADING: number;
|
||||
readonly DONE: number;
|
||||
|
||||
onabort: ((ev: ProgressEvent<FileReader>) => void) | null;
|
||||
onerror: ((ev: FileReaderEvent) => void) | null;
|
||||
onload: ((ev: FileReaderEvent) => void) | null;
|
||||
onloadstart: ((ev: FileReaderEvent) => void) | null;
|
||||
onloadend: ((ev: FileReaderEvent) => void) | null;
|
||||
onprogress: ((ev: FileReaderEvent) => void) | null;
|
||||
|
||||
abort(): void;
|
||||
readAsArrayBuffer(blob: Blob): void;
|
||||
readAsBinaryString(blob: Blob): void;
|
||||
readAsDataURL(blob: Blob): void;
|
||||
readAsText(blob: Blob): void;
|
||||
}
|
||||
|
||||
export class VBlob implements Blob {
|
||||
_path: string = '';
|
||||
_size: number;
|
||||
_offset: number = 0;
|
||||
_type: string;
|
||||
_writeTask: Promise<number> = Promise.resolve(0);
|
||||
|
||||
private _write(fn: (fd: number) => void | Promise<void>): void {
|
||||
this._writeTask = this._writeTask.then(async (fd) => {
|
||||
if (!fd) {
|
||||
this._path = await getTempPath();
|
||||
fd = await fdopen(this._path, 'w+');
|
||||
}
|
||||
await fn(fd);
|
||||
return fd;
|
||||
});
|
||||
}
|
||||
|
||||
private _writeEnd(): void {
|
||||
this._writeTask = this._writeTask.then((fd) => fdclose(fd)).then(() => 0);
|
||||
}
|
||||
|
||||
constructor(array?: any[], options?: BlobPropertyBag) {
|
||||
this._type = (options && options.type) || '';
|
||||
|
||||
if (!array) {
|
||||
this._path = '';
|
||||
this._size = 0;
|
||||
} else {
|
||||
var size = 0;
|
||||
for (const value of array) {
|
||||
if (value instanceof ArrayBuffer) {
|
||||
if (value.byteLength === 0) continue;
|
||||
this._write((fd) => fdwrite(fd, new Uint8Array(value)));
|
||||
size += value.byteLength;
|
||||
} else if (value instanceof Uint8Array) {
|
||||
if (value.byteLength === 0) continue;
|
||||
this._write((fd) => fdwrite(fd, value));
|
||||
size += value.byteLength;
|
||||
} else if (
|
||||
value instanceof Int8Array ||
|
||||
value instanceof Uint8ClampedArray ||
|
||||
value instanceof Int16Array ||
|
||||
value instanceof Uint16Array ||
|
||||
value instanceof Int32Array ||
|
||||
value instanceof Uint32Array ||
|
||||
value instanceof Float32Array ||
|
||||
value instanceof Float64Array ||
|
||||
value instanceof DataView
|
||||
) {
|
||||
if (value.byteLength === 0) continue;
|
||||
this._write((fd) =>
|
||||
fdwrite(
|
||||
fd,
|
||||
new Uint8Array(value.buffer, value.byteOffset, value.byteLength),
|
||||
),
|
||||
);
|
||||
size += value.byteLength;
|
||||
} else if (value instanceof VBlob) {
|
||||
if (value._size === 0) continue;
|
||||
this._write((fd) => fdwriteFile(fd, value._path));
|
||||
size += value._size;
|
||||
} else {
|
||||
const str = value + '';
|
||||
if (str.length === 0) continue;
|
||||
this._write((fd) => fdwrite(fd, str));
|
||||
size += str.length;
|
||||
}
|
||||
}
|
||||
this._writeEnd();
|
||||
this._size = size;
|
||||
}
|
||||
}
|
||||
|
||||
get size(): number {
|
||||
return this._size;
|
||||
}
|
||||
|
||||
get type(): string {
|
||||
return this._type;
|
||||
}
|
||||
|
||||
slice(start?: number, end?: number, contentType?: string): Blob {
|
||||
if (!start) start = 0;
|
||||
else if (start < 0) start = this._size + start;
|
||||
if (!end) end = this._size;
|
||||
|
||||
if (end < 0) end = this._size - end;
|
||||
else if (end >= this._size) end = this._size;
|
||||
if (start >= end) return new VBlob([]);
|
||||
|
||||
const newblob = new VBlob();
|
||||
newblob._type = contentType || this._type;
|
||||
newblob._writeTask = this._writeTask;
|
||||
newblob._offset = this._offset + start;
|
||||
newblob._size = end - start;
|
||||
this._writeTask.then(() => (newblob._path = this._path));
|
||||
return newblob;
|
||||
}
|
||||
|
||||
readBuffer(fd: number): Promise<ArrayBuffer> {
|
||||
return fdread(fd, this._size, this._offset).then((buffer) => buffer.buffer);
|
||||
}
|
||||
}
|
||||
|
||||
export var Blob: { new (array?: any[], options?: BlobPropertyBag): Blob } =
|
||||
global['Blob'] || VBlob;
|
||||
|
||||
interface Aborted {
|
||||
aborted: boolean;
|
||||
}
|
||||
export class VFileReader extends EventTarget implements FileReader {
|
||||
static readonly EMPTY = 0;
|
||||
static readonly LOADING = 1;
|
||||
static readonly DONE = 2;
|
||||
readonly EMPTY = 0;
|
||||
readonly LOADING = 1;
|
||||
readonly DONE = 2;
|
||||
|
||||
onabort: ((ev: ProgressEvent<FileReader>) => void) | null = null;
|
||||
onerror: ((ev: FileReaderEvent) => void) | null = null;
|
||||
onload: ((ev: FileReaderEvent) => void) | null = null;
|
||||
onloadstart: ((ev: FileReaderEvent) => void) | null = null;
|
||||
onloadend: ((ev: FileReaderEvent) => void) | null = null;
|
||||
onprogress: ((ev: FileReaderEvent) => void) | null = null;
|
||||
|
||||
private _readyState: 0 | 1 | 2;
|
||||
private _abort: (() => void) | null = null;
|
||||
private _abortPromise: Promise<null> | null = null;
|
||||
|
||||
public result: any;
|
||||
public error: any | null = null;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._readyState = 0;
|
||||
}
|
||||
|
||||
get readyState(): 0 | 1 | 2 {
|
||||
return this._readyState;
|
||||
}
|
||||
|
||||
abort(): void {
|
||||
if (this._abort !== null) {
|
||||
this._abort();
|
||||
this._abort = null;
|
||||
this._abortPromise = null;
|
||||
this.dispatchEvent({ type: 'abort' });
|
||||
}
|
||||
if (this._readyState === 1) {
|
||||
this._finishWork();
|
||||
}
|
||||
}
|
||||
|
||||
private _startWork(methodName: string): Aborted {
|
||||
if (this._readyState === 1) {
|
||||
throw Error(
|
||||
`Failed to execute '${methodName}' on 'FileReader': The object is already busy reading Blobs.`,
|
||||
);
|
||||
}
|
||||
this.result = null;
|
||||
this.error = null;
|
||||
this._readyState = 1;
|
||||
const aborted: Aborted = { aborted: false };
|
||||
if (this._abortPromise === null) {
|
||||
this._abortPromise = new Promise<null>((resolve) => {
|
||||
this._abort = () => {
|
||||
aborted.aborted = true;
|
||||
resolve(null);
|
||||
};
|
||||
});
|
||||
}
|
||||
return aborted;
|
||||
}
|
||||
|
||||
private _finishWork() {
|
||||
this.dispatchEvent({ type: 'loadend' });
|
||||
this._readyState = 2;
|
||||
}
|
||||
|
||||
private _readBuffer(
|
||||
methodName: string,
|
||||
blob: Blob,
|
||||
cb: (buffer: Buffer) => any,
|
||||
): Promise<void> {
|
||||
const aborted = this._startWork(methodName);
|
||||
|
||||
if (!(blob instanceof VBlob) && !(blob instanceof NodeBlob)) {
|
||||
throw TypeError(
|
||||
`vblob cannot handle the ${blob.constructor.name} class.`,
|
||||
);
|
||||
}
|
||||
|
||||
const prom = new Promise((resolve) => process.nextTick(resolve)).then(
|
||||
() => {
|
||||
if (aborted.aborted) return null;
|
||||
this.dispatchEvent({ type: 'loadstart' });
|
||||
if (blob instanceof VBlob) {
|
||||
return this._readVBlob(blob);
|
||||
} else if (blob instanceof NodeBlob) {
|
||||
return this._readNodeBlob(blob);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
);
|
||||
return Promise.race([this._abortPromise, prom]).then(
|
||||
(data) => {
|
||||
if (data === null) return;
|
||||
if (aborted.aborted) return;
|
||||
this.result = cb(data);
|
||||
this.dispatchEvent({ type: 'load' });
|
||||
this._finishWork();
|
||||
},
|
||||
(err) => {
|
||||
if (aborted.aborted) return;
|
||||
this.error = err;
|
||||
this.dispatchEvent({
|
||||
type: 'error',
|
||||
message: err ? err.message : 'Error',
|
||||
});
|
||||
this._finishWork();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
private async _readVBlob(blob: VBlob): Promise<Buffer> {
|
||||
if (blob._size === 0) {
|
||||
return Buffer.alloc(0);
|
||||
} else {
|
||||
await blob._writeTask;
|
||||
const fd = await fdopen(blob._path, 'r');
|
||||
try {
|
||||
return await fdread(fd, blob._size, blob._offset);
|
||||
} finally {
|
||||
fdclose(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async _readNodeBlob(blob: NodeBlob): Promise<Buffer> {
|
||||
const buf = await blob.arrayBuffer();
|
||||
return Buffer.from(buf);
|
||||
}
|
||||
|
||||
readAsArrayBuffer(blob: Blob): void {
|
||||
this._readBuffer('readAsArrayBuffer', blob, (data) => data.buffer);
|
||||
}
|
||||
readAsBinaryString(blob: Blob): void {
|
||||
this._readBuffer('readAsBinaryString', blob, (data) =>
|
||||
data.toString('binary'),
|
||||
);
|
||||
}
|
||||
readAsDataURL(blob: Blob): void {
|
||||
this._readBuffer(
|
||||
'readAsDataURL',
|
||||
blob,
|
||||
(data) =>
|
||||
'data:' +
|
||||
(blob.type || 'application/octet-stream') +
|
||||
';base64,' +
|
||||
data.toString('base64'),
|
||||
);
|
||||
}
|
||||
readAsText(blob: Blob): void {
|
||||
this._readBuffer('readAsText', blob, (data) => data.toString());
|
||||
}
|
||||
}
|
||||
|
||||
export var FileReader: { new (): FileReader } = VFileReader;
|
@ -1,27 +0,0 @@
|
||||
import { resolve } from 'path';
|
||||
import { ModelStore, MsonEvaluate } from '.';
|
||||
import { fillStoreFromFilesystem, saveGeometry, saveModel } from './util/node';
|
||||
import { ThreeBuilder } from './three';
|
||||
import { DoubleSide, MeshLambertMaterial } from 'three';
|
||||
|
||||
async function init() {
|
||||
const store = new ModelStore();
|
||||
const evaluate = new MsonEvaluate(store);
|
||||
const mat = new MeshLambertMaterial();
|
||||
// mat.side = DoubleSide;
|
||||
const builder = new ThreeBuilder(mat);
|
||||
|
||||
await fillStoreFromFilesystem(store, resolve(process.cwd(), 'inputs'));
|
||||
|
||||
// mson:steve
|
||||
// minelittlepony:steve_pony
|
||||
const final = evaluate.evaluateModel('minelittlepony:races/steve/alicorn');
|
||||
// console.log(final.texture);
|
||||
const geometry = builder.buildGeometry(final);
|
||||
const outputName = 'alicorn';
|
||||
const outputs = resolve(process.cwd(), 'outputs');
|
||||
await saveGeometry(outputs, outputName, geometry);
|
||||
await saveModel(outputs, outputName, final);
|
||||
}
|
||||
|
||||
init().catch(console.error);
|
@ -1,5 +1,6 @@
|
||||
import {
|
||||
BoxGeometry,
|
||||
BufferGeometry,
|
||||
CylinderGeometry,
|
||||
Material,
|
||||
MathUtils,
|
||||
@ -66,7 +67,10 @@ export class ThreeBuilder {
|
||||
new Vector3(pos.x + size.x / 2, pos.y - size.y / 2, pos.z),
|
||||
};
|
||||
|
||||
constructor(private readonly material: Material) {}
|
||||
/**
|
||||
* @param material Material to use for the whole model.
|
||||
*/
|
||||
constructor(protected readonly material: Material) {}
|
||||
|
||||
/**
|
||||
* Create a THREE.js object from MSON evaluated model data.
|
||||
@ -245,10 +249,7 @@ export class ThreeBuilder {
|
||||
adjustedTranslate.z,
|
||||
);
|
||||
|
||||
// TODO: FIXME: this crap is to hack .toJSON() into including the entire geometry
|
||||
// instead of just the properties used to initialize it.
|
||||
(geometry as any).type = 'BufferGeometry';
|
||||
delete (geometry as any).parameters;
|
||||
ThreeBuilder.obfuscateGeometry(geometry);
|
||||
|
||||
// Map UVs to box
|
||||
UVMapper.mapBoxUVs(size, geometry, texture);
|
||||
@ -307,10 +308,7 @@ export class ThreeBuilder {
|
||||
geometry = geometry.toNonIndexed() as CylinderGeometry;
|
||||
geometry.computeVertexNormals();
|
||||
|
||||
// TODO: FIXME: this crap is to hack .toJSON() into including the entire geometry
|
||||
// instead of just the properties used to initialize it.
|
||||
(geometry as any).type = 'BufferGeometry';
|
||||
delete (geometry as any).parameters;
|
||||
ThreeBuilder.obfuscateGeometry(geometry);
|
||||
|
||||
const mesh = new Mesh(geometry, this.material);
|
||||
mesh.name = `${name}__cone`;
|
||||
@ -341,10 +339,7 @@ export class ThreeBuilder {
|
||||
adjustedTranslate.z,
|
||||
);
|
||||
|
||||
// TODO: FIXME: this crap is to hack .toJSON() into including the entire geometry
|
||||
// instead of just the properties used to initialize it.
|
||||
(planeGeom as any).type = 'BufferGeometry';
|
||||
delete (planeGeom as any).parameters;
|
||||
ThreeBuilder.obfuscateGeometry(planeGeom);
|
||||
|
||||
UVMapper.mapPlanarUvs(face, size, planeGeom, texture, mirror);
|
||||
|
||||
@ -465,4 +460,14 @@ export class ThreeBuilder {
|
||||
wrapper.updateMatrix();
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* This crap is to hack `Object3D.toJSON()` into including the entire geometry
|
||||
* instead of just the properties used to initialize it.
|
||||
* @param geometry Geometry
|
||||
*/
|
||||
static obfuscateGeometry(geometry: BufferGeometry) {
|
||||
(geometry as any).type = 'BufferGeometry';
|
||||
delete (geometry as any).parameters;
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
/**
|
||||
* Simple object check.
|
||||
* @param item
|
||||
* @returns {boolean}
|
||||
* @returns {boolean} Is Object, not array, null or undefined.
|
||||
*/
|
||||
export function isObject(item: any) {
|
||||
export function isObject(item: any): boolean {
|
||||
return item && typeof item === 'object' && !Array.isArray(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deep merge two objects.
|
||||
* @param target
|
||||
* @param ...sources
|
||||
* @param target Merge `sources` into this object.
|
||||
* @param ...sources Objects to use in merge.
|
||||
*/
|
||||
export function mergeDeep(target: any, ...sources: any[]) {
|
||||
if (!sources.length) return target;
|
||||
|
@ -1,3 +1,13 @@
|
||||
/**
|
||||
* Convert number from one range to another.
|
||||
* @example
|
||||
* // returns 0.5
|
||||
* convertRange(0, [-1, 1], [0, 1]);
|
||||
* @param value Value to convert
|
||||
* @param r1 Source range
|
||||
* @param r2 Target range
|
||||
* @returns Value in new range
|
||||
*/
|
||||
export function convertRange(
|
||||
value: number,
|
||||
r1: [number, number],
|
||||
|
@ -9,7 +9,7 @@
|
||||
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
|
||||
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
||||
/* Language and Environment */
|
||||
"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
||||
"target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
|
||||
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
||||
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
|
||||
@ -22,7 +22,7 @@
|
||||
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
||||
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
||||
/* Modules */
|
||||
"module": "commonjs", /* Specify what module code is generated. */
|
||||
"module": "Node16" /* Specify what module code is generated. */,
|
||||
// "rootDir": "./", /* Specify the root folder within your source files. */
|
||||
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
|
||||
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
||||
@ -50,7 +50,7 @@
|
||||
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
|
||||
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
|
||||
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
|
||||
"outDir": "./lib", /* Specify an output folder for all emitted files. */
|
||||
"outDir": "./lib" /* Specify an output folder for all emitted files. */,
|
||||
// "removeComments": true, /* Disable emitting comments. */
|
||||
// "noEmit": true, /* Disable emitting files from a compilation. */
|
||||
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
||||
@ -71,11 +71,11 @@
|
||||
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
|
||||
// "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
|
||||
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
|
||||
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
|
||||
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
||||
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
|
||||
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
|
||||
/* Type Checking */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
"strict": true /* Enable all strict type-checking options. */,
|
||||
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
|
||||
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
|
||||
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
||||
|
Loading…
Reference in New Issue
Block a user