diff --git a/packages/room/src/object/visualization/room/RoomPlane.ts b/packages/room/src/object/visualization/room/RoomPlane.ts index e9c91086..2f53046c 100644 --- a/packages/room/src/object/visualization/room/RoomPlane.ts +++ b/packages/room/src/object/visualization/room/RoomPlane.ts @@ -1,14 +1,18 @@ import { IAssetPlaneVisualizationLayer, IAssetRoomVisualizationData, IRoomGeometry, IRoomPlane, IVector3D } from '@nitrots/api'; import { GetAssetManager } from '@nitrots/assets'; import { TextureUtils, Vector3d } from '@nitrots/utils'; -import { Matrix, Point, Texture, TilingSprite } from 'pixi.js'; +import { Container, Matrix, Point, Sprite, Texture, TilingSprite } from 'pixi.js'; import { RoomGeometry } from '../../../utils'; +import { RoomPlaneBitmapMask } from './RoomPlaneBitmapMask'; +import { RoomPlaneRectangleMask } from './RoomPlaneRectangleMask'; +import { PlaneMaskManager } from './mask'; import { Randomizer } from './utils'; export class RoomPlane implements IRoomPlane { public static HORIZONTAL_ANGLE_DEFAULT: number = 45; public static VERTICAL_ANGLE_DEFAULT: number = 30; + public static PLANE_GEOMETRY: IRoomGeometry = new RoomGeometry(64, new Vector3d(RoomPlane.HORIZONTAL_ANGLE_DEFAULT, RoomPlane.VERTICAL_ANGLE_DEFAULT), new Vector3d(-10, 0, 0)); public static TYPE_UNDEFINED: number = 0; public static TYPE_WALL: number = 1; @@ -16,25 +20,26 @@ export class RoomPlane implements IRoomPlane public static TYPE_LANDSCAPE: number = 3; private static _uniqueIdCounter: number = 1; - private _disposed: boolean; + private _disposed: boolean = false; private _randomSeed: number; - private _origin: IVector3D; - private _location: IVector3D; - private _leftSide: IVector3D; - private _rightSide: IVector3D; - private _normal: IVector3D; - private _secondaryNormals: IVector3D[]; + private _origin: IVector3D = new Vector3d(); + private _location: IVector3D = new Vector3d(); + private _leftSide: IVector3D = new Vector3d(); + private _rightSide: IVector3D = new Vector3d(); + private _normal: IVector3D = null; + private _secondaryNormals: IVector3D[] = []; private _type: number; - private _isVisible: boolean; - private _offset: Point; - private _relativeDepth: number; - private _color: number; - private _id: string; + private _isVisible: boolean = false; + private _offset: Point = new Point(); + private _relativeDepth: number = 0; + private _color: number = 0; + private _maskManager: PlaneMaskManager = null; + private _id: string = null; private _uniqueId: number; - private _cornerA: IVector3D; - private _cornerB: IVector3D; - private _cornerC: IVector3D; - private _cornerD: IVector3D; + private _cornerA: IVector3D = new Vector3d(); + private _cornerB: IVector3D = new Vector3d(); + private _cornerC: IVector3D = new Vector3d(); + private _cornerD: IVector3D = new Vector3d(); private _textureOffsetX: number; private _textureOffsetY: number; private _textureMaxX: number; @@ -42,29 +47,27 @@ export class RoomPlane implements IRoomPlane private _width: number = 0; private _height: number = 0; private _hasTexture: boolean = true; - private _canBeVisible: boolean; + private _canBeVisible: boolean = true; + + private _useMask: boolean; + private _bitmapMasks: RoomPlaneBitmapMask[] = []; + private _rectangleMasks: RoomPlaneRectangleMask[] = []; + private _maskChanged: boolean = false; + private _bitmapMasksOld: RoomPlaneBitmapMask[] = []; + private _rectangleMasksOld: RoomPlaneRectangleMask[] = []; - private _tilingSprite: TilingSprite = null; private _planeTexture: Texture = null; constructor(origin: IVector3D, location: IVector3D, leftSide: IVector3D, rightSide: IVector3D, type: number, usesMask: boolean, secondaryNormals: IVector3D[], randomSeed: number, textureOffsetX: number = 0, textureOffsetY: number = 0, textureMaxX: number = 0, textureMaxY: number = 0) { - this._secondaryNormals = []; this._randomSeed = randomSeed; - this._origin = new Vector3d(); this._origin.assign(origin); - this._location = new Vector3d(); this._location.assign(location); - this._leftSide = new Vector3d(); this._leftSide.assign(leftSide); - this._rightSide = new Vector3d(); this._rightSide.assign(rightSide); this._normal = Vector3d.crossProduct(this._leftSide, this._rightSide); - if(this._normal.length > 0) - { - this._normal.multiply((1 / this._normal.length)); - } + if(this._normal.length > 0) this._normal.multiply((1 / this._normal.length)); if(secondaryNormals != null) { @@ -79,24 +82,13 @@ export class RoomPlane implements IRoomPlane this._secondaryNormals.push(vector); } } - this._disposed = false; - this._isVisible = false; - this._id = null; - this._offset = new Point(); - this._relativeDepth = 0; + this._type = type; - this._color = 0; - this._canBeVisible = true; - this._cornerA = new Vector3d(); - this._cornerB = new Vector3d(); - this._cornerC = new Vector3d(); - this._cornerD = new Vector3d(); this._textureOffsetX = textureOffsetX; this._textureOffsetY = textureOffsetY; this._textureMaxX = textureMaxX; this._textureMaxY = textureMaxY; - this._width = 0; - this._height = 0; + this._useMask = usesMask; this._uniqueId = ++RoomPlane._uniqueIdCounter; } @@ -174,14 +166,9 @@ export class RoomPlane implements IRoomPlane Randomizer.setSeed(this._randomSeed); - const horizontalAngle = RoomPlane.HORIZONTAL_ANGLE_DEFAULT; - const verticalAngle = RoomPlane.VERTICAL_ANGLE_DEFAULT; - - geometry = new RoomGeometry(64, new Vector3d(horizontalAngle, verticalAngle), new Vector3d(-10, 0, 0)); - - let width = (this._leftSide.length * geometry.scale); - let height = (this._rightSide.length * geometry.scale); - const normal = geometry.getCoordinatePosition(this._normal); + let width = (this._leftSide.length * RoomPlane.PLANE_GEOMETRY.scale); + let height = (this._rightSide.length * RoomPlane.PLANE_GEOMETRY.scale); + const normal = RoomPlane.PLANE_GEOMETRY.getCoordinatePosition(this._normal); const getTextureAndColorForPlane = (planeId: string, planeType: number) => { @@ -207,7 +194,7 @@ export class RoomPlane implements IRoomPlane return parseInt(color, 16); }; - return { texture, color: getRandomColor() }; + return { texture, color: planeColor }; }; const planeData = getTextureAndColorForPlane(this._id, this._type); @@ -218,9 +205,9 @@ export class RoomPlane implements IRoomPlane switch(this._type) { case RoomPlane.TYPE_FLOOR: { - const _local_10 = geometry.getScreenPoint(new Vector3d(0, 0, 0)); - const _local_11 = geometry.getScreenPoint(new Vector3d(0, (height / geometry.scale), 0)); - const _local_12 = geometry.getScreenPoint(new Vector3d((width / geometry.scale), 0, 0)); + const _local_10 = RoomPlane.PLANE_GEOMETRY.getScreenPoint(new Vector3d(0, 0, 0)); + const _local_11 = RoomPlane.PLANE_GEOMETRY.getScreenPoint(new Vector3d(0, (height / RoomPlane.PLANE_GEOMETRY.scale), 0)); + const _local_12 = RoomPlane.PLANE_GEOMETRY.getScreenPoint(new Vector3d((width / RoomPlane.PLANE_GEOMETRY.scale), 0, 0)); let x = 0; let y = 0; @@ -230,7 +217,7 @@ export class RoomPlane implements IRoomPlane width = Math.round(Math.abs((_local_10.x - _local_12.x))); height = Math.round(Math.abs((_local_10.x - _local_11.x))); - const _local_15 = (_local_10.x - geometry.getScreenPoint(new Vector3d(1, 0, 0)).x); + const _local_15 = (_local_10.x - RoomPlane.PLANE_GEOMETRY.getScreenPoint(new Vector3d(1, 0, 0)).x); x = (this._textureOffsetX * Math.trunc(Math.abs(_local_15))); y = (this._textureOffsetY * Math.trunc(Math.abs(_local_15))); @@ -257,9 +244,9 @@ export class RoomPlane implements IRoomPlane break; } case RoomPlane.TYPE_WALL: { - const _local_8 = geometry.getScreenPoint(new Vector3d(0, 0, 0)); - const _local_9 = geometry.getScreenPoint(new Vector3d(0, 0, (height / geometry.scale))); - const _local_10 = geometry.getScreenPoint(new Vector3d(0, (width / geometry.scale), 0)); + const _local_8 = RoomPlane.PLANE_GEOMETRY.getScreenPoint(new Vector3d(0, 0, 0)); + const _local_9 = RoomPlane.PLANE_GEOMETRY.getScreenPoint(new Vector3d(0, 0, (height / RoomPlane.PLANE_GEOMETRY.scale))); + const _local_10 = RoomPlane.PLANE_GEOMETRY.getScreenPoint(new Vector3d(0, (width / RoomPlane.PLANE_GEOMETRY.scale), 0)); if(_local_8 && _local_9 && _local_10) { @@ -281,14 +268,14 @@ export class RoomPlane implements IRoomPlane break; } case RoomPlane.TYPE_LANDSCAPE: { - const _local_13 = geometry.getScreenPoint(new Vector3d(0, 0, 0)); - const _local_14 = geometry.getScreenPoint(new Vector3d(0, 0, 1)); - const _local_15 = geometry.getScreenPoint(new Vector3d(0, 1, 0)); + const _local_13 = RoomPlane.PLANE_GEOMETRY.getScreenPoint(new Vector3d(0, 0, 0)); + const _local_14 = RoomPlane.PLANE_GEOMETRY.getScreenPoint(new Vector3d(0, 0, 1)); + const _local_15 = RoomPlane.PLANE_GEOMETRY.getScreenPoint(new Vector3d(0, 1, 0)); if(_local_13 && _local_14 && _local_15) { - width = Math.round(Math.abs((((_local_13.x - _local_15.x) * width) / geometry.scale))); - height = Math.round(Math.abs((((_local_13.y - _local_14.y) * height) / geometry.scale))); + width = Math.round(Math.abs((((_local_13.x - _local_15.x) * width) / RoomPlane.PLANE_GEOMETRY.scale))); + height = Math.round(Math.abs((((_local_13.y - _local_14.y) * height) / RoomPlane.PLANE_GEOMETRY.scale))); } const renderMaxX = Math.trunc(this._textureMaxX * Math.abs((_local_13.x - _local_15.x))); @@ -320,6 +307,8 @@ export class RoomPlane implements IRoomPlane } } + this.updateMask(planeSprite, geometry); + this._planeTexture = TextureUtils.createAndWriteRenderTexture(this._width, this._height, planeSprite, this.getMatrixForDimensions(width, height)) as Texture; return true; @@ -395,6 +384,183 @@ export class RoomPlane implements IRoomPlane return matrix; } + public resetBitmapMasks(): void + { + if(this._disposed || !this._useMask || !this._bitmapMasks.length) return; + + this._maskChanged = true; + this._bitmapMasks = []; + } + + public addBitmapMask(maskType: string, leftSideLoc: number, rightSideLoc: number): boolean + { + if(!this._useMask) return false; + + for(const mask of this._bitmapMasks) + { + if(!mask) continue; + + if((((mask.type === maskType) && (mask.leftSideLoc === leftSideLoc)) && (mask.rightSideLoc === rightSideLoc))) return false; + } + + const mask = new RoomPlaneBitmapMask(maskType, leftSideLoc, rightSideLoc); + + this._bitmapMasks.push(mask); + this._maskChanged = true; + + return true; + } + + public resetRectangleMasks(): void + { + if(!this._useMask || !this._rectangleMasks.length) return; + + this._maskChanged = true; + this._rectangleMasks = []; + } + + public addRectangleMask(leftLocation: number, rightLocation: number, leftLength: number, rightLength: number): boolean + { + if(this._useMask) + { + for(const mask of this._rectangleMasks) + { + if(!mask) continue; + + if((((mask.leftSideLoc === leftLocation) && (mask.rightSideLoc === rightLocation)) && (mask.leftSideLength === leftLength)) && (mask.rightSideLength === rightLength)) return false; + } + + this._rectangleMasks.push(new RoomPlaneRectangleMask(leftLocation, rightLocation, leftLength, rightLength)); + this._maskChanged = true; + + return true; + } + + return false; + } + + private updateMaskChangeStatus(): void + { + if(!this._maskChanged) return; + + let maskChanged = true; + + if(this._bitmapMasks.length === this._bitmapMasksOld.length) + { + for(const mask of this._bitmapMasks) + { + if(!mask) continue; + + let _local_6 = false; + + for(const plane of this._bitmapMasksOld) + { + if(!plane) continue; + + if(((plane.type === mask.type) && (plane.leftSideLoc === mask.leftSideLoc)) && (plane.rightSideLoc === mask.rightSideLoc)) + { + _local_6 = true; + + break; + } + } + + if(!_local_6) + { + maskChanged = false; + + break; + } + } + } + else + { + maskChanged = false; + } + + if(this._rectangleMasks.length > this._rectangleMasksOld.length) maskChanged = false; + + if(maskChanged) this._maskChanged = false; + } + + private updateMask(sprite: Container, geometry: IRoomGeometry): void + { + if(!sprite || !geometry) return; + + if(!this._useMask || ((!this._bitmapMasks.length && !this._rectangleMasks.length) && !this._maskChanged) || !this._maskManager) return; + + this.updateMaskChangeStatus(); + + /* if(!this._maskBitmapData || (this._maskBitmapData.width !== width) || (this._maskBitmapData.height !== height)) + { + this._maskBitmapData = this._textureCache.createAndFillRenderTexture(width, height, 'mask'); + this._maskChanged = true; + } */ + + if(this._maskChanged) + { + this._bitmapMasksOld = []; + this._rectangleMasksOld = []; + + const normal = geometry.getCoordinatePosition(this._normal); + + let type: string = null; + let posX = 0; + let posY = 0; + let i = 0; + + while(i < this._bitmapMasks.length) + { + const mask = this._bitmapMasks[i]; + + if(mask) + { + type = mask.type; + posX = (sprite.width - ((sprite.width * mask.leftSideLoc) / this._leftSide.length)); + posY = (sprite.height - ((sprite.height * mask.rightSideLoc) / this._rightSide.length)); + + this._maskManager.updateMask(sprite, type, geometry.scale, normal, posX, posY); + this._bitmapMasksOld.push(new RoomPlaneBitmapMask(type, mask.leftSideLoc, mask.rightSideLoc)); + } + + i++; + } + + i = 0; + + while(i < this._rectangleMasks.length) + { + const rectMask = this._rectangleMasks[i]; + + if(rectMask) + { + posX = (sprite.width - ((sprite.width * rectMask.leftSideLoc) / this._leftSide.length)); + posY = (sprite.height - ((sprite.height * rectMask.rightSideLoc) / this._rightSide.length)); + + const wd = ((sprite.width * rectMask.leftSideLength) / this._leftSide.length); + const ht = ((sprite.height * rectMask.rightSideLength) / this._rightSide.length); + + const maskSprite = new Sprite(Texture.WHITE); + + maskSprite.tint = 0x000000; + maskSprite.width = wd; + maskSprite.height = ht; + maskSprite.position.set((posX - wd), (posY - ht)); + + //this._textureCache.writeToRenderTexture(sprite, this._maskBitmapData, false); + + this._rectangleMasksOld.push(new RoomPlaneRectangleMask(rectMask.leftSideLength, rectMask.rightSideLoc, rectMask.leftSideLength, rectMask.rightSideLength)); + } + + i++; + } + + this._maskChanged = false; + } + + //this.combineTextureMask(canvas, this._maskPixels); + } + public get canBeVisible(): boolean { return this._canBeVisible; @@ -462,6 +628,11 @@ export class RoomPlane implements IRoomPlane this._id = k; } + public set maskManager(k: PlaneMaskManager) + { + this._maskManager = k; + } + public get uniqueId(): number { return this._uniqueId; diff --git a/packages/room/src/object/visualization/room/RoomVisualization.ts b/packages/room/src/object/visualization/room/RoomVisualization.ts index cd9337fc..c3e47c23 100644 --- a/packages/room/src/object/visualization/room/RoomVisualization.ts +++ b/packages/room/src/object/visualization/room/RoomVisualization.ts @@ -2,6 +2,9 @@ import { ToInt32, Vector3d } from '@nitrots/utils'; import { Rectangle } from 'pixi.js'; import { AlphaTolerance, IObjectVisualizationData, IPlaneVisualization, IRoomGeometry, IRoomObjectModel, IRoomObjectSprite, IRoomPlane, RoomObjectSpriteType, RoomObjectVariable } from '../../../../../api'; import { RoomMapData } from '../../RoomMapData'; +import { RoomMapMaskData } from '../../RoomMapMaskData'; +import { RoomPlaneBitmapMaskData } from '../../RoomPlaneBitmapMaskData'; +import { RoomPlaneBitmapMaskParser } from '../../RoomPlaneBitmapMaskParser'; import { RoomPlaneData } from '../../RoomPlaneData'; import { RoomPlaneParser } from '../../RoomPlaneParser'; import { RoomObjectSpriteVisualization } from '../RoomObjectSpriteVisualization'; @@ -22,60 +25,39 @@ export class RoomVisualization extends RoomObjectSpriteVisualization implements public static LANDSCAPE_COLOR_BOTTOM: number = 0x999999; private static ROOM_DEPTH_OFFSET: number = 1000; - protected _data: RoomVisualizationData; + protected _data: RoomVisualizationData = null; - private _roomPlaneParser: RoomPlaneParser; - - private _geometryUpdateId: number; - private _boundingRectangle: Rectangle; - private _directionX: number; - private _directionY: number; - private _directionZ: number; - private _floorThickness: number; - private _wallThickness: number; - private _holeUpdateTime: number; - private _planes: RoomPlane[]; - private _visiblePlanes: RoomPlane[]; - private _visiblePlaneSpriteNumbers: number[]; - private _roomScale: number; - private _colorBackgroundOnly: boolean; - private _redColor: number; - private _greenColor: number; - private _blueColor: number; + private _roomPlaneParser: RoomPlaneParser = new RoomPlaneParser(); + private _roomPlaneBitmapMaskParser: RoomPlaneBitmapMaskParser = new RoomPlaneBitmapMaskParser(); + private _geometryUpdateId: number = -1; + private _boundingRectangle: Rectangle = null; + private _directionX: number = 0; + private _directionY: number = 0; + private _directionZ: number = 0; + private _floorThickness: number = 1; + private _wallThickness: number = 1; + private _holeUpdateTime: number = NaN; + private _planes: RoomPlane[] = []; + private _visiblePlanes: RoomPlane[] = []; + private _visiblePlaneSpriteNumbers: number[] = []; + private _roomScale: number = 0; + private _colorBackgroundOnly: boolean = true; + private _color: number = 0xFFFFFF; + private _redColor: number = 0xFFFFFF; + private _greenColor: number = 0xFFFFFF; + private _blueColor: number = 0xFFFFFF; private _wallType: string = null; private _floorType: string = null; private _landscapeType: string = null; - private _typeVisibility: boolean[]; - private _assetUpdateCounter: number; - private _isPlaneSet: boolean; + private _typeVisibility: boolean[] = []; + private _assetUpdateCounter: number = 0; + private _maskData: RoomMapMaskData = null; + private _isPlaneSet: boolean = false; constructor() { super(); - this._data = null; - - this._roomPlaneParser = new RoomPlaneParser(); - - this._geometryUpdateId = -1; - this._directionX = 0; - this._directionY = 0; - this._directionZ = 0; - this._floorThickness = 1; - this._wallThickness = 1; - this._holeUpdateTime = NaN; - this._planes = []; - this._visiblePlanes = []; - this._visiblePlaneSpriteNumbers = []; - this._roomScale = 0; - this._colorBackgroundOnly = true; - this._redColor = 0xFF; - this._greenColor = 0xFF; - this._blueColor = 0xFF; - this._typeVisibility = []; - this._assetUpdateCounter = 0; - this._isPlaneSet = false; - this._typeVisibility[RoomPlane.TYPE_UNDEFINED] = false; this._typeVisibility[RoomPlane.TYPE_FLOOR] = true; this._typeVisibility[RoomPlane.TYPE_WALL] = true; @@ -112,8 +94,18 @@ export class RoomVisualization extends RoomObjectSpriteVisualization implements this._roomPlaneParser = null; } + if(this._roomPlaneBitmapMaskParser) + { + this._roomPlaneBitmapMaskParser.dispose(); + + this._roomPlaneBitmapMaskParser = null; + } + + if(this._data) { + this._data.clearCache(); + this._data = null; } } @@ -122,6 +114,10 @@ export class RoomVisualization extends RoomObjectSpriteVisualization implements { super.reset(); + this._floorType = null; + this._wallType = null; + this._landscapeType = null; + this._maskData = null; this._geometryUpdateId = -1; this._roomScale = 0; } @@ -139,42 +135,49 @@ export class RoomVisualization extends RoomObjectSpriteVisualization implements if(this.updateHole(objectModel)) needsUpdate = true; + this.initializeRoomPlanes(); + + if(this.updateMasks(objectModel)) needsUpdate = true; + if(!needsUpdate) return; - this.initializeRoomPlanes(); - this.updatePlaneTexturesAndVisibilities(objectModel); - this.updatePlanes(geometry, geometryUpdate, time); + if(this.updatePlaneTexturesAndVisibilities(objectModel)) needsUpdate = true; - let index = 0; + if(this.updatePlanes(geometry, geometryUpdate, time)) needsUpdate = true; - while(index < this._visiblePlanes.length) + if(needsUpdate) { - const spriteIndex = this._visiblePlaneSpriteNumbers[index]; - const sprite = this.getSprite(spriteIndex); - const plane = this._visiblePlanes[index]; + let index = 0; - if(sprite && plane && (plane.type !== RoomPlane.TYPE_LANDSCAPE)) + while(index < this._visiblePlanes.length) { - if(this._colorBackgroundOnly) + const spriteIndex = this._visiblePlaneSpriteNumbers[index]; + const sprite = this.getSprite(spriteIndex); + const plane = this._visiblePlanes[index]; + + if(sprite && plane && (plane.type !== RoomPlane.TYPE_LANDSCAPE)) { - let _local_14 = plane.color; + if(this._colorBackgroundOnly) + { + let _local_14 = plane.color; - const _local_15 = (((_local_14 & 0xFF) * this._redColor) / 0xFF); - const _local_16 = ((((_local_14 >> 8) & 0xFF) * this._greenColor) / 0xFF); - const _local_17 = ((((_local_14 >> 16) & 0xFF) * this._blueColor) / 0xFF); - const _local_18 = (_local_14 >> 24); + const _local_15 = (((_local_14 & 0xFF) * this._redColor) / 0xFF); + const _local_16 = ((((_local_14 >> 8) & 0xFF) * this._greenColor) / 0xFF); + const _local_17 = ((((_local_14 >> 16) & 0xFF) * this._blueColor) / 0xFF); + const _local_18 = (_local_14 >> 24); - _local_14 = ((((_local_18 << 24) + (_local_17 << 16)) + (_local_16 << 8)) + _local_15); + _local_14 = ((((_local_18 << 24) + (_local_17 << 16)) + (_local_16 << 8)) + _local_15); - sprite.color = _local_14; - } - else - { - sprite.color = plane.color; + sprite.color = _local_14; + } + else + { + sprite.color = plane.color; + } } + + index++; } - - index++; } this.updateSpriteCounter++; @@ -259,6 +262,47 @@ export class RoomVisualization extends RoomObjectSpriteVisualization implements return (this.updatePlaneTypes(floorType, wallType, landscapeType) || this.updatePlaneVisibility(floorVisibility, wallVisibility, landscapeVisibility)); } + private updateMasks(model: IRoomObjectModel): boolean + { + if(this.updateModelCounter === model.updateCounter) return false; + + let didUpdate = false; + + const planeMask = model.getValue(RoomObjectVariable.ROOM_PLANE_MASK_XML); + + if(planeMask !== this._maskData) + { + this.updatePlaneMasks(planeMask); + + this._maskData = planeMask; + + didUpdate = true; + } + + const backgroundColor = model.getValue(RoomObjectVariable.ROOM_BACKGROUND_COLOR); + + if(backgroundColor !== this._color) + { + this._color = backgroundColor; + this._redColor = (this._color & 0xFF); + this._greenColor = ((this._color >> 8) & 0xFF); + this._blueColor = ((this._color >> 16) & 0xFF); + + didUpdate = true; + } + + const backgroundOnly = (model.getValue(RoomObjectVariable.ROOM_COLORIZE_BG_ONLY) || false); + + if(backgroundOnly !== this._colorBackgroundOnly) + { + this._colorBackgroundOnly = backgroundOnly; + + didUpdate = true; + } + + return didUpdate; + } + private clearPlanes(): void { if(this._planes) @@ -349,7 +393,26 @@ export class RoomVisualization extends RoomObjectSpriteVisualization implements landscapeOffsetX = (landscapeOffsetX + leftSide.length); } - if(plane) this._planes.push(plane); + if(plane) + { + plane.maskManager = this._data.maskManager; + + let i = 0; + + while(i < this._roomPlaneParser.getPlaneMaskCount(index)) + { + const _local_20 = this._roomPlaneParser.getPlaneMaskLeftSideLoc(index, i); + const _local_21 = this._roomPlaneParser.getPlaneMaskRightSideLoc(index, i); + const _local_22 = this._roomPlaneParser.getPlaneMaskLeftSideLength(index, i); + const _local_23 = this._roomPlaneParser.getPlaneMaskRightSideLength(index, i); + + plane.addRectangleMask(_local_20, _local_21, _local_22, _local_23); + + i++; + } + + this._planes.push(plane); + } } else { @@ -603,6 +666,109 @@ export class RoomVisualization extends RoomObjectSpriteVisualization implements return updated; } + protected updatePlaneMasks(maskData: RoomMapMaskData): void + { + if(!maskData) return; + + this._roomPlaneBitmapMaskParser.initialize(maskData); + + const _local_4: number[] = []; + const _local_5: number[] = []; + + let _local_6 = false; + let index = 0; + + while(index < this._planes.length) + { + const plane = this._planes[index]; + + if(plane) + { + plane.resetBitmapMasks(); + + if(plane.type === RoomPlane.TYPE_LANDSCAPE) _local_4.push(index); + } + + index++; + } + + for(const mask of this._roomPlaneBitmapMaskParser.masks.values()) + { + const maskType = this._roomPlaneBitmapMaskParser.getMaskType(mask); + const maskLocation = this._roomPlaneBitmapMaskParser.getMaskLocation(mask); + const maskCategory = this._roomPlaneBitmapMaskParser.getMaskCategory(mask); + + if(maskLocation) + { + let i = 0; + + while(i < this._planes.length) + { + const plane = this._planes[i]; + + if((plane.type === RoomPlane.TYPE_WALL) || (plane.type === RoomPlane.TYPE_LANDSCAPE)) + { + if(plane && plane.location && plane.normal) + { + const _local_14 = Vector3d.dif(maskLocation, plane.location); + const _local_15 = Math.abs(Vector3d.scalarProjection(_local_14, plane.normal)); + + if(_local_15 < 0.01) + { + if(plane.leftSide && plane.rightSide) + { + const leftSideLoc = Vector3d.scalarProjection(_local_14, plane.leftSide); + const rightSideLoc = Vector3d.scalarProjection(_local_14, plane.rightSide); + + if((plane.type === RoomPlane.TYPE_WALL) || ((plane.type === RoomPlane.TYPE_LANDSCAPE) && (maskCategory === RoomPlaneBitmapMaskData.HOLE))) + { + plane.addBitmapMask(maskType, leftSideLoc, rightSideLoc); + } + else + { + if(plane.type === RoomPlane.TYPE_LANDSCAPE) + { + if(!plane.canBeVisible) _local_6 = true; + + plane.canBeVisible = true; + + _local_5.push(i); + } + } + } + } + } + } + + i++; + } + } + } + + index = 0; + + while(index < _local_4.length) + { + const planeIndex = _local_4[index]; + + if(_local_5.indexOf(planeIndex) < 0) + { + const plane = this._planes[planeIndex]; + + plane.canBeVisible = false; + _local_6 = true; + } + + index++; + } + + if(_local_6) + { + this._visiblePlanes = []; + this._visiblePlaneSpriteNumbers = []; + } + } + private updateSprite(sprite: IRoomObjectSprite, geometry: IRoomGeometry, plane: RoomPlane, _arg_3: string, relativeDepth: number): void { const offset = plane.offset; diff --git a/packages/room/src/object/visualization/room/mask/PlaneMaskManager.ts b/packages/room/src/object/visualization/room/mask/PlaneMaskManager.ts index a47fff1e..80562ac0 100644 --- a/packages/room/src/object/visualization/room/mask/PlaneMaskManager.ts +++ b/packages/room/src/object/visualization/room/mask/PlaneMaskManager.ts @@ -1,6 +1,6 @@ import { IAssetPlaneMaskData, IAssetPlaneTextureBitmap, IGraphicAssetCollection, IVector3D } from '@nitrots/api'; -import { TextureUtils } from '@nitrots/utils'; -import { Matrix, Point, Sprite, Texture } from 'pixi.js'; +import { CutMaskFilter } from '@nitrots/utils'; +import { Container, Matrix, Point } from 'pixi.js'; import { PlaneMask } from './PlaneMask'; import { PlaneMaskVisualization } from './PlaneMaskVisualization'; @@ -141,7 +141,7 @@ export class PlaneMaskManager return graphicName; } - public updateMask(canvas: Texture, type: string, scale: number, normal: IVector3D, posX: number, posY: number): boolean + public updateMask(sprite: Container, type: string, scale: number, normal: IVector3D, posX: number, posY: number): boolean { const mask = this._masks.get(type); @@ -157,6 +157,14 @@ export class PlaneMaskManager const point = new Point((posX + asset.offsetX), (posY + asset.offsetY)); + const filter = new CutMaskFilter({ + maskTexture: texture + }); + + sprite.filters = [filter]; + + return true; + const matrix = new Matrix(); let xScale = 1; @@ -185,7 +193,7 @@ export class PlaneMaskManager matrix.scale(xScale, ySkew); matrix.translate(tx, ty); - TextureUtils.writeToTexture(new Sprite(texture), canvas, false, matrix); + //TextureUtils.writeToTexture(new Sprite(texture), canvas, false, matrix); return true; } diff --git a/packages/room/src/renderer/utils/ExtendedSprite.ts b/packages/room/src/renderer/utils/ExtendedSprite.ts index f9ddfffb..d3bb75ee 100644 --- a/packages/room/src/renderer/utils/ExtendedSprite.ts +++ b/packages/room/src/renderer/utils/ExtendedSprite.ts @@ -70,14 +70,7 @@ export class ExtendedSprite extends Sprite const index = (dx + dy * textureSource.width) * 4; - const red = hitMap[index]; - const green = hitMap[index + 1]; - const blue = hitMap[index + 2]; - const alpha = hitMap[index + 3]; - - const result = (alpha >= this.alphaTolerance); - - return result; + return (hitMap[index + 3] >= this.alphaTolerance); } private static generateHitMapForTextureSource(textureSource: TextureSource): boolean diff --git a/packages/utils/src/filters/CutMaskFilter.ts b/packages/utils/src/filters/CutMaskFilter.ts new file mode 100644 index 00000000..44b16d92 --- /dev/null +++ b/packages/utils/src/filters/CutMaskFilter.ts @@ -0,0 +1,93 @@ +import { Filter, FilterSystem, GlProgram, RenderSurface, Texture } from 'pixi.js'; + +export interface CutTransparentAreaFilterOptions +{ + maskTexture: Texture; +} + +export class CutMaskFilter extends Filter +{ + public static readonly DEFAULT_OPTIONS: CutTransparentAreaFilterOptions = { + maskTexture: Texture.WHITE, + }; + + public uniforms: { + uColor: Float32Array; + uAlpha: number; + uDimensions: Float32Array; + }; + + constructor(options: CutTransparentAreaFilterOptions) + { + options = { ...CutMaskFilter.DEFAULT_OPTIONS, ...options }; + + if(!options.maskTexture) throw Error('No texture provided for mask filter'); + + const glProgram = GlProgram.from({ + vertex: `in vec2 aPosition; + out vec2 vTextureCoord; + + uniform vec4 uInputSize; + uniform vec4 uOutputFrame; + uniform vec4 uOutputTexture; + + vec4 filterVertexPosition( void ) + { + vec2 position = aPosition * uOutputFrame.zw + uOutputFrame.xy; + + position.x = position.x * (2.0 / uOutputTexture.x) - 1.0; + position.y = position.y * (2.0*uOutputTexture.z / uOutputTexture.y) - uOutputTexture.z; + + return vec4(position, 0.0, 1.0); + } + + vec2 filterTextureCoord( void ) + { + return aPosition * (uOutputFrame.zw * uInputSize.zw); + } + + void main(void) + { + gl_Position = filterVertexPosition(); + vTextureCoord = filterTextureCoord(); + }`, + fragment: `varying vec2 vTextureCoord; + + uniform sampler2D uSampler; // The sprite's texture + uniform sampler2D maskTexture; // The mask texture + + void main(void) { + vec4 spriteColor = texture2D(uSampler, vTextureCoord); + vec4 maskColor = texture2D(maskTexture, vTextureCoord); + + // Use mask alpha to determine the transparency + float alpha = maskColor.a; + + // Apply the mask based on its alpha value + // You can modify this logic to suit your masking criteria + gl_FragColor = vec4(spriteColor.rgb, spriteColor.a * (1.0 - alpha)); + }`, + name: 'cut-mask-filter', + }); + + super({ + gpuProgram: null, + glProgram, + resources: { + maskTexture: options.maskTexture + }, + }); + + Object.assign(this, options); + } + + public apply( + filterManager: FilterSystem, + input: Texture, + output: RenderSurface, + clearMode: boolean, + ): void + { + filterManager.applyFilter(this, input, output, clearMode); + } +} diff --git a/packages/utils/src/filters/index.ts b/packages/utils/src/filters/index.ts new file mode 100644 index 00000000..828d16df --- /dev/null +++ b/packages/utils/src/filters/index.ts @@ -0,0 +1 @@ +export * from './CutMaskFilter'; diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index b9854ee2..bee669ee 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -24,4 +24,5 @@ export * from './PointMath'; export * from './RoomId'; export * from './TextureUtils'; export * from './Vector3d'; +export * from './filters'; export * from './motion';