mirror of
https://github.com/LucasDower/ObjToSchematic.git
synced 2025-12-11 20:15:30 +01:00
Added support for .tga textures
This commit is contained in:
parent
17e7d0ab59
commit
08aafe046b
1
.gitignore
vendored
1
.gitignore
vendored
@ -9,6 +9,7 @@ ObjToSchematic-darwin-x64
|
||||
/res/palettes/empty.palette
|
||||
/dist
|
||||
/dev
|
||||
/gen
|
||||
/tools/blocks
|
||||
/tools/models
|
||||
/tests/out
|
||||
|
||||
62
package-lock.json
generated
62
package-lock.json
generated
@ -13,6 +13,7 @@
|
||||
"jpeg-js": "^0.4.4",
|
||||
"pngjs": "^6.0.0",
|
||||
"prismarine-nbt": "^1.6.0",
|
||||
"tga": "^1.0.7",
|
||||
"twgl.js": "^4.19.1",
|
||||
"varint-array": "^0.0.0"
|
||||
},
|
||||
@ -6629,6 +6630,11 @@
|
||||
"lowercase-keys": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/restructure": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/restructure/-/restructure-2.0.1.tgz",
|
||||
"integrity": "sha512-e0dOpjm5DseomnXx2M5lpdZ5zoHqF1+bqdMJUohoYVVQa7cBdnk7fdmeI6byNWP/kiME72EeTiSypTCVnpLiDg=="
|
||||
},
|
||||
"node_modules/reusify": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
|
||||
@ -7257,6 +7263,31 @@
|
||||
"integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/tga": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/tga/-/tga-1.0.7.tgz",
|
||||
"integrity": "sha512-GFVJwov5aJTMgh8U1QfaRheIELXo+dYc1qYIvQEIqZX4n+S6Fj/SDWsdbelHt7WP08xOR6W1z5aJQ+Ilh5gIeA==",
|
||||
"dependencies": {
|
||||
"debug": "^2.6.1",
|
||||
"restructure": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tga/node_modules/debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"dependencies": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tga/node_modules/ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
},
|
||||
"node_modules/throat": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz",
|
||||
@ -13020,6 +13051,11 @@
|
||||
"lowercase-keys": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"restructure": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/restructure/-/restructure-2.0.1.tgz",
|
||||
"integrity": "sha512-e0dOpjm5DseomnXx2M5lpdZ5zoHqF1+bqdMJUohoYVVQa7cBdnk7fdmeI6byNWP/kiME72EeTiSypTCVnpLiDg=="
|
||||
},
|
||||
"reusify": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
|
||||
@ -13481,6 +13517,30 @@
|
||||
"integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
|
||||
"dev": true
|
||||
},
|
||||
"tga": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/tga/-/tga-1.0.7.tgz",
|
||||
"integrity": "sha512-GFVJwov5aJTMgh8U1QfaRheIELXo+dYc1qYIvQEIqZX4n+S6Fj/SDWsdbelHt7WP08xOR6W1z5aJQ+Ilh5gIeA==",
|
||||
"requires": {
|
||||
"debug": "^2.6.1",
|
||||
"restructure": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"throat": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz",
|
||||
@ -13978,4 +14038,4 @@
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,7 +62,8 @@
|
||||
"jpeg-js": "^0.4.4",
|
||||
"pngjs": "^6.0.0",
|
||||
"prismarine-nbt": "^1.6.0",
|
||||
"tga": "^1.0.7",
|
||||
"twgl.js": "^4.19.1",
|
||||
"varint-array": "^0.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,6 +18,7 @@ import { UI } from './ui/layout';
|
||||
import { UIMessageBuilder, UITreeBuilder } 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, PathUtil } from './util/path_util';
|
||||
import { Vector3 } from './vector';
|
||||
@ -42,6 +43,8 @@ export class AppContext {
|
||||
|
||||
AppConfig.Get.dumpConfig();
|
||||
|
||||
FileUtil.rmdirIfExist(AppPaths.Get.gen);
|
||||
|
||||
const gl = (<HTMLCanvasElement>document.getElementById('canvas')).getContext('webgl');
|
||||
if (!gl) {
|
||||
throw Error('Could not load WebGL context');
|
||||
|
||||
11
src/mesh.ts
11
src/mesh.ts
@ -4,7 +4,7 @@ import path from 'path';
|
||||
import { Bounds } from './bounds';
|
||||
import { RGBA, RGBAColours, RGBAUtil } from './colour';
|
||||
import { StatusHandler } from './status';
|
||||
import { Texture, TextureFiltering } from './texture';
|
||||
import { Texture, TextureConverter, TextureFiltering } from './texture';
|
||||
import { Triangle, UVTriangle } from './triangle';
|
||||
import { getRandomID, UV } from './util';
|
||||
import { AppError, ASSERT } from './util/error_util';
|
||||
@ -215,10 +215,6 @@ export class Mesh {
|
||||
if (material.type === MaterialType.textured) {
|
||||
ASSERT(path.isAbsolute(material.path), 'Material texture path not absolute');
|
||||
if (!fs.existsSync(material.path)) {
|
||||
//StatusHandler.Get.add(
|
||||
// 'warning',
|
||||
// `Could not find ${material.path}`,
|
||||
//);
|
||||
LOG_WARN(`Could not find ${material.path} for material ${materialName}, changing to solid-white material`);
|
||||
this._materials[materialName] = {
|
||||
type: MaterialType.solid,
|
||||
@ -227,6 +223,11 @@ export class Mesh {
|
||||
canBeTextured: true,
|
||||
set: false,
|
||||
};
|
||||
} else {
|
||||
const parsedPath = path.parse(material.path);
|
||||
if (parsedPath.ext === '.tga') {
|
||||
material.path = TextureConverter.createPNGfromTGA(material.path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,13 +2,16 @@ 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';
|
||||
import { AppConfig } from './config';
|
||||
import { clamp, wayThrough } from './math';
|
||||
import { UV } from './util';
|
||||
import { AppError, ASSERT } from './util/error_util';
|
||||
import { LOG, LOG_ERROR } from './util/log_util';
|
||||
import { FileUtil } from './util/file_util';
|
||||
import { LOG, LOG_ERROR, LOGF } from './util/log_util';
|
||||
import { AppPaths } from './util/path_util';
|
||||
|
||||
/* eslint-disable */
|
||||
export enum TextureFormat {
|
||||
@ -49,15 +52,31 @@ export class Texture {
|
||||
const filePath = path.parse(filename);
|
||||
try {
|
||||
const data = fs.readFileSync(filename);
|
||||
if (filePath.ext.toLowerCase() === '.png') {
|
||||
return PNG.sync.read(data);
|
||||
} else if (['.jpg', '.jpeg'].includes(filePath.ext.toLowerCase())) {
|
||||
this._useAlphaChannelValue = false;
|
||||
return jpeg.decode(data, {
|
||||
maxMemoryUsageInMB: AppConfig.Get.MAXIMUM_IMAGE_MEM_ALLOC,
|
||||
});
|
||||
|
||||
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,
|
||||
});
|
||||
}
|
||||
/*
|
||||
case '.tga': {
|
||||
const tga = new TGA(data);
|
||||
return {
|
||||
width: tga.width,
|
||||
height: tga.height,
|
||||
data: tga.pixels,
|
||||
};
|
||||
}
|
||||
*/
|
||||
default:
|
||||
ASSERT(false, 'Unsupported image format');
|
||||
}
|
||||
ASSERT(false);
|
||||
} catch (err) {
|
||||
LOG_ERROR(err);
|
||||
throw new AppError(`Could not read ${filename}`);
|
||||
@ -165,3 +184,24 @@ export class Texture {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class TextureConverter {
|
||||
public static createPNGfromTGA(filepath: string): string {
|
||||
ASSERT(fs.existsSync(filepath), '.tga does not exist');
|
||||
const parsed = path.parse(filepath);
|
||||
ASSERT(parsed.ext === '.tga');
|
||||
const data = fs.readFileSync(filepath);
|
||||
const tga = new TGA(data);
|
||||
const png = new PNG({
|
||||
width: tga.width,
|
||||
height: tga.height,
|
||||
});
|
||||
png.data = tga.pixels;
|
||||
FileUtil.mkdirIfNotExist(AppPaths.Get.gen);
|
||||
const buffer = PNG.sync.write(png);
|
||||
const newTexturePath = path.join(AppPaths.Get.gen, parsed.name + '.gen.png');
|
||||
LOGF(`Creating new generated texture of '${filepath}' at '${newTexturePath}'`);
|
||||
fs.writeFileSync(newTexturePath, buffer);
|
||||
return newTexturePath;
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,7 +80,7 @@ export class TextureMaterialUIElement extends MaterialUIElement {
|
||||
buttonLabel: 'Load',
|
||||
filters: [{
|
||||
name: 'Images',
|
||||
extensions: ['png', 'jpeg', 'jpg'],
|
||||
extensions: ['png', 'jpeg', 'jpg', 'tga'],
|
||||
}],
|
||||
});
|
||||
if (files && files[0]) {
|
||||
|
||||
@ -1,17 +1,25 @@
|
||||
import child from 'child_process';
|
||||
import fs from 'fs';
|
||||
import { LOGF } from './log_util';
|
||||
|
||||
export namespace FileUtil {
|
||||
export function fileExists(absolutePath: string) {
|
||||
return fs.existsSync(absolutePath);
|
||||
}
|
||||
|
||||
export function mkdirSyncIfNotExist(path: fs.PathLike) {
|
||||
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':
|
||||
|
||||
@ -79,7 +79,7 @@ export const TIME_END = (label: string) => {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Logs an error to the console and file, always.
|
||||
*/
|
||||
export const LOG_ERROR = (...data: any[]) => {
|
||||
@ -122,7 +122,7 @@ export class Logger {
|
||||
*/
|
||||
public initLogFile(suffix: string) {
|
||||
if (this._logStream === undefined && this._enabledLogToFile === true) {
|
||||
FileUtil.mkdirSyncIfNotExist(AppPaths.Get.logs);
|
||||
FileUtil.mkdirIfNotExist(AppPaths.Get.logs);
|
||||
this._logStream = fs.createWriteStream(PathUtil.join(AppPaths.Get.logs, `./${Date.now()}-${suffix}.log`));
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,4 +64,13 @@ export class AppPaths {
|
||||
public get logs() {
|
||||
return PathUtil.join(this._base, './logs/');
|
||||
}
|
||||
|
||||
/**
|
||||
* The `gen` directory stores any data generated at runtime.
|
||||
* This can safely be deleted when the program is not running and will
|
||||
* be empted upon each startup.
|
||||
*/
|
||||
public get gen() {
|
||||
return PathUtil.join(this._base, './gen/');
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,5 +5,5 @@ import { AppPaths, PathUtil } from '../src/util/path_util';
|
||||
export const TEST_PREAMBLE = () => {
|
||||
Logger.Get.disableLogToFile();
|
||||
AppPaths.Get.setBaseDir(PathUtil.join(__dirname, '..'));
|
||||
FileUtil.mkdirSyncIfNotExist(PathUtil.join(AppPaths.Get.tests, './out/'));
|
||||
FileUtil.mkdirIfNotExist(PathUtil.join(AppPaths.Get.tests, './out/'));
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user