Update voxel mesh constructor

This commit is contained in:
Lucas Dower 2023-12-13 20:09:49 +00:00
parent 0a5c4376ab
commit fcbb67c559
5 changed files with 70 additions and 35 deletions

View File

@ -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<OtS_Voxel> {
const voxelsCopy: OtS_Voxel[] = Array.from(this._voxels.values()).map((voxel) => {

View File

@ -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 {

View File

@ -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);

View File

@ -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');

View File

@ -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');