فهرست منبع

Merge remote-tracking branch 'upstream/master' into bug-fixes

Gary Hsu 8 سال پیش
والد
کامیت
4df6f88bdb

+ 2 - 1
Playground/scripts/scripts.txt

@@ -27,4 +27,5 @@ volumetric Light Scattering
 refraction and Reflection
 pbr
 instanced bones
-pointer events handling
+pointer events handling
+webvr

+ 35 - 0
Playground/scripts/webvr.js

@@ -0,0 +1,35 @@
+var createScene = function () {
+
+    // This creates a basic Babylon Scene object (non-mesh)
+    var scene = new BABYLON.Scene(engine);
+    scene.createDefaultVRExperience();
+
+    // This creates a light, aiming 0,1,0 - to the sky (non-mesh)
+    var light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 1, 0), scene);
+
+    // Default intensity is 1. Let's dim the light a small amount
+    light.intensity = 0.7;
+
+    // Create some spheres at the default eye level (2m)
+    createSphereBox(scene, 2, 2);
+    createSphereBox(scene, 3, 2);
+        
+    // Our built-in 'ground' shape. Params: name, width, depth, subdivs, scene
+    var ground = BABYLON.Mesh.CreateGround("ground1", 6, 6, 2, scene);
+
+    return scene;
+};
+
+function createSphereBox(scene, distance, height) {    
+    createSphere(scene,  distance, height,  distance);
+    createSphere(scene,  distance, height, -distance);
+    createSphere(scene, -distance, height,  distance);
+    createSphere(scene, -distance, height, -distance);    
+}
+function createSphere(scene, x, y, z) {
+    // Our built-in 'sphere' shape. Params: name, subdivs, size, scene
+    var sphere = BABYLON.Mesh.CreateSphere("sphere1", 4, 0.4, scene);
+    sphere.position.x = x;
+    sphere.position.y = y;
+    sphere.position.z = z;
+}

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 8474 - 8445
dist/preview release/babylon.d.ts


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 40 - 40
dist/preview release/babylon.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 214 - 113
dist/preview release/babylon.max.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 8474 - 8445
dist/preview release/babylon.module.d.ts


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 44 - 44
dist/preview release/babylon.worker.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 4448 - 4419
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 40 - 40
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 214 - 113
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 4448 - 4419
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.module.d.ts


+ 4 - 0
dist/preview release/gui/babylon.gui.d.ts

