Quellcode durchsuchen

extending PBREnv support and making sure config is updated
mainColor is now correctly updated as well.

Raanan Weber vor 7 Jahren
Ursprung
Commit
86c993ba57

+ 16 - 1
Viewer/src/configuration/configuration.ts

@@ -65,7 +65,22 @@ export interface ViewerConfiguration {
         }
         hideLoadingDelay?: number;
         environmentAssetsRootURL?: string;
-        environmentMap?: string;
+        environmentMap?: {
+            /**
+             * Environment map texture path in relative to the asset folder.
+             */
+            texture: string;
+
+            /**
+             * Default rotation to apply to the environment map.
+             */
+            rotationY: number;
+
+            /**
+             * Tint level of the main color on the environment map.
+             */
+            tintLevel: number;
+        }
     }
 }
 

+ 8 - 0
Viewer/src/configuration/types/extendedDefault.ts

@@ -99,5 +99,13 @@ export let extendedDefaultConfiguration: ViewerConfiguration = {
             emissiveIntensity: 1.04,
             environmentIntensity: 0.268
         }
+    },
+    lab: {
+        environmentAssetsRootURL: '/assets/environment/',
+        environmentMap: {
+            texture: 'EnvMap_2.0-256.env',
+            rotationY: 0,
+            tintLevel: 0.4
+        }
     }
 }

+ 255 - 0
Viewer/src/labs/texture.ts

