Start gif support

This commit is contained in:
Bill 2022-04-10 02:58:33 -04:00
parent 4b3f4b9548
commit 29c2ee2282
11 changed files with 559 additions and 249 deletions

View File

@ -1,4 +1,4 @@
import { Resource, Texture } from '@pixi/core'; import { BaseTexture, Resource, Texture } from '@pixi/core';
import { Loader, LoaderResource } from '@pixi/loaders'; import { Loader, LoaderResource } from '@pixi/loaders';
import { Spritesheet } from '@pixi/spritesheet'; import { Spritesheet } from '@pixi/spritesheet';
import { IGraphicAsset } from '../../room'; import { IGraphicAsset } from '../../room';
@ -94,158 +94,119 @@ export class AssetManager extends Disposable implements IAssetManager
return collection; return collection;
} }
public downloadAsset(assetUrl: string, cb: Function): boolean public downloadAsset(assetUrl: string, cb: (status: boolean) => void): void
{ {
return this.downloadAssets([ assetUrl ], cb); this.downloadAssets([ assetUrl ], cb);
} }
public downloadAssets(assetUrls: string[], cb: Function): boolean public downloadAssets(assetUrls: string[], cb: (status: boolean) => void): void
{ {
if(!assetUrls || !assetUrls.length) if(!assetUrls || !assetUrls.length)
{ {
cb(true); cb(true);
return true; return;
} }
const totalToDownload = assetUrls.length; const loader = new Loader();
let totalDownloaded = 0;
const onDownloaded = (loader: Loader, resource: LoaderResource, flag: boolean) =>
{
if(loader) loader.destroy();
if(!flag)
{
this._logger.error('Failed to download asset: ' + resource.url);
cb(false);
return;
}
totalDownloaded++;
if(totalDownloaded === totalToDownload) cb(true);
};
for(const url of assetUrls) for(const url of assetUrls)
{ {
if(!url) continue; if(!url) continue;
const loader = new Loader();
loader loader
.add({ .add({
url, url,
crossOrigin: 'anonymous', crossOrigin: 'anonymous',
xhrType: url.endsWith('.nitro') ? LoaderResource.XHR_RESPONSE_TYPE.BUFFER : LoaderResource.XHR_RESPONSE_TYPE.JSON xhrType: url.endsWith('.nitro') ? LoaderResource.XHR_RESPONSE_TYPE.BUFFER : LoaderResource.XHR_RESPONSE_TYPE.JSON
}) });
.use((resource: LoaderResource, next: Function) =>
{
this.assetLoader(loader, resource, onDownloaded);
next();
})
.load();
} }
return true; let remaining = assetUrls.length;
}
private assetLoader(loader: Loader, resource: LoaderResource, onDownloaded: Function): void const onDownloaded = (status: boolean, url: string) =>
{
if(!resource || resource.error)
{ {
if(resource && resource.texture) resource.texture.destroy(true); if(!status)
onDownloaded(loader, resource, false);
return;
}
if(resource.extension === 'nitro')
{
const nitroBundle = new NitroBundle(resource.data);
const assetData = (nitroBundle.jsonFile as IAssetData);
if(!assetData)
{ {
onDownloaded(loader, resource, false); this._logger.error('Failed to download asset: ' + url);
loader.destroy();
cb(false);
return; return;
} }
if(assetData.spritesheet && Object.keys(assetData.spritesheet).length) remaining--;
{
const baseTexture = nitroBundle.baseTexture;
if(!baseTexture) if(!remaining)
{
loader.destroy();
cb(true);
return;
}
};
loader.load((loader, resources) =>
{
for(const key in resources)
{
const resource = resources[key];
if(!resource || resource.error)
{ {
onDownloaded(loader, resource, false); onDownloaded(false, resource.url);
return; return;
} }
if(baseTexture.valid) if(resource.extension === 'nitro')
{ {
const spritesheet = new Spritesheet(baseTexture, assetData.spritesheet); const nitroBundle = new NitroBundle(resource.data);
spritesheet.parse(() => this.processAsset(nitroBundle.baseTexture, (nitroBundle.jsonFile as IAssetData), status =>
{ {
this.createCollection(assetData, spritesheet); onDownloaded(true, resource.url);
onDownloaded(loader, resource, true);
});
}
else
{
baseTexture.once('loaded', () =>
{
baseTexture.removeAllListeners();
const spritesheet = new Spritesheet(baseTexture, assetData.spritesheet);
spritesheet.parse(() =>
{
this.createCollection(assetData, spritesheet);
onDownloaded(loader, resource, true);
});
}); });
baseTexture.once('error', () => continue;
{
baseTexture.removeAllListeners();
onDownloaded(loader, resource, false);
});
} }
return; if(resource.type === LoaderResource.TYPE.IMAGE)
{
if(resource.texture) this.setTexture(resource.name, resource.texture);
onDownloaded(true, resource.url);
continue;
}
} }
});
}
this.createCollection(assetData, null); private processAsset(baseTexture: BaseTexture, data: IAssetData, onDownloaded: (status: boolean) => void): void
{
const spritesheetData = data.spritesheet;
onDownloaded(loader, resource, true); if(spritesheetData && Object.keys(spritesheetData).length)
}
else if(resource.type === LoaderResource.TYPE.IMAGE)
{ {
if(resource.texture.valid) const spritesheet = new Spritesheet(baseTexture, spritesheetData);
{
this.setTexture(resource.name, resource.texture);
onDownloaded(loader, resource, true); spritesheet.parse(() =>
}
else
{ {
onDownloaded(loader, resource, false); this.createCollection(data, spritesheet);
}
onDownloaded(true);
});
return; return;
} }
this.createCollection(data, null);
onDownloaded(true);
} }
public get collections(): Map<string, IGraphicAssetCollection> public get collections(): Map<string, IGraphicAssetCollection>

