UNPKG

@polygonjs/polygonjs

Version:

node-based WebGL 3D engine https://polygonjs.com

151 lines (150 loc) 5.33 kB
"use strict"; import { Group } from "three"; import { WFCTilesCollection } from "./WFCTilesCollection"; import { filterTileObjects } from "./WFCUtils"; import { stringToTileConfigs } from "./WFCTileConfig"; import { placeObjectOnQuad } from "./WFCBuilderUtils"; import { QuadPrimitive } from "../geometry/modules/quad/QuadPrimitive"; import { ERROR_TILE_ID, UNRESOLVED_TILE_ID } from "./WFCConstant"; import { CoreWFCTileAttribute, WFCQuadAttribute } from "./WFCAttributes"; import { coreObjectClassFactory, corePrimitiveClassFactory } from "../geometry/CoreObjectFactory"; export class WFCBuilder { constructor(options) { const { node, quadObject, tileAndRuleObjects, tileHeight } = options; this._node = node; this._quadObject = quadObject; this._tileObjects = filterTileObjects(tileAndRuleObjects); this._tileHeight = tileHeight; this._tilesCollection = new WFCTilesCollection({ tileAndRuleObjects }); this._primitivesCount = QuadPrimitive.entitiesCount(quadObject); const hasAttribute = QuadPrimitive.hasAttribute(quadObject, WFCQuadAttribute.SOLVED_TILE_CONFIGS); if (!hasAttribute) { this._node.states.error.set(`attribute not found: ${WFCQuadAttribute.SOLVED_TILE_CONFIGS}`); return; } } createObjects() { const group = new Group(); group.matrixAutoUpdate = false; this._createObjects(this._quadObject, group); return group; } update(builderObject, solverObject) { builderObject.remove(...builderObject.children); this._createObjects(solverObject, builderObject); } _createObjects(solverObject, parent) { const primitiveClass = corePrimitiveClassFactory(solverObject); for (let i = 0; i < this._primitivesCount; i++) { const solvedTileConfigsString = primitiveClass.attribValue( solverObject, i, WFCQuadAttribute.SOLVED_TILE_CONFIGS ); if (!solvedTileConfigsString) { this._node.states.error.set(`attribute empty in primitive: ${i}`); return; } const tileConfigs = stringToTileConfigs(solvedTileConfigsString); this._processTileConfigs( this._quadObject, i, this._tilesCollection, this._tileObjects, tileConfigs, parent ); } } _processTileConfigs(quadObject, primitiveIndex, tilesCollection, tileObjects, tileConfigs, parent) { const count = tileConfigs.length; switch (count) { case 0: { console.warn("no tile configs found"); return; } case 1: { const object = this._convertTileConfig( quadObject, primitiveIndex, tilesCollection, tileObjects, tileConfigs[0] ); if (object) { parent.add(object); } return; } default: { const object = this._convertTileConfigs( quadObject, primitiveIndex, tilesCollection, tileObjects, tileConfigs ); if (object) { parent.add(object); } return; } } } _convertTileConfig(quadObject, primitiveIndex, tilesCollection, tileObjects, tileConfig) { const tileObject = this._tileObject(tilesCollection, tileConfig, tileObjects); if (!tileObject) { this._node.states.error.set(`tile object not found for tile id: ${tileConfig.tileId}`); return; } const newObject = placeObjectOnQuad({ object: tileObject, quadObject, primitiveIndex, rotation: tileConfig.rotation, height: this._tileHeight }); const quadId = QuadPrimitive.attribValue(quadObject, primitiveIndex, WFCQuadAttribute.QUAD_ID); coreObjectClassFactory(newObject).addAttribute(newObject, WFCQuadAttribute.QUAD_ID, quadId); return newObject; } _convertTileConfigs(quadObject, primitiveIndex, tilesCollection, tileObjects, tileConfigs) { const objects = []; for (const tileConfig of tileConfigs) { const object = this._convertTileConfig( quadObject, primitiveIndex, tilesCollection, tileObjects, tileConfig ); if (object) { objects.push(object); } } const objectsCount = objects.length; const gridSizeX = Math.ceil(Math.sqrt(objectsCount)); const gridSizeY = Math.ceil(objectsCount / gridSizeX); const group = new Group(); for (let x = 0; x < gridSizeX; x++) { for (let y = 0; y < gridSizeY; y++) { const index = x + y * gridSizeX; if (index < objectsCount) { const object = objects[index]; object.position.set(0.5 + x - gridSizeX / 2, 0, 0.5 + y - gridSizeY / 2); object.updateMatrix(); group.add(object); } } } const max = Math.max(gridSizeX, gridSizeY); group.scale.multiplyScalar(1 / max); QuadPrimitive.position(quadObject, primitiveIndex, group.position); group.updateMatrix(); group.matrixAutoUpdate = false; return group; } _tileObject(tilesCollection, tileConfig, tileObjects) { return tileConfig.tileId == UNRESOLVED_TILE_ID ? tilesCollection.unresolvedTile() : tileConfig.tileId == ERROR_TILE_ID ? tilesCollection.errorTile() : tileObjects.find((tileObject) => CoreWFCTileAttribute.getTileId(tileObject) == tileConfig.tileId); } }