@@ -602,8 +602,10 @@ declare module BABYLON.GUI {
     class InputText extends Control implements IFocusableControl {
         name: string;
         private _text;
+        private _placeholderText;
         private _background;
         private _focusedBackground;
+        private _placeholderColor;
         private _thickness;
         private _margin;
         private _autoStretchWidth;
@@ -623,6 +625,8 @@ declare module BABYLON.GUI {
         thickness: number;
         focusedBackground: string;
         background: string;
+        placeholderColor: string;
+        placeholderText: string;
         text: string;
         constructor(name?: string, text?: string);
         onBlur(): void;

+ 39 - 2
dist/preview release/gui/babylon.gui.js

@@ -3793,8 +3793,10 @@ var BABYLON;
                 var _this = _super.call(this, name) || this;
                 _this.name = name;
                 _this._text = "";
+                _this._placeholderText = "";
                 _this._background = "black";
                 _this._focusedBackground = "black";
+                _this._placeholderColor = "gray";
                 _this._thickness = 1;
                 _this._margin = new GUI.ValueAndUnit(10, GUI.ValueAndUnit.UNITMODE_PIXEL);
                 _this._autoStretchWidth = true;
@@ -3895,6 +3897,34 @@ var BABYLON;
                 enumerable: true,
                 configurable: true
             });
+            Object.defineProperty(InputText.prototype, "placeholderColor", {
+                get: function () {
+                    return this._placeholderColor;
+                },
+                set: function (value) {
+                    if (this._placeholderColor === value) {
+                        return;
+                    }
+                    this._placeholderColor = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(InputText.prototype, "placeholderText", {
+                get: function () {
+                    return this._placeholderText;
+                },
+                set: function (value) {
+                    if (this._placeholderText === value) {
+                        return;
+                    }
+                    this._placeholderText = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
             Object.defineProperty(InputText.prototype, "text", {
                 get: function () {
                     return this._text;
@@ -4031,7 +4061,14 @@ var BABYLON;
                     if (this.color) {
                         context.fillStyle = this.color;
                     }
-                    var textWidth = context.measureText(this._text).width;
+                    var text = this._text;
+                    if (!this._isFocused && !this._text && this._placeholderText) {
+                        text = this._placeholderText;
+                        if (this._placeholderColor) {
+                            context.fillStyle = this._placeholderColor;
+                        }
+                    }
+                    var textWidth = context.measureText(text).width;
                     var marginWidth = this._margin.getValueInPixel(this._host, parentMeasure.width) * 2;
                     if (this._autoStretchWidth) {
                         this.width = Math.min(this._maxWidth.getValueInPixel(this._host, parentMeasure.width), textWidth + marginWidth) + "px";
@@ -4051,7 +4088,7 @@ var BABYLON;
                     else {
                         this._scrollLeft = clipTextLeft;
                     }
-                    context.fillText(this._text, this._scrollLeft, this._currentMeasure.top + rootY);
+                    context.fillText(text, this._scrollLeft, this._currentMeasure.top + rootY);
                     // Cursor
                     if (this._isFocused) {
                         if (!this._blinkIsEven) {

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 2 - 2
dist/preview release/gui/babylon.gui.min.js


+ 4 - 0
dist/preview release/gui/babylon.gui.module.d.ts

@@ -605,8 +605,10 @@ declare module BABYLON.GUI {
     class InputText extends Control implements IFocusableControl {
         name: string;
         private _text;
+        private _placeholderText;
         private _background;
         private _focusedBackground;
+        private _placeholderColor;
         private _thickness;
         private _margin;
         private _autoStretchWidth;
@@ -626,6 +628,8 @@ declare module BABYLON.GUI {
         thickness: number;
         focusedBackground: string;
         background: string;
+        placeholderColor: string;
+        placeholderText: string;
         text: string;
         constructor(name?: string, text?: string);
         onBlur(): void;

+ 39 - 2
gui/src/controls/inputText.ts

@@ -3,8 +3,10 @@
 module BABYLON.GUI {
     export class InputText extends Control implements IFocusableControl {
         private _text = "";
+        private _placeholderText = "";
         private _background = "black";   
         private _focusedBackground = "black";   
+        private _placeholderColor = "gray";   
         private _thickness = 1;
         private _margin = new ValueAndUnit(10, ValueAndUnit.UNITMODE_PIXEL);
         private _autoStretchWidth = true;        
@@ -99,7 +101,32 @@ module BABYLON.GUI {
 
             this._background = value;
             this._markAsDirty();
+        }  
+
+        public get placeholderColor(): string {
+            return this._placeholderColor;
+        }
+
+        public set placeholderColor(value: string) {
+            if (this._placeholderColor === value) {
+                return;
+            }
+
+            this._placeholderColor = value;
+            this._markAsDirty();
         }          
+        
+        public get placeholderText(): string {
+            return this._placeholderText;
+        }
+
+        public set placeholderText(value: string) {
+            if (this._placeholderText === value) {
+                return;
+            }
+            this._placeholderText = value;
+            this._markAsDirty();
+        }        
 
         public get text(): string {
             return this._text;
@@ -256,7 +283,17 @@ module BABYLON.GUI {
                     context.fillStyle = this.color;
                 }
 
-                let textWidth = context.measureText(this._text).width;   
+                let text = this._text;
+
+                if (!this._isFocused && !this._text && this._placeholderText) {  
+                    text = this._placeholderText;
+
+                    if (this._placeholderColor) {
+                        context.fillStyle = this._placeholderColor;
+                    }
+                }
+
+                let textWidth = context.measureText(text).width;   
                 let marginWidth = this._margin.getValueInPixel(this._host, parentMeasure.width) * 2;
                 if (this._autoStretchWidth) {
                     this.width = Math.min(this._maxWidth.getValueInPixel(this._host, parentMeasure.width), textWidth + marginWidth) + "px";
@@ -278,7 +315,7 @@ module BABYLON.GUI {
                     this._scrollLeft = clipTextLeft;
                 }
 
-                context.fillText(this._text, this._scrollLeft, this._currentMeasure.top + rootY);
+                context.fillText(text, this._scrollLeft, this._currentMeasure.top + rootY);
 
                 // Cursor
                 if (this._isFocused) {         

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 129 - 36
src/Cameras/VR/babylon.vrExperienceHelper.ts


+ 24 - 26
src/Cameras/VR/babylon.webVRCamera.ts

@@ -40,7 +40,7 @@ module BABYLON {
     export class WebVRFreeCamera extends FreeCamera implements PoseControlled {
         public _vrDevice = null;
         public rawPose: DevicePose = null;
-        private _vrEnabled = false;
+        private _onVREnabled: (success: boolean) => void;
         private _specsVersion: number = 1.1;
         private _attached: boolean = false;
 
@@ -95,7 +95,20 @@ module BABYLON {
             }
 
             //enable VR
-            this.getEngine().initWebVR();
+            var engine = this.getEngine();
+            this._onVREnabled = (success:boolean) => { if (success) { this.initControllers(); } };
+            engine.onVRRequestPresentComplete.add(this._onVREnabled);
+            engine.initWebVR().add((event:IDisplayChangedEventArgs) => {
+                
+                this._vrDevice = event.vrDisplay;
+
+                //reset the rig parameters.
+                this.setCameraRigMode(Camera.RIG_MODE_WEBVR, { parentCamera: this, vrDisplay: this._vrDevice, frameData: this._frameData, specs: this._specsVersion });
+
+                if (this._attached && this._vrDevice) {
+                    this.getEngine().enableVR();
+                }
+            });
 
             //check specs version
             if (!window.VRFrameData) {
@@ -106,22 +119,6 @@ module BABYLON {
                 this._frameData = new VRFrameData();
             }
 
-            this.getEngine().getVRDevice(this.webVROptions.displayName, device => {
-                if (!device) {
-                    return;
-                }
-
-                this._vrEnabled = true;               
-                this._vrDevice = device;
-
-                //reset the rig parameters.
-                this.setCameraRigMode(Camera.RIG_MODE_WEBVR, { parentCamera: this, vrDisplay: this._vrDevice, frameData: this._frameData, specs: this._specsVersion });
-
-                if (this._attached) {
-                    this.getEngine().enableVR(this._vrDevice)
-                }
-            });                
-
             /**
              * The idea behind the following lines:
              * objects that have the camera as parent should actually have the rig cameras as a parent.
@@ -155,6 +152,11 @@ module BABYLON {
                 }
             });
         }
+        
+        public dispose(): void {
+            this.getEngine().onVRRequestPresentComplete.removeCallback(this._onVREnabled);
+            super.dispose();
+        }
 
         public getControllerByName(name: string): WebVRController {
             for (var gp of this.controllers) {
@@ -194,11 +196,11 @@ module BABYLON {
         } 
 
         public _checkInputs(): void {
-            if (this._vrEnabled) {
+            if (this._vrDevice && this._vrDevice.isPresenting) {
                 if (this._specsVersion === 1.1) {
                     this._vrDevice.getFrameData(this._frameData);
                 } else {
-                    //backwards comp
+                    // TODO: Does backwards comp need to be here any more? The Engine class doesn't support it any more.
                     let pose = this._vrDevice.getPose();
                     this._frameData.pose = pose;
                 }
@@ -244,12 +246,9 @@ module BABYLON {
 
             noPreventDefault = Camera.ForceAttachControlToAlwaysPreventDefault ? false : noPreventDefault;
 
-            if (this._vrEnabled) {
-                this.getEngine().enableVR(this._vrDevice);
+            if (this._vrDevice) {
+                this.getEngine().enableVR();
             }
-
-            // try to attach the controllers, if found.
-            this.initControllers();
         }
 
         public detachControl(element: HTMLElement): void {
@@ -257,7 +256,6 @@ module BABYLON {
             this.getScene().gamepadManager.onGamepadDisconnectedObservable.remove(this._onGamepadDisconnectedObserver);
             
             super.detachControl(element);
-            this._vrEnabled = false;
             this._attached = false;
             this.getEngine().disableVR();
         }

+ 97 - 66
src/babylon.engine.ts

@@ -254,6 +254,11 @@
         doNotHandleContextLost?: boolean;
     }
 
+    export interface IDisplayChangedEventArgs {
+        vrDisplay: any;
+        vrSupported: boolean;
+    }
+
     /**
      * The engine class is responsible for interfacing with all lower-level APIs such as WebGL and Audio.
      */
@@ -556,12 +561,8 @@
 
         //WebVR
 
-        //The new WebVR uses promises.
-        //this promise resolves with the current devices available.
-        public vrDisplaysPromise;
-
-        private _vrDisplays;
-        private _vrDisplayEnabled;
+        private _vrDisplay: any = undefined;
+        private _vrSupported: boolean = false;
         private _oldSize: BABYLON.Size;
         private _oldHardwareScaleFactor: number;
         private _vrExclusivePointerMode = false;
@@ -613,6 +614,14 @@
         private _onVRDisplayPointerRestricted: () => void;
         private _onVRDisplayPointerUnrestricted: () => void;
 
+        // VRDisplay connection
+        private _onVrDisplayConnect: (display: any) => void;
+        private _onVrDisplayDisconnect: () => void;
+        private _onVrDisplayPresentChange: () => void;
+        public onVRDisplayChangedObservable = new Observable<IDisplayChangedEventArgs>();
+        public onVRRequestPresentComplete = new Observable<boolean>();
+        public onVRRequestPresentStart = new Observable<Engine>();
+
         private _hardwareScalingLevel: number;
         private _caps: EngineCapabilities;
         private _pointerLockRequested: boolean;
@@ -946,12 +955,10 @@
                 document.addEventListener("webkitpointerlockchange", this._onPointerLockChange, false);
 
                 this._onVRDisplayPointerRestricted = () => {
-                    this._vrExclusivePointerMode = true;
                     canvas.requestPointerLock();
                 }
 
                 this._onVRDisplayPointerUnrestricted = () => {
-                    this._vrExclusivePointerMode = false;
                     document.exitPointerLock();
                 }
 
@@ -1401,7 +1408,10 @@
 
             if (this._activeRenderLoops.length > 0) {
                 // Register new frame
-                this._frameHandler = Tools.QueueNewFrame(this._bindedRenderFunction, this._vrDisplayEnabled);
+                var requester = window;
+                if (this._vrDisplay && this._vrDisplay.isPresenting)
+                    requester = this._vrDisplay;
+                this._frameHandler = Tools.QueueNewFrame(this._bindedRenderFunction, requester);
             } else {
                 this._renderingQueueLaunched = false;
             }
@@ -1528,8 +1538,9 @@
             }
 
             //submit frame to the vr device, if enabled
-            if (this._vrDisplayEnabled && this._vrDisplayEnabled.isPresenting) {
-                this._vrDisplayEnabled.submitFrame()
+            if (this._vrDisplay && this._vrDisplay.isPresenting) {
+                // TODO: We should only submit the frame if we read frameData successfully.
+                this._vrDisplay.submitFrame();
             }
         }
 
@@ -1542,7 +1553,7 @@
          */
         public resize(): void {
             // We're not resizing the size of the canvas while in VR mode & presenting
-            if (!(this._vrDisplayEnabled && this._vrDisplayEnabled.isPresenting)) {
+            if (!(this._vrDisplay && this._vrDisplay.isPresenting)) {
                 var width = navigator.isCocoonJS ? window.innerWidth : this._renderingCanvas.clientWidth;
                 var height = navigator.isCocoonJS ? window.innerHeight : this._renderingCanvas.clientHeight;
 
@@ -1578,94 +1589,106 @@
             }
         }
 
+        // WebVR functions
+        public isVRDevicePresent() : boolean {
+            return !!this._vrDisplay;
+        }
 
-        //WebVR functions
-        public isVRDevicePresent(callback: (result: boolean) => void) {
-            this.getVRDevice(null, (device) => {
-                callback(device !== null);
-            });
+        public getVRDevice() : any {
+            return this._vrDisplay;
         }
 
-        public getVRDevice(name: string, callback: (device: any) => void) {
-            if (!this.vrDisplaysPromise) {
-                callback(null);
-                return;
+        public initWebVR(): Observable<any> {
+            var notifyObservers = () => {
+                var eventArgs = {
+                    vrDisplay: this._vrDisplay,
+                    vrSupported: this._vrSupported
+                };
+                this.onVRDisplayChangedObservable.notifyObservers(eventArgs);
             }
 
-            this.vrDisplaysPromise.then((devices) => {
-                if (devices.length > 0) {
-                    if (name) {
-                        var found = devices.some(device => {
-                            if (device.displayName === name) {
-                                callback(device);
-                                return true;
-                            } else {
-                                return false;
-                            }
-                        });
-                        if (!found) {
-                            Tools.Warn("Display " + name + " was not found. Using " + devices[0].displayName);
-                            callback(devices[0]);
-                        }
-                    } else {
-                        //choose the first one
-                        callback(devices[0]);
-                    }
-                } else {
-                    Tools.Error("No WebVR devices found!");
-                    callback(null);
+            if (!this._onVrDisplayConnect) {
+                this._onVrDisplayConnect = (event) => {
+                    this._vrDisplay = event.display;
+                    notifyObservers();
+                };
+                this._onVrDisplayDisconnect = () => {
+                    this._vrDisplay.cancelAnimationFrame(this._frameHandler);
+                    this._vrDisplay = undefined;
+                    this._frameHandler = Tools.QueueNewFrame(this._bindedRenderFunction);
+                    notifyObservers();
+                };
+                this._onVrDisplayPresentChange = () => {                    
+                    this._vrExclusivePointerMode = this._vrDisplay && this._vrDisplay.isPresenting;
                 }
-            });
-        }
-
-        public initWebVR(): void {
-            if (!this.vrDisplaysPromise) {
-                this._getVRDisplays();
+                window.addEventListener('vrdisplayconnect', this._onVrDisplayConnect);
+                window.addEventListener('vrdisplaydisconnect', this._onVrDisplayDisconnect);
+                window.addEventListener('vrdisplaypresentchange', this._onVrDisplayPresentChange);
             }
+            
+            this._getVRDisplays(notifyObservers);
+
+            return this.onVRDisplayChangedObservable;
         }
 
-        public enableVR(vrDevice) {
-            this._vrDisplayEnabled = vrDevice;
-            this._vrDisplayEnabled.requestPresent([{ source: this.getRenderingCanvas() }]).then(this._onVRFullScreenTriggered);
+        public enableVR() {
+            if (this._vrDisplay && !this._vrDisplay.isPresenting) {
+                var onResolved = () => {
+                    this.onVRRequestPresentComplete.notifyObservers(true);
+                    this._onVRFullScreenTriggered();
+                };
+                var onRejected = () => {
+                    this.onVRRequestPresentComplete.notifyObservers(false);
+                };
+                
+                this.onVRRequestPresentStart.notifyObservers(this);
+                this._vrDisplay.requestPresent([{ source: this.getRenderingCanvas() }]).then(onResolved).catch(onRejected);
+            }
         }
 
         public disableVR() {
-            if (this._vrDisplayEnabled) {
-                this._vrDisplayEnabled.exitPresent().then(this._onVRFullScreenTriggered);
+            if (this._vrDisplay && this._vrDisplay.isPresenting) {
+                this._vrDisplay.exitPresent().then(this._onVRFullScreenTriggered).catch(this._onVRFullScreenTriggered);
             }
         }
 
         private _onVRFullScreenTriggered = () => {
-            if (this._vrDisplayEnabled && this._vrDisplayEnabled.isPresenting) {
+            if (this._vrDisplay && this._vrDisplay.isPresenting) {
                 //get the old size before we change
                 this._oldSize = new BABYLON.Size(this.getRenderWidth(), this.getRenderHeight());
                 this._oldHardwareScaleFactor = this.getHardwareScalingLevel();
 
                 //get the width and height, change the render size
-                var leftEye = this._vrDisplayEnabled.getEyeParameters('left');
+                var leftEye = this._vrDisplay.getEyeParameters('left');
                 var width, height;
                 this.setHardwareScalingLevel(1);
                 this.setSize(leftEye.renderWidth * 2, leftEye.renderHeight);
             } else {
-                //When the specs are implemented, need to uncomment this.
                 this.setHardwareScalingLevel(this._oldHardwareScaleFactor);
                 this.setSize(this._oldSize.width, this._oldSize.height);
-                this._vrDisplayEnabled = undefined;
             }
         }
 
-        private _getVRDisplays() {
+        private _getVRDisplays(callback) {
             var getWebVRDevices = (devices: Array<any>) => {
-
-                this._vrDisplays = devices.filter(function (device) {
-                    return device instanceof VRDisplay;
-                });
-
-                return this._vrDisplays;
+                this._vrSupported = true;
+                // note that devices may actually be an empty array. This is fine;
+                // we expect this._vrDisplay to be undefined in this case.
+                return this._vrDisplay = devices[0];
             }
 
             if (navigator.getVRDisplays) {
-                this.vrDisplaysPromise = navigator.getVRDisplays().then(getWebVRDevices);
+                // TODO: Backwards compatible for 1.0?
+                navigator.getVRDisplays().then(getWebVRDevices).then(callback).catch((error) => {
+                    // TODO: System CANNOT support WebVR, despite API presence.
+                    this._vrSupported = false;
+                    callback();
+                });
+            } else {
+                // TODO: Browser does not support WebVR
+                this._vrDisplay = undefined;
+                this._vrSupported = false;
+                callback();
             }
         }
 
@@ -4416,6 +4439,14 @@
             document.removeEventListener("mspointerlockchange", this._onPointerLockChange);
             document.removeEventListener("mozpointerlockchange", this._onPointerLockChange);
             document.removeEventListener("webkitpointerlockchange", this._onPointerLockChange);
+            
+            if (this._onVrDisplayConnect) {
+                window.removeEventListener('vrdisplayconnect', this._onVrDisplayConnect);
+                window.removeEventListener('vrdisplaydisconnect', this._onVrDisplayDisconnect);
+                window.removeEventListener('vrdisplaypresentchange', this._onVrDisplayPresentChange);
+                this._onVrDisplayConnect = undefined;
+                this._onVrDisplayDisconnect = undefined;                
+            }
 
             // Remove from Instances
             var index = Engine.Instances.indexOf(this);