diff --git a/packages/room/src/object/visualization/furniture/FurnitureVisualization.ts b/packages/room/src/object/visualization/furniture/FurnitureVisualization.ts index 43ef8a2..a08cc7f 100644 --- a/packages/room/src/object/visualization/furniture/FurnitureVisualization.ts +++ b/packages/room/src/object/visualization/furniture/FurnitureVisualization.ts @@ -1,5 +1,5 @@ import { AlphaTolerance, IGraphicAsset, IObjectVisualizationData, IRoomGeometry, IRoomObjectSprite, RoomObjectVariable, RoomObjectVisualizationType } from '@nitrots/api'; -import { BlackToAlphaFilter } from '@nitrots/utils'; +import { BlackToAlphaFilter, ChooserSelectionFilter } from '@nitrots/utils'; import { BLEND_MODES, Filter, Texture } from 'pixi.js'; import { RoomObjectSpriteVisualization } from '../RoomObjectSpriteVisualization'; import { ColorData, LayerData } from '../data'; @@ -335,15 +335,21 @@ export class FurnitureVisualization extends RoomObjectSpriteVisualization sprite.posture = this.getPostureForAsset(scale, assetData.source); sprite.clickHandling = this._clickHandling; + const chooserFilters = (sprite.filters || []).filter(f => f instanceof ChooserSelectionFilter); + if(sprite.blendMode === 'add' && !this.isBackgroundColorBlack()) { if(!FurnitureVisualization._blackToAlphaFilter) FurnitureVisualization._blackToAlphaFilter = new BlackToAlphaFilter(); - sprite.filters = [FurnitureVisualization._blackToAlphaFilter]; + sprite.filters = chooserFilters.length > 0 + ? [FurnitureVisualization._blackToAlphaFilter, ...chooserFilters] + : [FurnitureVisualization._blackToAlphaFilter]; } else { - sprite.filters = this._filters; + sprite.filters = chooserFilters.length > 0 + ? [...this._filters, ...chooserFilters] + : this._filters; } } else diff --git a/packages/utils/src/filters/ChooserSelectionFilter.ts b/packages/utils/src/filters/ChooserSelectionFilter.ts new file mode 100644 index 0000000..fdc940f --- /dev/null +++ b/packages/utils/src/filters/ChooserSelectionFilter.ts @@ -0,0 +1,142 @@ +import { Color, ColorSource, Filter, FilterSystem, GlProgram, RenderSurface, Texture } from 'pixi.js'; + +export class ChooserSelectionFilter extends Filter +{ + public uniforms: { + uLineColor: Float32Array, + uColor: Float32Array, + uTime: number + }; + + private _lineColor!: Color; + private _color!: Color; + + constructor( + lineColor: ColorSource = [0.700, 0.880, 0.950], + color: ColorSource = [0.290, 0.350, 0.390] + ) + { + const glProgram = GlProgram.from({ + vertex: `in vec2 aPosition; + out vec2 vTextureCoord; + + uniform vec4 uInputSize; + uniform vec4 uOutputFrame; + uniform vec4 uOutputTexture; + + vec4 filterVertexPosition(void) + { + vec2 position = aPosition * uOutputFrame.zw + uOutputFrame.xy; + position.x = position.x * (2.0 / uOutputTexture.x) - 1.0; + position.y = position.y * (2.0*uOutputTexture.z / uOutputTexture.y) - uOutputTexture.z; + return vec4(position, 0.0, 1.0); + } + + vec2 filterTextureCoord(void) + { + return aPosition * (uOutputFrame.zw * uInputSize.zw); + } + + void main(void) + { + gl_Position = filterVertexPosition(); + vTextureCoord = filterTextureCoord(); + }`, + fragment: ` + in vec2 vTextureCoord; + out vec4 finalColor; + + uniform sampler2D uTexture; + uniform vec3 uLineColor; + uniform vec3 uColor; + uniform float uTime; + + void main(void) { + vec4 currentColor = texture(uTexture, vTextureCoord); + vec3 colorLine = uLineColor * currentColor.a; + vec3 colorOverlay = uColor * currentColor.a; + float fadeFactor = 0.75 + 0.25 * sin(uTime * 3.0); + + if(currentColor.r == 0.0 && currentColor.g == 0.0 && currentColor.b == 0.0 && currentColor.a > 0.0) { + finalColor = vec4(colorLine.r * fadeFactor, colorLine.g * fadeFactor, colorLine.b * fadeFactor, currentColor.a); + } else if(currentColor.a > 0.0) { + finalColor = vec4(colorOverlay.r * fadeFactor, colorOverlay.g * fadeFactor, colorOverlay.b * fadeFactor, currentColor.a * 0.35); + } + } + `, + name: 'chooser-selection-filter', + }); + + super({ + gpuProgram: null, + glProgram, + resources: { + chooserUniforms: { + uLineColor: { value: new Float32Array(3), type: 'vec3' }, + uColor: { value: new Float32Array(3), type: 'vec3' }, + uTime: { value: 0.0, type: 'f32' } + } + } + }); + + this.uniforms = this.resources.chooserUniforms.uniforms; + + this._lineColor = new Color(); + this.lineColor = lineColor; + + this._color = new Color(); + this.color = color; + } + + public apply( + filterManager: FilterSystem, + input: Texture, + output: RenderSurface, + clearMode: boolean, + ): void + { + filterManager.applyFilter(this, input, output, clearMode); + } + + public get lineColor(): ColorSource + { + return this._lineColor.value as ColorSource; + } + + public set lineColor(value: ColorSource) + { + this._lineColor.setValue(value); + + const [r, g, b] = this._lineColor.toArray(); + + this.uniforms.uLineColor[0] = r; + this.uniforms.uLineColor[1] = g; + this.uniforms.uLineColor[2] = b; + } + + public get color(): ColorSource + { + return this._color.value as ColorSource; + } + + public set color(value: ColorSource) + { + this._color.setValue(value); + + const [r, g, b] = this._color.toArray(); + + this.uniforms.uColor[0] = r; + this.uniforms.uColor[1] = g; + this.uniforms.uColor[2] = b; + } + + public get time(): number + { + return this.uniforms.uTime; + } + + public set time(value: number) + { + this.uniforms.uTime = value; + } +} diff --git a/packages/utils/src/filters/index.ts b/packages/utils/src/filters/index.ts index a2b018d..fa6e03d 100644 --- a/packages/utils/src/filters/index.ts +++ b/packages/utils/src/filters/index.ts @@ -1,4 +1,5 @@ export * from './BlackToAlphaFilter'; +export * from './ChooserSelectionFilter'; export * from './PaletteMapFilter'; export * from './PlaneMaskFilter'; export * from './WiredFilter';