From 8acd0c7de48e86de53f481479f61d8a1a30f11c6 Mon Sep 17 00:00:00 2001 From: duckietm Date: Tue, 18 Mar 2025 10:46:22 +0100 Subject: [PATCH] Wip --- .../FurnitureChangeStateWhenStepOnLogic.ts | 2 +- .../FurnitureDynamicThumbnailVisualization.ts | 68 ++-- .../IsometricImageFurniVisualization.ts | 308 ++++++++---------- .../src/renderer/cache/RoomObjectCache.ts | 22 +- 4 files changed, 187 insertions(+), 213 deletions(-) diff --git a/packages/room/src/object/logic/furniture/FurnitureChangeStateWhenStepOnLogic.ts b/packages/room/src/object/logic/furniture/FurnitureChangeStateWhenStepOnLogic.ts index ae776d6..a496c73 100644 --- a/packages/room/src/object/logic/furniture/FurnitureChangeStateWhenStepOnLogic.ts +++ b/packages/room/src/object/logic/furniture/FurnitureChangeStateWhenStepOnLogic.ts @@ -37,7 +37,7 @@ export class FurnitureChangeStateWhenStepOnLogic extends FurnitureLogic let sizeX = this.object.model.getValue(RoomObjectVariable.FURNITURE_SIZE_X); let sizeY = this.object.model.getValue(RoomObjectVariable.FURNITURE_SIZE_Y); - const direction = (((Math.floor(this.object.getDirection().x) + 45) % 360) / 90); + const direction = Math.floor(((this.object.getDirection().x + 45) % 360) / 90); if((direction === 1) || (direction === 3)) [sizeX, sizeY] = [sizeY, sizeX]; diff --git a/packages/room/src/object/visualization/furniture/FurnitureDynamicThumbnailVisualization.ts b/packages/room/src/object/visualization/furniture/FurnitureDynamicThumbnailVisualization.ts index 844c4ca..1fdb4d2 100644 --- a/packages/room/src/object/visualization/furniture/FurnitureDynamicThumbnailVisualization.ts +++ b/packages/room/src/object/visualization/furniture/FurnitureDynamicThumbnailVisualization.ts @@ -2,39 +2,47 @@ import { Texture } from 'pixi.js'; import { IsometricImageFurniVisualization } from './IsometricImageFurniVisualization'; export class FurnitureDynamicThumbnailVisualization extends IsometricImageFurniVisualization { - private _cachedUrl: string; + private _cachedUrl: string; - constructor() { - super(); - this._cachedUrl = null; - this._hasOutline = true; - } + constructor() { + super(); - protected updateModel(scale: number): boolean { - if (this.object) { - const thumbnailUrl = this.getThumbnailURL(); - if (this._cachedUrl !== thumbnailUrl) { - this._cachedUrl = thumbnailUrl; - if (this._cachedUrl && this._cachedUrl !== '') { - const image = new Image(); - image.crossOrigin = '*'; - image.onload = this.onImageLoad.bind(this, image); - image.src = thumbnailUrl; - } else { - this.setThumbnailImages(null); - } - } + this._cachedUrl = null; + this._hasOutline = true; } - return super.updateModel(scale); - } - private onImageLoad(image: HTMLImageElement): void { - const texture = Texture.from(image); - texture.source.scaleMode = 'linear'; - this.setThumbnailImages(texture); - } + protected updateModel(scale: number): boolean { + if (this.object) { + const thumbnailUrl = this.getThumbnailURL(); - protected getThumbnailURL(): string { - throw new Error('This method must be overridden!'); - } + if (this._cachedUrl !== thumbnailUrl) { + this._cachedUrl = thumbnailUrl; + + if (this._cachedUrl && this._cachedUrl !== '') { + const image = new Image(); + + image.src = thumbnailUrl; + image.crossOrigin = '*'; + + image.onload = () => { + if (image.complete && image.width > 0 && image.height > 0) { + const texture = Texture.from(image); + texture.source.scaleMode = 'linear'; + this.setThumbnailImages(texture, thumbnailUrl); // Pass URL here + } else { + console.error("Image failed to load properly:", thumbnailUrl); + } + }; + } else { + this.setThumbnailImages(null); + } + } + } + + return super.updateModel(scale); + } + + protected getThumbnailURL(): string { + throw new Error('This method must be overridden!'); + } } \ No newline at end of file diff --git a/packages/room/src/object/visualization/furniture/IsometricImageFurniVisualization.ts b/packages/room/src/object/visualization/furniture/IsometricImageFurniVisualization.ts index 2e747fa..4e1123c 100644 --- a/packages/room/src/object/visualization/furniture/IsometricImageFurniVisualization.ts +++ b/packages/room/src/object/visualization/furniture/IsometricImageFurniVisualization.ts @@ -1,206 +1,154 @@ import { IGraphicAsset } from '@nitrots/api'; -import { TextureUtils } from '@nitrots/utils'; -import * as PIXI from 'pixi.js'; +import { GetRenderer, TextureUtils } from '@nitrots/utils'; +import { Matrix, Sprite, Texture, RenderTexture } from 'pixi.js'; import { FurnitureAnimatedVisualization } from './FurnitureAnimatedVisualization'; -console.log('Pixi.js Version at import:', PIXI.VERSION); - export class IsometricImageFurniVisualization extends FurnitureAnimatedVisualization { - protected static THUMBNAIL: string = 'THUMBNAIL'; + protected static THUMBNAIL: string = 'THUMBNAIL'; - private _thumbnailAssetNameNormal: string; - private _thumbnailImageNormal: PIXI.Texture; - private _thumbnailDirection: number; - private _thumbnailChanged: boolean; - protected _hasOutline: boolean; + private _thumbnailAssetNameNormal: string; + private _thumbnailImageNormal: Texture; + private _thumbnailDirection: number; + private _thumbnailChanged: boolean; + private _uniqueId: string; + private _photoUrl: string; // Store the photo URL or ID - constructor() { - super(); + constructor() { + super(); - this._thumbnailAssetNameNormal = null; - this._thumbnailImageNormal = null; - this._thumbnailDirection = -1; - this._thumbnailChanged = false; - this._hasOutline = false; // Disable outline for simplicity - } - - public get hasThumbnailImage(): boolean { - return !!this._thumbnailImageNormal; - } - - public setThumbnailImages(k: PIXI.Texture): void { - this._thumbnailImageNormal = k; - this._thumbnailChanged = true; - } - - protected updateModel(scale: number): boolean { - const flag = super.updateModel(scale); - - 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); + this._thumbnailAssetNameNormal = null; + this._thumbnailImageNormal = null; + this._thumbnailDirection = -1; + this._thumbnailChanged = false; + this._uniqueId = `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`; + this._photoUrl = null; } - 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)); + public get hasThumbnailImage(): boolean { + return !(this._thumbnailImageNormal == null); } - this._thumbnailChanged = false; - this._thumbnailDirection = this.direction; - } - - private addThumbnailAsset(k: PIXI.Texture, scale: number): void { - if (!k) { - console.warn('addThumbnailAsset called with null/undefined texture. Skipping.'); - return; + public setThumbnailImages(k: Texture, url?: string): void { + this._thumbnailImageNormal = k; + this._photoUrl = url || null; // Store the URL or ID passed with the texture + this._thumbnailChanged = true; } - 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); + public getPhotoUrl(): string { + return this._photoUrl; // Expose the URL for the click handler + } - if (asset) { - const transformed = this.generateTransformedThumbnail(k, asset); - if (!transformed) return; + protected updateModel(scale: number): boolean { + const flag = super.updateModel(scale); - const thumbAssetName = this.getThumbnailAssetName(scale); - - this.asset.disposeAsset(thumbAssetName); - this.asset.addAsset( - thumbAssetName, - transformed, - true, - asset.offsetX, - asset.offsetY, - false, - false - ); + if (!this._thumbnailChanged && (this._thumbnailDirection === this.direction)) { + return flag; } - return; - } - layerId++; - } - } - protected generateTransformedThumbnail(texture: PIXI.Texture, asset: IGraphicAsset): PIXI.Texture { - console.log('Entering generateTransformedThumbnail'); - console.log('Initial texture dimensions:', texture.width, 'x', texture.height); - console.log('Asset dimensions:', asset.width, 'x', asset.height); + this.refreshThumbnail(); - // 1) Scale the texture to 320x320, then to 64x64 - const targetWidth = 64; - const targetHeight = 64; - let workingTexture = texture; - - // Ensure texture is 320x320 - if (texture.width !== 320 || texture.height !== 320) { - const scaleContainer = new PIXI.Container(); - const scaleSprite = new PIXI.Sprite(texture); - scaleSprite.width = 320; - scaleSprite.height = 320; - scaleContainer.addChild(scaleSprite); - workingTexture = TextureUtils.generateTexture(scaleContainer, 320, 320); - console.log('Scaled texture to 320x320:', workingTexture.width, 'x', workingTexture.height); - } - - // Scale to 64x64 - const scaleFactor = targetWidth / workingTexture.width; // 64/320 = 0.2 - const scaledContainer = new PIXI.Container(); - const scaledSprite = new PIXI.Sprite(workingTexture); - scaledSprite.scale.set(scaleFactor, scaleFactor); // Scale to 64x64 - scaledContainer.addChild(scaledSprite); - workingTexture = TextureUtils.generateTexture(scaledContainer, targetWidth, targetHeight); - console.log('Scaled texture to 64x64:', workingTexture.width, 'x', workingTexture.height); - - // 2) Apply trapezoid transformation: (0,0), (64,30), (64,64), (0,34) - if (this.direction === 4) { - const sprite = new PIXI.Sprite(workingTexture); - const container = new PIXI.Container(); - container.addChild(sprite); - - // Apply the trapezoid transformation - const points = [ - new PIXI.Point(0, 0), - new PIXI.Point(64, 30), - new PIXI.Point(64, 64), - new PIXI.Point(0, 34), - ]; - - const graphics = new PIXI.Graphics(); - graphics.beginFill(0xFFFFFF); - graphics.drawPolygon(points); - graphics.endFill(); - - container.addChild(graphics); - container.mask = graphics; - - const bounds = container.getBounds(); - console.log('Container bounds before render:', bounds.width, 'x', bounds.height); - - const finalTexture = TextureUtils.generateTexture(container, targetWidth, targetHeight); - console.log('Final texture dimensions:', finalTexture.width, 'x', finalTexture.height); - return finalTexture; - } else { - // Original matrix transformation for cases 0 and 2 - const matrix = new PIXI.Matrix(); - switch (this.direction) { - case 0: - case 2: - matrix.b = 0.5; // Positive skew - matrix.d /= 1.6; - matrix.tx = -0.5; // Shift left - break; - default: - break; + return true; } - const sprite = new PIXI.Sprite(workingTexture); - sprite.position.set(matrix.tx, matrix.ty); - sprite.scale.set(matrix.a, matrix.d); - sprite.skew.set(matrix.b, matrix.c); + private refreshThumbnail(): void { + if (this.asset == null) { + return; + } - const container = new PIXI.Container(); - container.addChild(sprite); - return TextureUtils.generateTexture(container); - } -} + const thumbnailAssetName = this.getThumbnailAssetName(64); + if (this._thumbnailImageNormal) { + this.addThumbnailAsset(this._thumbnailImageNormal, 64); + } else { + const layerId = 2; + const sprite = this.getSprite(layerId); + } - protected getSpriteAssetName(scale: number, layerId: number): string { - if ( - this._thumbnailImageNormal && - this.getLayerTag(scale, this.direction, layerId) === IsometricImageFurniVisualization.THUMBNAIL - ) { - return this.getThumbnailAssetName(scale); + this._thumbnailChanged = false; + this._thumbnailDirection = this.direction; } - 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; - } + private addThumbnailAsset(k: Texture, scale: number): void { + let layerId = 0; - protected getFullThumbnailAssetName(k: number, _arg_2: number): string { - return [this._type, k, 'thumb', _arg_2, this.direction].join('_'); - } -} + while (layerId < this.totalSprites) { + const layerTag = this.getLayerTag(scale, this.direction, layerId); + + if (layerTag === IsometricImageFurniVisualization.THUMBNAIL) { + const assetName = (this.cacheSpriteAssetName(scale, layerId, false) + this.getFrameNumber(scale, layerId)); + const asset = this.getAsset(assetName, layerId); + const thumbnailAssetName = `${this.getThumbnailAssetName(scale)}-${this._uniqueId}`; + const transformedTexture = this.generateTransformedThumbnail(k, asset || { width: 64, height: 64, offsetX: -34, offsetY: -30 }); + + this.asset.addAsset(thumbnailAssetName, transformedTexture, true, asset?.offsetX || -34, asset?.offsetY || -30, false, false); + + const sprite = this.getSprite(layerId); + if (sprite) { + sprite.texture = transformedTexture; + } + + return; + } + + layerId++; + } + } + + protected generateTransformedThumbnail(texture: Texture, asset: IGraphicAsset): Texture { + const sprite = new Sprite(texture); + const scaleFactor = (asset?.width || 64) / texture.width; + const matrix = new Matrix(); + + switch (this.direction) { + case 2: + matrix.a = scaleFactor; + matrix.b = (-0.5 * scaleFactor); + matrix.c = 0; + matrix.d = scaleFactor; + matrix.tx = 0; + matrix.ty = (0.5 * scaleFactor * texture.width); + break; + case 0: + case 4: + matrix.a = scaleFactor; + matrix.b = (0.5 * scaleFactor); + matrix.c = 0; + matrix.d = scaleFactor; + matrix.tx = 0; + matrix.ty = 0; + break; + default: + matrix.a = scaleFactor; + matrix.b = 0; + matrix.c = 0; + matrix.d = scaleFactor; + matrix.tx = 0; + matrix.ty = 0; + } + + sprite.setFromMatrix(matrix); + + const width = 64; + const height = 64; + const renderTexture = RenderTexture.create({ width, height, resolution: 1 }); + GetRenderer().render({ container: sprite, target: renderTexture }); + + return renderTexture; + } + + protected getSpriteAssetName(scale: number, layerId: number): string { + if (this._thumbnailImageNormal && (this.getLayerTag(scale, this.direction, layerId) === IsometricImageFurniVisualization.THUMBNAIL)) { + return `${this.getThumbnailAssetName(scale)}-${this._uniqueId}`; + } + + return super.getSpriteAssetName(scale, layerId); + } + + protected getThumbnailAssetName(scale: number): string { + return this.cacheSpriteAssetName(scale, 2, false) + this.getFrameNumber(scale, 2); + } + + protected getFullThumbnailAssetName(k: number, _arg_2: number): string { + return [this._type, k, 'thumb', _arg_2].join('_'); + } +} \ No newline at end of file diff --git a/packages/room/src/renderer/cache/RoomObjectCache.ts b/packages/room/src/renderer/cache/RoomObjectCache.ts index bdff1cb..384ceab 100644 --- a/packages/room/src/renderer/cache/RoomObjectCache.ts +++ b/packages/room/src/renderer/cache/RoomObjectCache.ts @@ -89,11 +89,24 @@ export class RoomObjectCache data.height = sprite.sprite.height; data.type = sprite.sprite.type; data.posture = sprite.sprite.posture; + + console.log("Sprite data before processing:", { + name: data.name, + type: data.type, + tag: sprite.sprite.tag, // Add this line to log the tag + width: data.width, + height: data.height, + frame: data.frame, + color: data.color + }); const isSkewed = this.isSkewedSprite(sprite.sprite); - if(isSkewed) data.skew = (((sprite.sprite.direction % 4) === 0) ? -0.5 : 0.5); - + if(isSkewed) + { + data.skew = (((sprite.sprite.direction % 4) === 0) ? -0.5 : 0.5); + } + if(((((isSkewed || (sprite.name.indexOf('%image.library.url%') >= 0)) || (sprite.name.indexOf('%group.badge.url%') >= 0)) && (data.width <= RoomObjectCache.MAX_SIZE_FOR_AVG_COLOR)) && (data.height <= RoomObjectCache.MAX_SIZE_FOR_AVG_COLOR))) { //data.color = Canvas._Str_23439(sprite.sprite.texture).toString(); @@ -117,6 +130,11 @@ export class RoomObjectCache private isSkewedSprite(k: IRoomObjectSprite): boolean { if(!k.type) return false; + + console.log("Checking if sprite is skewed:", { + type: k.type, + tag: k.tag + }); if((k.type.indexOf('external_image_wallitem') === 0) && (k.tag === 'THUMBNAIL')) return true;