forked from mirror/ObjToSchematic
Moved exporters into new folder
This commit is contained in:
parent
98d7bb16cd
commit
8289ba6579
@ -1,5 +1,6 @@
|
||||
import { UI } from './ui/layout';
|
||||
import { Litematic, Schematic } from './schematic';
|
||||
import { Schematic } from './exporters/schematic_exporter';
|
||||
import { Litematic } from './exporters/litematic_exporter';
|
||||
import { Renderer } from './renderer';
|
||||
import { Mesh } from './mesh';
|
||||
import { ObjImporter } from './importers/obj_importer';
|
||||
|
39
src/exporters/base_exporter.ts
Normal file
39
src/exporters/base_exporter.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { Vector3 } from '../vector';
|
||||
import { BlockMesh } from '../block_mesh';
|
||||
|
||||
import { NBT, writeUncompressed } from 'prismarine-nbt';
|
||||
import * as zlib from 'zlib';
|
||||
import * as fs from 'fs';
|
||||
|
||||
export abstract class IExporter {
|
||||
protected _sizeVector!: Vector3;
|
||||
|
||||
public abstract convertToNBT(blockMesh: BlockMesh): NBT
|
||||
abstract getFormatFilter(): Electron.FileFilter;
|
||||
abstract getFormatName(): string;
|
||||
abstract getFileExtension(): string;
|
||||
|
||||
getFormatDisclaimer(): string | undefined {
|
||||
return;
|
||||
}
|
||||
|
||||
export(blockMesh: BlockMesh, filePath: string): boolean {
|
||||
const bounds = blockMesh.getVoxelMesh()?.getBounds();
|
||||
this._sizeVector = Vector3.sub(bounds.max, bounds.min).addScalar(1);
|
||||
|
||||
const nbt = this.convertToNBT(blockMesh);
|
||||
|
||||
const outBuffer = fs.createWriteStream(filePath);
|
||||
const newBuffer = writeUncompressed(nbt, 'big');
|
||||
|
||||
zlib.gzip(newBuffer, (err, buffer) => {
|
||||
if (!err) {
|
||||
outBuffer.write(buffer);
|
||||
outBuffer.end();
|
||||
}
|
||||
return err;
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,123 +1,8 @@
|
||||
import * as zlib from 'zlib';
|
||||
import * as fs from 'fs';
|
||||
import path from 'path';
|
||||
import { NBT, TagType, writeUncompressed } from 'prismarine-nbt';
|
||||
import { Vector3 } from './vector';
|
||||
import { BlockMesh } from './block_mesh';
|
||||
import { RESOURCES_DIR } from './util';
|
||||
import { StatusHandler } from './status';
|
||||
import { BlockMesh } from '../block_mesh';
|
||||
import { Vector3 } from '../vector';
|
||||
import { IExporter } from './base_exporter';
|
||||
|
||||
export abstract class IExporter {
|
||||
protected _sizeVector!: Vector3;
|
||||
|
||||
public abstract convertToNBT(blockMesh: BlockMesh): NBT
|
||||
abstract getFormatFilter(): Electron.FileFilter;
|
||||
abstract getFormatName(): string;
|
||||
abstract getFileExtension(): string;
|
||||
|
||||
getFormatDisclaimer(): string | undefined {
|
||||
return;
|
||||
}
|
||||
|
||||
export(blockMesh: BlockMesh, filePath: string): boolean {
|
||||
const bounds = blockMesh.getVoxelMesh()?.getBounds();
|
||||
this._sizeVector = Vector3.sub(bounds.max, bounds.min).addScalar(1);
|
||||
|
||||
const nbt = this.convertToNBT(blockMesh);
|
||||
|
||||
const outBuffer = fs.createWriteStream(filePath);
|
||||
const newBuffer = writeUncompressed(nbt, 'big');
|
||||
|
||||
zlib.gzip(newBuffer, (err, buffer) => {
|
||||
if (!err) {
|
||||
outBuffer.write(buffer);
|
||||
outBuffer.end();
|
||||
}
|
||||
return err;
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export class Schematic extends IExporter {
|
||||
public override convertToNBT(blockMesh: BlockMesh) {
|
||||
const bufferSize = this._sizeVector.x * this._sizeVector.y * this._sizeVector.z;
|
||||
|
||||
const blocksData = Array<number>(bufferSize);
|
||||
const metaData = Array<number>(bufferSize);
|
||||
const bounds = blockMesh.getVoxelMesh().getBounds();
|
||||
|
||||
const schematicBlocks: { [blockName: string]: { id: number, meta: number, name: string } } = JSON.parse(
|
||||
fs.readFileSync(path.join(RESOURCES_DIR, './block_ids.json'), 'utf8'),
|
||||
);
|
||||
|
||||
const blocks = blockMesh.getBlocks();
|
||||
const unsupportedBlocks = new Set<string>();
|
||||
let numBlocksUnsupported = 0;
|
||||
for (const block of blocks) {
|
||||
const indexVector = Vector3.sub(block.voxel.position, bounds.min);
|
||||
const index = this._getBufferIndex(indexVector, this._sizeVector);
|
||||
if (block.blockInfo.name in schematicBlocks) {
|
||||
const schematicBlock = schematicBlocks[block.blockInfo.name];
|
||||
blocksData[index] = new Int8Array([schematicBlock.id])[0];
|
||||
metaData[index] = new Int8Array([schematicBlock.meta])[0];
|
||||
} else {
|
||||
blocksData[index] = 1; // Default to a Stone block
|
||||
metaData[index] = 0;
|
||||
unsupportedBlocks.add(block.blockInfo.name);
|
||||
++numBlocksUnsupported;
|
||||
}
|
||||
}
|
||||
|
||||
if (unsupportedBlocks.size > 0) {
|
||||
StatusHandler.Get.add(
|
||||
'warning',
|
||||
`${numBlocksUnsupported} blocks (${unsupportedBlocks.size} unique) are not supported by the .schematic format, Stone block are used in their place. Try using the schematic-friendly palette, or export using .litematica`,
|
||||
);
|
||||
}
|
||||
|
||||
const nbt: NBT = {
|
||||
type: TagType.Compound,
|
||||
name: 'Schematic',
|
||||
value: {
|
||||
Width: { type: TagType.Short, value: this._sizeVector.x },
|
||||
Height: { type: TagType.Short, value: this._sizeVector.y },
|
||||
Length: { type: TagType.Short, value: this._sizeVector.z },
|
||||
Materials: { type: TagType.String, value: 'Alpha' },
|
||||
Blocks: { type: TagType.ByteArray, value: blocksData },
|
||||
Data: { type: TagType.ByteArray, value: metaData },
|
||||
Entities: { type: TagType.List, value: { type: TagType.Int, value: Array(0) } },
|
||||
TileEntities: { type: TagType.List, value: { type: TagType.Int, value: Array(0) } },
|
||||
},
|
||||
};
|
||||
|
||||
return nbt;
|
||||
}
|
||||
|
||||
_getBufferIndex(vec: Vector3, sizeVector: Vector3) {
|
||||
return (sizeVector.z * sizeVector.x * vec.y) + (sizeVector.x * vec.z) + vec.x;
|
||||
}
|
||||
|
||||
getFormatFilter() {
|
||||
return {
|
||||
name: this.getFormatName(),
|
||||
extensions: ['schematic'],
|
||||
};
|
||||
}
|
||||
|
||||
getFormatName() {
|
||||
return 'Schematic';
|
||||
}
|
||||
|
||||
getFormatDisclaimer() {
|
||||
return 'Schematic files only support pre-1.13 blocks. As a result, all blocks will be exported as Stone. To export the blocks, use the .litematic format with the Litematica mod.';
|
||||
}
|
||||
|
||||
getFileExtension(): string {
|
||||
return 'schematic';
|
||||
}
|
||||
}
|
||||
import { NBT, TagType } from 'prismarine-nbt';
|
||||
|
||||
type BlockID = number;
|
||||
type long = [number, number];
|
88
src/exporters/schematic_exporter.ts
Normal file
88
src/exporters/schematic_exporter.ts
Normal file
@ -0,0 +1,88 @@
|
||||
import { BlockMesh } from '../block_mesh';
|
||||
import { RESOURCES_DIR } from '../util';
|
||||
import { IExporter } from './base_exporter';
|
||||
import { Vector3 } from '../vector';
|
||||
import { StatusHandler } from '../status';
|
||||
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { NBT, TagType } from 'prismarine-nbt';
|
||||
|
||||
export class Schematic extends IExporter {
|
||||
public override convertToNBT(blockMesh: BlockMesh) {
|
||||
const bufferSize = this._sizeVector.x * this._sizeVector.y * this._sizeVector.z;
|
||||
|
||||
const blocksData = Array<number>(bufferSize);
|
||||
const metaData = Array<number>(bufferSize);
|
||||
const bounds = blockMesh.getVoxelMesh().getBounds();
|
||||
|
||||
const schematicBlocks: { [blockName: string]: { id: number, meta: number, name: string } } = JSON.parse(
|
||||
fs.readFileSync(path.join(RESOURCES_DIR, './block_ids.json'), 'utf8'),
|
||||
);
|
||||
|
||||
const blocks = blockMesh.getBlocks();
|
||||
const unsupportedBlocks = new Set<string>();
|
||||
let numBlocksUnsupported = 0;
|
||||
for (const block of blocks) {
|
||||
const indexVector = Vector3.sub(block.voxel.position, bounds.min);
|
||||
const index = this._getBufferIndex(indexVector, this._sizeVector);
|
||||
if (block.blockInfo.name in schematicBlocks) {
|
||||
const schematicBlock = schematicBlocks[block.blockInfo.name];
|
||||
blocksData[index] = new Int8Array([schematicBlock.id])[0];
|
||||
metaData[index] = new Int8Array([schematicBlock.meta])[0];
|
||||
} else {
|
||||
blocksData[index] = 1; // Default to a Stone block
|
||||
metaData[index] = 0;
|
||||
unsupportedBlocks.add(block.blockInfo.name);
|
||||
++numBlocksUnsupported;
|
||||
}
|
||||
}
|
||||
|
||||
if (unsupportedBlocks.size > 0) {
|
||||
StatusHandler.Get.add(
|
||||
'warning',
|
||||
`${numBlocksUnsupported} blocks (${unsupportedBlocks.size} unique) are not supported by the .schematic format, Stone block are used in their place. Try using the schematic-friendly palette, or export using .litematica`,
|
||||
);
|
||||
}
|
||||
|
||||
const nbt: NBT = {
|
||||
type: TagType.Compound,
|
||||
name: 'Schematic',
|
||||
value: {
|
||||
Width: { type: TagType.Short, value: this._sizeVector.x },
|
||||
Height: { type: TagType.Short, value: this._sizeVector.y },
|
||||
Length: { type: TagType.Short, value: this._sizeVector.z },
|
||||
Materials: { type: TagType.String, value: 'Alpha' },
|
||||
Blocks: { type: TagType.ByteArray, value: blocksData },
|
||||
Data: { type: TagType.ByteArray, value: metaData },
|
||||
Entities: { type: TagType.List, value: { type: TagType.Int, value: Array(0) } },
|
||||
TileEntities: { type: TagType.List, value: { type: TagType.Int, value: Array(0) } },
|
||||
},
|
||||
};
|
||||
|
||||
return nbt;
|
||||
}
|
||||
|
||||
_getBufferIndex(vec: Vector3, sizeVector: Vector3) {
|
||||
return (sizeVector.z * sizeVector.x * vec.y) + (sizeVector.x * vec.z) + vec.x;
|
||||
}
|
||||
|
||||
getFormatFilter() {
|
||||
return {
|
||||
name: this.getFormatName(),
|
||||
extensions: ['schematic'],
|
||||
};
|
||||
}
|
||||
|
||||
getFormatName() {
|
||||
return 'Schematic';
|
||||
}
|
||||
|
||||
getFormatDisclaimer() {
|
||||
return 'Schematic files only support pre-1.13 blocks. As a result, all blocks will be exported as Stone. To export the blocks, use the .litematic format with the Litematica mod.';
|
||||
}
|
||||
|
||||
getFileExtension(): string {
|
||||
return 'schematic';
|
||||
}
|
||||
}
|
@ -1,69 +1,3 @@
|
||||
/*
|
||||
export class Occlusion {
|
||||
private _occlusionNeighboursIndices!: Array<Array<Array<number>>>; // Ew
|
||||
|
||||
public static calculateOcclusions(centre: Vector3, voxelMesh: VoxelMesh) {
|
||||
// Cache local neighbours
|
||||
const localNeighbourhoodCache = Array<number>(27);
|
||||
for (let i = -1; i <= 1; ++i) {
|
||||
for (let j = -1; j <= 1; ++j) {
|
||||
for (let k = -1; k <= 1; ++k) {
|
||||
const neighbour = new Vector3(i, j, k);
|
||||
const neighbourIndex = Renderer._getNeighbourIndex(neighbour);
|
||||
localNeighbourhoodCache[neighbourIndex] = voxelMesh.isVoxelAt(Vector3.add(centre, neighbour)) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const occlusions = new Array<Array<number>>(6);
|
||||
// For each face
|
||||
for (let f = 0; f < 6; ++f) {
|
||||
occlusions[f] = [1, 1, 1, 1];
|
||||
|
||||
// Only compute ambient occlusion if this face is visible
|
||||
const faceNormal = Occlusion._faceNormals[f];
|
||||
const faceNeighbourIndex = Occlusion._getNeighbourIndex(faceNormal);
|
||||
const faceVisible = localNeighbourhoodCache[faceNeighbourIndex] === 0;
|
||||
|
||||
if (faceVisible) {
|
||||
for (let v = 0; v < 4; ++v) {
|
||||
let numNeighbours = 0;
|
||||
for (let i = 0; i < 2; ++i) {
|
||||
const neighbourIndex = this._occlusionNeighboursIndices[f][v][i];
|
||||
numNeighbours += localNeighbourhoodCache[neighbourIndex];
|
||||
}
|
||||
// If both edge blocks along this vertex exist,
|
||||
// assume corner exists (even if it doesnt)
|
||||
// (This is a stylistic choice)
|
||||
if (numNeighbours == 2 && AppConfig.AMBIENT_OCCLUSION_OVERRIDE_CORNER) {
|
||||
++numNeighbours;
|
||||
} else {
|
||||
const neighbourIndex = this._occlusionNeighboursIndices[f][v][2];
|
||||
numNeighbours += localNeighbourhoodCache[neighbourIndex];
|
||||
}
|
||||
|
||||
// Convert from occlusion denoting the occlusion factor to the
|
||||
// attenuation in light value: 0 -> 1.0, 1 -> 0.8, 2 -> 0.6, 3 -> 0.4
|
||||
occlusions[f][v] = 1.0 - 0.2 * numNeighbours;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return occlusions;
|
||||
}
|
||||
|
||||
private static _getNeighbourIndex(neighbour: Vector3) {
|
||||
return 9 * (neighbour.x + 1) + 3 * (neighbour.y + 1) + (neighbour.z + 1);
|
||||
}
|
||||
|
||||
private static _faceNormals = [
|
||||
new Vector3(1, 0, 0), new Vector3(-1, 0, 0),
|
||||
new Vector3(0, 1, 0), new Vector3(0, -1, 0),
|
||||
new Vector3(0, 0, 1), new Vector3(0, 0, -1),
|
||||
];
|
||||
}
|
||||
*/
|
||||
|
||||
import { AppConfig } from './config';
|
||||
import { ASSERT } from './util';
|
||||
import { Vector3 } from './vector';
|
||||
|
@ -3,7 +3,9 @@ import { ObjImporter } from '../src/importers/obj_importer';
|
||||
import { IVoxeliser } from '../src/voxelisers/base-voxeliser';
|
||||
import { VoxelMesh, VoxelMeshParams } from '../src/voxel_mesh';
|
||||
import { BlockMesh, BlockMeshParams } from '../src/block_mesh';
|
||||
import { IExporter, Litematic, Schematic } from '../src/schematic';
|
||||
import { IExporter} from '../src/exporters/base_exporter';
|
||||
import { Schematic } from '../src/exporters/schematic_exporter';
|
||||
import { Litematic } from '../src/exporters/litematic_exporter';
|
||||
import { RayVoxeliser } from '../src/voxelisers/ray-voxeliser';
|
||||
import { NormalCorrectedRayVoxeliser } from '../src/voxelisers/normal-corrected-ray-voxeliser';
|
||||
import { TextureFiltering } from '../src/texture';
|
||||
|
Loading…
Reference in New Issue
Block a user