Begin plane masks/door

This commit is contained in:
billsonnn 2024-03-23 23:03:57 -04:00
parent 79b662fdb9
commit 842a996b93
7 changed files with 576 additions and 143 deletions

View File

@ -1,14 +1,18 @@
import { IAssetPlaneVisualizationLayer, IAssetRoomVisualizationData, IRoomGeometry, IRoomPlane, IVector3D } from '@nitrots/api'; import { IAssetPlaneVisualizationLayer, IAssetRoomVisualizationData, IRoomGeometry, IRoomPlane, IVector3D } from '@nitrots/api';
import { GetAssetManager } from '@nitrots/assets'; import { GetAssetManager } from '@nitrots/assets';
import { TextureUtils, Vector3d } from '@nitrots/utils'; 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 { RoomGeometry } from '../../../utils';
import { RoomPlaneBitmapMask } from './RoomPlaneBitmapMask';
import { RoomPlaneRectangleMask } from './RoomPlaneRectangleMask';
import { PlaneMaskManager } from './mask';
import { Randomizer } from './utils'; import { Randomizer } from './utils';
export class RoomPlane implements IRoomPlane export class RoomPlane implements IRoomPlane
{ {
public static HORIZONTAL_ANGLE_DEFAULT: number = 45; public static HORIZONTAL_ANGLE_DEFAULT: number = 45;
public static VERTICAL_ANGLE_DEFAULT: number = 30; 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_UNDEFINED: number = 0;
public static TYPE_WALL: number = 1; public static TYPE_WALL: number = 1;
@ -16,25 +20,26 @@ export class RoomPlane implements IRoomPlane
public static TYPE_LANDSCAPE: number = 3; public static TYPE_LANDSCAPE: number = 3;
private static _uniqueIdCounter: number = 1; private static _uniqueIdCounter: number = 1;
private _disposed: boolean; private _disposed: boolean = false;
private _randomSeed: number; private _randomSeed: number;
private _origin: IVector3D; private _origin: IVector3D = new Vector3d();
private _location: IVector3D; private _location: IVector3D = new Vector3d();
private _leftSide: IVector3D; private _leftSide: IVector3D = new Vector3d();
private _rightSide: IVector3D; private _rightSide: IVector3D = new Vector3d();
private _normal: IVector3D; private _normal: IVector3D = null;
private _secondaryNormals: IVector3D[]; private _secondaryNormals: IVector3D[] = [];
private _type: number; private _type: number;
private _isVisible: boolean; private _isVisible: boolean = false;
private _offset: Point; private _offset: Point = new Point();
private _relativeDepth: number; private _relativeDepth: number = 0;
private _color: number; private _color: number = 0;
private _id: string; private _maskManager: PlaneMaskManager = null;
private _id: string = null;
private _uniqueId: number; private _uniqueId: number;
private _cornerA: IVector3D; private _cornerA: IVector3D = new Vector3d();
private _cornerB: IVector3D; private _cornerB: IVector3D = new Vector3d();
private _cornerC: IVector3D; private _cornerC: IVector3D = new Vector3d();
private _cornerD: IVector3D; private _cornerD: IVector3D = new Vector3d();
private _textureOffsetX: number; private _textureOffsetX: number;
private _textureOffsetY: number; private _textureOffsetY: number;
private _textureMaxX: number; private _textureMaxX: number;
@ -42,29 +47,27 @@ export class RoomPlane implements IRoomPlane
private _width: number = 0; private _width: number = 0;
private _height: number = 0; private _height: number = 0;
private _hasTexture: boolean = true; 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; 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) 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._randomSeed = randomSeed;
this._origin = new Vector3d();
this._origin.assign(origin); this._origin.assign(origin);
this._location = new Vector3d();
this._location.assign(location); this._location.assign(location);
this._leftSide = new Vector3d();
this._leftSide.assign(leftSide); this._leftSide.assign(leftSide);
this._rightSide = new Vector3d();
this._rightSide.assign(rightSide); this._rightSide.assign(rightSide);
this._normal = Vector3d.crossProduct(this._leftSide, this._rightSide); this._normal = Vector3d.crossProduct(this._leftSide, this._rightSide);
if(this._normal.length > 0) if(this._normal.length > 0) this._normal.multiply((1 / this._normal.length));
{
this._normal.multiply((1 / this._normal.length));
}
if(secondaryNormals != null) if(secondaryNormals != null)
{ {
@ -79,24 +82,13 @@ export class RoomPlane implements IRoomPlane
this._secondaryNormals.push(vector); this._secondaryNormals.push(vector);
} }
} }
this._disposed = false;
this._isVisible = false;
this._id = null;
this._offset = new Point();
this._relativeDepth = 0;
this._type = type; 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._textureOffsetX = textureOffsetX;
this._textureOffsetY = textureOffsetY; this._textureOffsetY = textureOffsetY;
this._textureMaxX = textureMaxX; this._textureMaxX = textureMaxX;
this._textureMaxY = textureMaxY; this._textureMaxY = textureMaxY;
this._width = 0; this._useMask = usesMask;
this._height = 0;
this._uniqueId = ++RoomPlane._uniqueIdCounter; this._uniqueId = ++RoomPlane._uniqueIdCounter;
} }
@ -174,14 +166,9 @@ export class RoomPlane implements IRoomPlane
Randomizer.setSeed(this._randomSeed); Randomizer.setSeed(this._randomSeed);
const horizontalAngle = RoomPlane.HORIZONTAL_ANGLE_DEFAULT; let width = (this._leftSide.length * RoomPlane.PLANE_GEOMETRY.scale);
const verticalAngle = RoomPlane.VERTICAL_ANGLE_DEFAULT; let height = (this._rightSide.length * RoomPlane.PLANE_GEOMETRY.scale);
const normal = RoomPlane.PLANE_GEOMETRY.getCoordinatePosition(this._normal);
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);
const getTextureAndColorForPlane = (planeId: string, planeType: number) => const getTextureAndColorForPlane = (planeId: string, planeType: number) =>
{ {
@ -207,7 +194,7 @@ export class RoomPlane implements IRoomPlane
return parseInt(color, 16); return parseInt(color, 16);
}; };
return { texture, color: getRandomColor() }; return { texture, color: planeColor };
}; };
const planeData = getTextureAndColorForPlane(this._id, this._type); const planeData = getTextureAndColorForPlane(this._id, this._type);
@ -218,9 +205,9 @@ export class RoomPlane implements IRoomPlane
switch(this._type) switch(this._type)
{ {
case RoomPlane.TYPE_FLOOR: { case RoomPlane.TYPE_FLOOR: {
const _local_10 = geometry.getScreenPoint(new Vector3d(0, 0, 0)); const _local_10 = RoomPlane.PLANE_GEOMETRY.getScreenPoint(new Vector3d(0, 0, 0));
const _local_11 = geometry.getScreenPoint(new Vector3d(0, (height / geometry.scale), 0)); const _local_11 = RoomPlane.PLANE_GEOMETRY.getScreenPoint(new Vector3d(0, (height / RoomPlane.PLANE_GEOMETRY.scale), 0));
const _local_12 = geometry.getScreenPoint(new Vector3d((width / geometry.scale), 0, 0)); const _local_12 = RoomPlane.PLANE_GEOMETRY.getScreenPoint(new Vector3d((width / RoomPlane.PLANE_GEOMETRY.scale), 0, 0));
let x = 0; let x = 0;
let y = 0; let y = 0;
@ -230,7 +217,7 @@ export class RoomPlane implements IRoomPlane
width = Math.round(Math.abs((_local_10.x - _local_12.x))); width = Math.round(Math.abs((_local_10.x - _local_12.x)));
height = Math.round(Math.abs((_local_10.x - _local_11.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))); x = (this._textureOffsetX * Math.trunc(Math.abs(_local_15)));
y = (this._textureOffsetY * 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; break;
} }
case RoomPlane.TYPE_WALL: { case RoomPlane.TYPE_WALL: {
const _local_8 = geometry.getScreenPoint(new Vector3d(0, 0, 0)); const _local_8 = RoomPlane.PLANE_GEOMETRY.getScreenPoint(new Vector3d(0, 0, 0));
const _local_9 = geometry.getScreenPoint(new Vector3d(0, 0, (height / geometry.scale))); const _local_9 = RoomPlane.PLANE_GEOMETRY.getScreenPoint(new Vector3d(0, 0, (height / RoomPlane.PLANE_GEOMETRY.scale)));
const _local_10 = geometry.getScreenPoint(new Vector3d(0, (width / geometry.scale), 0)); const _local_10 = RoomPlane.PLANE_GEOMETRY.getScreenPoint(new Vector3d(0, (width / RoomPlane.PLANE_GEOMETRY.scale), 0));
if(_local_8 && _local_9 && _local_10) if(_local_8 && _local_9 && _local_10)
{ {
@ -281,14 +268,14 @@ export class RoomPlane implements IRoomPlane
break; break;
} }
case RoomPlane.TYPE_LANDSCAPE: { case RoomPlane.TYPE_LANDSCAPE: {
const _local_13 = geometry.getScreenPoint(new Vector3d(0, 0, 0)); const _local_13 = RoomPlane.PLANE_GEOMETRY.getScreenPoint(new Vector3d(0, 0, 0));
const _local_14 = geometry.getScreenPoint(new Vector3d(0, 0, 1)); const _local_14 = RoomPlane.PLANE_GEOMETRY.getScreenPoint(new Vector3d(0, 0, 1));
const _local_15 = geometry.getScreenPoint(new Vector3d(0, 1, 0)); const _local_15 = RoomPlane.PLANE_GEOMETRY.getScreenPoint(new Vector3d(0, 1, 0));
if(_local_13 && _local_14 && _local_15) if(_local_13 && _local_14 && _local_15)
{ {
width = Math.round(Math.abs((((_local_13.x - _local_15.x) * width) / 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) / 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))); 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; this._planeTexture = TextureUtils.createAndWriteRenderTexture(this._width, this._height, planeSprite, this.getMatrixForDimensions(width, height)) as Texture;
return true; return true;
@ -395,6 +384,183 @@ export class RoomPlane implements IRoomPlane
return matrix; 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 public get canBeVisible(): boolean
{ {
return this._canBeVisible; return this._canBeVisible;
@ -462,6 +628,11 @@ export class RoomPlane implements IRoomPlane
this._id = k; this._id = k;
} }
public set maskManager(k: PlaneMaskManager)
{
this._maskManager = k;
}
public get uniqueId(): number public get uniqueId(): number
{ {
return this._uniqueId; return this._uniqueId;

View File

@ -2,6 +2,9 @@ import { ToInt32, Vector3d } from '@nitrots/utils';
import { Rectangle } from 'pixi.js'; import { Rectangle } from 'pixi.js';
import { AlphaTolerance, IObjectVisualizationData, IPlaneVisualization, IRoomGeometry, IRoomObjectModel, IRoomObjectSprite, IRoomPlane, RoomObjectSpriteType, RoomObjectVariable } from '../../../../../api'; import { AlphaTolerance, IObjectVisualizationData, IPlaneVisualization, IRoomGeometry, IRoomObjectModel, IRoomObjectSprite, IRoomPlane, RoomObjectSpriteType, RoomObjectVariable } from '../../../../../api';
import { RoomMapData } from '../../RoomMapData'; import { RoomMapData } from '../../RoomMapData';
import { RoomMapMaskData } from '../../RoomMapMaskData';
import { RoomPlaneBitmapMaskData } from '../../RoomPlaneBitmapMaskData';
import { RoomPlaneBitmapMaskParser } from '../../RoomPlaneBitmapMaskParser';
import { RoomPlaneData } from '../../RoomPlaneData'; import { RoomPlaneData } from '../../RoomPlaneData';
import { RoomPlaneParser } from '../../RoomPlaneParser'; import { RoomPlaneParser } from '../../RoomPlaneParser';
import { RoomObjectSpriteVisualization } from '../RoomObjectSpriteVisualization'; import { RoomObjectSpriteVisualization } from '../RoomObjectSpriteVisualization';
@ -22,60 +25,39 @@ export class RoomVisualization extends RoomObjectSpriteVisualization implements
public static LANDSCAPE_COLOR_BOTTOM: number = 0x999999; public static LANDSCAPE_COLOR_BOTTOM: number = 0x999999;
private static ROOM_DEPTH_OFFSET: number = 1000; private static ROOM_DEPTH_OFFSET: number = 1000;
protected _data: RoomVisualizationData; protected _data: RoomVisualizationData = null;
private _roomPlaneParser: RoomPlaneParser; private _roomPlaneParser: RoomPlaneParser = new RoomPlaneParser();
private _roomPlaneBitmapMaskParser: RoomPlaneBitmapMaskParser = new RoomPlaneBitmapMaskParser();
private _geometryUpdateId: number; private _geometryUpdateId: number = -1;
private _boundingRectangle: Rectangle; private _boundingRectangle: Rectangle = null;
private _directionX: number; private _directionX: number = 0;
private _directionY: number; private _directionY: number = 0;
private _directionZ: number; private _directionZ: number = 0;
private _floorThickness: number; private _floorThickness: number = 1;
private _wallThickness: number; private _wallThickness: number = 1;
private _holeUpdateTime: number; private _holeUpdateTime: number = NaN;
private _planes: RoomPlane[]; private _planes: RoomPlane[] = [];
private _visiblePlanes: RoomPlane[]; private _visiblePlanes: RoomPlane[] = [];
private _visiblePlaneSpriteNumbers: number[]; private _visiblePlaneSpriteNumbers: number[] = [];
private _roomScale: number; private _roomScale: number = 0;
private _colorBackgroundOnly: boolean; private _colorBackgroundOnly: boolean = true;
private _redColor: number; private _color: number = 0xFFFFFF;
private _greenColor: number; private _redColor: number = 0xFFFFFF;
private _blueColor: number; private _greenColor: number = 0xFFFFFF;
private _blueColor: number = 0xFFFFFF;
private _wallType: string = null; private _wallType: string = null;
private _floorType: string = null; private _floorType: string = null;
private _landscapeType: string = null; private _landscapeType: string = null;
private _typeVisibility: boolean[]; private _typeVisibility: boolean[] = [];
private _assetUpdateCounter: number; private _assetUpdateCounter: number = 0;
private _isPlaneSet: boolean; private _maskData: RoomMapMaskData = null;
private _isPlaneSet: boolean = false;
constructor() constructor()
{ {
super(); 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_UNDEFINED] = false;
this._typeVisibility[RoomPlane.TYPE_FLOOR] = true; this._typeVisibility[RoomPlane.TYPE_FLOOR] = true;
this._typeVisibility[RoomPlane.TYPE_WALL] = true; this._typeVisibility[RoomPlane.TYPE_WALL] = true;
@ -112,8 +94,18 @@ export class RoomVisualization extends RoomObjectSpriteVisualization implements
this._roomPlaneParser = null; this._roomPlaneParser = null;
} }
if(this._roomPlaneBitmapMaskParser)
{
this._roomPlaneBitmapMaskParser.dispose();
this._roomPlaneBitmapMaskParser = null;
}
if(this._data) if(this._data)
{ {
this._data.clearCache();
this._data = null; this._data = null;
} }
} }
@ -122,6 +114,10 @@ export class RoomVisualization extends RoomObjectSpriteVisualization implements
{ {
super.reset(); super.reset();
this._floorType = null;
this._wallType = null;
this._landscapeType = null;
this._maskData = null;
this._geometryUpdateId = -1; this._geometryUpdateId = -1;
this._roomScale = 0; this._roomScale = 0;
} }
@ -139,12 +135,18 @@ export class RoomVisualization extends RoomObjectSpriteVisualization implements
if(this.updateHole(objectModel)) needsUpdate = true; if(this.updateHole(objectModel)) needsUpdate = true;
this.initializeRoomPlanes();
if(this.updateMasks(objectModel)) needsUpdate = true;
if(!needsUpdate) return; if(!needsUpdate) return;
this.initializeRoomPlanes(); if(this.updatePlaneTexturesAndVisibilities(objectModel)) needsUpdate = true;
this.updatePlaneTexturesAndVisibilities(objectModel);
this.updatePlanes(geometry, geometryUpdate, time);
if(this.updatePlanes(geometry, geometryUpdate, time)) needsUpdate = true;
if(needsUpdate)
{
let index = 0; let index = 0;
while(index < this._visiblePlanes.length) while(index < this._visiblePlanes.length)
@ -176,6 +178,7 @@ export class RoomVisualization extends RoomObjectSpriteVisualization implements
index++; index++;
} }
}
this.updateSpriteCounter++; this.updateSpriteCounter++;
@ -259,6 +262,47 @@ export class RoomVisualization extends RoomObjectSpriteVisualization implements
return (this.updatePlaneTypes(floorType, wallType, landscapeType) || this.updatePlaneVisibility(floorVisibility, wallVisibility, landscapeVisibility)); 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<RoomMapMaskData>(RoomObjectVariable.ROOM_PLANE_MASK_XML);
if(planeMask !== this._maskData)
{
this.updatePlaneMasks(planeMask);
this._maskData = planeMask;
didUpdate = true;
}
const backgroundColor = model.getValue<number>(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<boolean>(RoomObjectVariable.ROOM_COLORIZE_BG_ONLY) || false);
if(backgroundOnly !== this._colorBackgroundOnly)
{
this._colorBackgroundOnly = backgroundOnly;
didUpdate = true;
}
return didUpdate;
}
private clearPlanes(): void private clearPlanes(): void
{ {
if(this._planes) if(this._planes)
@ -349,7 +393,26 @@ export class RoomVisualization extends RoomObjectSpriteVisualization implements
landscapeOffsetX = (landscapeOffsetX + leftSide.length); 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 else
{ {
@ -603,6 +666,109 @@ export class RoomVisualization extends RoomObjectSpriteVisualization implements
return updated; 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 private updateSprite(sprite: IRoomObjectSprite, geometry: IRoomGeometry, plane: RoomPlane, _arg_3: string, relativeDepth: number): void
{ {
const offset = plane.offset; const offset = plane.offset;

View File

@ -1,6 +1,6 @@
import { IAssetPlaneMaskData, IAssetPlaneTextureBitmap, IGraphicAssetCollection, IVector3D } from '@nitrots/api'; import { IAssetPlaneMaskData, IAssetPlaneTextureBitmap, IGraphicAssetCollection, IVector3D } from '@nitrots/api';
import { TextureUtils } from '@nitrots/utils'; import { CutMaskFilter } from '@nitrots/utils';
import { Matrix, Point, Sprite, Texture } from 'pixi.js'; import { Container, Matrix, Point } from 'pixi.js';
import { PlaneMask } from './PlaneMask'; import { PlaneMask } from './PlaneMask';
import { PlaneMaskVisualization } from './PlaneMaskVisualization'; import { PlaneMaskVisualization } from './PlaneMaskVisualization';
@ -141,7 +141,7 @@ export class PlaneMaskManager
return graphicName; 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); const mask = this._masks.get(type);
@ -157,6 +157,14 @@ export class PlaneMaskManager
const point = new Point((posX + asset.offsetX), (posY + asset.offsetY)); 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(); const matrix = new Matrix();
let xScale = 1; let xScale = 1;
@ -185,7 +193,7 @@ export class PlaneMaskManager
matrix.scale(xScale, ySkew); matrix.scale(xScale, ySkew);
matrix.translate(tx, ty); matrix.translate(tx, ty);
TextureUtils.writeToTexture(new Sprite(texture), canvas, false, matrix); //TextureUtils.writeToTexture(new Sprite(texture), canvas, false, matrix);
return true; return true;
} }

View File

@ -70,14 +70,7 @@ export class ExtendedSprite extends Sprite
const index = (dx + dy * textureSource.width) * 4; const index = (dx + dy * textureSource.width) * 4;
const red = hitMap[index]; return (hitMap[index + 3] >= this.alphaTolerance);
const green = hitMap[index + 1];
const blue = hitMap[index + 2];
const alpha = hitMap[index + 3];
const result = (alpha >= this.alphaTolerance);
return result;
} }
private static generateHitMapForTextureSource(textureSource: TextureSource): boolean private static generateHitMapForTextureSource(textureSource: TextureSource): boolean

View File

@ -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);
}
}

View File

@ -0,0 +1 @@
export * from './CutMaskFilter';

View File

@ -24,4 +24,5 @@ export * from './PointMath';
export * from './RoomId'; export * from './RoomId';
export * from './TextureUtils'; export * from './TextureUtils';
export * from './Vector3d'; export * from './Vector3d';
export * from './filters';
export * from './motion'; export * from './motion';