@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
151 lines (150 loc) • 5.33 kB
JavaScript
"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);
}
}