Swap material types, change solid material colour

This commit is contained in:
Lucas Dower 2022-11-12 20:59:48 +00:00
parent 8f0b2ed131
commit 9a38dd8207
No known key found for this signature in database
GPG Key ID: B3EE6B8499593605
4 changed files with 146 additions and 50 deletions

View File

@ -3,12 +3,12 @@ import path from 'path';
import { FallableBehaviour } from './block_mesh';
import { ArcballCamera } from './camera';
import { RGBAUtil } from './colour';
import { RGBAColours, RGBAUtil, RGBA } from './colour';
import { AppConfig } from './config';
import { EAppEvent, EventManager } from './event';
import { IExporter } from './exporters/base_exporter';
import { ExporterFactory, TExporters } from './exporters/exporters';
import { MaterialMap, MaterialType, TexturedMaterial } from './mesh';
import { MaterialMap, MaterialType, TexturedMaterial, SolidMaterial } from './mesh';
import { Renderer } from './renderer';
import { StatusHandler, StatusMessage } from './status';
import { TextureFiltering } from './texture';
@ -20,7 +20,7 @@ import { ASSERT } from './util/error_util';
import { FileUtil } from './util/file_util';
import { LOG, LOG_ERROR, Logger } from './util/log_util';
import { TWorkerJob, WorkerController } from './worker_controller';
import { TFromWorkerMessage, TToWorkerMessage } from './worker_types';
import { SetMaterialsParams, TFromWorkerMessage, TToWorkerMessage } from './worker_types';
export class AppContext {
private _ui: UI;
@ -202,17 +202,7 @@ export class AppContext {
return { id: 'Import', payload: payload, callback: callback };
}
private _onMaterialTextureReplace(materialName: string, newTexturePath: string) {
const oldMaterial = this._materialMap[materialName];
ASSERT(oldMaterial.type === MaterialType.textured);
this._materialMap[materialName] = {
type: MaterialType.textured,
alphaFactor: oldMaterial.alphaFactor,
alphaPath: oldMaterial.alphaPath,
path: newTexturePath,
};
private _sendMaterialsToWorker(callback: (result: SetMaterialsParams.Output) => void) {
const payload: TToWorkerMessage = {
action: 'SetMaterials',
params: {
@ -227,8 +217,8 @@ export class AppContext {
// TODO: Check the action didn't fail
this._materialMap = result.result.materials;
this._onMaterialMapChanged();
Renderer.Get.updateMeshMaterialTexture(materialName, result.result.materials[materialName] as TexturedMaterial);
this._ui.enableTo(EAction.Voxelise);
callback(result.result);
},
};
@ -236,6 +226,50 @@ export class AppContext {
this._ui.disableAll();
}
private _onMaterialTypeSwitched(materialName: string) {
const oldMaterial = this._materialMap[materialName];
if (oldMaterial.type == MaterialType.textured) {
this._materialMap[materialName] = {
type: MaterialType.solid,
colour: RGBAUtil.copy(RGBAColours.WHITE),
};
}
this._sendMaterialsToWorker((result: SetMaterialsParams.Output) => {
// TODO: Check the action didn't fail
Renderer.Get.recreateMaterialBuffer(materialName, result.materials[materialName]);
});
}
private _onMaterialTextureReplace(materialName: string, newTexturePath: string) {
const oldMaterial = this._materialMap[materialName];
ASSERT(oldMaterial.type === MaterialType.textured);
this._materialMap[materialName] = {
type: MaterialType.textured,
alphaFactor: oldMaterial.alphaFactor,
alphaPath: oldMaterial.alphaPath,
path: newTexturePath,
};
this._sendMaterialsToWorker((result: SetMaterialsParams.Output) => {
Renderer.Get.updateMeshMaterialTexture(materialName, result.materials[materialName] as TexturedMaterial);
});
}
private _onMaterialColourChanged(materialName: string, newColour: RGBA) {
ASSERT(this._materialMap[materialName].type === MaterialType.solid);
this._materialMap[materialName] = {
type: MaterialType.solid,
colour: newColour,
};
this._sendMaterialsToWorker((result: SetMaterialsParams.Output) => {
Renderer.Get.recreateMaterialBuffer(materialName, result.materials[materialName] as SolidMaterial);
});
}
private _onMaterialMapChanged() {
// Add material information to the output log
const outputElement = this._ui.getActionOutput(EAction.Import);
@ -250,21 +284,41 @@ export class AppContext {
const subTree = UITreeBuilder.create(materialName);
if (material.type === MaterialType.solid) {
subTree.addChild({ text: `Colour: ${RGBAUtil.toUint8String(material.colour)}`, warning: false });
const colourId = getRandomID();
subTree.addChild({ text: `Colour: <input type="color" id="${colourId}" value="${RGBAUtil.toHexString(material.colour)}">`, warning: false }, () => {
const tmp = document.getElementById(colourId) as HTMLInputElement;
if (tmp) {
tmp.addEventListener('change', () => {
const newColour = RGBAUtil.fromHexString(tmp.value);
this._onMaterialColourChanged(materialName, newColour);
});
}
});
} else {
const parsedPath = path.parse(material.path);
const dirId = getRandomID();
const replaceId = getRandomID();
const switchId = getRandomID();
if (parsedPath.base !== 'debug.png') {
subTree.addChild({ text: `Texture: <a id="${dirId}">${parsedPath.base}</a> <a id="${replaceId}">[Replace]</a>`, warning: false }, () => {
const isMissingTexture = parsedPath.base === 'debug.png';
if (!isMissingTexture) {
subTree.addChild({ text: `Texture: <a id="${dirId}">${parsedPath.base}</a>`, warning: false }, () => {
const tmp = document.getElementById(dirId) as HTMLLinkElement;
tmp.onclick = () => {
FileUtil.openDir(material.path);
};
if (tmp) {
tmp.onclick = () => {
FileUtil.openDir(material.path);
};
}
});
} else {
subTree.addChild({ text: `Texture: Missing`, warning: true });
}
const tmp2 = document.getElementById(replaceId) as HTMLLinkElement;
tmp2.onclick = () => {
// Add option to replace texture
subTree.addChild({ text: `<a id="${replaceId}">[${isMissingTexture ? 'Find' : 'Replace' } Texture]</a>`, warning: false }, () => {
const tmp = document.getElementById(replaceId) as HTMLLinkElement;
if (tmp) {
tmp.onclick = () => {
const files = remote.dialog.showOpenDialogSync({
title: 'Load',
buttonLabel: 'Load',
@ -277,25 +331,16 @@ export class AppContext {
this._onMaterialTextureReplace(materialName, files[0]);
}
};
});
} else {
subTree.addChild({ text: `Texture: MISSING <a id="${replaceId}">[Find]</a>`, warning: true }, () => {
const tmp = document.getElementById(replaceId) as HTMLLinkElement;
tmp.onclick = () => {
const files = remote.dialog.showOpenDialogSync({
title: 'Load ',
buttonLabel: 'Load',
filters: [{
name: 'Images',
extensions: ['png', 'jpeg', 'jpg'],
}],
});
if (files && files[0]) {
this._onMaterialTextureReplace(materialName, files[0]);
}
};
});
}
}
});
// Add option to switch to colour material
subTree.addChild({ text: `<a id="${switchId}">[Switch to Colour]</a>`, warning: false }, () => {
const tmp = document.getElementById(switchId) as HTMLLinkElement;
tmp.onclick = () => {
this._onMaterialTypeSwitched(materialName);
};
});
}
tree.addChild(subTree);

View File

@ -12,6 +12,19 @@ export namespace RGBAUtil {
return `(${a.r}, ${a.g}, ${a.b}, ${a.a})`;
}
export function toHexString(a: RGBA) {
return `#${Math.floor(255 * a.r).toString(16)}${Math.floor(255 * a.g).toString(16)}${Math.floor(255 * a.b).toString(16)}`;
}
export function fromHexString(str: string) {
return {
r: parseInt(str.substring(1, 3), 16) / 255,
g: parseInt(str.substring(3, 5), 16) / 255,
b: parseInt(str.substring(5, 7), 16) / 255,
a: 1.0,
};
}
export function toUint8String(a: RGBA) {
return `(${Math.floor(255 * a.r)}, ${Math.floor(255 * a.g)}, ${Math.floor(255 * a.b)}, ${Math.floor(255 * a.a)})`;
}

View File

@ -7,6 +7,7 @@ import { MaterialType, SolidMaterial, TexturedMaterial } from './mesh';
import { RenderBuffer } from './render_buffer';
import { ShaderManager } from './shaders';
import { Texture } from './texture';
import { ASSERT } from './util/error_util';
import { Vector3 } from './vector';
import { RenderBlockMeshParams, RenderMeshParams, RenderVoxelMeshParams } from './worker_types';
@ -45,7 +46,7 @@ export class Renderer {
private _modelsAvailable: number;
private _materialBuffers: Array<{
private _materialBuffers: Map<string, {
material: SolidMaterial | (TexturedMaterial & TextureMaterialRenderAddons)
buffer: twgl.BufferInfo,
numElements: number,
@ -79,7 +80,7 @@ export class Renderer {
twgl.addExtensionsToContext(this._gl);
this._modelsAvailable = 0;
this._materialBuffers = [];
this._materialBuffers = new Map();
this._gridBuffers = { x: {}, y: {}, z: {} };
this._gridEnabled = true;
@ -158,12 +159,45 @@ export class Renderer {
}
public clearMesh() {
this._materialBuffers = [];
this._materialBuffers = new Map();
this._modelsAvailable = 0;
this.setModelToUse(MeshType.None);
}
public recreateMaterialBuffer(materialName: string, material: SolidMaterial | TexturedMaterial) {
const oldBuffer = this._materialBuffers.get(materialName);
ASSERT(oldBuffer !== undefined);
if (material.type === MaterialType.solid) {
this._materialBuffers.set(materialName, {
buffer: oldBuffer.buffer,
material: material,
numElements: oldBuffer.numElements,
materialName: materialName,
});
} else {
this._materialBuffers.set(materialName, {
buffer: oldBuffer.buffer,
material: {
type: MaterialType.textured,
path: material.path,
texture: twgl.createTexture(this._gl, {
src: material.path,
mag: this._gl.LINEAR,
}),
alphaFactor: material.alphaFactor,
alpha: material.alphaPath ? twgl.createTexture(this._gl, {
src: material.alphaPath,
mag: this._gl.LINEAR,
}) : undefined,
useAlphaChannel: material.alphaPath ? new Texture(material.path, material.alphaPath)._useAlphaChannel() : undefined,
},
numElements: oldBuffer.numElements,
materialName: materialName,
});
}
}
public updateMeshMaterialTexture(materialName: string, material: TexturedMaterial) {
this._materialBuffers.forEach((buffer) => {
if (buffer.materialName === materialName) {
@ -186,19 +220,20 @@ export class Renderer {
});
}
public useMesh(params: RenderMeshParams.Output) {
this._materialBuffers = [];
this._materialBuffers = new Map();
for (const { material, buffer, numElements, materialName } of params.buffers) {
if (material.type === MaterialType.solid) {
this._materialBuffers.push({
this._materialBuffers.set(materialName, {
buffer: twgl.createBufferInfoFromArrays(this._gl, buffer),
material: material,
numElements: numElements,
materialName: materialName,
});
} else {
this._materialBuffers.push({
this._materialBuffers.set(materialName, {
buffer: twgl.createBufferInfoFromArrays(this._gl, buffer),
material: {
type: MaterialType.textured,
@ -332,7 +367,7 @@ export class Renderer {
}
private _drawMesh() {
for (const materialBuffer of this._materialBuffers) {
this._materialBuffers.forEach((materialBuffer, materialName) => {
if (materialBuffer.material.type === MaterialType.textured) {
this._drawMeshBuffer(materialBuffer.buffer, materialBuffer.numElements, ShaderManager.Get.textureTriProgram, {
u_lightWorldPos: ArcballCamera.Get.getCameraPosition(0.0, 0.0),
@ -352,7 +387,7 @@ export class Renderer {
u_fillColour: RGBAUtil.toArray(materialBuffer.material.colour),
});
}
}
});
}
private _drawVoxelMesh() {

View File

@ -16,6 +16,9 @@ export namespace FileUtil {
switch (process.platform) {
case 'darwin':
child.exec(`open -R ${absolutePath}`);
break;
case 'win32':
child.exec(`explorer /select,"${absolutePath}"`);
}
}
}