589 lines
17 KiB
TypeScript
589 lines
17 KiB
TypeScript
import { AlphaTolerance, IGraphicAsset, IObjectVisualizationData, IRoomGeometry, IRoomObjectSprite, RoomObjectVariable, RoomObjectVisualizationType } from '../../../../../api';
|
|
import { RoomObjectSpriteVisualization } from '../../../../../room';
|
|
import { ColorData, LayerData } from '../data';
|
|
import { FurnitureVisualizationData } from './FurnitureVisualizationData';
|
|
|
|
export class FurnitureVisualization extends RoomObjectSpriteVisualization
|
|
{
|
|
protected static DEPTH_MULTIPLIER: number = Math.sqrt(0.5);
|
|
|
|
public static TYPE: string = RoomObjectVisualizationType.FURNITURE_STATIC;
|
|
|
|
protected _data: FurnitureVisualizationData;
|
|
|
|
protected _type: string;
|
|
protected _direction: number;
|
|
protected _lastCameraAngle: number;
|
|
protected _selectedColor: number;
|
|
protected _furnitureLift: number;
|
|
protected _alphaMultiplier: number;
|
|
protected _alphaChanged: boolean;
|
|
protected _clickUrl: string;
|
|
protected _clickHandling: boolean;
|
|
|
|
protected _cacheDirection: number;
|
|
protected _cacheScale: number;
|
|
protected _cacheSize: number;
|
|
|
|
protected _layerCount: number;
|
|
protected _shadowLayerIndex: number;
|
|
protected _updatedLayers: boolean[];
|
|
protected _assetNames: string[];
|
|
protected _spriteTags: string[];
|
|
protected _spriteInks: number[];
|
|
protected _spriteAlphas: number[];
|
|
protected _spriteColors: number[];
|
|
protected _spriteMouseCaptures: boolean[];
|
|
protected _spriteXOffsets: number[];
|
|
protected _spriteYOffsets: number[];
|
|
protected _spriteZOffsets: number[];
|
|
|
|
private _animationNumber: number;
|
|
|
|
constructor()
|
|
{
|
|
super();
|
|
|
|
this._data = null;
|
|
|
|
this._type = null;
|
|
this._direction = 0;
|
|
this._lastCameraAngle = NaN;
|
|
this._selectedColor = 0;
|
|
this._furnitureLift = 0;
|
|
this._alphaMultiplier = 1;
|
|
this._alphaChanged = false;
|
|
this._clickUrl = null;
|
|
this._clickHandling = false;
|
|
|
|
this._cacheDirection = -1;
|
|
this._cacheScale = 0;
|
|
this._cacheSize = -1;
|
|
|
|
this._layerCount = 0;
|
|
this._shadowLayerIndex = -1;
|
|
this._updatedLayers = [];
|
|
this._assetNames = [];
|
|
this._spriteTags = [];
|
|
this._spriteInks = [];
|
|
this._spriteAlphas = [];
|
|
this._spriteColors = [];
|
|
this._spriteMouseCaptures = [];
|
|
this._spriteXOffsets = [];
|
|
this._spriteYOffsets = [];
|
|
this._spriteZOffsets = [];
|
|
|
|
this._animationNumber = 0;
|
|
}
|
|
|
|
public initialize(data: IObjectVisualizationData): boolean
|
|
{
|
|
this.reset();
|
|
|
|
if(!(data instanceof FurnitureVisualizationData)) return false;
|
|
|
|
this._type = data.type;
|
|
this._data = data;
|
|
|
|
return true;
|
|
}
|
|
|
|
public dispose(): void
|
|
{
|
|
super.dispose();
|
|
|
|
this._data = null;
|
|
this._updatedLayers = null;
|
|
this._assetNames = null;
|
|
this._spriteTags = null;
|
|
this._spriteInks = null;
|
|
this._spriteAlphas = null;
|
|
this._spriteColors = null;
|
|
this._spriteMouseCaptures = null;
|
|
this._spriteXOffsets = null;
|
|
this._spriteYOffsets = null;
|
|
this._spriteZOffsets = null;
|
|
}
|
|
|
|
protected reset(): void
|
|
{
|
|
super.reset();
|
|
|
|
this.setDirection(-1);
|
|
|
|
this._data = null;
|
|
this._updatedLayers = [];
|
|
this._assetNames = [];
|
|
this._spriteTags = [];
|
|
this._spriteInks = [];
|
|
this._spriteAlphas = [];
|
|
this._spriteColors = [];
|
|
this._spriteMouseCaptures = [];
|
|
this._spriteXOffsets = [];
|
|
this._spriteYOffsets = [];
|
|
this._spriteZOffsets = [];
|
|
|
|
this.createSprites(0);
|
|
}
|
|
|
|
protected resetLayers(scale: number, direction: number): void
|
|
{
|
|
if((this._cacheDirection === direction) && (this._cacheScale === scale)) return;
|
|
|
|
this._updatedLayers = [];
|
|
this._assetNames = [];
|
|
this._spriteTags = [];
|
|
this._spriteInks = [];
|
|
this._spriteAlphas = [];
|
|
this._spriteColors = [];
|
|
this._spriteMouseCaptures = [];
|
|
this._spriteXOffsets = [];
|
|
this._spriteYOffsets = [];
|
|
this._spriteZOffsets = [];
|
|
|
|
this._cacheDirection = direction;
|
|
this._cacheScale = scale;
|
|
this._cacheSize = this.getValidSize(scale);
|
|
|
|
this.setLayerCount(((this._data && this._data.getLayerCount(scale)) || 0) + this.getAdditionalLayerCount());
|
|
}
|
|
|
|
public update(geometry: IRoomGeometry, time: number, update: boolean, skipUpdate: boolean): void
|
|
{
|
|
if(!geometry) return;
|
|
|
|
const scale = geometry.scale;
|
|
let updateSprites = false;
|
|
|
|
if(this.updateObject(scale, geometry.direction.x)) updateSprites = true;
|
|
|
|
if(this.updateModel(scale)) updateSprites = true;
|
|
|
|
let number = 0;
|
|
|
|
if(skipUpdate)
|
|
{
|
|
this._animationNumber = (this._animationNumber | this.updateAnimation(scale));
|
|
}
|
|
else
|
|
{
|
|
number = this.updateAnimation(scale) | this._animationNumber;
|
|
|
|
this._animationNumber = 0;
|
|
}
|
|
|
|
if(updateSprites || (number !== 0))
|
|
{
|
|
this.updateSprites(scale, updateSprites, number);
|
|
|
|
this._scale = scale;
|
|
|
|
this.updateSpriteCounter++;
|
|
}
|
|
}
|
|
|
|
protected updateObject(scale: number, direction: number): boolean
|
|
{
|
|
if(!this.object) return false;
|
|
|
|
if((this.updateObjectCounter === this.object.updateCounter) && (scale === this._scale) && (this._lastCameraAngle === direction)) return false;
|
|
|
|
let offsetDirection = (this.object.getDirection().x - (direction + 135));
|
|
|
|
offsetDirection = ((((offsetDirection) % 360) + 360) % 360);
|
|
|
|
if(this._data)
|
|
{
|
|
const validDirection = this._data.getValidDirection(scale, offsetDirection);
|
|
|
|
this.setDirection(validDirection);
|
|
}
|
|
|
|
this._lastCameraAngle = direction;
|
|
this._scale = scale;
|
|
|
|
this.updateObjectCounter = this.object.updateCounter;
|
|
|
|
this.resetLayers(scale, this._direction);
|
|
|
|
return true;
|
|
}
|
|
|
|
protected updateModel(scale: number): boolean
|
|
{
|
|
const model = this.object && this.object.model;
|
|
|
|
if(!model) return false;
|
|
|
|
if(this.updateModelCounter === model.updateCounter) return false;
|
|
|
|
this._selectedColor = model.getValue<number>(RoomObjectVariable.FURNITURE_COLOR);
|
|
this._clickUrl = model.getValue<string>(RoomObjectVariable.FURNITURE_AD_URL);
|
|
this._clickHandling = ((this._clickUrl && (this._clickUrl !== '') && (this._clickUrl.indexOf('http') === 0)) || false);
|
|
this._furnitureLift = (model.getValue<number>(RoomObjectVariable.FURNITURE_LIFT_AMOUNT) || 0);
|
|
|
|
let alphaMultiplier = model.getValue<number>(RoomObjectVariable.FURNITURE_ALPHA_MULTIPLIER);
|
|
|
|
if(isNaN(alphaMultiplier)) alphaMultiplier = 1;
|
|
|
|
if(this._alphaMultiplier !== alphaMultiplier)
|
|
{
|
|
this._alphaMultiplier = alphaMultiplier;
|
|
|
|
this._alphaChanged = true;
|
|
}
|
|
|
|
this.updateModelCounter = model.updateCounter;
|
|
|
|
return true;
|
|
}
|
|
|
|
protected updateSprites(scale: number, update: boolean, animation: number): void
|
|
{
|
|
if(this._layerCount !== this.totalSprites) this.createSprites(this._layerCount);
|
|
|
|
if(update)
|
|
{
|
|
let layerId = (this.totalSprites - 1);
|
|
|
|
while(layerId >= 0)
|
|
{
|
|
this.updateSprite(scale, layerId);
|
|
|
|
layerId--;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
let layerId = 0;
|
|
|
|
while(animation > 0)
|
|
{
|
|
if(animation) this.updateSprite(scale, layerId);
|
|
|
|
layerId++;
|
|
animation = (animation >> 1);
|
|
}
|
|
}
|
|
|
|
this._alphaChanged = false;
|
|
}
|
|
|
|
protected updateSprite(scale: number, layerId: number): void
|
|
{
|
|
const assetName = this.getSpriteAssetName(scale, layerId);
|
|
const sprite = this.getSprite(layerId);
|
|
|
|
if(assetName && sprite)
|
|
{
|
|
const assetData = this.getAsset(assetName, layerId);
|
|
|
|
if(assetData && assetData.texture)
|
|
{
|
|
sprite.visible = true;
|
|
sprite.type = this._type;
|
|
sprite.texture = assetData.texture;
|
|
sprite.flipH = assetData.flipH;
|
|
sprite.flipV = assetData.flipV;
|
|
sprite.direction = this._direction;
|
|
|
|
let relativeDepth = 0;
|
|
|
|
if(layerId !== this._shadowLayerIndex)
|
|
{
|
|
sprite.tag = this.getLayerTag(scale, this._direction, layerId);
|
|
sprite.alpha = this.getLayerAlpha(scale, this._direction, layerId);
|
|
sprite.color = this.getLayerColor(scale, layerId, this._selectedColor);
|
|
sprite.offsetX = (assetData.offsetX + this.getLayerXOffset(scale, this._direction, layerId));
|
|
sprite.offsetY = (assetData.offsetY + this.getLayerYOffset(scale, this._direction, layerId));
|
|
sprite.blendMode = this.getLayerInk(scale, this._direction, layerId);
|
|
sprite.alphaTolerance = (this.getLayerIgnoreMouse(scale, this._direction, layerId) ? AlphaTolerance.MATCH_NOTHING : AlphaTolerance.MATCH_OPAQUE_PIXELS);
|
|
|
|
relativeDepth = this.getLayerZOffset(scale, this._direction, layerId);
|
|
relativeDepth = (relativeDepth - (layerId * 0.001));
|
|
}
|
|
else
|
|
{
|
|
sprite.offsetX = assetData.offsetX;
|
|
sprite.offsetY = (assetData.offsetY + this.getLayerYOffset(scale, this._direction, layerId));
|
|
sprite.alpha = (48 * this._alphaMultiplier);
|
|
sprite.alphaTolerance = AlphaTolerance.MATCH_NOTHING;
|
|
|
|
relativeDepth = 1;
|
|
}
|
|
|
|
sprite.relativeDepth = (relativeDepth * FurnitureVisualization.DEPTH_MULTIPLIER);
|
|
sprite.name = assetName;
|
|
sprite.libraryAssetName = this.getLibraryAssetNameForSprite(assetData, sprite);
|
|
sprite.posture = this.getPostureForAsset(scale, assetData.source);
|
|
sprite.clickHandling = this._clickHandling;
|
|
}
|
|
else
|
|
{
|
|
this.resetSprite(sprite);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(sprite) this.resetSprite(sprite);
|
|
}
|
|
}
|
|
|
|
protected getLibraryAssetNameForSprite(asset: IGraphicAsset, sprite: IRoomObjectSprite): string
|
|
{
|
|
return asset.source;
|
|
}
|
|
|
|
protected getPostureForAssetFile(scale: number, _arg_2: string): string
|
|
{
|
|
return null;
|
|
}
|
|
|
|
private resetSprite(sprite: IRoomObjectSprite): void
|
|
{
|
|
if(!sprite) return;
|
|
|
|
sprite.texture = null;
|
|
sprite.libraryAssetName = '';
|
|
sprite.posture = '';
|
|
sprite.tag = '';
|
|
sprite.offsetX = 0;
|
|
sprite.offsetY = 0;
|
|
sprite.flipH = false;
|
|
sprite.flipV = false;
|
|
sprite.relativeDepth = 0;
|
|
sprite.clickHandling = false;
|
|
}
|
|
|
|
protected getSpriteAssetName(scale: number, layerId: number): string
|
|
{
|
|
if(!this._data || (layerId >= FurnitureVisualizationData.LAYER_LETTERS.length)) return '';
|
|
|
|
let assetName = this._assetNames[layerId];
|
|
let updated = this._updatedLayers[layerId];
|
|
|
|
if(!assetName || !assetName.length)
|
|
{
|
|
assetName = this.cacheSpriteAssetName(scale, layerId, true);
|
|
updated = (this._cacheSize !== 1);
|
|
}
|
|
|
|
if(updated) assetName += this.getFrameNumber(scale, layerId);
|
|
|
|
return assetName;
|
|
}
|
|
|
|
protected cacheSpriteAssetName(scale: number, layerId: number, cache: boolean): string
|
|
{
|
|
const type = this._type;
|
|
const size = (cache) ? this._cacheSize : this.getValidSize(scale);
|
|
let layerCode = '';
|
|
const isntIcon = (size !== 1);
|
|
|
|
if(layerId !== this._shadowLayerIndex)
|
|
{
|
|
layerCode = FurnitureVisualizationData.LAYER_LETTERS[layerId] || '';
|
|
}
|
|
else
|
|
{
|
|
layerCode = 'sd';
|
|
}
|
|
|
|
if(layerCode === '') return null;
|
|
|
|
const assetName = (this._type + ((isntIcon) ? ('_' + size + '_' + layerCode + '_' + this._direction + '_') : ('_icon_' + layerCode)));
|
|
|
|
if(cache)
|
|
{
|
|
this._assetNames[layerId] = assetName;
|
|
this._updatedLayers[layerId] = isntIcon;
|
|
}
|
|
|
|
return assetName;
|
|
}
|
|
|
|
protected getLayerTag(scale: number, direction: number, layerId: number): string
|
|
{
|
|
const existing = this._spriteTags[layerId];
|
|
|
|
if(existing !== undefined) return existing;
|
|
|
|
if(!this._data) return LayerData.DEFAULT_TAG;
|
|
|
|
const tag = this._data.getLayerTag(scale, direction, layerId);
|
|
|
|
this._spriteTags[layerId] = tag;
|
|
|
|
return tag;
|
|
}
|
|
|
|
protected getLayerInk(scale: number, direction: number, layerId: number): number
|
|
{
|
|
const existing = this._spriteInks[layerId];
|
|
|
|
if(existing !== undefined) return existing;
|
|
|
|
if(!this._data) return LayerData.DEFAULT_INK;
|
|
|
|
const ink = this._data.getLayerInk(scale, direction, layerId);
|
|
|
|
this._spriteInks[layerId] = ink;
|
|
|
|
return ink;
|
|
}
|
|
|
|
protected getLayerAlpha(scale: number, direction: number, layerId: number): number
|
|
{
|
|
if(!this._alphaChanged)
|
|
{
|
|
const existing = this._spriteAlphas[layerId];
|
|
|
|
if(existing !== undefined) return existing;
|
|
}
|
|
|
|
if(!this._data) return LayerData.DEFAULT_ALPHA;
|
|
|
|
let alpha = this._data.getLayerAlpha(scale, direction, layerId);
|
|
|
|
if(this._alphaMultiplier !== null) alpha = (alpha * this._alphaMultiplier);
|
|
|
|
this._spriteAlphas[layerId] = alpha;
|
|
|
|
return alpha;
|
|
}
|
|
|
|
protected getLayerColor(scale: number, layerId: number, colorId: number): number
|
|
{
|
|
const existing = this._spriteColors[layerId];
|
|
|
|
if(existing !== undefined) return existing;
|
|
|
|
if(!this._data) return ColorData.DEFAULT_COLOR;
|
|
|
|
const color = this._data.getLayerColor(scale, layerId, colorId);
|
|
|
|
this._spriteColors[layerId] = color;
|
|
|
|
return color;
|
|
}
|
|
|
|
protected getLayerIgnoreMouse(scale: number, direction: number, layerId: number): boolean
|
|
{
|
|
const existing = this._spriteMouseCaptures[layerId];
|
|
|
|
if(existing !== undefined) return existing;
|
|
|
|
if(!this._data) return LayerData.DEFAULT_IGNORE_MOUSE;
|
|
|
|
const ignoreMouse = this._data.getLayerIgnoreMouse(scale, direction, layerId);
|
|
|
|
this._spriteMouseCaptures[layerId] = ignoreMouse;
|
|
|
|
return ignoreMouse;
|
|
}
|
|
|
|
protected getLayerXOffset(scale: number, direction: number, layerId: number): number
|
|
{
|
|
const existing = this._spriteXOffsets[layerId];
|
|
|
|
if(existing !== undefined) return existing;
|
|
|
|
if(!this._data) return LayerData.DEFAULT_XOFFSET;
|
|
|
|
const xOffset = this._data.getLayerXOffset(scale, direction, layerId);
|
|
|
|
this._spriteXOffsets[layerId] = xOffset;
|
|
|
|
return xOffset;
|
|
}
|
|
|
|
protected getLayerYOffset(scale: number, direction: number, layerId: number): number
|
|
{
|
|
if(layerId === this._shadowLayerIndex) return Math.ceil((this._furnitureLift * (scale / 2)));
|
|
|
|
const existing = this._spriteYOffsets[layerId];
|
|
|
|
if(existing !== undefined) return existing;
|
|
|
|
if(!this._data) return LayerData.DEFAULT_YOFFSET;
|
|
|
|
const yOffset = this._data.getLayerYOffset(scale, direction, layerId);
|
|
|
|
this._spriteYOffsets[layerId] = yOffset;
|
|
|
|
return yOffset;
|
|
}
|
|
|
|
protected getLayerZOffset(scale: number, direction: number, layerId: number): number
|
|
{
|
|
const existing = this._spriteZOffsets[layerId];
|
|
|
|
if(existing !== undefined) return existing;
|
|
|
|
if(!this._data) return LayerData.DEFAULT_ZOFFSET;
|
|
|
|
const zOffset = this._data.getLayerZOffset(scale, direction, layerId);
|
|
|
|
this._spriteZOffsets[layerId] = zOffset;
|
|
|
|
return zOffset;
|
|
}
|
|
|
|
protected getValidSize(scale: number): number
|
|
{
|
|
if(!this._data) return scale;
|
|
|
|
return this._data.getValidSize(scale);
|
|
}
|
|
|
|
protected setLayerCount(count: number): void
|
|
{
|
|
this._layerCount = count;
|
|
this._shadowLayerIndex = count - this.getAdditionalLayerCount();
|
|
}
|
|
|
|
protected setDirection(direction: number): void
|
|
{
|
|
if(this._direction === direction) return;
|
|
|
|
this._direction = direction;
|
|
}
|
|
|
|
protected getAdditionalLayerCount(): number
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
protected updateAnimation(scale: number): number
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
protected getFrameNumber(scale: number, layerId: number): number
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
protected getPostureForAsset(scale: number, name: string): string
|
|
{
|
|
return null;
|
|
}
|
|
|
|
public getAsset(name: string, layerId: number = -1): IGraphicAsset
|
|
{
|
|
if(!this.asset) return null;
|
|
|
|
return this.asset.getAsset(name);
|
|
}
|
|
|
|
protected get direction(): number
|
|
{
|
|
return this._direction;
|
|
}
|
|
|
|
protected get data(): FurnitureVisualizationData
|
|
{
|
|
return this._data;
|
|
}
|
|
}
|