View File

@ -1,4 +1,4 @@
import { Resource, Texture } from '@pixi/core'; import { BaseTexture, Resource, Texture } from '@pixi/core';
import { Loader, LoaderResource } from '@pixi/loaders'; import { Loader, LoaderResource } from '@pixi/loaders';
import { Spritesheet } from '@pixi/spritesheet'; import { Spritesheet } from '@pixi/spritesheet';
import { IAssetData } from '../../core/asset/interfaces'; import { IAssetData } from '../../core/asset/interfaces';
@ -10,6 +10,7 @@ import { NitroEvent } from '../../core/events/NitroEvent';
import { RoomContentLoadedEvent } from '../../room/events/RoomContentLoadedEvent'; import { RoomContentLoadedEvent } from '../../room/events/RoomContentLoadedEvent';
import { IRoomObject } from '../../room/object/IRoomObject'; import { IRoomObject } from '../../room/object/IRoomObject';
import { GraphicAssetCollection } from '../../room/object/visualization/utils/GraphicAssetCollection'; import { GraphicAssetCollection } from '../../room/object/visualization/utils/GraphicAssetCollection';
import { GraphicAssetGifCollection } from '../../room/object/visualization/utils/GraphicAssetGifCollection';
import { IGraphicAssetCollection } from '../../room/object/visualization/utils/IGraphicAssetCollection'; import { IGraphicAssetCollection } from '../../room/object/visualization/utils/IGraphicAssetCollection';
import { Nitro } from '../Nitro'; import { Nitro } from '../Nitro';
import { FurnitureType } from '../session/furniture/FurnitureType'; import { FurnitureType } from '../session/furniture/FurnitureType';
@ -42,6 +43,7 @@ export class RoomContentLoader implements IFurnitureDataListener
private _waitingForSessionDataManager: boolean; private _waitingForSessionDataManager: boolean;
private _iconListener: IRoomContentListener; private _iconListener: IRoomContentListener;
private _collections: Map<string, IGraphicAssetCollection>; private _collections: Map<string, IGraphicAssetCollection>;
private _gifCollections: Map<string, GraphicAssetGifCollection>;
private _images: Map<string, HTMLImageElement>; private _images: Map<string, HTMLImageElement>;
private _events: Map<string, IEventDispatcher>; private _events: Map<string, IEventDispatcher>;
@ -69,6 +71,7 @@ export class RoomContentLoader implements IFurnitureDataListener
this._waitingForSessionDataManager = false; this._waitingForSessionDataManager = false;
this._iconListener = null; this._iconListener = null;
this._collections = new Map(); this._collections = new Map();
this._gifCollections = new Map();
this._images = new Map(); this._images = new Map();
this._events = new Map(); this._events = new Map();
@ -312,6 +315,13 @@ export class RoomContentLoader implements IFurnitureDataListener
return existing; return existing;
} }
public getGifCollection(name: string): GraphicAssetGifCollection
{
if(!name) return null;
return this._gifCollections.get(name) || null;
}
public getImage(name: string): HTMLImageElement public getImage(name: string): HTMLImageElement
{ {
if(!name) return null; if(!name) return null;
@ -336,6 +346,17 @@ export class RoomContentLoader implements IFurnitureDataListener
return collection.addAsset(assetName, texture, override, 0, 0, false, false); return collection.addAsset(assetName, texture, override, 0, 0, false, false);
} }
public createGifCollection(collectionName: string, textures: Texture<Resource>[], durations: number[]): GraphicAssetGifCollection
{
if(!collectionName || !textures || !durations) return null;
const collection = new GraphicAssetGifCollection(collectionName, textures, durations);
this._gifCollections.set(collectionName, collection);
return collection;
}
private createCollection(data: IAssetData, spritesheet: Spritesheet): GraphicAssetCollection private createCollection(data: IAssetData, spritesheet: Spritesheet): GraphicAssetCollection
{ {
if(!data || !spritesheet) return null; if(!data || !spritesheet) return null;
@ -480,149 +501,111 @@ export class RoomContentLoader implements IFurnitureDataListener
return false; return false;
} }
public downloadAsset(type: string, events: IEventDispatcher): boolean public downloadAsset(type: string, events: IEventDispatcher): void
{ {
const assetUrls: string[] = this.getAssetUrls(type); const assetUrls: string[] = this.getAssetUrls(type);
if(!assetUrls || !assetUrls.length) return false; if(!assetUrls || !assetUrls.length) return;
if((this._pendingContentTypes.indexOf(type) >= 0) || this.getOrRemoveEventDispatcher(type)) return false; if((this._pendingContentTypes.indexOf(type) >= 0) || this.getOrRemoveEventDispatcher(type)) return;
this._pendingContentTypes.push(type); this._pendingContentTypes.push(type);
this._events.set(type, events); this._events.set(type, events);
const totalToDownload = assetUrls.length; const loader = new Loader();
let totalDownloaded = 0;
const onDownloaded = (loader: Loader, resource: LoaderResource, flag: boolean) =>
{
if(loader) loader.destroy();
if(!flag)
{
this._logger.error('Failed to download asset: ' + resource.url);
events.dispatchEvent(new RoomContentLoadedEvent(RoomContentLoadedEvent.RCLE_FAILURE, type));
return;
}
totalDownloaded++;
if(totalDownloaded === totalToDownload)
{
const events = this._events.get(type);
if(!events) return;
events.dispatchEvent(new RoomContentLoadedEvent(RoomContentLoadedEvent.RCLE_SUCCESS, type));
}
};
for(const url of assetUrls) for(const url of assetUrls)
{ {
if(!url) continue; if(!url || !url.endsWith('.nitro')) continue;
const loader = new Loader();
loader loader
.add({ .add({
url, url,
crossOrigin: 'anonymous', crossOrigin: 'anonymous',
xhrType: url.endsWith('.nitro') ? LoaderResource.XHR_RESPONSE_TYPE.BUFFER : LoaderResource.XHR_RESPONSE_TYPE.JSON xhrType: url.endsWith('.nitro') ? LoaderResource.XHR_RESPONSE_TYPE.BUFFER : LoaderResource.XHR_RESPONSE_TYPE.JSON
}) });
.use((resource: LoaderResource, next: Function) =>
{
this.assetLoader(loader, resource, onDownloaded);
next();
})
.load();
} }
return true; let remaining = assetUrls.length;
}
private assetLoader(loader: Loader, resource: LoaderResource, onDownloaded: Function): void const onDownloaded = (status: boolean, url: string) =>
{
if(!resource || resource.error)
{ {
if(resource && resource.texture) resource.texture.destroy(true); if(!status)
onDownloaded(loader, resource, false);
return;
}
if(resource.extension === 'nitro')
{
const nitroBundle = new NitroBundle(resource.data);
const assetData = (nitroBundle.jsonFile as IAssetData);
if(!assetData)
{ {
onDownloaded(loader, resource, false); this._logger.error('Failed to download asset: ' + url);
loader.destroy();
events.dispatchEvent(new RoomContentLoadedEvent(RoomContentLoadedEvent.RCLE_FAILURE, type));
return; return;
} }
if(assetData.spritesheet && Object.keys(assetData.spritesheet).length) remaining--;
{
const baseTexture = nitroBundle.baseTexture;
if(!baseTexture) if(!remaining)
{
loader.destroy();
const events = this._events.get(type);
if(!events) return;
events.dispatchEvent(new RoomContentLoadedEvent(RoomContentLoadedEvent.RCLE_SUCCESS, type));
return;
}
};
loader.load((loader, resources) =>
{
for(const key in resources)
{
const resource = resources[key];
if(!resource || resource.error)
{ {
onDownloaded(loader, resource, false); onDownloaded(false, resource.url);
return; return;
} }
if(baseTexture.valid) if(resource.extension === 'nitro')
{ {
const spritesheet = new Spritesheet(baseTexture, assetData.spritesheet); const nitroBundle = new NitroBundle(resource.data);
spritesheet.parse(() => this.processAsset(nitroBundle.baseTexture, (nitroBundle.jsonFile as IAssetData), status =>
{ {
this.createCollection(assetData, spritesheet); onDownloaded(true, resource.url);
onDownloaded(loader, resource, true);
}); });
continue;
} }
else
{
baseTexture.once('loaded', () =>
{
baseTexture.removeAllListeners();
const spritesheet = new Spritesheet(baseTexture, assetData.spritesheet);
spritesheet.parse(() =>
{
this.createCollection(assetData, spritesheet);
onDownloaded(loader, resource, true);
});
});
baseTexture.once('error', () =>
{
baseTexture.removeAllListeners();
onDownloaded(loader, resource, false);
});
}
return;
} }
});
}
this.createCollection(assetData, null); private processAsset(baseTexture: BaseTexture, data: IAssetData, onDownloaded: (status: boolean) => void): void
{
const spritesheetData = data.spritesheet;
onDownloaded(loader, resource, true); if(spritesheetData && Object.keys(spritesheetData).length)
}
else
{ {
onDownloaded(loader, resource, false); const spritesheet = new Spritesheet(baseTexture, spritesheetData);
spritesheet.parse(() =>
{
this.createCollection(data, spritesheet);
onDownloaded(true);
});
return;
} }
this.createCollection(data, null);
onDownloaded(true);
} }
public setAssetAliasName(name: string, originalName: string): void public setAssetAliasName(name: string, originalName: string): void

