From fcbb67c559a8dc389d0f252b8674a9367694fedc Mon Sep 17 00:00:00 2001 From: Lucas Dower Date: Wed, 13 Dec 2023 20:09:49 +0000 Subject: [PATCH] Update voxel mesh constructor --- Core/src/ots_voxel_mesh.ts | 64 ++++++++++++++----- Core/src/ots_voxel_mesh_converter.ts | 5 +- Core/tests/ots_block_mesh_converter.test.ts | 4 +- Core/tests/ots_voxel_mesh.test.ts | 20 +++--- .../ots_voxel_mesh_neighbourhood.test.ts | 12 ++-- 5 files changed, 70 insertions(+), 35 deletions(-) diff --git a/Core/src/ots_voxel_mesh.ts b/Core/src/ots_voxel_mesh.ts index 618dd25..de7d070 100644 --- a/Core/src/ots_voxel_mesh.ts +++ b/Core/src/ots_voxel_mesh.ts @@ -20,20 +20,38 @@ export class OtS_VoxelMesh { private _bounds: Bounds; private _replaceMode: OtS_ReplaceMode; - public constructor() { + /** + * Create a new voxel mesh + * @returns A new `OtS_VoxelMesh` instance + */ + public static Create(): OtS_VoxelMesh { + return new OtS_VoxelMesh(); + } + + private constructor() { this._voxels = new Map(); this._bounds = Bounds.getEmptyBounds(); this._isBoundsDirty = false; this._replaceMode = 'average'; } + /** + * Set the behaviour for what should happen when adding a voxel in a + * position where one already exists + * @param replaceMode The behaviour to set + */ public setReplaceMode(replaceMode: OtS_ReplaceMode) { this._replaceMode = replaceMode; } - public addVoxel(x: number, y: number, z: number, colour: RGBA, replaceMode?: OtS_ReplaceMode) { - const useReplaceMode = replaceMode ?? this._replaceMode; - + /** + * Add a voxel at a position with a particular colour + * @param x The x-coordinate (north/south) + * @param y The y-coordinate (up/down) + * @param z The z-coordinate (east/west) + * @param colour The colour of the voxel + */ + public addVoxel(x: number, y: number, z: number, colour: RGBA) { const key = Vector3.Hash(x, y, z); let voxel: (OtS_Voxel_Internal | undefined) = this._voxels.get(key); @@ -48,13 +66,13 @@ export class OtS_VoxelMesh { //this._bounds.extendByPoint(position); this._isBoundsDirty = true; } else { - if (useReplaceMode === 'average') { + if (this._replaceMode === 'average') { voxel.colour.r = ((voxel.colour.r * voxel.collisions) + colour.r) / (voxel.collisions + 1); voxel.colour.g = ((voxel.colour.g * voxel.collisions) + colour.g) / (voxel.collisions + 1); voxel.colour.b = ((voxel.colour.b * voxel.collisions) + colour.b) / (voxel.collisions + 1); voxel.colour.a = ((voxel.colour.a * voxel.collisions) + colour.a) / (voxel.collisions + 1); ++voxel.collisions; - } else if (useReplaceMode === 'replace') { + } else if (this._replaceMode === 'replace') { voxel.colour = RGBAUtil.copy(colour); voxel.collisions = 1; } @@ -62,7 +80,11 @@ export class OtS_VoxelMesh { } /** - * Remove a voxel from a given location. + * Remoave a voxel at a position + * @param x The x-coordinate (north/south) + * @param y The y-coordinate (up/down) + * @param z The z-coordinate (east/west) + * @returns Whether or not a voxel was found and removed */ public removeVoxel(x: number, y: number, z: number): boolean { const key = Vector3.Hash(x, y, z); @@ -72,9 +94,11 @@ export class OtS_VoxelMesh { } /** - * Returns the colour of a voxel at a location, if one exists. - * @note Modifying the returned colour will not update the voxel's colour. - * For that, use `addVoxel` with the replaceMode set to 'replace' + * Returns a copy of the voxel at a location, if one exists + * @param x The x-coordinate (north/south) + * @param y The y-coordinate (up/down) + * @param z The z-coordinate (east/west) + * @returns The copy of the voxel or null if one does not exist */ public getVoxelAt(x: number, y: number, z: number): (OtS_Voxel | null) { const key = Vector3.Hash(x, y, z); @@ -91,15 +115,23 @@ export class OtS_VoxelMesh { } /** - * Get whether or not there is a voxel at a given location. + * Get whether or not there is a voxel at a given location + * @param x The x-coordinate (north/south) + * @param y The y-coordinate (up/down) + * @param z The z-coordinate (east/west) + * @returns Whether or not a voxel is at this location */ - public isVoxelAt(x: number, y: number, z: number) { + public isVoxelAt(x: number, y: number, z: number): boolean { const key = Vector3.Hash(x, y, z); return this._voxels.has(key); } /** - * Get whether or not there is a opaque voxel at a given location. + * Get whether or not there is a opaque voxel at a given location + * @param x The x-coordinate (north/south) + * @param y The y-coordinate (up/down) + * @param z The z-coordinate (east/west) + * @returns Whether or not an opaque voxel is at this location */ public isOpaqueVoxelAt(x: number, y: number, z: number) { const voxel = this.getVoxelAt(x, y, z); @@ -107,7 +139,8 @@ export class OtS_VoxelMesh { } /** - * Get the bounds/dimensions of the VoxelMesh. + * Get the bounds/dimensions of the voxel mesh + * @returns The bounds of the voxel mesh */ public getBounds(): Bounds { if (this._isBoundsDirty) { @@ -129,7 +162,8 @@ export class OtS_VoxelMesh { /** * Iterate over the voxels in this VoxelMesh, note that these are copies - * and editing each entry will not modify the underlying voxel. + * and editing each entry will not modify the underlying voxel + * @returns An iterator to the voxels */ public getVoxels(): IterableIterator { const voxelsCopy: OtS_Voxel[] = Array.from(this._voxels.values()).map((voxel) => { diff --git a/Core/src/ots_voxel_mesh_converter.ts b/Core/src/ots_voxel_mesh_converter.ts index a7dbc0d..b9d73d7 100644 --- a/Core/src/ots_voxel_mesh_converter.ts +++ b/Core/src/ots_voxel_mesh_converter.ts @@ -40,7 +40,8 @@ export class OtS_VoxelMesh_Converter { } public process(mesh: OtS_Mesh): OtS_VoxelMesh { - const voxelMesh = new OtS_VoxelMesh(); + const voxelMesh = OtS_VoxelMesh.Create(); + voxelMesh.setReplaceMode('average'); const { scale, offset } = this._calcScaleOffset(mesh); @@ -117,7 +118,7 @@ export class OtS_VoxelMesh_Converter { ); } - voxelMesh.addVoxel(voxelPosition.x, voxelPosition.y, voxelPosition.z, voxelColour, this._config.replaceMode); + voxelMesh.addVoxel(voxelPosition.x, voxelPosition.y, voxelPosition.z, voxelColour); } private _getVoxelColour(triangle: OtS_Triangle, location: Vector3): RGBA { diff --git a/Core/tests/ots_block_mesh_converter.test.ts b/Core/tests/ots_block_mesh_converter.test.ts index a1792c7..05ac091 100644 --- a/Core/tests/ots_block_mesh_converter.test.ts +++ b/Core/tests/ots_block_mesh_converter.test.ts @@ -3,7 +3,7 @@ import { OtS_Colours, RGBAUtil } from '../src/colour'; import { OtS_BlockMesh_Converter } from '../src/ots_block_mesh_converter'; test('Per-block', () => { - const voxelMesh = new OtS_VoxelMesh(); + const voxelMesh = OtS_VoxelMesh.Create(); voxelMesh.addVoxel(0, 0, 0, OtS_Colours.RED); voxelMesh.addVoxel(1, 0, 0, OtS_Colours.GREEN); voxelMesh.addVoxel(2, 0, 0, OtS_Colours.BLUE); @@ -32,7 +32,7 @@ test('Per-block', () => { }); test('Per-face', () => { - const voxelMesh = new OtS_VoxelMesh(); + const voxelMesh = OtS_VoxelMesh.Create(); voxelMesh.addVoxel(0, 0, 0, OtS_Colours.RED); voxelMesh.addVoxel(0, -1, 0, OtS_Colours.BLUE); voxelMesh.addVoxel(1, 0, 0, OtS_Colours.BLUE); diff --git a/Core/tests/ots_voxel_mesh.test.ts b/Core/tests/ots_voxel_mesh.test.ts index f964fca..f0bd15b 100644 --- a/Core/tests/ots_voxel_mesh.test.ts +++ b/Core/tests/ots_voxel_mesh.test.ts @@ -3,13 +3,13 @@ import { ASSERT } from '../src/util/error_util'; import { Vector3 } from '../src/vector'; test('VoxelMesh #1', () => { - const voxelMesh = new OtS_VoxelMesh(); + const voxelMesh = OtS_VoxelMesh.Create(); expect(voxelMesh.getVoxelCount()).toBe(0); expect(voxelMesh.getVoxelAt(0, 0, 0)).toBe(null); }); test('VoxelMesh #2', () => { - const voxelMesh = new OtS_VoxelMesh(); + const voxelMesh = OtS_VoxelMesh.Create(); voxelMesh.addVoxel(1, 2, 3, { r: 1.0, g: 0.5, b: 0.25, a: 0.125 }, 'keep'); expect(voxelMesh.getVoxelCount()).toBe(1); expect(voxelMesh.isVoxelAt(1, 2, 3)).toBe(true); @@ -22,7 +22,7 @@ test('VoxelMesh #2', () => { }); test('VoxelMesh #3', () => { - const voxelMesh = new OtS_VoxelMesh(); + const voxelMesh = OtS_VoxelMesh.Create(); voxelMesh.addVoxel(1, 2, 3, { r: 1.0, g: 0.5, b: 0.25, a: 0.125 }, 'keep'); const voxel = voxelMesh.getVoxelAt(1, 2, 3); @@ -32,7 +32,7 @@ test('VoxelMesh #3', () => { }); test('VoxelMesh #4', () => { - const voxelMesh = new OtS_VoxelMesh(); + const voxelMesh = OtS_VoxelMesh.Create(); voxelMesh.addVoxel(1, 2, 3, { r: 1.0, g: 0.5, b: 0.25, a: 0.125 }, 'keep'); expect(voxelMesh.getVoxelAt(1, 2, 3)?.colour).toStrictEqual({ r: 1.0, g: 0.5, b: 0.25, a: 0.125 }); @@ -41,7 +41,7 @@ test('VoxelMesh #4', () => { }); test('VoxelMesh #5', () => { - const voxelMesh = new OtS_VoxelMesh(); + const voxelMesh = OtS_VoxelMesh.Create(); voxelMesh.addVoxel(1, 2, 3, { r: 1.0, g: 0.5, b: 0.25, a: 0.125 }, 'replace'); expect(voxelMesh.getVoxelAt(1, 2, 3)?.colour).toStrictEqual({ r: 1.0, g: 0.5, b: 0.25, a: 0.125 }); @@ -50,7 +50,7 @@ test('VoxelMesh #5', () => { }); test('VoxelMesh #6', () => { - const voxelMesh = new OtS_VoxelMesh(); + const voxelMesh = OtS_VoxelMesh.Create(); voxelMesh.addVoxel(1, 2, 3, { r: 1.0, g: 0.5, b: 0.125, a: 1.0 }, 'average'); expect(voxelMesh.getVoxelAt(1, 2, 3)?.colour).toStrictEqual({ r: 1.0, g: 0.5, b: 0.125, a: 1.0 }); @@ -59,7 +59,7 @@ test('VoxelMesh #6', () => { }); test('VoxelMesh #7', () => { - const voxelMesh = new OtS_VoxelMesh(); + const voxelMesh = OtS_VoxelMesh.Create(); voxelMesh.addVoxel(1, 2, 3, { r: 1.0, g: 1.0, b: 1.0, a: 1.0 }, 'average'); expect(voxelMesh.getVoxelAt(1, 2, 3)?.colour).toStrictEqual({ r: 1.0, g: 1.0, b: 1.0, a: 1.0 }); @@ -74,7 +74,7 @@ test('VoxelMesh #7', () => { }); test('VoxelMesh #8', () => { - const voxelMesh = new OtS_VoxelMesh(); + const voxelMesh = OtS_VoxelMesh.Create(); voxelMesh.addVoxel(1, 2, 3, { r: 1.0, g: 1.0, b: 1.0, a: 1.0 }, 'average'); expect(voxelMesh.getVoxelCount()).toBe(1); expect(voxelMesh.isVoxelAt(1, 2, 3)).toBe(true); @@ -87,7 +87,7 @@ test('VoxelMesh #8', () => { }); test('VoxelMesh #9', () => { - const voxelMesh = new OtS_VoxelMesh(); + const voxelMesh = OtS_VoxelMesh.Create(); voxelMesh.addVoxel(1, 2, 3, { r: 1.0, g: 1.0, b: 1.0, a: 1.0 }, 'average'); expect(voxelMesh.getBounds().getCentre().equals(new Vector3(1, 2, 3))).toBe(true); expect(voxelMesh.getBounds().getDimensions().equals(new Vector3(0, 0, 0))).toBe(true); @@ -100,7 +100,7 @@ test('VoxelMesh #9', () => { }); test('VoxelMesh #10', () => { - const voxelMesh = new OtS_VoxelMesh(); + const voxelMesh = OtS_VoxelMesh.Create(); voxelMesh.addVoxel(1, 0, 0, { r: 1.0, g: 0.0, b: 0.0, a: 1.0 }, 'replace'); voxelMesh.addVoxel(0, 1, 0, { r: 0.0, g: 1.0, b: 0.0, a: 1.0 }, 'replace'); voxelMesh.addVoxel(0, 0, 1, { r: 0.0, g: 0.0, b: 1.0, a: 1.0 }, 'replace'); diff --git a/Core/tests/ots_voxel_mesh_neighbourhood.test.ts b/Core/tests/ots_voxel_mesh_neighbourhood.test.ts index 62d0594..9158211 100644 --- a/Core/tests/ots_voxel_mesh_neighbourhood.test.ts +++ b/Core/tests/ots_voxel_mesh_neighbourhood.test.ts @@ -3,7 +3,7 @@ import { OtS_VoxelMesh } from '../src/ots_voxel_mesh'; import { OtS_FaceVisibility, OtS_VoxelMesh_Neighbourhood } from '../src/ots_voxel_mesh_neighbourhood'; test('VoxelMesh Neighbourhood #1', () => { - const voxelMesh = new OtS_VoxelMesh(); + const voxelMesh = OtS_VoxelMesh.Create(); voxelMesh.addVoxel(0, 0, 0, OtS_Colours.WHITE, 'replace'); const neighbourhood = new OtS_VoxelMesh_Neighbourhood(); @@ -19,7 +19,7 @@ test('VoxelMesh Neighbourhood #2', () => { }); test('VoxelMesh Neighbourhood #3', () => { - const voxelMesh = new OtS_VoxelMesh(); + const voxelMesh = OtS_VoxelMesh.Create(); voxelMesh.addVoxel(0, 0, 0, OtS_Colours.WHITE, 'replace'); voxelMesh.addVoxel(0, 1, 0, OtS_Colours.WHITE, 'replace'); @@ -34,7 +34,7 @@ test('VoxelMesh Neighbourhood #3', () => { }); test('VoxelMesh Neighbourhood #4', () => { - const voxelMesh = new OtS_VoxelMesh(); + const voxelMesh = OtS_VoxelMesh.Create(); voxelMesh.addVoxel(0, 0, 0, OtS_Colours.WHITE, 'replace'); voxelMesh.addVoxel(1, 0, 0, OtS_Colours.WHITE, 'replace'); voxelMesh.addVoxel(0, 1, 0, OtS_Colours.WHITE, 'replace'); @@ -61,7 +61,7 @@ test('VoxelMesh Neighbourhood #5', () => { }); test('VoxelMesh Neighbourhood #6', () => { - const voxelMesh = new OtS_VoxelMesh(); + const voxelMesh = OtS_VoxelMesh.Create(); voxelMesh.addVoxel(0, 0, 0, OtS_Colours.WHITE, 'replace'); voxelMesh.addVoxel(1, 1, 1, OtS_Colours.WHITE, 'replace'); @@ -74,7 +74,7 @@ test('VoxelMesh Neighbourhood #6', () => { test('VoxelMesh Neighbourhood #6', () => { // Checking a non-cardinal neighbour when processing using 'cardinal' mode - const voxelMesh = new OtS_VoxelMesh(); + const voxelMesh = OtS_VoxelMesh.Create(); voxelMesh.addVoxel(0, 0, 0, OtS_Colours.WHITE, 'replace'); voxelMesh.addVoxel(1, 1, 1, OtS_Colours.WHITE, 'replace'); @@ -92,7 +92,7 @@ test('VoxelMesh Neighbourhood #6', () => { test('VoxelMesh Neighbourhood #6', () => { // Checking a cardinal neighbour when processing using 'non-cardinal' mode - const voxelMesh = new OtS_VoxelMesh(); + const voxelMesh = OtS_VoxelMesh.Create(); voxelMesh.addVoxel(0, 0, 0, OtS_Colours.WHITE, 'replace'); voxelMesh.addVoxel(1, 0, 0, OtS_Colours.WHITE, 'replace');