David Catuhe %!s(int64=7) %!d(string=hai) anos
pai
achega
8d94f1d29c

+ 48 - 0
Viewer/dist/loadModelManually.html

@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html lang="en">
+
+    <head>
+        <meta charset="UTF-8">
+        <meta name="viewport" content="width=device-width, initial-scale=1.0">
+        <meta http-equiv="X-UA-Compatible" content="ie=edge">
+        <title>BabylonJS Viewer - Basic usage</title>
+        <style>
+            babylon {
+                max-width: 800px;
+                max-height: 500px;
+                width: 100%;
+                height: 600px;
+            }
+        </style>
+    </head>
+
+    <body>
+        <babylon id="babylon-viewer" camera.behaviors.auto-rotate="0"></babylon>
+        <script src="viewer.js"></script>
+        <script>
+            BabylonViewer.viewerManager.getViewerPromiseById('babylon-viewer').then(function (viewer) {
+                // this will resolve only after the viewer with this specific ID is initialized
+
+                viewer.onEngineInitObservable.add(function (scene) {
+                    viewer.loadModel({
+                        title: "Helmet",
+                        subtitle: "BabylonJS",
+                        thumbnail: "https://www.babylonjs.com/img/favicon/apple-icon-144x144.png",
+                        url: "https://www.babylonjs.com/Assets/DamagedHelmet/glTF/DamagedHelmet.gltf"
+                    });
+                });
+
+                // load another model after 20 seconds. Just for fun.
+                setTimeout(() => {
+                    viewer.loadModel({
+                        title: "Rabbit",
+                        subtitle: "BabylonJS",
+                        thumbnail: "https://www.babylonjs.com/img/favicon/apple-icon-144x144.png",
+                        url: "https://playground.babylonjs.com/scenes/Rabbit.babylon"
+                    });
+                }, 20000)
+            });
+        </script>
+    </body>
+
+</html>

+ 20 - 14
Viewer/src/configuration/loader.ts

