mirror of
https://github.com/LucasDower/ObjToSchematic.git
synced 2025-03-07 14:06:41 +08:00
Added UI value cacheing
This commit is contained in:
parent
bb11207e70
commit
24a4038362
@ -110,6 +110,7 @@ export class AppContext {
|
||||
this._warnings = [];
|
||||
const groupName = UI.Get.uiOrder[action];
|
||||
LOG(`Doing ${action}`);
|
||||
UI.Get.cacheValues(action);
|
||||
const delegate = this._actionMap.get(action)!;
|
||||
try {
|
||||
delegate.action();
|
||||
@ -141,12 +142,8 @@ export class AppContext {
|
||||
}
|
||||
|
||||
private _import() {
|
||||
const objPath = UI.Get.layout.import.elements.input.getValue();
|
||||
|
||||
this._loadedMesh = new ObjImporter().createMesh(objPath);
|
||||
this._loadedMesh = new ObjImporter().createMesh();
|
||||
Renderer.Get.useMesh(this._loadedMesh);
|
||||
LOG(this._loadedMesh);
|
||||
LOG(Renderer.Get);
|
||||
}
|
||||
|
||||
private _simplify() {
|
||||
@ -154,30 +151,23 @@ export class AppContext {
|
||||
}
|
||||
|
||||
private _voxelise() {
|
||||
const desiredHeight = UI.Get.layout.build.elements.height.getValue();
|
||||
const ambientOcclusion = UI.Get.layout.build.elements.ambientOcclusion.getValue() === 'on';
|
||||
const multisampleColouring = UI.Get.layout.build.elements.multisampleColouring.getValue() === 'on';
|
||||
const textureFiltering = UI.Get.layout.build.elements.textureFiltering.getValue() === 'nearest' ? TextureFiltering.Nearest : TextureFiltering.Linear;
|
||||
|
||||
ASSERT(this._loadedMesh);
|
||||
this._loadedVoxelMesh = new VoxelMesh(desiredHeight);
|
||||
this._loadedVoxelMesh.voxelise(this._loadedMesh, multisampleColouring, textureFiltering);
|
||||
this._loadedVoxelMesh = new VoxelMesh();
|
||||
this._loadedVoxelMesh.voxelise(this._loadedMesh);
|
||||
|
||||
Renderer.Get.useVoxelMesh(this._loadedVoxelMesh, ambientOcclusion);
|
||||
Renderer.Get.useVoxelMesh(this._loadedVoxelMesh);
|
||||
}
|
||||
|
||||
private _palette() {
|
||||
const ditheringEnabled = UI.Get.layout.palette.elements.dithering.getValue() === 'on';
|
||||
|
||||
ASSERT(this._loadedVoxelMesh);
|
||||
this._loadedBlockMesh = new BlockMesh(ditheringEnabled);
|
||||
this._loadedBlockMesh = new BlockMesh();
|
||||
this._loadedBlockMesh.assignBlocks(this._loadedVoxelMesh);
|
||||
|
||||
Renderer.Get.useBlockMesh(this._loadedBlockMesh);
|
||||
}
|
||||
|
||||
private _export() {
|
||||
const exportFormat = UI.Get.layout.export.elements.export.getValue();
|
||||
const exportFormat = UI.Get.layout.export.elements.export.getCachedValue() as string;
|
||||
const exporter = (exportFormat === 'schematic') ? new Schematic() : new Litematic();
|
||||
|
||||
if (exportFormat === 'schematic') {
|
||||
|
@ -3,6 +3,7 @@ import { Voxel, VoxelMesh } from './voxel_mesh';
|
||||
import { BlockInfo } from './block_atlas';
|
||||
import { CustomError, LOG } from './util';
|
||||
import { Renderer } from './renderer';
|
||||
import { UI } from './ui/layout';
|
||||
|
||||
interface Block {
|
||||
voxel: Voxel;
|
||||
@ -15,10 +16,10 @@ export class BlockMesh {
|
||||
private _blocks: Block[];
|
||||
private _voxelMesh?: VoxelMesh;
|
||||
|
||||
public constructor(ditheringEnabled: boolean) {
|
||||
public constructor() {
|
||||
LOG('New block mesh');
|
||||
|
||||
this._ditheringEnabled = ditheringEnabled;
|
||||
this._ditheringEnabled = UI.Get.layout.palette.elements.dithering.getCachedValue() as string === 'on';
|
||||
this._blockPalette = [];
|
||||
this._blocks = [];
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import { IImporter } from '../importer';
|
||||
import { MaterialType, Mesh, SolidMaterial, TexturedMaterial, Tri } from '../mesh';
|
||||
import { Vector3 } from '../vector';
|
||||
import { UV, ASSERT, RGB, LOG_WARN } from '../util';
|
||||
import { UI } from '../ui/layout';
|
||||
|
||||
export class ObjImporter extends IImporter {
|
||||
private _vertices!: Vector3[];
|
||||
@ -15,7 +16,8 @@ export class ObjImporter extends IImporter {
|
||||
private _materials!: {[key: string]: (SolidMaterial | TexturedMaterial)};
|
||||
private _mtlLibs!: string[];
|
||||
|
||||
override createMesh(filePath: string): Mesh {
|
||||
override createMesh(): Mesh {
|
||||
const filePath = UI.Get.layout.import.elements.input.getCachedValue();
|
||||
ASSERT(path.isAbsolute(filePath));
|
||||
this._parseOBJ(filePath);
|
||||
|
||||
|
@ -129,10 +129,10 @@ export class Renderer {
|
||||
this._meshToUse = MeshType.TriangleMesh;
|
||||
}
|
||||
|
||||
public useVoxelMesh(voxelMesh: VoxelMesh, ambientOcclusionEnabled: boolean) {
|
||||
public useVoxelMesh(voxelMesh: VoxelMesh) {
|
||||
LOG('Using voxel mesh');
|
||||
LOG(voxelMesh);
|
||||
this._voxelBuffer = voxelMesh.createBuffer(ambientOcclusionEnabled);
|
||||
this._voxelBuffer = voxelMesh.createBuffer();
|
||||
this._meshToUse = MeshType.VoxelMesh;
|
||||
this._voxelSize = voxelMesh?.getVoxelSize();
|
||||
}
|
||||
|
@ -1,7 +1,11 @@
|
||||
import { ASSERT } from '../../util';
|
||||
|
||||
export abstract class BaseUIElement {
|
||||
protected _id: string;
|
||||
protected _label: string;
|
||||
protected _isEnabled: boolean;
|
||||
protected _value: any;
|
||||
protected _cachedValue?: any;
|
||||
|
||||
constructor(label: string) {
|
||||
this._id = '_' + Math.random().toString(16);
|
||||
@ -14,8 +18,22 @@ export abstract class BaseUIElement {
|
||||
this._onEnabledChanged();
|
||||
}
|
||||
|
||||
public getCachedValue() {
|
||||
ASSERT(this._cachedValue !== undefined, 'Attempting to access value before cached');
|
||||
return this._cachedValue;
|
||||
}
|
||||
|
||||
protected getValue() {
|
||||
return this._value;
|
||||
}
|
||||
|
||||
public cacheValue() {
|
||||
this._cachedValue = this.getValue();
|
||||
}
|
||||
|
||||
public abstract generateHTML(): string;
|
||||
public abstract registerEvents(): void;
|
||||
|
||||
|
||||
protected abstract _onEnabledChanged(): void;
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ export class ComboBoxElement extends LabelledElement {
|
||||
public registerEvents(): void {
|
||||
}
|
||||
|
||||
public getValue() {
|
||||
protected getValue() {
|
||||
const element = document.getElementById(this._id) as HTMLSelectElement;
|
||||
ASSERT(element !== null);
|
||||
return this._items[element.selectedIndex].id;
|
||||
|
@ -42,18 +42,16 @@ export class FileInputElement extends LabelledElement {
|
||||
if (files && files.length === 1) {
|
||||
const filePath = files[0];
|
||||
this._loadedFilePath = filePath;
|
||||
this._value = filePath;
|
||||
} else {
|
||||
this._loadedFilePath = '';
|
||||
this._value = '';
|
||||
}
|
||||
const parsedPath = path.parse(this._loadedFilePath);
|
||||
element.innerHTML = parsedPath.name + parsedPath.ext;
|
||||
};
|
||||
}
|
||||
|
||||
public getValue() {
|
||||
return this._loadedFilePath;
|
||||
}
|
||||
|
||||
protected _onEnabledChanged() {
|
||||
super._onEnabledChanged();
|
||||
|
||||
|
@ -6,7 +6,6 @@ export class SliderElement extends LabelledElement {
|
||||
private _min: number;
|
||||
private _max: number;
|
||||
private _decimals: number;
|
||||
private _value: number;
|
||||
private _dragging: boolean;
|
||||
|
||||
public constructor(label: string, min: number, max: number, decimals: number, value: number) {
|
||||
@ -77,7 +76,7 @@ export class SliderElement extends LabelledElement {
|
||||
elementValue.innerHTML = this._value.toFixed(this._decimals);
|
||||
}
|
||||
|
||||
public getValue() {
|
||||
protected getValue() {
|
||||
return this._value;
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,8 @@ import { ComboBoxElement } from './elements/combobox';
|
||||
import { FileInputElement } from './elements/file_input';
|
||||
import { ButtonElement } from './elements/button';
|
||||
import { OutputElement } from './elements/output';
|
||||
import { Action, ActionReturnType, AppContext } from '../app_context';
|
||||
import { Action, AppContext } from '../app_context';
|
||||
import { LOG } from '../util';
|
||||
|
||||
export interface Group {
|
||||
label: string;
|
||||
@ -13,6 +14,7 @@ export interface Group {
|
||||
submitButton: ButtonElement;
|
||||
output: OutputElement;
|
||||
}
|
||||
|
||||
export class UI {
|
||||
public uiOrder = ['import', 'simplify', 'build', 'palette', 'export'];
|
||||
private _ui = {
|
||||
@ -138,6 +140,15 @@ export class UI {
|
||||
` + itemHTML + `</div></div>`;
|
||||
}
|
||||
|
||||
public cacheValues(action: Action) {
|
||||
const group = this._getActionGroup(action);
|
||||
for (const elementName of group.elementsOrder) {
|
||||
LOG(`Caching ${elementName}`);
|
||||
const element = group.elements[elementName];
|
||||
element.cacheValue();
|
||||
}
|
||||
}
|
||||
|
||||
private _buildGroup(group: Group) {
|
||||
let groupHTML = '';
|
||||
for (const elementName of group.elementsOrder) {
|
||||
@ -212,4 +223,9 @@ export class UI {
|
||||
group.output.clearMessage();
|
||||
}
|
||||
}
|
||||
|
||||
private _getActionGroup(action: Action): Group {
|
||||
const key = this.uiOrder[action];
|
||||
return this._uiDull[key];
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import { OcclusionManager } from './occlusion';
|
||||
import { Axes, generateRays, rayIntersectTriangle } from './ray';
|
||||
import { Texture, TextureFiltering } from './texture';
|
||||
import { Triangle, UVTriangle } from './triangle';
|
||||
import { UI } from './ui/layout';
|
||||
import { Bounds, LOG, RGB, UV } from './util';
|
||||
import { Vector3 } from './vector';
|
||||
|
||||
@ -23,9 +24,10 @@ export class VoxelMesh {
|
||||
private _loadedTextures: { [materialName: string]: Texture };
|
||||
private _bounds: Bounds;
|
||||
|
||||
public constructor(desiredHeight: number) {
|
||||
public constructor() {
|
||||
LOG('New voxel mesh');
|
||||
|
||||
const desiredHeight = UI.Get.layout.build.elements.height.getCachedValue() as number;
|
||||
this._voxelSize = 8.0 / Math.round(desiredHeight);
|
||||
this._voxels = [];
|
||||
this._voxelsHash = new HashMap(2048);
|
||||
@ -41,7 +43,7 @@ export class VoxelMesh {
|
||||
return this._voxelsHash.has(pos);
|
||||
}
|
||||
|
||||
public voxelise(mesh: Mesh, multisampleColouring: boolean, filtering: TextureFiltering) {
|
||||
public voxelise(mesh: Mesh) {
|
||||
LOG('Voxelising');
|
||||
|
||||
mesh.tris.forEach((tri, index) => {
|
||||
@ -52,11 +54,11 @@ export class VoxelMesh {
|
||||
}
|
||||
}
|
||||
const uvTriangle = mesh.getUVTriangle(index);
|
||||
this._voxeliseTri(uvTriangle, material, tri.material, multisampleColouring, filtering);
|
||||
this._voxeliseTri(uvTriangle, material, tri.material);
|
||||
});
|
||||
}
|
||||
|
||||
private _voxeliseTri(triangle: UVTriangle, material: (SolidMaterial | TexturedMaterial), materialName: string, multisampleColouring: boolean, filtering: TextureFiltering) {
|
||||
private _voxeliseTri(triangle: UVTriangle, material: (SolidMaterial | TexturedMaterial), materialName: string) {
|
||||
const v0Scaled = Vector3.divScalar(triangle.v0, this._voxelSize);
|
||||
const v1Scaled = Vector3.divScalar(triangle.v1, this._voxelSize);
|
||||
const v2Scaled = Vector3.divScalar(triangle.v2, this._voxelSize);
|
||||
@ -79,22 +81,23 @@ export class VoxelMesh {
|
||||
}
|
||||
|
||||
let voxelColour: RGB;
|
||||
if (multisampleColouring && material.type === MaterialType.textured) {
|
||||
const useMultisampleColouring = UI.Get.layout.build.elements.multisampleColouring.getCachedValue() as string === 'on';
|
||||
if (useMultisampleColouring && material.type === MaterialType.textured) {
|
||||
const samples: RGB[] = [];
|
||||
for (let i = 0; i < AppConfig.MULTISAMPLE_COUNT; ++i) {
|
||||
const samplePosition = Vector3.mulScalar(Vector3.add(voxelPosition, Vector3.random().addScalar(-0.5)), this._voxelSize);
|
||||
samples.push(this._getVoxelColour(triangle, material, materialName, samplePosition, filtering));
|
||||
samples.push(this._getVoxelColour(triangle, material, materialName, samplePosition));
|
||||
}
|
||||
voxelColour = RGB.averageFrom(samples);
|
||||
} else {
|
||||
voxelColour = this._getVoxelColour(triangle, material, materialName, Vector3.mulScalar(voxelPosition, this._voxelSize), filtering);
|
||||
voxelColour = this._getVoxelColour(triangle, material, materialName, Vector3.mulScalar(voxelPosition, this._voxelSize));
|
||||
}
|
||||
this._addVoxel(voxelPosition, voxelColour);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private _getVoxelColour(triangle: UVTriangle, material: (SolidMaterial | TexturedMaterial), materialName: string, location: Vector3, filtering: TextureFiltering): RGB {
|
||||
private _getVoxelColour(triangle: UVTriangle, material: (SolidMaterial | TexturedMaterial), materialName: string, location: Vector3): RGB {
|
||||
if (material.type == MaterialType.solid) {
|
||||
return material.colour;
|
||||
}
|
||||
@ -112,7 +115,8 @@ export class VoxelMesh {
|
||||
triangle.uv0.u * w0 + triangle.uv1.u * w1 + triangle.uv2.u * w2,
|
||||
triangle.uv0.v * w0 + triangle.uv1.v * w1 + triangle.uv2.v * w2,
|
||||
);
|
||||
|
||||
|
||||
const filtering = UI.Get.layout.build.elements.textureFiltering.getCachedValue() as string === 'linear' ? TextureFiltering.Linear : TextureFiltering.Nearest;
|
||||
return this._loadedTextures[materialName].getRGB(uv, filtering);
|
||||
}
|
||||
|
||||
@ -147,7 +151,7 @@ export class VoxelMesh {
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public createBuffer(ambientOcclusionEnabled: boolean) {
|
||||
public createBuffer() {
|
||||
const buffer = new RenderBuffer([
|
||||
{ name: 'position', numComponents: 3 },
|
||||
{ name: 'colour', numComponents: 3 },
|
||||
@ -156,6 +160,7 @@ export class VoxelMesh {
|
||||
{ name: 'normal', numComponents: 3 },
|
||||
]);
|
||||
|
||||
const ambientOcclusionEnabled = UI.Get.layout.build.elements.ambientOcclusion.getCachedValue() as string === 'on';
|
||||
for (const voxel of this._voxels) {
|
||||
// Each vertex of a face needs the occlusion data for the other 3 vertices
|
||||
// in it's face, not just itself. Also flatten occlusion data.
|
||||
|
Loading…
Reference in New Issue
Block a user