View File

@ -75,6 +75,7 @@ export class RoomObjectVariable
public static FURNITURE_BRANDING_OFFSET_X: string = 'furniture_branding_offset_x'; public static FURNITURE_BRANDING_OFFSET_X: string = 'furniture_branding_offset_x';
public static FURNITURE_BRANDING_OFFSET_Y: string = 'furniture_branding_offset_y'; public static FURNITURE_BRANDING_OFFSET_Y: string = 'furniture_branding_offset_y';
public static FURNITURE_BRANDING_OFFSET_Z: string = 'furniture_branding_offset_z'; public static FURNITURE_BRANDING_OFFSET_Z: string = 'furniture_branding_offset_z';
public static FURNITURE_BRANDING_IS_ANIMATED: string = 'furniture_branding_is_animated';
public static FURNITURE_BADGE_IMAGE_STATUS: string = 'furniture_badge_image_status'; public static FURNITURE_BADGE_IMAGE_STATUS: string = 'furniture_badge_image_status';
public static FURNITURE_BADGE_ASSET_NAME: string = 'furniture_badge_asset_name'; public static FURNITURE_BADGE_ASSET_NAME: string = 'furniture_badge_asset_name';
public static FURNITURE_BADGE_VISIBLE_IN_STATE: string = 'furniture_badge_visible_in_state'; public static FURNITURE_BADGE_VISIBLE_IN_STATE: string = 'furniture_badge_visible_in_state';

