Files
Nitro_Render_V3/packages/room/src/object/visualization/furniture/IsometricImageFurniVisualization.ts
T
2025-03-15 14:54:10 +01:00

193 lines
6.1 KiB
TypeScript

import { IGraphicAsset } from '@nitrots/api';
import { TextureUtils } from '@nitrots/utils';
import { Container, Matrix, Sprite, Texture } from 'pixi.js';
import { FurnitureAnimatedVisualization } from './FurnitureAnimatedVisualization';
export class IsometricImageFurniVisualization extends FurnitureAnimatedVisualization {
protected static THUMBNAIL: string = 'THUMBNAIL';
private _thumbnailAssetNameNormal: string;
private _thumbnailImageNormal: Texture;
private _thumbnailDirection: number;
private _thumbnailChanged: boolean;
protected _hasOutline: boolean;
constructor() {
super();
this._thumbnailAssetNameNormal = null;
this._thumbnailImageNormal = null;
this._thumbnailDirection = -1;
this._thumbnailChanged = false;
this._hasOutline = false;
}
public get hasThumbnailImage(): boolean {
return !!this._thumbnailImageNormal;
}
public setThumbnailImages(k: Texture): void {
this._thumbnailImageNormal = k;
this._thumbnailChanged = true;
}
protected updateModel(scale: number): boolean {
const flag = super.updateModel(scale);
// Example: apply color tint for testing.
if (this.object && this.object.model) {
if (this.direction === 2) this.object.model.setValue('furniture_color', 0xFF0000);
else if (this.direction === 4) this.object.model.setValue('furniture_color', 0x0000FF);
}
// Only refresh thumbnail if something changed or the direction changed.
if (!this._thumbnailChanged && (this._thumbnailDirection === this.direction))
return flag;
this.refreshThumbnail();
return true;
}
private refreshThumbnail(): void {
if (!this.asset) return;
if (this._thumbnailImageNormal) {
this.addThumbnailAsset(this._thumbnailImageNormal, 64);
} else {
this.asset.disposeAsset(this.getThumbnailAssetName(64));
}
this._thumbnailChanged = false;
this._thumbnailDirection = this.direction;
}
private addThumbnailAsset(k: Texture, scale: number): void {
if (!k) {
console.warn('addThumbnailAsset called with null/undefined texture. Skipping.');
return;
}
let layerId = 0;
while (layerId < this.totalSprites) {
if (
this.getLayerTag(scale, this.direction, layerId) ===
IsometricImageFurniVisualization.THUMBNAIL
) {
const assetName =
this.cacheSpriteAssetName(scale, layerId, false) + this.getFrameNumber(scale, layerId);
const asset = this.getAsset(assetName, layerId);
if (asset) {
const transformed = this.generateTransformedThumbnail(k, asset);
if (!transformed) return;
const thumbAssetName = this.getThumbnailAssetName(scale);
this.asset.disposeAsset(thumbAssetName);
this.asset.addAsset(
thumbAssetName,
transformed,
true,
asset.offsetX,
asset.offsetY,
false,
false
);
}
return;
}
layerId++;
}
}
protected generateTransformedThumbnail(texture: Texture, asset: IGraphicAsset): Texture {
// 1) If an outline is needed, generate it.
if (this._hasOutline) {
const outlineContainer = new Container();
const background = new Sprite(Texture.WHITE);
background.tint = 0x000000;
background.width = texture.width + 40;
background.height = texture.height + 40;
const sprite = new Sprite(texture);
sprite.x = (background.width - sprite.width) / 2;
sprite.y = (background.height - sprite.height) / 2;
outlineContainer.addChild(background, sprite);
// Generate a new texture that includes the outline.
texture = TextureUtils.generateTexture(outlineContainer);
}
// 2) Set the texture's intended dimensions.
texture.orig.width = asset.width;
texture.orig.height = asset.height;
// 3) Build the matrix (same as your original logic).
// Default matrix: (a=1, b=0, c=0, d=1, tx=0, ty=0)
const matrix = new Matrix();
switch (this.direction) {
case 2:
matrix.b = -0.5; // negative skew
matrix.d /= 1.6; // flatten vertically
matrix.ty = 0.5 * texture.width; // shift downward
break;
case 0:
case 4:
matrix.b = 0.5; // positive skew
matrix.d /= 1.6;
matrix.tx = -0.5; // shift left
break;
}
// 4) Decompose the matrix.
const rotation = Math.atan2(matrix.b, matrix.a);
const scaleX = Math.sqrt(matrix.a * matrix.a + matrix.b * matrix.b);
const scaleY = matrix.d;
const tx = matrix.tx;
const ty = matrix.ty;
// 5) Create a sprite from the texture.
const finalSprite = new Sprite(texture);
// Set the anchor to center to ease flipping.
finalSprite.anchor.set(0.5, 0.5);
// 6) Apply the decomposed transform.
// Since our anchor is center, add half of the texture's width/height.
finalSprite.x = tx + texture.width / 2;
finalSprite.y = ty + texture.height / 2;
finalSprite.rotation = rotation;
finalSprite.scale.set(scaleX, scaleY);
console.log(
'Manual override: direction', this.direction,
'rotation =', finalSprite.rotation,
'scale =', finalSprite.scale.x, finalSprite.scale.y,
'position =', finalSprite.x, finalSprite.y
);
// 8) Wrap the sprite in a container and generate the final texture.
const container = new Container();
container.addChild(finalSprite);
return TextureUtils.generateTexture(container);
}
protected getSpriteAssetName(scale: number, layerId: number): string {
if (
this._thumbnailImageNormal &&
this.getLayerTag(scale, this.direction, layerId) === IsometricImageFurniVisualization.THUMBNAIL
) {
return this.getThumbnailAssetName(scale);
}
return super.getSpriteAssetName(scale, layerId);
}
protected getThumbnailAssetName(scale: number): string {
this._thumbnailAssetNameNormal = [this._type, this.object.id, 'thumb', 64, this.direction].join('_');
return this._thumbnailAssetNameNormal;
}
protected getFullThumbnailAssetName(k: number, _arg_2: number): string {
return [this._type, k, 'thumb', _arg_2, this.direction].join('_');
}
}