@@ -14,9 +14,9 @@ export class ConfigurationLoader {
 
     public loadConfiguration(initConfig: ViewerConfiguration = {}): Promise<ViewerConfiguration> {
 
-        let loadedConfig = deepmerge({}, initConfig);
+        let loadedConfig: ViewerConfiguration = deepmerge({}, initConfig);
 
-        let extendedConfiguration = getConfigurationType(loadedConfig && loadedConfig.extends);
+        let extendedConfiguration = getConfigurationType(loadedConfig.extends || "");
 
         loadedConfig = deepmerge(extendedConfiguration, loadedConfig);
 
@@ -24,23 +24,33 @@ export class ConfigurationLoader {
 
             let mapperType = "json";
             return Promise.resolve().then(() => {
-                if (typeof loadedConfig.configuration === "string" || loadedConfig.configuration.url) {
+                if (typeof loadedConfig.configuration === "string" || (loadedConfig.configuration && loadedConfig.configuration.url)) {
                     // a file to load
-                    let url = loadedConfig.configuration;
+
+                    let url: string = '';
+                    if (typeof loadedConfig.configuration === "string") {
+                        url = loadedConfig.configuration;
+                    }
 
                     // if configuration is an object
-                    if (loadedConfig.configuration.url) {
+                    if (typeof loadedConfig.configuration === "object" && loadedConfig.configuration.url) {
                         url = loadedConfig.configuration.url;
-                        mapperType = loadedConfig.configuration.mapper;
-                        if (!mapperType) {
+                        let type = loadedConfig.configuration.mapper;
+                        // empty string?
+                        if (!type) {
                             // load mapper type from filename / url
-                            mapperType = loadedConfig.configuration.url.split('.').pop();
+                            type = loadedConfig.configuration.url.split('.').pop();
                         }
+                        mapperType = type || mapperType;
                     }
                     return this.loadFile(url);
                 } else {
-                    mapperType = loadedConfig.configuration.mapper || mapperType;
-                    return loadedConfig.configuration.payload || {};
+                    if (typeof loadedConfig.configuration === "object") {
+                        mapperType = loadedConfig.configuration.mapper || mapperType;
+                        return loadedConfig.configuration.payload || {};
+                    }
+                    return {};
+
                 }
             }).then((data: any) => {
                 let mapper = mapperManager.getMapper(mapperType);
@@ -52,10 +62,6 @@ export class ConfigurationLoader {
         }
     }
 
-    public getConfigurationType(type: string) {
-
-    }
-
     private loadFile(url: string): Promise<any> {
         let cacheReference = this.configurationCache;
         if (cacheReference[url]) {

+ 3 - 1
Viewer/src/index.ts

@@ -15,10 +15,12 @@ import 'babylonjs';
 import 'babylonjs-loaders';
 import '../assets/pep.min';
 
+import { PromisePolyfill } from 'babylonjs';
+
 import { InitTags } from './initializer';
 
 // promise polyfill, if needed!
-global.Promise = typeof Promise === 'undefined' ? require('es6-promise').Promise : Promise;
+PromisePolyfill.Apply();
 
 export let disableInit: boolean = false;
 document.addEventListener("DOMContentLoaded", function (event) {

+ 52 - 15
Viewer/src/templateManager.ts

@@ -195,6 +195,7 @@ export class Template {
     public initPromise: Promise<Template>;
 
     private fragment: DocumentFragment;
+    private htmlTemplate: string;
 
     constructor(public name: string, private _configuration: ITemplateConfiguration) {
         this.onInit = new Observable<Template>();
@@ -216,6 +217,7 @@ export class Template {
 
         this.initPromise = htmlContentPromise.then(htmlTemplate => {
             if (htmlTemplate) {
+                this.htmlTemplate = htmlTemplate;
                 let compiledTemplate = Handlebars.compile(htmlTemplate);
                 let config = this._configuration.params || {};
                 let rawHtml = compiledTemplate(config);
@@ -228,6 +230,21 @@ export class Template {
         });
     }
 
+    public updateParams(params: { [key: string]: string | number | boolean | object }) {
+        this._configuration.params = params;
+        // update the template
+        if (this.isLoaded) {
+            this.dispose();
+        }
+        let compiledTemplate = Handlebars.compile(this.htmlTemplate);
+        let config = this._configuration.params || {};
+        let rawHtml = compiledTemplate(config);
+        this.fragment = document.createRange().createContextualFragment(rawHtml);
+        if (this.parent) {
+            this.appendTo(this.parent, true);
+        }
+    }
+
     public get configuration(): ITemplateConfiguration {
         return this._configuration;
     }
@@ -246,23 +263,25 @@ export class Template {
         return childrenArray;
     }
 
-    public appendTo(parent: HTMLElement) {
+    public appendTo(parent: HTMLElement, forceRemove?: boolean) {
         if (this.parent) {
-            console.error('Already appanded to ', this.parent);
-        } else {
-            this.parent = parent;
-
-            if (this._configuration.id) {
-                this.parent.id = this._configuration.id;
+            if (forceRemove) {
+                this.parent.removeChild(this.fragment);
+            } else {
+                return;
             }
-            this.parent.appendChild(this.fragment);
-            // appended only one frame after.
-            setTimeout(() => {
-                this.registerEvents();
-                this.onAppended.notifyObservers(this);
-            });
         }
+        this.parent = parent;
 
+        if (this._configuration.id) {
+            this.parent.id = this._configuration.id;
+        }
+        this.fragment = this.parent.appendChild(this.fragment);
+        // appended only one frame after.
+        setTimeout(() => {
+            this.registerEvents();
+            this.onAppended.notifyObservers(this);
+        });
     }
 
     public show(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template> {
@@ -304,10 +323,21 @@ export class Template {
         this.onLoaded.clear();
         this.onStateChange.clear();
         this.isLoaded = false;
+        // remove from parent
+        this.parent.removeChild(this.fragment);
     }
 
+    private registeredEvents: Array<{ htmlElement: HTMLElement, eventName: string, function: EventListenerOrEventListenerObject }>;
+
     // TODO - Should events be removed as well? when are templates disposed?
     private registerEvents() {
+        this.registeredEvents = this.registeredEvents || [];
+        if (this.registeredEvents.length) {
+            // first remove the registered events
+            this.registeredEvents.forEach(evt => {
+                evt.htmlElement.removeEventListener(evt.eventName, evt.function);
+            });
+        }
         if (this._configuration.events) {
             for (let eventName in this._configuration.events) {
                 if (this._configuration.events && this._configuration.events[eventName]) {
@@ -327,14 +357,21 @@ export class Template {
                                 selector = '#' + selector;
                             }
                             let htmlElement = <HTMLElement>this.parent.querySelector(selector);
-                            htmlElement && htmlElement.addEventListener(eventName, functionToFire.bind(this, selector), false)
+                            if (htmlElement) {
+                                let binding = functionToFire.bind(this, selector);
+                                htmlElement.addEventListener(eventName, binding, false);
+                                this.registeredEvents.push({
+                                    htmlElement: htmlElement,
+                                    eventName: eventName,
+                                    function: binding
+                                });
+                            }
                         });
                     }
                 }
             }
         }
     }
-
 }
 
 export function getTemplateAsHtml(templateConfig: ITemplateConfiguration): Promise<string> {

+ 7 - 6
Viewer/src/viewer/viewer.ts

@@ -114,11 +114,12 @@ export abstract class AbstractViewer {
      * @memberof AbstractViewer
      */
     protected onTemplatesLoaded(): Promise<AbstractViewer> {
+        let autoLoadModel = !!this.configuration.model;
         return this.initEngine().then(() => {
-            if (this.configuration.model) {
+            if (autoLoadModel) {
                 return this.loadModel();
             } else {
-                return this.scene;
+                return this.scene || this.initScene();
             }
         }).then(() => {
             return this;
@@ -176,7 +177,7 @@ export abstract class AbstractViewer {
             this.scene.debugLayer.show();
         }
         return this.onSceneInitObservable.notifyWithPromise(this.scene).then(() => {
-            return this.scene;
+            return this.scene!;
         });
     }
 
@@ -188,9 +189,9 @@ export abstract class AbstractViewer {
         let base = parts.join('/') + '/';
         let plugin = (typeof model === 'string') ? undefined : model.loader;
 
-        return Promise.resolve().then(() => {
-            if (!this.scene || clearScene) return this.initScene();
-            else return this.scene;
+        return Promise.resolve(this.scene).then((scene) => {
+            if (!scene || clearScene) return this.initScene();
+            else return this.scene!;
         }).then(() => {
             return new Promise<Array<AbstractMesh>>((resolve, reject) => {
                 SceneLoader.ImportMesh(undefined, base, filename, this.scene, (meshes) => {

+ 1 - 1
Viewer/webpack.gulp.config.js

@@ -19,7 +19,7 @@ module.exports = {
             "babylonjs": __dirname + '/../dist/preview release/babylon.max.js',
             "babylonjs-materials": __dirname + '/../dist/preview release/materialsLibrary/babylonjs.materials.js',
             "babylonjs-loaders": __dirname + '/../dist/preview release/loaders/babylonjs.loaders.js',
-            "es6-promise": __dirname + '/assets/es6-promise.min.js',
+            // "es6-promise": __dirname + '/assets/es6-promise.min.js',
             "deepmerge": __dirname + '/assets/deepmerge.min.js',
         }
     },

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 60 - 61
dist/preview release/viewer/babylon.viewer.js


+ 6 - 1
dist/preview release/what's new.md

@@ -23,11 +23,16 @@
    ([carloslanderas](https://github.com/carloslanderas))
 - VRHelper now exposes onNewMeshPicked observable that will notify a PickingInfo object after meshSelectionPredicate evaluation
    ([carloslanderas](https://github.com/carloslanderas))
-- `AssetsManager` will now clear its `tasks` list from all successfully loaded tasks ([deltakosh](https://github.com/deltakosh))
+- `AssetsManager` will now clear its `tasks` lsit from all successfully loaded tasks ([deltakosh](https://github.com/deltakosh))tasks ([deltakosh](https://github.com/deltakosh))
 - Added documentation to WebVRCamera and VRExperienceHelper ([trevordev](https://github.com/trevordev))
 - Introduced `isStroke` on `HighlightLayerOptions` which makes the highlight solid ([PixelsCommander](https://github.com/pixelscommander))
+- (Viewer) There is now an option to paste payload instead of a URL for configuration ([RaananW](https://github.com/RaananW))
+- (Viewer) Models can be loaded async using JavaScript ([RaananW](https://github.com/RaananW))
+- VRHelper will notify now onSelectedMeshUnselected observable to subscribers when the applied ray selection predicate does not produce a hit and a mesh compliant with the meshSelectionPredicate was previously selected
+   ([carloslanderas](https://github.com/carloslanderas))
 
 ## Bug fixes
+- Texture extension detection in `Engine.CreateTexture` ([sebavan](https://github.com/sebavan))
 
 ## Breaking changes
 

+ 10 - 6
src/Cameras/VR/babylon.vrExperienceHelper.ts

@@ -1487,9 +1487,8 @@ module BABYLON {
                     // Moving the teleportation area to this targetted point
 
                     //Raise onSelectedMeshUnselected observable if ray collided floor mesh/meshes and a non floor mesh was previously selected
-                    if (this._currentMeshSelected &&
-                        !this._isTeleportationFloor(this._currentMeshSelected)) {
-                        this.onSelectedMeshUnselected.notifyObservers(this._currentMeshSelected);
+                    if (this._currentMeshSelected && !this._isTeleportationFloor(this._currentMeshSelected)) {
+                        this._notifySelectedMeshUnselected();
                     }
 
                     this._currentMeshSelected = null;
@@ -1522,9 +1521,7 @@ module BABYLON {
                         }
                     }
                     else {
-                        if (this._currentMeshSelected) {
-                            this.onSelectedMeshUnselected.notifyObservers(this._currentMeshSelected);
-                        }
+                        this._notifySelectedMeshUnselected();
                         this._currentMeshSelected = null;
                         this.changeGazeColor(new Color3(0.7, 0.7, 0.7));
                         this.changeLaserColor(new Color3(0.7, 0.7, 0.7));
@@ -1533,6 +1530,7 @@ module BABYLON {
             }
             else {
                 this._currentHit = null;
+                this._notifySelectedMeshUnselected();
                 this._currentMeshSelected = null;
                 this._teleportationAllowed = false;
                 this._hideTeleportationTarget();
@@ -1540,6 +1538,12 @@ module BABYLON {
                 this.changeLaserColor(new Color3(0.7, 0.7, 0.7));
             }
         }
+        
+        private _notifySelectedMeshUnselected( ) {
+            if(this._currentMeshSelected) {
+                this.onSelectedMeshUnselected.notifyObservers(this._currentMeshSelected);
+            }
+        }
 
         /**
          * Sets the color of the laser ray from the vr controllers.

+ 2 - 2
src/Engine/babylon.engine.ts

@@ -3136,8 +3136,8 @@
             // establish the file extension, if possible
             var lastDot = url.lastIndexOf('.');
             var extension = (lastDot > 0) ? url.substring(lastDot).toLowerCase() : "";
-            var isDDS = this.getCaps().s3tc && (extension === ".dds");
-            var isTGA = (extension === ".tga");
+            var isDDS = this.getCaps().s3tc && (extension.indexOf(".dds") === 0);
+            var isTGA = (extension.indexOf(".tga") === 0);
 
             // determine if a ktx file should be substituted
             var isKTX = false;