Skip to content

Commit

Permalink
Expose Block Class Properties in Editor and Tidy Property Tab Compone…
Browse files Browse the repository at this point in the history
…nts (#57)
  • Loading branch information
alexchuber authored Oct 4, 2024
1 parent 7780ef5 commit 828cbcc
Show file tree
Hide file tree
Showing 23 changed files with 584 additions and 400 deletions.
9 changes: 9 additions & 0 deletions packages/demo/src/configuration/blocks/effects/blurBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { AggregateBlock, SmartFilter } from "@babylonjs/smart-filters";

import { DirectionalBlurBlock } from "./directionalBlurBlock";
import { BlockNames } from "../blockNames";
import { editableInPropertyPage, PropertyTypeForEdition } from "@babylonjs/smart-filters-editor";

const defaultBlurTextureRatioPerPass = 0.5;
const defaultBlurSize = 2;
Expand Down Expand Up @@ -46,6 +47,11 @@ export class BlurBlock extends AggregateBlock {
/**
* Sets how much smaller we should make the texture between the 2 consecutive bi lateral passes.
*/
@editableInPropertyPage("Pass Texture Ratio", PropertyTypeForEdition.Float, "PROPERTIES", {
min: 0,
max: 1,
notifiers: { rebuild: true },
})
public set blurTextureRatioPerPass(value: number) {
this._blurTextureRatioPerPass = value;
this._intermediateBlurV.blurTextureRatio = value;
Expand All @@ -64,6 +70,9 @@ export class BlurBlock extends AggregateBlock {
/**
* Sets how far the kernel might fetch the data from.
*/
@editableInPropertyPage("Size", PropertyTypeForEdition.Float, "PROPERTIES", {
notifiers: { rebuild: true },
})
public set blurSize(value: number) {
this._blurSize = value;
this._intermediateBlurV.blurHorizontalWidth = value;
Expand Down
11 changes: 11 additions & 0 deletions packages/demo/src/configuration/blocks/effects/compositionBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
createStrongRef,
} from "@babylonjs/smart-filters";
import { BlockNames } from "../blockNames";
import { editableInPropertyPage, PropertyTypeForEdition } from "@babylonjs/smart-filters-editor";

/** Defines that alpha blending is disabled */
export const ALPHA_DISABLE = 0;
Expand Down Expand Up @@ -232,6 +233,16 @@ export class CompositionBlock extends ShaderBlock {
/**
* Defines blend mode of the composition.
*/
@editableInPropertyPage("Alpha Mode", PropertyTypeForEdition.List, "PROPERTIES", {
notifiers: { rebuild: true },
options: [
{ label: "Disable", value: ALPHA_DISABLE },
{ label: "Add", value: ALPHA_ADD },
{ label: "Combine", value: ALPHA_COMBINE },
{ label: "Subtract", value: ALPHA_SUBTRACT },
{ label: "Multiply", value: ALPHA_MULTIPLY },
],
})
public alphaMode: number = ALPHA_COMBINE;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { Effect } from "@babylonjs/core/Materials/effect";
import type { SmartFilter, IDisableableBlock, RuntimeData } from "@babylonjs/smart-filters";
import { ShaderBlock, ConnectionPointType, ShaderBinding, injectDisableUniform } from "@babylonjs/smart-filters";
import { BlockNames } from "../blockNames";
import { editableInPropertyPage, PropertyTypeForEdition } from "@babylonjs/smart-filters-editor";

const shaderProgram = injectDisableUniform({
fragment: {
Expand Down Expand Up @@ -122,16 +123,31 @@ export class DirectionalBlurBlock extends ShaderBlock {
/**
* Defines how smaller we should make the target compared to the screen size.
*/
@editableInPropertyPage("Texture Ratio", PropertyTypeForEdition.Float, "PROPERTIES", {
min: 0,
max: 1,
notifiers: { rebuild: true },
})
public blurTextureRatio = 0.5;

/**
* Defines the horizontal strength of the blur.
*/
@editableInPropertyPage("Horizontal strength", PropertyTypeForEdition.Float, "PROPERTIES", {
min: 0,
max: 1,
notifiers: { rebuild: true },
})
public blurHorizontalWidth = 0;

/**
* Defines the vertical strength of the blur.
*/
@editableInPropertyPage("Vertical strength", PropertyTypeForEdition.Float, "PROPERTIES", {
min: 0,
max: 1,
notifiers: { rebuild: true },
})
public blurVerticalWidth = 1;

/**
Expand Down
120 changes: 85 additions & 35 deletions packages/demo/src/configuration/blocks/inputs/webCamInputBlock.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,106 @@
import { Observable } from "@babylonjs/core/Misc/observable.js";
import type { ThinEngine } from "@babylonjs/core/Engines/thinEngine.js";
import { WebCamRuntime } from "./webCamRuntime";
import { ConnectionPointType, type SmartFilter, InputBlock, createStrongRef } from "@babylonjs/smart-filters";
import type { InitializationData } from "core/src/smartFilter";
import {
editableInPropertyPage,
PropertyTypeForEdition,
type IEditablePropertyListOption,
} from "@babylonjs/smart-filters-editor";
import { Observable } from "@babylonjs/core/Misc/observable";

export type WebCamSource = {
name: string;
id: string;
/** The friendly name of the device */
label: string;
/** The deviceId */
value: string;
};

export const WebCamInputBlockName = "WebCam";

const LocalStorageWebcamIdKey = "webCamDeviceId";
const LocalStorageNameKey = "webCamName";
const DefaultWebCamSource: WebCamSource = {
label: "Default",
value: "",
};

/**
* A utility class to manage the webcam sources for the WebCamInputBlock
*/
class WebcamSourceManager {
public sources: WebCamSource[] = [];
public onSourcesLoaded: Observable<WebCamSource[]> = new Observable(undefined, true);

constructor() {
this._updateWebcamSources();
navigator.mediaDevices.addEventListener("devicechange", () => {
this._updateWebcamSources();
});
}

private async _updateWebcamSources(): Promise<void> {
let foundDefault = false;
const devices = await navigator.mediaDevices.enumerateDevices();
const sources = devices
.filter((device: MediaDeviceInfo) => device.kind === "videoinput")
.map((device: MediaDeviceInfo) => {
if (device.deviceId === "") {
foundDefault = true;
return DefaultWebCamSource;
}
return {
label: device.label,
value: device.deviceId,
};
});
if (!foundDefault) {
sources.unshift(DefaultWebCamSource);
}

// Only update if the sources have changed (sometimes, they don't)
if (JSON.stringify(this.sources) !== JSON.stringify(sources)) {
this.sources = sources;
this.onSourcesLoaded.notifyObservers(this.sources);
}
}
}

/**
* A custom InputBlock that exposes webcam feed as a texture
*/
export class WebCamInputBlock extends InputBlock<ConnectionPointType.Texture> {
private static _WebCamSourceManager: WebcamSourceManager = new WebcamSourceManager();
private readonly _engine: ThinEngine;
private _webCamRuntime: WebCamRuntime | undefined;
private _webCamSource: WebCamSource;

public get webcamSource(): WebCamSource {
return this._webCamSource;
}
public set webcamSource(webcamSource: WebCamSource) {
if (this._webCamRuntime) {
this._webCamRuntime.deviceId = webcamSource.value;
}
this._webCamSource = webcamSource;

public readonly onWebCamSourceChanged: Observable<WebCamSource> = new Observable<WebCamSource>(undefined);
// Save the last used webcam source
localStorage.setItem(LocalStorageWebcamIdKey, webcamSource.value);
localStorage.setItem(LocalStorageNameKey, webcamSource.label);
}

@editableInPropertyPage("Source", PropertyTypeForEdition.List, "PROPERTIES", {
notifiers: { update: true },
options: WebCamInputBlock._WebCamSourceManager.onSourcesLoaded as Observable<IEditablePropertyListOption[]>,
valuesAreStrings: true,
})
public set webcamSourceId(id: string) {
const source = WebCamInputBlock._WebCamSourceManager.sources.find((source) => source.value === id);
this.webcamSource = source ?? this.webcamSource;
}
public get webcamSourceId(): string {
return this._webCamSource.value;
}

constructor(smartFilter: SmartFilter, engine: ThinEngine) {
super(smartFilter, WebCamInputBlockName, ConnectionPointType.Texture, createStrongRef(null));
Expand All @@ -34,33 +111,17 @@ export class WebCamInputBlock extends InputBlock<ConnectionPointType.Texture> {
const lastWebCamName = localStorage.getItem(LocalStorageNameKey);
if (lastWebCamId && lastWebCamName) {
this._webCamSource = {
id: lastWebCamId,
name: lastWebCamName,
label: lastWebCamName,
value: lastWebCamId,
};
} else {
this._webCamSource = {
id: "",
name: "Default",
};
this._webCamSource = DefaultWebCamSource;
}

this.onWebCamSourceChanged.add(this._onWebCamSourceChanged.bind(this));
}

public static async EnumerateWebCamSources(): Promise<WebCamSource[]> {
const devices = await navigator.mediaDevices.enumerateDevices();

return devices
.filter((device: MediaDeviceInfo) => device.kind === "videoinput")
.map((device: MediaDeviceInfo) => ({
name: device.label,
id: device.deviceId,
}));
}

public initializeWebCamRuntime(): WebCamRuntime {
this._webCamRuntime = new WebCamRuntime(this._engine, this.runtimeValue);
this._webCamRuntime.deviceId = this._webCamSource.id;
this._webCamRuntime.deviceId = this._webCamSource.value;
return this._webCamRuntime;
}

Expand All @@ -70,15 +131,4 @@ export class WebCamInputBlock extends InputBlock<ConnectionPointType.Texture> {
): void {
initializationData.disposableResources.push(this.initializeWebCamRuntime());
}

private async _onWebCamSourceChanged(webCamSource: WebCamSource): Promise<void> {
if (this._webCamRuntime) {
this._webCamRuntime.deviceId = webCamSource.id;
}
this._webCamSource = webCamSource;

// Save the last used webcam source
localStorage.setItem(LocalStorageWebcamIdKey, webCamSource.id);
localStorage.setItem(LocalStorageNameKey, webCamSource.name);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { Effect } from "@babylonjs/core/Materials/effect";
import type { SmartFilter, IDisableableBlock, RuntimeData } from "@babylonjs/smart-filters";
import { ShaderBlock, ConnectionPointType, ShaderBinding, injectDisableUniform } from "@babylonjs/smart-filters";
import { BlockNames } from "../blockNames";
import { editableInPropertyPage, PropertyTypeForEdition } from "@babylonjs/smart-filters-editor";

const shaderProgram = injectDisableUniform({
fragment: {
Expand Down Expand Up @@ -122,6 +123,7 @@ export class TileBlock extends ShaderBlock {
/**
* Defines the number of tiles to use for the transition.
*/
@editableInPropertyPage("Tile Count", PropertyTypeForEdition.Int, "PROPERTIES", { notifiers: { rebuild: true } })
public tileCount = 10;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { Effect } from "@babylonjs/core/Materials/effect";
import type { SmartFilter, IDisableableBlock, RuntimeData } from "@babylonjs/smart-filters";
import { ShaderBlock, ConnectionPointType, ShaderBinding, injectDisableUniform } from "@babylonjs/smart-filters";
import { BlockNames } from "../blockNames";
import { editableInPropertyPage, PropertyTypeForEdition } from "@babylonjs/smart-filters-editor";

const shaderProgram = injectDisableUniform({
fragment: {
Expand Down Expand Up @@ -130,6 +131,11 @@ export class WipeBlock extends ShaderBlock {
/**
* Defines the angle of the wipe effect.
*/
@editableInPropertyPage("Angle", PropertyTypeForEdition.Float, "PROPERTIES", {
min: 0,
max: Math.PI * 2,
notifiers: { rebuild: true },
})
public angle = Math.PI;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export class CustomInputDisplayManager extends InputDisplayManager {

if (inputBlock.type === ConnectionPointType.Texture && inputBlock.name === WebCamInputBlockName) {
const webCamInputBlock = inputBlock as WebCamInputBlock;
value = webCamInputBlock.webcamSource?.name ?? "Default";
value = webCamInputBlock.webcamSource?.label ?? "Default";
contentArea.innerHTML = value;
} else {
return super.updatePreviewContent(nodeData, contentArea);
Expand Down

This file was deleted.

Loading

0 comments on commit 828cbcc

Please sign in to comment.