@@ -152,4 +152,259 @@ export class TextureCube {
      * @param source An array containing mipmap levels of faces, where each mipmap level is an array of faces and each face is a TextureSource object
      */
     constructor(public internalFormat: PixelFormat, public type: PixelType, public source: MipmapsCube = []) { }
+}
+
+/**
+     * A static class providing methods to aid working with Bablyon textures.
+     */
+export class TextureUtils {
+
+    /**
+     * A prefix used when storing a babylon texture object reference on a Spectre texture object
+     */
+    public static BabylonTextureKeyPrefix = '__babylonTexture_';
+
+    /**
+     * Controls anisotropic filtering for deserialized textures.
+     */
+    public static MaxAnisotropy = 4;
+
+    /**
+     * Returns a BabylonCubeTexture instance from a Spectre texture cube, subject to sampling parameters.
+     * If such a texture has already been requested in the past, this texture will be returned, otherwise a new one will be created.
+     * The advantage of this is to enable working with texture objects without the need to initialize on the GPU until desired.
+     * @param scene A Babylon Scene instance
+     * @param textureCube A Spectre TextureCube object
+     * @param parameters WebGL texture sampling parameters
+     * @param automaticMipmaps Pass true to enable automatic mipmap generation where possible (requires power of images)
+     * @param environment Specifies that the texture will be used as an environment
+     * @param singleLod Specifies that the texture will be a singleLod (for environment)
+     * @return Babylon cube texture
+     */
+    public static GetBabylonCubeTexture(scene: BABYLON.Scene, textureCube: TextureCube, automaticMipmaps: boolean, environment = false, singleLod = false): BABYLON.CubeTexture {
+        if (!textureCube) throw new Error("no texture cube provided");
+
+        var parameters: SamplingParameters;
+        if (environment) {
+            parameters = singleLod ? TextureUtils._EnvironmentSingleMipSampling : TextureUtils._EnvironmentSampling;
+        }
+        else {
+            parameters = {
+                magFilter: TextureMagFilter.NEAREST,
+                minFilter: TextureMinFilter.NEAREST,
+                wrapS: TextureWrapMode.CLAMP_TO_EDGE,
+                wrapT: TextureWrapMode.CLAMP_TO_EDGE
+            };
+        }
+
+        let key = TextureUtils.BabylonTextureKeyPrefix + parameters.magFilter + '' + parameters.minFilter + '' + parameters.wrapS + '' + parameters.wrapT;
+
+        let babylonTexture: BABYLON.CubeTexture = (<any>textureCube)[key];
+
+        if (!babylonTexture) {
+
+            //initialize babylon texture
+            babylonTexture = new BABYLON.CubeTexture('', scene);
+            if (environment) {
+                babylonTexture.lodGenerationOffset = TextureUtils.EnvironmentLODOffset;
+                babylonTexture.lodGenerationScale = TextureUtils.EnvironmentLODScale;
+            }
+
+            babylonTexture.gammaSpace = false;
+
+            let internalTexture = new BABYLON.InternalTexture(scene.getEngine(), BABYLON.InternalTexture.DATASOURCE_CUBERAW);
+            let glTexture = internalTexture._webGLTexture;
+            //babylon properties
+            internalTexture.isCube = true;
+            internalTexture.generateMipMaps = false;
+
+            babylonTexture._texture = internalTexture;
+
+            TextureUtils.ApplySamplingParameters(babylonTexture, parameters);
+
+            let maxMipLevel = automaticMipmaps ? 0 : textureCube.source.length - 1;
+            let texturesUploaded = 0;
+
+            var textureComplete = function () {
+                return texturesUploaded === ((maxMipLevel + 1) * 6);
+            };
+
+            var uploadFace = function (i: number, level: number, face: TextureSource) {
+                if (!glTexture) return;
+
+                if (i === 0 && level === 0) {
+                    internalTexture.width = face.width;
+                    internalTexture.height = face.height;
+                }
+
+                let gl = (<any>(scene.getEngine()))._gl;
+                gl.bindTexture(gl.TEXTURE_CUBE_MAP, glTexture);
+                gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 0);
+                if (face instanceof HTMLElement || face instanceof ImageData) {
+                    gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, level, textureCube.internalFormat, textureCube.internalFormat, textureCube.type, <any>face);
+                } else {
+                    let textureData = <TextureData>face;
+                    gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, level, textureCube.internalFormat, textureData.width, textureData.height, 0, textureData.format, textureCube.type, textureData.data);
+                }
+
+                texturesUploaded++;
+
+                if (textureComplete()) {
+                    //generate mipmaps
+                    if (automaticMipmaps) {
+                        let w = face.width;
+                        let h = face.height;
+                        let isPot = (((w !== 0) && (w & (w - 1))) === 0) && (((h !== 0) && (h & (h - 1))) === 0);
+                        if (isPot) {
+                            gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
+                        }
+                    }
+
+                    // Upload Separate lods in case there is no support for texture lod.
+                    if (environment && !scene.getEngine().getCaps().textureLOD && !singleLod) {
+                        const mipSlices = 3;
+                        for (let i = 0; i < mipSlices; i++) {
+                            let lodKey = TextureUtils.BabylonTextureKeyPrefix + 'lod' + i;
+                            let lod: BABYLON.CubeTexture = (<any>textureCube)[lodKey];
+
+                            //initialize lod texture if it doesn't already exist
+                            if (lod == null && textureCube.Width) {
+                                //compute LOD from even spacing in smoothness (matching shader calculation)
+                                let smoothness = i / (mipSlices - 1);
+                                let roughness = 1 - smoothness;
+                                const kMinimumVariance = 0.0005;
+                                let alphaG = roughness * roughness + kMinimumVariance;
+                                let microsurfaceAverageSlopeTexels = alphaG * textureCube.Width;
+
+                                let environmentSpecularLOD = TextureUtils.EnvironmentLODScale * (BABYLON.Scalar.Log2(microsurfaceAverageSlopeTexels)) + TextureUtils.EnvironmentLODOffset;
+
+                                let maxLODIndex = textureCube.source.length - 1;
+                                let mipmapIndex = Math.min(Math.max(Math.round(environmentSpecularLOD), 0), maxLODIndex);
+
+                                lod = TextureUtils.GetBabylonCubeTexture(scene, new TextureCube(PixelFormat.RGBA, PixelType.UNSIGNED_BYTE, [textureCube.source[mipmapIndex]]), false, true, true);
+
+                                if (i === 0) {
+                                    internalTexture._lodTextureLow = lod;
+                                }
+                                else if (i === 1) {
+                                    internalTexture._lodTextureMid = lod;
+                                }
+                                else {
+                                    internalTexture._lodTextureHigh = lod;
+                                }
+
+                                (<any>textureCube)[lodKey] = lod;
+                            }
+                        }
+                    }
+
+                    internalTexture.isReady = true;
+                }
+
+                gl.bindTexture(gl.TEXTURE_CUBE_MAP, null);
+                scene.getEngine().resetTextureCache();
+            };
+
+            for (let i = 0; i <= maxMipLevel; i++) {
+                let faces = textureCube.source[i];
+                for (let j = 0; j < faces.length; j++) {
+                    let face = faces[j];
+                    if (face instanceof HTMLImageElement && !face.complete) {
+                        face.addEventListener('load', () => {
+                            uploadFace(j, i, face);
+                        }, false);
+                    } else {
+                        uploadFace(j, i, face);
+                    }
+                }
+            }
+
+            scene.getEngine().resetTextureCache();
+
+            babylonTexture.isReady = () => {
+                return textureComplete();
+            };
+
+            (<any>textureCube)[key] = babylonTexture;
+        }
+
+        return babylonTexture;
+    }
+
+    /**
+     * Applies Spectre SamplingParameters to a Babylon texture by directly setting texture parameters on the internal WebGLTexture as well as setting Babylon fields
+     * @param babylonTexture Babylon texture to apply texture to (requires the Babylon texture has an initialize _texture field)
+     * @param parameters Spectre SamplingParameters to apply
+     */
+    public static ApplySamplingParameters(babylonTexture: BABYLON.BaseTexture, parameters: SamplingParameters) {
+        let scene = babylonTexture.getScene();
+        if (!scene) return;
+        let gl = (<any>(scene.getEngine()))._gl;
+
+        let target = babylonTexture.isCube ? gl.TEXTURE_CUBE_MAP : gl.TEXTURE_2D;
+
+        let internalTexture = babylonTexture._texture;
+        if (!internalTexture) return;
+        let glTexture = internalTexture._webGLTexture;
+        gl.bindTexture(target, glTexture);
+
+        if (parameters.magFilter != null) gl.texParameteri(target, gl.TEXTURE_MAG_FILTER, parameters.magFilter);
+        if (parameters.minFilter != null) gl.texParameteri(target, gl.TEXTURE_MIN_FILTER, parameters.minFilter);
+        if (parameters.wrapS != null) gl.texParameteri(target, gl.TEXTURE_WRAP_S, parameters.wrapS);
+        if (parameters.wrapT != null) gl.texParameteri(target, gl.TEXTURE_WRAP_T, parameters.wrapT);
+
+        //set babylon wrap modes from sampling parameter
+        switch (parameters.wrapS) {
+            case TextureWrapMode.REPEAT: babylonTexture.wrapU = BABYLON.Texture.WRAP_ADDRESSMODE; break;
+            case TextureWrapMode.CLAMP_TO_EDGE: babylonTexture.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE; break;
+            case TextureWrapMode.MIRRORED_REPEAT: babylonTexture.wrapU = BABYLON.Texture.MIRROR_ADDRESSMODE; break;
+            default: babylonTexture.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
+        }
+
+        switch (parameters.wrapT) {
+            case TextureWrapMode.REPEAT: babylonTexture.wrapV = BABYLON.Texture.WRAP_ADDRESSMODE; break;
+            case TextureWrapMode.CLAMP_TO_EDGE: babylonTexture.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE; break;
+            case TextureWrapMode.MIRRORED_REPEAT: babylonTexture.wrapV = BABYLON.Texture.MIRROR_ADDRESSMODE; break;
+            default: babylonTexture.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
+        }
+
+        if (parameters.maxAnisotropy != null && parameters.maxAnisotropy > 1) {
+            let anisotropicExt = gl.getExtension('EXT_texture_filter_anisotropic');
+            if (anisotropicExt) {
+                let maxAnisotropicSamples = gl.getParameter(anisotropicExt.MAX_TEXTURE_MAX_ANISOTROPY_EXT);
+                let maxAnisotropy = Math.min(parameters.maxAnisotropy, maxAnisotropicSamples);
+                gl.texParameterf(target, anisotropicExt.TEXTURE_MAX_ANISOTROPY_EXT, maxAnisotropy);
+                babylonTexture.anisotropicFilteringLevel = maxAnisotropy;
+            }
+        }
+
+        gl.bindTexture(target, null);
+        scene.getEngine().resetTextureCache();
+    }
+
+    private static _EnvironmentSampling: SamplingParameters = {
+        magFilter: TextureMagFilter.LINEAR,
+        minFilter: TextureMinFilter.LINEAR_MIPMAP_LINEAR,
+        wrapS: TextureWrapMode.CLAMP_TO_EDGE,
+        wrapT: TextureWrapMode.CLAMP_TO_EDGE,
+        maxAnisotropy: 1
+    };
+
+    private static _EnvironmentSingleMipSampling: SamplingParameters = {
+        magFilter: TextureMagFilter.LINEAR,
+        minFilter: TextureMinFilter.LINEAR,
+        wrapS: TextureWrapMode.CLAMP_TO_EDGE,
+        wrapT: TextureWrapMode.CLAMP_TO_EDGE,
+        maxAnisotropy: 1
+    };
+
+    //from "/Internal/Lighting.EnvironmentFilterScale" in Engine/*/Configuration.cpp
+    /**
+     * Environment preprocessing dedicated value (Internal Use or Advanced only).
+     */
+    public static EnvironmentLODScale = 0.8;
+    /**
+     * Environment preprocessing dedicated value (Internal Use or Advanced only)..
+     */
+    public static EnvironmentLODOffset = 1.0;
 }

