mirror of
https://github.com/LucasDower/ObjToSchematic.git
synced 2024-11-27 02:19:58 +08:00
Major refactor to block assigning
* Removed assigners as there was significant overlap * Added explicit dithering options
This commit is contained in:
parent
cbc53ddfe5
commit
ec532586cd
@ -13,5 +13,6 @@
|
||||
"CAMERA_DEFAULT_AZIMUTH_RADIANS": -1.0,
|
||||
"CAMERA_DEFAULT_ELEVATION_RADIANS": 1.3,
|
||||
"CAMERA_SENSITIVITY_ROTATION": 0.005,
|
||||
"CAMERA_SENSITIVITY_ZOOM": 0.005
|
||||
"CAMERA_SENSITIVITY_ZOOM": 0.005,
|
||||
"DITHER_MAGNITUDE": 32
|
||||
}
|
@ -328,7 +328,7 @@ export class AppContext {
|
||||
params: {
|
||||
textureAtlas: uiElements.textureAtlas.getCachedValue(),
|
||||
blockPalette: uiElements.blockPalette.getCachedValue(),
|
||||
blockAssigner: uiElements.dithering.getCachedValue(),
|
||||
dithering: uiElements.dithering.getCachedValue(),
|
||||
colourSpace: ColourSpace.RGB,
|
||||
fallable: uiElements.fallable.getCachedValue() as FallableBehaviour,
|
||||
resolution: Math.pow(2, uiElements.colourAccuracy.getCachedValue()),
|
||||
|
@ -1,19 +0,0 @@
|
||||
import { IBlockAssigner } from './base_assigner';
|
||||
import { BasicBlockAssigner } from './basic_assigner';
|
||||
import { OrderedDitheringBlockAssigner } from './ordered_dithering_assigner';
|
||||
import { RandomDitheringBlockAssigner } from './random_dithering_assigner';
|
||||
|
||||
export type TBlockAssigners = 'basic' | 'ordered-dithering' | 'random-dithering';
|
||||
|
||||
export class BlockAssignerFactory {
|
||||
public static GetAssigner(blockAssigner: TBlockAssigners): IBlockAssigner {
|
||||
switch (blockAssigner) {
|
||||
case 'basic':
|
||||
return new BasicBlockAssigner();
|
||||
case 'ordered-dithering':
|
||||
return new OrderedDitheringBlockAssigner();
|
||||
case 'random-dithering':
|
||||
return new RandomDitheringBlockAssigner();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
import { AtlasPalette, TBlockCollection } from '../block_assigner';
|
||||
import { BlockInfo } from '../block_atlas';
|
||||
import { RGBA, RGBAUtil } from '../colour';
|
||||
import { ColourSpace } from '../util';
|
||||
import { Vector3 } from '../vector';
|
||||
|
||||
export interface IBlockAssigner {
|
||||
assignBlock(atlasPalette: AtlasPalette, voxelColour: RGBA, voxelPosition: Vector3, resolution: RGBAUtil.TColourAccuracy, colourSpace: ColourSpace, blockCollection: TBlockCollection): BlockInfo;
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
import { AtlasPalette, TBlockCollection } from '../block_assigner';
|
||||
import { BlockInfo } from '../block_atlas';
|
||||
import { RGBA, RGBAUtil } from '../colour';
|
||||
import { ColourSpace } from '../util';
|
||||
import { Vector3 } from '../vector';
|
||||
import { IBlockAssigner } from './base_assigner';
|
||||
|
||||
export class BasicBlockAssigner implements IBlockAssigner {
|
||||
assignBlock(atlasPalette: AtlasPalette, voxelColour: RGBA, voxelPosition: Vector3, resolution: RGBAUtil.TColourAccuracy, colourSpace: ColourSpace, blockCollection: TBlockCollection): BlockInfo {
|
||||
return atlasPalette.getBlock(voxelColour, blockCollection, resolution);
|
||||
}
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
import { AtlasPalette, TBlockCollection } from '../block_assigner';
|
||||
import { BlockInfo } from '../block_atlas';
|
||||
import { RGBA, RGBAUtil } from '../colour';
|
||||
import { ColourSpace } from '../util';
|
||||
import { ASSERT } from '../util/error_util';
|
||||
import { Vector3 } from '../vector';
|
||||
import { IBlockAssigner } from './base_assigner';
|
||||
|
||||
export class OrderedDitheringBlockAssigner implements IBlockAssigner {
|
||||
/** 4x4x4 */
|
||||
private static _size = 4;
|
||||
private static _threshold = 256 / 8;
|
||||
|
||||
private static _mapMatrix = [
|
||||
0, 16, 2, 18, 48, 32, 50, 34,
|
||||
6, 22, 4, 20, 54, 38, 52, 36,
|
||||
24, 40, 26, 42, 8, 56, 10, 58,
|
||||
30, 46, 28, 44, 14, 62, 12, 60,
|
||||
3, 19, 5, 21, 51, 35, 53, 37,
|
||||
1, 17, 7, 23, 49, 33, 55, 39,
|
||||
27, 43, 29, 45, 11, 59, 13, 61,
|
||||
25, 41, 31, 47, 9, 57, 15, 63,
|
||||
];
|
||||
|
||||
private _getThresholdValue(x: number, y: number, z: number) {
|
||||
const size = OrderedDitheringBlockAssigner._size;
|
||||
ASSERT(0 <= x && x < size && 0 <= y && y < size && 0 <= z && z < size);
|
||||
const index = (x + (size * y) + (size * size * z));
|
||||
ASSERT(0 <= index && index < size * size * size);
|
||||
return (OrderedDitheringBlockAssigner._mapMatrix[index] / (size * size * size)) - 0.5;
|
||||
}
|
||||
|
||||
assignBlock(atlasPalette: AtlasPalette, voxelColour: RGBA, voxelPosition: Vector3, resolution: RGBAUtil.TColourAccuracy, colourSpace: ColourSpace, blockCollection: TBlockCollection): BlockInfo {
|
||||
const size = OrderedDitheringBlockAssigner._size;
|
||||
const map = this._getThresholdValue(
|
||||
Math.abs(voxelPosition.x % size),
|
||||
Math.abs(voxelPosition.y % size),
|
||||
Math.abs(voxelPosition.z % size),
|
||||
);
|
||||
|
||||
const newVoxelColour: RGBA = {
|
||||
r: ((255 * voxelColour.r) + map * OrderedDitheringBlockAssigner._threshold) / 255,
|
||||
g: ((255 * voxelColour.g) + map * OrderedDitheringBlockAssigner._threshold) / 255,
|
||||
b: ((255 * voxelColour.b) + map * OrderedDitheringBlockAssigner._threshold) / 255,
|
||||
a: ((255 * voxelColour.a) + map * OrderedDitheringBlockAssigner._threshold) / 255,
|
||||
};
|
||||
|
||||
return atlasPalette.getBlock(newVoxelColour, blockCollection, resolution);
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
import { AtlasPalette, TBlockCollection } from '../block_assigner';
|
||||
import { BlockInfo } from '../block_atlas';
|
||||
import { RGBA, RGBAUtil } from '../colour';
|
||||
import { ColourSpace } from '../util';
|
||||
import { Vector3 } from '../vector';
|
||||
import { IBlockAssigner } from './base_assigner';
|
||||
|
||||
export class RandomDitheringBlockAssigner implements IBlockAssigner {
|
||||
private static _deviation = 32;
|
||||
|
||||
assignBlock(atlasPalette: AtlasPalette, voxelColour: RGBA, voxelPosition: Vector3, resolution: RGBAUtil.TColourAccuracy, colourSpace: ColourSpace, blockCollection: TBlockCollection): BlockInfo {
|
||||
const map = Math.random() - 0.5;
|
||||
|
||||
const newVoxelColour: RGBA = {
|
||||
r: ((255 * voxelColour.r) + map * RandomDitheringBlockAssigner._deviation) / 255,
|
||||
g: ((255 * voxelColour.g) + map * RandomDitheringBlockAssigner._deviation) / 255,
|
||||
b: ((255 * voxelColour.b) + map * RandomDitheringBlockAssigner._deviation) / 255,
|
||||
a: ((255 * voxelColour.a) + map * RandomDitheringBlockAssigner._deviation) / 255,
|
||||
};
|
||||
|
||||
return atlasPalette.getBlock(newVoxelColour, blockCollection, resolution);
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import { Atlas, TAtlasBlock } from './atlas';
|
||||
import { RGBA, RGBAUtil } from './colour';
|
||||
import { RGBA, RGBA_255, RGBAUtil } from './colour';
|
||||
import { Palette } from './palette';
|
||||
import { AppTypes, TOptional } from './util';
|
||||
import { ASSERT } from './util/error_util';
|
||||
@ -62,8 +62,8 @@ export class AtlasPalette {
|
||||
* @param blockToExclude A list of blocks that should not be used, this should be a subset of the palette blocks.
|
||||
* @returns
|
||||
*/
|
||||
public getBlock(colour: RGBA, blockCollection: TBlockCollection, resolution: RGBAUtil.TColourAccuracy) {
|
||||
const { colourHash, binnedColour } = RGBAUtil.bin(colour, resolution);
|
||||
public getBlock(colour: RGBA_255, blockCollection: TBlockCollection) {
|
||||
const colourHash = RGBAUtil.hash255(colour);
|
||||
|
||||
// If we've already calculated the block associated with this colour, return it.
|
||||
const cachedBlock = blockCollection.cache.get(colourHash);
|
||||
@ -76,7 +76,7 @@ export class AtlasPalette {
|
||||
let blockChoice: TOptional<TAtlasBlock>;
|
||||
{
|
||||
blockCollection.blocks.forEach((blockData) => {
|
||||
const colourDistance = RGBAUtil.squaredDistance(binnedColour, blockData.colour);
|
||||
const colourDistance = RGBAUtil.squaredDistance(RGBAUtil.fromRGBA255(colour), blockData.colour);
|
||||
if (colourDistance < minDistance) {
|
||||
minDistance = colourDistance;
|
||||
blockChoice = blockData;
|
||||
|
@ -1,10 +1,11 @@
|
||||
import fs from 'fs';
|
||||
|
||||
import { BlockAssignerFactory, TBlockAssigners } from './assigners/assigners';
|
||||
import { Atlas } from './atlas';
|
||||
import { AtlasPalette } from './block_assigner';
|
||||
import { BlockInfo } from './block_atlas';
|
||||
import { ChunkedBufferGenerator, TBlockMeshBufferDescription } from './buffer';
|
||||
import { RGBA_255, RGBAUtil } from './colour';
|
||||
import { Ditherer } from './dither';
|
||||
import { Palette } from './palette';
|
||||
import { ProgressManager } from './progress';
|
||||
import { StatusHandler } from './status';
|
||||
@ -26,13 +27,12 @@ export type FallableBehaviour = 'replace-falling' | 'replace-fallable' | 'place-
|
||||
export interface BlockMeshParams {
|
||||
textureAtlas: Atlas,
|
||||
blockPalette: Palette,
|
||||
blockAssigner: TBlockAssigners,
|
||||
colourSpace: ColourSpace,
|
||||
fallable: FallableBehaviour,
|
||||
}
|
||||
|
||||
export class BlockMesh {
|
||||
private _blocksUsed: string[];
|
||||
private _blocksUsed: Set<string>;
|
||||
private _blocks: Block[];
|
||||
private _voxelMesh: VoxelMesh;
|
||||
private _fallableBlocks: string[];
|
||||
@ -45,7 +45,7 @@ export class BlockMesh {
|
||||
}
|
||||
|
||||
private constructor(voxelMesh: VoxelMesh) {
|
||||
this._blocksUsed = [];
|
||||
this._blocksUsed = new Set();
|
||||
this._blocks = [];
|
||||
this._voxelMesh = voxelMesh;
|
||||
this._atlas = Atlas.getVanillaAtlas()!;
|
||||
@ -55,6 +55,32 @@ export class BlockMesh {
|
||||
this._fallableBlocks = JSON.parse(fallableBlocksString).fallable_blocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Before we turn a voxel into a block we have the opportunity to alter the voxel's colour.
|
||||
* This is where the colour accuracy bands colours together and where dithering is calculated.
|
||||
*/
|
||||
private _getFinalVoxelColour(voxel: Voxel, blockMeshParams: AssignParams.Input) {
|
||||
const voxelColour = RGBAUtil.copy(voxel.colour);
|
||||
const binnedColour = RGBAUtil.bin(voxelColour, blockMeshParams.resolution);
|
||||
|
||||
const ditheredColour: RGBA_255 = RGBAUtil.copy255(binnedColour);
|
||||
switch (blockMeshParams.dithering) {
|
||||
case 'off': {
|
||||
break;
|
||||
}
|
||||
case 'random': {
|
||||
Ditherer.ditherRandom(ditheredColour);
|
||||
break;
|
||||
}
|
||||
case 'ordered': {
|
||||
Ditherer.ditherOrdered(ditheredColour, voxel.position);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ditheredColour;
|
||||
}
|
||||
|
||||
private _assignBlocks(blockMeshParams: AssignParams.Input) {
|
||||
const atlas = Atlas.load(blockMeshParams.textureAtlas);
|
||||
ASSERT(atlas !== undefined, 'Could not load atlas');
|
||||
@ -67,54 +93,39 @@ export class BlockMesh {
|
||||
const allBlockCollection = atlasPalette.createBlockCollection([]);
|
||||
const nonFallableBlockCollection = atlasPalette.createBlockCollection(this._fallableBlocks);
|
||||
|
||||
const blockAssigner = BlockAssignerFactory.GetAssigner(blockMeshParams.blockAssigner);
|
||||
|
||||
let countFalling = 0;
|
||||
const taskHandle = ProgressManager.Get.start('Assigning');
|
||||
const voxels = this._voxelMesh.getVoxels();
|
||||
for (let voxelIndex = 0; voxelIndex < voxels.length; ++voxelIndex) {
|
||||
ProgressManager.Get.progress(taskHandle, voxelIndex / voxels.length);
|
||||
|
||||
// Convert the voxel into a block
|
||||
const voxel = voxels[voxelIndex];
|
||||
|
||||
let block = blockAssigner.assignBlock(
|
||||
atlasPalette,
|
||||
voxel.colour,
|
||||
voxel.position,
|
||||
blockMeshParams.resolution,
|
||||
blockMeshParams.colourSpace,
|
||||
allBlockCollection,
|
||||
);
|
||||
const voxelColour = this._getFinalVoxelColour(voxel, blockMeshParams);
|
||||
let block = atlasPalette.getBlock(voxelColour, allBlockCollection);
|
||||
|
||||
const isFallable = this._fallableBlocks.includes(block.name);
|
||||
const isSupported = this._voxelMesh.isVoxelAt(Vector3.add(voxel.position, new Vector3(0, -1, 0)));
|
||||
// Check that this block meets the fallable behaviour, we may need
|
||||
// to choose a different block if the current one doesn't meet the requirements
|
||||
const isBlockFallable = this._fallableBlocks.includes(block.name);
|
||||
const isBlockSupported = this._voxelMesh.isVoxelAt(Vector3.add(voxel.position, new Vector3(0, -1, 0)));
|
||||
|
||||
if (isFallable && !isSupported) {
|
||||
if (isBlockFallable && !isBlockSupported) {
|
||||
++countFalling;
|
||||
}
|
||||
|
||||
let shouldReplace = (blockMeshParams.fallable === 'replace-fallable' && isFallable);
|
||||
shouldReplace ||= (blockMeshParams.fallable === 'replace-falling' && isFallable && !isSupported);
|
||||
const shouldReplaceBlock =
|
||||
(blockMeshParams.fallable === 'replace-fallable' && isBlockFallable) ||
|
||||
(blockMeshParams.fallable === 'replace-falling' && isBlockFallable && !isBlockSupported);
|
||||
|
||||
if (shouldReplace) {
|
||||
const replacedBlock = blockAssigner.assignBlock(
|
||||
atlasPalette,
|
||||
voxel.colour,
|
||||
voxel.position,
|
||||
blockMeshParams.resolution,
|
||||
ColourSpace.RGB,
|
||||
nonFallableBlockCollection,
|
||||
);
|
||||
block = replacedBlock;
|
||||
if (shouldReplaceBlock) {
|
||||
block = atlasPalette.getBlock(voxelColour, nonFallableBlockCollection);
|
||||
}
|
||||
|
||||
this._blocks.push({
|
||||
voxel: voxel,
|
||||
blockInfo: block,
|
||||
});
|
||||
if (!this._blocksUsed.includes(block.name)) {
|
||||
this._blocksUsed.push(block.name);
|
||||
}
|
||||
this._blocksUsed.add(block.name);
|
||||
}
|
||||
ProgressManager.Get.end(taskHandle);
|
||||
|
||||
@ -128,7 +139,7 @@ export class BlockMesh {
|
||||
}
|
||||
|
||||
public getBlockPalette() {
|
||||
return this._blocksUsed;
|
||||
return Array.from(this._blocksUsed);
|
||||
}
|
||||
|
||||
public getVoxelMesh() {
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { AppConfig } from './config';
|
||||
import { TBrand } from './util/type_util';
|
||||
|
||||
export type RGBA = {
|
||||
r: number,
|
||||
@ -7,7 +8,29 @@ export type RGBA = {
|
||||
a: number
|
||||
}
|
||||
|
||||
export type RGBA_255 = TBrand<RGBA, '255'>;
|
||||
|
||||
export namespace RGBAUtil {
|
||||
export function toRGBA255(c: RGBA): RGBA_255 {
|
||||
const out: RGBA = {
|
||||
r: c.r * 255,
|
||||
g: c.r * 255,
|
||||
b: c.r * 255,
|
||||
a: c.r * 255,
|
||||
};
|
||||
return out as RGBA_255;
|
||||
}
|
||||
|
||||
export function fromRGBA255(c: RGBA_255): RGBA {
|
||||
const out: RGBA = {
|
||||
r: c.r / 255,
|
||||
g: c.g / 255,
|
||||
b: c.b / 255,
|
||||
a: c.a / 255,
|
||||
};
|
||||
return out;
|
||||
}
|
||||
|
||||
export function lerp(a: RGBA, b: RGBA, alpha: number) {
|
||||
return {
|
||||
r: a.r * (1 - alpha) + b.r * alpha,
|
||||
@ -53,32 +76,28 @@ export namespace RGBAUtil {
|
||||
};
|
||||
}
|
||||
|
||||
export function copy255(a: RGBA_255): RGBA_255 {
|
||||
return {
|
||||
r: a.r,
|
||||
g: a.g,
|
||||
b: a.b,
|
||||
a: a.a,
|
||||
} as RGBA_255;
|
||||
}
|
||||
|
||||
export function toArray(a: RGBA): number[] {
|
||||
return [a.r, a.g, a.b, a.a];
|
||||
}
|
||||
|
||||
export function bin(col: RGBA, resolution: TColourAccuracy) {
|
||||
const r = Math.floor(col.r * resolution);
|
||||
const g = Math.floor(col.g * resolution);
|
||||
const b = Math.floor(col.b * resolution);
|
||||
const a = Math.ceil(col.a * resolution);
|
||||
|
||||
let hash = r;
|
||||
hash = (hash << 8) + g;
|
||||
hash = (hash << 8) + b;
|
||||
hash = (hash << 8) + a;
|
||||
|
||||
const binnedColour: RGBA = {
|
||||
r: r / resolution,
|
||||
g: g / resolution,
|
||||
b: b / resolution,
|
||||
a: a / resolution,
|
||||
r: Math.floor(Math.floor(col.r * resolution) * (255 / resolution)),
|
||||
g: Math.floor(Math.floor(col.g * resolution) * (255 / resolution)),
|
||||
b: Math.floor(Math.floor(col.b * resolution) * (255 / resolution)),
|
||||
a: Math.floor(Math.ceil(col.a * resolution) * (255 / resolution)),
|
||||
};
|
||||
|
||||
return {
|
||||
colourHash: hash,
|
||||
binnedColour: binnedColour,
|
||||
};
|
||||
return binnedColour as RGBA_255;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -100,6 +119,14 @@ export namespace RGBAUtil {
|
||||
return hash;
|
||||
}
|
||||
|
||||
export function hash255(col: RGBA_255) {
|
||||
let hash = col.r;
|
||||
hash = (hash << 8) + col.g;
|
||||
hash = (hash << 8) + col.b;
|
||||
hash = (hash << 8) + col.a;
|
||||
return hash;
|
||||
}
|
||||
|
||||
export type TColourAccuracy = number;
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,7 @@ export class AppConfig {
|
||||
public readonly CAMERA_DEFAULT_ELEVATION_RADIANS: number;
|
||||
public readonly CAMERA_SENSITIVITY_ROTATION: number;
|
||||
public readonly CAMERA_SENSITIVITY_ZOOM: number;
|
||||
public readonly DITHER_MAGNITUDE: number;
|
||||
|
||||
private constructor() {
|
||||
this.RELEASE_MODE = false;
|
||||
@ -54,6 +55,7 @@ export class AppConfig {
|
||||
this.CAMERA_DEFAULT_ELEVATION_RADIANS = configJSON.CAMERA_DEFAULT_ELEVATION_RADIANS;
|
||||
this.CAMERA_SENSITIVITY_ROTATION = configJSON.CAMERA_SENSITIVITY_ROTATION;
|
||||
this.CAMERA_SENSITIVITY_ZOOM = configJSON.CAMERA_SENSITIVITY_ZOOM;
|
||||
this.DITHER_MAGNITUDE = configJSON.DITHER_MAGNITUDE;
|
||||
}
|
||||
|
||||
public dumpConfig() {
|
||||
|
47
src/dither.ts
Normal file
47
src/dither.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import { RGBA_255 } from './colour';
|
||||
import { AppConfig } from './config';
|
||||
import { ASSERT } from './util/error_util';
|
||||
import { Vector3 } from './vector';
|
||||
|
||||
export class Ditherer {
|
||||
public static ditherRandom(colour: RGBA_255) {
|
||||
const offset = (Math.random() - 0.5) * AppConfig.Get.DITHER_MAGNITUDE;
|
||||
|
||||
colour.r += offset;
|
||||
colour.g += offset;
|
||||
colour.b += offset;
|
||||
}
|
||||
|
||||
public static ditherOrdered(colour: RGBA_255, position: Vector3) {
|
||||
const map = this._getThresholdValue(
|
||||
Math.abs(position.x % 4),
|
||||
Math.abs(position.y % 4),
|
||||
Math.abs(position.z % 4),
|
||||
);
|
||||
|
||||
const offset = map * AppConfig.Get.DITHER_MAGNITUDE;
|
||||
|
||||
colour.r += offset;
|
||||
colour.g += offset;
|
||||
colour.b += offset;
|
||||
}
|
||||
|
||||
private static _mapMatrix = [
|
||||
0, 16, 2, 18, 48, 32, 50, 34,
|
||||
6, 22, 4, 20, 54, 38, 52, 36,
|
||||
24, 40, 26, 42, 8, 56, 10, 58,
|
||||
30, 46, 28, 44, 14, 62, 12, 60,
|
||||
3, 19, 5, 21, 51, 35, 53, 37,
|
||||
1, 17, 7, 23, 49, 33, 55, 39,
|
||||
27, 43, 29, 45, 11, 59, 13, 61,
|
||||
25, 41, 31, 47, 9, 57, 15, 63,
|
||||
];
|
||||
|
||||
private static _getThresholdValue(x: number, y: number, z: number) {
|
||||
const size = 4;
|
||||
ASSERT(0 <= x && x < size && 0 <= y && y < size && 0 <= z && z < size);
|
||||
const index = (x + (size * y) + (size * size * z));
|
||||
ASSERT(0 <= index && index < size * size * size);
|
||||
return (Ditherer._mapMatrix[index] / (size * size * size)) - 0.5;
|
||||
}
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
import fs from 'fs';
|
||||
|
||||
import { AppContext } from '../app_context';
|
||||
import { TBlockAssigners } from '../assigners/assigners';
|
||||
import { ArcballCamera } from '../camera';
|
||||
import { TExporters } from '../exporters/exporters';
|
||||
import { PaletteManager } from '../palette';
|
||||
@ -10,6 +9,7 @@ import { EAction } from '../util';
|
||||
import { ASSERT } from '../util/error_util';
|
||||
import { LOG } from '../util/log_util';
|
||||
import { AppPaths } from '../util/path_util';
|
||||
import { TDithering } from '../util/type_util';
|
||||
import { TVoxelOverlapRule } from '../voxel_mesh';
|
||||
import { TVoxelisers } from '../voxelisers/voxelisers';
|
||||
import { BaseUIElement } from './elements/base';
|
||||
@ -125,10 +125,10 @@ export class UI {
|
||||
elements: {
|
||||
'textureAtlas': new ComboBoxElement('Texture atlas', this._getTextureAtlases()),
|
||||
'blockPalette': new ComboBoxElement('Block palette', this._getBlockPalettes()),
|
||||
'dithering': new ComboBoxElement<TBlockAssigners>('Dithering', [
|
||||
{ id: 'ordered-dithering', displayText: 'Ordered' },
|
||||
{ id: 'random-dithering', displayText: 'Random' },
|
||||
{ id: 'basic', displayText: 'Off' },
|
||||
'dithering': new ComboBoxElement<TDithering>('Dithering', [
|
||||
{ id: 'ordered', displayText: 'Ordered' },
|
||||
{ id: 'random', displayText: 'Random' },
|
||||
{ id: 'off', displayText: 'Off' },
|
||||
]),
|
||||
'fallable': new ComboBoxElement('Fallable blocks', [
|
||||
{
|
||||
|
3
src/util/type_util.ts
Normal file
3
src/util/type_util.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export type TBrand<K, T> = K & { __brand: T };
|
||||
|
||||
export type TDithering = 'off' | 'random' | 'ordered';
|
@ -1,12 +1,13 @@
|
||||
import { TBlockAssigners } from './assigners/assigners';
|
||||
import { FallableBehaviour } from './block_mesh';
|
||||
import { TBlockMeshBufferDescription, TMeshBufferDescription, TVoxelMeshBufferDescription } from './buffer';
|
||||
import { RGBAUtil } from './colour';
|
||||
import { Ditherer } from './dither';
|
||||
import { TExporters } from './exporters/exporters';
|
||||
import { StatusMessage } from './status';
|
||||
import { TextureFiltering } from './texture';
|
||||
import { ColourSpace } from './util';
|
||||
import { AppError } from './util/error_util';
|
||||
import { TDithering } from './util/type_util';
|
||||
import { Vector3 } from './vector';
|
||||
import { TVoxelOverlapRule } from './voxel_mesh';
|
||||
import { TVoxelisers } from './voxelisers/voxelisers';
|
||||
@ -92,7 +93,7 @@ export namespace AssignParams {
|
||||
export type Input = {
|
||||
textureAtlas: TAtlasId,
|
||||
blockPalette: TPaletteId,
|
||||
blockAssigner: TBlockAssigners,
|
||||
dithering: TDithering,
|
||||
colourSpace: ColourSpace,
|
||||
fallable: FallableBehaviour,
|
||||
resolution: RGBAUtil.TColourAccuracy,
|
||||
|
@ -19,7 +19,7 @@ const baseConfig: THeadlessConfig = {
|
||||
assign: {
|
||||
textureAtlas: 'vanilla', // Must be an atlas name that exists in /resources/atlases
|
||||
blockPalette: 'all-snapshot', // Must be a palette name that exists in /resources/palettes
|
||||
blockAssigner: 'ordered-dithering',
|
||||
dithering: 'ordered',
|
||||
colourSpace: ColourSpace.RGB,
|
||||
fallable: 'replace-falling',
|
||||
resolution: 32,
|
||||
|
@ -19,7 +19,7 @@ const baseConfig: THeadlessConfig = {
|
||||
assign: {
|
||||
textureAtlas: 'vanilla', // Must be an atlas name that exists in /resources/atlases
|
||||
blockPalette: 'all-snapshot', // Must be a palette name that exists in /resources/palettes
|
||||
blockAssigner: 'ordered-dithering',
|
||||
dithering: 'ordered',
|
||||
colourSpace: ColourSpace.RGB,
|
||||
fallable: 'replace-falling',
|
||||
resolution: 32,
|
||||
|
@ -19,7 +19,7 @@ const baseConfig: THeadlessConfig = {
|
||||
assign: {
|
||||
textureAtlas: 'vanilla', // Must be an atlas name that exists in /resources/atlases
|
||||
blockPalette: 'all-snapshot', // Must be a palette name that exists in /resources/palettes
|
||||
blockAssigner: 'ordered-dithering',
|
||||
dithering: 'ordered',
|
||||
colourSpace: ColourSpace.RGB,
|
||||
fallable: 'replace-falling',
|
||||
resolution: 32,
|
||||
|
@ -19,7 +19,7 @@ const baseConfig: THeadlessConfig = {
|
||||
assign: {
|
||||
textureAtlas: 'vanilla', // Must be an atlas name that exists in /resources/atlases
|
||||
blockPalette: 'all-snapshot', // Must be a palette name that exists in /resources/palettes
|
||||
blockAssigner: 'ordered-dithering',
|
||||
dithering: 'ordered',
|
||||
colourSpace: ColourSpace.RGB,
|
||||
fallable: 'replace-falling',
|
||||
resolution: 32,
|
||||
|
@ -10,7 +10,7 @@ test('Random-dither', () => {
|
||||
const config = headlessConfig;
|
||||
|
||||
config.import.filepath = PathUtil.join(AppPaths.Get.resources, './samples/skull.obj');
|
||||
config.assign.blockAssigner = 'random-dithering';
|
||||
config.assign.dithering = 'random';
|
||||
|
||||
const worker = WorkerClient.Get;
|
||||
worker.import(headlessConfig.import);
|
||||
|
@ -17,7 +17,7 @@ export const headlessConfig: THeadlessConfig = {
|
||||
assign: {
|
||||
textureAtlas: 'vanilla', // Must be an atlas name that exists in /resources/atlases
|
||||
blockPalette: 'all-snapshot', // Must be a palette name that exists in /resources/palettes
|
||||
blockAssigner: 'ordered-dithering',
|
||||
dithering: 'ordered',
|
||||
colourSpace: ColourSpace.RGB,
|
||||
fallable: 'replace-falling',
|
||||
resolution: 32,
|
||||
|
Loading…
Reference in New Issue
Block a user