function Engine(canvasOrContext, antialias, options, adaptToDeviceRatio) {
            if (adaptToDeviceRatio === void 0) { adaptToDeviceRatio = false; }
            var _this = this;
            // Public members
            this.forcePOTTextures = false;
            this.isFullscreen = false;
            this.isPointerLock = false;
            this.cullBackFaces = true;
            this.renderEvenInBackground = true;
            this.preventCacheWipeBetweenFrames = false;
            // To enable/disable IDB support and avoid XHR on .manifest
            this.enableOfflineSupport = false;
            this.scenes = new Array();
            this.postProcesses = new Array();
            // Observables
            /**
             * Observable event triggered each time the rendering canvas is resized
             */
            this.onResizeObservable = new BABYLON.Observable();
            /**
             * Observable event triggered each time the canvas loses focus
             */
            this.onCanvasBlurObservable = new BABYLON.Observable();
            /**
             * Observable event triggered each time the canvas gains focus
             */
            this.onCanvasFocusObservable = new BABYLON.Observable();
            /**
             * Observable event triggered each time the canvas receives pointerout event
             */
            this.onCanvasPointerOutObservable = new BABYLON.Observable();
            /**
             * Observable event triggered before each texture is initialized
             */
            this.onBeforeTextureInitObservable = new BABYLON.Observable();
            //WebVR
            this._vrDisplay = undefined;
            this._vrSupported = false;
            this._vrExclusivePointerMode = false;
            // Uniform buffers list
            this.disableUniformBuffers = false;
            this._uniformBuffers = new Array();
            // Observables
            /**
             * Observable raised when the engine begins a new frame
             */
            this.onBeginFrameObservable = new BABYLON.Observable();
            /**
             * Observable raised when the engine ends the current frame
             */
            this.onEndFrameObservable = new BABYLON.Observable();
            /**
             * Observable raised when the engine is about to compile a shader
             */
            this.onBeforeShaderCompilationObservable = new BABYLON.Observable();
            /**
             * Observable raised when the engine has jsut compiled a shader
             */
            this.onAfterShaderCompilationObservable = new BABYLON.Observable();
            this._windowIsBackground = false;
            this._webGLVersion = 1.0;
            this._badOS = false;
            this._badDesktopOS = false;
            this.onVRDisplayChangedObservable = new BABYLON.Observable();
            this.onVRRequestPresentComplete = new BABYLON.Observable();
            this.onVRRequestPresentStart = new BABYLON.Observable();
            this._colorWrite = true;
            this._drawCalls = new BABYLON.PerfCounter();
            this._renderingQueueLaunched = false;
            this._activeRenderLoops = new Array();
            // Deterministic lockstepMaxSteps
            this._deterministicLockstep = false;
            this._lockstepMaxSteps = 4;
            // Lost context
            this.onContextLostObservable = new BABYLON.Observable();
            this.onContextRestoredObservable = new BABYLON.Observable();
            this._contextWasLost = false;
            this._doNotHandleContextLost = false;
            // FPS
            this._performanceMonitor = new BABYLON.PerformanceMonitor();
            this._fps = 60;
            this._deltaTime = 0;
            /**
             * Turn this value on if you want to pause FPS computation when in background
             */
            this.disablePerformanceMonitorInBackground = false;
            // States
            this._depthCullingState = new BABYLON.Internals._DepthCullingState();
            this._stencilState = new BABYLON.Internals._StencilState();
            this._alphaState = new BABYLON.Internals._AlphaState();
            this._alphaMode = Engine.ALPHA_DISABLE;
            // Cache
            this._internalTexturesCache = new Array();
            this._boundTexturesCache = {};
            this._compiledEffects = {};
            this._vertexAttribArraysEnabled = [];
            this._uintIndicesCurrentlySet = false;
            this._currentBoundBuffer = new Array();
            this._currentBufferPointers = new Array();
            this._currentInstanceLocations = new Array();
            this._currentInstanceBuffers = new Array();
            this._vaoRecordInProgress = false;
            this._mustWipeVertexAttributes = false;
            // Hardware supported Compressed Textures
            this._texturesSupported = new Array();
            this._onVRFullScreenTriggered = function () {
                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._vrDisplay.getEyeParameters('left');
                    _this.setHardwareScalingLevel(1);
                    _this.setSize(leftEye.renderWidth * 2, leftEye.renderHeight);
                }
                else {
                    _this.setHardwareScalingLevel(_this._oldHardwareScaleFactor);
                    _this.setSize(_this._oldSize.width, _this._oldSize.height);
                }
            };
            var canvas = null;
            Engine.Instances.push(this);
            if (!canvasOrContext) {
                return;
            }
            options = options || {};
            if (canvasOrContext.getContext) {
                canvas = canvasOrContext;
                this._renderingCanvas = canvas;
                if (antialias != null) {
                    options.antialias = antialias;
                }
                if (options.deterministicLockstep === undefined) {
                    options.deterministicLockstep = false;
                }
                if (options.lockstepMaxSteps === undefined) {
                    options.lockstepMaxSteps = 4;
                }
                if (options.preserveDrawingBuffer === undefined) {
                    options.preserveDrawingBuffer = false;
                }
                if (options.audioEngine === undefined) {
                    options.audioEngine = true;
                }
                if (options.stencil === undefined) {
                    options.stencil = true;
                }
                this._deterministicLockstep = options.deterministicLockstep;
                this._lockstepMaxSteps = options.lockstepMaxSteps;
                this._doNotHandleContextLost = options.doNotHandleContextLost ? true : false;
                // Exceptions
                if (!options.disableWebGL2Support) {
                    if (navigator && navigator.userAgent) {
                        var ua = navigator.userAgent;
                        for (var _i = 0, _a = Engine.WebGL2UniformBuffersExceptionList; _i < _a.length; _i++) {
                            var exception = _a[_i];
                            if (ua.indexOf(exception) > -1) {
                                this.disableUniformBuffers = true;
                                break;
                            }
                        }
                    }
                }
                // GL
                if (!options.disableWebGL2Support) {
                    try {
                        this._gl = (canvas.getContext("webgl2", options) || canvas.getContext("experimental-webgl2", options));
                        if (this._gl) {
                            this._webGLVersion = 2.0;
                        }
                    }
                    catch (e) {
                        // Do nothing
                    }
                }
                if (!this._gl) {
                    if (!canvas) {
                        throw new Error("The provided canvas is null or undefined.");
                    }
                    try {
                        this._gl = (canvas.getContext("webgl", options) || canvas.getContext("experimental-webgl", options));
                    }
                    catch (e) {
                        throw new Error("WebGL not supported");
                    }
                }
                if (!this._gl) {
                    throw new Error("WebGL not supported");
                }
                this._onCanvasFocus = function () {
                    _this.onCanvasFocusObservable.notifyObservers(_this);
                };
                this._onCanvasBlur = function () {
                    _this.onCanvasBlurObservable.notifyObservers(_this);
                };
                canvas.addEventListener("focus", this._onCanvasFocus);
                canvas.addEventListener("blur", this._onCanvasBlur);
                this._onBlur = function () {
                    if (_this.disablePerformanceMonitorInBackground) {
                        _this._performanceMonitor.disable();
                    }
                    _this._windowIsBackground = true;
                };
                this._onFocus = function () {
                    if (_this.disablePerformanceMonitorInBackground) {
                        _this._performanceMonitor.enable();
                    }
                    _this._windowIsBackground = false;
                };
                this._onCanvasPointerOut = function () {
                    _this.onCanvasPointerOutObservable.notifyObservers(_this);
                };
                window.addEventListener("blur", this._onBlur);
                window.addEventListener("focus", this._onFocus);
                canvas.addEventListener("pointerout", this._onCanvasPointerOut);
                // Context lost
                if (!this._doNotHandleContextLost) {
                    this._onContextLost = function (evt) {
                        evt.preventDefault();
                        _this._contextWasLost = true;
                        BABYLON.Tools.Warn("WebGL context lost.");
                        _this.onContextLostObservable.notifyObservers(_this);
                    };
                    this._onContextRestored = function (evt) {
                        // Adding a timeout to avoid race condition at browser level
                        setTimeout(function () {
                            // Rebuild gl context
                            _this._initGLContext();
                            // Rebuild effects
                            _this._rebuildEffects();
                            // Rebuild textures
                            _this._rebuildInternalTextures();
                            // Rebuild buffers
                            _this._rebuildBuffers();
                            // Cache
                            _this.wipeCaches(true);
                            BABYLON.Tools.Warn("WebGL context successfully restored.");
                            _this.onContextRestoredObservable.notifyObservers(_this);
                            _this._contextWasLost = false;
                        }, 0);
                    };
                    canvas.addEventListener("webglcontextlost", this._onContextLost, false);
                    canvas.addEventListener("webglcontextrestored", this._onContextRestored, false);
                }
            }
            else {
                this._gl = canvasOrContext;
                this._renderingCanvas = this._gl.canvas;
                if (this._gl.renderbufferStorageMultisample) {
                    this._webGLVersion = 2.0;
                }
                options.stencil = this._gl.getContextAttributes().stencil;
            }
            // Viewport
            var limitDeviceRatio = options.limitDeviceRatio || window.devicePixelRatio || 1.0;
            this._hardwareScalingLevel = adaptToDeviceRatio ? 1.0 / Math.min(limitDeviceRatio, window.devicePixelRatio || 1.0) : 1.0;
            this.resize();
            this._isStencilEnable = options.stencil ? true : false;
            this._initGLContext();
            if (canvas) {
                // Fullscreen
                this._onFullscreenChange = function () {
                    if (document.fullscreen !== undefined) {
                        _this.isFullscreen = document.fullscreen;
                    }
                    else if (document.mozFullScreen !== undefined) {
                        _this.isFullscreen = document.mozFullScreen;
                    }
                    else if (document.webkitIsFullScreen !== undefined) {
                        _this.isFullscreen = document.webkitIsFullScreen;
                    }
                    else if (document.msIsFullScreen !== undefined) {
                        _this.isFullscreen = document.msIsFullScreen;
                    }
                    // Pointer lock
                    if (_this.isFullscreen && _this._pointerLockRequested && canvas) {
                        canvas.requestPointerLock = canvas.requestPointerLock ||
                            canvas.msRequestPointerLock ||
                            canvas.mozRequestPointerLock ||
                            canvas.webkitRequestPointerLock;
                        if (canvas.requestPointerLock) {
                            canvas.requestPointerLock();
                        }
                    }
                };
                document.addEventListener("fullscreenchange", this._onFullscreenChange, false);
                document.addEventListener("mozfullscreenchange", this._onFullscreenChange, false);
                document.addEventListener("webkitfullscreenchange", this._onFullscreenChange, false);
                document.addEventListener("msfullscreenchange", this._onFullscreenChange, false);
                // Pointer lock
                this._onPointerLockChange = function () {
                    _this.isPointerLock = (document.mozPointerLockElement === canvas ||
                        document.webkitPointerLockElement === canvas ||
                        document.msPointerLockElement === canvas ||
                        document.pointerLockElement === canvas);
                };
                document.addEventListener("pointerlockchange", this._onPointerLockChange, false);
                document.addEventListener("mspointerlockchange", this._onPointerLockChange, false);
                document.addEventListener("mozpointerlockchange", this._onPointerLockChange, false);
                document.addEventListener("webkitpointerlockchange", this._onPointerLockChange, false);
                this._onVRDisplayPointerRestricted = function () {
                    if (canvas) {
                        canvas.requestPointerLock();
                    }
                };
                this._onVRDisplayPointerUnrestricted = function () {
                    document.exitPointerLock();
                };
                window.addEventListener('vrdisplaypointerrestricted', this._onVRDisplayPointerRestricted, false);
                window.addEventListener('vrdisplaypointerunrestricted', this._onVRDisplayPointerUnrestricted, false);
            }
            if (options.audioEngine && BABYLON.AudioEngine && !Engine.audioEngine) {
                Engine.audioEngine = new BABYLON.AudioEngine();
            }
            // Prepare buffer pointers
            for (var i = 0; i < this._caps.maxVertexAttribs; i++) {
                this._currentBufferPointers[i] = new BufferPointer();
            }
            // Load WebVR Devices
            if (options.autoEnableWebVR) {
                this.initWebVR();
            }
            // Detect if we are running on a faulty buggy OS.
            this._badOS = /iPad/i.test(navigator.userAgent) || /iPhone/i.test(navigator.userAgent);
            // Detect if we are running on a faulty buggy desktop OS.
            this._badDesktopOS = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
            BABYLON.Tools.Log("Babylon.js engine (v" + Engine.Version + ") launched");
            this.enableOfflineSupport = (BABYLON.Database !== undefined);
        }
@constructor
@param {HTMLCanvasElement | WebGLRenderingContext} canvasOrContext - the canvas or the webgl context to be used for rendering
@param {boolean} [antialias] - enable antialias
@param options - further options to be sent to the getContext function