+ 64 - 7
Viewer/src/labs/viewerLabs.ts

@@ -1,13 +1,31 @@
 import { PBREnvironment, EnvironmentDeserializer } from "./environmentSerializer";
 import { SceneManager } from '../viewer/sceneManager';
 
-import { Tools } from 'babylonjs';
+import { Tools, Quaternion } from 'babylonjs';
 import { ViewerConfiguration } from "../configuration/configuration";
+import { TextureUtils } from "./texture";
 
 export class ViewerLabs {
 
+    constructor(private _sceneManager: SceneManager) { }
+
     public environmentAssetsRootURL: string;
-    public environment: PBREnvironment;
+    public environment: PBREnvironment = {
+        //irradiance
+        irradiancePolynomialCoefficients: {
+            x: new BABYLON.Vector3(0, 0, 0),
+            y: new BABYLON.Vector3(0, 0, 0),
+            z: new BABYLON.Vector3(0, 0, 0),
+            xx: new BABYLON.Vector3(0, 0, 0),
+            yy: new BABYLON.Vector3(0, 0, 0),
+            zz: new BABYLON.Vector3(0, 0, 0),
+            yz: new BABYLON.Vector3(0, 0, 0),
+            zx: new BABYLON.Vector3(0, 0, 0),
+            xy: new BABYLON.Vector3(0, 0, 0)
+        },
+
+        textureIntensityScale: 1.0
+    };
 
     /**
          * Loads an environment map from a given URL
@@ -16,7 +34,7 @@ export class ViewerLabs {
          * @param onProgress Callback fired at progress events while loading the environment map
          * @param onError Callback fired when the load fails
          */
-    public loadEnvironment(sceneManager: SceneManager, url: string, onSuccess?: (env: PBREnvironment) => void, onProgress?: (bytesLoaded: number, bytesTotal: number) => void, onError?: (e: any) => void): void;
+    public loadEnvironment(url: string, onSuccess?: (env: PBREnvironment) => void, onProgress?: (bytesLoaded: number, bytesTotal: number) => void, onError?: (e: any) => void): void;
     /**
      * Loads an environment map from a given URL
      * @param buffer ArrayBuffer containing environment map
@@ -24,7 +42,7 @@ export class ViewerLabs {
      * @param onProgress Callback fired at progress events while loading the environment map
      * @param onError Callback fired when the load fails
      */
-    public loadEnvironment(sceneManager: SceneManager, buffer: ArrayBuffer, onSuccess?: (env: PBREnvironment) => void, onProgress?: (bytesLoaded: number, bytesTotal: number) => void, onError?: (e: any) => void): void;
+    public loadEnvironment(buffer: ArrayBuffer, onSuccess?: (env: PBREnvironment) => void, onProgress?: (bytesLoaded: number, bytesTotal: number) => void, onError?: (e: any) => void): void;
     /**
      * Sets the environment to an already loaded environment
      * @param env PBREnvironment instance
@@ -32,15 +50,15 @@ export class ViewerLabs {
      * @param onProgress Callback fired at progress events while loading the environment map
      * @param onError Callback fired when the load fails
      */
-    public loadEnvironment(sceneManager: SceneManager, env: PBREnvironment, onSuccess?: (env: PBREnvironment) => void, onProgress?: (bytesLoaded: number, bytesTotal: number) => void, onError?: (e: any) => void): void;
-    public loadEnvironment(sceneManager: SceneManager, data: string | ArrayBuffer | PBREnvironment, onSuccess?: (env: PBREnvironment) => void, onProgress?: (bytesLoaded: number, bytesTotal: number) => void, onError?: (e: any) => void): void {
+    public loadEnvironment(env: PBREnvironment, onSuccess?: (env: PBREnvironment) => void, onProgress?: (bytesLoaded: number, bytesTotal: number) => void, onError?: (e: any) => void): void;
+    public loadEnvironment(data: string | ArrayBuffer | PBREnvironment, onSuccess?: (env: PBREnvironment) => void, onProgress?: (bytesLoaded: number, bytesTotal: number) => void, onError?: (e: any) => void): void {
         //@! todo: should loadEnvironment cancel any currently loading environments?
         if (data instanceof ArrayBuffer) {
             this.environment = EnvironmentDeserializer.Parse(data);
             if (onSuccess) onSuccess(this.environment);
         } else if (typeof data === 'string') {
             let url = this.getEnvironmentAssetUrl(data);
-            sceneManager.scene._loadFile(
+            this._sceneManager.scene._loadFile(
                 url,
                 (arrayBuffer: ArrayBuffer) => {
                     this.environment = EnvironmentDeserializer.Parse(arrayBuffer);
@@ -63,6 +81,45 @@ export class ViewerLabs {
     }
 
     /**
+     * Applies an `EnvironmentMapConfiguration` to the scene
+     * @param environmentMapConfiguration Environment map configuration to apply
+     */
+    public applyEnvironmentMapConfiguration(rotationY?: number) {
+        if (!this.environment) return;
+
+        //set orientation
+        let rotatquatRotationionY = Quaternion.RotationAxis(BABYLON.Axis.Y, rotationY || 0);
+
+        // Add env texture to the scene.
+        if (this.environment.specularTexture) {
+            // IE crashes when disposing the old texture and setting a new one
+            if (!this._sceneManager.scene.environmentTexture) {
+                this._sceneManager.scene.environmentTexture = TextureUtils.GetBabylonCubeTexture(this._sceneManager.scene, this.environment.specularTexture, false, true);
+            }
+            if (this._sceneManager.scene.environmentTexture) {
+                this._sceneManager.scene.environmentTexture.level = this.environment.textureIntensityScale;
+                this._sceneManager.scene.environmentTexture.invertZ = true;
+                this._sceneManager.scene.environmentTexture.lodLevelInAlpha = true;
+
+                var poly = this._sceneManager.scene.environmentTexture.sphericalPolynomial || new BABYLON.SphericalPolynomial();
+                poly.x = this.environment.irradiancePolynomialCoefficients.x;
+                poly.y = this.environment.irradiancePolynomialCoefficients.y;
+                poly.z = this.environment.irradiancePolynomialCoefficients.z;
+                poly.xx = this.environment.irradiancePolynomialCoefficients.xx;
+                poly.xy = this.environment.irradiancePolynomialCoefficients.xy;
+                poly.yy = this.environment.irradiancePolynomialCoefficients.yy;
+                poly.yz = this.environment.irradiancePolynomialCoefficients.yz;
+                poly.zx = this.environment.irradiancePolynomialCoefficients.zx;
+                poly.zz = this.environment.irradiancePolynomialCoefficients.zz;
+                this._sceneManager.scene.environmentTexture.sphericalPolynomial = poly;
+
+                //set orientation
+                BABYLON.Matrix.FromQuaternionToRef(rotatquatRotationionY, this._sceneManager.scene.environmentTexture.getReflectionTextureMatrix());
+            }
+        }
+    }
+
+    /**
      * Get an environment asset url by using the configuration if the path is not absolute.
      * @param url Asset url
      * @returns The Asset url using the `environmentAssetsRootURL` if the url is not an absolute path.

+ 38 - 20
Viewer/src/viewer/sceneManager.ts

@@ -65,7 +65,8 @@ export class SceneManager {
      */
     private _hdrSupport: boolean;
 
-    private _mainColor: Color3;
+    private _mainColor: Color3 = Color3.White();
+    private readonly _white = Color3.White();
 
     //Labs!
     public labs: ViewerLabs;
@@ -94,7 +95,7 @@ export class SceneManager {
             return this._initEnvironment(model);
         });
 
-        this.labs = new ViewerLabs();
+        this.labs = new ViewerLabs(this);
     }
 
     /**
@@ -185,20 +186,50 @@ export class SceneManager {
      */
     public updateConfiguration(newConfiguration: Partial<ViewerConfiguration>, globalConfiguration: ViewerConfiguration) {
 
-        if (globalConfiguration.lab) {
-            if (globalConfiguration.lab.environmentAssetsRootURL) {
-                this.labs.environmentAssetsRootURL = globalConfiguration.lab.environmentAssetsRootURL;
+        if (newConfiguration.lab) {
+            if (newConfiguration.lab.environmentAssetsRootURL) {
+                this.labs.environmentAssetsRootURL = newConfiguration.lab.environmentAssetsRootURL;
             }
 
-            if (globalConfiguration.lab.environmentMap) {
-                this.labs.loadEnvironment(this, globalConfiguration.lab.environmentMap);
+            if (newConfiguration.lab.environmentMap) {
+                let rot = newConfiguration.lab.environmentMap.rotationY;
+                this.labs.loadEnvironment(newConfiguration.lab.environmentMap.texture, () => {
+                    this.labs.applyEnvironmentMapConfiguration(rot);
+                });
+
+                if (!newConfiguration.lab.environmentMap.texture && newConfiguration.lab.environmentMap.rotationY) {
+                    this.labs.applyEnvironmentMapConfiguration(newConfiguration.lab.environmentMap.rotationY);
+                }
             }
         }
 
         // update scene configuration
         if (newConfiguration.scene) {
             this._configureScene(newConfiguration.scene);
+
+            // process mainColor changes:
+            if (newConfiguration.scene.mainColor) {
+                let mc = newConfiguration.scene.mainColor;
+                if (mc.r !== undefined) {
+                    this._mainColor.r = mc.r;
+                }
+                if (mc.g !== undefined) {
+                    this._mainColor.g = mc.g
+                }
+                if (mc.b !== undefined) {
+                    this._mainColor.b = mc.b
+                }
+
+                this._mainColor.toLinearSpaceToRef(this._mainColor);
+                let exposure = Math.pow(2.0, -((globalConfiguration.camera && globalConfiguration.camera.exposure) || 0.75)) * Math.PI;
+                this._mainColor.scaleToRef(1 / exposure, this._mainColor);
+                let environmentTint = (globalConfiguration.lab && globalConfiguration.lab.environmentMap && globalConfiguration.lab.environmentMap.tintLevel) || 0;
+                this._mainColor = BABYLON.Color3.Lerp(this._white, this._mainColor, environmentTint);
+            }
         }
+
+
+
         // optimizer
         if (newConfiguration.optimizer) {
             this._configureOptimizer(newConfiguration.optimizer);
@@ -268,19 +299,6 @@ export class SceneManager {
             this.scene.environmentTexture = environmentTexture;
         }
 
-        if (sceneConfig.mainColor) {
-            let mc = sceneConfig.mainColor;
-            if (mc.r !== undefined) {
-                this._mainColor.r = mc.r;
-            }
-            if (mc.g !== undefined) {
-                this._mainColor.g = mc.g
-            }
-            if (mc.b !== undefined) {
-                this._mainColor.b = mc.b
-            }
-        }
-
         this.onSceneConfiguredObservable.notifyObservers({
             sceneManager: this,
             object: this.scene,

+ 4 - 1
Viewer/src/viewer/viewer.ts

@@ -172,7 +172,10 @@ export abstract class AbstractViewer {
             if (this._configuration.observers) {
                 this._configureObservers(this._configuration.observers);
             }
-            //this.updateConfiguration(configuration);
+            this.onSceneInitObservable.add(() => {
+                this.updateConfiguration(configuration);
+            });
+            //
 
             // initialize the templates
             let templateConfiguration = this._configuration.templates || {};