Fixed schematic-friendly palette, added tests

This commit is contained in:
Lucas Dower 2022-09-17 12:00:30 +01:00
parent 27abfb348c
commit e25e7850ad
21 changed files with 172 additions and 81 deletions

View File

@ -8,10 +8,9 @@
"node": ">=14.0.0"
},
"scripts": {
"lint": "eslint --fix src tools --ext .ts",
"lint": "eslint --fix src tools tests --ext .ts",
"build": "tsc",
"test": "jest --config jestconfig.json",
"test-full": "jest --config jestconfig.full.json --runInBand",
"test": "jest --config jestconfig.json --runInBand",
"start": "npm run build && electron ./dist/src/main.js --enable-logging",
"atlas": "node ./dist/tools/build-atlas.js",
"palette": "node ./dist/tools/build-palette.js",

View File

@ -1,5 +1,4 @@
import { BlockMesh } from '../block_mesh';
import { TOptional } from '../util';
import { Vector3 } from '../vector';
export abstract class IExporter {

View File

@ -104,8 +104,8 @@ export class Palette {
public remove(blockName: string): boolean {
const index = this._blocks.indexOf(AppUtil.Text.namespaceBlock(blockName));
if (index !== undefined) {
this._blocks.slice(index, 1);
if (index !== -1) {
this._blocks.splice(index, 1);
return true;
}
return false;
@ -164,8 +164,8 @@ export class Palette {
}
/**
* atlas. If not, the block is removed from the palette.
* Checks if each block in this block palette has texture data in the given
* Removes blocks from the palette if they do not
* have texture data in the given atlas.
*/
public removeMissingAtlasBlocks(atlas: Atlas) {
const missingBlocks: AppTypes.TNamespacedBlockName[] = [];

View File

@ -9,6 +9,7 @@ export class AppError extends Error {
export function ASSERT(condition: any, errorMessage = 'Assertion Failed'): asserts condition {
if (AppConfig.ASSERTIONS_ENABLED && !condition) {
Error(errorMessage);
throw Error(errorMessage);
}
}

View File

@ -1,7 +1,7 @@
import fs from 'fs';
import { AppConfig } from '../config';
import util from 'util';
import { AppConfig } from '../config';
import { FileUtil } from './file_util';
import { AppPaths, PathUtil } from './path_util';

View File

@ -6,11 +6,11 @@ import { ExporterFactory } from './exporters/exporters';
import { ObjImporter } from './importers/obj_importer';
import { Mesh } from './mesh';
import { ASSERT } from './util/error_util';
import { Logger } from './util/log_util';
import { VoxelMesh } from './voxel_mesh';
import { IVoxeliser } from './voxelisers/base-voxeliser';
import { VoxeliserFactory } from './voxelisers/voxelisers';
import { AssignParams, ExportParams, ImportParams, RenderBlockMeshParams, RenderMeshParams, RenderVoxelMeshParams, VoxeliseParams } from './worker_types';
import { Logger } from './util/log_util';
export class WorkerClient {
private static _instance: WorkerClient;

View File

@ -1,6 +1,9 @@
import { AttributeData, MergeAttributeData } from '../src/render_buffer';
import { TEST_PREAMBLE } from './preamble';
test('MergeAttributeData #1', () => {
TEST_PREAMBLE();
const a: AttributeData = {
indices: new Uint32Array([0, 1, 2]),
custom: {
@ -13,6 +16,8 @@ test('MergeAttributeData #1', () => {
});
test('MergeAttributeData #2', () => {
TEST_PREAMBLE();
const a: AttributeData = {
indices: new Uint32Array([0, 1, 2]),
custom: {
@ -45,6 +50,8 @@ test('MergeAttributeData #2', () => {
});
test('MergeAttributeData #3', () => {
TEST_PREAMBLE();
const a: AttributeData = {
indices: new Uint32Array([0, 1]),
custom: {

View File

@ -1,13 +1,16 @@
import { NormalCorrectedRayVoxeliser } from '../src/voxelisers/normal-corrected-ray-voxeliser';
import path from 'path';
import { RGBAColours } from '../src/colour';
import { ObjImporter } from '../src/importers/obj_importer';
import { TextureFiltering } from '../src/texture';
import { Vector3 } from '../src/vector';
import path from 'path';
import { RGBAColours } from '../src/colour';
import { ASSERT } from '../src/util/error_util';
import { Vector3 } from '../src/vector';
import { NormalCorrectedRayVoxeliser } from '../src/voxelisers/normal-corrected-ray-voxeliser';
import { TEST_PREAMBLE } from './preamble';
test('Voxelise solid 2x2 cube', () => {
TEST_PREAMBLE();
const importer = new ObjImporter();
importer.parseFile(path.join(__dirname, './data/cube.obj'));
const mesh = importer.toMesh();

View File

@ -1,8 +1,11 @@
import { ObjImporter } from '../src/importers/obj_importer';
import { ASSERT } from '../src/util/error_util';
import { Vector3 } from '../src/vector';
import { TEST_PREAMBLE } from './preamble';
test('Parse vertex #1', () => {
TEST_PREAMBLE();
const importer = new ObjImporter();
importer.parseOBJLine('v 1.0 -2.0 3.0');
const mesh = importer.toMesh();
@ -11,6 +14,8 @@ test('Parse vertex #1', () => {
});
test('Parse vertex #2', () => {
TEST_PREAMBLE();
const importer = new ObjImporter();
importer.parseOBJLine('v 4.467e+000 9.243e+000 9.869e+000');
const mesh = importer.toMesh();
@ -19,6 +24,8 @@ test('Parse vertex #2', () => {
});
test('Parse normal #1', () => {
TEST_PREAMBLE();
const importer = new ObjImporter();
importer.parseOBJLine('vn -1.0 -0.5 0.0');
const mesh = importer.toMesh();
@ -27,6 +34,8 @@ test('Parse normal #1', () => {
});
test('Parse texcoord #1', () => {
TEST_PREAMBLE();
const importer = new ObjImporter();
importer.parseOBJLine('vt 0.5 -0.8');
const mesh = importer.toMesh();
@ -35,6 +44,8 @@ test('Parse texcoord #1', () => {
});
test('Parse face #1', () => {
TEST_PREAMBLE();
const importer = new ObjImporter();
importer.parseOBJLine('f 12 24 36');
const mesh = importer.toMesh();
@ -48,6 +59,8 @@ test('Parse face #1', () => {
});
test('Parse face #2', () => {
TEST_PREAMBLE();
const importer = new ObjImporter();
importer.parseOBJLine('f 1/2 3/4 5/6');
const mesh = importer.toMesh();
@ -60,6 +73,8 @@ test('Parse face #2', () => {
});
test('Parse face #3', () => {
TEST_PREAMBLE();
const importer = new ObjImporter();
importer.parseOBJLine('f 11/2/3 4/55/6 7/8/99');
const mesh = importer.toMesh();
@ -67,12 +82,14 @@ test('Parse face #3', () => {
const tri = mesh._tris[0];
expect(tri.texcoordIndices).toBeDefined(); ASSERT(tri.texcoordIndices);
expect(tri.normalIndices).toBeDefined(); ASSERT(tri.normalIndices);
expect(tri.positionIndices.x === 11 - 1 && tri.positionIndices.y === 4 - 1&& tri.positionIndices.z === 7 - 1).toBe(true);
expect(tri.positionIndices.x === 11 - 1 && tri.positionIndices.y === 4 - 1 && tri.positionIndices.z === 7 - 1).toBe(true);
expect(tri.texcoordIndices.x === 2 - 1 && tri.texcoordIndices.y === 55 - 1 && tri.texcoordIndices.z === 8 - 1).toBe(true);
expect(tri.normalIndices.x === 3 - 1 && tri.normalIndices.y === 6 - 1 && tri.normalIndices.z === 99 - 1).toBe(true);
});
test('Parse mini #1', () => {
TEST_PREAMBLE();
const importer = new ObjImporter();
importer.parseOBJLine('v -1 2 3');
importer.parseOBJLine('v 4 -5 6');
@ -109,6 +126,8 @@ test('Parse mini #1', () => {
test('Parse mini #2', () => {
TEST_PREAMBLE();
const importer = new ObjImporter();
importer.parseOBJLine('v -1 2 3');
importer.parseOBJLine('v 4 -5 6');
@ -144,6 +163,8 @@ test('Parse mini #2', () => {
});
test('Parse mini #3', () => {
TEST_PREAMBLE();
const importer = new ObjImporter();
importer.parseOBJLine('v 0 0 0');
importer.parseOBJLine('v 1 0 0');
@ -168,6 +189,8 @@ test('Parse mini #3', () => {
});
test('Parse comments', () => {
TEST_PREAMBLE();
const importer = new ObjImporter();
importer.parseOBJLine('# v -1 2 3');
importer.parseOBJLine('# vn 0.0 0.1 0.2');

View File

@ -1,9 +1,8 @@
import { TextureFiltering } from '../../src/texture';
import { ColourSpace } from '../../src/util';
import { AppPaths, PathUtil } from '../../src/util/path_util';
import { runHeadless, THeadlessConfig } from '../../tools/headless';
import { FileUtil } from '../../src/util/file_util';
import { TEST_PREAMBLE } from '../preamble';
import { TextureFiltering } from '../src/texture';
import { ColourSpace } from '../src/util';
import { AppPaths, PathUtil } from '../src/util/path_util';
import { runHeadless, THeadlessConfig } from '../tools/headless';
import { TEST_PREAMBLE } from './preamble';
const baseConfig: THeadlessConfig = {
import: {
@ -38,9 +37,6 @@ const baseConfig: THeadlessConfig = {
test('FULL Obj->Obj', () => {
TEST_PREAMBLE();
AppPaths.Get.setBaseDir(PathUtil.join(__dirname, '../..'));
FileUtil.mkdirSyncIfNotExist(PathUtil.join(AppPaths.Get.testData, '../out/'));
const config: THeadlessConfig = baseConfig;
config.import.filepath = PathUtil.join(AppPaths.Get.resources, './samples/skull.obj');

View File

@ -1,9 +1,8 @@
import { TextureFiltering } from '../../src/texture';
import { ColourSpace } from '../../src/util';
import { AppPaths, PathUtil } from '../../src/util/path_util';
import { runHeadless, THeadlessConfig } from '../../tools/headless';
import { FileUtil } from '../../src/util/file_util';
import { TEST_PREAMBLE } from '../preamble';
import { TextureFiltering } from '../src/texture';
import { ColourSpace } from '../src/util';
import { AppPaths, PathUtil } from '../src/util/path_util';
import { runHeadless, THeadlessConfig } from '../tools/headless';
import { TEST_PREAMBLE } from './preamble';
const baseConfig: THeadlessConfig = {
import: {
@ -38,9 +37,6 @@ const baseConfig: THeadlessConfig = {
test('FULL Obj->Obj', () => {
TEST_PREAMBLE();
AppPaths.Get.setBaseDir(PathUtil.join(__dirname, '../..'));
FileUtil.mkdirSyncIfNotExist(PathUtil.join(AppPaths.Get.testData, '../out/'));
const config: THeadlessConfig = baseConfig;
config.import.filepath = PathUtil.join(AppPaths.Get.resources, './samples/skull.obj');

View File

@ -1,9 +1,8 @@
import { TextureFiltering } from '../../src/texture';
import { ColourSpace } from '../../src/util';
import { AppPaths, PathUtil } from '../../src/util/path_util';
import { runHeadless, THeadlessConfig } from '../../tools/headless';
import { FileUtil } from '../../src/util/file_util';
import { TEST_PREAMBLE } from '../preamble';
import { TextureFiltering } from '../src/texture';
import { ColourSpace } from '../src/util';
import { AppPaths, PathUtil } from '../src/util/path_util';
import { runHeadless, THeadlessConfig } from '../tools/headless';
import { TEST_PREAMBLE } from './preamble';
const baseConfig: THeadlessConfig = {
import: {
@ -38,9 +37,6 @@ const baseConfig: THeadlessConfig = {
test('FULL Obj->Obj', () => {
TEST_PREAMBLE();
AppPaths.Get.setBaseDir(PathUtil.join(__dirname, '../..'));
FileUtil.mkdirSyncIfNotExist(PathUtil.join(AppPaths.Get.testData, '../out/'));
const config: THeadlessConfig = baseConfig;
config.import.filepath = PathUtil.join(AppPaths.Get.resources, './samples/skull.obj');

View File

@ -1,9 +1,8 @@
import { TextureFiltering } from '../../src/texture';
import { ColourSpace } from '../../src/util';
import { AppPaths, PathUtil } from '../../src/util/path_util';
import { runHeadless, THeadlessConfig } from '../../tools/headless';
import { FileUtil } from '../../src/util/file_util';
import { TEST_PREAMBLE } from '../preamble';
import { TextureFiltering } from '../src/texture';
import { ColourSpace } from '../src/util';
import { AppPaths, PathUtil } from '../src/util/path_util';
import { runHeadless, THeadlessConfig } from '../tools/headless';
import { TEST_PREAMBLE } from './preamble';
const baseConfig: THeadlessConfig = {
import: {
@ -38,9 +37,6 @@ const baseConfig: THeadlessConfig = {
test('FULL Obj->Schematic', () => {
TEST_PREAMBLE();
AppPaths.Get.setBaseDir(PathUtil.join(__dirname, '../..'));
FileUtil.mkdirSyncIfNotExist(PathUtil.join(AppPaths.Get.testData, '../out/'));
const config: THeadlessConfig = baseConfig;
config.import.filepath = PathUtil.join(AppPaths.Get.resources, './samples/skull.obj');

9
tests/palette.test.ts Normal file
View File

@ -0,0 +1,9 @@
import { Palette } from '../src/palette';
test('Palette', () => {
const myPalette = Palette.create();
myPalette.add('minecraft:stone');
expect(myPalette.count()).toBe(1);
myPalette.remove('minecraft:stone');
expect(myPalette.count()).toBe(0);
});

View File

@ -1,5 +1,9 @@
import { Logger } from "../src/util/log_util"
import { FileUtil } from '../src/util/file_util';
import { Logger } from '../src/util/log_util';
import { AppPaths, PathUtil } from '../src/util/path_util';
export const TEST_PREAMBLE = () => {
Logger.Get.disableLogToFile();
}
AppPaths.Get.setBaseDir(PathUtil.join(__dirname, '..'));
FileUtil.mkdirSyncIfNotExist(PathUtil.join(AppPaths.Get.testData, './out/'));
};

View File

@ -1,9 +1,12 @@
import { Ray, Axes, rayIntersectTriangle } from '../src/ray';
import { Vector3 } from '../src/vector';
import { Axes, Ray, rayIntersectTriangle } from '../src/ray';
import { Triangle } from '../src/triangle';
import { ASSERT } from '../src/util/error_util';
import { Vector3 } from '../src/vector';
import { TEST_PREAMBLE } from './preamble';
test('rayIntersectTriangle x-axis #1', () => {
TEST_PREAMBLE();
const ray: Ray = {
origin: new Vector3(-1, 0, 0),
axis: Axes.x,
@ -20,6 +23,8 @@ test('rayIntersectTriangle x-axis #1', () => {
});
test('rayIntersectTriangle x-axis #2', () => {
TEST_PREAMBLE();
const ray: Ray = {
origin: new Vector3(1, 0, 0),
axis: Axes.x,
@ -34,14 +39,16 @@ test('rayIntersectTriangle x-axis #2', () => {
});
test('rayIntersectTriangle y-axis #1', () => {
TEST_PREAMBLE();
const ray: Ray = {
origin: new Vector3(0, -1, 0),
axis: Axes.y,
};
const tri = new Triangle(
new Vector3(-1, 6, -1),
new Vector3( 0, 6, 1),
new Vector3( 1, 6, -1),
new Vector3(0, 6, 1),
new Vector3(1, 6, -1),
);
const intersects = rayIntersectTriangle(ray, tri.v0, tri.v1, tri.v2);
expect(intersects).toBeDefined();
@ -50,28 +57,32 @@ test('rayIntersectTriangle y-axis #1', () => {
});
test('rayIntersectTriangle y-axis #2', () => {
TEST_PREAMBLE();
const ray: Ray = {
origin: new Vector3(0, 1, 0),
axis: Axes.y,
};
const tri = new Triangle(
new Vector3(-1, 0, -1),
new Vector3( 0, 0, 1),
new Vector3( 1, 0, -1),
new Vector3(0, 0, 1),
new Vector3(1, 0, -1),
);
const intersects = rayIntersectTriangle(ray, tri.v0, tri.v1, tri.v2);
expect(intersects).toBeUndefined();
});
test('rayIntersectTriangle z-axis #1', () => {
TEST_PREAMBLE();
const ray: Ray = {
origin: new Vector3(0, 0, -1),
axis: Axes.z,
};
const tri = new Triangle(
new Vector3(-1, -1, 7),
new Vector3( 0, 1, 7),
new Vector3( 1, -1, 7),
new Vector3(0, 1, 7),
new Vector3(1, -1, 7),
);
const intersects = rayIntersectTriangle(ray, tri.v0, tri.v1, tri.v2);
expect(intersects).toBeDefined();
@ -80,14 +91,16 @@ test('rayIntersectTriangle z-axis #1', () => {
});
test('rayIntersectTriangle z-axis #2', () => {
TEST_PREAMBLE();
const ray: Ray = {
origin: new Vector3(0, 0, 1),
axis: Axes.z,
};
const tri = new Triangle(
new Vector3(-1, -1, 0),
new Vector3( 0, 1, 0),
new Vector3( 1, -1, 0),
new Vector3(0, 1, 0),
new Vector3(1, -1, 0),
);
const intersects = rayIntersectTriangle(ray, tri.v0, tri.v1, tri.v2);
expect(intersects).toBeUndefined();

View File

@ -0,0 +1,15 @@
import { WorkerClient } from '../src/worker_client';
import { headlessConfig } from '../tools/headless-config';
import { TEST_PREAMBLE } from './preamble';
test('Schematic-friendly Palette', () => {
TEST_PREAMBLE();
const worker = WorkerClient.Get;
const config = headlessConfig;
config.assign.blockPalette = 'schematic-friendly';
worker.import(headlessConfig.import);
worker.voxelise(headlessConfig.voxelise);
worker.assign(headlessConfig.assign);
});

View File

@ -1,6 +1,9 @@
import { StatusHandler } from '../src/status';
import { TEST_PREAMBLE } from './preamble';
test('Status', () => {
TEST_PREAMBLE();
StatusHandler.Get.add(
'warning',
'This is a warning',
@ -11,6 +14,8 @@ test('Status', () => {
});
test('Status', () => {
TEST_PREAMBLE();
StatusHandler.Get.add(
'warning',
'This is a warning',
@ -23,9 +28,9 @@ test('Status', () => {
'info',
'This is some more info',
);
expect(StatusHandler.Get.getStatusMessages( 'info').length).toBe(2);
expect(StatusHandler.Get.getStatusMessages( 'warning').length).toBe(1);
expect(StatusHandler.Get.getStatusMessages('info').length).toBe(2);
expect(StatusHandler.Get.getStatusMessages('warning').length).toBe(1);
StatusHandler.Get.clear();
expect(StatusHandler.Get.getStatusMessages( 'info').length).toBe(0);
expect(StatusHandler.Get.getStatusMessages( 'warning').length).toBe(0);
expect(StatusHandler.Get.getStatusMessages('info').length).toBe(0);
expect(StatusHandler.Get.getStatusMessages('warning').length).toBe(0);
});

View File

@ -1,7 +1,11 @@
import { RegExpBuilder, REGEX_NUMBER, REGEX_NZ_ANY } from '../src/util/regex_util';
import { AppUtil } from '../src/util';
import { ASSERT } from '../src/util/error_util';
import { REGEX_NUMBER, REGEX_NZ_ANY, RegExpBuilder } from '../src/util/regex_util';
import { TEST_PREAMBLE } from './preamble';
test('RegExpBuilder', () => {
TEST_PREAMBLE();
const regex = new RegExpBuilder()
.add(/hello/)
.toRegExp();
@ -10,6 +14,8 @@ test('RegExpBuilder', () => {
});
test('RegExpBuilder REGEX_NUMBER', () => {
TEST_PREAMBLE();
const tests = [
{ f: '0', s: 0 },
{ f: '0.0', s: 0.0 },
@ -26,6 +32,8 @@ test('RegExpBuilder REGEX_NUMBER', () => {
});
test('RegExpBuilder Required-whitespace', () => {
TEST_PREAMBLE();
const regex = new RegExpBuilder()
.add(/hello/)
.addNonzeroWhitespace()
@ -37,6 +45,8 @@ test('RegExpBuilder Required-whitespace', () => {
});
test('RegExpBuilder Optional', () => {
TEST_PREAMBLE();
const regex = new RegExpBuilder()
.add(/hello/)
.addNonzeroWhitespace()
@ -49,6 +59,8 @@ test('RegExpBuilder Optional', () => {
});
test('RegExpBuilder Capture', () => {
TEST_PREAMBLE();
const regex = new RegExpBuilder()
.add(/[0-9]+/, 'myNumber')
.toRegExp();
@ -61,6 +73,8 @@ test('RegExpBuilder Capture', () => {
});
test('RegExpBuilder Capture-multiple', () => {
TEST_PREAMBLE();
const regex = new RegExpBuilder()
.add(/[0-9]+/, 'x')
.addNonzeroWhitespace()
@ -82,6 +96,8 @@ test('RegExpBuilder Capture-multiple', () => {
});
test('RegExpBuilder Capture-multiple', () => {
TEST_PREAMBLE();
const regex = new RegExpBuilder()
.add(/f/)
.addNonzeroWhitespace()
@ -124,6 +140,8 @@ test('RegExpBuilder Capture-multiple', () => {
});
test('RegExpBuilder Capture-multiple', () => {
TEST_PREAMBLE();
const regex = new RegExpBuilder()
.add(/usemtl/)
.add(/ /)
@ -136,3 +154,11 @@ test('RegExpBuilder Capture-multiple', () => {
expect(exec.groups['path']).toBe('hellothere.txt');
}
});
test('Namespace block', () => {
expect(AppUtil.Text.namespaceBlock('stone')).toBe('minecraft:stone');
});
test('Namespace already namespaced block', () => {
expect(AppUtil.Text.namespaceBlock('minecraft:stone')).toBe('minecraft:stone');
});

View File

@ -1,9 +1,12 @@
import { Vector3 } from '../src/vector';
import { VoxelMesh } from '../src/voxel_mesh';
import { RGBAColours } from '../src/colour';
import { ASSERT } from '../src/util/error_util';
import { Vector3 } from '../src/vector';
import { VoxelMesh } from '../src/voxel_mesh';
import { TEST_PREAMBLE } from './preamble';
test('Voxel neighbours', () => {
TEST_PREAMBLE();
const voxelMesh = new VoxelMesh({
voxelOverlapRule: 'first',
enableAmbientOcclusion: true,

View File

@ -1,4 +1,4 @@
import { Logger, LOG_MAJOR } from '../src/util/log_util';
import { LOG_MAJOR, Logger } from '../src/util/log_util';
import { AppPaths, PathUtil } from '../src/util/path_util';
import { runHeadless } from './headless';
import { headlessConfig } from './headless-config';