Added JPEG support

This commit is contained in:
Lucas Dower 2021-08-20 15:41:02 +01:00
parent a03e3632d5
commit 62cde694dc
4 changed files with 47 additions and 26 deletions

View File

@ -29,6 +29,7 @@ A tool to convert .obj files into Minecraft Schematics.
* ✔️ **Quality of life** * ✔️ **Quality of life**
* ✔️ Model PSR, ✔️ voxel size preview ✔️ limit warnings * ✔️ Model PSR, ✔️ voxel size preview ✔️ limit warnings
* ✔️ **.mtl support for block choice** * ✔️ **.mtl support for block choice**
* ✔️ PNG support, ✔️ JPEG support
* ✔️ **Convert to TypeScript** * ✔️ **Convert to TypeScript**
* ⌛ Block choice exported * ⌛ Block choice exported

View File

@ -7,7 +7,12 @@ const expandVertexData: any = require("expand-vertex-data");
import { Triangle } from "./triangle"; import { Triangle } from "./triangle";
import { Vector3 } from "./vector"; import { Vector3 } from "./vector";
import { RGB } from "./util"; import { RGB } from "./util";
import { Texture } from "./texture";
export enum TextureFormat {
PNG,
JPEG
}
interface objData { interface objData {
vertexNormals: Array<number>; vertexNormals: Array<number>;
@ -31,7 +36,8 @@ export interface FillMaterial {
export interface TextureMaterial { export interface TextureMaterial {
readonly type: MaterialType.Texture readonly type: MaterialType.Texture
texturePath: string, texturePath: string,
texture?: WebGLTexture texture?: WebGLTexture,
format: TextureFormat
} }
export enum MaterialType { export enum MaterialType {
@ -112,12 +118,13 @@ export class Mesh {
this._loadTextures(materials); this._loadTextures(materials);
} }
private _addMaterial(materialsJSON: Materials, materialName: string, materialDiffuseColour: RGB, materialDiffuseTexturePath: string) { private _addMaterial(materialsJSON: Materials, materialName: string, materialDiffuseColour: RGB, materialDiffuseTexturePath: string, materialFormat: TextureFormat) {
console.log(materialName, materialDiffuseColour, materialDiffuseTexturePath); console.log(materialName, materialDiffuseColour, materialDiffuseTexturePath);
if (materialDiffuseTexturePath !== "") { if (materialDiffuseTexturePath !== "") {
materialsJSON[materialName] = { materialsJSON[materialName] = {
texturePath: materialDiffuseTexturePath, texturePath: materialDiffuseTexturePath,
type: MaterialType.Texture type: MaterialType.Texture,
format: materialFormat
}; };
} else if (materialName !== "") { } else if (materialName !== "") {
materialsJSON[materialName] = { materialsJSON[materialName] = {
@ -127,6 +134,7 @@ export class Mesh {
} }
} }
// TODO: Rewrite
private _parseMaterial(materialString: string): Materials { private _parseMaterial(materialString: string): Materials {
var materialsJSON: Materials = {}; var materialsJSON: Materials = {};
@ -135,6 +143,7 @@ export class Mesh {
let materialName: string = ""; let materialName: string = "";
let materialDiffuseColour: RGB = {r: 1.0, g: 1.0, b: 1.0}; let materialDiffuseColour: RGB = {r: 1.0, g: 1.0, b: 1.0};
let materialDiffuseTexturePath: string = ""; let materialDiffuseTexturePath: string = "";
let materialTextureFormat: TextureFormat = TextureFormat.PNG;
for (let i = 0; i < lines.length; ++i) { for (let i = 0; i < lines.length; ++i) {
const line = lines[i]; const line = lines[i];
@ -142,7 +151,7 @@ export class Mesh {
switch (lineTokens[0]) { switch (lineTokens[0]) {
case "newmtl": case "newmtl":
this._addMaterial(materialsJSON, materialName, materialDiffuseColour, materialDiffuseTexturePath); this._addMaterial(materialsJSON, materialName, materialDiffuseColour, materialDiffuseTexturePath, materialTextureFormat);
materialName = lineTokens[1]; materialName = lineTokens[1];
materialDiffuseColour = {r: 0, g: 0, b: 0}; materialDiffuseColour = {r: 0, g: 0, b: 0};
materialDiffuseTexturePath = "" materialDiffuseTexturePath = ""
@ -174,8 +183,13 @@ export class Mesh {
throw Error(`Cannot load texture ${texturePath}`); throw Error(`Cannot load texture ${texturePath}`);
} }
const _path = path.parse(texturePath); const _path = path.parse(texturePath);
if (_path.ext.toLowerCase() != ".png") { if (".png" === _path.ext.toLowerCase()) {
throw Error(`Can only load .png textures`); materialTextureFormat = TextureFormat.PNG;
}
else if ([".jpeg", ".jpg"].includes(_path.ext.toLowerCase())) {
materialTextureFormat = TextureFormat.JPEG;
} else {
throw Error(`Can only load PNG and JPEG textures`);
} }
materialDiffuseTexturePath = texturePath; materialDiffuseTexturePath = texturePath;
@ -183,7 +197,7 @@ export class Mesh {
} }
} }
this._addMaterial(materialsJSON, materialName, materialDiffuseColour, materialDiffuseTexturePath); this._addMaterial(materialsJSON, materialName, materialDiffuseColour, materialDiffuseTexturePath, materialTextureFormat);
return materialsJSON; return materialsJSON;
} }

View File

@ -1,24 +1,31 @@
//const fs = require("fs");
//const png = require("pngjs").PNG;
import * as fs from "fs"; import * as fs from "fs";
import { PNG, PNGWithMetadata } from "pngjs"; import * as jpeg from "jpeg-js";
import { PNG } from "pngjs";
import { UV, RGBA } from "./util"; import { UV, RGBA } from "./util";
import { clamp } from "./math"; import { TextureFormat } from "./mesh";
export class Texture { export class Texture {
private _image: PNGWithMetadata; private _image: {
data: Buffer,
width: number,
height: number
};
constructor(filename: string) { constructor(filename: string, format: TextureFormat) {
try { try {
const data = fs.readFileSync(filename); const data = fs.readFileSync(filename);
this._image = PNG.sync.read(data); if (format === TextureFormat.PNG) {
this._image = PNG.sync.read(data);
} else {
this._image = jpeg.decode(data);
}
if (this._image.width * this._image.height * 4 !== this._image.data.length) {
throw Error();
}
} catch (err) { } catch (err) {
throw Error(`Could not read ${filename}`); throw Error(`Could not parse ${filename}`);
}
if (this._image.bpp !== 4) {
throw Error("Image must be RBGA format");
} }
} }
@ -28,15 +35,14 @@ export class Texture {
const x = Math.floor(uv.u * this._image.width); const x = Math.floor(uv.u * this._image.width);
const y = Math.floor(uv.v * this._image.height); const y = Math.floor(uv.v * this._image.height);
const index = this._image.bpp * (this._image.width * y + x); const index = 4 * (this._image.width * y + x);
const rgba = this._image.data.slice(index, index + this._image.bpp) const rgba = this._image.data.slice(index, index + 4)
return { return {
r: rgba[0]/255, r: rgba[0]/255,
g: rgba[1]/255, g: rgba[1]/255,
b: rgba[2]/255, b: rgba[2]/255,
a: rgba[3]/255 a: 1.0
}; };
} }
} }

View File

@ -1,6 +1,6 @@
import { AABB, CubeAABB } from "./aabb"; import { CubeAABB } from "./aabb";
import { Vector3 } from "./vector.js"; import { Vector3 } from "./vector.js";
import { HashSet, HashMap } from "./hash_map"; import { HashSet } from "./hash_map";
import { Texture } from "./texture"; import { Texture } from "./texture";
import { BlockAtlas } from "./block_atlas"; import { BlockAtlas } from "./block_atlas";
import { UV, RGB } from "./util"; import { UV, RGB } from "./util";
@ -360,8 +360,8 @@ export class VoxelManager {
const materialTriangles = mesh.materialTriangles[materialName]; const materialTriangles = mesh.materialTriangles[materialName];
// Setup material // Setup material
if (materialTriangles.material.type === MaterialType.Texture) { if (materialTriangles.material.type === MaterialType.Texture) {
this._currentTexture = new Texture(materialTriangles.material.texturePath);
this._blockMode = MaterialType.Texture; this._blockMode = MaterialType.Texture;
this._currentTexture = new Texture(materialTriangles.material.texturePath, materialTriangles.material.format);
} else { } else {
this._currentColour = materialTriangles.material.diffuseColour; this._currentColour = materialTriangles.material.diffuseColour;
this._blockMode = MaterialType.Fill; this._blockMode = MaterialType.Fill;