Initial commits for webpack
6532
package-lock.json
generated
18
package.json
@ -17,7 +17,9 @@
|
||||
"headless": "tsc && node ./dist/tools/run-headless.js",
|
||||
"package:win": "electron-packager . ObjToSchematic --overwrite --platform=win32 --arch=x64 --icon=res/static/icon.ico --prune=true --out=release",
|
||||
"package:linux": "electron-packager . ObjToSchematic --overwrite --platform=linux --arch=x64 --icon=res/static/icon.png --prune=true --out=release",
|
||||
"package:macos": "electron-packager . ObjToSchematic --overwrite --platform=darwin --arch=x64 --icon=res/static/icon.icns --prune=true --out=release"
|
||||
"package:macos": "electron-packager . ObjToSchematic --overwrite --platform=darwin --arch=x64 --icon=res/static/icon.icns --prune=true --out=release",
|
||||
"webdev": "webpack serve --config ./webpack.dev.js",
|
||||
"webbuild": "webpack --config ./webpack.prod.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -42,20 +44,32 @@
|
||||
"@typescript-eslint/eslint-plugin": "^5.9.1",
|
||||
"@typescript-eslint/parser": "^5.9.1",
|
||||
"adm-zip": "^0.5.9",
|
||||
"browserify-zlib": "^0.2.0",
|
||||
"chalk": "^4.1.2",
|
||||
"copy-dir": "^1.3.0",
|
||||
"css-loader": "^6.7.3",
|
||||
"electron": "^13.6.6",
|
||||
"electron-packager": "^15.2.0",
|
||||
"eslint": "^8.7.0",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
"eslint-plugin-simple-import-sort": "^8.0.0",
|
||||
"file-loader": "^6.2.0",
|
||||
"images": "^3.2.3",
|
||||
"jest": "^27.5.1",
|
||||
"node-polyfill-webpack-plugin": "^2.0.1",
|
||||
"prompt": "^1.2.1",
|
||||
"raw-loader": "^4.0.2",
|
||||
"sharp": "^0.31.1",
|
||||
"style-loader": "^3.3.1",
|
||||
"ts-jest": "^27.1.3",
|
||||
"ts-loader": "^9.4.2",
|
||||
"ts-node": "^10.1.0",
|
||||
"typescript": "^4.3.5"
|
||||
"typescript": "^4.3.5",
|
||||
"webpack": "^5.75.0",
|
||||
"webpack-cli": "^5.0.1",
|
||||
"webpack-dev-server": "^4.11.1",
|
||||
"webpack-merge": "^5.8.0",
|
||||
"webpack-strip-block": "^0.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"bvh-tree": "^1.0.1",
|
||||
|
@ -1,28 +0,0 @@
|
||||
{
|
||||
"AMBIENT_OCCLUSION_OVERRIDE_CORNER": true,
|
||||
"LOG_TO_FILE": true,
|
||||
"USE_WORKER_THREAD": true,
|
||||
"MULTISAMPLE_COUNT": 16,
|
||||
"OLD_SPACE_SIZE_MB": 8192,
|
||||
"ALPHA_BIAS": 1.0,
|
||||
"ANGLE_SNAP_RADIUS_DEGREES": 10.0,
|
||||
"RENDER_TRIANGLE_THRESHOLD": 1000000,
|
||||
"MAXIMUM_IMAGE_MEM_ALLOC": 2048,
|
||||
"CAMERA_FOV_DEGREES": 30.0,
|
||||
"CAMERA_DEFAULT_DISTANCE_UNITS": 18.0,
|
||||
"CAMERA_DEFAULT_AZIMUTH_RADIANS": -1.0,
|
||||
"CAMERA_DEFAULT_ELEVATION_RADIANS": 1.3,
|
||||
"CAMERA_SENSITIVITY_ROTATION": 0.005,
|
||||
"CAMERA_SENSITIVITY_ZOOM": 0.005,
|
||||
"CONSTRAINT_MAXIMUM_HEIGHT": 380,
|
||||
"DITHER_MAGNITUDE": 32,
|
||||
"SMOOTHNESS_MAX": 3.0,
|
||||
"CAMERA_SMOOTHING": 0.1,
|
||||
"VIEWPORT_BACKGROUND_COLOUR": {
|
||||
"R": 0.125,
|
||||
"G": 0.125,
|
||||
"B": 0.125
|
||||
},
|
||||
"FRESNEL_EXPONENT": 3.0,
|
||||
"FRESNEL_MIX": 0.3
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-axis-x" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#00abfb" fill="none" stroke-linecap="round" stroke-linejoin="round" id="axes-svg">
|
||||
<path d="M17 20l3 -3l-3 -3" />
|
||||
<path d="M4 17h16" />
|
||||
<path d="M4 7l3 -3l3 3" />
|
||||
<path d="M7 20v-16" />
|
||||
</svg>
|
Before Width: | Height: | Size: 354 B |
@ -1,7 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-box" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#00abfb" fill="none" stroke-linecap="round" stroke-linejoin="round" id="block-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<polyline points="12 3 20 7.5 20 16.5 12 21 4 16.5 4 7.5 12 3" />
|
||||
<line x1="12" y1="12" x2="20" y2="7.5" />
|
||||
<line x1="12" y1="12" x2="12" y2="21" />
|
||||
<line x1="12" y1="12" x2="4" y2="7.5" />
|
||||
</svg>
|
Before Width: | Height: | Size: 493 B |
@ -1,9 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-box-model" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#00abfb" fill="none" stroke-linecap="round" stroke-linejoin="round" id="bounds-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M8 8h8v8h-8z" />
|
||||
<rect x="4" y="4" width="16" height="16" rx="2" />
|
||||
<path d="M16 16l3.3 3.3" />
|
||||
<path d="M16 8l3.3 -3.3" />
|
||||
<path d="M8 8l-3.3 -3.3" />
|
||||
<path d="M8 16l-3.3 3.3" />
|
||||
</svg>
|
Before Width: | Height: | Size: 503 B |
@ -1,5 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-sun" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#00abfb" fill="none" stroke-linecap="round" stroke-linejoin="round" id="bulb-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<circle cx="12" cy="12" r="4" />
|
||||
<path d="M3 12h1m8 -9v1m8 8h1m-9 8v1m-6.4 -15.4l.7 .7m12.1 -.7l-.7 .7m0 11.4l.7 .7m-12.1 -.7l-.7 .7" />
|
||||
</svg>
|
Before Width: | Height: | Size: 435 B |
@ -1,9 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-focus-2" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#00abfb" fill="none" stroke-linecap="round" stroke-linejoin="round" id="centre-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<circle cx="12" cy="12" r=".5" fill="currentColor" />
|
||||
<circle cx="12" cy="12" r="7" />
|
||||
<line x1="12" y1="3" x2="12" y2="5" />
|
||||
<line x1="3" y1="12" x2="5" y2="12" />
|
||||
<line x1="12" y1="19" x2="12" y2="21" />
|
||||
<line x1="19" y1="12" x2="21" y2="12" />
|
||||
</svg>
|
Before Width: | Height: | Size: 559 B |
@ -1,12 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-bug" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#00abfb" fill="none" stroke-linecap="round" stroke-linejoin="round" id="debug-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M9 9v-1a3 3 0 0 1 6 0v1" />
|
||||
<path d="M8 9h8a6 6 0 0 1 1 3v3a5 5 0 0 1 -10 0v-3a6 6 0 0 1 1 -3" />
|
||||
<line x1="3" y1="13" x2="7" y2="13" />
|
||||
<line x1="17" y1="13" x2="21" y2="13" />
|
||||
<line x1="12" y1="20" x2="12" y2="14" />
|
||||
<line x1="4" y1="19" x2="7.35" y2="17" />
|
||||
<line x1="20" y1="19" x2="16.65" y2="17" />
|
||||
<line x1="4" y1="7" x2="7.75" y2="9.4" />
|
||||
<line x1="20" y1="7" x2="16.25" y2="9.4" />
|
||||
</svg>
|
Before Width: | Height: | Size: 713 B |
@ -1,4 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-folder" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#2c3e50" fill="none" stroke-linecap="round" stroke-linejoin="round" id="folder-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M5 4h4l3 3h7a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2v-11a2 2 0 0 1 2 -2" />
|
||||
</svg>
|
Before Width: | Height: | Size: 397 B |
@ -1,6 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-border-all" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#00abfb" fill="none" stroke-linecap="round" stroke-linejoin="round" id="grid-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<rect x="4" y="4" width="16" height="16" rx="2" />
|
||||
<line x1="4" y1="12" x2="20" y2="12" />
|
||||
<line x1="12" y1="4" x2="12" y2="20" />
|
||||
</svg>
|
Before Width: | Height: | Size: 438 B |
@ -1,6 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-magnet" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#00abfb" fill="none" stroke-linecap="round" stroke-linejoin="round" id="magnet-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M4 13v-8a2 2 0 0 1 2 -2h1a2 2 0 0 1 2 2v8a2 2 0 0 0 6 0v-8a2 2 0 0 1 2 -2h1a2 2 0 0 1 2 2v8a8 8 0 0 1 -16 0" />
|
||||
<line x1="4" y1="8" x2="9" y2="8" />
|
||||
<line x1="15" y1="8" x2="19" y2="8" />
|
||||
</svg>
|
Before Width: | Height: | Size: 502 B |
@ -1,11 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-grain" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#00abfb" fill="none" stroke-linecap="round" stroke-linejoin="round" id="mesh-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<circle cx="4.5" cy="9.5" r="1" />
|
||||
<circle cx="9.5" cy="4.5" r="1" />
|
||||
<circle cx="9.5" cy="14.5" r="1" />
|
||||
<circle cx="4.5" cy="19.5" r="1" />
|
||||
<circle cx="14.5" cy="9.5" r="1" />
|
||||
<circle cx="19.5" cy="4.5" r="1" />
|
||||
<circle cx="14.5" cy="19.5" r="1" />
|
||||
<circle cx="19.5" cy="14.5" r="1" />
|
||||
</svg>
|
Before Width: | Height: | Size: 600 B |
@ -1,4 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-minus" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#00abfb" fill="none" stroke-linecap="round" stroke-linejoin="round" id="minus-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<line x1="5" y1="12" x2="19" y2="12" />
|
||||
</svg>
|
Before Width: | Height: | Size: 339 B |
@ -1,7 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-arrows-up" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#00abfb" fill="none" stroke-linecap="round" stroke-linejoin="round" id="normal-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<line x1="17" y1="3" x2="17" y2="21" />
|
||||
<path d="M4 6l3 -3l3 3" />
|
||||
<path d="M20 6l-3 -3l-3 3" />
|
||||
<line x1="7" y1="3" x2="7" y2="21" />
|
||||
</svg>
|
Before Width: | Height: | Size: 445 B |
@ -1,4 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-rectangle" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#00abfb" fill="none" stroke-linecap="round" stroke-linejoin="round" id="orthographic-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<rect x="3" y="5" width="18" height="14" rx="2" />
|
||||
</svg>
|
Before Width: | Height: | Size: 361 B |
@ -1,4 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-perspective" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#00abfb" fill="none" stroke-linecap="round" stroke-linejoin="round" id="perspective-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M6.141 4.163l12 1.714a1 1 0 0 1 .859 .99v10.266a1 1 0 0 1 -.859 .99l-12 1.714a1 1 0 0 1 -1.141 -.99v-13.694a1 1 0 0 1 1.141 -.99z" />
|
||||
</svg>
|
Before Width: | Height: | Size: 454 B |
@ -1,5 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-plus" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#00abfb" fill="none" stroke-linecap="round" stroke-linejoin="round" id="plus-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<line x1="12" y1="5" x2="12" y2="19" />
|
||||
<line x1="5" y1="12" x2="19" y2="12" />
|
||||
</svg>
|
Before Width: | Height: | Size: 379 B |
@ -1,5 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-rotate-360" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#00abfb" fill="none" stroke-linecap="round" stroke-linejoin="round" id="rotate-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M12 16h4v4" />
|
||||
<path d="M19.458 11.042c.86 -2.366 .722 -4.58 -.6 -5.9c-2.272 -2.274 -7.185 -1.045 -10.973 2.743c-3.788 3.788 -5.017 8.701 -2.744 10.974c2.227 2.226 6.987 1.093 10.74 -2.515" />
|
||||
</svg>
|
Before Width: | Height: | Size: 509 B |
@ -1,7 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-switch-3" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#2c3e50" fill="none" stroke-linecap="round" stroke-linejoin="round" id="switch-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M3 17h2.397a5 5 0 0 0 4.096 -2.133l.177 -.253m3.66 -5.227l.177 -.254a5 5 0 0 1 4.096 -2.133h3.397" />
|
||||
<path d="M18 4l3 3l-3 3" />
|
||||
<path d="M3 7h2.397a5 5 0 0 1 4.096 2.133l4.014 5.734a5 5 0 0 0 4.096 2.133h3.397" />
|
||||
<path d="M18 20l3 -3l-3 -3" />
|
||||
</svg>
|
Before Width: | Height: | Size: 565 B |
@ -1,11 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-arrows-maximize" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#00abfb" fill="none" stroke-linecap="round" stroke-linejoin="round" id="translate-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<polyline points="16 4 20 4 20 8" />
|
||||
<line x1="14" y1="10" x2="20" y2="4" />
|
||||
<polyline points="8 20 4 20 4 16" />
|
||||
<line x1="4" y1="20" x2="10" y2="14" />
|
||||
<polyline points="16 20 20 20 20 16" />
|
||||
<line x1="14" y1="14" x2="20" y2="20" />
|
||||
<polyline points="8 4 4 4 4 8" />
|
||||
<line x1="4" y1="4" x2="10" y2="10" />
|
||||
</svg>
|
Before Width: | Height: | Size: 635 B |
@ -1,6 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-upload" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#2c3e50" fill="none" stroke-linecap="round" stroke-linejoin="round" id="upload-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2 -2v-2" />
|
||||
<polyline points="7 9 12 4 17 9" />
|
||||
<line x1="12" y1="4" x2="12" y2="16" />
|
||||
</svg>
|
Before Width: | Height: | Size: 437 B |
@ -1,15 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-3d-cube-sphere" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#00abfb" fill="none" stroke-linecap="round" stroke-linejoin="round" id="voxel-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M6 17.6l-2 -1.1v-2.5" />
|
||||
<path d="M4 10v-2.5l2 -1.1" />
|
||||
<path d="M10 4.1l2 -1.1l2 1.1" />
|
||||
<path d="M18 6.4l2 1.1v2.5" />
|
||||
<path d="M20 14v2.5l-2 1.12" />
|
||||
<path d="M14 19.9l-2 1.1l-2 -1.1" />
|
||||
<line x1="12" y1="12" x2="14" y2="10.9" />
|
||||
<line x1="18" y1="8.6" x2="20" y2="7.5" />
|
||||
<line x1="12" y1="12" x2="12" y2="14.5" />
|
||||
<line x1="12" y1="18.5" x2="12" y2="21" />
|
||||
<path d="M12 12l-2 -1.12" />
|
||||
<line x1="6" y1="8.6" x2="4" y2="7.5" />
|
||||
</svg>
|
Before Width: | Height: | Size: 771 B |
@ -1,6 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-squares-diagonal" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#00abfb" fill="none" stroke-linecap="round" stroke-linejoin="round" id="wireframe-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<rect x="8" y="8" width="12" height="12" rx="2" />
|
||||
<path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2" />
|
||||
<path d="M8.586 19.414l10.827 -10.827" />
|
||||
</svg>
|
Before Width: | Height: | Size: 485 B |
@ -1,4 +1,5 @@
|
||||
import { remote } from 'electron';
|
||||
import '../styles.css';
|
||||
|
||||
import path from 'path';
|
||||
|
||||
import { FallableBehaviour } from './block_mesh';
|
||||
@ -18,7 +19,6 @@ import { UI } from './ui/layout';
|
||||
import { UIMessageBuilder } from './ui/misc';
|
||||
import { ColourSpace, EAction } from './util';
|
||||
import { ASSERT } from './util/error_util';
|
||||
import { FileUtil } from './util/file_util';
|
||||
import { LOG_ERROR, Logger } from './util/log_util';
|
||||
import { AppPaths } from './util/path_util';
|
||||
import { Vector3 } from './vector';
|
||||
@ -35,15 +35,14 @@ export class AppContext {
|
||||
public constructor() {
|
||||
this._materialManager = new MaterialMapManager(new Map());
|
||||
|
||||
Logger.Get.enableLogToFile();
|
||||
Logger.Get.initLogFile('client');
|
||||
Logger.Get.enableLOG();
|
||||
Logger.Get.enableLOGMAJOR();
|
||||
Logger.Get.enableLOGWARN();
|
||||
|
||||
AppConfig.Get.dumpConfig();
|
||||
|
||||
FileUtil.rmdirIfExist(AppPaths.Get.gen);
|
||||
// TODO Unimplemented
|
||||
//FileUtil.rmdirIfExist(AppPaths.Get.gen);
|
||||
|
||||
const gl = (<HTMLCanvasElement>document.getElementById('canvas')).getContext('webgl');
|
||||
if (!gl) {
|
||||
@ -505,6 +504,9 @@ export class AppContext {
|
||||
const exporterID: TExporters = this._ui.layout.export.elements.export.getValue();
|
||||
const exporter: IExporter = ExporterFactory.GetExporter(exporterID);
|
||||
|
||||
|
||||
// TODO Unimplemented
|
||||
/*
|
||||
const filepath = remote.dialog.showSaveDialogSync({
|
||||
title: 'Save structure',
|
||||
buttonLabel: 'Save',
|
||||
@ -516,7 +518,10 @@ export class AppContext {
|
||||
}
|
||||
|
||||
this._ui.getActionOutput(EAction.Export)
|
||||
.setTaskInProgress('action', '[Exporter]: Saving...');
|
||||
.setTaskInProgress('action', '[Exporter]: Saving...');
|
||||
*/
|
||||
|
||||
const filepath = '';
|
||||
|
||||
const payload: TToWorkerMessage = {
|
||||
action: 'Export',
|
||||
|
@ -1,7 +1,5 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
import { TAtlasVersion } from '../tools/build-atlas';
|
||||
import { RGBA } from './colour';
|
||||
import { AppTypes, AppUtil, TOptional, UV } from './util';
|
||||
import { AppError, ASSERT } from './util/error_util';
|
||||
@ -51,6 +49,9 @@ export class Atlas {
|
||||
}
|
||||
|
||||
public static load(atlasName: string): TOptional<Atlas> {
|
||||
// TODO Unimplemented
|
||||
return undefined;
|
||||
/*
|
||||
if (!Atlas._isValidAtlasName(atlasName)) {
|
||||
return;
|
||||
}
|
||||
@ -131,6 +132,7 @@ export class Atlas {
|
||||
}
|
||||
|
||||
return atlas;
|
||||
*/
|
||||
}
|
||||
|
||||
public getAtlasSize(): number {
|
||||
|
@ -1,5 +1,3 @@
|
||||
import fs from 'fs';
|
||||
|
||||
import { RGBA } from './colour';
|
||||
import { LOG } from './util/log_util';
|
||||
import { AppPaths, PathUtil } from './util/path_util';
|
||||
@ -11,69 +9,38 @@ export class AppConfig {
|
||||
return this._instance || (this._instance = new this());
|
||||
}
|
||||
|
||||
public readonly RELEASE_MODE: boolean;
|
||||
public readonly RELEASE_VERSION: string;
|
||||
public readonly VOXEL_BUFFER_CHUNK_SIZE: number;
|
||||
public readonly RELEASE_MODE = false;
|
||||
public readonly RELEASE_VERSION = '0.7.2d';
|
||||
public readonly VOXEL_BUFFER_CHUNK_SIZE = 5_000;
|
||||
|
||||
// Loaded from .json
|
||||
public readonly AMBIENT_OCCLUSION_OVERRIDE_CORNER: boolean;
|
||||
public readonly LOG_TO_FILE: boolean;
|
||||
public readonly USE_WORKER_THREAD: boolean;
|
||||
public readonly MULTISAMPLE_COUNT: number;
|
||||
public readonly OLD_SPACE_SIZE_MB: number;
|
||||
public readonly ALPHA_BIAS: number;
|
||||
public readonly ANGLE_SNAP_RADIUS_DEGREES: number;
|
||||
public readonly RENDER_TRIANGLE_THRESHOLD: number;
|
||||
public readonly MAXIMUM_IMAGE_MEM_ALLOC: number;
|
||||
public readonly CAMERA_FOV_DEGREES: number;
|
||||
public readonly CAMERA_DEFAULT_DISTANCE_UNITS: number;
|
||||
public readonly CAMERA_DEFAULT_AZIMUTH_RADIANS: number;
|
||||
public readonly CAMERA_DEFAULT_ELEVATION_RADIANS: number;
|
||||
public readonly CAMERA_SENSITIVITY_ROTATION: number;
|
||||
public readonly CAMERA_SENSITIVITY_ZOOM: number;
|
||||
public readonly CONSTRAINT_MAXIMUM_HEIGHT: number;
|
||||
public readonly DITHER_MAGNITUDE: number;
|
||||
public readonly SMOOTHNESS_MAX: number;
|
||||
public readonly CAMERA_SMOOTHING: number;
|
||||
public readonly VIEWPORT_BACKGROUND_COLOUR: RGBA;
|
||||
public readonly FRESNEL_EXPONENT: number;
|
||||
public readonly FRESNEL_MIX: number;
|
||||
public readonly AMBIENT_OCCLUSION_OVERRIDE_CORNER = true;
|
||||
public readonly USE_WORKER_THREAD = false;
|
||||
public readonly MULTISAMPLE_COUNT = 16;
|
||||
public readonly ALPHA_BIAS = 1.0;
|
||||
public readonly ANGLE_SNAP_RADIUS_DEGREES = 10.0;
|
||||
public readonly RENDER_TRIANGLE_THRESHOLD = 1_000_000;
|
||||
public readonly MAXIMUM_IMAGE_MEM_ALLOC = 2048;
|
||||
public readonly CAMERA_FOV_DEGREES = 30.0;
|
||||
public readonly CAMERA_DEFAULT_DISTANCE_UNITS = 18.0;
|
||||
public readonly CAMERA_DEFAULT_AZIMUTH_RADIANS = -1.0;
|
||||
public readonly CAMERA_DEFAULT_ELEVATION_RADIANS = 1.3;
|
||||
public readonly CAMERA_SENSITIVITY_ROTATION = 0.005;
|
||||
public readonly CAMERA_SENSITIVITY_ZOOM = 0.005;
|
||||
public readonly CONSTRAINT_MAXIMUM_HEIGHT = 380;
|
||||
public readonly DITHER_MAGNITUDE = 32;
|
||||
public readonly SMOOTHNESS_MAX = 3.0;
|
||||
public readonly CAMERA_SMOOTHING = 0.1;
|
||||
public readonly VIEWPORT_BACKGROUND_COLOUR: RGBA = {
|
||||
r: 0.125,
|
||||
g: 0.125,
|
||||
b: 0.125,
|
||||
a: 1.0,
|
||||
};
|
||||
public readonly FRESNEL_EXPONENT = 3.0;
|
||||
public readonly FRESNEL_MIX = 0.3;
|
||||
|
||||
private constructor() {
|
||||
this.RELEASE_MODE = true;
|
||||
this.RELEASE_VERSION = '0.7.2d';
|
||||
this.VOXEL_BUFFER_CHUNK_SIZE = 5_000;
|
||||
|
||||
const configFile = fs.readFileSync(PathUtil.join(AppPaths.Get.resources, 'config.json'), 'utf8');
|
||||
const configJSON = JSON.parse(configFile);
|
||||
|
||||
this.AMBIENT_OCCLUSION_OVERRIDE_CORNER = configJSON.AMBIENT_OCCLUSION_OVERRIDE_CORNER;
|
||||
this.LOG_TO_FILE = configJSON.LOG_TO_FILE;
|
||||
this.USE_WORKER_THREAD = configJSON.USE_WORKER_THREAD && !process.argv.includes('--OTS-ENABLE-DEBUG');
|
||||
this.MULTISAMPLE_COUNT = configJSON.MULTISAMPLE_COUNT;
|
||||
this.OLD_SPACE_SIZE_MB = configJSON.OLD_SPACE_SIZE_MB;
|
||||
this.ALPHA_BIAS = configJSON.ALPHA_BIAS;
|
||||
this.ANGLE_SNAP_RADIUS_DEGREES = configJSON.ANGLE_SNAP_RADIUS_DEGREES;
|
||||
this.RENDER_TRIANGLE_THRESHOLD = configJSON.RENDER_TRIANGLE_THRESHOLD;
|
||||
this.MAXIMUM_IMAGE_MEM_ALLOC = configJSON.MAXIMUM_IMAGE_MEM_ALLOC;
|
||||
this.CAMERA_FOV_DEGREES = configJSON.CAMERA_FOV_DEGREES;
|
||||
this.CAMERA_DEFAULT_DISTANCE_UNITS = configJSON.CAMERA_DEFAULT_DISTANCE_UNITS;
|
||||
this.CAMERA_DEFAULT_AZIMUTH_RADIANS = configJSON.CAMERA_DEFAULT_AZIMUTH_RADIANS;
|
||||
this.CAMERA_DEFAULT_ELEVATION_RADIANS = configJSON.CAMERA_DEFAULT_ELEVATION_RADIANS;
|
||||
this.CAMERA_SENSITIVITY_ROTATION = configJSON.CAMERA_SENSITIVITY_ROTATION;
|
||||
this.CAMERA_SENSITIVITY_ZOOM = configJSON.CAMERA_SENSITIVITY_ZOOM;
|
||||
this.CONSTRAINT_MAXIMUM_HEIGHT = configJSON.CONSTRAINT_MAXIMUM_HEIGHT;
|
||||
this.DITHER_MAGNITUDE = configJSON.DITHER_MAGNITUDE;
|
||||
this.SMOOTHNESS_MAX = configJSON.SMOOTHNESS_MAX;
|
||||
this.CAMERA_SMOOTHING = configJSON.CAMERA_SMOOTHING;
|
||||
this.VIEWPORT_BACKGROUND_COLOUR = {
|
||||
r: configJSON.VIEWPORT_BACKGROUND_COLOUR.R,
|
||||
g: configJSON.VIEWPORT_BACKGROUND_COLOUR.G,
|
||||
b: configJSON.VIEWPORT_BACKGROUND_COLOUR.B,
|
||||
a: 1.0,
|
||||
};
|
||||
this.FRESNEL_EXPONENT = configJSON.FRESNEL_EXPONENT;
|
||||
this.FRESNEL_MIX = configJSON.FRESNEL_MIX;
|
||||
}
|
||||
|
||||
public dumpConfig() {
|
||||
|
@ -1,6 +1,4 @@
|
||||
|
||||
import fs from 'fs';
|
||||
|
||||
import { AppTypes } from './util';
|
||||
import { AppPaths, PathUtil } from './util/path_util';
|
||||
|
||||
@ -40,22 +38,89 @@ export class AppRuntimeConstants {
|
||||
return this._instance || (this._instance = new this());
|
||||
}
|
||||
|
||||
public readonly FALLABLE_BLOCKS: AppTypes.TNamespacedBlockName[];
|
||||
public readonly TRANSPARENT_BLOCKS: AppTypes.TNamespacedBlockName[];
|
||||
public readonly GRASS_LIKE_BLOCKS: AppTypes.TNamespacedBlockName[];
|
||||
public readonly EMISSIVE_BLOCKS: AppTypes.TNamespacedBlockName[];
|
||||
public readonly FALLABLE_BLOCKS = [
|
||||
'minecraft:anvil',
|
||||
'minecraft:lime_concrete_powder',
|
||||
'minecraft:orange_concrete_powder',
|
||||
'minecraft:black_concrete_powder',
|
||||
'minecraft:brown_concrete_powder',
|
||||
'minecraft:cyan_concrete_powder',
|
||||
'minecraft:light_gray_concrete_powder',
|
||||
'minecraft:purple_concrete_powder',
|
||||
'minecraft:magenta_concrete_powder',
|
||||
'minecraft:light_blue_concrete_powder',
|
||||
'minecraft:yellow_concrete_powder',
|
||||
'minecraft:white_concrete_powder',
|
||||
'minecraft:blue_concrete_powder',
|
||||
'minecraft:red_concrete_powder',
|
||||
'minecraft:gray_concrete_powder',
|
||||
'minecraft:pink_concrete_powder',
|
||||
'minecraft:green_concrete_powder',
|
||||
'minecraft:dragon_egg',
|
||||
'minecraft:gravel',
|
||||
'minecraft:pointed_dripstone',
|
||||
'minecraft:red_sand',
|
||||
'minecraft:sand',
|
||||
'minecraft:scaffolding',
|
||||
];
|
||||
|
||||
public readonly TRANSPARENT_BLOCKS = [
|
||||
'minecraft:frosted_ice',
|
||||
'minecraft:glass',
|
||||
'minecraft:white_stained_glass',
|
||||
'minecraft:orange_stained_glass',
|
||||
'minecraft:magenta_stained_glass',
|
||||
'minecraft:light_blue_stained_glass',
|
||||
'minecraft:yellow_stained_glass',
|
||||
'minecraft:lime_stained_glass',
|
||||
'minecraft:pink_stained_glass',
|
||||
'minecraft:gray_stained_glass',
|
||||
'minecraft:light_gray_stained_glass',
|
||||
'minecraft:cyan_stained_glass',
|
||||
'minecraft:purple_stained_glass',
|
||||
'minecraft:blue_stained_glass',
|
||||
'minecraft:brown_stained_glass',
|
||||
'minecraft:green_stained_glass',
|
||||
'minecraft:red_stained_glass',
|
||||
'minecraft:black_stained_glass',
|
||||
'minecraft:ice',
|
||||
'minecraft:oak_leaves',
|
||||
'minecraft:spruce_leaves',
|
||||
'minecraft:birch_leaves',
|
||||
'minecraft:jungle_leaves',
|
||||
'minecraft:acacia_leaves',
|
||||
'minecraft:dark_oak_leaves',
|
||||
'minecraft:mangrove_leaves',
|
||||
'minecraft:azalea_leaves',
|
||||
'minecraft:flowering_azalea_leaves',
|
||||
'minecraft:slime_block',
|
||||
'minecraft:honey_block',
|
||||
];
|
||||
|
||||
public readonly GRASS_LIKE_BLOCKS = [
|
||||
'minecraft:grass_block',
|
||||
'minecraft:grass_path',
|
||||
'minecraft:podzol',
|
||||
'minecraft:crimson_nylium',
|
||||
'minecraft:warped_nylium',
|
||||
'minecraft:mycelium',
|
||||
'minecraft:farmland',
|
||||
];
|
||||
|
||||
public readonly EMISSIVE_BLOCKS = [
|
||||
'minecraft:respawn_anchor',
|
||||
'minecraft:magma_block',
|
||||
'minecraft:sculk_catalyst',
|
||||
'minecraft:crying_obsidian',
|
||||
'minecraft:shroomlight',
|
||||
'minecraft:sea_lantern',
|
||||
'minecraft:jack_o_lantern',
|
||||
'minecraft:glowstone',
|
||||
'minecraft:pearlescent_froglight',
|
||||
'minecraft:verdant_froglight',
|
||||
'minecraft:ochre_froglight',
|
||||
];
|
||||
|
||||
private constructor() {
|
||||
const fallableBlocksString = fs.readFileSync(PathUtil.join(AppPaths.Get.resources, 'fallable_blocks.json'), 'utf-8');
|
||||
this.FALLABLE_BLOCKS = JSON.parse(fallableBlocksString).fallable_blocks;
|
||||
|
||||
const transparentBlocksString = fs.readFileSync(PathUtil.join(AppPaths.Get.resources, 'transparent_blocks.json'), 'utf-8');
|
||||
this.TRANSPARENT_BLOCKS = JSON.parse(transparentBlocksString).transparent_blocks;
|
||||
|
||||
const emissiveBlocksString = fs.readFileSync(PathUtil.join(AppPaths.Get.resources, 'emissive_blocks.json'), 'utf-8');
|
||||
this.EMISSIVE_BLOCKS = JSON.parse(emissiveBlocksString).emissive_blocks;
|
||||
|
||||
const grassLikeBlocksString = fs.readFileSync(PathUtil.join(AppPaths.Get.resources, 'grass_like_blocks.json'), 'utf-8');
|
||||
this.GRASS_LIKE_BLOCKS = JSON.parse(grassLikeBlocksString).grass_like_blocks;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { NBT, TagType } from 'prismarine-nbt';
|
||||
//import { NBT, TagType } from 'prismarine-nbt';
|
||||
|
||||
import { BlockMesh } from '../block_mesh';
|
||||
import { AppConstants } from '../constants';
|
||||
@ -134,11 +134,14 @@ export class Litematic extends IExporter {
|
||||
|
||||
private _createBlockStatePalette(blockMapping: BlockMapping) {
|
||||
const blockStatePalette = Array(Object.keys(blockMapping).length);
|
||||
|
||||
/*
|
||||
for (const blockName of Object.keys(blockMapping)) {
|
||||
const index = blockMapping[blockName];
|
||||
blockStatePalette[index] = { Name: { type: TagType.String, value: blockName } };
|
||||
}
|
||||
blockStatePalette[0] = { Name: { type: TagType.String, value: 'minecraft:air' } };
|
||||
*/
|
||||
|
||||
return blockStatePalette;
|
||||
}
|
||||
@ -151,6 +154,7 @@ export class Litematic extends IExporter {
|
||||
const blockStatePalette = this._createBlockStatePalette(blockMapping);
|
||||
const numBlocks = blockMesh.getBlocks().length;
|
||||
|
||||
/*
|
||||
const nbt: NBT = {
|
||||
type: TagType.Compound,
|
||||
name: 'Litematic',
|
||||
@ -208,6 +212,7 @@ export class Litematic extends IExporter {
|
||||
};
|
||||
|
||||
return nbt;
|
||||
*/
|
||||
}
|
||||
|
||||
getFormatFilter() {
|
||||
@ -230,7 +235,8 @@ export class Litematic extends IExporter {
|
||||
this._sizeVector = Vector3.sub(bounds.max, bounds.min).add(1);
|
||||
|
||||
const nbt = this._convertToNBT(blockMesh);
|
||||
saveNBT(nbt, filePath);
|
||||
// TODO Unimplemented
|
||||
//saveNBT(nbt, filePath);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { NBT, TagType } from 'prismarine-nbt';
|
||||
//import { NBT, TagType } from 'prismarine-nbt';
|
||||
|
||||
import { BlockMesh } from '../block_mesh';
|
||||
import { AppConstants } from '../constants';
|
||||
@ -25,84 +25,86 @@ export class NBTExporter extends IExporter {
|
||||
}
|
||||
|
||||
public override export(blockMesh: BlockMesh, filePath: string): boolean {
|
||||
const bounds = blockMesh.getVoxelMesh().getBounds();
|
||||
const sizeVector = bounds.getDimensions().add(1);
|
||||
|
||||
const isTooBig = sizeVector.x > 48 && sizeVector.y > 48 && sizeVector.z > 48;
|
||||
if (isTooBig) {
|
||||
StatusHandler.Get.add('warning', 'Structure blocks only support structures of size 48x48x48, blocks outside this range will be removed');
|
||||
}
|
||||
|
||||
const blockNameToIndex = new Map<string, number>();
|
||||
const palette: any = [];
|
||||
for (const blockName of blockMesh.getBlockPalette()) {
|
||||
palette.push({
|
||||
Name: {
|
||||
type: TagType.String,
|
||||
value: AppUtil.Text.namespaceBlock(blockName),
|
||||
},
|
||||
});
|
||||
blockNameToIndex.set(blockName, palette.length - 1);
|
||||
}
|
||||
|
||||
const blocks: any = [];
|
||||
for (const block of blockMesh.getBlocks()) {
|
||||
const pos = block.voxel.position;
|
||||
const blockIndex = blockNameToIndex.get(block.blockInfo.name);
|
||||
if (blockIndex) {
|
||||
if (pos.x > -24 && pos.x <= 24 && pos.y > -24 && pos.y <= 24 && pos.z > -24 && pos.z <= 24) {
|
||||
blocks.push({
|
||||
pos: {
|
||||
type: TagType.List,
|
||||
value: {
|
||||
type: TagType.Int,
|
||||
value: Vector3.sub(block.voxel.position, bounds.min).toArray(),
|
||||
},
|
||||
},
|
||||
state: {
|
||||
type: TagType.Int,
|
||||
value: blockIndex,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const nbt: NBT = {
|
||||
type: TagType.Compound,
|
||||
name: 'SchematicBlocks',
|
||||
value: {
|
||||
DataVersion: {
|
||||
type: TagType.Int,
|
||||
value: AppConstants.DATA_VERSION,
|
||||
},
|
||||
size: {
|
||||
type: TagType.List,
|
||||
value: {
|
||||
type: TagType.Int,
|
||||
value: sizeVector.toArray(),
|
||||
},
|
||||
},
|
||||
palette: {
|
||||
type: TagType.List,
|
||||
value: {
|
||||
type: TagType.Compound,
|
||||
value: palette,
|
||||
},
|
||||
},
|
||||
blocks: {
|
||||
type: TagType.List,
|
||||
value: {
|
||||
type: TagType.Compound,
|
||||
value: blocks,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
saveNBT(nbt, filePath);
|
||||
|
||||
// TODO Unimplemented
|
||||
return false;
|
||||
// const bounds = blockMesh.getVoxelMesh().getBounds();
|
||||
// const sizeVector = bounds.getDimensions().add(1);
|
||||
|
||||
// const isTooBig = sizeVector.x > 48 && sizeVector.y > 48 && sizeVector.z > 48;
|
||||
// if (isTooBig) {
|
||||
// StatusHandler.Get.add('warning', 'Structure blocks only support structures of size 48x48x48, blocks outside this range will be removed');
|
||||
// }
|
||||
|
||||
// const blockNameToIndex = new Map<string, number>();
|
||||
// const palette: any = [];
|
||||
// for (const blockName of blockMesh.getBlockPalette()) {
|
||||
// palette.push({
|
||||
// Name: {
|
||||
// type: TagType.String,
|
||||
// value: AppUtil.Text.namespaceBlock(blockName),
|
||||
// },
|
||||
// });
|
||||
// blockNameToIndex.set(blockName, palette.length - 1);
|
||||
// }
|
||||
|
||||
// const blocks: any = [];
|
||||
// for (const block of blockMesh.getBlocks()) {
|
||||
// const pos = block.voxel.position;
|
||||
// const blockIndex = blockNameToIndex.get(block.blockInfo.name);
|
||||
// if (blockIndex) {
|
||||
// if (pos.x > -24 && pos.x <= 24 && pos.y > -24 && pos.y <= 24 && pos.z > -24 && pos.z <= 24) {
|
||||
// blocks.push({
|
||||
// pos: {
|
||||
// type: TagType.List,
|
||||
// value: {
|
||||
// type: TagType.Int,
|
||||
// value: Vector3.sub(block.voxel.position, bounds.min).toArray(),
|
||||
// },
|
||||
// },
|
||||
// state: {
|
||||
// type: TagType.Int,
|
||||
// value: blockIndex,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// const nbt: NBT = {
|
||||
// type: TagType.Compound,
|
||||
// name: 'SchematicBlocks',
|
||||
// value: {
|
||||
// DataVersion: {
|
||||
// type: TagType.Int,
|
||||
// value: AppConstants.DATA_VERSION,
|
||||
// },
|
||||
// size: {
|
||||
// type: TagType.List,
|
||||
// value: {
|
||||
// type: TagType.Int,
|
||||
// value: sizeVector.toArray(),
|
||||
// },
|
||||
// },
|
||||
// palette: {
|
||||
// type: TagType.List,
|
||||
// value: {
|
||||
// type: TagType.Compound,
|
||||
// value: palette,
|
||||
// },
|
||||
// },
|
||||
// blocks: {
|
||||
// type: TagType.List,
|
||||
// value: {
|
||||
// type: TagType.Compound,
|
||||
// value: blocks,
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// };
|
||||
|
||||
// saveNBT(nbt, filePath);
|
||||
|
||||
// return false;
|
||||
}
|
||||
|
||||
private static _getBufferIndex(dimensions: Vector3, vec: Vector3) {
|
||||
|
@ -1,4 +1,3 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
import { BlockMesh } from '../block_mesh';
|
||||
@ -7,7 +6,7 @@ import { ASSERT } from '../util/error_util';
|
||||
import { IExporter } from './base_exporter';
|
||||
|
||||
export class ObjExporter extends IExporter {
|
||||
public override getFormatFilter(): Electron.FileFilter {
|
||||
public override getFormatFilter() {
|
||||
return {
|
||||
name: 'Wavefront Obj',
|
||||
extensions: ['obj'],
|
||||
@ -85,20 +84,22 @@ export class ObjExporter extends IExporter {
|
||||
buffers.forEach(({ buffer }) => {
|
||||
positionData.set(buffer.position.data, positionIndex);
|
||||
positionIndex += buffer.position.data.length;
|
||||
|
||||
|
||||
normalData.set(buffer.normal.data, normalIndex);
|
||||
normalIndex += buffer.normal.data.length;
|
||||
|
||||
|
||||
texcoordData.set(buffer.texcoord.data, texcoordIndex);
|
||||
texcoordIndex += buffer.texcoord.data.length;
|
||||
|
||||
|
||||
blockTexcoordData.set(buffer.blockTexcoord.data, blockTexcoordIndex);
|
||||
blockTexcoordIndex += buffer.blockTexcoord.data.length;
|
||||
|
||||
|
||||
indexData.set(buffer.indices.data, indicesIndex);
|
||||
indicesIndex += buffer.indices.data.length;
|
||||
});
|
||||
|
||||
// TODO Unimplemented
|
||||
/*
|
||||
const file = fs.openSync(filepath, 'w');
|
||||
fs.writeSync(file, '# Created with ObjToSchematic\n');
|
||||
fs.writeSync(file, '# https://github.com/LucasDower/ObjToSchematic/\n\n');
|
||||
@ -136,9 +137,12 @@ export class ObjExporter extends IExporter {
|
||||
}
|
||||
|
||||
fs.closeSync(file);
|
||||
*/
|
||||
}
|
||||
|
||||
private _exportMTL(filepathMTL: string, filepathTexture: string, blockMesh: BlockMesh) {
|
||||
// TODO Unimplemented
|
||||
/*
|
||||
ASSERT(path.isAbsolute(filepathMTL));
|
||||
ASSERT(path.isAbsolute(filepathTexture));
|
||||
|
||||
@ -157,5 +161,6 @@ export class ObjExporter extends IExporter {
|
||||
// Export texture
|
||||
const filepathAtlasTexture = blockMesh.getAtlas().getAtlasTexturePath();
|
||||
fs.copyFileSync(filepathAtlasTexture, filepathTexture);
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { NBT, TagType } from 'prismarine-nbt';
|
||||
//import { NBT, TagType } from 'prismarine-nbt';
|
||||
|
||||
import { BlockMesh } from '../block_mesh';
|
||||
import { AppConstants } from '../constants';
|
||||
@ -28,66 +28,68 @@ export class SchemExporter extends IExporter {
|
||||
private static SCHEMA_VERSION = 2;
|
||||
|
||||
public override export(blockMesh: BlockMesh, filePath: string): boolean {
|
||||
const bounds = blockMesh.getVoxelMesh().getBounds();
|
||||
const sizeVector = bounds.getDimensions().add(1);
|
||||
|
||||
// https://github.com/SpongePowered/Schematic-Specification/blob/master/versions/schematic-3.md#paletteObject
|
||||
// const blockMapping: BlockMapping = {};
|
||||
const blockMapping: {[name: string]: { type: TagType, value: any }} = {
|
||||
'minecraft:air': { type: TagType.Int, value: 0 },
|
||||
};
|
||||
|
||||
let blockIndex = 1;
|
||||
for (const blockName of blockMesh.getBlockPalette()) {
|
||||
const namespacedBlockName = AppUtil.Text.namespaceBlock(blockName);
|
||||
|
||||
blockMapping[namespacedBlockName] = { type: TagType.Int, value: blockIndex };
|
||||
++blockIndex;
|
||||
}
|
||||
LOG(blockMapping);
|
||||
|
||||
// const paletteObject = SchemExporter._createBlockStatePalette(blockMapping);
|
||||
const blockData = new Array<number>(sizeVector.x * sizeVector.y * sizeVector.z).fill(0);
|
||||
for (const block of blockMesh.getBlocks()) {
|
||||
const indexVector = Vector3.sub(block.voxel.position, bounds.min);
|
||||
const bufferIndex = SchemExporter._getBufferIndex(sizeVector, indexVector);
|
||||
const namespacedBlockName = AppUtil.Text.namespaceBlock(block.blockInfo.name);
|
||||
blockData[bufferIndex] = blockMapping[namespacedBlockName].value;
|
||||
}
|
||||
|
||||
const blockEncoding: number[] = [];
|
||||
for (let i = 0; i < blockData.length; ++i) {
|
||||
let id = blockData[i];
|
||||
|
||||
while ((id & -128) != 0) {
|
||||
blockEncoding.push(id & 127 | 128);
|
||||
id >>>= 7;
|
||||
}
|
||||
blockEncoding.push(id);
|
||||
}
|
||||
|
||||
for (let i = 0; i < blockEncoding.length; ++i) {
|
||||
blockEncoding[i] = MathUtil.int8(blockEncoding[i]);
|
||||
}
|
||||
|
||||
const nbt: NBT = {
|
||||
type: TagType.Compound,
|
||||
name: 'Schematic',
|
||||
value: {
|
||||
Version: { type: TagType.Int, value: SchemExporter.SCHEMA_VERSION },
|
||||
DataVersion: { type: TagType.Int, value: AppConstants.DATA_VERSION },
|
||||
Width: { type: TagType.Short, value: sizeVector.x },
|
||||
Height: { type: TagType.Short, value: sizeVector.y },
|
||||
Length: { type: TagType.Short, value: sizeVector.z },
|
||||
PaletteMax: { type: TagType.Int, value: blockIndex },
|
||||
Palette: { type: TagType.Compound, value: blockMapping },
|
||||
BlockData: { type: TagType.ByteArray, value: blockEncoding },
|
||||
},
|
||||
};
|
||||
|
||||
saveNBT(nbt, filePath);
|
||||
|
||||
// TODO Unimplemented
|
||||
return false;
|
||||
// const bounds = blockMesh.getVoxelMesh().getBounds();
|
||||
// const sizeVector = bounds.getDimensions().add(1);
|
||||
|
||||
// // https://github.com/SpongePowered/Schematic-Specification/blob/master/versions/schematic-3.md#paletteObject
|
||||
// // const blockMapping: BlockMapping = {};
|
||||
// const blockMapping: {[name: string]: { type: TagType, value: any }} = {
|
||||
// 'minecraft:air': { type: TagType.Int, value: 0 },
|
||||
// };
|
||||
|
||||
// let blockIndex = 1;
|
||||
// for (const blockName of blockMesh.getBlockPalette()) {
|
||||
// const namespacedBlockName = AppUtil.Text.namespaceBlock(blockName);
|
||||
|
||||
// blockMapping[namespacedBlockName] = { type: TagType.Int, value: blockIndex };
|
||||
// ++blockIndex;
|
||||
// }
|
||||
// LOG(blockMapping);
|
||||
|
||||
// // const paletteObject = SchemExporter._createBlockStatePalette(blockMapping);
|
||||
// const blockData = new Array<number>(sizeVector.x * sizeVector.y * sizeVector.z).fill(0);
|
||||
// for (const block of blockMesh.getBlocks()) {
|
||||
// const indexVector = Vector3.sub(block.voxel.position, bounds.min);
|
||||
// const bufferIndex = SchemExporter._getBufferIndex(sizeVector, indexVector);
|
||||
// const namespacedBlockName = AppUtil.Text.namespaceBlock(block.blockInfo.name);
|
||||
// blockData[bufferIndex] = blockMapping[namespacedBlockName].value;
|
||||
// }
|
||||
|
||||
// const blockEncoding: number[] = [];
|
||||
// for (let i = 0; i < blockData.length; ++i) {
|
||||
// let id = blockData[i];
|
||||
|
||||
// while ((id & -128) != 0) {
|
||||
// blockEncoding.push(id & 127 | 128);
|
||||
// id >>>= 7;
|
||||
// }
|
||||
// blockEncoding.push(id);
|
||||
// }
|
||||
|
||||
// for (let i = 0; i < blockEncoding.length; ++i) {
|
||||
// blockEncoding[i] = MathUtil.int8(blockEncoding[i]);
|
||||
// }
|
||||
|
||||
// const nbt: NBT = {
|
||||
// type: TagType.Compound,
|
||||
// name: 'Schematic',
|
||||
// value: {
|
||||
// Version: { type: TagType.Int, value: SchemExporter.SCHEMA_VERSION },
|
||||
// DataVersion: { type: TagType.Int, value: AppConstants.DATA_VERSION },
|
||||
// Width: { type: TagType.Short, value: sizeVector.x },
|
||||
// Height: { type: TagType.Short, value: sizeVector.y },
|
||||
// Length: { type: TagType.Short, value: sizeVector.z },
|
||||
// PaletteMax: { type: TagType.Int, value: blockIndex },
|
||||
// Palette: { type: TagType.Compound, value: blockMapping },
|
||||
// BlockData: { type: TagType.ByteArray, value: blockEncoding },
|
||||
// },
|
||||
// };
|
||||
|
||||
// saveNBT(nbt, filePath);
|
||||
|
||||
// return false;
|
||||
}
|
||||
|
||||
private static _getBufferIndex(dimensions: Vector3, vec: Vector3) {
|
||||
|
@ -1,5 +1,4 @@
|
||||
import fs from 'fs';
|
||||
import { NBT, TagType } from 'prismarine-nbt';
|
||||
//import { NBT, TagType } from 'prismarine-nbt';
|
||||
|
||||
import { BlockMesh } from '../block_mesh';
|
||||
import { StatusHandler, StatusID } from '../status';
|
||||
@ -17,9 +16,13 @@ export class Schematic extends IExporter {
|
||||
const metaData = Array<number>(bufferSize);
|
||||
const bounds = blockMesh.getVoxelMesh().getBounds();
|
||||
|
||||
// TODO Unimplemented
|
||||
const schematicBlocks: { [blockName: string]: { id: number, meta: number, name: string } } = {};
|
||||
/*
|
||||
const schematicBlocks: { [blockName: string]: { id: number, meta: number, name: string } } = JSON.parse(
|
||||
fs.readFileSync(PathUtil.join(AppPaths.Get.resources, './block_ids.json'), 'utf8'),
|
||||
);
|
||||
*/
|
||||
|
||||
const blocks = blockMesh.getBlocks();
|
||||
const unsupportedBlocks = new Set<string>();
|
||||
@ -48,6 +51,8 @@ export class Schematic extends IExporter {
|
||||
LOG_WARN(unsupportedBlocks);
|
||||
}
|
||||
|
||||
// TODO Unimplemented
|
||||
/*
|
||||
const nbt: NBT = {
|
||||
type: TagType.Compound,
|
||||
name: 'Schematic',
|
||||
@ -64,6 +69,7 @@ export class Schematic extends IExporter {
|
||||
};
|
||||
|
||||
return nbt;
|
||||
*/
|
||||
}
|
||||
|
||||
_getBufferIndex(vec: Vector3, sizeVector: Vector3) {
|
||||
@ -90,7 +96,8 @@ export class Schematic extends IExporter {
|
||||
this._sizeVector = Vector3.sub(bounds.max, bounds.min).add(1);
|
||||
|
||||
const nbt = this._convertToNBT(blockMesh);
|
||||
saveNBT(nbt, filePath);
|
||||
// TODO Unimplemented
|
||||
//saveNBT(nbt, filePath);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
3
src/global.d.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
declare module '*.vs';
|
||||
|
||||
declare module '*.fs';
|
@ -1,4 +1,3 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
import { RGBA, RGBAColours } from '../colour';
|
||||
@ -311,6 +310,8 @@ export class ObjImporter extends IImporter {
|
||||
}
|
||||
|
||||
private _parseOBJ(path: string) {
|
||||
// TODO Unimplemented
|
||||
/*
|
||||
if (path === '') {
|
||||
throw new AppError(`No filepath given`);
|
||||
}
|
||||
@ -328,6 +329,7 @@ export class ObjImporter extends IImporter {
|
||||
for (const line of fileLines) {
|
||||
this.parseOBJLine(line);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
public parseOBJLine(line: string) {
|
||||
@ -357,6 +359,8 @@ export class ObjImporter extends IImporter {
|
||||
}
|
||||
|
||||
private _parseMTL() {
|
||||
//TODO Unimplemented
|
||||
/*
|
||||
for (const mtlLib of this._mtlLibs) {
|
||||
if (!fs.existsSync(mtlLib)) {
|
||||
StatusHandler.Get.add('warning', `Could not find ${mtlLib}`);
|
||||
@ -373,6 +377,7 @@ export class ObjImporter extends IImporter {
|
||||
|
||||
this._addCurrentMaterial();
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
private _parseMTLLine(line: string) {
|
||||
|
198
src/main.ts
@ -1,118 +1,118 @@
|
||||
|
||||
/**
|
||||
,d
|
||||
88
|
||||
,adPPYba, MM88MMM ,adPPYba, 8b,dPPYba,
|
||||
I8[ "" 88 a8" "8a 88P' "8a
|
||||
`"Y8ba, 88 8b d8 88 d8
|
||||
aa ]8I 88, "8a, ,a8" 88b, ,a8"
|
||||
`"YbbdP"' "Y888 `"YbbdP"' 88`YbbdP"'
|
||||
88
|
||||
88
|
||||
// /**
|
||||
// ,d
|
||||
// 88
|
||||
// ,adPPYba, MM88MMM ,adPPYba, 8b,dPPYba,
|
||||
// I8[ "" 88 a8" "8a 88P' "8a
|
||||
// `"Y8ba, 88 8b d8 88 d8
|
||||
// aa ]8I 88, "8a, ,a8" 88b, ,a8"
|
||||
// `"YbbdP"' "Y888 `"YbbdP"' 88`YbbdP"'
|
||||
// 88
|
||||
// 88
|
||||
|
||||
If you're interested in the code, I recommend starting in /src/AppContext.ts
|
||||
The stuff here is boring Electron boilerplate \(•◡•)/
|
||||
*/
|
||||
// If you're interested in the code, I recommend starting in /src/AppContext.ts
|
||||
// The stuff here is boring Electron boilerplate \(•◡•)/
|
||||
// */
|
||||
|
||||
import { app, BrowserWindow } from 'electron';
|
||||
import url from 'url';
|
||||
// import { app, BrowserWindow } from 'electron';
|
||||
// import url from 'url';
|
||||
|
||||
import { AppConfig } from './config';
|
||||
import { AppPaths, PathUtil } from './util/path_util';
|
||||
// import { AppConfig } from './config';
|
||||
// import { AppPaths, PathUtil } from './util/path_util';
|
||||
|
||||
app.commandLine.appendSwitch('js-flags', `--max-old-space-size=${AppConfig.Get.OLD_SPACE_SIZE_MB}`);
|
||||
// app.commandLine.appendSwitch('js-flags', `--max-old-space-size=${AppConfig.Get.OLD_SPACE_SIZE_MB}`);
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let mainWindow: BrowserWindow;
|
||||
// // Keep a global reference of the window object, if you don't, the window will
|
||||
// // be closed automatically when the JavaScript object is garbage collected.
|
||||
// let mainWindow: BrowserWindow;
|
||||
|
||||
function createWindow() {
|
||||
// Create the browser window.
|
||||
// const {width, height} = electron.screen.getPrimaryDisplay().workAreaSize;
|
||||
const width = 1400;
|
||||
const height = 800;
|
||||
// function createWindow() {
|
||||
// // Create the browser window.
|
||||
// // const {width, height} = electron.screen.getPrimaryDisplay().workAreaSize;
|
||||
// const width = 1400;
|
||||
// const height = 800;
|
||||
|
||||
// Create list of args to pass from main process to render process
|
||||
const additionalArgs = [];
|
||||
if (process.argv.includes('--OTS-ENABLE-DEBUG')) {
|
||||
additionalArgs.push('--OTS-ENABLE-DEBUG');
|
||||
}
|
||||
// // Create list of args to pass from main process to render process
|
||||
// const additionalArgs = [];
|
||||
// if (process.argv.includes('--OTS-ENABLE-DEBUG')) {
|
||||
// additionalArgs.push('--OTS-ENABLE-DEBUG');
|
||||
// }
|
||||
|
||||
// const appIcon = new Tray("../resources/icon.png");
|
||||
mainWindow = new BrowserWindow({
|
||||
width: width,
|
||||
height: height,
|
||||
icon: PathUtil.join(AppPaths.Get.static, process.platform === 'win32' ? './icon.ico' : './icon.png'),
|
||||
minWidth: 1280,
|
||||
minHeight: 720,
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
nodeIntegrationInWorker: true,
|
||||
contextIsolation: false,
|
||||
enableRemoteModule: true,
|
||||
additionalArguments: additionalArgs,
|
||||
},
|
||||
});
|
||||
if (AppConfig.Get.RELEASE_MODE) {
|
||||
mainWindow.removeMenu();
|
||||
}
|
||||
// // const appIcon = new Tray("../resources/icon.png");
|
||||
// mainWindow = new BrowserWindow({
|
||||
// width: width,
|
||||
// height: height,
|
||||
// icon: PathUtil.join(AppPaths.Get.static, process.platform === 'win32' ? './icon.ico' : './icon.png'),
|
||||
// minWidth: 1280,
|
||||
// minHeight: 720,
|
||||
// webPreferences: {
|
||||
// nodeIntegration: true,
|
||||
// nodeIntegrationInWorker: true,
|
||||
// contextIsolation: false,
|
||||
// enableRemoteModule: true,
|
||||
// additionalArguments: additionalArgs,
|
||||
// },
|
||||
// });
|
||||
// if (AppConfig.Get.RELEASE_MODE) {
|
||||
// mainWindow.removeMenu();
|
||||
// }
|
||||
|
||||
// Load index.html
|
||||
mainWindow.loadURL(url.format({
|
||||
pathname: PathUtil.join(AppPaths.Get.base, './index.html'),
|
||||
protocol: 'file:',
|
||||
slashes: true,
|
||||
}));
|
||||
// // Load index.html
|
||||
// mainWindow.loadURL(url.format({
|
||||
// pathname: PathUtil.join(AppPaths.Get.base, './index.html'),
|
||||
// protocol: 'file:',
|
||||
// slashes: true,
|
||||
// }));
|
||||
|
||||
const baseTitle = 'ObjToSchematic – Convert 3D models into Minecraft builds';
|
||||
if (AppConfig.Get.RELEASE_MODE) {
|
||||
mainWindow.setTitle(`${baseTitle} (${AppConfig.Get.RELEASE_VERSION})`);
|
||||
} else {
|
||||
try {
|
||||
const branchName: Buffer = require('child_process')
|
||||
.execSync('git rev-parse --abbrev-ref HEAD')
|
||||
.toString()
|
||||
.replace('\n', '');
|
||||
// const baseTitle = 'ObjToSchematic – Convert 3D models into Minecraft builds';
|
||||
// if (AppConfig.Get.RELEASE_MODE) {
|
||||
// mainWindow.setTitle(`${baseTitle} (${AppConfig.Get.RELEASE_VERSION})`);
|
||||
// } else {
|
||||
// try {
|
||||
// const branchName: Buffer = require('child_process')
|
||||
// .execSync('git rev-parse --abbrev-ref HEAD')
|
||||
// .toString()
|
||||
// .replace('\n', '');
|
||||
|
||||
const commitHash: (string | Buffer) = require('child_process')
|
||||
.execSync('git rev-parse --short HEAD')
|
||||
.toString()
|
||||
.replace('\n', '');
|
||||
// const commitHash: (string | Buffer) = require('child_process')
|
||||
// .execSync('git rev-parse --short HEAD')
|
||||
// .toString()
|
||||
// .replace('\n', '');
|
||||
|
||||
mainWindow.setTitle(`${baseTitle} (git ${branchName.toString()} ${commitHash.toString().trim()})`);
|
||||
} catch (e: any) {
|
||||
mainWindow.setTitle(`${baseTitle} (git)`);
|
||||
}
|
||||
}
|
||||
// mainWindow.setTitle(`${baseTitle} (git ${branchName.toString()} ${commitHash.toString().trim()})`);
|
||||
// } catch (e: any) {
|
||||
// mainWindow.setTitle(`${baseTitle} (git)`);
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// Open the DevTools.
|
||||
// mainWindow.webContents.openDevTools();
|
||||
// // Open the DevTools.
|
||||
// // mainWindow.webContents.openDevTools();
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on('closed', function () {
|
||||
app.quit();
|
||||
});
|
||||
}
|
||||
// // Emitted when the window is closed.
|
||||
// mainWindow.on('closed', function () {
|
||||
// app.quit();
|
||||
// });
|
||||
// }
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.on('ready', createWindow);
|
||||
// // This method will be called when Electron has finished
|
||||
// // initialization and is ready to create browser windows.
|
||||
// // Some APIs can only be used after this event occurs.
|
||||
// app.on('ready', createWindow);
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On OS X it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit();
|
||||
}
|
||||
});
|
||||
// // Quit when all windows are closed.
|
||||
// app.on('window-all-closed', function () {
|
||||
// // On OS X it is common for applications and their menu bar
|
||||
// // to stay active until the user quits explicitly with Cmd + Q
|
||||
// if (process.platform !== 'darwin') {
|
||||
// app.quit();
|
||||
// }
|
||||
// });
|
||||
|
||||
app.on('activate', function () {
|
||||
// On OS X it's common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow();
|
||||
}
|
||||
});
|
||||
// app.on('activate', function () {
|
||||
// // On OS X it's common to re-create a window in the app when the
|
||||
// // dock icon is clicked and there are no other windows open.
|
||||
// if (mainWindow === null) {
|
||||
// createWindow();
|
||||
// }
|
||||
// });
|
||||
|
@ -1,4 +1,3 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
import { Bounds } from './bounds';
|
||||
@ -246,6 +245,8 @@ export class Mesh {
|
||||
|
||||
// Check texture paths are absolute and exist
|
||||
this._materials.forEach((material, materialName) => {
|
||||
// TODO Unimplemented
|
||||
/*
|
||||
if (material.type === MaterialType.textured) {
|
||||
ASSERT(path.isAbsolute(material.path), 'Material texture path not absolute');
|
||||
if (!fs.existsSync(material.path)) {
|
||||
@ -263,6 +264,7 @@ export class Mesh {
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
});
|
||||
|
||||
// Deduce default texture wrap mode for each material type
|
||||
|
@ -1,4 +1,3 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
import { Atlas } from './atlas';
|
||||
@ -12,6 +11,8 @@ export class PaletteManager {
|
||||
public static getPalettesInfo(): { paletteID: string, paletteDisplayName: string }[] {
|
||||
const palettes: { paletteID: string, paletteDisplayName: string }[] = [];
|
||||
|
||||
// TODO Unimplemented
|
||||
/*
|
||||
fs.readdirSync(AppPaths.Get.palettes).forEach((file) => {
|
||||
const paletteFilePath = path.parse(file);
|
||||
if (paletteFilePath.ext === Palette.PALETTE_FILE_EXT) {
|
||||
@ -23,6 +24,7 @@ export class PaletteManager {
|
||||
palettes.push({ paletteID: paletteID, paletteDisplayName: paletteDisplayName });
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
return palettes;
|
||||
}
|
||||
@ -44,6 +46,9 @@ export class Palette {
|
||||
}
|
||||
|
||||
public static load(paletteName: string): TOptional<Palette> {
|
||||
// TODO Unimplemented
|
||||
return undefined;
|
||||
/*
|
||||
if (!Palette._isValidPaletteName(paletteName)) {
|
||||
return;
|
||||
}
|
||||
@ -74,9 +79,13 @@ export class Palette {
|
||||
}
|
||||
|
||||
return palette;
|
||||
*/
|
||||
}
|
||||
|
||||
public save(paletteName: string): boolean {
|
||||
// TODO Unimplemented
|
||||
return false;
|
||||
/*
|
||||
if (!Palette._isValidPaletteName(paletteName)) {
|
||||
return false;
|
||||
}
|
||||
@ -93,6 +102,7 @@ export class Palette {
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
public add(blockName: AppTypes.TNamespacedBlockName): void {
|
||||
|
@ -1,8 +1,16 @@
|
||||
import * as fs from 'fs';
|
||||
import * as twgl from 'twgl.js';
|
||||
|
||||
import FRAG_BLOCK from '../res/shaders/block_fragment.fs';
|
||||
import VERT_BLOCK from '../res/shaders/block_vertex.vs';
|
||||
import FRAG_DEBUG from '../res/shaders/debug_fragment.fs';
|
||||
import VERT_DEBUG from '../res/shaders/debug_vertex.vs';
|
||||
import FRAG_TRI_SOLID from '../res/shaders/solid_tri_fragment.fs';
|
||||
import VERT_TRI_SOLID from '../res/shaders/solid_tri_vertex.vs';
|
||||
import FRAG_TRI_TEXTURE from '../res/shaders/texture_tri_fragment.fs';
|
||||
import VERT_TRI_TEXTURE from '../res/shaders/texture_tri_vertex.vs';
|
||||
import FRAG_VOXEL from '../res/shaders/voxel_fragment.fs';
|
||||
import VERT_VOXEL from '../res/shaders/voxel_vertex.vs';
|
||||
import { Renderer } from './renderer';
|
||||
import { AppPaths, PathUtil } from './util/path_util';
|
||||
|
||||
export class ShaderManager {
|
||||
public readonly textureTriProgram: twgl.ProgramInfo;
|
||||
@ -19,29 +27,14 @@ export class ShaderManager {
|
||||
private constructor() {
|
||||
const gl = Renderer.Get._gl;
|
||||
|
||||
const textureTriVertex = this._getShader('texture_tri_vertex.vs');
|
||||
const textureTriFragment = this._getShader('texture_tri_fragment.fs');
|
||||
this.textureTriProgram = twgl.createProgramInfo(gl, [textureTriVertex, textureTriFragment]);
|
||||
this.textureTriProgram = twgl.createProgramInfo(gl, [VERT_TRI_TEXTURE, FRAG_TRI_TEXTURE]);
|
||||
|
||||
const solidTriVertex = this._getShader('solid_tri_vertex.vs');
|
||||
const solidTriFragment = this._getShader('solid_tri_fragment.fs');
|
||||
this.solidTriProgram = twgl.createProgramInfo(gl, [solidTriVertex, solidTriFragment]);
|
||||
this.solidTriProgram = twgl.createProgramInfo(gl, [VERT_TRI_SOLID, FRAG_TRI_SOLID]);
|
||||
|
||||
const voxelVertexShader = this._getShader('voxel_vertex.vs');
|
||||
const voxelFragmentShader = this._getShader('voxel_fragment.fs');
|
||||
this.voxelProgram = twgl.createProgramInfo(gl, [voxelVertexShader, voxelFragmentShader]);
|
||||
this.voxelProgram = twgl.createProgramInfo(gl, [VERT_VOXEL, FRAG_VOXEL]);
|
||||
|
||||
const blockVertexShader = this._getShader('block_vertex.vs');
|
||||
const blockFragmentShader = this._getShader('block_fragment.fs');
|
||||
this.blockProgram = twgl.createProgramInfo(gl, [blockVertexShader, blockFragmentShader]);
|
||||
this.blockProgram = twgl.createProgramInfo(gl, [VERT_BLOCK, FRAG_BLOCK]);
|
||||
|
||||
const debugVertexShader = this._getShader('debug_vertex.vs');
|
||||
const debugFragmentShader = this._getShader('debug_fragment.fs');
|
||||
this.debugProgram = twgl.createProgramInfo(gl, [debugVertexShader, debugFragmentShader]);
|
||||
}
|
||||
|
||||
private _getShader(filename: string) {
|
||||
const absPath = PathUtil.join(AppPaths.Get.shaders, filename);
|
||||
return fs.readFileSync(absPath, 'utf8');
|
||||
this.debugProgram = twgl.createProgramInfo(gl, [VERT_DEBUG, FRAG_DEBUG]);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
import * as fs from 'fs';
|
||||
import * as jpeg from 'jpeg-js';
|
||||
import path from 'path';
|
||||
import { PNG } from 'pngjs';
|
||||
const TGA = require('tga');
|
||||
|
||||
import { RGBA, RGBAColours, RGBAUtil } from './colour';
|
||||
@ -9,7 +7,6 @@ import { AppConfig } from './config';
|
||||
import { clamp } from './math';
|
||||
import { UV } from './util';
|
||||
import { AppError, ASSERT } from './util/error_util';
|
||||
import { FileUtil } from './util/file_util';
|
||||
import { LOG, LOG_ERROR, LOGF } from './util/log_util';
|
||||
import { AppPaths } from './util/path_util';
|
||||
import { TTexelExtension, TTexelInterpolation } from './util/type_util';
|
||||
@ -68,40 +65,47 @@ export class Texture {
|
||||
}
|
||||
|
||||
private _loadImageFile(filename: string): ImageData {
|
||||
ASSERT(path.isAbsolute(filename));
|
||||
const filePath = path.parse(filename);
|
||||
try {
|
||||
const data = fs.readFileSync(filename);
|
||||
// TODO Unimplemented
|
||||
return {
|
||||
width: 0,
|
||||
height: 0,
|
||||
data: new Buffer(0),
|
||||
};
|
||||
// ASSERT(path.isAbsolute(filename));
|
||||
// const filePath = path.parse(filename);
|
||||
// try {
|
||||
// const data = fs.readFileSync(filename);
|
||||
|
||||
switch (filePath.ext.toLowerCase()) {
|
||||
case '.png': {
|
||||
return PNG.sync.read(data);
|
||||
}
|
||||
case '.jpg':
|
||||
case '.jpeg': {
|
||||
this._useAlphaChannelValue = false;
|
||||
return jpeg.decode(data, {
|
||||
maxMemoryUsageInMB: AppConfig.Get.MAXIMUM_IMAGE_MEM_ALLOC,
|
||||
formatAsRGBA: true,
|
||||
});
|
||||
}
|
||||
/*
|
||||
case '.tga': {
|
||||
const tga = new TGA(data);
|
||||
return {
|
||||
width: tga.width,
|
||||
height: tga.height,
|
||||
data: tga.pixels,
|
||||
};
|
||||
}
|
||||
*/
|
||||
default:
|
||||
ASSERT(false, 'Unsupported image format');
|
||||
}
|
||||
} catch (err) {
|
||||
LOG_ERROR(err);
|
||||
throw new AppError(`Could not read ${filename}`);
|
||||
}
|
||||
// switch (filePath.ext.toLowerCase()) {
|
||||
// case '.png': {
|
||||
// ASSERT(false); // TODO Unimplemented
|
||||
// //return PNG.sync.read(data);
|
||||
// }
|
||||
// case '.jpg':
|
||||
// case '.jpeg': {
|
||||
// this._useAlphaChannelValue = false;
|
||||
// return jpeg.decode(data, {
|
||||
// maxMemoryUsageInMB: AppConfig.Get.MAXIMUM_IMAGE_MEM_ALLOC,
|
||||
// formatAsRGBA: true,
|
||||
// });
|
||||
// }
|
||||
// /*
|
||||
// case '.tga': {
|
||||
// const tga = new TGA(data);
|
||||
// return {
|
||||
// width: tga.width,
|
||||
// height: tga.height,
|
||||
// data: tga.pixels,
|
||||
// };
|
||||
// }
|
||||
// */
|
||||
// default:
|
||||
// ASSERT(false, 'Unsupported image format');
|
||||
// }
|
||||
// } catch (err) {
|
||||
// LOG_ERROR(err);
|
||||
// throw new AppError(`Could not read ${filename}`);
|
||||
// }
|
||||
}
|
||||
|
||||
private _correctTexcoord(a: number) {
|
||||
@ -128,7 +132,7 @@ export class Texture {
|
||||
ASSERT(uv.u >= 0.0 && uv.u <= 1.0, 'Texcoord UV.u OOB');
|
||||
ASSERT(uv.v >= 0.0 && uv.v <= 1.0, 'Texcoord UV.v OOB');
|
||||
uv.v = 1.0 - uv.v;
|
||||
|
||||
|
||||
const diffuse = (interpolation === 'nearest') ?
|
||||
this._getNearestRGBA(this._image, uv) :
|
||||
this._getLinearRGBA(this._image, uv);
|
||||
@ -235,6 +239,9 @@ export class Texture {
|
||||
|
||||
export class TextureConverter {
|
||||
public static createPNGfromTGA(filepath: string): string {
|
||||
// TODO Unimplemented;
|
||||
return '';
|
||||
/*
|
||||
ASSERT(fs.existsSync(filepath), '.tga does not exist');
|
||||
const parsed = path.parse(filepath);
|
||||
ASSERT(parsed.ext === '.tga');
|
||||
@ -251,5 +258,6 @@ export class TextureConverter {
|
||||
LOGF(`Creating new generated texture of '${filepath}' at '${newTexturePath}'`);
|
||||
fs.writeFileSync(newTexturePath, buffer);
|
||||
return newTexturePath;
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ export class ComboBoxElement<T> extends ConfigUIElement<T, HTMLSelectElement> {
|
||||
*/
|
||||
|
||||
public override _generateInnerHTML() {
|
||||
ASSERT(this._items.length > 0);
|
||||
//ASSERT(this._items.length > 0);
|
||||
|
||||
let itemsHTML = '';
|
||||
for (const item of this._items) {
|
||||
@ -85,7 +85,7 @@ export class ComboBoxElement<T> extends ConfigUIElement<T, HTMLSelectElement> {
|
||||
const selectedIndex = this._items.findIndex((item) => item.payload === this.getValue());
|
||||
const element = this._getElement();
|
||||
|
||||
ASSERT(selectedIndex !== -1, 'Invalid selected index');
|
||||
//ASSERT(selectedIndex !== -1, 'Invalid selected index');
|
||||
element.selectedIndex = selectedIndex;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { remote } from 'electron';
|
||||
import * as path from 'path';
|
||||
|
||||
import { ConfigUIElement } from './config_element';
|
||||
@ -43,6 +42,8 @@ export class FileInputElement extends ConfigUIElement<string, HTMLDivElement> {
|
||||
});
|
||||
|
||||
this._getElement().addEventListener('click', () => {
|
||||
// TODO Unimplemented
|
||||
/*
|
||||
if (!this.getEnabled()) {
|
||||
return;
|
||||
}
|
||||
@ -61,6 +62,7 @@ export class FileInputElement extends ConfigUIElement<string, HTMLDivElement> {
|
||||
this._loadedFilePath = filePath;
|
||||
this._setValue(filePath);
|
||||
}
|
||||
*/
|
||||
});
|
||||
|
||||
this._getElement().addEventListener('mousemove', () => {
|
||||
|
@ -1,9 +1,8 @@
|
||||
import { remote } from 'electron';
|
||||
import path from 'path';
|
||||
|
||||
import { getRandomID } from '../../util';
|
||||
import { FileUtil } from '../../util/file_util';
|
||||
import { UIUtil } from '../../util/ui_util';
|
||||
import { AppIcons } from '../icons';
|
||||
import { ConfigUIElement } from './config_element';
|
||||
import { ToolbarItemElement } from './toolbar_item';
|
||||
|
||||
@ -15,10 +14,12 @@ export class ImageElement extends ConfigUIElement<string, HTMLDivElement> {
|
||||
|
||||
public constructor(path: string) {
|
||||
super(path);
|
||||
this._switchElement = new ToolbarItemElement({ icon: 'upload' })
|
||||
this._switchElement = new ToolbarItemElement({ iconSVG: AppIcons.UPLOAD })
|
||||
.setSmall()
|
||||
.setLabel('Choose')
|
||||
.onClick(() => {
|
||||
// TODO Unimplemented
|
||||
/*
|
||||
const files = remote.dialog.showOpenDialogSync({
|
||||
title: 'Load',
|
||||
buttonLabel: 'Load',
|
||||
@ -30,11 +31,13 @@ export class ImageElement extends ConfigUIElement<string, HTMLDivElement> {
|
||||
if (files && files[0]) {
|
||||
this._setValue(files[0]);
|
||||
}
|
||||
*/
|
||||
});
|
||||
this._openElement = new ToolbarItemElement({ icon: 'folder' })
|
||||
this._openElement = new ToolbarItemElement({ iconSVG: AppIcons.FOLDER })
|
||||
.setSmall()
|
||||
.onClick(() => {
|
||||
FileUtil.openDir(this.getValue());
|
||||
// TODO Unimplemented
|
||||
//FileUtil.openDir(this.getValue());
|
||||
});
|
||||
|
||||
this._imageId = getRandomID();
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { MaterialType } from '../../mesh';
|
||||
import { AppIcons } from '../icons';
|
||||
import { ConfigUIElement } from './config_element';
|
||||
import { ToolbarItemElement } from './toolbar_item';
|
||||
|
||||
@ -7,7 +8,7 @@ export class MaterialTypeElement extends ConfigUIElement<MaterialType, HTMLDivEl
|
||||
|
||||
public constructor(material: MaterialType) {
|
||||
super(material);
|
||||
this._switchElement = new ToolbarItemElement({ icon: 'switch' })
|
||||
this._switchElement = new ToolbarItemElement({ iconSVG: AppIcons.SWITCH })
|
||||
.setSmall()
|
||||
.setLabel('Switch')
|
||||
.onClick(() => {
|
||||
|
@ -1,5 +1,3 @@
|
||||
import fs from 'fs';
|
||||
|
||||
import { getRandomID } from '../../util';
|
||||
import { ASSERT } from '../../util/error_util';
|
||||
import { AppPaths } from '../../util/path_util';
|
||||
@ -9,13 +7,12 @@ import { UIUtil } from '../../util/ui_util';
|
||||
export type TToolbarBooleanProperty = 'enabled' | 'active';
|
||||
|
||||
export type TToolbarItemParams = {
|
||||
icon: string;
|
||||
iconSVG: string;
|
||||
}
|
||||
|
||||
export class ToolbarItemElement {
|
||||
private _id: string;
|
||||
private _iconName: string;
|
||||
private _iconPath: string;
|
||||
private _iconSVG: SVGSVGElement;
|
||||
private _isEnabled: boolean;
|
||||
private _isActive: boolean;
|
||||
private _isHovering: boolean;
|
||||
@ -26,8 +23,15 @@ export class ToolbarItemElement {
|
||||
public constructor(params: TToolbarItemParams) {
|
||||
this._id = getRandomID();
|
||||
|
||||
this._iconName = params.icon;
|
||||
this._iconPath = PathUtil.join(AppPaths.Get.static, params.icon + '.svg');
|
||||
{
|
||||
const parser = new DOMParser();
|
||||
const svgParse = parser.parseFromString(params.iconSVG, 'text/html');
|
||||
const svgs = svgParse.getElementsByTagName('svg');
|
||||
ASSERT(svgs.length === 1, 'Missing SVG');
|
||||
|
||||
this._iconSVG = svgs[0];
|
||||
this._iconSVG.id = this._id + '-svg';
|
||||
}
|
||||
|
||||
this._isEnabled = true;
|
||||
this._isActive = false;
|
||||
@ -82,10 +86,9 @@ export class ToolbarItemElement {
|
||||
}
|
||||
|
||||
public generateHTML() {
|
||||
const svg = fs.readFileSync(this._iconPath, 'utf8');
|
||||
return `
|
||||
<div class="toolbar-item ${this._small ? 'toolbar-item-small' : ''}" id="${this._id}">
|
||||
${svg} ${this._label}
|
||||
${this._iconSVG.outerHTML} ${this._label}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@ -110,15 +113,11 @@ export class ToolbarItemElement {
|
||||
this._updateElements();
|
||||
});
|
||||
|
||||
// Modify the svg's Id so that multiple svgs can be used without Id clashes
|
||||
const svgElement = document.getElementById(this._iconName + '-svg') as HTMLDivElement;
|
||||
svgElement.id += `-${this._id}`;
|
||||
|
||||
this._updateElements();
|
||||
}
|
||||
|
||||
private _getSVGElement() {
|
||||
const svgId = `${this._iconName}-svg-${this._id}`;
|
||||
const svgId = this._id + '-svg';
|
||||
return UIUtil.getElementById(svgId);
|
||||
}
|
||||
|
||||
|
146
src/ui/icons.ts
Normal file
@ -0,0 +1,146 @@
|
||||
export namespace AppIcons {
|
||||
|
||||
export const MESH = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-grain" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#00abfb" fill="none" stroke-linecap="round" stroke-linejoin="round" id="mesh-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<circle cx="4.5" cy="9.5" r="1" />
|
||||
<circle cx="9.5" cy="4.5" r="1" />
|
||||
<circle cx="9.5" cy="14.5" r="1" />
|
||||
<circle cx="4.5" cy="19.5" r="1" />
|
||||
<circle cx="14.5" cy="9.5" r="1" />
|
||||
<circle cx="19.5" cy="4.5" r="1" />
|
||||
<circle cx="14.5" cy="19.5" r="1" />
|
||||
<circle cx="19.5" cy="14.5" r="1" />
|
||||
</svg>
|
||||
`;
|
||||
|
||||
export const VOXEL = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-3d-cube-sphere" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#00abfb" fill="none" stroke-linecap="round" stroke-linejoin="round" id="voxel-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M6 17.6l-2 -1.1v-2.5" />
|
||||
<path d="M4 10v-2.5l2 -1.1" />
|
||||
<path d="M10 4.1l2 -1.1l2 1.1" />
|
||||
<path d="M18 6.4l2 1.1v2.5" />
|
||||
<path d="M20 14v2.5l-2 1.12" />
|
||||
<path d="M14 19.9l-2 1.1l-2 -1.1" />
|
||||
<line x1="12" y1="12" x2="14" y2="10.9" />
|
||||
<line x1="18" y1="8.6" x2="20" y2="7.5" />
|
||||
<line x1="12" y1="12" x2="12" y2="14.5" />
|
||||
<line x1="12" y1="18.5" x2="12" y2="21" />
|
||||
<path d="M12 12l-2 -1.12" />
|
||||
<line x1="6" y1="8.6" x2="4" y2="7.5" />
|
||||
</svg>
|
||||
`;
|
||||
|
||||
export const BLOCK = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-box" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#00abfb" fill="none" stroke-linecap="round" stroke-linejoin="round" id="block-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<polyline points="12 3 20 7.5 20 16.5 12 21 4 16.5 4 7.5 12 3" />
|
||||
<line x1="12" y1="12" x2="20" y2="7.5" />
|
||||
<line x1="12" y1="12" x2="12" y2="21" />
|
||||
<line x1="12" y1="12" x2="4" y2="7.5" />
|
||||
</svg>
|
||||
`;
|
||||
|
||||
export const GRID = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-border-all" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#00abfb" fill="none" stroke-linecap="round" stroke-linejoin="round" id="grid-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<rect x="4" y="4" width="16" height="16" rx="2" />
|
||||
<line x1="4" y1="12" x2="20" y2="12" />
|
||||
<line x1="12" y1="4" x2="12" y2="20" />
|
||||
</svg>
|
||||
`;
|
||||
|
||||
export const AXES = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-axis-x" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#00abfb" fill="none" stroke-linecap="round" stroke-linejoin="round" id="axes-svg">
|
||||
<path d="M17 20l3 -3l-3 -3" />
|
||||
<path d="M4 17h16" />
|
||||
<path d="M4 7l3 -3l3 3" />
|
||||
<path d="M7 20v-16" />
|
||||
</svg>
|
||||
`;
|
||||
|
||||
export const BULB = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-sun" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#00abfb" fill="none" stroke-linecap="round" stroke-linejoin="round" id="bulb-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<circle cx="12" cy="12" r="4" />
|
||||
<path d="M3 12h1m8 -9v1m8 8h1m-9 8v1m-6.4 -15.4l.7 .7m12.1 -.7l-.7 .7m0 11.4l.7 .7m-12.1 -.7l-.7 .7" />
|
||||
</svg>
|
||||
`;
|
||||
|
||||
export const MINUS = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-minus" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#00abfb" fill="none" stroke-linecap="round" stroke-linejoin="round" id="minus-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<line x1="5" y1="12" x2="19" y2="12" />
|
||||
</svg>
|
||||
`;
|
||||
|
||||
export const PLUS = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-plus" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#00abfb" fill="none" stroke-linecap="round" stroke-linejoin="round" id="plus-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<line x1="12" y1="5" x2="12" y2="19" />
|
||||
<line x1="5" y1="12" x2="19" y2="12" />
|
||||
</svg>
|
||||
`;
|
||||
|
||||
export const CENTRE = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-focus-2" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#00abfb" fill="none" stroke-linecap="round" stroke-linejoin="round" id="centre-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<circle cx="12" cy="12" r=".5" fill="currentColor" />
|
||||
<circle cx="12" cy="12" r="7" />
|
||||
<line x1="12" y1="3" x2="12" y2="5" />
|
||||
<line x1="3" y1="12" x2="5" y2="12" />
|
||||
<line x1="12" y1="19" x2="12" y2="21" />
|
||||
<line x1="19" y1="12" x2="21" y2="12" />
|
||||
</svg>
|
||||
`;
|
||||
|
||||
export const PERSPECTIVE = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-perspective" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#00abfb" fill="none" stroke-linecap="round" stroke-linejoin="round" id="perspective-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M6.141 4.163l12 1.714a1 1 0 0 1 .859 .99v10.266a1 1 0 0 1 -.859 .99l-12 1.714a1 1 0 0 1 -1.141 -.99v-13.694a1 1 0 0 1 1.141 -.99z" />
|
||||
</svg>
|
||||
`;
|
||||
|
||||
export const ORTHOGRAPHIC = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-rectangle" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#00abfb" fill="none" stroke-linecap="round" stroke-linejoin="round" id="orthographic-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<rect x="3" y="5" width="18" height="14" rx="2" />
|
||||
</svg>
|
||||
`;
|
||||
|
||||
export const MAGNET = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-magnet" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#00abfb" fill="none" stroke-linecap="round" stroke-linejoin="round" id="magnet-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M4 13v-8a2 2 0 0 1 2 -2h1a2 2 0 0 1 2 2v8a2 2 0 0 0 6 0v-8a2 2 0 0 1 2 -2h1a2 2 0 0 1 2 2v8a8 8 0 0 1 -16 0" />
|
||||
<line x1="4" y1="8" x2="9" y2="8" />
|
||||
<line x1="15" y1="8" x2="19" y2="8" />
|
||||
</svg>
|
||||
`;
|
||||
|
||||
export const UPLOAD = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-upload" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#2c3e50" fill="none" stroke-linecap="round" stroke-linejoin="round" id="upload-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2 -2v-2" />
|
||||
<polyline points="7 9 12 4 17 9" />
|
||||
<line x1="12" y1="4" x2="12" y2="16" />
|
||||
</svg>
|
||||
`;
|
||||
|
||||
export const FOLDER = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-folder" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#2c3e50" fill="none" stroke-linecap="round" stroke-linejoin="round" id="folder-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M5 4h4l3 3h7a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2v-11a2 2 0 0 1 2 -2" />
|
||||
</svg>
|
||||
`;
|
||||
|
||||
export const SWITCH = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-switch-3" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#2c3e50" fill="none" stroke-linecap="round" stroke-linejoin="round" id="switch-svg">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M3 17h2.397a5 5 0 0 0 4.096 -2.133l.177 -.253m3.66 -5.227l.177 -.254a5 5 0 0 1 4.096 -2.133h3.397" />
|
||||
path d="M18 4l3 3l-3 3" />
|
||||
<path d="M3 7h2.397a5 5 0 0 1 4.096 2.133l4.014 5.734a5 5 0 0 0 4.096 2.133h3.397" />
|
||||
<path d="M18 20l3 -3l-3 -3" />
|
||||
</svg>
|
||||
`;
|
||||
}
|
@ -1,5 +1,3 @@
|
||||
import fs from 'fs';
|
||||
|
||||
import { AppContext } from '../app_context';
|
||||
import { FallableBehaviour } from '../block_mesh';
|
||||
import { ArcballCamera } from '../camera';
|
||||
@ -23,6 +21,7 @@ import { OutputElement } from './elements/output';
|
||||
import { SliderElement } from './elements/slider';
|
||||
import { ToolbarItemElement } from './elements/toolbar_item';
|
||||
import { VectorSpinboxElement } from './elements/vector_spinbox';
|
||||
import { AppIcons } from './icons';
|
||||
|
||||
export interface Group {
|
||||
label: string;
|
||||
@ -285,7 +284,7 @@ export class UI {
|
||||
groups: {
|
||||
'viewmode': {
|
||||
elements: {
|
||||
'mesh': new ToolbarItemElement({ icon: 'mesh' })
|
||||
'mesh': new ToolbarItemElement({ iconSVG: AppIcons.MESH })
|
||||
.onClick(() => {
|
||||
Renderer.Get.setModelToUse(MeshType.TriangleMesh);
|
||||
})
|
||||
@ -295,7 +294,7 @@ export class UI {
|
||||
.isEnabled(() => {
|
||||
return Renderer.Get.getModelsAvailable() >= MeshType.TriangleMesh;
|
||||
}),
|
||||
'voxelMesh': new ToolbarItemElement({ icon: 'voxel' })
|
||||
'voxelMesh': new ToolbarItemElement({ iconSVG: AppIcons.VOXEL })
|
||||
.onClick(() => {
|
||||
Renderer.Get.setModelToUse(MeshType.VoxelMesh);
|
||||
})
|
||||
@ -305,7 +304,7 @@ export class UI {
|
||||
.isEnabled(() => {
|
||||
return Renderer.Get.getModelsAvailable() >= MeshType.VoxelMesh;
|
||||
}),
|
||||
'blockMesh': new ToolbarItemElement({ icon: 'block' })
|
||||
'blockMesh': new ToolbarItemElement({ iconSVG: AppIcons.BLOCK })
|
||||
.onClick(() => {
|
||||
Renderer.Get.setModelToUse(MeshType.BlockMesh);
|
||||
})
|
||||
@ -320,7 +319,7 @@ export class UI {
|
||||
},
|
||||
'debug': {
|
||||
elements: {
|
||||
'grid': new ToolbarItemElement({ icon: 'grid' })
|
||||
'grid': new ToolbarItemElement({ iconSVG: AppIcons.GRID })
|
||||
.onClick(() => {
|
||||
Renderer.Get.toggleIsGridEnabled();
|
||||
})
|
||||
@ -330,14 +329,14 @@ export class UI {
|
||||
.isEnabled(() => {
|
||||
return Renderer.Get.getActiveMeshType() !== MeshType.None;
|
||||
}),
|
||||
'axes': new ToolbarItemElement({ icon: 'axes' })
|
||||
'axes': new ToolbarItemElement({ iconSVG: AppIcons.AXES })
|
||||
.onClick(() => {
|
||||
Renderer.Get.toggleIsAxesEnabled();
|
||||
})
|
||||
.isActive(() => {
|
||||
return Renderer.Get.isAxesEnabled();
|
||||
}),
|
||||
'night-vision': new ToolbarItemElement({ icon: 'bulb' })
|
||||
'night-vision': new ToolbarItemElement({ iconSVG: AppIcons.BULB })
|
||||
.onClick(() => {
|
||||
Renderer.Get.toggleIsNightVisionEnabled();
|
||||
})
|
||||
@ -359,15 +358,15 @@ export class UI {
|
||||
groups: {
|
||||
'zoom': {
|
||||
elements: {
|
||||
'zoomOut': new ToolbarItemElement({ icon: 'minus' })
|
||||
'zoomOut': new ToolbarItemElement({ iconSVG: AppIcons.MINUS })
|
||||
.onClick(() => {
|
||||
ArcballCamera.Get.onZoomOut();
|
||||
}),
|
||||
'zoomIn': new ToolbarItemElement({ icon: 'plus' })
|
||||
'zoomIn': new ToolbarItemElement({ iconSVG: AppIcons.PLUS })
|
||||
.onClick(() => {
|
||||
ArcballCamera.Get.onZoomIn();
|
||||
}),
|
||||
'reset': new ToolbarItemElement({ icon: 'centre' })
|
||||
'reset': new ToolbarItemElement({ iconSVG: AppIcons.CENTRE })
|
||||
.onClick(() => {
|
||||
ArcballCamera.Get.reset();
|
||||
}),
|
||||
@ -376,21 +375,21 @@ export class UI {
|
||||
},
|
||||
'camera': {
|
||||
elements: {
|
||||
'perspective': new ToolbarItemElement({ icon: 'perspective' })
|
||||
'perspective': new ToolbarItemElement({ iconSVG: AppIcons.PERSPECTIVE })
|
||||
.onClick(() => {
|
||||
ArcballCamera.Get.setCameraMode('perspective');
|
||||
})
|
||||
.isActive(() => {
|
||||
return ArcballCamera.Get.isPerspective();
|
||||
}),
|
||||
'orthographic': new ToolbarItemElement({ icon: 'orthographic' })
|
||||
'orthographic': new ToolbarItemElement({ iconSVG: AppIcons.ORTHOGRAPHIC })
|
||||
.onClick(() => {
|
||||
ArcballCamera.Get.setCameraMode('orthographic');
|
||||
})
|
||||
.isActive(() => {
|
||||
return ArcballCamera.Get.isOrthographic();
|
||||
}),
|
||||
'angleSnap': new ToolbarItemElement({ icon: 'magnet' })
|
||||
'angleSnap': new ToolbarItemElement({ iconSVG: AppIcons.MAGNET })
|
||||
.onClick(() => {
|
||||
ArcballCamera.Get.toggleAngleSnap();
|
||||
})
|
||||
@ -651,6 +650,8 @@ export class UI {
|
||||
private _getTextureAtlases(): ComboBoxItem<string>[] {
|
||||
const textureAtlases: ComboBoxItem<string>[] = [];
|
||||
|
||||
// TODO Unimplemented
|
||||
/*
|
||||
fs.readdirSync(AppPaths.Get.atlases).forEach((file) => {
|
||||
if (file.endsWith('.atlas')) {
|
||||
const paletteID = file.split('.')[0];
|
||||
@ -659,6 +660,7 @@ export class UI {
|
||||
textureAtlases.push({ payload: paletteID, displayText: paletteName });
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
return textureAtlases;
|
||||
}
|
||||
|
@ -1,35 +0,0 @@
|
||||
import child from 'child_process';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
import { LOGF } from './log_util';
|
||||
|
||||
export namespace FileUtil {
|
||||
export function fileExists(absolutePath: string) {
|
||||
return fs.existsSync(absolutePath);
|
||||
}
|
||||
|
||||
export function mkdirIfNotExist(path: fs.PathLike) {
|
||||
if (!fs.existsSync(path)) {
|
||||
fs.mkdirSync(path);
|
||||
}
|
||||
}
|
||||
|
||||
export function rmdirIfExist(path: fs.PathLike) {
|
||||
if (fs.existsSync(path)) {
|
||||
LOGF(`Deleting '${path.toString()}'`);
|
||||
fs.rmSync(path, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
export function openDir(absolutePath: string) {
|
||||
switch (process.platform) {
|
||||
case 'darwin':
|
||||
child.exec(`open -R ${absolutePath}`);
|
||||
break;
|
||||
case 'win32':
|
||||
const parsed = path.parse(absolutePath);
|
||||
child.exec(`start ${parsed.dir}`);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,6 @@
|
||||
import fs from 'fs';
|
||||
import util from 'util';
|
||||
|
||||
import { AppConfig } from '../config';
|
||||
import { FileUtil } from './file_util';
|
||||
import { AppPaths, PathUtil } from './path_util';
|
||||
|
||||
/**
|
||||
@ -15,16 +13,9 @@ export const LOG = (...data: any[]) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(...data);
|
||||
}
|
||||
if (Logger.Get.logToFile) {
|
||||
Logger.Get.logToFile(...data);
|
||||
}
|
||||
};
|
||||
|
||||
export const LOGF = (...data: any[]) => {
|
||||
if (Logger.Get.logToFile) {
|
||||
Logger.Get.logToFile(...data);
|
||||
}
|
||||
};
|
||||
export const LOGF = LOG;
|
||||
|
||||
/**
|
||||
* Logs to console and file if logging `LOG_MAJOR` is enabled.
|
||||
@ -37,9 +28,6 @@ export const LOG_MAJOR = (...data: any[]) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(...data);
|
||||
}
|
||||
if (Logger.Get.logToFile) {
|
||||
Logger.Get.logToFile(...data);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -50,9 +38,6 @@ export const LOG_WARN = (...data: any[]) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(...data);
|
||||
}
|
||||
if (Logger.Get.logToFile) {
|
||||
Logger.Get.logToFile(...data);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -85,9 +70,6 @@ export const TIME_END = (label: string) => {
|
||||
export const LOG_ERROR = (...data: any[]) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(...data);
|
||||
if (Logger.Get.logToFile) {
|
||||
Logger.Get.logToFile(...data);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -107,8 +89,6 @@ export class Logger {
|
||||
|
||||
private _enabledLogToFile?: boolean;
|
||||
|
||||
private _logStream?: fs.WriteStream;
|
||||
|
||||
private constructor() {
|
||||
this._enabledLOG = false;
|
||||
this._enabledLOGMAJOR = false;
|
||||
@ -116,27 +96,6 @@ export class Logger {
|
||||
this._enabledLOGTIME = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the log file.
|
||||
* @param suffix The suffix to append to the end of the log file name.
|
||||
*/
|
||||
public initLogFile(suffix: string) {
|
||||
if (this._logStream === undefined && this._enabledLogToFile === true) {
|
||||
FileUtil.mkdirIfNotExist(AppPaths.Get.logs);
|
||||
this._logStream = fs.createWriteStream(PathUtil.join(AppPaths.Get.logs, `./${Date.now()}-${suffix}.log`));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs to the log file if setup.
|
||||
* @param data The data to print.
|
||||
*/
|
||||
public logToFile(...data: any[]) {
|
||||
if (this._logStream && this._enabledLogToFile) {
|
||||
this._logStream.write(`[${(new Date()).toISOString()}] ${util.format(...data)}\n`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow `LOG` calls to be printed to the console and to the log file if setup.
|
||||
*/
|
||||
@ -193,16 +152,6 @@ export class Logger {
|
||||
this._enabledLOGTIME = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow console log calls to logged to the log file if setup.
|
||||
* Should be called before `initLogFile`
|
||||
*/
|
||||
public enableLogToFile() {
|
||||
if (AppConfig.Get.LOG_TO_FILE && this._enabledLogToFile === undefined) {
|
||||
this._enabledLogToFile = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent console log calls to logged to the log file if setup.
|
||||
*/
|
||||
@ -237,11 +186,4 @@ export class Logger {
|
||||
public isLOGTIMEEnabled() {
|
||||
return this._enabledLOGTIME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not console log calls should be logged to the log file if setup.
|
||||
*/
|
||||
public isLogToFileEnabled() {
|
||||
return this.logToFile;
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,18 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { NBT, writeUncompressed } from 'prismarine-nbt';
|
||||
//import { NBT, writeUncompressed } from 'prismarine-nbt';
|
||||
import zlib from 'zlib';
|
||||
|
||||
import { ASSERT } from './error_util';
|
||||
|
||||
type NBT = {};
|
||||
|
||||
export function saveNBT(nbt: NBT, filepath: string) {
|
||||
// TODO Unimplemented
|
||||
/*
|
||||
ASSERT(path.isAbsolute(filepath), '[saveNBT]: filepath is not absolute');
|
||||
|
||||
const uncompressedBuffer = writeUncompressed(nbt, 'big');
|
||||
const compressedBuffer = zlib.gzipSync(uncompressedBuffer);
|
||||
fs.writeFileSync(filepath, compressedBuffer);
|
||||
*/
|
||||
}
|
||||
|
@ -21,8 +21,6 @@ export class WorkerClient {
|
||||
}
|
||||
|
||||
private constructor() {
|
||||
Logger.Get.enableLogToFile();
|
||||
Logger.Get.initLogFile('worker');
|
||||
}
|
||||
|
||||
private _loadedMesh?: Mesh;
|
||||
|
@ -12,15 +12,17 @@ export type TWorkerJob = {
|
||||
}
|
||||
|
||||
export class WorkerController {
|
||||
private _worker: Worker;
|
||||
private _worker?: Worker;
|
||||
private _jobQueue: TWorkerJob[];
|
||||
private _jobPending: TWorkerJob | undefined;
|
||||
private _jobStartTime: number;
|
||||
private _timerOn: boolean;
|
||||
|
||||
public constructor(scriptURL: string, options?: WorkerOptions) {
|
||||
this._worker = new Worker(scriptURL, options);
|
||||
this._worker.onmessage = this._onWorkerMessage.bind(this);
|
||||
if (AppConfig.Get.USE_WORKER_THREAD) {
|
||||
this._worker = new Worker(scriptURL, options);
|
||||
this._worker.onmessage = this._onWorkerMessage.bind(this);
|
||||
}
|
||||
|
||||
this._jobQueue = [];
|
||||
this._jobStartTime = 0;
|
||||
@ -105,6 +107,7 @@ export class WorkerController {
|
||||
}
|
||||
|
||||
if (AppConfig.Get.USE_WORKER_THREAD) {
|
||||
ASSERT(this._worker !== undefined, 'No worker instance');
|
||||
this._worker.postMessage(this._jobPending.payload);
|
||||
} else {
|
||||
const result = doWork(this._jobPending.payload);
|
||||
|
@ -1,423 +1,419 @@
|
||||
import fs from 'fs';
|
||||
import images from 'images';
|
||||
import path from 'path';
|
||||
import { PNG } from 'pngjs';
|
||||
import prompt from 'prompt';
|
||||
// import images from 'images';
|
||||
// import path from 'path';
|
||||
// import prompt from 'prompt';
|
||||
|
||||
import { RGBA, RGBAUtil } from '../src/colour';
|
||||
import { AppUtil } from '../src/util';
|
||||
import { LOG, LOG_WARN, Logger } from '../src/util/log_util';
|
||||
// import { RGBA, RGBAUtil } from '../src/colour';
|
||||
// import { AppUtil } from '../src/util';
|
||||
// import { LOG, LOG_WARN, Logger } from '../src/util/log_util';
|
||||
|
||||
const AdmZip = require('adm-zip');
|
||||
const copydir = require('copy-dir');
|
||||
// const AdmZip = require('adm-zip');
|
||||
// const copydir = require('copy-dir');
|
||||
|
||||
import { AppPaths, PathUtil } from '../src/util/path_util';
|
||||
import { log } from './logging';
|
||||
import { ASSERT_EXISTS, getAverageColour, getMinecraftDir, getStandardDeviation } from './misc';
|
||||
// import { AppPaths, PathUtil } from '../src/util/path_util';
|
||||
// import { log } from './logging';
|
||||
// import { ASSERT_EXISTS, getAverageColour, getMinecraftDir, getStandardDeviation } from './misc';
|
||||
|
||||
const BLOCKS_DIR = PathUtil.join(AppPaths.Get.tools, '/blocks');
|
||||
const MODELS_DIR = PathUtil.join(AppPaths.Get.tools, '/models');
|
||||
// const BLOCKS_DIR = PathUtil.join(AppPaths.Get.tools, '/blocks');
|
||||
// const MODELS_DIR = PathUtil.join(AppPaths.Get.tools, '/models');
|
||||
|
||||
type TFaceData<T> = {
|
||||
up: T,
|
||||
down: T,
|
||||
north: T,
|
||||
south: T,
|
||||
east: T,
|
||||
west: T,
|
||||
}
|
||||
// type TFaceData<T> = {
|
||||
// up: T,
|
||||
// down: T,
|
||||
// north: T,
|
||||
// south: T,
|
||||
// east: T,
|
||||
// west: T,
|
||||
// }
|
||||
|
||||
export type TAtlasVersion = {
|
||||
formatVersion: 3,
|
||||
atlasSize: number,
|
||||
blocks: Array<{ name: string, faces: TFaceData<string>, colour: RGBA }>,
|
||||
textures: { [texture: string]: { atlasColumn: number, atlasRow: number, colour: RGBA, std: number } },
|
||||
supportedBlockNames: string[],
|
||||
};
|
||||
// export type TAtlasVersion = {
|
||||
// formatVersion: 3,
|
||||
// atlasSize: number,
|
||||
// blocks: Array<{ name: string, faces: TFaceData<string>, colour: RGBA }>,
|
||||
// textures: { [texture: string]: { atlasColumn: number, atlasRow: number, colour: RGBA, std: number } },
|
||||
// supportedBlockNames: string[],
|
||||
// };
|
||||
|
||||
void async function main() {
|
||||
AppPaths.Get.setBaseDir(PathUtil.join(__dirname, '../..'));
|
||||
Logger.Get.enableLogToFile();
|
||||
Logger.Get.initLogFile('atlas');
|
||||
// void async function main() {
|
||||
// AppPaths.Get.setBaseDir(PathUtil.join(__dirname, '../..'));
|
||||
// Logger.Get.enableLogToFile();
|
||||
// Logger.Get.initLogFile('atlas');
|
||||
|
||||
const minecraftDir = getMinecraftDir();
|
||||
// const minecraftDir = getMinecraftDir();
|
||||
|
||||
// Clean up temporary data from previous use
|
||||
{
|
||||
fs.rmSync(BLOCKS_DIR, { recursive: true, force: true });
|
||||
fs.rmSync(MODELS_DIR, { recursive: true, force: true });
|
||||
}
|
||||
// // Clean up temporary data from previous use
|
||||
// {
|
||||
// fs.rmSync(BLOCKS_DIR, { recursive: true, force: true });
|
||||
// fs.rmSync(MODELS_DIR, { recursive: true, force: true });
|
||||
// }
|
||||
|
||||
// Ask for permission to access Minecraft dir
|
||||
{
|
||||
log('Prompt', `This script requires files inside '${minecraftDir}'`);
|
||||
// // Ask for permission to access Minecraft dir
|
||||
// {
|
||||
// log('Prompt', `This script requires files inside '${minecraftDir}'`);
|
||||
|
||||
const { permission } = await prompt.get({
|
||||
properties: {
|
||||
permission: {
|
||||
pattern: /^[YyNn]$/,
|
||||
description: 'Do you give permission to access these files? (y/n)',
|
||||
message: 'Response must be Y or N',
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
// const { permission } = await prompt.get({
|
||||
// properties: {
|
||||
// permission: {
|
||||
// pattern: /^[YyNn]$/,
|
||||
// description: 'Do you give permission to access these files? (y/n)',
|
||||
// message: 'Response must be Y or N',
|
||||
// required: true,
|
||||
// },
|
||||
// },
|
||||
// });
|
||||
|
||||
const isResponseYes = ['Y', 'y'].includes(permission as string);
|
||||
if (!isResponseYes) {
|
||||
process.exit(0);
|
||||
}
|
||||
}
|
||||
// const isResponseYes = ['Y', 'y'].includes(permission as string);
|
||||
// if (!isResponseYes) {
|
||||
// process.exit(0);
|
||||
// }
|
||||
// }
|
||||
|
||||
ASSERT_EXISTS(minecraftDir);
|
||||
// ASSERT_EXISTS(minecraftDir);
|
||||
|
||||
// Prompt user to pick a version
|
||||
let chosenVersionName: string;
|
||||
let chosenVersionDir: string;
|
||||
{
|
||||
const versionsDir = PathUtil.join(minecraftDir, '/versions');
|
||||
ASSERT_EXISTS(versionsDir);
|
||||
// // Prompt user to pick a version
|
||||
// let chosenVersionName: string;
|
||||
// let chosenVersionDir: string;
|
||||
// {
|
||||
// const versionsDir = PathUtil.join(minecraftDir, '/versions');
|
||||
// ASSERT_EXISTS(versionsDir);
|
||||
|
||||
const versions = fs.readdirSync(versionsDir)
|
||||
.filter((file) => fs.lstatSync(PathUtil.join(versionsDir, file)).isDirectory())
|
||||
.map((file) => ({ file, birthtime: fs.lstatSync(PathUtil.join(versionsDir, file)).birthtime }))
|
||||
.sort((a, b) => b.birthtime.getTime() - a.birthtime.getTime());
|
||||
{
|
||||
versions.forEach((version, index) => {
|
||||
log('Option', `${index + 1}) ${version.file}`);
|
||||
});
|
||||
}
|
||||
// const versions = fs.readdirSync(versionsDir)
|
||||
// .filter((file) => fs.lstatSync(PathUtil.join(versionsDir, file)).isDirectory())
|
||||
// .map((file) => ({ file, birthtime: fs.lstatSync(PathUtil.join(versionsDir, file)).birthtime }))
|
||||
// .sort((a, b) => b.birthtime.getTime() - a.birthtime.getTime());
|
||||
// {
|
||||
// versions.forEach((version, index) => {
|
||||
// log('Option', `${index + 1}) ${version.file}`);
|
||||
// });
|
||||
// }
|
||||
|
||||
// Prompt user to pick a version
|
||||
const { packChoice } = await prompt.get({
|
||||
properties: {
|
||||
packChoice: {
|
||||
description: `Which version do you want to build an atlas for? (1-${versions.length})`,
|
||||
message: `Response must be between 1 and ${versions.length}`,
|
||||
required: true,
|
||||
conform: (value) => {
|
||||
return value >= 1 && value <= versions.length;
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
// // Prompt user to pick a version
|
||||
// const { packChoice } = await prompt.get({
|
||||
// properties: {
|
||||
// packChoice: {
|
||||
// description: `Which version do you want to build an atlas for? (1-${versions.length})`,
|
||||
// message: `Response must be between 1 and ${versions.length}`,
|
||||
// required: true,
|
||||
// conform: (value) => {
|
||||
// return value >= 1 && value <= versions.length;
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// });
|
||||
|
||||
chosenVersionName = versions[(<number>packChoice) - 1].file;
|
||||
chosenVersionDir = PathUtil.join(versionsDir, chosenVersionName);
|
||||
}
|
||||
// chosenVersionName = versions[(<number>packChoice) - 1].file;
|
||||
// chosenVersionDir = PathUtil.join(versionsDir, chosenVersionName);
|
||||
// }
|
||||
|
||||
// Get vanilla models and textures
|
||||
{
|
||||
const jarName = `${chosenVersionName}.jar`;
|
||||
const jarDir = PathUtil.join(chosenVersionDir, jarName);
|
||||
ASSERT_EXISTS(jarDir);
|
||||
// // Get vanilla models and textures
|
||||
// {
|
||||
// const jarName = `${chosenVersionName}.jar`;
|
||||
// const jarDir = PathUtil.join(chosenVersionDir, jarName);
|
||||
// ASSERT_EXISTS(jarDir);
|
||||
|
||||
log('Info', `Upzipping '${jarDir}'...`);
|
||||
{
|
||||
const zip = new AdmZip(jarDir);
|
||||
const zipEntries = zip.getEntries();
|
||||
zipEntries.forEach((zipEntry: any) => {
|
||||
if (zipEntry.entryName.startsWith('assets/minecraft/textures/block')) {
|
||||
zip.extractEntryTo(zipEntry.entryName, BLOCKS_DIR, false, true);
|
||||
} else if (zipEntry.entryName.startsWith('assets/minecraft/models/block')) {
|
||||
zip.extractEntryTo(zipEntry.entryName, MODELS_DIR, false, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
log('Success', `Extracted Vanilla models to '${MODELS_DIR}'`);
|
||||
log('Success', `Extracted Vanilla textures to '${BLOCKS_DIR}'`);
|
||||
}
|
||||
// log('Info', `Upzipping '${jarDir}'...`);
|
||||
// {
|
||||
// const zip = new AdmZip(jarDir);
|
||||
// const zipEntries = zip.getEntries();
|
||||
// zipEntries.forEach((zipEntry: any) => {
|
||||
// if (zipEntry.entryName.startsWith('assets/minecraft/textures/block')) {
|
||||
// zip.extractEntryTo(zipEntry.entryName, BLOCKS_DIR, false, true);
|
||||
// } else if (zipEntry.entryName.startsWith('assets/minecraft/models/block')) {
|
||||
// zip.extractEntryTo(zipEntry.entryName, MODELS_DIR, false, true);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// log('Success', `Extracted Vanilla models to '${MODELS_DIR}'`);
|
||||
// log('Success', `Extracted Vanilla textures to '${BLOCKS_DIR}'`);
|
||||
// }
|
||||
|
||||
// Prompt user to pick a resource pack
|
||||
let chosenResourcePackDir: string | undefined;
|
||||
{
|
||||
const resourcePacksDir = PathUtil.join(minecraftDir, '/resourcepacks');
|
||||
ASSERT_EXISTS(resourcePacksDir);
|
||||
// // Prompt user to pick a resource pack
|
||||
// let chosenResourcePackDir: string | undefined;
|
||||
// {
|
||||
// const resourcePacksDir = PathUtil.join(minecraftDir, '/resourcepacks');
|
||||
// ASSERT_EXISTS(resourcePacksDir);
|
||||
|
||||
const resourcePacks = fs.readdirSync(resourcePacksDir);
|
||||
{
|
||||
log('Option', `1) Vanilla`);
|
||||
resourcePacks.forEach((resourcePack, index) => {
|
||||
log('Option', `${index + 2}) ${resourcePack}`);
|
||||
});
|
||||
}
|
||||
// const resourcePacks = fs.readdirSync(resourcePacksDir);
|
||||
// {
|
||||
// log('Option', `1) Vanilla`);
|
||||
// resourcePacks.forEach((resourcePack, index) => {
|
||||
// log('Option', `${index + 2}) ${resourcePack}`);
|
||||
// });
|
||||
// }
|
||||
|
||||
const { resourcePackChoiceIndex } = await prompt.get({
|
||||
properties: {
|
||||
packChoice: {
|
||||
description: `Which resource pack do you want to build an atlas for? (1-${resourcePacks.length + 1})`,
|
||||
message: `Response must be between 1 and ${resourcePacks.length + 1}`,
|
||||
required: true,
|
||||
conform: (value) => {
|
||||
return value >= 1 && value <= resourcePacks.length + 1;
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
// const { resourcePackChoiceIndex } = await prompt.get({
|
||||
// properties: {
|
||||
// packChoice: {
|
||||
// description: `Which resource pack do you want to build an atlas for? (1-${resourcePacks.length + 1})`,
|
||||
// message: `Response must be between 1 and ${resourcePacks.length + 1}`,
|
||||
// required: true,
|
||||
// conform: (value) => {
|
||||
// return value >= 1 && value <= resourcePacks.length + 1;
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// });
|
||||
|
||||
chosenResourcePackDir = (<number>resourcePackChoiceIndex) === 1 ? undefined : resourcePacks[(<number>resourcePackChoiceIndex) - 2];
|
||||
}
|
||||
// chosenResourcePackDir = (<number>resourcePackChoiceIndex) === 1 ? undefined : resourcePacks[(<number>resourcePackChoiceIndex) - 2];
|
||||
// }
|
||||
|
||||
// Get resource pack textures
|
||||
if (chosenResourcePackDir !== undefined) {
|
||||
log('Warning', 'Using non-16x16 texture packs is not supported and will result in undefined behaviour');
|
||||
{
|
||||
if (fs.lstatSync(chosenResourcePackDir).isDirectory()) {
|
||||
log('Info', `Resource pack '${chosenResourcePackDir}' is a directory`);
|
||||
// // Get resource pack textures
|
||||
// if (chosenResourcePackDir !== undefined) {
|
||||
// log('Warning', 'Using non-16x16 texture packs is not supported and will result in undefined behaviour');
|
||||
// {
|
||||
// if (fs.lstatSync(chosenResourcePackDir).isDirectory()) {
|
||||
// log('Info', `Resource pack '${chosenResourcePackDir}' is a directory`);
|
||||
|
||||
const blockTexturesSrc = PathUtil.join(chosenResourcePackDir, 'assets/minecraft/textures/block');
|
||||
const blockTexturesDst = BLOCKS_DIR;
|
||||
// const blockTexturesSrc = PathUtil.join(chosenResourcePackDir, 'assets/minecraft/textures/block');
|
||||
// const blockTexturesDst = BLOCKS_DIR;
|
||||
|
||||
log('Info', `Copying ${blockTexturesSrc} to ${blockTexturesDst}...`);
|
||||
copydir(blockTexturesSrc, blockTexturesDst, {
|
||||
utimes: true,
|
||||
mode: true,
|
||||
cover: true,
|
||||
});
|
||||
} else {
|
||||
log('Info', `Resource pack '${chosenResourcePackDir}' is not a directory, expecting to be a .zip`);
|
||||
// log('Info', `Copying ${blockTexturesSrc} to ${blockTexturesDst}...`);
|
||||
// copydir(blockTexturesSrc, blockTexturesDst, {
|
||||
// utimes: true,
|
||||
// mode: true,
|
||||
// cover: true,
|
||||
// });
|
||||
// } else {
|
||||
// log('Info', `Resource pack '${chosenResourcePackDir}' is not a directory, expecting to be a .zip`);
|
||||
|
||||
const zip = new AdmZip(chosenResourcePackDir);
|
||||
const zipEntries = zip.getEntries();
|
||||
zipEntries.forEach((zipEntry: any) => {
|
||||
if (zipEntry.entryName.startsWith('assets/minecraft/textures/block')) {
|
||||
zip.extractEntryTo(zipEntry.entryName, BLOCKS_DIR, false, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
log('Success', `Copied block textures successfully`);
|
||||
}
|
||||
// const zip = new AdmZip(chosenResourcePackDir);
|
||||
// const zipEntries = zip.getEntries();
|
||||
// zipEntries.forEach((zipEntry: any) => {
|
||||
// if (zipEntry.entryName.startsWith('assets/minecraft/textures/block')) {
|
||||
// zip.extractEntryTo(zipEntry.entryName, BLOCKS_DIR, false, true);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// log('Success', `Copied block textures successfully`);
|
||||
// }
|
||||
|
||||
// Load the ignore list
|
||||
let ignoreList: Array<string> = [];
|
||||
{
|
||||
log('Info', 'Loading ignore list...');
|
||||
{
|
||||
const ignoreListPath = PathUtil.join(AppPaths.Get.tools, './models-ignore-list.txt');
|
||||
if (fs.existsSync(ignoreListPath)) {
|
||||
log('Success', `Found ignore list in '${ignoreListPath}'`);
|
||||
ignoreList = fs.readFileSync(ignoreListPath, 'utf-8').replace(/\r/g, '').split('\n');
|
||||
log('Info', `Found ${ignoreList.length} blocks in ignore list`);
|
||||
} else {
|
||||
log('Warning', `Could not find ignore list '${ignoreListPath}'`);
|
||||
}
|
||||
}
|
||||
}
|
||||
// // Load the ignore list
|
||||
// let ignoreList: Array<string> = [];
|
||||
// {
|
||||
// log('Info', 'Loading ignore list...');
|
||||
// {
|
||||
// const ignoreListPath = PathUtil.join(AppPaths.Get.tools, './models-ignore-list.txt');
|
||||
// if (fs.existsSync(ignoreListPath)) {
|
||||
// log('Success', `Found ignore list in '${ignoreListPath}'`);
|
||||
// ignoreList = fs.readFileSync(ignoreListPath, 'utf-8').replace(/\r/g, '').split('\n');
|
||||
// log('Info', `Found ${ignoreList.length} blocks in ignore list`);
|
||||
// } else {
|
||||
// log('Warning', `Could not find ignore list '${ignoreListPath}'`);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
const usedTextures = new Set<string>();
|
||||
const usedModels: Array<{ name: string, faces: TFaceData<string> }> = [];
|
||||
// const usedTextures = new Set<string>();
|
||||
// const usedModels: Array<{ name: string, faces: TFaceData<string> }> = [];
|
||||
|
||||
// Load all models to use
|
||||
{
|
||||
const allModels = fs.readdirSync(MODELS_DIR);
|
||||
log('Info', `Found ${allModels.length} models in '${MODELS_DIR}'`);
|
||||
// // Load all models to use
|
||||
// {
|
||||
// const allModels = fs.readdirSync(MODELS_DIR);
|
||||
// log('Info', `Found ${allModels.length} models in '${MODELS_DIR}'`);
|
||||
|
||||
allModels.forEach((modelRelDir, index) => {
|
||||
const modelAbsDir = PathUtil.join(MODELS_DIR, modelRelDir);
|
||||
const parsed = path.parse(modelAbsDir);
|
||||
// allModels.forEach((modelRelDir, index) => {
|
||||
// const modelAbsDir = PathUtil.join(MODELS_DIR, modelRelDir);
|
||||
// const parsed = path.parse(modelAbsDir);
|
||||
|
||||
if (parsed.ext !== '.json' || ignoreList.includes(parsed.base)) {
|
||||
return;
|
||||
}
|
||||
// if (parsed.ext !== '.json' || ignoreList.includes(parsed.base)) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
const fileData = fs.readFileSync(modelAbsDir, 'utf8');
|
||||
const modelData = JSON.parse(fileData);
|
||||
// const fileData = fs.readFileSync(modelAbsDir, 'utf8');
|
||||
// const modelData = JSON.parse(fileData);
|
||||
|
||||
const faceData: TFaceData<string> | undefined = (() => {
|
||||
switch (modelData.parent) {
|
||||
case 'minecraft:block/cube_column_horizontal':
|
||||
return {
|
||||
up: modelData.textures.side,
|
||||
down: modelData.textures.side,
|
||||
north: modelData.textures.end,
|
||||
south: modelData.textures.end,
|
||||
east: modelData.textures.side,
|
||||
west: modelData.textures.side,
|
||||
};
|
||||
case 'minecraft:block/cube_all':
|
||||
return {
|
||||
up: modelData.textures.all,
|
||||
down: modelData.textures.all,
|
||||
north: modelData.textures.all,
|
||||
south: modelData.textures.all,
|
||||
east: modelData.textures.all,
|
||||
west: modelData.textures.all,
|
||||
};
|
||||
case 'minecraft:block/cube_column':
|
||||
return {
|
||||
up: modelData.textures.end,
|
||||
down: modelData.textures.end,
|
||||
north: modelData.textures.side,
|
||||
south: modelData.textures.side,
|
||||
east: modelData.textures.side,
|
||||
west: modelData.textures.side,
|
||||
};
|
||||
case 'minecraft:block/cube_bottom_top':
|
||||
return {
|
||||
up: modelData.textures.top,
|
||||
down: modelData.textures.bottom,
|
||||
north: modelData.textures.side,
|
||||
south: modelData.textures.side,
|
||||
east: modelData.textures.side,
|
||||
west: modelData.textures.side,
|
||||
};
|
||||
case 'minecraft:block/cube':
|
||||
return {
|
||||
up: modelData.textures.up,
|
||||
down: modelData.textures.down,
|
||||
north: modelData.textures.north,
|
||||
south: modelData.textures.south,
|
||||
east: modelData.textures.east,
|
||||
west: modelData.textures.west,
|
||||
};
|
||||
case 'minecraft:block/template_single_face':
|
||||
return {
|
||||
up: modelData.textures.texture,
|
||||
down: modelData.textures.texture,
|
||||
north: modelData.textures.texture,
|
||||
south: modelData.textures.texture,
|
||||
east: modelData.textures.texture,
|
||||
west: modelData.textures.texture,
|
||||
};
|
||||
case 'minecraft:block/template_glazed_terracotta':
|
||||
return {
|
||||
up: modelData.textures.pattern,
|
||||
down: modelData.textures.pattern,
|
||||
north: modelData.textures.pattern,
|
||||
south: modelData.textures.pattern,
|
||||
east: modelData.textures.pattern,
|
||||
west: modelData.textures.pattern,
|
||||
};
|
||||
case 'minecraft:block/leaves':
|
||||
return {
|
||||
up: modelData.textures.all,
|
||||
down: modelData.textures.all,
|
||||
north: modelData.textures.all,
|
||||
south: modelData.textures.all,
|
||||
east: modelData.textures.all,
|
||||
west: modelData.textures.all,
|
||||
};
|
||||
}
|
||||
})();
|
||||
// const faceData: TFaceData<string> | undefined = (() => {
|
||||
// switch (modelData.parent) {
|
||||
// case 'minecraft:block/cube_column_horizontal':
|
||||
// return {
|
||||
// up: modelData.textures.side,
|
||||
// down: modelData.textures.side,
|
||||
// north: modelData.textures.end,
|
||||
// south: modelData.textures.end,
|
||||
// east: modelData.textures.side,
|
||||
// west: modelData.textures.side,
|
||||
// };
|
||||
// case 'minecraft:block/cube_all':
|
||||
// return {
|
||||
// up: modelData.textures.all,
|
||||
// down: modelData.textures.all,
|
||||
// north: modelData.textures.all,
|
||||
// south: modelData.textures.all,
|
||||
// east: modelData.textures.all,
|
||||
// west: modelData.textures.all,
|
||||
// };
|
||||
// case 'minecraft:block/cube_column':
|
||||
// return {
|
||||
// up: modelData.textures.end,
|
||||
// down: modelData.textures.end,
|
||||
// north: modelData.textures.side,
|
||||
// south: modelData.textures.side,
|
||||
// east: modelData.textures.side,
|
||||
// west: modelData.textures.side,
|
||||
// };
|
||||
// case 'minecraft:block/cube_bottom_top':
|
||||
// return {
|
||||
// up: modelData.textures.top,
|
||||
// down: modelData.textures.bottom,
|
||||
// north: modelData.textures.side,
|
||||
// south: modelData.textures.side,
|
||||
// east: modelData.textures.side,
|
||||
// west: modelData.textures.side,
|
||||
// };
|
||||
// case 'minecraft:block/cube':
|
||||
// return {
|
||||
// up: modelData.textures.up,
|
||||
// down: modelData.textures.down,
|
||||
// north: modelData.textures.north,
|
||||
// south: modelData.textures.south,
|
||||
// east: modelData.textures.east,
|
||||
// west: modelData.textures.west,
|
||||
// };
|
||||
// case 'minecraft:block/template_single_face':
|
||||
// return {
|
||||
// up: modelData.textures.texture,
|
||||
// down: modelData.textures.texture,
|
||||
// north: modelData.textures.texture,
|
||||
// south: modelData.textures.texture,
|
||||
// east: modelData.textures.texture,
|
||||
// west: modelData.textures.texture,
|
||||
// };
|
||||
// case 'minecraft:block/template_glazed_terracotta':
|
||||
// return {
|
||||
// up: modelData.textures.pattern,
|
||||
// down: modelData.textures.pattern,
|
||||
// north: modelData.textures.pattern,
|
||||
// south: modelData.textures.pattern,
|
||||
// east: modelData.textures.pattern,
|
||||
// west: modelData.textures.pattern,
|
||||
// };
|
||||
// case 'minecraft:block/leaves':
|
||||
// return {
|
||||
// up: modelData.textures.all,
|
||||
// down: modelData.textures.all,
|
||||
// north: modelData.textures.all,
|
||||
// south: modelData.textures.all,
|
||||
// east: modelData.textures.all,
|
||||
// west: modelData.textures.all,
|
||||
// };
|
||||
// }
|
||||
// })();
|
||||
|
||||
// Debug logging to file
|
||||
if (faceData === undefined) {
|
||||
LOG_WARN(`Could not parse '${parsed.base}'`);
|
||||
return;
|
||||
} else {
|
||||
LOG(`Parsed '${parsed.base}'`);
|
||||
}
|
||||
// // Debug logging to file
|
||||
// if (faceData === undefined) {
|
||||
// LOG_WARN(`Could not parse '${parsed.base}'`);
|
||||
// return;
|
||||
// } else {
|
||||
// LOG(`Parsed '${parsed.base}'`);
|
||||
// }
|
||||
|
||||
// Check that the textures that this model uses can be found
|
||||
Object.values(faceData).forEach((texture) => {
|
||||
const textureBaseName = texture.split('/')[1] + '.png';
|
||||
const textureAbsDir = PathUtil.join(BLOCKS_DIR, textureBaseName);
|
||||
// // Check that the textures that this model uses can be found
|
||||
// Object.values(faceData).forEach((texture) => {
|
||||
// const textureBaseName = texture.split('/')[1] + '.png';
|
||||
// const textureAbsDir = PathUtil.join(BLOCKS_DIR, textureBaseName);
|
||||
|
||||
if (fs.existsSync(textureAbsDir)) {
|
||||
LOG(`Found '${textureAbsDir}'`);
|
||||
} else {
|
||||
log('Warning', `'${parsed.base}' uses texture '${texture}' but the texture file could not be found at '${textureAbsDir}'`);
|
||||
return;
|
||||
}
|
||||
});
|
||||
// if (fs.existsSync(textureAbsDir)) {
|
||||
// LOG(`Found '${textureAbsDir}'`);
|
||||
// } else {
|
||||
// log('Warning', `'${parsed.base}' uses texture '${texture}' but the texture file could not be found at '${textureAbsDir}'`);
|
||||
// return;
|
||||
// }
|
||||
// });
|
||||
|
||||
// Update usedTextures and usedModels
|
||||
Object.values(faceData).forEach((texture) => {
|
||||
usedTextures.add(texture);
|
||||
});
|
||||
usedModels.push({
|
||||
name: parsed.name,
|
||||
faces: faceData,
|
||||
});
|
||||
});
|
||||
// // Update usedTextures and usedModels
|
||||
// Object.values(faceData).forEach((texture) => {
|
||||
// usedTextures.add(texture);
|
||||
// });
|
||||
// usedModels.push({
|
||||
// name: parsed.name,
|
||||
// faces: faceData,
|
||||
// });
|
||||
// });
|
||||
|
||||
LOG('All Textures', usedTextures);
|
||||
LOG('All Models', usedModels);
|
||||
log('Info', `Found ${usedModels.length} models to use`);
|
||||
// LOG('All Textures', usedTextures);
|
||||
// LOG('All Models', usedModels);
|
||||
// log('Info', `Found ${usedModels.length} models to use`);
|
||||
|
||||
// Prompt user for an atlas name
|
||||
const { atlasName } = await prompt.get({
|
||||
properties: {
|
||||
atlasName: {
|
||||
pattern: /^[a-zA-Z\-]+$/,
|
||||
description: 'What do you want to call this texture atlas?',
|
||||
message: 'Name must only be letters or dash',
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
// // Prompt user for an atlas name
|
||||
// const { atlasName } = await prompt.get({
|
||||
// properties: {
|
||||
// atlasName: {
|
||||
// pattern: /^[a-zA-Z\-]+$/,
|
||||
// description: 'What do you want to call this texture atlas?',
|
||||
// message: 'Name must only be letters or dash',
|
||||
// required: true,
|
||||
// },
|
||||
// },
|
||||
// });
|
||||
|
||||
// Create atlas texture file
|
||||
const textureDetails: { [texture: string]: { atlasColumn: number, atlasRow: number, colour: RGBA, std: number } } = {};
|
||||
const atlasSize = Math.ceil(Math.sqrt(usedTextures.size));
|
||||
{
|
||||
const atlasWidth = atlasSize * 16;
|
||||
// // Create atlas texture file
|
||||
// const textureDetails: { [texture: string]: { atlasColumn: number, atlasRow: number, colour: RGBA, std: number } } = {};
|
||||
// const atlasSize = Math.ceil(Math.sqrt(usedTextures.size));
|
||||
// {
|
||||
// const atlasWidth = atlasSize * 16;
|
||||
|
||||
let offsetX = 0;
|
||||
let offsetY = 0;
|
||||
const outputImage = images(atlasWidth * 3, atlasWidth * 3);
|
||||
// let offsetX = 0;
|
||||
// let offsetY = 0;
|
||||
// const outputImage = images(atlasWidth * 3, atlasWidth * 3);
|
||||
|
||||
usedTextures.forEach((texture) => {
|
||||
const shortName = texture.split('/')[1]; // Eww
|
||||
const absolutePath = path.join(BLOCKS_DIR, shortName + '.png');
|
||||
const fileData = fs.readFileSync(absolutePath);
|
||||
const pngData = PNG.sync.read(fileData);
|
||||
const image = images(absolutePath);
|
||||
// usedTextures.forEach((texture) => {
|
||||
// const shortName = texture.split('/')[1]; // Eww
|
||||
// const absolutePath = path.join(BLOCKS_DIR, shortName + '.png');
|
||||
// const fileData = fs.readFileSync(absolutePath);
|
||||
// //const pngData = PNG.sync.read(fileData);
|
||||
// const image = images(absolutePath);
|
||||
|
||||
for (let x = 0; x < 3; ++x) {
|
||||
for (let y = 0; y < 3; ++y) {
|
||||
outputImage.draw(image, 16 * (3 * offsetX + x), 16 * (3 * offsetY + y));
|
||||
}
|
||||
}
|
||||
// for (let x = 0; x < 3; ++x) {
|
||||
// for (let y = 0; y < 3; ++y) {
|
||||
// outputImage.draw(image, 16 * (3 * offsetX + x), 16 * (3 * offsetY + y));
|
||||
// }
|
||||
// }
|
||||
|
||||
const average = getAverageColour(pngData);
|
||||
textureDetails[texture] = {
|
||||
/*
|
||||
texcoord: new UV(
|
||||
16 * (3 * offsetX + 1) / (atlasWidth * 3),
|
||||
16 * (3 * offsetY + 1) / (atlasWidth * 3),
|
||||
),
|
||||
*/
|
||||
atlasColumn: offsetX,
|
||||
atlasRow: offsetY,
|
||||
colour: average,
|
||||
std: getStandardDeviation(pngData, average),
|
||||
};
|
||||
// // TODO Unimplemented
|
||||
// /*
|
||||
// const average = getAverageColour(pngData);
|
||||
// textureDetails[texture] = {
|
||||
// atlasColumn: offsetX,
|
||||
// atlasRow: offsetY,
|
||||
// colour: average,
|
||||
// std: getStandardDeviation(pngData, average),
|
||||
// };
|
||||
// */
|
||||
|
||||
++offsetX;
|
||||
if (offsetX >= atlasSize) {
|
||||
++offsetY;
|
||||
offsetX = 0;
|
||||
}
|
||||
});
|
||||
// ++offsetX;
|
||||
// if (offsetX >= atlasSize) {
|
||||
// ++offsetY;
|
||||
// offsetX = 0;
|
||||
// }
|
||||
// });
|
||||
|
||||
const atlasDir = PathUtil.join(AppPaths.Get.atlases, `./${atlasName}.png`);
|
||||
outputImage.save(atlasDir);
|
||||
}
|
||||
// const atlasDir = PathUtil.join(AppPaths.Get.atlases, `./${atlasName}.png`);
|
||||
// outputImage.save(atlasDir);
|
||||
// }
|
||||
|
||||
const modelDetails = new Array<{ name: string, faces: TFaceData<string>, colour: RGBA }>();
|
||||
{
|
||||
usedModels.forEach((model) => {
|
||||
const faceColours = Object.values(model.faces)
|
||||
.map((face) => textureDetails[face]!.colour);
|
||||
// const modelDetails = new Array<{ name: string, faces: TFaceData<string>, colour: RGBA }>();
|
||||
// {
|
||||
// usedModels.forEach((model) => {
|
||||
// const faceColours = Object.values(model.faces)
|
||||
// .map((face) => textureDetails[face]!.colour);
|
||||
|
||||
modelDetails.push({
|
||||
name: AppUtil.Text.namespaceBlock(model.name),
|
||||
faces: model.faces,
|
||||
colour: RGBAUtil.average(...faceColours),
|
||||
});
|
||||
});
|
||||
}
|
||||
// modelDetails.push({
|
||||
// name: AppUtil.Text.namespaceBlock(model.name),
|
||||
// faces: model.faces,
|
||||
// colour: RGBAUtil.average(...faceColours),
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
|
||||
const toExport: TAtlasVersion = {
|
||||
formatVersion: 3,
|
||||
atlasSize: atlasSize,
|
||||
blocks: modelDetails,
|
||||
textures: textureDetails,
|
||||
supportedBlockNames: modelDetails.map((model) => model.name),
|
||||
};
|
||||
// const toExport: TAtlasVersion = {
|
||||
// formatVersion: 3,
|
||||
// atlasSize: atlasSize,
|
||||
// blocks: modelDetails,
|
||||
// textures: textureDetails,
|
||||
// supportedBlockNames: modelDetails.map((model) => model.name),
|
||||
// };
|
||||
|
||||
fs.writeFileSync(path.join(AppPaths.Get.atlases, `./${atlasName}.atlas`), JSON.stringify(toExport, null, 4));
|
||||
}
|
||||
}();
|
||||
// fs.writeFileSync(path.join(AppPaths.Get.atlases, `./${atlasName}.atlas`), JSON.stringify(toExport, null, 4));
|
||||
// }
|
||||
// }();
|
||||
console.log('Unimplemented');
|
||||
|
@ -1,67 +1,68 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import prompt from 'prompt';
|
||||
// import fs from 'fs';
|
||||
// import path from 'path';
|
||||
// import prompt from 'prompt';
|
||||
|
||||
import { Palette } from '../src/palette';
|
||||
import { AppPaths, PathUtil } from '../src/util/path_util';
|
||||
import { log } from './logging';
|
||||
// import { Palette } from '../src/palette';
|
||||
// import { AppPaths, PathUtil } from '../src/util/path_util';
|
||||
// import { log } from './logging';
|
||||
|
||||
const PALETTE_NAME_REGEX = /^[a-zA-Z\-]+$/;
|
||||
// const PALETTE_NAME_REGEX = /^[a-zA-Z\-]+$/;
|
||||
|
||||
void async function main() {
|
||||
AppPaths.Get.setBaseDir(PathUtil.join(__dirname, '../..'));
|
||||
// void async function main() {
|
||||
// AppPaths.Get.setBaseDir(PathUtil.join(__dirname, '../..'));
|
||||
|
||||
log('Info', 'Creating a new palette...');
|
||||
// log('Info', 'Creating a new palette...');
|
||||
|
||||
const paletteBlocksDir = path.join(AppPaths.Get.tools, './new-palette-blocks.txt');
|
||||
if (!fs.existsSync(paletteBlocksDir)) {
|
||||
log('Failure', 'Could not find /tools/new-palette-blocks.txt');
|
||||
return;
|
||||
}
|
||||
log('Success', 'Found list of blocks to use in /tools/new-palette-blocks.txt');
|
||||
// const paletteBlocksDir = path.join(AppPaths.Get.tools, './new-palette-blocks.txt');
|
||||
// if (!fs.existsSync(paletteBlocksDir)) {
|
||||
// log('Failure', 'Could not find /tools/new-palette-blocks.txt');
|
||||
// return;
|
||||
// }
|
||||
// log('Success', 'Found list of blocks to use in /tools/new-palette-blocks.txt');
|
||||
|
||||
let blocksToUse: string[] = fs.readFileSync(paletteBlocksDir, 'utf8').replace(/\r/g, '').split('\n');
|
||||
blocksToUse = blocksToUse.filter((block) => {
|
||||
return block.length !== 0;
|
||||
});
|
||||
if (blocksToUse.length === 0) {
|
||||
log('Failure', 'No blocks listed for palette');
|
||||
log('Info', 'List the blocks you want from /tools/all-supported-blocks.txt ');
|
||||
return;
|
||||
}
|
||||
log('Info', `Found ${blocksToUse.length} blocks to use`);
|
||||
// let blocksToUse: string[] = fs.readFileSync(paletteBlocksDir, 'utf8').replace(/\r/g, '').split('\n');
|
||||
// blocksToUse = blocksToUse.filter((block) => {
|
||||
// return block.length !== 0;
|
||||
// });
|
||||
// if (blocksToUse.length === 0) {
|
||||
// log('Failure', 'No blocks listed for palette');
|
||||
// log('Info', 'List the blocks you want from /tools/all-supported-blocks.txt ');
|
||||
// return;
|
||||
// }
|
||||
// log('Info', `Found ${blocksToUse.length} blocks to use`);
|
||||
|
||||
const schema: prompt.Schema = {
|
||||
properties: {
|
||||
paletteName: {
|
||||
pattern: PALETTE_NAME_REGEX,
|
||||
description: 'What do you want to call this block palette? (e.g. my-block-palette)',
|
||||
message: 'Must be only letters or dash',
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
// const schema: prompt.Schema = {
|
||||
// properties: {
|
||||
// paletteName: {
|
||||
// pattern: PALETTE_NAME_REGEX,
|
||||
// description: 'What do you want to call this block palette? (e.g. my-block-palette)',
|
||||
// message: 'Must be only letters or dash',
|
||||
// required: true,
|
||||
// },
|
||||
// },
|
||||
// };
|
||||
|
||||
const promptUser = await prompt.get(schema);
|
||||
// const promptUser = await prompt.get(schema);
|
||||
|
||||
log('Info', 'Creating palette...');
|
||||
const palette = Palette.create();
|
||||
if (palette === undefined) {
|
||||
log('Failure', 'Invalid palette name');
|
||||
return;
|
||||
}
|
||||
// log('Info', 'Creating palette...');
|
||||
// const palette = Palette.create();
|
||||
// if (palette === undefined) {
|
||||
// log('Failure', 'Invalid palette name');
|
||||
// return;
|
||||
// }
|
||||
|
||||
log('Info', 'Adding blocks to palette...');
|
||||
for (const blockNames of blocksToUse) {
|
||||
palette.add(blockNames);
|
||||
}
|
||||
// log('Info', 'Adding blocks to palette...');
|
||||
// for (const blockNames of blocksToUse) {
|
||||
// palette.add(blockNames);
|
||||
// }
|
||||
|
||||
log('Info', 'Saving palette...');
|
||||
const success = palette.save(promptUser.paletteName as string);
|
||||
// log('Info', 'Saving palette...');
|
||||
// const success = palette.save(promptUser.paletteName as string);
|
||||
|
||||
if (success) {
|
||||
log('Success', 'Palette saved.');
|
||||
} else {
|
||||
log('Failure', 'Could not save palette.');
|
||||
}
|
||||
}();
|
||||
// if (success) {
|
||||
// log('Success', 'Palette saved.');
|
||||
// } else {
|
||||
// log('Failure', 'Could not save palette.');
|
||||
// }
|
||||
// }();
|
||||
console.log('Unimplemented');
|
||||
|
@ -1,6 +1,4 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { PNG } from 'pngjs';
|
||||
import prompt from 'prompt';
|
||||
|
||||
import { RGBA } from '../src/colour';
|
||||
@ -13,26 +11,10 @@ export const ASSERT = (condition: boolean, onFailMessage: string) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const ASSERT_EXISTS = (path: fs.PathLike) => {
|
||||
clog(
|
||||
fs.existsSync(path),
|
||||
`Found '${path}'`,
|
||||
`Could not find '${path}'`,
|
||||
);
|
||||
};
|
||||
|
||||
export function isDirSetup(absolutePath: string) {
|
||||
if (fs.existsSync(absolutePath)) {
|
||||
if (fs.readdirSync(absolutePath).length > 0) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
fs.mkdirSync(absolutePath);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
type PNG = {};
|
||||
|
||||
export function getAverageColour(image: PNG): RGBA {
|
||||
/*
|
||||
let r = 0;
|
||||
let g = 0;
|
||||
let b = 0;
|
||||
@ -57,9 +39,14 @@ export function getAverageColour(image: PNG): RGBA {
|
||||
b: b / weight,
|
||||
a: a / numPixels,
|
||||
};
|
||||
*/
|
||||
return { r: 0, g: 0, b: 0, a: 0 };
|
||||
}
|
||||
|
||||
|
||||
export function getStandardDeviation(image: PNG, average: RGBA): number {
|
||||
return 0; // TODO Unimplemented
|
||||
/*
|
||||
let squaredDist = 0.0;
|
||||
let weight = 0.0;
|
||||
for (let x = 0; x < image.width; ++x) {
|
||||
@ -75,6 +62,7 @@ export function getStandardDeviation(image: PNG, average: RGBA): number {
|
||||
}
|
||||
}
|
||||
return Math.sqrt(squaredDist / weight);
|
||||
*/
|
||||
}
|
||||
|
||||
export async function getPermission() {
|
||||
|
@ -1,12 +1,10 @@
|
||||
import { LOG_MAJOR, Logger } from '../src/util/log_util';
|
||||
import { LOG_MAJOR } from '../src/util/log_util';
|
||||
import { AppPaths, PathUtil } from '../src/util/path_util';
|
||||
import { runHeadless } from './headless';
|
||||
import { headlessConfig } from './headless-config';
|
||||
|
||||
void async function main() {
|
||||
AppPaths.Get.setBaseDir(PathUtil.join(__dirname, '../..'));
|
||||
Logger.Get.enableLogToFile();
|
||||
Logger.Get.initLogFile('headless');
|
||||
|
||||
runHeadless(headlessConfig);
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
"incremental": true, /* Enable incremental compilation */
|
||||
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
||||
//"resolveJsonModule": true,
|
||||
// "resolveJsonModule": true,
|
||||
// "lib": [], /* Specify library files to be included in the compilation. */
|
||||
"allowJs": true, /* Allow javascript files to be compiled. */
|
||||
// "checkJs": true, /* Report errors in .js files. */
|
||||
|
33
webpack.common.js
Normal file
@ -0,0 +1,33 @@
|
||||
const path = require('path');
|
||||
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');
|
||||
|
||||
module.exports = {
|
||||
entry: './src/client.ts',
|
||||
plugins: [
|
||||
new NodePolyfillPlugin(),
|
||||
],
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.css$/i,
|
||||
use: ['style-loader', 'css-loader'],
|
||||
},
|
||||
{
|
||||
test: /\.vs|fs$/,
|
||||
use: 'raw-loader',
|
||||
},
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: 'ts-loader',
|
||||
exclude: /node_modules|main\.ts/,
|
||||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.tsx', '.ts', '.js'],
|
||||
},
|
||||
output: {
|
||||
filename: 'bundle.js',
|
||||
path: path.resolve(__dirname, './webpack'),
|
||||
},
|
||||
};
|
14
webpack.dev.js
Normal file
@ -0,0 +1,14 @@
|
||||
const { merge } = require('webpack-merge');
|
||||
const common = require('./webpack.common.js');
|
||||
const path = require('path');
|
||||
|
||||
module.exports = merge(common, {
|
||||
mode: 'development',
|
||||
devtool: 'eval-source-map',
|
||||
devServer: {
|
||||
static: {
|
||||
directory: path.join(__dirname, './webpack'),
|
||||
},
|
||||
hot: true,
|
||||
},
|
||||
});
|
9
webpack.prod.js
Normal file
@ -0,0 +1,9 @@
|
||||
const { merge } = require('webpack-merge');
|
||||
const common = require('./webpack.common.js');
|
||||
|
||||
module.exports = merge(common, {
|
||||
mode: 'production',
|
||||
performance: {
|
||||
hints: false,
|
||||
},
|
||||
});
|
@ -2,8 +2,8 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<link rel="stylesheet" href="./styles.css">
|
||||
<meta charset="utf8">
|
||||
<title>ObjToSchematic Web</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@ -18,11 +18,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script type="module" src="bundle.js"></script>
|
||||
</body>
|
||||
|
||||
<script>
|
||||
require("./dist/src/client.js");
|
||||
</script>
|
||||
|
||||
</html>
|