diff --git a/packages/camera/src/RoomCameraWidgetManager.ts b/packages/camera/src/RoomCameraWidgetManager.ts index 98572d7..1d28a4c 100644 --- a/packages/camera/src/RoomCameraWidgetManager.ts +++ b/packages/camera/src/RoomCameraWidgetManager.ts @@ -3,7 +3,7 @@ import { GetAssetManager } from '@nitrots/assets'; import { GetConfiguration } from '@nitrots/configuration'; import { GetEventDispatcher, RoomCameraWidgetManagerEvent } from '@nitrots/events'; import { TextureUtils } from '@nitrots/utils'; -import { BLEND_MODES, ColorMatrix, ColorMatrixFilter, Container, Filter, Sprite, Texture } from 'pixi.js'; +import { BLEND_MODES, ColorMatrix, ColorMatrixFilter, Container, Filter, RenderTexture, Sprite, Texture } from 'pixi.js'; import { RoomCameraWidgetEffect } from './RoomCameraWidgetEffect'; const COLOR_MATRIX_OFFSET_INDICES = [4, 9, 14, 19] as const; @@ -112,7 +112,12 @@ export class RoomCameraWidgetManager implements IRoomCameraWidgetManager container.filters = filters; - return await TextureUtils.generateImage(container); + const resolution = texture.source.resolution || 1; + const renderTexture = RenderTexture.create({ width: texture.width, height: texture.height, resolution }); + + TextureUtils.writeToTexture(container, renderTexture); + + return await TextureUtils.generateImage(renderTexture); } public get effects(): Map diff --git a/packages/communication/src/messages/outgoing/camera/RenderRoomMessageComposer.ts b/packages/communication/src/messages/outgoing/camera/RenderRoomMessageComposer.ts index cf4c3ac..2089f69 100644 --- a/packages/communication/src/messages/outgoing/camera/RenderRoomMessageComposer.ts +++ b/packages/communication/src/messages/outgoing/camera/RenderRoomMessageComposer.ts @@ -1,7 +1,10 @@ import { IMessageComposer } from '@nitrots/api'; -import { TextureUtils } from '@nitrots/utils'; +import { NitroLogger, TextureUtils } from '@nitrots/utils'; import { RenderTexture } from 'pixi.js'; +const MAX_IMAGE_BYTES = 2 * 1024 * 1024; +const PNG_MAGIC_BYTES = [0x89, 0x50, 0x4E, 0x47]; + export class RenderRoomMessageComposer implements IMessageComposer> { private _data: any; @@ -27,16 +30,63 @@ export class RenderRoomMessageComposer implements IMessageComposer c.charCodeAt(0)); - - this._data.push(binaryData.byteLength, binaryData.buffer); + this.processBase64(url); } public assignBase64(base64: string): void { + this.processBase64(base64); + } + + private processBase64(base64: string): void + { + if(!base64 || !base64.includes(',')) + { + NitroLogger.error('Camera: invalid base64 data URL'); + return; + } + + if(!base64.startsWith('data:image/png')) + { + NitroLogger.error('Camera: rejected non-PNG image data'); + return; + } + const base64Data = base64.split(',')[1]; - const binaryData = Uint8Array.from(atob(base64Data), c => c.charCodeAt(0)); + + if(!base64Data || !base64Data.length) + { + NitroLogger.error('Camera: empty base64 payload'); + return; + } + + let binaryData: Uint8Array; + + try + { + binaryData = Uint8Array.from(atob(base64Data), c => c.charCodeAt(0)); + } + catch(e) + { + NitroLogger.error('Camera: failed to decode base64 data'); + return; + } + + if(binaryData.byteLength > MAX_IMAGE_BYTES) + { + NitroLogger.error(`Camera: image too large (${binaryData.byteLength} bytes, max ${MAX_IMAGE_BYTES})`); + return; + } + + if(binaryData.length < 4 + || binaryData[0] !== PNG_MAGIC_BYTES[0] + || binaryData[1] !== PNG_MAGIC_BYTES[1] + || binaryData[2] !== PNG_MAGIC_BYTES[2] + || binaryData[3] !== PNG_MAGIC_BYTES[3]) + { + NitroLogger.error('Camera: binary data does not have valid PNG header'); + return; + } this._data.push(binaryData.byteLength, binaryData.buffer); } diff --git a/packages/room/src/object/visualization/avatar/AvatarVisualization.ts b/packages/room/src/object/visualization/avatar/AvatarVisualization.ts index 59b2f6a..ff2323e 100644 --- a/packages/room/src/object/visualization/avatar/AvatarVisualization.ts +++ b/packages/room/src/object/visualization/avatar/AvatarVisualization.ts @@ -30,7 +30,7 @@ export class AvatarVisualization extends RoomObjectSpriteVisualization implement private static BASE_Y_SCALE: number = 1000; private static AVATAR_SPRITE_DEFAULT_DEPTH: number = -0.01; private static AVATAR_OWN_DEPTH_ADJUST: number = 0.001; - private static AVATAR_SPRITE_LAYING_DEPTH: number = 0.2; + private static AVATAR_SPRITE_LAYING_DEPTH: number = 0.002; protected _data: AvatarVisualizationData;