var __extends = this.__extends || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    __.prototype = b.prototype;
    d.prototype = new __();
};
var BABYLON;
(function (BABYLON) {
    // Standard optimizations
    var SceneOptimization = (function () {
        function SceneOptimization(priority) {
            if (priority === void 0) { priority = 0; }
            this.priority = priority;
            this.apply = function (scene) {
                return true; // Return true if everything that can be done was applied
            };
        }
        return SceneOptimization;
    })();
    BABYLON.SceneOptimization = SceneOptimization;
    var TextureOptimization = (function (_super) {
        __extends(TextureOptimization, _super);
        function TextureOptimization(priority, maximumSize) {
            var _this = this;
            if (priority === void 0) { priority = 0; }
            if (maximumSize === void 0) { maximumSize = 1024; }
            _super.call(this, priority);
            this.priority = priority;
            this.maximumSize = maximumSize;
            this.apply = function (scene) {
                var allDone = true;
                for (var index = 0; index < scene.textures.length; index++) {
                    var texture = scene.textures[index];
                    if (!texture.canRescale) {
                        continue;
                    }
                    var currentSize = texture.getSize();
                    var maxDimension = Math.max(currentSize.width, currentSize.height);
                    if (maxDimension > _this.maximumSize) {
                        texture.scale(0.5);
                        allDone = false;
                    }
                }
                return allDone;
            };
        }
        return TextureOptimization;
    })(SceneOptimization);
    BABYLON.TextureOptimization = TextureOptimization;
    var HardwareScalingOptimization = (function (_super) {
        __extends(HardwareScalingOptimization, _super);
        function HardwareScalingOptimization(priority, maximumScale) {
            var _this = this;
            if (priority === void 0) { priority = 0; }
            if (maximumScale === void 0) { maximumScale = 2; }
            _super.call(this, priority);
            this.priority = priority;
            this.maximumScale = maximumScale;
            this._currentScale = 1;
            this.apply = function (scene) {
                _this._currentScale++;
                scene.getEngine().setHardwareScalingLevel(_this._currentScale);
                return _this._currentScale >= _this.maximumScale;
            };
        }
        return HardwareScalingOptimization;
    })(SceneOptimization);
    BABYLON.HardwareScalingOptimization = HardwareScalingOptimization;
    var ShadowsOptimization = (function (_super) {
        __extends(ShadowsOptimization, _super);
        function ShadowsOptimization() {
            _super.apply(this, arguments);
            this.apply = function (scene) {
                scene.shadowsEnabled = false;
                return true;
            };
        }
        return ShadowsOptimization;
    })(SceneOptimization);
    BABYLON.ShadowsOptimization = ShadowsOptimization;
    var PostProcessesOptimization = (function (_super) {
        __extends(PostProcessesOptimization, _super);
        function PostProcessesOptimization() {
            _super.apply(this, arguments);
            this.apply = function (scene) {
                scene.postProcessesEnabled = false;
                return true;
            };
        }
        return PostProcessesOptimization;
    })(SceneOptimization);
    BABYLON.PostProcessesOptimization = PostProcessesOptimization;
    var LensFlaresOptimization = (function (_super) {
        __extends(LensFlaresOptimization, _super);
        function LensFlaresOptimization() {
            _super.apply(this, arguments);
            this.apply = function (scene) {
                scene.lensFlaresEnabled = false;
                return true;
            };
        }
        return LensFlaresOptimization;
    })(SceneOptimization);
    BABYLON.LensFlaresOptimization = LensFlaresOptimization;
    var ParticlesOptimization = (function (_super) {
        __extends(ParticlesOptimization, _super);
        function ParticlesOptimization() {
            _super.apply(this, arguments);
            this.apply = function (scene) {
                scene.particlesEnabled = false;
                return true;
            };
        }
        return ParticlesOptimization;
    })(SceneOptimization);
    BABYLON.ParticlesOptimization = ParticlesOptimization;
    var RenderTargetsOptimization = (function (_super) {
        __extends(RenderTargetsOptimization, _super);
        function RenderTargetsOptimization() {
            _super.apply(this, arguments);
            this.apply = function (scene) {
                scene.renderTargetsEnabled = false;
                return true;
            };
        }
        return RenderTargetsOptimization;
    })(SceneOptimization);
    BABYLON.RenderTargetsOptimization = RenderTargetsOptimization;
    var MergeMeshesOptimization = (function (_super) {
        __extends(MergeMeshesOptimization, _super);
        function MergeMeshesOptimization() {
            var _this = this;
            _super.apply(this, arguments);
            this._canBeMerged = function (abstractMesh) {
                if (!(abstractMesh instanceof BABYLON.Mesh)) {
                    return false;
                }
                var mesh = abstractMesh;
                if (!mesh.isVisible || !mesh.isEnabled()) {
                    return false;
                }
                if (mesh.instances.length > 0) {
                    return false;
                }
                if (mesh.skeleton || mesh.hasLODLevels) {
                    return false;
                }
                return true;
            };
            this.apply = function (scene) {
                var globalPool = scene.meshes.slice(0);
                var globalLength = globalPool.length;
                for (var index = 0; index < globalLength; index++) {
                    var currentPool = new Array();
                    var current = globalPool[index];
                    // Checks
                    if (!_this._canBeMerged(current)) {
                        continue;
                    }
                    currentPool.push(current);
                    for (var subIndex = index + 1; subIndex < globalLength; subIndex++) {
                        var otherMesh = globalPool[subIndex];
                        if (!_this._canBeMerged(otherMesh)) {
                            continue;
                        }
                        if (otherMesh.material !== current.material) {
                            continue;
                        }
                        if (otherMesh.checkCollisions !== current.checkCollisions) {
                            continue;
                        }
                        currentPool.push(otherMesh);
                        globalLength--;
                        globalPool.splice(subIndex, 1);
                        subIndex--;
                    }
                    if (currentPool.length < 2) {
                        continue;
                    }
                    // Merge meshes
                    BABYLON.Mesh.MergeMeshes(currentPool);
                }
                return true;
            };
        }
        return MergeMeshesOptimization;
    })(SceneOptimization);
    BABYLON.MergeMeshesOptimization = MergeMeshesOptimization;
    // Options
    var SceneOptimizerOptions = (function () {
        function SceneOptimizerOptions(targetFrameRate, trackerDuration) {
            if (targetFrameRate === void 0) { targetFrameRate = 60; }
            if (trackerDuration === void 0) { trackerDuration = 2000; }
            this.targetFrameRate = targetFrameRate;
            this.trackerDuration = trackerDuration;
            this.optimizations = new Array();
        }
        SceneOptimizerOptions.LowDegradationAllowed = function (targetFrameRate) {
            var result = new SceneOptimizerOptions(targetFrameRate);
            var priority = 0;
            result.optimizations.push(new MergeMeshesOptimization(priority));
            result.optimizations.push(new ShadowsOptimization(priority));
            result.optimizations.push(new LensFlaresOptimization(priority));
            // Next priority
            priority++;
            result.optimizations.push(new PostProcessesOptimization(priority));
            result.optimizations.push(new ParticlesOptimization(priority));
            // Next priority
            priority++;
            result.optimizations.push(new TextureOptimization(priority, 1024));
            return result;
        };
        SceneOptimizerOptions.ModerateDegradationAllowed = function (targetFrameRate) {
            var result = new SceneOptimizerOptions(targetFrameRate);
            var priority = 0;
            result.optimizations.push(new MergeMeshesOptimization(priority));
            result.optimizations.push(new ShadowsOptimization(priority));
            result.optimizations.push(new LensFlaresOptimization(priority));
            // Next priority
            priority++;
            result.optimizations.push(new PostProcessesOptimization(priority));
            result.optimizations.push(new ParticlesOptimization(priority));
            // Next priority
            priority++;
            result.optimizations.push(new TextureOptimization(priority, 512));
            // Next priority
            priority++;
            result.optimizations.push(new RenderTargetsOptimization(priority));
            // Next priority
            priority++;
            result.optimizations.push(new HardwareScalingOptimization(priority, 2));
            return result;
        };
        SceneOptimizerOptions.HighDegradationAllowed = function (targetFrameRate) {
            var result = new SceneOptimizerOptions(targetFrameRate);
            var priority = 0;
            result.optimizations.push(new MergeMeshesOptimization(priority));
            result.optimizations.push(new ShadowsOptimization(priority));
            result.optimizations.push(new LensFlaresOptimization(priority));
            // Next priority
            priority++;
            result.optimizations.push(new PostProcessesOptimization(priority));
            result.optimizations.push(new ParticlesOptimization(priority));
            // Next priority
            priority++;
            result.optimizations.push(new TextureOptimization(priority, 256));
            // Next priority
            priority++;
            result.optimizations.push(new RenderTargetsOptimization(priority));
            // Next priority
            priority++;
            result.optimizations.push(new HardwareScalingOptimization(priority, 4));
            return result;
        };
        return SceneOptimizerOptions;
    })();
    BABYLON.SceneOptimizerOptions = SceneOptimizerOptions;
    // Scene optimizer tool
    var SceneOptimizer = (function () {
        function SceneOptimizer() {
        }
        SceneOptimizer._CheckCurrentState = function (scene, options, currentPriorityLevel, onSuccess, onFailure) {
            // TODO: add an epsilon
            if (scene.getEngine().getFps() >= options.targetFrameRate) {
                if (onSuccess) {
                    onSuccess();
                }
                return;
            }
            // Apply current level of optimizations
            var allDone = true;
            var noOptimizationApplied = true;
            for (var index = 0; index < options.optimizations.length; index++) {
                var optimization = options.optimizations[index];
                if (optimization.priority === currentPriorityLevel) {
                    noOptimizationApplied = false;
                    allDone = allDone && optimization.apply(scene);
                }
            }
            // If no optimization was applied, this is a failure :(
            if (noOptimizationApplied) {
                if (onFailure) {
                    onFailure();
                }
                return;
            }
            // If all optimizations were done, move to next level
            if (allDone) {
                currentPriorityLevel++;
            }
            // Let's the system running for a specific amount of time before checking FPS
            scene.executeWhenReady(function () {
                setTimeout(function () {
                    SceneOptimizer._CheckCurrentState(scene, options, currentPriorityLevel, onSuccess, onFailure);
                }, options.trackerDuration);
            });
        };
        SceneOptimizer.OptimizeAsync = function (scene, options, onSuccess, onFailure) {
            if (!options) {
                options = SceneOptimizerOptions.ModerateDegradationAllowed();
            }
            // Let's the system running for a specific amount of time before checking FPS
            scene.executeWhenReady(function () {
                setTimeout(function () {
                    SceneOptimizer._CheckCurrentState(scene, options, 0, onSuccess, onFailure);
                }, options.trackerDuration);
            });
        };
        return SceneOptimizer;
    })();
    BABYLON.SceneOptimizer = SceneOptimizer;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.sceneOptimizer.js.map