View File

@ -23,6 +23,7 @@ import { FurnitureGiftWrappedVisualization } from './visualization/furniture/Fur
import { FurnitureGuildCustomizedVisualization } from './visualization/furniture/FurnitureGuildCustomizedVisualization'; import { FurnitureGuildCustomizedVisualization } from './visualization/furniture/FurnitureGuildCustomizedVisualization';
import { FurnitureGuildIsometricBadgeVisualization } from './visualization/furniture/FurnitureGuildIsometricBadgeVisualization'; import { FurnitureGuildIsometricBadgeVisualization } from './visualization/furniture/FurnitureGuildIsometricBadgeVisualization';
import { FurnitureHabboWheelVisualization } from './visualization/furniture/FurnitureHabboWheelVisualization'; import { FurnitureHabboWheelVisualization } from './visualization/furniture/FurnitureHabboWheelVisualization';
import { FurnitureIsometricBBVisualization } from './visualization/furniture/FurnitureIsometricBBVisualization';
import { FurnitureMannequinVisualization } from './visualization/furniture/FurnitureMannequinVisualization'; import { FurnitureMannequinVisualization } from './visualization/furniture/FurnitureMannequinVisualization';
import { FurnitureMannequinVisualizationData } from './visualization/furniture/FurnitureMannequinVisualizationData'; import { FurnitureMannequinVisualizationData } from './visualization/furniture/FurnitureMannequinVisualizationData';
import { FurniturePartyBeamerVisualization } from './visualization/furniture/FurniturePartyBeamerVisualization'; import { FurniturePartyBeamerVisualization } from './visualization/furniture/FurniturePartyBeamerVisualization';
@ -107,6 +108,9 @@ export class RoomObjectVisualizationFactory implements IRoomObjectVisualizationF
case RoomObjectVisualizationType.FURNITURE_BB: case RoomObjectVisualizationType.FURNITURE_BB:
visualization = FurnitureBBVisualization; visualization = FurnitureBBVisualization;
break; break;
case RoomObjectVisualizationType.FURNITURE_ISOMETRIC_BB:
visualization = FurnitureIsometricBBVisualization;
break;
case RoomObjectVisualizationType.FURNITURE_BOTTLE: case RoomObjectVisualizationType.FURNITURE_BOTTLE:
visualization = FurnitureBottleVisualization; visualization = FurnitureBottleVisualization;
break; break;
@ -204,6 +208,7 @@ export class RoomObjectVisualizationFactory implements IRoomObjectVisualizationF
case RoomObjectVisualizationType.FURNITURE_STATIC: case RoomObjectVisualizationType.FURNITURE_STATIC:
case RoomObjectVisualizationType.FURNITURE_GIFT_WRAPPED: case RoomObjectVisualizationType.FURNITURE_GIFT_WRAPPED:
case RoomObjectVisualizationType.FURNITURE_BB: case RoomObjectVisualizationType.FURNITURE_BB:
case RoomObjectVisualizationType.FURNITURE_ISOMETRIC_BB:
case RoomObjectVisualizationType.FURNITURE_BG: case RoomObjectVisualizationType.FURNITURE_BG:
case RoomObjectVisualizationType.FURNITURE_STICKIE: case RoomObjectVisualizationType.FURNITURE_STICKIE:
case RoomObjectVisualizationType.FURNITURE_BUILDER_PLACEHOLDER: case RoomObjectVisualizationType.FURNITURE_BUILDER_PLACEHOLDER:

View File

@ -19,6 +19,7 @@ export class RoomObjectVisualizationType
public static FURNITURE_SCORE_BOARD = 'furniture_score_board'; public static FURNITURE_SCORE_BOARD = 'furniture_score_board';
public static FURNITURE_FIREWORKS = 'furniture_fireworks'; public static FURNITURE_FIREWORKS = 'furniture_fireworks';
public static FURNITURE_BB = 'furniture_bb'; public static FURNITURE_BB = 'furniture_bb';
public static FURNITURE_ISOMETRIC_BB = 'furniture_isometric_bb';
public static FURNITURE_BG = 'furniture_bg'; public static FURNITURE_BG = 'furniture_bg';
public static FURNITURE_STICKIE = 'furniture_stickie'; public static FURNITURE_STICKIE = 'furniture_stickie';
public static FURNITURE_MANNEQUIN = 'furniture_mannequin'; public static FURNITURE_MANNEQUIN = 'furniture_mannequin';

View File

@ -1,3 +1,5 @@
import { BaseTexture, Texture } from '@pixi/core';
import { decompressFrames, parseGIF } from 'gifuct-js';
import { IAssetData } from '../../../../../core'; import { IAssetData } from '../../../../../core';
import { IRoomGeometry, RoomSpriteMouseEvent } from '../../../../../room'; import { IRoomGeometry, RoomSpriteMouseEvent } from '../../../../../room';
import { RoomObjectUpdateMessage } from '../../../../../room/messages/RoomObjectUpdateMessage'; import { RoomObjectUpdateMessage } from '../../../../../room/messages/RoomObjectUpdateMessage';
@ -149,29 +151,89 @@ export class FurnitureRoomBrandingLogic extends FurnitureLogic
if(!imageUrl || (imageUrl === '') || (imageStatus === 1)) return; if(!imageUrl || (imageUrl === '') || (imageStatus === 1)) return;
const asset = Nitro.instance.core && Nitro.instance.core.asset; if(imageUrl.endsWith('.gif'))
if(!asset) return;
const texture = asset.getTexture(imageUrl);
if(!texture)
{ {
asset.downloadAsset(imageUrl, (flag: boolean) => this.object.model.setValue(RoomObjectVariable.FURNITURE_BRANDING_IS_ANIMATED, true);
{
if(flag) fetch(imageUrl)
.then(resp => resp.arrayBuffer())
.then(buff => parseGIF(buff))
.then(gif =>
{ {
const width = gif.lsd.width;
const height = gif.lsd.height;
const wh = width * height;
const frames = decompressFrames(gif, false);
const textures = [];
const durations = [];
let frame = new Uint8Array(wh * 4);
for(let ind = 0; ind < frames.length; ind++)
{
if(ind > 0) frame = frame.slice(0);
const pixels = frames[ind].pixels;
const colorTable = frames[ind].colorTable;
const trans = frames[ind].transparentIndex;
const dims = frames[ind].dims;
for(let j = 0; j < dims.height; j++)
{
for(let i = 0; i < dims.width; i++)
{
const pixel = pixels[j*dims.width + i];
const coord = (j + dims.top) * width + (i + dims.left);
if(trans !== pixel)
{
const c = colorTable[pixel];
frame[ 4 * coord ] = c[0];
frame[ 4 * coord + 1 ] = c[1];
frame[ 4 * coord + 2 ] = c[2];
frame[ 4 * coord + 3 ] = 255;
}
}
}
const baseTexture = BaseTexture.fromBuffer(frame, width, height);
textures.push(new Texture(baseTexture));
durations.push(frames[ind].delay);
}
Nitro.instance.roomEngine.roomContentLoader.createGifCollection(imageUrl, textures, durations);
this.processUpdateMessage(new ObjectAdUpdateMessage(ObjectAdUpdateMessage.IMAGE_LOADED)); this.processUpdateMessage(new ObjectAdUpdateMessage(ObjectAdUpdateMessage.IMAGE_LOADED));
} });
else
{
this.processUpdateMessage(new ObjectAdUpdateMessage(ObjectAdUpdateMessage.IMAGE_LOADING_FAILED));
}
});
return;
} }
else
{
const asset = Nitro.instance.core && Nitro.instance.core.asset;
this.processUpdateMessage(new ObjectAdUpdateMessage(ObjectAdUpdateMessage.IMAGE_LOADED)); if(!asset) return;
const texture = asset.getTexture(imageUrl);
if(!texture)
{
asset.downloadAsset(imageUrl, (flag: boolean) =>
{
if(flag)
{
this.processUpdateMessage(new ObjectAdUpdateMessage(ObjectAdUpdateMessage.IMAGE_LOADED));
}
else
{
this.processUpdateMessage(new ObjectAdUpdateMessage(ObjectAdUpdateMessage.IMAGE_LOADING_FAILED));
}
});
return;
}
this.processUpdateMessage(new ObjectAdUpdateMessage(ObjectAdUpdateMessage.IMAGE_LOADED));
}
} }
} }

