You've already forked Nitro_Render_V3
mirror of
https://github.com/duckietm/Nitro_Render_V3.git
synced 2026-06-19 15:06:20 +00:00
799 lines
26 KiB
TypeScript
799 lines
26 KiB
TypeScript
import { AvatarAction, AvatarDirectionAngle, AvatarScaleType, AvatarSetType, IActiveActionData, IAnimationLayerData, IAvatarDataContainer, IAvatarEffectListener, IAvatarFigureContainer, IAvatarImage, IPartColor, ISpriteDataContainer } from '@nitrots/api';
|
|
import { GetRenderer, GetTexturePool, GetTickerTime, PaletteMapFilter, TextureUtils } from '@nitrots/utils';
|
|
import { ColorMatrixFilter, Container, RenderTexture, Sprite, Texture } from 'pixi.js';
|
|
import { AvatarFigureContainer } from './AvatarFigureContainer';
|
|
import { AvatarStructure } from './AvatarStructure';
|
|
import { EffectAssetDownloadManager } from './EffectAssetDownloadManager';
|
|
import { ActiveActionData } from './actions';
|
|
import { AssetAliasCollection } from './alias';
|
|
import { AvatarImageCache } from './cache';
|
|
import { AvatarCanvas } from './structure';
|
|
|
|
export class AvatarImage implements IAvatarImage, IAvatarEffectListener
|
|
{
|
|
private static CHANNELS_EQUAL: string = 'CHANNELS_EQUAL';
|
|
private static CHANNELS_UNIQUE: string = 'CHANNELS_UNIQUE';
|
|
private static CHANNELS_RED: string = 'CHANNELS_RED';
|
|
private static CHANNELS_GREEN: string = 'CHANNELS_GREEN';
|
|
private static CHANNELS_BLUE: string = 'CHANNELS_BLUE';
|
|
private static CHANNELS_DESATURATED: string = 'CHANNELS_DESATURATED';
|
|
private static DEFAULT_ACTION: string = 'Default';
|
|
private static DEFAULT_DIRECTION: number = 2;
|
|
private static DEFAULT_AVATAR_SET: string = AvatarSetType.FULL;
|
|
|
|
protected _mainDirection: number;
|
|
protected _headDirection: number;
|
|
protected _mainAction: IActiveActionData;
|
|
protected _disposed: boolean = false;
|
|
protected _canvasOffsets: number[] = [];
|
|
protected _cache: AvatarImageCache;
|
|
protected _avatarSpriteData: IAvatarDataContainer;
|
|
protected _actions: ActiveActionData[] = [];
|
|
protected _activeTexture: Texture = null;
|
|
|
|
private _defaultAction: IActiveActionData = null;
|
|
private _frameCounter: number = 0;
|
|
private _directionOffset: number = 0;
|
|
private _changes: boolean = true;
|
|
private _sprites: ISpriteDataContainer[];
|
|
private _isAnimating: boolean = false;
|
|
private _animationHasResetOnToggle: boolean = false;
|
|
private _actionsSorted: boolean = false;
|
|
private _sortedActions: IActiveActionData[];
|
|
private _lastActionsString: string = null;
|
|
private _currentActionsString: string = null;
|
|
private _effectIdInUse: number = -1;
|
|
private _animationFrameCount: number = -1;
|
|
private _cachedBodyParts: string[] = [];
|
|
private _cachedBodyPartsDirection: number = -1;
|
|
private _cachedBodyPartsGeometryType: string = null;
|
|
private _cachedBodyPartsAvatarSet: string = null;
|
|
|
|
constructor(
|
|
private _structure: AvatarStructure,
|
|
private _assets: AssetAliasCollection,
|
|
private _figure: AvatarFigureContainer,
|
|
private _scale: string,
|
|
private _effectManager: EffectAssetDownloadManager,
|
|
private _effectListener: IAvatarEffectListener = null)
|
|
{
|
|
if(!this._figure) this._figure = new AvatarFigureContainer('hr-893-45.hd-180-2.ch-210-66.lg-270-82.sh-300-91.wa-2007-.ri-1-');
|
|
if(!this._scale) this._scale = AvatarScaleType.LARGE;
|
|
|
|
this._cache = new AvatarImageCache(this._structure, this, this._assets, this._scale);
|
|
this.setDirection(AvatarImage.DEFAULT_AVATAR_SET, AvatarImage.DEFAULT_DIRECTION);
|
|
this._defaultAction = new ActiveActionData(AvatarAction.POSTURE_STAND);
|
|
this._defaultAction.definition = this._structure.getActionDefinition(AvatarImage.DEFAULT_ACTION);
|
|
this.resetActions();
|
|
this._animationFrameCount = 0;
|
|
}
|
|
|
|
public dispose(): void
|
|
{
|
|
if(this._disposed) return;
|
|
|
|
this._structure = null;
|
|
this._assets = null;
|
|
this._mainAction = null;
|
|
this._figure = null;
|
|
this._avatarSpriteData = null;
|
|
this._actions = null;
|
|
|
|
if(this._activeTexture)
|
|
{
|
|
GetTexturePool().putTexture(this._activeTexture);
|
|
|
|
this._activeTexture = null;
|
|
}
|
|
|
|
if(this._cache)
|
|
{
|
|
this._cache.dispose();
|
|
this._cache = null;
|
|
}
|
|
|
|
this._canvasOffsets = null;
|
|
this._disposed = true;
|
|
}
|
|
|
|
public get disposed(): boolean
|
|
{
|
|
return this._disposed;
|
|
}
|
|
|
|
public getFigure(): IAvatarFigureContainer
|
|
{
|
|
return this._figure;
|
|
}
|
|
|
|
public getScale(): string
|
|
{
|
|
return this._scale;
|
|
}
|
|
|
|
public getPartColor(k: string): IPartColor
|
|
{
|
|
return this._structure.getPartColor(this._figure, k);
|
|
}
|
|
|
|
public setDirection(avatarPart: string, direction: number): void
|
|
{
|
|
direction += this._directionOffset;
|
|
|
|
if(direction < AvatarDirectionAngle.MIN_DIRECTION)
|
|
{
|
|
direction = AvatarDirectionAngle.MAX_DIRECTION + (direction + 1);
|
|
}
|
|
else if(direction > AvatarDirectionAngle.MAX_DIRECTION)
|
|
{
|
|
direction -= (AvatarDirectionAngle.MAX_DIRECTION + 1);
|
|
}
|
|
|
|
if(this._structure.isMainAvatarSet(avatarPart)) this._mainDirection = direction;
|
|
|
|
// Special handling for head direction, including prevention checks for turning
|
|
if(avatarPart === AvatarSetType.HEAD || avatarPart === AvatarSetType.FULL)
|
|
{
|
|
if(avatarPart === AvatarSetType.HEAD && this.isHeadTurnPreventedByAction()) direction = this._mainDirection;
|
|
|
|
this._headDirection = direction;
|
|
}
|
|
|
|
this._cache.setDirection(avatarPart, direction);
|
|
this._changes = true;
|
|
}
|
|
|
|
public setDirectionAngle(k: string, _arg_2: number): void
|
|
{
|
|
this.setDirection(k, Math.floor(_arg_2 / 45));
|
|
}
|
|
|
|
public getSprites(): ISpriteDataContainer[]
|
|
{
|
|
return this._sprites;
|
|
}
|
|
|
|
public getCanvasOffsets(): number[]
|
|
{
|
|
return this._canvasOffsets;
|
|
}
|
|
|
|
public getMainAction(): IActiveActionData
|
|
{
|
|
return this._mainAction;
|
|
}
|
|
|
|
public getLayerData(k: ISpriteDataContainer): IAnimationLayerData
|
|
{
|
|
return this._structure.getBodyPartData(k.animation.id, this._frameCounter, k.id);
|
|
}
|
|
|
|
public updateAnimationByFrames(k: number = 1): void
|
|
{
|
|
this._frameCounter += k;
|
|
this._changes = true;
|
|
}
|
|
|
|
public resetAnimationFrameCounter(): void
|
|
{
|
|
this._frameCounter = 0;
|
|
this._changes = true;
|
|
}
|
|
|
|
private getBodyParts(avatarSet: string, geometryType: string, direction: number): string[]
|
|
{
|
|
const shouldUpdateCache = direction !== this._cachedBodyPartsDirection || geometryType !== this._cachedBodyPartsGeometryType || avatarSet !== this._cachedBodyPartsAvatarSet;
|
|
|
|
if(shouldUpdateCache)
|
|
{
|
|
this._cachedBodyPartsDirection = direction;
|
|
this._cachedBodyPartsGeometryType = geometryType;
|
|
this._cachedBodyPartsAvatarSet = avatarSet;
|
|
|
|
this._cachedBodyParts = this._structure.getBodyParts(avatarSet, geometryType, direction);
|
|
}
|
|
|
|
return this._cachedBodyParts;
|
|
}
|
|
|
|
private buildAvatarContainer(avatarCanvas: AvatarCanvas, setType: string): Container
|
|
{
|
|
const bodyParts = this.getBodyParts(setType, this._mainAction.definition.geometryType, this._mainDirection);
|
|
const container = new Container();
|
|
|
|
let partCount = (bodyParts.length - 1);
|
|
|
|
while(partCount >= 0)
|
|
{
|
|
const set = bodyParts[partCount];
|
|
const part = this._cache.getImageContainer(set, this._frameCounter);
|
|
|
|
if(part)
|
|
{
|
|
const partCacheContainer = part.image;
|
|
|
|
if(partCacheContainer)
|
|
{
|
|
const partContainer = new Container();
|
|
|
|
partContainer.addChild(partCacheContainer);
|
|
|
|
const point = part.regPoint.clone();
|
|
|
|
point.x += avatarCanvas.offset.x;
|
|
point.y += avatarCanvas.offset.y;
|
|
|
|
point.x += avatarCanvas.regPoint.x;
|
|
point.y += avatarCanvas.regPoint.y;
|
|
|
|
partContainer.x = Math.floor(point.x);
|
|
partContainer.y = Math.floor(point.y);
|
|
|
|
container.addChild(partContainer);
|
|
}
|
|
}
|
|
|
|
partCount--;
|
|
}
|
|
|
|
container.filters = [];
|
|
|
|
if(this._avatarSpriteData)
|
|
{
|
|
if(this._avatarSpriteData.colorTransform)
|
|
{
|
|
if(container.filters === undefined || container.filters === null) container.filters = [ this._avatarSpriteData.colorTransform ];
|
|
else if(Array.isArray(container.filters)) container.filters = [ ...container.filters, this._avatarSpriteData.colorTransform ];
|
|
else container.filters = [ container.filters, this._avatarSpriteData.colorTransform ];
|
|
}
|
|
|
|
if(this._avatarSpriteData.paletteIsGrayscale)
|
|
{
|
|
this.convertToGrayscale(container);
|
|
|
|
const paletteMapFilter = new PaletteMapFilter({
|
|
palette: this._avatarSpriteData.reds,
|
|
channel: PaletteMapFilter.CHANNEL_RED
|
|
});
|
|
|
|
if(container.filters === undefined || container.filters === null) container.filters = [ paletteMapFilter ];
|
|
else if(Array.isArray(container.filters)) container.filters = [ ...container.filters, paletteMapFilter ];
|
|
else container.filters = [ container.filters, paletteMapFilter ];
|
|
}
|
|
}
|
|
|
|
return container;
|
|
}
|
|
|
|
public processAsTexture(setType: string, hightlight: boolean): Texture
|
|
{
|
|
if(!this._changes) return this._activeTexture;
|
|
|
|
if(!this._mainAction) return null;
|
|
|
|
if(!this._actionsSorted) this.endActionAppends();
|
|
|
|
const avatarCanvas = this._structure.getCanvas(this._scale, this._mainAction.definition.geometryType);
|
|
|
|
if(!avatarCanvas) return null;
|
|
|
|
if(this._activeTexture && ((this._activeTexture.width !== avatarCanvas.width) || (this._activeTexture.height !== avatarCanvas.height)))
|
|
{
|
|
GetTexturePool().putTexture(this._activeTexture);
|
|
|
|
this._activeTexture = null;
|
|
}
|
|
|
|
if(!this._activeTexture) this._activeTexture = GetTexturePool().getTexture(avatarCanvas.width, avatarCanvas.height);
|
|
|
|
if(!this._activeTexture) return null;
|
|
|
|
const container = this.buildAvatarContainer(avatarCanvas, setType);
|
|
|
|
if(!container) return null;
|
|
|
|
GetRenderer().render({
|
|
target: this._activeTexture,
|
|
container: container,
|
|
clear: true
|
|
});
|
|
|
|
for(const child of container.children)
|
|
{
|
|
child.removeChildren();
|
|
}
|
|
|
|
container.destroy({ children: true });
|
|
|
|
//@ts-ignore
|
|
this._activeTexture.source.hitMap = null;
|
|
|
|
this._changes = false;
|
|
|
|
return this._activeTexture;
|
|
}
|
|
|
|
public processAsImageUrl(setType: string, scale: number = 1): string
|
|
{
|
|
const texture = this.processAsTexture(setType, false);
|
|
const canvas = GetRenderer().texture.generateCanvas(texture);
|
|
|
|
const url = canvas.toDataURL('image/png');
|
|
|
|
canvas.width = 0;
|
|
canvas.height = 0;
|
|
|
|
return url;
|
|
}
|
|
|
|
public processAsContainer(setType: string): Container
|
|
{
|
|
if(!this._mainAction) return null;
|
|
|
|
if(!this._actionsSorted) this.endActionAppends();
|
|
|
|
const avatarCanvas = this._structure.getCanvas(this._scale, this._mainAction.definition.geometryType);
|
|
|
|
if(!avatarCanvas) return null;
|
|
|
|
return this.buildAvatarContainer(avatarCanvas, setType);
|
|
}
|
|
|
|
// TODO this needs to be added still
|
|
public applyPalette(texture: RenderTexture, reds: number[] = [], greens: number[] = [], blues: number[] = []): RenderTexture
|
|
{
|
|
const textureCanvas = TextureUtils.generateCanvas(texture);
|
|
const textureCtx = textureCanvas.getContext('2d');
|
|
const textureImageData = textureCtx.getImageData(0, 0, textureCanvas.width, textureCanvas.height);
|
|
const data = textureImageData.data;
|
|
|
|
for(let i = 0; i < data.length; i += 4)
|
|
{
|
|
if(reds.length == 256)
|
|
{
|
|
let paletteColor = reds[data[i]];
|
|
if(paletteColor === undefined) paletteColor = 0;
|
|
|
|
data[i] = ((paletteColor >> 16) & 0xFF);
|
|
data[i + 1] = ((paletteColor >> 8) & 0xFF);
|
|
data[i + 2] = (paletteColor & 0xFF);
|
|
}
|
|
|
|
if(greens.length == 256)
|
|
{
|
|
let paletteColor = greens[data[i + 1]];
|
|
if(paletteColor === undefined) paletteColor = 0;
|
|
|
|
data[i] = ((paletteColor >> 16) & 0xFF);
|
|
data[i + 1] = ((paletteColor >> 8) & 0xFF);
|
|
data[i + 2] = (paletteColor & 0xFF);
|
|
}
|
|
if(blues.length == 256)
|
|
{
|
|
let paletteColor = greens[data[i + 2]];
|
|
if(paletteColor === undefined) paletteColor = 0;
|
|
|
|
data[i] = ((paletteColor >> 16) & 0xFF);
|
|
data[i + 1] = ((paletteColor >> 8) & 0xFF);
|
|
data[i + 2] = (paletteColor & 0xFF);
|
|
}
|
|
}
|
|
|
|
textureCtx.putImageData(textureImageData, 0, 0);
|
|
|
|
const newTexture = new Sprite(Texture.from(textureCanvas));
|
|
|
|
TextureUtils.writeToTexture(newTexture, texture, true);
|
|
|
|
return texture;
|
|
}
|
|
|
|
|
|
public getAsset(name: string): IGraphicAsset
|
|
{
|
|
return this._assets.getAsset(name);
|
|
}
|
|
|
|
public getDirection(): number
|
|
{
|
|
return this._mainDirection;
|
|
}
|
|
|
|
public getDirectionOffset(): number
|
|
{
|
|
return this._directionOffset;
|
|
}
|
|
|
|
public initActionAppends(): void
|
|
{
|
|
this._actions = [];
|
|
this._actionsSorted = false;
|
|
this._currentActionsString = '';
|
|
}
|
|
|
|
public endActionAppends(): void
|
|
{
|
|
if(!this.sortActions()) return;
|
|
|
|
for(const k of this._sortedActions)
|
|
{
|
|
if(k.actionType === AvatarAction.EFFECT)
|
|
{
|
|
if(!this._effectManager.isAvatarEffectReady(parseInt(k.actionParameter))) this._effectManager.downloadAvatarEffect(parseInt(k.actionParameter), this);
|
|
}
|
|
}
|
|
|
|
this.resetActions();
|
|
this.setActionsToParts();
|
|
}
|
|
|
|
public appendAction(k: string, ..._args: any[]): boolean
|
|
{
|
|
let _local_3 = '';
|
|
|
|
this._actionsSorted = false;
|
|
|
|
if(_args && (_args.length > 0)) _local_3 = _args[0];
|
|
|
|
if((_local_3 !== undefined) && (_local_3 !== null)) _local_3 = _local_3.toString();
|
|
|
|
switch(k)
|
|
{
|
|
case AvatarAction.POSTURE:
|
|
switch(_local_3)
|
|
{
|
|
case AvatarAction.POSTURE_LAY:
|
|
case AvatarAction.POSTURE_WALK:
|
|
case AvatarAction.POSTURE_STAND:
|
|
case AvatarAction.POSTURE_SWIM:
|
|
case AvatarAction.POSTURE_FLOAT:
|
|
case AvatarAction.POSTURE_SIT:
|
|
case AvatarAction.SNOWWAR_RUN:
|
|
case AvatarAction.SNOWWAR_DIE_FRONT:
|
|
case AvatarAction.SNOWWAR_DIE_BACK:
|
|
case AvatarAction.SNOWWAR_PICK:
|
|
case AvatarAction.SNOWWAR_THROW:
|
|
if((_local_3 === AvatarAction.POSTURE_LAY) || (_local_3 === AvatarAction.POSTURE_LAY) || (_local_3 === AvatarAction.POSTURE_LAY))
|
|
{
|
|
if(_local_3 === AvatarAction.POSTURE_LAY)
|
|
{
|
|
if(this._mainDirection == 0)
|
|
{
|
|
this.setDirection(AvatarSetType.FULL, 4);
|
|
}
|
|
else
|
|
{
|
|
this.setDirection(AvatarSetType.FULL, 2);
|
|
}
|
|
}
|
|
}
|
|
|
|
this.addActionData(_local_3);
|
|
break;
|
|
}
|
|
break;
|
|
case AvatarAction.GESTURE:
|
|
switch(_local_3)
|
|
{
|
|
case AvatarAction.GESTURE_AGGRAVATED:
|
|
case AvatarAction.GESTURE_SAD:
|
|
case AvatarAction.GESTURE_SMILE:
|
|
case AvatarAction.GESTURE_SURPRISED:
|
|
this.addActionData(_local_3);
|
|
break;
|
|
}
|
|
break;
|
|
case AvatarAction.EFFECT:
|
|
case AvatarAction.DANCE:
|
|
case AvatarAction.TALK:
|
|
case AvatarAction.EXPRESSION_WAVE:
|
|
case AvatarAction.SLEEP:
|
|
case AvatarAction.BLINK:
|
|
case AvatarAction.SIGN:
|
|
case AvatarAction.EXPRESSION_RESPECT:
|
|
case AvatarAction.EXPRESSION_BLOW_A_KISS:
|
|
case AvatarAction.EXPRESSION_LAUGH:
|
|
case AvatarAction.EXPRESSION_CRY:
|
|
case AvatarAction.EXPRESSION_IDLE:
|
|
case AvatarAction.EXPRESSION_SNOWBOARD_OLLIE:
|
|
case AvatarAction.EXPRESSION_SNOWBORD_360:
|
|
case AvatarAction.EXPRESSION_RIDE_JUMP:
|
|
if(_local_3 === AvatarAction.EFFECT)
|
|
{
|
|
if((((((_local_3 === '33') || (_local_3 === '34')) || (_local_3 === '35')) || (_local_3 === '36')) || (_local_3 === '38')) || (_local_3 === '39'))
|
|
{
|
|
//
|
|
}
|
|
}
|
|
|
|
this.addActionData(k, _local_3);
|
|
break;
|
|
case AvatarAction.CARRY_OBJECT:
|
|
case AvatarAction.USE_OBJECT: {
|
|
const _local_4 = this._structure.getActionDefinitionWithState(k);
|
|
if(_local_4) _local_3 = _local_4.getParameterValue(_local_3);
|
|
this.addActionData(k, _local_3);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
protected addActionData(actionType: string, actionParameter: string = ''): void
|
|
{
|
|
if(!this._actions) this._actions = [];
|
|
|
|
const actionExists = this._actions.some(action =>
|
|
action.actionType === actionType && action.actionParameter === actionParameter
|
|
);
|
|
|
|
if(!actionExists) this._actions.push(new ActiveActionData(actionType, actionParameter, this._frameCounter));
|
|
}
|
|
|
|
public isAnimating(): boolean
|
|
{
|
|
return (this._isAnimating) || (this._animationFrameCount > 1);
|
|
}
|
|
|
|
private resetActions(): boolean
|
|
{
|
|
this._animationHasResetOnToggle = false;
|
|
this._isAnimating = false;
|
|
this._sprites = [];
|
|
this._avatarSpriteData = null;
|
|
this._directionOffset = 0;
|
|
this._structure.removeDynamicItems(this);
|
|
this._mainAction = this._defaultAction;
|
|
this._mainAction.definition = this._defaultAction.definition;
|
|
this.resetBodyPartCache(this._defaultAction);
|
|
return true;
|
|
}
|
|
|
|
private isHeadTurnPreventedByAction(): boolean
|
|
{
|
|
if(!this._sortedActions) return false;
|
|
|
|
for(const action of this._sortedActions)
|
|
{
|
|
const actionDefinition = this._structure.getActionDefinitionWithState(action.actionType);
|
|
|
|
if(actionDefinition != null && actionDefinition.getPreventHeadTurn(action.actionParameter)) return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private sortActions(): boolean
|
|
{
|
|
let hasChanges = false;
|
|
let hasEffectAction = false;
|
|
let effectChanged = false;
|
|
|
|
this._currentActionsString = '';
|
|
this._sortedActions = this._structure.sortActions(this._actions);
|
|
this._animationFrameCount = this._structure.maxFrames(this._sortedActions);
|
|
|
|
if(!this._sortedActions)
|
|
{
|
|
this._canvasOffsets = [0, 0, 0];
|
|
|
|
if(this._lastActionsString !== '')
|
|
{
|
|
hasChanges = true;
|
|
|
|
this._lastActionsString = '';
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this._canvasOffsets = this._structure.getCanvasOffsets(this._sortedActions, this._scale, this._mainDirection);
|
|
|
|
for(const action of this._sortedActions)
|
|
{
|
|
this._currentActionsString += action.actionType + action.actionParameter;
|
|
|
|
if(action.actionType === AvatarAction.EFFECT)
|
|
{
|
|
const effectId = parseInt(action.actionParameter);
|
|
|
|
if(this._effectIdInUse !== effectId) effectChanged = true;
|
|
|
|
this._effectIdInUse = effectId;
|
|
|
|
hasEffectAction = true;
|
|
}
|
|
}
|
|
|
|
if(!hasEffectAction)
|
|
{
|
|
if(this._effectIdInUse > -1) effectChanged = true;
|
|
|
|
this._effectIdInUse = -1;
|
|
}
|
|
|
|
if(effectChanged) this._cache.disposeInactiveActions(0);
|
|
|
|
if(this._lastActionsString != this._currentActionsString)
|
|
{
|
|
hasChanges = true;
|
|
|
|
this._lastActionsString = this._currentActionsString;
|
|
}
|
|
}
|
|
|
|
this._actionsSorted = true;
|
|
|
|
return hasChanges;
|
|
}
|
|
|
|
private setActionsToParts(): void
|
|
{
|
|
if(!this._sortedActions) return;
|
|
|
|
const currentTime = GetTickerTime();
|
|
const actionTypes: string[] = [];
|
|
|
|
for(const action of this._sortedActions) actionTypes.push(action.actionType);
|
|
|
|
for(const action of this._sortedActions)
|
|
{
|
|
if(action && action.definition && action.definition.isAnimation)
|
|
{
|
|
const animation = this._structure.getAnimation(`${action.definition.state}.${action.actionParameter}`);
|
|
|
|
if(animation && animation.hasOverriddenActions())
|
|
{
|
|
const overriddenActionNames = animation.overriddenActionNames();
|
|
|
|
if(overriddenActionNames)
|
|
{
|
|
for(const overriddenActionName of overriddenActionNames)
|
|
{
|
|
if(actionTypes.includes(overriddenActionName)) action.overridingAction = animation.overridingAction(overriddenActionName);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(animation && animation.resetOnToggle) this._animationHasResetOnToggle = true;
|
|
}
|
|
}
|
|
|
|
for(const action of this._sortedActions)
|
|
{
|
|
if(action && action.definition)
|
|
{
|
|
if(action.definition.isAnimation && action.actionParameter === '') action.actionParameter = '1';
|
|
|
|
this.setActionToParts(action, currentTime);
|
|
|
|
if(action.definition.isAnimation)
|
|
{
|
|
this._isAnimating = action.definition.isAnimated(action.actionParameter);
|
|
|
|
const animation = this._structure.getAnimation(`${action.definition.state}.${action.actionParameter}`);
|
|
|
|
if(animation)
|
|
{
|
|
this._sprites = [...this._sprites, ...animation.spriteData];
|
|
|
|
if(animation.hasDirectionData()) this._directionOffset = animation.directionData.offset;
|
|
|
|
if(animation.hasAvatarData()) this._avatarSpriteData = animation.avatarData;
|
|
|
|
if(!this._isAnimating && (animation.spriteData?.length > 0 || animation.hasAvatarData()))
|
|
{
|
|
this._isAnimating = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private setActionToParts(action: IActiveActionData, currentTime: number): void
|
|
{
|
|
if(!action || !action.definition || action.definition.assetPartDefinition === '') return;
|
|
|
|
if(action.definition.isMain)
|
|
{
|
|
this._mainAction = action;
|
|
this._cache.setGeometryType(action.definition.geometryType);
|
|
}
|
|
|
|
this._cache.setAction(action, currentTime);
|
|
|
|
this._changes = true;
|
|
}
|
|
|
|
private resetBodyPartCache(action: IActiveActionData): void
|
|
{
|
|
if(!action || action.definition.assetPartDefinition === '') return;
|
|
|
|
if(action.definition.isMain)
|
|
{
|
|
this._mainAction = action;
|
|
this._cache.setGeometryType(action.definition.geometryType);
|
|
}
|
|
|
|
this._cache.resetBodyPartCache(action);
|
|
|
|
this._changes = true;
|
|
}
|
|
|
|
private convertToGrayscale(container: Container, channel: string = 'CHANNELS_EQUAL'): Container
|
|
{
|
|
let redWeight = 0.33;
|
|
let greenWeight = 0.33;
|
|
let blueWeight = 0.33;
|
|
|
|
switch(channel)
|
|
{
|
|
case AvatarImage.CHANNELS_UNIQUE:
|
|
redWeight = 0.3;
|
|
greenWeight = 0.59;
|
|
blueWeight = 0.11;
|
|
break;
|
|
case AvatarImage.CHANNELS_RED:
|
|
redWeight = 1;
|
|
greenWeight = 0;
|
|
blueWeight = 0;
|
|
break;
|
|
case AvatarImage.CHANNELS_GREEN:
|
|
redWeight = 0;
|
|
greenWeight = 1;
|
|
blueWeight = 0;
|
|
break;
|
|
case AvatarImage.CHANNELS_BLUE:
|
|
redWeight = 0;
|
|
greenWeight = 0;
|
|
blueWeight = 1;
|
|
break;
|
|
case AvatarImage.CHANNELS_DESATURATED:
|
|
redWeight = 0.3086;
|
|
greenWeight = 0.6094;
|
|
blueWeight = 0.082;
|
|
break;
|
|
}
|
|
|
|
const filter = new ColorMatrixFilter();
|
|
|
|
filter.matrix = [
|
|
redWeight, greenWeight, blueWeight, 0, 0, // Red channel
|
|
redWeight, greenWeight, blueWeight, 0, 0, // Green channel
|
|
redWeight, greenWeight, blueWeight, 0, 0, // Blue channel
|
|
0, 0, 0, 1, 0 // Alpha channel
|
|
];
|
|
|
|
if(container.filters === undefined || container.filters === null) container.filters = [ filter ];
|
|
else if(Array.isArray(container.filters)) container.filters = [ ...container.filters, filter ];
|
|
else container.filters = [ container.filters, filter ];
|
|
|
|
return container;
|
|
}
|
|
|
|
public isPlaceholder(): boolean
|
|
{
|
|
return false;
|
|
}
|
|
|
|
public get animationHasResetOnToggle(): boolean
|
|
{
|
|
return this._animationHasResetOnToggle;
|
|
}
|
|
|
|
public resetEffect(effect: number): void
|
|
{
|
|
if(effect === this._effectIdInUse)
|
|
{
|
|
this.resetActions();
|
|
this.setActionsToParts();
|
|
|
|
this._animationHasResetOnToggle = true;
|
|
this._changes = true;
|
|
|
|
if(this._effectListener) this._effectListener.resetEffect(effect);
|
|
}
|
|
}
|
|
}
|