606 lines
19 KiB
TypeScript
606 lines
19 KiB
TypeScript
import { RenderTexture, Resource, Texture } from '@pixi/core';
|
|
import { Point } from '@pixi/math';
|
|
import { IAssetPlaneMaterial, IAssetPlaneMaterialCellColumn, IAssetPlaneTexture, IAssetPlaneVisualization, IAssetPlaneVisualizationData, IAssetPlaneVisualizationLayer, IGraphicAsset, IGraphicAssetCollection, IRoomGeometry, IVector3D, Vector3d } from '../../../../../../../api';
|
|
import { Rasterizer, RoomGeometry } from '../../../../../../../room';
|
|
import { PlaneBitmapData } from '../../utils';
|
|
import { IPlaneRasterizer } from '../IPlaneRasterizer';
|
|
import { FloorPlane } from './FloorPlane';
|
|
import { Plane } from './Plane';
|
|
import { PlaneMaterial } from './PlaneMaterial';
|
|
import { PlaneMaterialCell } from './PlaneMaterialCell';
|
|
import { PlaneMaterialCellColumn } from './PlaneMaterialCellColumn';
|
|
import { PlaneMaterialCellMatrix } from './PlaneMaterialCellMatrix';
|
|
import { PlaneTexture } from './PlaneTexture';
|
|
import { PlaneVisualizationLayer } from './PlaneVisualizationLayer';
|
|
|
|
export class PlaneRasterizer implements IPlaneRasterizer
|
|
{
|
|
protected static DEFAULT: string = 'default';
|
|
|
|
private _assetCollection: IGraphicAssetCollection;
|
|
private _materials: Map<string, PlaneMaterial>;
|
|
private _textures: Map<string, PlaneTexture>;
|
|
private _planes: Map<string, Plane>;
|
|
private _geometries: Map<string, RoomGeometry>;
|
|
private _data: IAssetPlaneVisualizationData;
|
|
|
|
constructor()
|
|
{
|
|
this._assetCollection = null;
|
|
this._textures = new Map();
|
|
this._materials = new Map();
|
|
this._planes = new Map();
|
|
this._geometries = new Map();
|
|
this._data = null;
|
|
}
|
|
|
|
protected get data(): IAssetPlaneVisualizationData
|
|
{
|
|
return this._data;
|
|
}
|
|
|
|
protected get assetCollection(): IGraphicAssetCollection
|
|
{
|
|
return this._assetCollection;
|
|
}
|
|
|
|
public initializeDimensions(k: number, _arg_2: number): boolean
|
|
{
|
|
return true;
|
|
}
|
|
|
|
public dispose(): void
|
|
{
|
|
if(this._planes)
|
|
{
|
|
for(const plane of this._planes.values())
|
|
{
|
|
if(!plane) continue;
|
|
|
|
plane.dispose();
|
|
}
|
|
|
|
this._planes = null;
|
|
}
|
|
|
|
if(this._materials)
|
|
{
|
|
this.resetMaterials();
|
|
|
|
this._materials = null;
|
|
}
|
|
|
|
if(this._textures)
|
|
{
|
|
this.resetTextures();
|
|
|
|
this._textures = null;
|
|
}
|
|
|
|
if(this._geometries)
|
|
{
|
|
for(const geometry of this._geometries.values())
|
|
{
|
|
if(!geometry) continue;
|
|
|
|
geometry.dispose();
|
|
}
|
|
|
|
this._geometries = null;
|
|
}
|
|
|
|
this._data = null;
|
|
this._assetCollection = null;
|
|
}
|
|
|
|
public clearCache(): void
|
|
{
|
|
for(const plane of this._planes.values())
|
|
{
|
|
if(!plane) continue;
|
|
|
|
plane.clearCache();
|
|
}
|
|
|
|
for(const material of this._materials.values())
|
|
{
|
|
if(!material) continue;
|
|
|
|
material.clearCache();
|
|
}
|
|
}
|
|
|
|
public initialize(data: IAssetPlaneVisualizationData): void
|
|
{
|
|
this._data = data;
|
|
}
|
|
|
|
public reinitialize(): void
|
|
{
|
|
this.resetTextures();
|
|
this.resetMaterials();
|
|
this.initializeAll();
|
|
}
|
|
|
|
private resetMaterials(): void
|
|
{
|
|
for(const material of this._materials.values())
|
|
{
|
|
if(!material) continue;
|
|
|
|
material.dispose();
|
|
}
|
|
|
|
this._materials.clear();
|
|
}
|
|
|
|
private resetTextures(): void
|
|
{
|
|
for(const texture of this._textures.values())
|
|
{
|
|
if(!texture) continue;
|
|
|
|
texture.dispose();
|
|
}
|
|
|
|
this._textures.clear();
|
|
}
|
|
|
|
protected getTexture(textureId: string): PlaneTexture
|
|
{
|
|
return this._textures.get(textureId);
|
|
}
|
|
|
|
protected getMaterial(materialId: string): PlaneMaterial
|
|
{
|
|
return this._materials.get(materialId);
|
|
}
|
|
|
|
protected getPlane(planeId: string): Plane
|
|
{
|
|
return this._planes.get(planeId);
|
|
}
|
|
|
|
protected addPlane(id: string, plane: Plane): boolean
|
|
{
|
|
if(!plane) return false;
|
|
|
|
const existing = this._planes.get(id);
|
|
|
|
if(!existing)
|
|
{
|
|
this._planes.set(id, plane);
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public initializeAssetCollection(collection: IGraphicAssetCollection): void
|
|
{
|
|
if(!this._data) return;
|
|
|
|
this._assetCollection = collection;
|
|
|
|
this.initializeAll();
|
|
}
|
|
|
|
private initializeAll(): void
|
|
{
|
|
if(!this._data) return;
|
|
|
|
this.initializeTexturesAndMaterials();
|
|
|
|
this.initializePlanes();
|
|
}
|
|
|
|
private initializeTexturesAndMaterials(): void
|
|
{
|
|
if(this._data.textures && this._data.textures.length) this.parseTextures(this._data.textures, this.assetCollection);
|
|
if(this._data.materials && this._data.materials.length) this.parsePlaneMaterials(this._data.materials);
|
|
}
|
|
|
|
protected initializePlanes(): void
|
|
{
|
|
}
|
|
|
|
private parseTextures(textures: IAssetPlaneTexture[], collection: IGraphicAssetCollection): void
|
|
{
|
|
if(!textures || !collection) return;
|
|
|
|
if(textures.length)
|
|
{
|
|
for(const texture of textures)
|
|
{
|
|
if(!texture) continue;
|
|
|
|
const id = texture.id;
|
|
|
|
if(!this._textures.get(id))
|
|
{
|
|
const plane = new PlaneTexture();
|
|
|
|
if(texture.bitmaps && texture.bitmaps.length)
|
|
{
|
|
for(const bitmap of texture.bitmaps)
|
|
{
|
|
if(!bitmap) continue;
|
|
|
|
const assetName = bitmap.assetName;
|
|
|
|
let normalMinX = PlaneTexture.MIN_NORMAL_COORDINATE_VALUE;
|
|
let normalMaxX = PlaneTexture.MAX_NORMAL_COORDINATE_VALUE;
|
|
let normalMinY = PlaneTexture.MIN_NORMAL_COORDINATE_VALUE;
|
|
let normalMaxY = PlaneTexture.MAX_NORMAL_COORDINATE_VALUE;
|
|
|
|
if(bitmap.normalMinX !== undefined) normalMinX = bitmap.normalMinX;
|
|
if(bitmap.normalMaxX !== undefined) normalMaxX = bitmap.normalMaxX;
|
|
if(bitmap.normalMinY !== undefined) normalMinY = bitmap.normalMinY;
|
|
if(bitmap.normalMaxY !== undefined) normalMaxY = bitmap.normalMaxY;
|
|
|
|
const asset = collection.getAsset(assetName);
|
|
|
|
if(asset)
|
|
{
|
|
const texture = asset.texture;
|
|
|
|
if(texture)
|
|
{
|
|
let newTexture: Texture<Resource> = texture;
|
|
|
|
if(asset.flipH)
|
|
{
|
|
newTexture = Rasterizer.getFlipHBitmapData(texture);
|
|
}
|
|
else
|
|
{
|
|
newTexture = newTexture.clone();
|
|
}
|
|
|
|
plane.addBitmap(newTexture, normalMinX, normalMaxX, normalMinY, normalMaxY, assetName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
this._textures.set(id, plane);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private parsePlaneMaterials(materials: IAssetPlaneMaterial[]): void
|
|
{
|
|
if(!materials || !materials.length) return;
|
|
|
|
for(const material of materials)
|
|
{
|
|
if(!material) continue;
|
|
|
|
const id = material.id;
|
|
const newMaterial = new PlaneMaterial();
|
|
|
|
if(material.matrices && material.matrices.length)
|
|
{
|
|
for(const matrix of material.matrices)
|
|
{
|
|
if(!matrix) continue;
|
|
|
|
let repeatMode = PlaneMaterialCellMatrix.REPEAT_MODE_DEFAULT;
|
|
let align = PlaneMaterialCellMatrix.ALIGN_DEFAULT;
|
|
|
|
let normalMinX = PlaneMaterialCellMatrix.MIN_NORMAL_COORDINATE_VALUE;
|
|
let normalMaxX = PlaneMaterialCellMatrix.MAX_NORMAL_COORDINATE_VALUE;
|
|
let normalMinY = PlaneMaterialCellMatrix.MIN_NORMAL_COORDINATE_VALUE;
|
|
let normalMaxY = PlaneMaterialCellMatrix.MAX_NORMAL_COORDINATE_VALUE;
|
|
|
|
if(matrix.normalMinX !== undefined) normalMinX = matrix.normalMinX;
|
|
if(matrix.normalMaxX !== undefined) normalMaxX = matrix.normalMaxX;
|
|
if(matrix.normalMinY !== undefined) normalMinY = matrix.normalMinY;
|
|
if(matrix.normalMaxY !== undefined) normalMaxY = matrix.normalMaxY;
|
|
|
|
switch(matrix.repeatMode)
|
|
{
|
|
case 'borders':
|
|
repeatMode = PlaneMaterialCellMatrix.REPEAT_MODE_BORDERS;
|
|
break;
|
|
case 'center':
|
|
repeatMode = PlaneMaterialCellMatrix.REPEAT_MODE_CENTER;
|
|
break;
|
|
case 'first':
|
|
repeatMode = PlaneMaterialCellMatrix.REPEAT_MODE_FIRST;
|
|
break;
|
|
case 'last':
|
|
repeatMode = PlaneMaterialCellMatrix.REPEAT_MODE_LAST;
|
|
break;
|
|
case 'random':
|
|
repeatMode = PlaneMaterialCellMatrix.REPEAT_MODE_RANDOM;
|
|
break;
|
|
default:
|
|
repeatMode = PlaneMaterialCellMatrix.REPEAT_MODE_DEFAULT;
|
|
break;
|
|
}
|
|
|
|
switch(matrix.align)
|
|
{
|
|
case 'top':
|
|
align = PlaneMaterialCellMatrix.ALIGN_TOP;
|
|
break;
|
|
case 'bottom':
|
|
align = PlaneMaterialCellMatrix.ALIGN_BOTTOM;
|
|
break;
|
|
default:
|
|
align = PlaneMaterialCellMatrix.ALIGN_DEFAULT;
|
|
break;
|
|
}
|
|
|
|
if(matrix.columns && matrix.columns.length)
|
|
{
|
|
const cellMatrix = newMaterial.addMaterialCellMatrix(matrix.columns.length, repeatMode, align, normalMinX, normalMaxX, normalMinY, normalMaxY);
|
|
|
|
let index = 0;
|
|
|
|
while(index < matrix.columns.length)
|
|
{
|
|
const column = matrix.columns[index];
|
|
|
|
if(column) this.parsePlaneMaterialCellColumn(column, cellMatrix, index);
|
|
|
|
index++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
this._materials.set(id, newMaterial);
|
|
}
|
|
}
|
|
|
|
private parsePlaneMaterialCellColumn(column: IAssetPlaneMaterialCellColumn, cellMatrix: PlaneMaterialCellMatrix, index: number): void
|
|
{
|
|
if(!column || !cellMatrix) return;
|
|
|
|
let repeatMode = PlaneMaterialCellColumn.REPEAT_MODE_ALL;
|
|
|
|
const width = column.width;
|
|
|
|
const cells = this.parsePlaneMaterialCells(column);
|
|
|
|
switch(column.repeatMode)
|
|
{
|
|
case 'borders':
|
|
repeatMode = PlaneMaterialCellColumn.REPEAT_MODE_BORDERS;
|
|
break;
|
|
case 'center':
|
|
repeatMode = PlaneMaterialCellColumn.REPEAT_MODE_CENTER;
|
|
break;
|
|
case 'first':
|
|
repeatMode = PlaneMaterialCellColumn.REPEAT_MODE_FIRST;
|
|
break;
|
|
case 'last':
|
|
repeatMode = PlaneMaterialCellColumn.REPEAT_MODE_LAST;
|
|
break;
|
|
case 'none':
|
|
repeatMode = PlaneMaterialCellColumn.REPEAT_MODE_NONE;
|
|
break;
|
|
default:
|
|
repeatMode = PlaneMaterialCellColumn.REPEAT_MODE_ALL;
|
|
break;
|
|
}
|
|
|
|
cellMatrix.createColumn(index, width, cells, repeatMode);
|
|
}
|
|
|
|
private parsePlaneMaterialCells(column: IAssetPlaneMaterialCellColumn): PlaneMaterialCell[]
|
|
{
|
|
if(!column || !column.cells || !column.cells.length) return null;
|
|
|
|
const cells: PlaneMaterialCell[] = [];
|
|
|
|
let index = 0;
|
|
|
|
while(index < column.cells.length)
|
|
{
|
|
const cell = column.cells[index];
|
|
|
|
if(cell)
|
|
{
|
|
const textureId = cell.textureId;
|
|
|
|
let assetNames: string[] = null;
|
|
let offsetPoints: Point[] = null;
|
|
let graphics: IGraphicAsset[] = null;
|
|
let limit = 0;
|
|
|
|
if(cell.extraData)
|
|
{
|
|
const types = cell.extraData.extraItemTypes;
|
|
const offsets = cell.extraData.offsets;
|
|
|
|
if(types && offsets)
|
|
{
|
|
if(types.length && offsets.length)
|
|
{
|
|
assetNames = this.parseExtraItemTypes(types);
|
|
offsetPoints = this.parseExtraItemOffsets(offsets);
|
|
limit = offsetPoints.length;
|
|
|
|
if(cell.extraData.limitMax !== undefined) limit = cell.extraData.limitMax;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(assetNames && assetNames.length)
|
|
{
|
|
graphics = [];
|
|
|
|
for(const assetName of assetNames)
|
|
{
|
|
if(!assetName) continue;
|
|
|
|
const asset = this._assetCollection.getAsset(assetName);
|
|
|
|
if(!asset) continue;
|
|
|
|
graphics.push(asset);
|
|
}
|
|
}
|
|
|
|
const texture = this.getTexture(textureId);
|
|
const newCell = new PlaneMaterialCell(texture, graphics, offsetPoints, limit);
|
|
|
|
cells.push(newCell);
|
|
}
|
|
|
|
index++;
|
|
}
|
|
|
|
if(!cells || !cells.length) return null;
|
|
|
|
return cells;
|
|
}
|
|
|
|
private parseExtraItemTypes(k: string[]): string[]
|
|
{
|
|
const assetNames: string[] = [];
|
|
|
|
if(k && k.length)
|
|
{
|
|
let index = 0;
|
|
|
|
while(index < k.length)
|
|
{
|
|
const type = k[index];
|
|
|
|
if(type) assetNames.push(type);
|
|
|
|
index++;
|
|
}
|
|
}
|
|
|
|
return assetNames;
|
|
}
|
|
|
|
private parseExtraItemOffsets(k: [ number, number][]): Point[]
|
|
{
|
|
const offsets: Point[] = [];
|
|
|
|
if(k && k.length)
|
|
{
|
|
let index = 0;
|
|
|
|
while(index < k.length)
|
|
{
|
|
const [ x, y ] = k[index];
|
|
|
|
offsets.push(new Point(x, y));
|
|
|
|
index++;
|
|
}
|
|
}
|
|
|
|
return offsets;
|
|
}
|
|
|
|
protected getGeometry(size: number, horizontalAngle: number, verticalAngle: number): IRoomGeometry
|
|
{
|
|
horizontalAngle = Math.abs(horizontalAngle);
|
|
if(horizontalAngle > 90) horizontalAngle = 90;
|
|
|
|
verticalAngle = Math.abs(verticalAngle);
|
|
if(verticalAngle > 90) verticalAngle = 90;
|
|
|
|
const identifier = `${size}_${Math.round(horizontalAngle)}_${Math.round(verticalAngle)}`;
|
|
|
|
let geometry = this._geometries.get(identifier);
|
|
|
|
if(geometry) return geometry;
|
|
|
|
geometry = new RoomGeometry(size, new Vector3d(horizontalAngle, verticalAngle), new Vector3d(-10, 0, 0));
|
|
|
|
this._geometries.set(identifier, geometry);
|
|
|
|
return geometry;
|
|
}
|
|
|
|
protected parseVisualizations(plane: Plane, visualizations: IAssetPlaneVisualization[]): void
|
|
{
|
|
if(!plane || !visualizations) return;
|
|
|
|
if(visualizations && visualizations.length)
|
|
{
|
|
for(const visualization of visualizations)
|
|
{
|
|
if(!visualization) continue;
|
|
|
|
const size = visualization.size;
|
|
|
|
let horizontalAngle = FloorPlane.HORIZONTAL_ANGLE_DEFAULT;
|
|
let verticalAngle = FloorPlane.VERTICAL_ANGLE_DEFAULT;
|
|
|
|
if(visualization.horizontalAngle !== undefined) horizontalAngle = visualization.horizontalAngle;
|
|
if(visualization.verticalAngle !== undefined) verticalAngle = visualization.verticalAngle;
|
|
|
|
const layers = visualization.allLayers as IAssetPlaneVisualizationLayer[];
|
|
|
|
const planeVisualization = plane.createPlaneVisualization(size, ((layers && layers.length) || 0), this.getGeometry(size, horizontalAngle, verticalAngle));
|
|
|
|
if(planeVisualization && (layers && layers.length))
|
|
{
|
|
let layerId = 0;
|
|
|
|
while(layerId < layers.length)
|
|
{
|
|
const layer = layers[layerId];
|
|
|
|
if(layer)
|
|
{
|
|
let material: PlaneMaterial = null;
|
|
let align: number = PlaneVisualizationLayer.ALIGN_DEFAULT;
|
|
let color: number = FloorPlane.DEFAULT_COLOR;
|
|
let offset: number = PlaneVisualizationLayer.DEFAULT_OFFSET;
|
|
|
|
if(layer.materialId) material = this.getMaterial(layer.materialId);
|
|
|
|
if(layer.color) color = layer.color;
|
|
|
|
if(layer.offset) offset = layer.offset;
|
|
|
|
if(layer.align)
|
|
{
|
|
if(layer.align === 'bottom') align = PlaneVisualizationLayer.ALIGN_BOTTOM;
|
|
|
|
else if(layer.align == 'top') align = PlaneVisualizationLayer.ALIGN_TOP;
|
|
}
|
|
|
|
planeVisualization.setLayer(layerId, material, color, align, offset);
|
|
}
|
|
|
|
layerId++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public render(planeId: string, canvas: RenderTexture, id: string, width: number, height: number, size: number, normal: IVector3D, useTexture: boolean, offsetX: number = 0, offsetY: number = 0, maxX: number = 0, maxY: number = 0, timeSinceStartMs: number = 0): PlaneBitmapData
|
|
{
|
|
return null;
|
|
}
|
|
|
|
public getTextureIdentifier(k: number, normal: IVector3D): string
|
|
{
|
|
return k.toString();
|
|
}
|
|
|
|
public getLayers(id: string): PlaneVisualizationLayer[]
|
|
{
|
|
let planes = this.getPlane(id);
|
|
|
|
if(!planes) planes = this.getPlane(PlaneRasterizer.DEFAULT);
|
|
|
|
return planes.getLayers();
|
|
}
|
|
}
|