forked from mirror/ObjToSchematic
Added transparency options in material section
* Fixed sampling texture colour with mismatched diffuse and alpha map dimensions * Fixed opening directory of texture on Windows
This commit is contained in:
parent
3b2d126264
commit
458b2ddf58
@ -5,8 +5,7 @@ uniform vec3 u_cameraDir;
|
|||||||
|
|
||||||
uniform sampler2D u_texture;
|
uniform sampler2D u_texture;
|
||||||
uniform sampler2D u_alpha;
|
uniform sampler2D u_alpha;
|
||||||
uniform bool u_useAlphaMap;
|
uniform int u_alphaChannel;
|
||||||
uniform bool u_useAlphaChannel;
|
|
||||||
uniform float u_alphaFactor;
|
uniform float u_alphaFactor;
|
||||||
uniform float u_fresnelExponent;
|
uniform float u_fresnelExponent;
|
||||||
uniform float u_fresnelMix;
|
uniform float u_fresnelMix;
|
||||||
@ -106,10 +105,17 @@ const float ditherThreshold[64] = float[64](
|
|||||||
void main() {
|
void main() {
|
||||||
vec2 tex = vec2(v_texcoord.x, 1.0 - v_texcoord.y);
|
vec2 tex = vec2(v_texcoord.x, 1.0 - v_texcoord.y);
|
||||||
vec4 diffuse = texture2D(u_texture, tex).rgba;
|
vec4 diffuse = texture2D(u_texture, tex).rgba;
|
||||||
|
vec4 alphaSample = texture2D(u_alpha, tex);
|
||||||
|
|
||||||
float alpha = diffuse.a;
|
float alpha = 1.0;
|
||||||
if (u_useAlphaMap) {
|
if (u_alphaChannel == 0) {
|
||||||
alpha = u_useAlphaChannel ? texture2D(u_alpha, tex).a : texture2D(u_alpha, tex).r;
|
alpha = alphaSample.r;
|
||||||
|
} else if (u_alphaChannel == 1) {
|
||||||
|
alpha = alphaSample.g;
|
||||||
|
} else if (u_alphaChannel == 2) {
|
||||||
|
alpha = alphaSample.b;
|
||||||
|
} else if (u_alphaChannel == 3) {
|
||||||
|
alpha = alphaSample.a;
|
||||||
}
|
}
|
||||||
|
|
||||||
alpha *= u_alphaFactor;
|
alpha *= u_alphaFactor;
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 1.1 KiB |
BIN
res/static/debug_alpha.png
Normal file
BIN
res/static/debug_alpha.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
@ -279,6 +279,10 @@ export class AppContext {
|
|||||||
.onChangeTypeDelegate(() => {
|
.onChangeTypeDelegate(() => {
|
||||||
this._materialManager.changeMaterialType(materialName, MaterialType.solid);
|
this._materialManager.changeMaterialType(materialName, MaterialType.solid);
|
||||||
this._updateMaterialsAction();
|
this._updateMaterialsAction();
|
||||||
|
})
|
||||||
|
.onChangeTransparencyTypeDelegate((newTransparency) => {
|
||||||
|
this._materialManager.changeTransparencyType(materialName, newTransparency);
|
||||||
|
this._updateMaterialsAction();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import { RGBA, RGBAColours } from '../colour';
|
|||||||
import { checkFractional, checkNaN } from '../math';
|
import { checkFractional, checkNaN } from '../math';
|
||||||
import { MaterialType, Mesh, SolidMaterial, TexturedMaterial, Tri } from '../mesh';
|
import { MaterialType, Mesh, SolidMaterial, TexturedMaterial, Tri } from '../mesh';
|
||||||
import { StatusHandler } from '../status';
|
import { StatusHandler } from '../status';
|
||||||
|
import { EImageChannel, TTransparencyOptions } from '../texture';
|
||||||
import { UV } from '../util';
|
import { UV } from '../util';
|
||||||
import { AppError, ASSERT } from '../util/error_util';
|
import { AppError, ASSERT } from '../util/error_util';
|
||||||
import { LOG } from '../util/log_util';
|
import { LOG } from '../util/log_util';
|
||||||
@ -205,7 +206,7 @@ export class ObjImporter extends IImporter {
|
|||||||
];
|
];
|
||||||
|
|
||||||
private _currentColour: RGBA = RGBAColours.BLACK;
|
private _currentColour: RGBA = RGBAColours.BLACK;
|
||||||
private _currentAlpha: number = 1.0;
|
private _currentAlpha?: number;
|
||||||
private _currentTexture: string = '';
|
private _currentTexture: string = '';
|
||||||
private _currentTransparencyTexture: string = '';
|
private _currentTransparencyTexture: string = '';
|
||||||
private _materialReady: boolean = false;
|
private _materialReady: boolean = false;
|
||||||
@ -237,7 +238,7 @@ export class ObjImporter extends IImporter {
|
|||||||
const b = parseFloat(match.b);
|
const b = parseFloat(match.b);
|
||||||
checkNaN(r, g, b);
|
checkNaN(r, g, b);
|
||||||
checkFractional(r, g, b);
|
checkFractional(r, g, b);
|
||||||
this._currentColour = { r: r, g: g, b: b, a: this._currentAlpha };
|
this._currentColour = { r: r, g: g, b: b, a: this._currentAlpha ?? 1.0 };
|
||||||
this._materialReady = true;
|
this._materialReady = true;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -402,12 +403,34 @@ export class ObjImporter extends IImporter {
|
|||||||
private _addCurrentMaterial() {
|
private _addCurrentMaterial() {
|
||||||
if (this._materialReady && this._currentMaterialName !== '') {
|
if (this._materialReady && this._currentMaterialName !== '') {
|
||||||
if (this._currentTexture !== '') {
|
if (this._currentTexture !== '') {
|
||||||
|
let transparency: TTransparencyOptions;
|
||||||
|
if (this._currentTransparencyTexture === this._currentTexture) {
|
||||||
|
transparency = {
|
||||||
|
type: 'UseDiffuseMapAlphaChannel',
|
||||||
|
};
|
||||||
|
} else if (this._currentTransparencyTexture === '') {
|
||||||
|
if (this._currentAlpha === undefined) {
|
||||||
|
transparency = {
|
||||||
|
type: 'None',
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
transparency = {
|
||||||
|
type: 'UseAlphaValue',
|
||||||
|
alpha: this._currentAlpha,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
transparency = {
|
||||||
|
type: 'UseAlphaMap',
|
||||||
|
path: this._currentTransparencyTexture,
|
||||||
|
channel: EImageChannel.R,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
this._materials.set(this._currentMaterialName, {
|
this._materials.set(this._currentMaterialName, {
|
||||||
type: MaterialType.textured,
|
type: MaterialType.textured,
|
||||||
path: this._currentTexture,
|
path: this._currentTexture,
|
||||||
alphaPath: this._currentTransparencyTexture === '' ? undefined : this._currentTransparencyTexture,
|
transparency: transparency,
|
||||||
alphaFactor: this._currentAlpha,
|
|
||||||
canBeTextured: true,
|
|
||||||
extension: 'repeat',
|
extension: 'repeat',
|
||||||
interpolation: 'linear',
|
interpolation: 'linear',
|
||||||
needsAttention: false,
|
needsAttention: false,
|
||||||
@ -420,7 +443,7 @@ export class ObjImporter extends IImporter {
|
|||||||
r: this._currentColour.r,
|
r: this._currentColour.r,
|
||||||
g: this._currentColour.g,
|
g: this._currentColour.g,
|
||||||
b: this._currentColour.b,
|
b: this._currentColour.b,
|
||||||
a: this._currentAlpha,
|
a: this._currentAlpha ?? 1.0,
|
||||||
},
|
},
|
||||||
canBeTextured: false,
|
canBeTextured: false,
|
||||||
needsAttention: false,
|
needsAttention: false,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { RGBAColours } from './colour';
|
import { RGBAColours } from './colour';
|
||||||
import { MaterialMap, MaterialType } from './mesh';
|
import { MaterialMap, MaterialType } from './mesh';
|
||||||
|
import { EImageChannel, TTransparencyTypes } from './texture';
|
||||||
import { ASSERT } from './util/error_util';
|
import { ASSERT } from './util/error_util';
|
||||||
import { AppPaths, PathUtil } from './util/path_util';
|
import { AppPaths, PathUtil } from './util/path_util';
|
||||||
|
|
||||||
@ -10,6 +11,38 @@ export class MaterialMapManager {
|
|||||||
this.materials = materials;
|
this.materials = materials;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public changeTransparencyType(materialName: string, newTransparencyType: TTransparencyTypes) {
|
||||||
|
const currentMaterial = this.materials.get(materialName);
|
||||||
|
ASSERT(currentMaterial !== undefined, 'Cannot change transparency type of non-existent material');
|
||||||
|
ASSERT(currentMaterial.type === MaterialType.textured);
|
||||||
|
|
||||||
|
switch (newTransparencyType) {
|
||||||
|
case 'None':
|
||||||
|
currentMaterial.transparency = { type: 'None' };
|
||||||
|
break;
|
||||||
|
case 'UseAlphaMap':
|
||||||
|
currentMaterial.transparency = {
|
||||||
|
type: 'UseAlphaMap',
|
||||||
|
path: PathUtil.join(AppPaths.Get.static, 'debug_alpha.png'),
|
||||||
|
channel: EImageChannel.R,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case 'UseAlphaValue':
|
||||||
|
currentMaterial.transparency = {
|
||||||
|
type: 'UseAlphaValue',
|
||||||
|
alpha: 1.0,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case 'UseDiffuseMapAlphaChannel':
|
||||||
|
currentMaterial.transparency = {
|
||||||
|
type: 'UseDiffuseMapAlphaChannel',
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.materials.set(materialName, currentMaterial);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a material to a new type, i.e. textured to solid.
|
* Convert a material to a new type, i.e. textured to solid.
|
||||||
* Will return if the material is already the given type.
|
* Will return if the material is already the given type.
|
||||||
@ -24,19 +57,21 @@ export class MaterialMapManager {
|
|||||||
|
|
||||||
switch (newMaterialType) {
|
switch (newMaterialType) {
|
||||||
case MaterialType.solid:
|
case MaterialType.solid:
|
||||||
|
ASSERT(currentMaterial.type === MaterialType.textured, 'Old material expect to be texture');
|
||||||
this.materials.set(materialName, {
|
this.materials.set(materialName, {
|
||||||
type: MaterialType.solid,
|
type: MaterialType.solid,
|
||||||
colour: RGBAColours.MAGENTA,
|
colour: RGBAColours.MAGENTA,
|
||||||
canBeTextured: currentMaterial.canBeTextured,
|
canBeTextured: true,
|
||||||
needsAttention: true,
|
needsAttention: true,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case MaterialType.textured:
|
case MaterialType.textured:
|
||||||
|
ASSERT(currentMaterial.type === MaterialType.solid, 'Old material expect to be solid');
|
||||||
this.materials.set(materialName, {
|
this.materials.set(materialName, {
|
||||||
type: MaterialType.textured,
|
type: MaterialType.textured,
|
||||||
alphaFactor: 1.0,
|
transparency: {
|
||||||
alphaPath: undefined,
|
type: 'None',
|
||||||
canBeTextured: currentMaterial.canBeTextured,
|
},
|
||||||
extension: 'repeat',
|
extension: 'repeat',
|
||||||
interpolation: 'linear',
|
interpolation: 'linear',
|
||||||
needsAttention: true,
|
needsAttention: true,
|
||||||
|
33
src/mesh.ts
33
src/mesh.ts
@ -5,7 +5,7 @@ import { Bounds } from './bounds';
|
|||||||
import { RGBA, RGBAColours, RGBAUtil } from './colour';
|
import { RGBA, RGBAColours, RGBAUtil } from './colour';
|
||||||
import { degreesToRadians } from './math';
|
import { degreesToRadians } from './math';
|
||||||
import { StatusHandler } from './status';
|
import { StatusHandler } from './status';
|
||||||
import { Texture, TextureConverter } from './texture';
|
import { Texture, TextureConverter, TTransparencyOptions } from './texture';
|
||||||
import { Triangle, UVTriangle } from './triangle';
|
import { Triangle, UVTriangle } from './triangle';
|
||||||
import { getRandomID, UV } from './util';
|
import { getRandomID, UV } from './util';
|
||||||
import { AppError, ASSERT } from './util/error_util';
|
import { AppError, ASSERT } from './util/error_util';
|
||||||
@ -30,21 +30,20 @@ export interface Tri {
|
|||||||
export enum MaterialType { solid, textured }
|
export enum MaterialType { solid, textured }
|
||||||
/* eslint-enable */
|
/* eslint-enable */
|
||||||
type BaseMaterial = {
|
type BaseMaterial = {
|
||||||
canBeTextured: boolean,
|
|
||||||
needsAttention: boolean, // True if the user should make edits to this material
|
needsAttention: boolean, // True if the user should make edits to this material
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SolidMaterial = BaseMaterial & {
|
export type SolidMaterial = BaseMaterial & {
|
||||||
type: MaterialType.solid,
|
type: MaterialType.solid,
|
||||||
colour: RGBA,
|
colour: RGBA,
|
||||||
|
canBeTextured: boolean,
|
||||||
}
|
}
|
||||||
export type TexturedMaterial = BaseMaterial & {
|
export type TexturedMaterial = BaseMaterial & {
|
||||||
type: MaterialType.textured,
|
type: MaterialType.textured,
|
||||||
path: string,
|
path: string,
|
||||||
alphaPath?: string,
|
|
||||||
alphaFactor: number,
|
|
||||||
interpolation: TTexelInterpolation,
|
interpolation: TTexelInterpolation,
|
||||||
extension: TTexelExtension,
|
extension: TTexelExtension,
|
||||||
|
transparency: TTransparencyOptions,
|
||||||
}
|
}
|
||||||
export type MaterialMap = Map<string, SolidMaterial | TexturedMaterial>;
|
export type MaterialMap = Map<string, SolidMaterial | TexturedMaterial>;
|
||||||
|
|
||||||
@ -57,7 +56,7 @@ export class Mesh {
|
|||||||
public _tris!: Tri[];
|
public _tris!: Tri[];
|
||||||
|
|
||||||
private _materials!: MaterialMap;
|
private _materials!: MaterialMap;
|
||||||
private _loadedTextures: { [materialName: string]: Texture };
|
private _loadedTextures: Map<string, Texture>;
|
||||||
public static desiredHeight = 8.0;
|
public static desiredHeight = 8.0;
|
||||||
|
|
||||||
constructor(vertices: Vector3[], normals: Vector3[], uvs: UV[], tris: Tri[], materials: MaterialMap) {
|
constructor(vertices: Vector3[], normals: Vector3[], uvs: UV[], tris: Tri[], materials: MaterialMap) {
|
||||||
@ -68,7 +67,7 @@ export class Mesh {
|
|||||||
this._uvs = uvs;
|
this._uvs = uvs;
|
||||||
this._tris = tris;
|
this._tris = tris;
|
||||||
this._materials = materials;
|
this._materials = materials;
|
||||||
this._loadedTextures = {};
|
this._loadedTextures = new Map();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Always check
|
// TODO: Always check
|
||||||
@ -290,17 +289,12 @@ export class Mesh {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _loadTextures() {
|
private _loadTextures() {
|
||||||
this._loadedTextures = {};
|
this._loadedTextures.clear();
|
||||||
for (const tri of this._tris) {
|
this._materials.forEach((material, materialName) => {
|
||||||
const material = this._materials.get(tri.material);
|
if (material.type === MaterialType.textured && !this._loadedTextures.has(materialName)) {
|
||||||
ASSERT(material !== undefined, 'Triangle uses a material that doesn\'t exist in the material map');
|
this._loadedTextures.set(materialName, new Texture(material.path, material.transparency));
|
||||||
|
|
||||||
if (material.type == MaterialType.textured) {
|
|
||||||
if (!(tri.material in this._loadedTextures)) {
|
|
||||||
this._loadedTextures[tri.material] = new Texture(material.path, material.alphaPath);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public getVertices(triIndex: number) {
|
public getVertices(triIndex: number) {
|
||||||
@ -393,11 +387,10 @@ export class Mesh {
|
|||||||
ASSERT(material !== undefined, `Sampling material that does not exist: ${materialName}`);
|
ASSERT(material !== undefined, `Sampling material that does not exist: ${materialName}`);
|
||||||
ASSERT(material.type === MaterialType.textured, 'Sampling texture material of non-texture material');
|
ASSERT(material.type === MaterialType.textured, 'Sampling texture material of non-texture material');
|
||||||
|
|
||||||
ASSERT(materialName in this._loadedTextures, 'Sampling texture that is not loaded');
|
const texture = this._loadedTextures.get(materialName);
|
||||||
|
ASSERT(texture !== undefined, 'Sampling texture that is not loaded');
|
||||||
|
|
||||||
const colour = this._loadedTextures[materialName].getRGBA(uv, material.interpolation, material.extension);
|
return texture.getRGBA(uv, material.interpolation, material.extension);
|
||||||
colour.a *= material.alphaFactor;
|
|
||||||
return colour;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public getTriangleCount(): number {
|
public getTriangleCount(): number {
|
||||||
|
202
src/renderer.ts
202
src/renderer.ts
@ -7,7 +7,7 @@ import { DebugGeometryTemplates } from './geometry';
|
|||||||
import { MaterialType, SolidMaterial, TexturedMaterial } from './mesh';
|
import { MaterialType, SolidMaterial, TexturedMaterial } from './mesh';
|
||||||
import { RenderBuffer } from './render_buffer';
|
import { RenderBuffer } from './render_buffer';
|
||||||
import { ShaderManager } from './shaders';
|
import { ShaderManager } from './shaders';
|
||||||
import { Texture } from './texture';
|
import { EImageChannel, Texture } from './texture';
|
||||||
import { ASSERT } from './util/error_util';
|
import { ASSERT } from './util/error_util';
|
||||||
import { Vector3 } from './vector';
|
import { Vector3 } from './vector';
|
||||||
import { RenderMeshParams, RenderNextBlockMeshChunkParams, RenderNextVoxelMeshChunkParams } from './worker_types';
|
import { RenderMeshParams, RenderNextBlockMeshChunkParams, RenderNextVoxelMeshChunkParams } from './worker_types';
|
||||||
@ -30,10 +30,28 @@ enum EDebugBufferComponents {
|
|||||||
}
|
}
|
||||||
/* eslint-enable */
|
/* eslint-enable */
|
||||||
|
|
||||||
export type TextureMaterialRenderAddons = {
|
/**
|
||||||
texture: WebGLTexture, alpha?: WebGLTexture, useAlphaChannel?: boolean,
|
* Dedicated type for passing to shaders for solid materials
|
||||||
|
*/
|
||||||
|
type InternalSolidMaterial = {
|
||||||
|
type: MaterialType.solid,
|
||||||
|
colourArray: number[],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dedicated type for passing to shaders for textured materials
|
||||||
|
*/
|
||||||
|
type InternalTextureMaterial = {
|
||||||
|
type: MaterialType.textured,
|
||||||
|
diffuseTexture: WebGLTexture,
|
||||||
|
// The texture to sample alpha values from (if is using a texture map)
|
||||||
|
alphaTexture: WebGLTexture,
|
||||||
|
// What texture channel to sample the alpha value from
|
||||||
|
alphaChannel: EImageChannel,
|
||||||
|
// What alpha value to use (only used if using constant transparency mode)
|
||||||
|
alphaValue: number,
|
||||||
|
};
|
||||||
|
|
||||||
export class Renderer {
|
export class Renderer {
|
||||||
public _gl: WebGLRenderingContext;
|
public _gl: WebGLRenderingContext;
|
||||||
|
|
||||||
@ -48,7 +66,7 @@ export class Renderer {
|
|||||||
private _modelsAvailable: number;
|
private _modelsAvailable: number;
|
||||||
|
|
||||||
private _materialBuffers: Map<string, {
|
private _materialBuffers: Map<string, {
|
||||||
material: SolidMaterial | (TexturedMaterial & TextureMaterialRenderAddons)
|
material: InternalSolidMaterial | InternalTextureMaterial,
|
||||||
buffer: twgl.BufferInfo,
|
buffer: twgl.BufferInfo,
|
||||||
numElements: number,
|
numElements: number,
|
||||||
materialName: string,
|
materialName: string,
|
||||||
@ -192,123 +210,77 @@ export class Renderer {
|
|||||||
this.setModelToUse(MeshType.None);
|
this.setModelToUse(MeshType.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
public recreateMaterialBuffer(materialName: string, material: SolidMaterial | TexturedMaterial) {
|
private _createInternalMaterial(material: SolidMaterial | TexturedMaterial): (InternalSolidMaterial | InternalTextureMaterial) {
|
||||||
const oldBuffer = this._materialBuffers.get(materialName);
|
|
||||||
ASSERT(oldBuffer !== undefined);
|
|
||||||
if (material.type === MaterialType.solid) {
|
if (material.type === MaterialType.solid) {
|
||||||
this._materialBuffers.set(materialName, {
|
return {
|
||||||
buffer: oldBuffer.buffer,
|
type: MaterialType.solid,
|
||||||
material: {
|
colourArray: RGBAUtil.toArray(material.colour),
|
||||||
type: MaterialType.solid,
|
};
|
||||||
colour: RGBAUtil.copy(material.colour),
|
|
||||||
needsAttention: material.needsAttention,
|
|
||||||
canBeTextured: material.canBeTextured,
|
|
||||||
},
|
|
||||||
numElements: oldBuffer.numElements,
|
|
||||||
materialName: materialName,
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
this._materialBuffers.set(materialName, {
|
const diffuseTexture = twgl.createTexture(this._gl, {
|
||||||
buffer: oldBuffer.buffer,
|
src: material.path,
|
||||||
material: {
|
min: material.interpolation === 'linear' ? this._gl.LINEAR : this._gl.NEAREST,
|
||||||
type: MaterialType.textured,
|
mag: material.interpolation === 'linear' ? this._gl.LINEAR : this._gl.NEAREST,
|
||||||
path: material.path,
|
wrap: material.extension === 'clamp' ? this._gl.CLAMP_TO_EDGE : this._gl.REPEAT,
|
||||||
canBeTextured: material.canBeTextured,
|
|
||||||
interpolation: material.interpolation,
|
|
||||||
extension: material.extension,
|
|
||||||
texture: twgl.createTexture(this._gl, {
|
|
||||||
src: material.path,
|
|
||||||
min: material.interpolation === 'linear' ? this._gl.LINEAR : this._gl.NEAREST,
|
|
||||||
mag: material.interpolation === 'linear' ? this._gl.LINEAR : this._gl.NEAREST,
|
|
||||||
wrap: material.extension === 'clamp' ? this._gl.CLAMP_TO_EDGE : this._gl.REPEAT,
|
|
||||||
}),
|
|
||||||
alphaFactor: material.alphaFactor,
|
|
||||||
alpha: material.alphaPath ? twgl.createTexture(this._gl, {
|
|
||||||
src: material.alphaPath,
|
|
||||||
min: material.interpolation === 'linear' ? this._gl.LINEAR : this._gl.NEAREST,
|
|
||||||
mag: material.interpolation === 'linear' ? this._gl.LINEAR : this._gl.NEAREST,
|
|
||||||
wrap: material.extension === 'clamp' ? this._gl.CLAMP_TO_EDGE : this._gl.REPEAT,
|
|
||||||
}) : undefined,
|
|
||||||
useAlphaChannel: material.alphaPath ? new Texture(material.path, material.alphaPath)._useAlphaChannel() : undefined,
|
|
||||||
needsAttention: material.needsAttention,
|
|
||||||
},
|
|
||||||
numElements: oldBuffer.numElements,
|
|
||||||
materialName: materialName,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const alphaTexture = material.transparency.type === 'UseAlphaMap' ? twgl.createTexture(this._gl, {
|
||||||
|
src: material.transparency.path,
|
||||||
|
min: material.interpolation === 'linear' ? this._gl.LINEAR : this._gl.NEAREST,
|
||||||
|
mag: material.interpolation === 'linear' ? this._gl.LINEAR : this._gl.NEAREST,
|
||||||
|
wrap: material.extension === 'clamp' ? this._gl.CLAMP_TO_EDGE : this._gl.REPEAT,
|
||||||
|
}) : diffuseTexture;
|
||||||
|
|
||||||
|
const alphaValue = material.transparency.type === 'UseAlphaValue' ?
|
||||||
|
material.transparency.alpha : 1.0;
|
||||||
|
|
||||||
|
let alphaChannel: EImageChannel = EImageChannel.MAX;
|
||||||
|
switch (material.transparency.type) {
|
||||||
|
case 'UseAlphaValue':
|
||||||
|
alphaChannel = EImageChannel.MAX;
|
||||||
|
break;
|
||||||
|
case 'UseDiffuseMapAlphaChannel':
|
||||||
|
alphaChannel = EImageChannel.A;
|
||||||
|
break;
|
||||||
|
case 'UseAlphaMap':
|
||||||
|
alphaChannel = material.transparency.channel;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: MaterialType.textured,
|
||||||
|
diffuseTexture: diffuseTexture,
|
||||||
|
alphaTexture: alphaTexture,
|
||||||
|
alphaValue: alphaValue,
|
||||||
|
alphaChannel: alphaChannel,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateMeshMaterialTexture(materialName: string, material: TexturedMaterial) {
|
public recreateMaterialBuffer(materialName: string, material: SolidMaterial | TexturedMaterial) {
|
||||||
this._materialBuffers.forEach((buffer) => {
|
const oldBuffer = this._materialBuffers.get(materialName);
|
||||||
if (buffer.materialName === materialName) {
|
ASSERT(oldBuffer !== undefined);
|
||||||
buffer.material = {
|
|
||||||
type: MaterialType.textured,
|
const internalMaterial = this._createInternalMaterial(material);
|
||||||
path: material.path,
|
this._materialBuffers.set(materialName, {
|
||||||
interpolation: material.interpolation,
|
buffer: oldBuffer.buffer,
|
||||||
extension: material.extension,
|
material: internalMaterial,
|
||||||
canBeTextured: material.canBeTextured,
|
numElements: oldBuffer.numElements,
|
||||||
texture: twgl.createTexture(this._gl, {
|
materialName: materialName,
|
||||||
src: material.path,
|
|
||||||
min: material.interpolation === 'linear' ? this._gl.LINEAR : this._gl.NEAREST,
|
|
||||||
mag: material.interpolation === 'linear' ? this._gl.LINEAR : this._gl.NEAREST,
|
|
||||||
wrap: material.extension === 'clamp' ? this._gl.CLAMP_TO_EDGE : this._gl.REPEAT,
|
|
||||||
}),
|
|
||||||
alphaFactor: material.alphaFactor,
|
|
||||||
alpha: material.alphaPath ? twgl.createTexture(this._gl, {
|
|
||||||
src: material.alphaPath,
|
|
||||||
min: material.interpolation === 'linear' ? this._gl.LINEAR : this._gl.NEAREST,
|
|
||||||
mag: material.interpolation === 'linear' ? this._gl.LINEAR : this._gl.NEAREST,
|
|
||||||
wrap: material.extension === 'clamp' ? this._gl.CLAMP_TO_EDGE : this._gl.REPEAT,
|
|
||||||
}) : undefined,
|
|
||||||
useAlphaChannel: material.alphaPath ? new Texture(material.path, material.alphaPath)._useAlphaChannel() : undefined,
|
|
||||||
needsAttention: material.needsAttention,
|
|
||||||
};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public useMesh(params: RenderMeshParams.Output) {
|
public useMesh(params: RenderMeshParams.Output) {
|
||||||
this._materialBuffers = new Map();
|
this._materialBuffers = new Map();
|
||||||
|
|
||||||
for (const { material, buffer, numElements, materialName } of params.buffers) {
|
for (const { material, buffer, numElements, materialName } of params.buffers) {
|
||||||
if (material.type === MaterialType.solid) {
|
const internalMaterial = this._createInternalMaterial(material);
|
||||||
this._materialBuffers.set(materialName, {
|
this._materialBuffers.set(materialName, {
|
||||||
buffer: twgl.createBufferInfoFromArrays(this._gl, buffer),
|
buffer: twgl.createBufferInfoFromArrays(this._gl, buffer),
|
||||||
material: material,
|
material: internalMaterial,
|
||||||
numElements: numElements,
|
numElements: numElements,
|
||||||
materialName: materialName,
|
materialName: materialName,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
this._materialBuffers.set(materialName, {
|
|
||||||
buffer: twgl.createBufferInfoFromArrays(this._gl, buffer),
|
|
||||||
material: {
|
|
||||||
canBeTextured: material.canBeTextured,
|
|
||||||
type: MaterialType.textured,
|
|
||||||
interpolation: material.interpolation,
|
|
||||||
extension: material.extension,
|
|
||||||
path: material.path,
|
|
||||||
texture: twgl.createTexture(this._gl, {
|
|
||||||
src: material.path,
|
|
||||||
min: material.interpolation === 'linear' ? this._gl.LINEAR : this._gl.NEAREST,
|
|
||||||
mag: material.interpolation === 'linear' ? this._gl.LINEAR : this._gl.NEAREST,
|
|
||||||
wrap: material.extension === 'clamp' ? this._gl.CLAMP_TO_EDGE : this._gl.REPEAT,
|
|
||||||
}),
|
|
||||||
alphaFactor: material.alphaFactor,
|
|
||||||
alpha: material.alphaPath ? twgl.createTexture(this._gl, {
|
|
||||||
src: material.alphaPath,
|
|
||||||
min: material.interpolation === 'linear' ? this._gl.LINEAR : this._gl.NEAREST,
|
|
||||||
mag: material.interpolation === 'linear' ? this._gl.LINEAR : this._gl.NEAREST,
|
|
||||||
wrap: material.extension === 'clamp' ? this._gl.CLAMP_TO_EDGE : this._gl.REPEAT,
|
|
||||||
}) : undefined,
|
|
||||||
useAlphaChannel: material.alphaPath ? new Texture(material.path, material.alphaPath)._useAlphaChannel() : undefined,
|
|
||||||
needsAttention: material.needsAttention,
|
|
||||||
},
|
|
||||||
numElements: numElements,
|
|
||||||
materialName: materialName,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this._gridBuffers.x[MeshType.TriangleMesh] = DebugGeometryTemplates.gridX(params.dimensions);
|
this._gridBuffers.x[MeshType.TriangleMesh] = DebugGeometryTemplates.gridX(params.dimensions);
|
||||||
@ -458,9 +430,6 @@ export class Renderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public parseRawMeshData(buffer: string, dimensions: Vector3) {
|
|
||||||
}
|
|
||||||
|
|
||||||
private _drawMesh() {
|
private _drawMesh() {
|
||||||
this._materialBuffers.forEach((materialBuffer, materialName) => {
|
this._materialBuffers.forEach((materialBuffer, materialName) => {
|
||||||
if (materialBuffer.material.type === MaterialType.textured) {
|
if (materialBuffer.material.type === MaterialType.textured) {
|
||||||
@ -468,11 +437,10 @@ export class Renderer {
|
|||||||
u_lightWorldPos: ArcballCamera.Get.getCameraPosition(-Math.PI/4, 0.0).toArray(),
|
u_lightWorldPos: ArcballCamera.Get.getCameraPosition(-Math.PI/4, 0.0).toArray(),
|
||||||
u_worldViewProjection: ArcballCamera.Get.getWorldViewProjection(),
|
u_worldViewProjection: ArcballCamera.Get.getWorldViewProjection(),
|
||||||
u_worldInverseTranspose: ArcballCamera.Get.getWorldInverseTranspose(),
|
u_worldInverseTranspose: ArcballCamera.Get.getWorldInverseTranspose(),
|
||||||
u_texture: materialBuffer.material.texture,
|
u_texture: materialBuffer.material.diffuseTexture,
|
||||||
u_alpha: materialBuffer.material.alpha || materialBuffer.material.texture,
|
u_alpha: materialBuffer.material.alphaTexture ?? materialBuffer.material.diffuseTexture,
|
||||||
u_useAlphaMap: materialBuffer.material.alpha !== undefined,
|
u_alphaChannel: materialBuffer.material.alphaChannel,
|
||||||
u_useAlphaChannel: materialBuffer.material.useAlphaChannel,
|
u_alphaFactor: materialBuffer.material.alphaValue,
|
||||||
u_alphaFactor: materialBuffer.material.alphaFactor,
|
|
||||||
u_cameraDir: ArcballCamera.Get.getCameraDirection().toArray(),
|
u_cameraDir: ArcballCamera.Get.getCameraDirection().toArray(),
|
||||||
u_fresnelExponent: AppConfig.Get.FRESNEL_EXPONENT,
|
u_fresnelExponent: AppConfig.Get.FRESNEL_EXPONENT,
|
||||||
u_fresnelMix: AppConfig.Get.FRESNEL_MIX,
|
u_fresnelMix: AppConfig.Get.FRESNEL_MIX,
|
||||||
@ -482,7 +450,7 @@ export class Renderer {
|
|||||||
u_lightWorldPos: ArcballCamera.Get.getCameraPosition(-Math.PI/4, 0.0).toArray(),
|
u_lightWorldPos: ArcballCamera.Get.getCameraPosition(-Math.PI/4, 0.0).toArray(),
|
||||||
u_worldViewProjection: ArcballCamera.Get.getWorldViewProjection(),
|
u_worldViewProjection: ArcballCamera.Get.getWorldViewProjection(),
|
||||||
u_worldInverseTranspose: ArcballCamera.Get.getWorldInverseTranspose(),
|
u_worldInverseTranspose: ArcballCamera.Get.getWorldInverseTranspose(),
|
||||||
u_fillColour: RGBAUtil.toArray(materialBuffer.material.colour),
|
u_fillColour: materialBuffer.material.colourArray,
|
||||||
u_cameraDir: ArcballCamera.Get.getCameraDirection().toArray(),
|
u_cameraDir: ArcballCamera.Get.getCameraDirection().toArray(),
|
||||||
u_fresnelExponent: AppConfig.Get.FRESNEL_EXPONENT,
|
u_fresnelExponent: AppConfig.Get.FRESNEL_EXPONENT,
|
||||||
u_fresnelMix: AppConfig.Get.FRESNEL_MIX,
|
u_fresnelMix: AppConfig.Get.FRESNEL_MIX,
|
||||||
|
@ -34,18 +34,37 @@ type ImageData = {
|
|||||||
height: number
|
height: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* eslint-disable */
|
||||||
|
export enum EImageChannel {
|
||||||
|
R = 0,
|
||||||
|
G = 1,
|
||||||
|
B = 2,
|
||||||
|
A = 3,
|
||||||
|
MAX = 4,
|
||||||
|
}
|
||||||
|
/* eslint-enable */
|
||||||
|
|
||||||
|
export type TTransparencyTypes = 'None' | 'UseDiffuseMapAlphaChannel' | 'UseAlphaValue' | 'UseAlphaMap';
|
||||||
|
|
||||||
|
export type TTransparencyOptions =
|
||||||
|
| { type: 'None' }
|
||||||
|
| { type: 'UseDiffuseMapAlphaChannel' }
|
||||||
|
| { type: 'UseAlphaValue', alpha: number }
|
||||||
|
| { type: 'UseAlphaMap', path: string, channel: EImageChannel };
|
||||||
|
|
||||||
export class Texture {
|
export class Texture {
|
||||||
private _image: ImageData;
|
private _image: ImageData;
|
||||||
private _alphaImage?: ImageData;
|
private _alphaImage: ImageData;
|
||||||
|
private _transparency: TTransparencyOptions;
|
||||||
|
|
||||||
constructor(filename: string, transparencyFilename?: string) {
|
constructor(diffusePath: string, transparency: TTransparencyOptions) {
|
||||||
ASSERT(path.isAbsolute(filename));
|
ASSERT(path.isAbsolute(diffusePath));
|
||||||
|
|
||||||
this._image = this._loadImageFile(filename);
|
this._image = this._loadImageFile(diffusePath);
|
||||||
|
this._transparency = transparency;
|
||||||
if (transparencyFilename) {
|
this._alphaImage = transparency.type === 'UseAlphaMap' ?
|
||||||
this._alphaImage = this._loadImageFile(transparencyFilename);
|
this._loadImageFile(transparency.path) :
|
||||||
}
|
this._image;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _loadImageFile(filename: string): ImageData {
|
private _loadImageFile(filename: string): ImageData {
|
||||||
@ -63,6 +82,7 @@ export class Texture {
|
|||||||
this._useAlphaChannelValue = false;
|
this._useAlphaChannelValue = false;
|
||||||
return jpeg.decode(data, {
|
return jpeg.decode(data, {
|
||||||
maxMemoryUsageInMB: AppConfig.Get.MAXIMUM_IMAGE_MEM_ALLOC,
|
maxMemoryUsageInMB: AppConfig.Get.MAXIMUM_IMAGE_MEM_ALLOC,
|
||||||
|
formatAsRGBA: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -101,19 +121,28 @@ export class Texture {
|
|||||||
ASSERT(uv.v >= 0.0 && uv.v <= 1.0, 'Texcoord UV.v OOB');
|
ASSERT(uv.v >= 0.0 && uv.v <= 1.0, 'Texcoord UV.v OOB');
|
||||||
uv.v = 1.0 - uv.v;
|
uv.v = 1.0 - uv.v;
|
||||||
|
|
||||||
if (interpolation === 'nearest') {
|
const diffuse = (interpolation === 'nearest') ?
|
||||||
return this._getNearestRGBA(uv);
|
this._getNearestRGBA(this._image, uv) :
|
||||||
} else {
|
this._getLinearRGBA(this._image, uv);
|
||||||
return this._getLinearRGBA(uv);
|
|
||||||
}
|
const alpha = (interpolation === 'nearest') ?
|
||||||
|
this._getNearestRGBA(this._alphaImage, uv) :
|
||||||
|
this._getLinearRGBA(this._alphaImage, uv);
|
||||||
|
|
||||||
|
return {
|
||||||
|
r: diffuse.r,
|
||||||
|
g: diffuse.g,
|
||||||
|
b: diffuse.b,
|
||||||
|
a: alpha.a,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UV is assumed to be in [0, 1] range.
|
* UV is assumed to be in [0, 1] range.
|
||||||
*/
|
*/
|
||||||
private _getLinearRGBA(uv: UV): RGBA {
|
private _getLinearRGBA(image: ImageData, uv: UV): RGBA {
|
||||||
const x = uv.u * this._image.width;
|
const x = uv.u * image.width;
|
||||||
const y = uv.v * this._image.height;
|
const y = uv.v * image.height;
|
||||||
|
|
||||||
const xLeft = Math.floor(x);
|
const xLeft = Math.floor(x);
|
||||||
const xRight = xLeft + 1;
|
const xRight = xLeft + 1;
|
||||||
@ -127,12 +156,12 @@ export class Texture {
|
|||||||
return RGBAColours.MAGENTA;
|
return RGBAColours.MAGENTA;
|
||||||
}
|
}
|
||||||
|
|
||||||
const A = this._getFromXY(xLeft, yUp);
|
const A = Texture._sampleImage(this._image, xLeft, yUp);
|
||||||
const B = this._getFromXY(xRight, yUp);
|
const B = Texture._sampleImage(this._image, xRight, yUp);
|
||||||
const AB = RGBAUtil.lerp(A, B, u);
|
const AB = RGBAUtil.lerp(A, B, u);
|
||||||
|
|
||||||
const C = this._getFromXY(xLeft, yDown);
|
const C = Texture._sampleImage(this._image, xLeft, yDown);
|
||||||
const D = this._getFromXY(xRight, yDown);
|
const D = Texture._sampleImage(this._image, xRight, yDown);
|
||||||
const CD = RGBAUtil.lerp(C, D, u);
|
const CD = RGBAUtil.lerp(C, D, u);
|
||||||
|
|
||||||
return RGBAUtil.lerp(AB, CD, v);
|
return RGBAUtil.lerp(AB, CD, v);
|
||||||
@ -141,27 +170,20 @@ export class Texture {
|
|||||||
/**
|
/**
|
||||||
* UV is assumed to be in [0, 1] range.
|
* UV is assumed to be in [0, 1] range.
|
||||||
*/
|
*/
|
||||||
private _getNearestRGBA(uv: UV): RGBA {
|
private _getNearestRGBA(image: ImageData, uv: UV): RGBA {
|
||||||
const x = Math.floor(uv.u * this._image.width);
|
const diffuseX = Math.floor(uv.u * image.width);
|
||||||
const y = Math.floor(uv.v * this._image.height);
|
const diffuseY = Math.floor(uv.v * image.height);
|
||||||
|
|
||||||
return this._getFromXY(x, y);
|
return Texture._sampleImage(image, diffuseX, diffuseY);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getFromXY(x: number, y: number): RGBA {
|
private _sampleChannel(colour: RGBA, channel: EImageChannel) {
|
||||||
const diffuse = Texture._sampleImage(this._image, x, y);
|
switch (channel) {
|
||||||
|
case EImageChannel.R: return colour.r;
|
||||||
if (this._alphaImage) {
|
case EImageChannel.G: return colour.g;
|
||||||
const alpha = Texture._sampleImage(this._alphaImage, x, y);
|
case EImageChannel.B: return colour.b;
|
||||||
return {
|
case EImageChannel.A: return colour.a;
|
||||||
r: diffuse.r,
|
|
||||||
g: diffuse.g,
|
|
||||||
b: diffuse.b,
|
|
||||||
a: this._useAlphaChannel() ? alpha.a : alpha.r,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return diffuse;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public _useAlphaChannelValue?: boolean;
|
public _useAlphaChannelValue?: boolean;
|
||||||
|
@ -72,8 +72,8 @@ export class ImageElement extends ConfigUIElement<string, HTMLDivElement> {
|
|||||||
const newPath = this.getValue();
|
const newPath = this.getValue();
|
||||||
const parsedPath = path.parse(newPath);
|
const parsedPath = path.parse(newPath);
|
||||||
|
|
||||||
this._openElement.setEnabled(parsedPath.base !== 'debug.png');
|
this._openElement.setEnabled(parsedPath.base !== 'debug.png' && parsedPath.base !== 'debug_alpha.png');
|
||||||
this._switchElement.setActive(parsedPath.base === 'debug.png');
|
this._switchElement.setActive(parsedPath.base === 'debug.png' || parsedPath.base === 'debug_alpha.png');
|
||||||
|
|
||||||
const imageElement = UIUtil.getElementById(this._imageId) as HTMLImageElement;
|
const imageElement = UIUtil.getElementById(this._imageId) as HTMLImageElement;
|
||||||
imageElement.src = newPath;
|
imageElement.src = newPath;
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import { MaterialType, TexturedMaterial } from '../../mesh';
|
import { MaterialType, TexturedMaterial } from '../../mesh';
|
||||||
|
import { EImageChannel, TTransparencyTypes } from '../../texture';
|
||||||
import { getRandomID } from '../../util';
|
import { getRandomID } from '../../util';
|
||||||
|
import { ASSERT } from '../../util/error_util';
|
||||||
import { ComboBoxElement } from './combobox';
|
import { ComboBoxElement } from './combobox';
|
||||||
import { ConfigUIElement } from './config_element';
|
import { ConfigUIElement } from './config_element';
|
||||||
import { ImageElement } from './image_element';
|
import { ImageElement } from './image_element';
|
||||||
@ -11,9 +13,12 @@ export class TexturedMaterialElement extends ConfigUIElement<TexturedMaterial, H
|
|||||||
private _colourId: string;
|
private _colourId: string;
|
||||||
private _filteringElement: ComboBoxElement<'nearest' | 'linear'>;
|
private _filteringElement: ComboBoxElement<'nearest' | 'linear'>;
|
||||||
private _wrapElement: ComboBoxElement<'clamp' | 'repeat'>;
|
private _wrapElement: ComboBoxElement<'clamp' | 'repeat'>;
|
||||||
|
private _transparencyElement: ComboBoxElement<TTransparencyTypes>;
|
||||||
private _imageElement: ImageElement;
|
private _imageElement: ImageElement;
|
||||||
private _typeElement: MaterialTypeElement;
|
private _typeElement: MaterialTypeElement;
|
||||||
private _alphaElement: SliderElement;
|
private _alphaValueElement?: SliderElement;
|
||||||
|
private _alphaMapElement?: ImageElement;
|
||||||
|
private _alphaChannelElement?: ComboBoxElement<EImageChannel>;
|
||||||
|
|
||||||
public constructor(materialName: string, material: TexturedMaterial) {
|
public constructor(materialName: string, material: TexturedMaterial) {
|
||||||
super(material);
|
super(material);
|
||||||
@ -32,17 +37,39 @@ export class TexturedMaterialElement extends ConfigUIElement<TexturedMaterial, H
|
|||||||
.setSmall()
|
.setSmall()
|
||||||
.setDefaultValue(material.extension);
|
.setDefaultValue(material.extension);
|
||||||
|
|
||||||
|
this._transparencyElement = new ComboBoxElement<TTransparencyTypes>()
|
||||||
|
.addItem({ payload: 'None', displayText: 'None' })
|
||||||
|
.addItem({ payload: 'UseAlphaMap', displayText: 'Alpha map' })
|
||||||
|
.addItem({ payload: 'UseAlphaValue', displayText: 'Alpha constant' })
|
||||||
|
.addItem({ payload: 'UseDiffuseMapAlphaChannel', displayText: 'Diffuse map alpha channel' })
|
||||||
|
.setSmall()
|
||||||
|
.setDefaultValue(material.transparency.type);
|
||||||
|
|
||||||
this._imageElement = new ImageElement(material.path);
|
this._imageElement = new ImageElement(material.path);
|
||||||
|
|
||||||
this._typeElement = new MaterialTypeElement(MaterialType.textured);
|
this._typeElement = new MaterialTypeElement(MaterialType.textured);
|
||||||
|
|
||||||
this._alphaElement = new SliderElement()
|
switch (material.transparency.type) {
|
||||||
.setMin(0.0)
|
case 'UseAlphaValue':
|
||||||
.setMax(1.0)
|
this._alphaValueElement = new SliderElement()
|
||||||
.setDefaultValue(material.alphaFactor)
|
.setMin(0.0)
|
||||||
.setDecimals(2)
|
.setMax(1.0)
|
||||||
.setStep(0.01)
|
.setDefaultValue(material.transparency.alpha)
|
||||||
.setSmall();
|
.setDecimals(2)
|
||||||
|
.setStep(0.01)
|
||||||
|
.setSmall();
|
||||||
|
break;
|
||||||
|
case 'UseAlphaMap':
|
||||||
|
this._alphaMapElement = new ImageElement(material.transparency.path);
|
||||||
|
this._alphaChannelElement = new ComboBoxElement<EImageChannel>()
|
||||||
|
.addItem({ payload: EImageChannel.R, displayText: 'Red' })
|
||||||
|
.addItem({ payload: EImageChannel.G, displayText: 'Green' })
|
||||||
|
.addItem({ payload: EImageChannel.B, displayText: 'Blue' })
|
||||||
|
.addItem({ payload: EImageChannel.A, displayText: 'Alpha' })
|
||||||
|
.setSmall()
|
||||||
|
.setDefaultValue(material.transparency.channel);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override registerEvents(): void {
|
public override registerEvents(): void {
|
||||||
@ -50,7 +77,10 @@ export class TexturedMaterialElement extends ConfigUIElement<TexturedMaterial, H
|
|||||||
this._typeElement.registerEvents();
|
this._typeElement.registerEvents();
|
||||||
this._filteringElement.registerEvents();
|
this._filteringElement.registerEvents();
|
||||||
this._wrapElement.registerEvents();
|
this._wrapElement.registerEvents();
|
||||||
this._alphaElement.registerEvents();
|
this._transparencyElement.registerEvents();
|
||||||
|
this._alphaValueElement?.registerEvents();
|
||||||
|
this._alphaMapElement?.registerEvents();
|
||||||
|
this._alphaChannelElement?.registerEvents();
|
||||||
|
|
||||||
this._imageElement.addValueChangedListener((newPath) => {
|
this._imageElement.addValueChangedListener((newPath) => {
|
||||||
const material = this.getValue();
|
const material = this.getValue();
|
||||||
@ -71,14 +101,30 @@ export class TexturedMaterialElement extends ConfigUIElement<TexturedMaterial, H
|
|||||||
this._onChangeTypeDelegate?.();
|
this._onChangeTypeDelegate?.();
|
||||||
});
|
});
|
||||||
|
|
||||||
this._alphaElement.addValueChangedListener((newAlpha) => {
|
this._alphaValueElement?.addValueChangedListener((newAlpha) => {
|
||||||
this.getValue().alphaFactor = newAlpha;
|
const material = this.getValue();
|
||||||
|
ASSERT(material.transparency.type === 'UseAlphaValue');
|
||||||
|
material.transparency.alpha = newAlpha;
|
||||||
|
});
|
||||||
|
|
||||||
|
this._alphaMapElement?.addValueChangedListener((newPath) => {
|
||||||
|
const material = this.getValue();
|
||||||
|
ASSERT(material.transparency.type === 'UseAlphaMap');
|
||||||
|
material.transparency.path = newPath;
|
||||||
|
});
|
||||||
|
|
||||||
|
this._alphaChannelElement?.addValueChangedListener((newChannel) => {
|
||||||
|
const material = this.getValue();
|
||||||
|
ASSERT(material.transparency.type === 'UseAlphaMap');
|
||||||
|
material.transparency.channel = newChannel;
|
||||||
|
});
|
||||||
|
|
||||||
|
this._transparencyElement.addValueChangedListener((newTransparency) => {
|
||||||
|
this._onChangeTransparencyTypeDelegate?.(newTransparency);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override _generateInnerHTML(): string {
|
protected override _generateInnerHTML(): string {
|
||||||
const material = this.getValue();
|
|
||||||
|
|
||||||
const subproperties: string[] = [];
|
const subproperties: string[] = [];
|
||||||
const addSubproperty = (key: string, value: string) => {
|
const addSubproperty = (key: string, value: string) => {
|
||||||
subproperties.push(`
|
subproperties.push(`
|
||||||
@ -94,10 +140,18 @@ export class TexturedMaterialElement extends ConfigUIElement<TexturedMaterial, H
|
|||||||
};
|
};
|
||||||
|
|
||||||
addSubproperty('Type', this._typeElement._generateInnerHTML());
|
addSubproperty('Type', this._typeElement._generateInnerHTML());
|
||||||
addSubproperty('Alpha', this._alphaElement._generateInnerHTML());
|
addSubproperty('Diffuse map', this._imageElement._generateInnerHTML());
|
||||||
addSubproperty('File', this._imageElement._generateInnerHTML());
|
|
||||||
addSubproperty('Filtering', this._filteringElement._generateInnerHTML());
|
addSubproperty('Filtering', this._filteringElement._generateInnerHTML());
|
||||||
addSubproperty('Wrap', this._wrapElement._generateInnerHTML());
|
addSubproperty('Wrap', this._wrapElement._generateInnerHTML());
|
||||||
|
addSubproperty('Transparency', this._transparencyElement._generateInnerHTML());
|
||||||
|
if (this._alphaMapElement !== undefined) {
|
||||||
|
ASSERT(this._alphaChannelElement !== undefined);
|
||||||
|
addSubproperty('Alpha map', this._alphaMapElement._generateInnerHTML());
|
||||||
|
addSubproperty('Channel', this._alphaChannelElement._generateInnerHTML());
|
||||||
|
}
|
||||||
|
if (this._alphaValueElement) {
|
||||||
|
addSubproperty('Alpha', this._alphaValueElement._generateInnerHTML());
|
||||||
|
}
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="subproperty-container">
|
<div class="subproperty-container">
|
||||||
@ -120,6 +174,10 @@ export class TexturedMaterialElement extends ConfigUIElement<TexturedMaterial, H
|
|||||||
this._typeElement.finalise();
|
this._typeElement.finalise();
|
||||||
this._filteringElement.finalise();
|
this._filteringElement.finalise();
|
||||||
this._wrapElement.finalise();
|
this._wrapElement.finalise();
|
||||||
|
this._transparencyElement.finalise();
|
||||||
|
this._alphaValueElement?.finalise();
|
||||||
|
this._alphaMapElement?.finalise();
|
||||||
|
this._alphaChannelElement?.finalise();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onChangeTypeDelegate?: () => void;
|
private _onChangeTypeDelegate?: () => void;
|
||||||
@ -127,4 +185,10 @@ export class TexturedMaterialElement extends ConfigUIElement<TexturedMaterial, H
|
|||||||
this._onChangeTypeDelegate = delegate;
|
this._onChangeTypeDelegate = delegate;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _onChangeTransparencyTypeDelegate?: (newTransparency: TTransparencyTypes) => void;
|
||||||
|
public onChangeTransparencyTypeDelegate(delegate: (newTransparency: TTransparencyTypes) => void) {
|
||||||
|
this._onChangeTransparencyTypeDelegate = delegate;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import child from 'child_process';
|
import child from 'child_process';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
import { LOGF } from './log_util';
|
import { LOGF } from './log_util';
|
||||||
|
|
||||||
@ -27,7 +28,8 @@ export namespace FileUtil {
|
|||||||
child.exec(`open -R ${absolutePath}`);
|
child.exec(`open -R ${absolutePath}`);
|
||||||
break;
|
break;
|
||||||
case 'win32':
|
case 'win32':
|
||||||
child.exec(`explorer /select,"${absolutePath}"`);
|
const parsed = path.parse(absolutePath);
|
||||||
|
child.exec(`start ${parsed.dir}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user