View File

@ -1,23 +1,28 @@
import { Resource, Texture } from '@pixi/core'; import { Resource, Texture } from '@pixi/core';
import { GraphicAssetGifCollection } from '../../../../../room/object/visualization/utils/GraphicAssetGifCollection';
import { Nitro } from '../../../../Nitro'; import { Nitro } from '../../../../Nitro';
import { RoomObjectVariable } from '../../RoomObjectVariable'; import { RoomObjectVariable } from '../../RoomObjectVariable';
import { FurnitureVisualization } from './FurnitureVisualization'; import { FurnitureVisualization } from './FurnitureVisualization';
export class FurnitureBrandedImageVisualization extends FurnitureVisualization export class FurnitureBrandedImageVisualization extends FurnitureVisualization
{ {
private static BRANDED_IMAGE: string = 'branded_image'; protected static BRANDED_IMAGE: string = 'branded_image';
private static STATE_0: number = 0; protected static STATE_0: number = 0;
private static STATE_1: number = 1; protected static STATE_1: number = 1;
private static STATE_2: number = 2; protected static STATE_2: number = 2;
private static STATE_3: number = 3; protected static STATE_3: number = 3;
protected _imageUrl: string; protected _imageUrl: string;
protected _shortUrl: string; protected _shortUrl: string;
protected _imageReady: boolean; protected _imageReady: boolean;
protected _isAnimated: boolean;
protected _gifCollection: GraphicAssetGifCollection;
protected _offsetX: number; protected _offsetX: number;
protected _offsetY: number; protected _offsetY: number;
protected _offsetZ: number; protected _offsetZ: number;
protected _currentFrame: number;
protected _totalFrames: number;
constructor() constructor()
{ {
@ -26,17 +31,25 @@ export class FurnitureBrandedImageVisualization extends FurnitureVisualization
this._imageUrl = null; this._imageUrl = null;
this._shortUrl = null; this._shortUrl = null;
this._imageReady = false; this._imageReady = false;
this._isAnimated = false;
this._gifCollection = null;
this._offsetX = 0; this._offsetX = 0;
this._offsetY = 0; this._offsetY = 0;
this._offsetZ = 0; this._offsetZ = 0;
this._currentFrame = -1;
this._totalFrames = -1;
} }
public dispose(): void public dispose(): void
{ {
super.dispose(); super.dispose();
if(this._imageUrl) (this.asset && this.asset.disposeAsset(this._imageUrl)); if(this._imageUrl)
{
(this.asset && this.asset.disposeAsset(this._imageUrl));
// dispose all
}
} }
protected updateObject(scale: number, direction: number): boolean protected updateObject(scale: number, direction: number): boolean
@ -54,9 +67,10 @@ export class FurnitureBrandedImageVisualization extends FurnitureVisualization
if(flag) if(flag)
{ {
this._offsetX = this.object.model.getValue<number>(RoomObjectVariable.FURNITURE_BRANDING_OFFSET_X); this._offsetX = (this.object.model.getValue<number>(RoomObjectVariable.FURNITURE_BRANDING_OFFSET_X) || 0);
this._offsetY = this.object.model.getValue<number>(RoomObjectVariable.FURNITURE_BRANDING_OFFSET_Y); this._offsetY = (this.object.model.getValue<number>(RoomObjectVariable.FURNITURE_BRANDING_OFFSET_Y) || 0);
this._offsetZ = this.object.model.getValue<number>(RoomObjectVariable.FURNITURE_BRANDING_OFFSET_Z); this._offsetZ = (this.object.model.getValue<number>(RoomObjectVariable.FURNITURE_BRANDING_OFFSET_Z) || 0);
this._isAnimated = (this.object.model.getValue<boolean>(RoomObjectVariable.FURNITURE_BRANDING_IS_ANIMATED) || false);
} }
if(!this._imageReady) if(!this._imageReady)
@ -84,26 +98,21 @@ export class FurnitureBrandedImageVisualization extends FurnitureVisualization
return flag; return flag;
} }
protected imageReady(texture: Texture<Resource>, imageUrl: string): void
{
if(!texture)
{
this._imageUrl = null;
return;
}
this._imageUrl = imageUrl;
}
private checkIfImageChanged(): boolean private checkIfImageChanged(): boolean
{ {
const imageUrl = this.object.model.getValue<string>(RoomObjectVariable.FURNITURE_BRANDING_IMAGE_URL); const imageUrl = this.object.model.getValue<string>(RoomObjectVariable.FURNITURE_BRANDING_IMAGE_URL);
if(imageUrl && (imageUrl === this._imageUrl)) return false; if(imageUrl && (imageUrl === this._imageUrl)) return false;
if(this._gifCollection)
{
//
}
(this.asset && this.asset.disposeAsset(this._imageUrl)); (this.asset && this.asset.disposeAsset(this._imageUrl));
// dispose all
return true; return true;
} }
@ -123,7 +132,23 @@ export class FurnitureBrandedImageVisualization extends FurnitureVisualization
if(imageStatus === 1) if(imageStatus === 1)
{ {
const texture = Nitro.instance.core.asset.getTexture(imageUrl); let texture: Texture = null;
if(this._isAnimated)
{
const gifCollection = Nitro.instance.roomEngine.roomContentLoader.getGifCollection(imageUrl);
if(gifCollection)
{
this._gifCollection = gifCollection;
texture = gifCollection.textures[0];
}
}
else
{
texture = Nitro.instance.core.asset.getTexture(imageUrl);
}
if(!texture) return false; if(!texture) return false;
@ -135,8 +160,27 @@ export class FurnitureBrandedImageVisualization extends FurnitureVisualization
return false; return false;
} }
protected imageReady(texture: Texture<Resource>, imageUrl: string): void
{
if(!texture)
{
this._imageUrl = null;
return;
}
this._imageUrl = imageUrl;
}
protected checkAndCreateImageForCurrentState(): void protected checkAndCreateImageForCurrentState(): void
{ {
if(this._isAnimated)
{
this.buildAssetsForGif();
return;
}
if(!this._imageUrl) return; if(!this._imageUrl) return;
const texture = Nitro.instance.core.asset.getTexture(this._imageUrl); const texture = Nitro.instance.core.asset.getTexture(this._imageUrl);
@ -145,6 +189,36 @@ export class FurnitureBrandedImageVisualization extends FurnitureVisualization
const state = this.object.getState(0); const state = this.object.getState(0);
this.addBackgroundAsset(texture, state, 0);
}
protected buildAssetsForGif(): void
{
if(!this._gifCollection) return;
const textures = this._gifCollection.textures;
const durations = this._gifCollection.durations;
if(!textures.length || !durations.length || (textures.length !== durations.length)) return;
const state = this.object.getState(0);
for(let i = 0; i < textures.length; i++)
{
const texture = textures[i];
const duration = durations[i];
if(!texture) continue;
this.addBackgroundAsset(texture, state, i);
}
this._currentFrame = -1;
this._totalFrames = textures.length;
}
protected addBackgroundAsset(texture: Texture<Resource>, state: number, frame: number): void
{
let x = 0; let x = 0;
let y = 0; let y = 0;
let flipH = false; let flipH = false;
@ -178,15 +252,54 @@ export class FurnitureBrandedImageVisualization extends FurnitureVisualization
break; break;
} }
this.asset.addAsset(this._imageUrl, texture, true, x, y, flipH, flipV); this.asset.addAsset(`${ this._imageUrl }_${ frame }`, texture, true, x, y, flipH, flipV);
} }
protected getSpriteAssetName(scale: number, layerId: number): string protected getSpriteAssetName(scale: number, layerId: number): string
{ {
const tag = this.getLayerTag(scale, this._direction, layerId); const tag = this.getLayerTag(scale, this._direction, layerId);
if((tag === FurnitureBrandedImageVisualization.BRANDED_IMAGE) && this._imageUrl) return this._imageUrl; if((tag === FurnitureBrandedImageVisualization.BRANDED_IMAGE) && this._imageUrl)
{
return `${ this._imageUrl }_${ this.getFrameNumber(scale, layerId) }`;
}
return super.getSpriteAssetName(scale, layerId); return super.getSpriteAssetName(scale, layerId);
} }
protected updateAnimation(scale: number): number
{
if(!this._imageReady || !this._isAnimated || (this._totalFrames <= 0)) return 0;
return 1;
}
protected getFrameNumber(scale: number, layerId: number): number
{
if(!this._imageReady || !this._isAnimated || (this._totalFrames <= 0)) return 0;
const tag = this.getLayerTag(scale, this._direction, layerId);
if((tag === FurnitureBrandedImageVisualization.BRANDED_IMAGE) && this._imageUrl)
{
let newFrame = this._currentFrame;
if(newFrame < 0)
{
newFrame = 0;
}
else
{
newFrame += 1;
}
if(newFrame === this._totalFrames) newFrame = 0;
this._currentFrame = newFrame;
return this._currentFrame;
}
return 0;
}
} }

