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**
* ✔️ Model PSR, ✔️ voxel size preview ✔️ limit warnings
* ✔️ **.mtl support for block choice**
* ✔️ PNG support, ✔️ JPEG support
* ✔️ **Convert to TypeScript**
* ⌛ Block choice exported

View File

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

View File

@ -1,24 +1,31 @@
//const fs = require("fs");
//const png = require("pngjs").PNG;
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 { clamp } from "./math";
import { TextureFormat } from "./mesh";
export class Texture {
private _image: PNGWithMetadata;
private _image: {
data: Buffer,
width: number,
height: number
};
constructor(filename: string) {
constructor(filename: string, format: TextureFormat) {
try {
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) {
throw Error(`Could not read ${filename}`);
}
if (this._image.bpp !== 4) {
throw Error("Image must be RBGA format");
throw Error(`Could not parse ${filename}`);
}
}
@ -28,15 +35,14 @@ export class Texture {
const x = Math.floor(uv.u * this._image.width);
const y = Math.floor(uv.v * this._image.height);
const index = this._image.bpp * (this._image.width * y + x);
const rgba = this._image.data.slice(index, index + this._image.bpp)
const index = 4 * (this._image.width * y + x);
const rgba = this._image.data.slice(index, index + 4)
return {
r: rgba[0]/255,
g: rgba[1]/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 { HashSet, HashMap } from "./hash_map";
import { HashSet } from "./hash_map";
import { Texture } from "./texture";
import { BlockAtlas } from "./block_atlas";
import { UV, RGB } from "./util";
@ -360,8 +360,8 @@ export class VoxelManager {
const materialTriangles = mesh.materialTriangles[materialName];
// Setup material
if (materialTriangles.material.type === MaterialType.Texture) {
this._currentTexture = new Texture(materialTriangles.material.texturePath);
this._blockMode = MaterialType.Texture;
this._currentTexture = new Texture(materialTriangles.material.texturePath, materialTriangles.material.format);
} else {
this._currentColour = materialTriangles.material.diffuseColour;
this._blockMode = MaterialType.Fill;