forked from mirror/ObjToSchematic
Fixed schematic-friendly palette, added tests
This commit is contained in:
parent
27abfb348c
commit
e25e7850ad
@ -8,10 +8,9 @@
|
|||||||
"node": ">=14.0.0"
|
"node": ">=14.0.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "eslint --fix src tools --ext .ts",
|
"lint": "eslint --fix src tools tests --ext .ts",
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"test": "jest --config jestconfig.json",
|
"test": "jest --config jestconfig.json --runInBand",
|
||||||
"test-full": "jest --config jestconfig.full.json --runInBand",
|
|
||||||
"start": "npm run build && electron ./dist/src/main.js --enable-logging",
|
"start": "npm run build && electron ./dist/src/main.js --enable-logging",
|
||||||
"atlas": "node ./dist/tools/build-atlas.js",
|
"atlas": "node ./dist/tools/build-atlas.js",
|
||||||
"palette": "node ./dist/tools/build-palette.js",
|
"palette": "node ./dist/tools/build-palette.js",
|
||||||
@ -64,4 +63,4 @@
|
|||||||
"twgl.js": "^4.19.1",
|
"twgl.js": "^4.19.1",
|
||||||
"varint-array": "^0.0.0"
|
"varint-array": "^0.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,4 @@
|
|||||||
import { BlockMesh } from '../block_mesh';
|
import { BlockMesh } from '../block_mesh';
|
||||||
import { TOptional } from '../util';
|
|
||||||
import { Vector3 } from '../vector';
|
import { Vector3 } from '../vector';
|
||||||
|
|
||||||
export abstract class IExporter {
|
export abstract class IExporter {
|
||||||
|
@ -104,8 +104,8 @@ export class Palette {
|
|||||||
|
|
||||||
public remove(blockName: string): boolean {
|
public remove(blockName: string): boolean {
|
||||||
const index = this._blocks.indexOf(AppUtil.Text.namespaceBlock(blockName));
|
const index = this._blocks.indexOf(AppUtil.Text.namespaceBlock(blockName));
|
||||||
if (index !== undefined) {
|
if (index !== -1) {
|
||||||
this._blocks.slice(index, 1);
|
this._blocks.splice(index, 1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -164,8 +164,8 @@ export class Palette {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* atlas. If not, the block is removed from the palette.
|
* Removes blocks from the palette if they do not
|
||||||
* Checks if each block in this block palette has texture data in the given
|
* have texture data in the given atlas.
|
||||||
*/
|
*/
|
||||||
public removeMissingAtlasBlocks(atlas: Atlas) {
|
public removeMissingAtlasBlocks(atlas: Atlas) {
|
||||||
const missingBlocks: AppTypes.TNamespacedBlockName[] = [];
|
const missingBlocks: AppTypes.TNamespacedBlockName[] = [];
|
||||||
|
@ -9,6 +9,7 @@ export class AppError extends Error {
|
|||||||
|
|
||||||
export function ASSERT(condition: any, errorMessage = 'Assertion Failed'): asserts condition {
|
export function ASSERT(condition: any, errorMessage = 'Assertion Failed'): asserts condition {
|
||||||
if (AppConfig.ASSERTIONS_ENABLED && !condition) {
|
if (AppConfig.ASSERTIONS_ENABLED && !condition) {
|
||||||
|
Error(errorMessage);
|
||||||
throw Error(errorMessage);
|
throw Error(errorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { AppConfig } from '../config';
|
|
||||||
import util from 'util';
|
import util from 'util';
|
||||||
|
|
||||||
|
import { AppConfig } from '../config';
|
||||||
import { FileUtil } from './file_util';
|
import { FileUtil } from './file_util';
|
||||||
import { AppPaths, PathUtil } from './path_util';
|
import { AppPaths, PathUtil } from './path_util';
|
||||||
|
|
||||||
|
@ -6,11 +6,11 @@ import { ExporterFactory } from './exporters/exporters';
|
|||||||
import { ObjImporter } from './importers/obj_importer';
|
import { ObjImporter } from './importers/obj_importer';
|
||||||
import { Mesh } from './mesh';
|
import { Mesh } from './mesh';
|
||||||
import { ASSERT } from './util/error_util';
|
import { ASSERT } from './util/error_util';
|
||||||
|
import { Logger } from './util/log_util';
|
||||||
import { VoxelMesh } from './voxel_mesh';
|
import { VoxelMesh } from './voxel_mesh';
|
||||||
import { IVoxeliser } from './voxelisers/base-voxeliser';
|
import { IVoxeliser } from './voxelisers/base-voxeliser';
|
||||||
import { VoxeliserFactory } from './voxelisers/voxelisers';
|
import { VoxeliserFactory } from './voxelisers/voxelisers';
|
||||||
import { AssignParams, ExportParams, ImportParams, RenderBlockMeshParams, RenderMeshParams, RenderVoxelMeshParams, VoxeliseParams } from './worker_types';
|
import { AssignParams, ExportParams, ImportParams, RenderBlockMeshParams, RenderMeshParams, RenderVoxelMeshParams, VoxeliseParams } from './worker_types';
|
||||||
import { Logger } from './util/log_util';
|
|
||||||
|
|
||||||
export class WorkerClient {
|
export class WorkerClient {
|
||||||
private static _instance: WorkerClient;
|
private static _instance: WorkerClient;
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
import { AttributeData, MergeAttributeData } from '../src/render_buffer';
|
import { AttributeData, MergeAttributeData } from '../src/render_buffer';
|
||||||
|
import { TEST_PREAMBLE } from './preamble';
|
||||||
|
|
||||||
test('MergeAttributeData #1', () => {
|
test('MergeAttributeData #1', () => {
|
||||||
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
const a: AttributeData = {
|
const a: AttributeData = {
|
||||||
indices: new Uint32Array([0, 1, 2]),
|
indices: new Uint32Array([0, 1, 2]),
|
||||||
custom: {
|
custom: {
|
||||||
@ -13,6 +16,8 @@ test('MergeAttributeData #1', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('MergeAttributeData #2', () => {
|
test('MergeAttributeData #2', () => {
|
||||||
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
const a: AttributeData = {
|
const a: AttributeData = {
|
||||||
indices: new Uint32Array([0, 1, 2]),
|
indices: new Uint32Array([0, 1, 2]),
|
||||||
custom: {
|
custom: {
|
||||||
@ -32,7 +37,7 @@ test('MergeAttributeData #2', () => {
|
|||||||
indices: new Uint32Array([0, 1, 2, 3, 4, 5]),
|
indices: new Uint32Array([0, 1, 2, 3, 4, 5]),
|
||||||
custom: {
|
custom: {
|
||||||
position: [
|
position: [
|
||||||
1, 2, 3, 4, 5, 6, 7, 8, 9,
|
1, 2, 3, 4, 5, 6, 7, 8, 9,
|
||||||
10, 11, 12, 13, 14, 15, 16, 17, 18,
|
10, 11, 12, 13, 14, 15, 16, 17, 18,
|
||||||
],
|
],
|
||||||
colour: [
|
colour: [
|
||||||
@ -45,6 +50,8 @@ test('MergeAttributeData #2', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('MergeAttributeData #3', () => {
|
test('MergeAttributeData #3', () => {
|
||||||
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
const a: AttributeData = {
|
const a: AttributeData = {
|
||||||
indices: new Uint32Array([0, 1]),
|
indices: new Uint32Array([0, 1]),
|
||||||
custom: {
|
custom: {
|
||||||
|
@ -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 { ObjImporter } from '../src/importers/obj_importer';
|
||||||
import { TextureFiltering } from '../src/texture';
|
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 { 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('Voxelise solid 2x2 cube', () => {
|
||||||
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
const importer = new ObjImporter();
|
const importer = new ObjImporter();
|
||||||
importer.parseFile(path.join(__dirname, './data/cube.obj'));
|
importer.parseFile(path.join(__dirname, './data/cube.obj'));
|
||||||
const mesh = importer.toMesh();
|
const mesh = importer.toMesh();
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
import { ObjImporter } from '../src/importers/obj_importer';
|
import { ObjImporter } from '../src/importers/obj_importer';
|
||||||
import { ASSERT } from '../src/util/error_util';
|
import { ASSERT } from '../src/util/error_util';
|
||||||
import { Vector3 } from '../src/vector';
|
import { Vector3 } from '../src/vector';
|
||||||
|
import { TEST_PREAMBLE } from './preamble';
|
||||||
|
|
||||||
test('Parse vertex #1', () => {
|
test('Parse vertex #1', () => {
|
||||||
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
const importer = new ObjImporter();
|
const importer = new ObjImporter();
|
||||||
importer.parseOBJLine('v 1.0 -2.0 3.0');
|
importer.parseOBJLine('v 1.0 -2.0 3.0');
|
||||||
const mesh = importer.toMesh();
|
const mesh = importer.toMesh();
|
||||||
@ -11,6 +14,8 @@ test('Parse vertex #1', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Parse vertex #2', () => {
|
test('Parse vertex #2', () => {
|
||||||
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
const importer = new ObjImporter();
|
const importer = new ObjImporter();
|
||||||
importer.parseOBJLine('v 4.467e+000 9.243e+000 9.869e+000');
|
importer.parseOBJLine('v 4.467e+000 9.243e+000 9.869e+000');
|
||||||
const mesh = importer.toMesh();
|
const mesh = importer.toMesh();
|
||||||
@ -19,6 +24,8 @@ test('Parse vertex #2', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Parse normal #1', () => {
|
test('Parse normal #1', () => {
|
||||||
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
const importer = new ObjImporter();
|
const importer = new ObjImporter();
|
||||||
importer.parseOBJLine('vn -1.0 -0.5 0.0');
|
importer.parseOBJLine('vn -1.0 -0.5 0.0');
|
||||||
const mesh = importer.toMesh();
|
const mesh = importer.toMesh();
|
||||||
@ -27,6 +34,8 @@ test('Parse normal #1', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Parse texcoord #1', () => {
|
test('Parse texcoord #1', () => {
|
||||||
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
const importer = new ObjImporter();
|
const importer = new ObjImporter();
|
||||||
importer.parseOBJLine('vt 0.5 -0.8');
|
importer.parseOBJLine('vt 0.5 -0.8');
|
||||||
const mesh = importer.toMesh();
|
const mesh = importer.toMesh();
|
||||||
@ -35,6 +44,8 @@ test('Parse texcoord #1', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Parse face #1', () => {
|
test('Parse face #1', () => {
|
||||||
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
const importer = new ObjImporter();
|
const importer = new ObjImporter();
|
||||||
importer.parseOBJLine('f 12 24 36');
|
importer.parseOBJLine('f 12 24 36');
|
||||||
const mesh = importer.toMesh();
|
const mesh = importer.toMesh();
|
||||||
@ -44,10 +55,12 @@ test('Parse face #1', () => {
|
|||||||
expect(tri.normalIndices).toBeDefined(); ASSERT(tri.normalIndices);
|
expect(tri.normalIndices).toBeDefined(); ASSERT(tri.normalIndices);
|
||||||
expect(tri.positionIndices.x === 12 - 1 && tri.positionIndices.y === 24 - 1 && tri.positionIndices.z === 36 - 1).toBe(true);
|
expect(tri.positionIndices.x === 12 - 1 && tri.positionIndices.y === 24 - 1 && tri.positionIndices.z === 36 - 1).toBe(true);
|
||||||
expect(tri.texcoordIndices.x === 12 - 1 && tri.texcoordIndices.y === 24 - 1 && tri.texcoordIndices.z === 36 - 1).toBe(true);
|
expect(tri.texcoordIndices.x === 12 - 1 && tri.texcoordIndices.y === 24 - 1 && tri.texcoordIndices.z === 36 - 1).toBe(true);
|
||||||
expect(tri.normalIndices.x === 12 - 1 && tri.normalIndices.y === 24 - 1 && tri.normalIndices.z === 36 - 1).toBe(true);
|
expect(tri.normalIndices.x === 12 - 1 && tri.normalIndices.y === 24 - 1 && tri.normalIndices.z === 36 - 1).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Parse face #2', () => {
|
test('Parse face #2', () => {
|
||||||
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
const importer = new ObjImporter();
|
const importer = new ObjImporter();
|
||||||
importer.parseOBJLine('f 1/2 3/4 5/6');
|
importer.parseOBJLine('f 1/2 3/4 5/6');
|
||||||
const mesh = importer.toMesh();
|
const mesh = importer.toMesh();
|
||||||
@ -60,6 +73,8 @@ test('Parse face #2', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Parse face #3', () => {
|
test('Parse face #3', () => {
|
||||||
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
const importer = new ObjImporter();
|
const importer = new ObjImporter();
|
||||||
importer.parseOBJLine('f 11/2/3 4/55/6 7/8/99');
|
importer.parseOBJLine('f 11/2/3 4/55/6 7/8/99');
|
||||||
const mesh = importer.toMesh();
|
const mesh = importer.toMesh();
|
||||||
@ -67,12 +82,14 @@ test('Parse face #3', () => {
|
|||||||
const tri = mesh._tris[0];
|
const tri = mesh._tris[0];
|
||||||
expect(tri.texcoordIndices).toBeDefined(); ASSERT(tri.texcoordIndices);
|
expect(tri.texcoordIndices).toBeDefined(); ASSERT(tri.texcoordIndices);
|
||||||
expect(tri.normalIndices).toBeDefined(); ASSERT(tri.normalIndices);
|
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.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);
|
expect(tri.normalIndices.x === 3 - 1 && tri.normalIndices.y === 6 - 1 && tri.normalIndices.z === 99 - 1).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Parse mini #1', () => {
|
test('Parse mini #1', () => {
|
||||||
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
const importer = new ObjImporter();
|
const importer = new ObjImporter();
|
||||||
importer.parseOBJLine('v -1 2 3');
|
importer.parseOBJLine('v -1 2 3');
|
||||||
importer.parseOBJLine('v 4 -5 6');
|
importer.parseOBJLine('v 4 -5 6');
|
||||||
@ -95,7 +112,7 @@ test('Parse mini #1', () => {
|
|||||||
expect(vertexData.v0.equals(new Vector3(-1, 2, 3))).toBe(true);
|
expect(vertexData.v0.equals(new Vector3(-1, 2, 3))).toBe(true);
|
||||||
expect(vertexData.v1.equals(new Vector3(4, -5, 6))).toBe(true);
|
expect(vertexData.v1.equals(new Vector3(4, -5, 6))).toBe(true);
|
||||||
expect(vertexData.v2.equals(new Vector3(7, 8, -9))).toBe(true);
|
expect(vertexData.v2.equals(new Vector3(7, 8, -9))).toBe(true);
|
||||||
|
|
||||||
const texcoordData = mesh.getUVs(0);
|
const texcoordData = mesh.getUVs(0);
|
||||||
expect(texcoordData.uv0.u === 0.0 && texcoordData.uv0.v === 0.5).toBe(true);
|
expect(texcoordData.uv0.u === 0.0 && texcoordData.uv0.v === 0.5).toBe(true);
|
||||||
expect(texcoordData.uv1.u === 0.5 && texcoordData.uv1.v === 1.0).toBe(true);
|
expect(texcoordData.uv1.u === 0.5 && texcoordData.uv1.v === 1.0).toBe(true);
|
||||||
@ -109,6 +126,8 @@ test('Parse mini #1', () => {
|
|||||||
|
|
||||||
|
|
||||||
test('Parse mini #2', () => {
|
test('Parse mini #2', () => {
|
||||||
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
const importer = new ObjImporter();
|
const importer = new ObjImporter();
|
||||||
importer.parseOBJLine('v -1 2 3');
|
importer.parseOBJLine('v -1 2 3');
|
||||||
importer.parseOBJLine('v 4 -5 6');
|
importer.parseOBJLine('v 4 -5 6');
|
||||||
@ -131,7 +150,7 @@ test('Parse mini #2', () => {
|
|||||||
expect(vertexData.v0.equals(new Vector3(7, 8, -9))).toBe(true);
|
expect(vertexData.v0.equals(new Vector3(7, 8, -9))).toBe(true);
|
||||||
expect(vertexData.v1.equals(new Vector3(-1, 2, 3))).toBe(true);
|
expect(vertexData.v1.equals(new Vector3(-1, 2, 3))).toBe(true);
|
||||||
expect(vertexData.v2.equals(new Vector3(4, -5, 6))).toBe(true);
|
expect(vertexData.v2.equals(new Vector3(4, -5, 6))).toBe(true);
|
||||||
|
|
||||||
const texcoordData = mesh.getUVs(0);
|
const texcoordData = mesh.getUVs(0);
|
||||||
expect(texcoordData.uv0.u === 0.0 && texcoordData.uv0.v === 0.5).toBe(true);
|
expect(texcoordData.uv0.u === 0.0 && texcoordData.uv0.v === 0.5).toBe(true);
|
||||||
expect(texcoordData.uv1.u === 0.5 && texcoordData.uv1.v === 1.0).toBe(true);
|
expect(texcoordData.uv1.u === 0.5 && texcoordData.uv1.v === 1.0).toBe(true);
|
||||||
@ -144,6 +163,8 @@ test('Parse mini #2', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Parse mini #3', () => {
|
test('Parse mini #3', () => {
|
||||||
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
const importer = new ObjImporter();
|
const importer = new ObjImporter();
|
||||||
importer.parseOBJLine('v 0 0 0');
|
importer.parseOBJLine('v 0 0 0');
|
||||||
importer.parseOBJLine('v 1 0 0');
|
importer.parseOBJLine('v 1 0 0');
|
||||||
@ -168,6 +189,8 @@ test('Parse mini #3', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Parse comments', () => {
|
test('Parse comments', () => {
|
||||||
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
const importer = new ObjImporter();
|
const importer = new ObjImporter();
|
||||||
importer.parseOBJLine('# v -1 2 3');
|
importer.parseOBJLine('# v -1 2 3');
|
||||||
importer.parseOBJLine('# vn 0.0 0.1 0.2');
|
importer.parseOBJLine('# vn 0.0 0.1 0.2');
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import { TextureFiltering } from '../../src/texture';
|
import { TextureFiltering } from '../src/texture';
|
||||||
import { ColourSpace } from '../../src/util';
|
import { ColourSpace } from '../src/util';
|
||||||
import { AppPaths, PathUtil } from '../../src/util/path_util';
|
import { AppPaths, PathUtil } from '../src/util/path_util';
|
||||||
import { runHeadless, THeadlessConfig } from '../../tools/headless';
|
import { runHeadless, THeadlessConfig } from '../tools/headless';
|
||||||
import { FileUtil } from '../../src/util/file_util';
|
import { TEST_PREAMBLE } from './preamble';
|
||||||
import { TEST_PREAMBLE } from '../preamble';
|
|
||||||
|
|
||||||
const baseConfig: THeadlessConfig = {
|
const baseConfig: THeadlessConfig = {
|
||||||
import: {
|
import: {
|
||||||
@ -38,9 +37,6 @@ const baseConfig: THeadlessConfig = {
|
|||||||
test('FULL Obj->Obj', () => {
|
test('FULL Obj->Obj', () => {
|
||||||
TEST_PREAMBLE();
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
AppPaths.Get.setBaseDir(PathUtil.join(__dirname, '../..'));
|
|
||||||
FileUtil.mkdirSyncIfNotExist(PathUtil.join(AppPaths.Get.testData, '../out/'));
|
|
||||||
|
|
||||||
const config: THeadlessConfig = baseConfig;
|
const config: THeadlessConfig = baseConfig;
|
||||||
|
|
||||||
config.import.filepath = PathUtil.join(AppPaths.Get.resources, './samples/skull.obj');
|
config.import.filepath = PathUtil.join(AppPaths.Get.resources, './samples/skull.obj');
|
@ -1,9 +1,8 @@
|
|||||||
import { TextureFiltering } from '../../src/texture';
|
import { TextureFiltering } from '../src/texture';
|
||||||
import { ColourSpace } from '../../src/util';
|
import { ColourSpace } from '../src/util';
|
||||||
import { AppPaths, PathUtil } from '../../src/util/path_util';
|
import { AppPaths, PathUtil } from '../src/util/path_util';
|
||||||
import { runHeadless, THeadlessConfig } from '../../tools/headless';
|
import { runHeadless, THeadlessConfig } from '../tools/headless';
|
||||||
import { FileUtil } from '../../src/util/file_util';
|
import { TEST_PREAMBLE } from './preamble';
|
||||||
import { TEST_PREAMBLE } from '../preamble';
|
|
||||||
|
|
||||||
const baseConfig: THeadlessConfig = {
|
const baseConfig: THeadlessConfig = {
|
||||||
import: {
|
import: {
|
||||||
@ -38,9 +37,6 @@ const baseConfig: THeadlessConfig = {
|
|||||||
test('FULL Obj->Obj', () => {
|
test('FULL Obj->Obj', () => {
|
||||||
TEST_PREAMBLE();
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
AppPaths.Get.setBaseDir(PathUtil.join(__dirname, '../..'));
|
|
||||||
FileUtil.mkdirSyncIfNotExist(PathUtil.join(AppPaths.Get.testData, '../out/'));
|
|
||||||
|
|
||||||
const config: THeadlessConfig = baseConfig;
|
const config: THeadlessConfig = baseConfig;
|
||||||
|
|
||||||
config.import.filepath = PathUtil.join(AppPaths.Get.resources, './samples/skull.obj');
|
config.import.filepath = PathUtil.join(AppPaths.Get.resources, './samples/skull.obj');
|
@ -1,9 +1,8 @@
|
|||||||
import { TextureFiltering } from '../../src/texture';
|
import { TextureFiltering } from '../src/texture';
|
||||||
import { ColourSpace } from '../../src/util';
|
import { ColourSpace } from '../src/util';
|
||||||
import { AppPaths, PathUtil } from '../../src/util/path_util';
|
import { AppPaths, PathUtil } from '../src/util/path_util';
|
||||||
import { runHeadless, THeadlessConfig } from '../../tools/headless';
|
import { runHeadless, THeadlessConfig } from '../tools/headless';
|
||||||
import { FileUtil } from '../../src/util/file_util';
|
import { TEST_PREAMBLE } from './preamble';
|
||||||
import { TEST_PREAMBLE } from '../preamble';
|
|
||||||
|
|
||||||
const baseConfig: THeadlessConfig = {
|
const baseConfig: THeadlessConfig = {
|
||||||
import: {
|
import: {
|
||||||
@ -38,9 +37,6 @@ const baseConfig: THeadlessConfig = {
|
|||||||
test('FULL Obj->Obj', () => {
|
test('FULL Obj->Obj', () => {
|
||||||
TEST_PREAMBLE();
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
AppPaths.Get.setBaseDir(PathUtil.join(__dirname, '../..'));
|
|
||||||
FileUtil.mkdirSyncIfNotExist(PathUtil.join(AppPaths.Get.testData, '../out/'));
|
|
||||||
|
|
||||||
const config: THeadlessConfig = baseConfig;
|
const config: THeadlessConfig = baseConfig;
|
||||||
|
|
||||||
config.import.filepath = PathUtil.join(AppPaths.Get.resources, './samples/skull.obj');
|
config.import.filepath = PathUtil.join(AppPaths.Get.resources, './samples/skull.obj');
|
@ -1,9 +1,8 @@
|
|||||||
import { TextureFiltering } from '../../src/texture';
|
import { TextureFiltering } from '../src/texture';
|
||||||
import { ColourSpace } from '../../src/util';
|
import { ColourSpace } from '../src/util';
|
||||||
import { AppPaths, PathUtil } from '../../src/util/path_util';
|
import { AppPaths, PathUtil } from '../src/util/path_util';
|
||||||
import { runHeadless, THeadlessConfig } from '../../tools/headless';
|
import { runHeadless, THeadlessConfig } from '../tools/headless';
|
||||||
import { FileUtil } from '../../src/util/file_util';
|
import { TEST_PREAMBLE } from './preamble';
|
||||||
import { TEST_PREAMBLE } from '../preamble';
|
|
||||||
|
|
||||||
const baseConfig: THeadlessConfig = {
|
const baseConfig: THeadlessConfig = {
|
||||||
import: {
|
import: {
|
||||||
@ -38,9 +37,6 @@ const baseConfig: THeadlessConfig = {
|
|||||||
test('FULL Obj->Schematic', () => {
|
test('FULL Obj->Schematic', () => {
|
||||||
TEST_PREAMBLE();
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
AppPaths.Get.setBaseDir(PathUtil.join(__dirname, '../..'));
|
|
||||||
FileUtil.mkdirSyncIfNotExist(PathUtil.join(AppPaths.Get.testData, '../out/'));
|
|
||||||
|
|
||||||
const config: THeadlessConfig = baseConfig;
|
const config: THeadlessConfig = baseConfig;
|
||||||
|
|
||||||
config.import.filepath = PathUtil.join(AppPaths.Get.resources, './samples/skull.obj');
|
config.import.filepath = PathUtil.join(AppPaths.Get.resources, './samples/skull.obj');
|
9
tests/palette.test.ts
Normal file
9
tests/palette.test.ts
Normal 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);
|
||||||
|
});
|
@ -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 = () => {
|
export const TEST_PREAMBLE = () => {
|
||||||
Logger.Get.disableLogToFile();
|
Logger.Get.disableLogToFile();
|
||||||
}
|
AppPaths.Get.setBaseDir(PathUtil.join(__dirname, '..'));
|
||||||
|
FileUtil.mkdirSyncIfNotExist(PathUtil.join(AppPaths.Get.testData, './out/'));
|
||||||
|
};
|
||||||
|
@ -1,17 +1,20 @@
|
|||||||
import { Ray, Axes, rayIntersectTriangle } from '../src/ray';
|
import { Axes, Ray, rayIntersectTriangle } from '../src/ray';
|
||||||
import { Vector3 } from '../src/vector';
|
|
||||||
import { Triangle } from '../src/triangle';
|
import { Triangle } from '../src/triangle';
|
||||||
import { ASSERT } from '../src/util/error_util';
|
import { ASSERT } from '../src/util/error_util';
|
||||||
|
import { Vector3 } from '../src/vector';
|
||||||
|
import { TEST_PREAMBLE } from './preamble';
|
||||||
|
|
||||||
test('rayIntersectTriangle x-axis #1', () => {
|
test('rayIntersectTriangle x-axis #1', () => {
|
||||||
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
const ray: Ray = {
|
const ray: Ray = {
|
||||||
origin: new Vector3(-1, 0, 0),
|
origin: new Vector3(-1, 0, 0),
|
||||||
axis: Axes.x,
|
axis: Axes.x,
|
||||||
};
|
};
|
||||||
const tri = new Triangle(
|
const tri = new Triangle(
|
||||||
new Vector3(5, -1, -1),
|
new Vector3(5, -1, -1),
|
||||||
new Vector3(5, 0, 1),
|
new Vector3(5, 0, 1),
|
||||||
new Vector3(5, 1, -1),
|
new Vector3(5, 1, -1),
|
||||||
);
|
);
|
||||||
const intersects = rayIntersectTriangle(ray, tri.v0, tri.v1, tri.v2);
|
const intersects = rayIntersectTriangle(ray, tri.v0, tri.v1, tri.v2);
|
||||||
expect(intersects).toBeDefined();
|
expect(intersects).toBeDefined();
|
||||||
@ -20,28 +23,32 @@ test('rayIntersectTriangle x-axis #1', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('rayIntersectTriangle x-axis #2', () => {
|
test('rayIntersectTriangle x-axis #2', () => {
|
||||||
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
const ray: Ray = {
|
const ray: Ray = {
|
||||||
origin: new Vector3(1, 0, 0),
|
origin: new Vector3(1, 0, 0),
|
||||||
axis: Axes.x,
|
axis: Axes.x,
|
||||||
};
|
};
|
||||||
const tri = new Triangle(
|
const tri = new Triangle(
|
||||||
new Vector3(0, -1, -1),
|
new Vector3(0, -1, -1),
|
||||||
new Vector3(0, 0, 1),
|
new Vector3(0, 0, 1),
|
||||||
new Vector3(0, 1, -1),
|
new Vector3(0, 1, -1),
|
||||||
);
|
);
|
||||||
const intersects = rayIntersectTriangle(ray, tri.v0, tri.v1, tri.v2);
|
const intersects = rayIntersectTriangle(ray, tri.v0, tri.v1, tri.v2);
|
||||||
expect(intersects).toBeUndefined();
|
expect(intersects).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('rayIntersectTriangle y-axis #1', () => {
|
test('rayIntersectTriangle y-axis #1', () => {
|
||||||
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
const ray: Ray = {
|
const ray: Ray = {
|
||||||
origin: new Vector3(0, -1, 0),
|
origin: new Vector3(0, -1, 0),
|
||||||
axis: Axes.y,
|
axis: Axes.y,
|
||||||
};
|
};
|
||||||
const tri = new Triangle(
|
const tri = new Triangle(
|
||||||
new Vector3(-1, 6, -1),
|
new Vector3(-1, 6, -1),
|
||||||
new Vector3( 0, 6, 1),
|
new Vector3(0, 6, 1),
|
||||||
new Vector3( 1, 6, -1),
|
new Vector3(1, 6, -1),
|
||||||
);
|
);
|
||||||
const intersects = rayIntersectTriangle(ray, tri.v0, tri.v1, tri.v2);
|
const intersects = rayIntersectTriangle(ray, tri.v0, tri.v1, tri.v2);
|
||||||
expect(intersects).toBeDefined();
|
expect(intersects).toBeDefined();
|
||||||
@ -50,28 +57,32 @@ test('rayIntersectTriangle y-axis #1', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('rayIntersectTriangle y-axis #2', () => {
|
test('rayIntersectTriangle y-axis #2', () => {
|
||||||
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
const ray: Ray = {
|
const ray: Ray = {
|
||||||
origin: new Vector3(0, 1, 0),
|
origin: new Vector3(0, 1, 0),
|
||||||
axis: Axes.y,
|
axis: Axes.y,
|
||||||
};
|
};
|
||||||
const tri = new Triangle(
|
const tri = new Triangle(
|
||||||
new Vector3(-1, 0, -1),
|
new Vector3(-1, 0, -1),
|
||||||
new Vector3( 0, 0, 1),
|
new Vector3(0, 0, 1),
|
||||||
new Vector3( 1, 0, -1),
|
new Vector3(1, 0, -1),
|
||||||
);
|
);
|
||||||
const intersects = rayIntersectTriangle(ray, tri.v0, tri.v1, tri.v2);
|
const intersects = rayIntersectTriangle(ray, tri.v0, tri.v1, tri.v2);
|
||||||
expect(intersects).toBeUndefined();
|
expect(intersects).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('rayIntersectTriangle z-axis #1', () => {
|
test('rayIntersectTriangle z-axis #1', () => {
|
||||||
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
const ray: Ray = {
|
const ray: Ray = {
|
||||||
origin: new Vector3(0, 0, -1),
|
origin: new Vector3(0, 0, -1),
|
||||||
axis: Axes.z,
|
axis: Axes.z,
|
||||||
};
|
};
|
||||||
const tri = new Triangle(
|
const tri = new Triangle(
|
||||||
new Vector3(-1, -1, 7),
|
new Vector3(-1, -1, 7),
|
||||||
new Vector3( 0, 1, 7),
|
new Vector3(0, 1, 7),
|
||||||
new Vector3( 1, -1, 7),
|
new Vector3(1, -1, 7),
|
||||||
);
|
);
|
||||||
const intersects = rayIntersectTriangle(ray, tri.v0, tri.v1, tri.v2);
|
const intersects = rayIntersectTriangle(ray, tri.v0, tri.v1, tri.v2);
|
||||||
expect(intersects).toBeDefined();
|
expect(intersects).toBeDefined();
|
||||||
@ -80,14 +91,16 @@ test('rayIntersectTriangle z-axis #1', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('rayIntersectTriangle z-axis #2', () => {
|
test('rayIntersectTriangle z-axis #2', () => {
|
||||||
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
const ray: Ray = {
|
const ray: Ray = {
|
||||||
origin: new Vector3(0, 0, 1),
|
origin: new Vector3(0, 0, 1),
|
||||||
axis: Axes.z,
|
axis: Axes.z,
|
||||||
};
|
};
|
||||||
const tri = new Triangle(
|
const tri = new Triangle(
|
||||||
new Vector3(-1, -1, 0),
|
new Vector3(-1, -1, 0),
|
||||||
new Vector3( 0, 1, 0),
|
new Vector3(0, 1, 0),
|
||||||
new Vector3( 1, -1, 0),
|
new Vector3(1, -1, 0),
|
||||||
);
|
);
|
||||||
const intersects = rayIntersectTriangle(ray, tri.v0, tri.v1, tri.v2);
|
const intersects = rayIntersectTriangle(ray, tri.v0, tri.v1, tri.v2);
|
||||||
expect(intersects).toBeUndefined();
|
expect(intersects).toBeUndefined();
|
||||||
|
15
tests/schematic-friendly.test.ts
Normal file
15
tests/schematic-friendly.test.ts
Normal 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);
|
||||||
|
});
|
@ -1,6 +1,9 @@
|
|||||||
import { StatusHandler } from '../src/status';
|
import { StatusHandler } from '../src/status';
|
||||||
|
import { TEST_PREAMBLE } from './preamble';
|
||||||
|
|
||||||
test('Status', () => {
|
test('Status', () => {
|
||||||
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
StatusHandler.Get.add(
|
StatusHandler.Get.add(
|
||||||
'warning',
|
'warning',
|
||||||
'This is a warning',
|
'This is a warning',
|
||||||
@ -11,6 +14,8 @@ test('Status', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Status', () => {
|
test('Status', () => {
|
||||||
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
StatusHandler.Get.add(
|
StatusHandler.Get.add(
|
||||||
'warning',
|
'warning',
|
||||||
'This is a warning',
|
'This is a warning',
|
||||||
@ -23,9 +28,9 @@ test('Status', () => {
|
|||||||
'info',
|
'info',
|
||||||
'This is some more info',
|
'This is some more info',
|
||||||
);
|
);
|
||||||
expect(StatusHandler.Get.getStatusMessages( 'info').length).toBe(2);
|
expect(StatusHandler.Get.getStatusMessages('info').length).toBe(2);
|
||||||
expect(StatusHandler.Get.getStatusMessages( 'warning').length).toBe(1);
|
expect(StatusHandler.Get.getStatusMessages('warning').length).toBe(1);
|
||||||
StatusHandler.Get.clear();
|
StatusHandler.Get.clear();
|
||||||
expect(StatusHandler.Get.getStatusMessages( 'info').length).toBe(0);
|
expect(StatusHandler.Get.getStatusMessages('info').length).toBe(0);
|
||||||
expect(StatusHandler.Get.getStatusMessages( 'warning').length).toBe(0);
|
expect(StatusHandler.Get.getStatusMessages('warning').length).toBe(0);
|
||||||
});
|
});
|
||||||
|
@ -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 { 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('RegExpBuilder', () => {
|
||||||
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
const regex = new RegExpBuilder()
|
const regex = new RegExpBuilder()
|
||||||
.add(/hello/)
|
.add(/hello/)
|
||||||
.toRegExp();
|
.toRegExp();
|
||||||
@ -10,6 +14,8 @@ test('RegExpBuilder', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('RegExpBuilder REGEX_NUMBER', () => {
|
test('RegExpBuilder REGEX_NUMBER', () => {
|
||||||
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
const tests = [
|
const tests = [
|
||||||
{ f: '0', s: 0 },
|
{ f: '0', s: 0 },
|
||||||
{ f: '0.0', s: 0.0 },
|
{ f: '0.0', s: 0.0 },
|
||||||
@ -26,6 +32,8 @@ test('RegExpBuilder REGEX_NUMBER', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('RegExpBuilder Required-whitespace', () => {
|
test('RegExpBuilder Required-whitespace', () => {
|
||||||
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
const regex = new RegExpBuilder()
|
const regex = new RegExpBuilder()
|
||||||
.add(/hello/)
|
.add(/hello/)
|
||||||
.addNonzeroWhitespace()
|
.addNonzeroWhitespace()
|
||||||
@ -37,6 +45,8 @@ test('RegExpBuilder Required-whitespace', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('RegExpBuilder Optional', () => {
|
test('RegExpBuilder Optional', () => {
|
||||||
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
const regex = new RegExpBuilder()
|
const regex = new RegExpBuilder()
|
||||||
.add(/hello/)
|
.add(/hello/)
|
||||||
.addNonzeroWhitespace()
|
.addNonzeroWhitespace()
|
||||||
@ -49,6 +59,8 @@ test('RegExpBuilder Optional', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('RegExpBuilder Capture', () => {
|
test('RegExpBuilder Capture', () => {
|
||||||
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
const regex = new RegExpBuilder()
|
const regex = new RegExpBuilder()
|
||||||
.add(/[0-9]+/, 'myNumber')
|
.add(/[0-9]+/, 'myNumber')
|
||||||
.toRegExp();
|
.toRegExp();
|
||||||
@ -61,6 +73,8 @@ test('RegExpBuilder Capture', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('RegExpBuilder Capture-multiple', () => {
|
test('RegExpBuilder Capture-multiple', () => {
|
||||||
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
const regex = new RegExpBuilder()
|
const regex = new RegExpBuilder()
|
||||||
.add(/[0-9]+/, 'x')
|
.add(/[0-9]+/, 'x')
|
||||||
.addNonzeroWhitespace()
|
.addNonzeroWhitespace()
|
||||||
@ -82,6 +96,8 @@ test('RegExpBuilder Capture-multiple', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('RegExpBuilder Capture-multiple', () => {
|
test('RegExpBuilder Capture-multiple', () => {
|
||||||
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
const regex = new RegExpBuilder()
|
const regex = new RegExpBuilder()
|
||||||
.add(/f/)
|
.add(/f/)
|
||||||
.addNonzeroWhitespace()
|
.addNonzeroWhitespace()
|
||||||
@ -124,6 +140,8 @@ test('RegExpBuilder Capture-multiple', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('RegExpBuilder Capture-multiple', () => {
|
test('RegExpBuilder Capture-multiple', () => {
|
||||||
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
const regex = new RegExpBuilder()
|
const regex = new RegExpBuilder()
|
||||||
.add(/usemtl/)
|
.add(/usemtl/)
|
||||||
.add(/ /)
|
.add(/ /)
|
||||||
@ -136,3 +154,11 @@ test('RegExpBuilder Capture-multiple', () => {
|
|||||||
expect(exec.groups['path']).toBe('hellothere.txt');
|
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');
|
||||||
|
});
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
import { Vector3 } from '../src/vector';
|
|
||||||
import { VoxelMesh } from '../src/voxel_mesh';
|
|
||||||
import { RGBAColours } from '../src/colour';
|
import { RGBAColours } from '../src/colour';
|
||||||
import { ASSERT } from '../src/util/error_util';
|
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('Voxel neighbours', () => {
|
||||||
|
TEST_PREAMBLE();
|
||||||
|
|
||||||
const voxelMesh = new VoxelMesh({
|
const voxelMesh = new VoxelMesh({
|
||||||
voxelOverlapRule: 'first',
|
voxelOverlapRule: 'first',
|
||||||
enableAmbientOcclusion: true,
|
enableAmbientOcclusion: true,
|
||||||
|
@ -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 { AppPaths, PathUtil } from '../src/util/path_util';
|
||||||
import { runHeadless } from './headless';
|
import { runHeadless } from './headless';
|
||||||
import { headlessConfig } from './headless-config';
|
import { headlessConfig } from './headless-config';
|
||||||
|
Loading…
Reference in New Issue
Block a user