View File

@ -0,0 +1,172 @@
import { RenderTexture, Resource, Texture } from '@pixi/core';
import { Matrix } from '@pixi/math';
import { NitroSprite } from '../../../../../core/utils/proxy/NitroSprite';
import { IGraphicAsset } from '../../../../../room/object/visualization/utils/IGraphicAsset';
import { TextureUtils } from '../../../../../room/utils/TextureUtils';
import { Nitro } from '../../../../Nitro';
import { FurnitureBBVisualization } from './FurnitureBBVisualization';
import { FurnitureBrandedImageVisualization } from './FurnitureBrandedImageVisualization';
export class FurnitureIsometricBBVisualization extends FurnitureBBVisualization
{
private _needsTransform: boolean = true;
protected transformGifTextures(asset: IGraphicAsset): void
{
if(!this._gifCollection) return;
const textures = this._gifCollection.textures;
if(!textures.length) return;
for(let i = 0; i < textures.length; i++)
{
const texture = textures[i];
if(!texture) continue;
const existingAsset = this.getAsset(`${ this._imageUrl }_${ i }`);
if(!existingAsset) continue;
const scale = 1.1;
const matrix = new Matrix();
const difference = (asset.width / texture.width);
switch(this.direction)
{
case 2:
matrix.a = difference;
matrix.b = (-0.5 * difference);
matrix.c = 0;
matrix.d = (difference * scale);
matrix.tx = 0;
matrix.ty = ((0.5 * difference) * texture.width);
break;
case 0:
case 4:
matrix.a = difference;
matrix.b = (0.5 * difference);
matrix.c = 0;
matrix.d = (difference * scale);
matrix.tx = 0;
matrix.ty = 0;
break;
default:
matrix.a = difference;
matrix.b = 0;
matrix.c = 0;
matrix.d = difference;
matrix.tx = 0;
matrix.ty = 0;
}
const sprite = new NitroSprite(texture);
const x = asset.x;
const y = asset.y;
const flipH = asset.flipH;
const flipV = asset.flipV;
const renderTexture = RenderTexture.create({
width: asset.width,
height: asset.height
});
Nitro.instance.renderer.render(sprite, {
renderTexture: renderTexture,
clear: true,
transform: matrix
});
const newTexture = TextureUtils.generateTexture(sprite);
this.asset.disposeAsset(`${ this._imageUrl }_${ i }`);
this.asset.addAsset(`${ this._imageUrl }_${ i }`, newTexture, true, x, y, flipH, flipV);
}
this._needsTransform = false;
}
protected generateTransformedImage(texture: Texture<Resource>, asset: IGraphicAsset): void
{
const scale = 1.1;
const matrix = new Matrix();
const difference = (asset.width / texture.width);
switch(this.direction)
{
case 2:
matrix.a = difference;
matrix.b = (-0.5 * difference);
matrix.c = 0;
matrix.d = (difference * scale);
matrix.tx = 0;
matrix.ty = ((0.5 * difference) * texture.width);
break;
case 0:
case 4:
matrix.a = difference;
matrix.b = (0.5 * difference);
matrix.c = 0;
matrix.d = (difference * scale);
matrix.tx = 0;
matrix.ty = 0;
break;
default:
matrix.a = difference;
matrix.b = 0;
matrix.c = 0;
matrix.d = difference;
matrix.tx = 0;
matrix.ty = 0;
}
const sprite = new NitroSprite(texture);
sprite.transform.setFromMatrix(matrix);
const x = asset.x;
const y = asset.y;
const flipH = asset.flipH;
const flipV = asset.flipV;
const newTexture = TextureUtils.generateTexture(sprite);
this.asset.disposeAsset(`${ this._imageUrl }_0`);
this.asset.addAsset(`${ this._imageUrl }_0`, newTexture, true, x, y, flipH, flipV);
this._needsTransform = false;
}
protected checkAndCreateImageForCurrentState(): void
{
super.checkAndCreateImageForCurrentState();
this._needsTransform = true;
}
protected getSpriteAssetName(scale: number, layerId: number): string
{
const tag = this.getLayerTag(scale, this._direction, layerId);
if((tag === FurnitureBrandedImageVisualization.BRANDED_IMAGE) && this._imageUrl)
{
if(this._needsTransform)
{
if(this._isAnimated)
{
this.transformGifTextures(this.getAsset(super.getSpriteAssetName(scale, layerId)));
}
else
{
this.generateTransformedImage(Nitro.instance.core.asset.getTexture(this._imageUrl), this.getAsset(super.getSpriteAssetName(scale, layerId)));
}
}
return `${ this._imageUrl }_${ this.getFrameNumber(scale, layerId) }`;
}
return super.getSpriteAssetName(scale, layerId);
}
}

View File

@ -0,0 +1,11 @@
import { Resource, Texture } from '@pixi/core';
export class GraphicAssetGifCollection
{
constructor(
public name: string,
public textures: Texture<Resource>[],
public durations: number[]
)
{}
}

View File

@ -1,4 +1,5 @@
export * from './GraphicAsset'; export * from './GraphicAsset';
export * from './GraphicAssetGifCollection';
//export * from './GraphicAssetCollection'; //export * from './GraphicAssetCollection';
export * from './GraphicAssetPalette'; export * from './GraphicAssetPalette';
export * from './IGraphicAsset'; export * from './IGraphicAsset';