Ver Fonte

Merge branch 'master' of https://github.com/defold/doc

mathiaswking há 6 anos atrás
pai
commit
6a8c254af2
39 ficheiros alterados com 1203 adições e 105 exclusões
  1. 1 0
      docs/assets/easier/archive/archive_files.json
  2. BIN
      docs/assets/easier/archive/game.arcd0
  3. BIN
      docs/assets/easier/archive/game.arci0
  4. BIN
      docs/assets/easier/archive/game.dmanifest0
  5. 144 0
      docs/assets/easier/archive/game.projectc0
  6. BIN
      docs/assets/easier/archive/game.public.der0
  7. BIN
      docs/assets/easier/defold_sound.swf
  8. 652 0
      docs/assets/easier/dmloader.js
  9. BIN
      docs/assets/easier/easier.wasm
  10. 0 0
      docs/assets/easier/easier_asmjs.js
  11. 0 0
      docs/assets/easier/easier_wasm.js
  12. BIN
      docs/assets/easier/preview.jpg
  13. 49 36
      docs/en/en.json
  14. 4 4
      docs/en/faq/faq.md
  15. 33 5
      docs/en/manuals/android.md
  16. 99 15
      docs/en/manuals/animation.md
  17. 54 0
      docs/en/manuals/bundling.md
  18. 1 1
      docs/en/manuals/collection-proxy.md
  19. 10 4
      docs/en/manuals/debugging.md
  20. 0 2
      docs/en/manuals/extensions-best-practices.md
  21. 5 5
      docs/en/manuals/gui-pie.md
  22. BIN
      docs/en/manuals/images/bundling/bundle_menu.png
  23. BIN
      docs/en/manuals/images/render/fixed_fit_projection.png
  24. BIN
      docs/en/manuals/images/render/fixed_fit_projection_resized.png
  25. BIN
      docs/en/manuals/images/render/fixed_fit_projection_resized_smaller.png
  26. BIN
      docs/en/manuals/images/render/fixed_projection_zoom_0_5.png
  27. BIN
      docs/en/manuals/images/render/fixed_projection_zoom_2_0.png
  28. BIN
      docs/en/manuals/images/render/fixed_projection_zoom_2_0_resized.png
  29. BIN
      docs/en/manuals/images/render/stretch_projection.png
  30. BIN
      docs/en/manuals/images/render/stretch_projection_resized.png
  31. 2 2
      docs/en/manuals/particlefx.md
  32. 1 1
      docs/en/manuals/physics.md
  33. 18 8
      docs/en/manuals/properties.md
  34. 87 15
      docs/en/manuals/render.md
  35. 24 0
      docs/en/manuals/writing-code.md
  36. 1 1
      docs/en/shared/platforms.md
  37. 4 1
      docs/en/tutorials/car.md
  38. 1 1
      docs/en/tutorials/magic-link.md
  39. 13 4
      docs/ko/ko.json

+ 1 - 0
docs/assets/easier/archive/archive_files.json

@@ -0,0 +1 @@
+{"content":[{"name":"game.projectc","size":2310,"pieces":[{"name":"game.projectc0","offset":0}]},{"name":"game.arci","size":3088,"pieces":[{"name":"game.arci0","offset":0}]},{"name":"game.arcd","size":113454,"pieces":[{"name":"game.arcd0","offset":0}]},{"name":"game.dmanifest","size":5772,"pieces":[{"name":"game.dmanifest0","offset":0}]},{"name":"game.public.der","size":162,"pieces":[{"name":"game.public.der0","offset":0}]}]}

BIN
docs/assets/easier/archive/game.arcd0


BIN
docs/assets/easier/archive/game.arci0


BIN
docs/assets/easier/archive/game.dmanifest0


+ 144 - 0
docs/assets/easier/archive/game.projectc0

@@ -0,0 +1,144 @@
+[project]
+title = easier
+version = 1.0
+write_log = 0
+compress_archive = 1
+
+[display]
+width = 640
+height = 512
+high_dpi = 0
+samples = 0
+fullscreen = 0
+update_frequency = 0
+vsync = 1
+display_profiles = /builtins/render/default.display_profilesc
+dynamic_orientation = 0
+
+[physics]
+type = 2D
+gravity_y = -10
+debug = 0
+debug_alpha = 0.9
+world_count = 4
+gravity_x = 0
+gravity_z = 0
+scale = 1
+debug_scale = 30
+max_collisions = 64
+max_contacts = 128
+contact_impulse_limit = 0
+ray_cast_limit_2d = 64
+ray_cast_limit_3d = 128
+trigger_overlap_capacity = 16
+
+[bootstrap]
+main_collection = /main/main.collectionc
+render = /builtins/render/default.renderc
+
+[graphics]
+default_texture_min_filter = linear
+default_texture_mag_filter = linear
+max_draw_calls = 1024
+max_characters = 8192
+max_debug_vertices = 10000
+texture_profiles = /builtins/graphics/default.texture_profiles
+
+[sound]
+gain = 1
+max_sound_data = 128
+max_sound_buffers = 32
+max_sound_sources = 16
+max_sound_instances = 256
+
+[resource]
+http_cache = 0
+max_resources = 1024
+
+[input]
+repeat_delay = 0.5
+repeat_interval = 0.2
+gamepads = /builtins/input/default.gamepadsc
+game_binding = /input/game.input_bindingc
+use_accelerometer = 1
+
+[sprite]
+max_count = 128
+subpixels = 1
+
+[spine]
+max_count = 128
+
+[model]
+max_count = 128
+
+[gui]
+max_count = 64
+max_particlefx_count = 64
+max_particle_count = 1024
+
+[collection]
+max_instances = 1024
+
+[collection_proxy]
+max_count = 8
+
+[collectionfactory]
+max_count = 128
+
+[factory]
+max_count = 128
+
+[ios]
+pre_renderered_icons = 0
+bundle_identifier = example.unnamed
+infoplist = /builtins/manifests/ios/Info.plist
+
+[android]
+version_code = 1
+package = com.example.todo
+manifest = /builtins/manifests/android/AndroidManifest.xml
+iap_provider = GooglePlay
+input_method = KeyEvent
+immersive_mode = 0
+debuggable = 0
+
+[osx]
+infoplist = /builtins/manifests/osx/Info.plist
+bundle_identifier = example.unnamed
+
+[windows]
+
+[html5]
+custom_heap_size = 0
+include_dev_tool = 0
+htmlfile = /builtins/manifests/web/engine_template.html
+archive_location_prefix = archive
+
+[particle_fx]
+max_count = 64
+max_particle_count = 1024
+
+[iap]
+auto_finish_transactions = 1
+
+[network]
+http_timeout = 0
+
+[library]
+
+[script]
+shared_state = 1
+
+[tracking]
+
+[label]
+max_count = 64
+subpixels = 1
+
+[profiler]
+track_cpu = 0
+
+[liveupdate]
+settings = /liveupdate.settings
+

BIN
docs/assets/easier/archive/game.public.der0


BIN
docs/assets/easier/defold_sound.swf


+ 652 - 0
docs/assets/easier/dmloader.js

@@ -0,0 +1,652 @@
+/* ********************************************************************* */
+/* Load and combine data that is split into archives                     */
+/* ********************************************************************* */
+
+var Combine = {
+    _targets: [],
+    _targetIndex: 0,
+    // target: build target
+    //  name: intended filepath of built object
+    //  size: expected size of built object.
+    //  data: combined data
+    //  downloaded: total amount of data downloaded
+    //  pieces: array of name, offset and data objects
+    //  numExpectedFiles: total number of files expected in description
+    //  lastRequestedPiece: index of last data file requested (strictly ascending)
+    //  totalLoadedPieces: counts the number of data files received
+
+    //MAX_CONCURRENT_XHR: 6,    // remove comment if throttling of XHR is desired.
+
+    isCompleted: false,       // status of process
+
+    _onCombineCompleted: [],    // signature: name, data.
+    _onAllTargetsBuilt:[],      // signature: void
+    _onDownloadProgress: [],    // signature: downloaded, total
+
+    _totalDownloadBytes: 0,
+    _archiveLocationFilter: function(path) { return "split" + path; },
+
+    addProgressListener: function(callback) {
+        if (typeof callback !== 'function') {
+            throw "Invalid callback registration";
+        }
+        this._onDownloadProgress.push(callback);
+    },
+
+    addCombineCompletedListener: function(callback) {
+        if (typeof callback !== 'function') {
+            throw "Invalid callback registration";
+        }
+        this._onCombineCompleted.push(callback);
+    },
+
+    addAllTargetsBuiltListener: function(callback) {
+        if (typeof callback !== 'function') {
+            throw "Invalid callback registration";
+        }
+        this._onAllTargetsBuilt.push(callback);
+    },
+
+    // descriptUrl: location of text file describing files to be preloaded
+    process: function(descriptUrl) {
+        var xhr = new XMLHttpRequest();
+        xhr.open('GET', descriptUrl);
+        xhr.responseType = 'text';
+        xhr.onload = function(evt) {
+            Combine.onReceiveDescription(xhr);
+        };
+        xhr.send(null);
+    },
+
+    cleanUp: function() {
+        this._targets =  [];
+        this._targetIndex = 0;
+        this.isCompleted = false;
+        this._onCombineCompleted = [];
+        this._onAllTargetsBuilt = [];
+        this._onDownloadProgress = [];
+
+        this._totalDownloadBytes = 0;
+    },
+
+    onReceiveDescription: function(xhr) {
+        var json = JSON.parse(xhr.responseText);
+        this._targets = json.content;
+        this._totalDownloadBytes = 0;
+
+        var targets = this._targets;
+        for(var i=0; i<targets.length; ++i) {
+            this._totalDownloadBytes += targets[i].size;
+        }
+        this.requestContent();
+    },
+
+    requestContent: function() {
+        var target = this._targets[this._targetIndex];
+        if (1 < target.pieces.length) {
+            target.data = new Uint8Array(target.size);
+        }
+        var limit = target.pieces.length;
+        if (typeof this.MAX_CONCURRENT_XHR !== 'undefined') {
+            limit = Math.min(limit, this.MAX_CONCURRENT_XHR);
+        }
+        for (var i=0; i<limit; ++i) {
+            this.requestPiece(target, i);
+        }
+    },
+
+    requestPiece: function(target, index) {
+        if (index <  target.lastRequestedPiece) {
+            throw "Request out of order";
+        }
+
+        target.lastRequestedPiece = index;
+        target.progress = {};
+
+        var item = target.pieces[index];
+        var xhr = new XMLHttpRequest();
+        xhr.open('GET', this._archiveLocationFilter('/' + item.name), true);
+        xhr.responseType = 'arraybuffer';
+        xhr.onprogress = function(evt) {
+           target.progress[item.name] = {total: 0, downloaded: 0};
+            if (evt.total && evt.lengthComputable) {
+                target.progress[item.name].total = evt.total;
+            }
+            if (evt.loaded && evt.lengthComputable) {
+                target.progress[item.name].downloaded = evt.loaded;
+                Combine.updateProgress(target);
+            }
+        };
+        xhr.onload = function(evt) {
+            item.data = new Uint8Array(xhr.response);
+            item.dataLength = item.data.length;
+            target.progress[item.name].total = item.dataLength;
+            target.progress[item.name].downloaded = item.dataLength;
+            Combine.copyData(target, item);
+            Combine.onPieceLoaded(target, item);
+            Combine.updateProgress(target);
+            item.data = undefined;
+        };
+        xhr.send(null);
+    },
+
+    updateProgress: function(target) {
+        var total_downloaded = 0;
+        for (var p in target.progress) {
+            total_downloaded += target.progress[p].downloaded;
+        }
+        for(i = 0; i<this._onDownloadProgress.length; ++i) {
+            this._onDownloadProgress[i](total_downloaded, this._totalDownloadBytes);
+        }
+    },
+
+    copyData: function(target, item) {
+        if (1 == target.pieces.length) {
+            target.data = item.data;
+        } else {
+            var start = item.offset;
+            var end = start + item.data.length;
+            if (0 > start) {
+                throw "Buffer underflow";
+            }
+            if (end > target.data.length) {
+                throw "Buffer overflow";
+            }
+            target.data.set(item.data, item.offset);
+        }
+    },
+
+    onPieceLoaded: function(target, item) {
+        if (typeof target.totalLoadedPieces === 'undefined') {
+            target.totalLoadedPieces = 0;
+        }
+        ++target.totalLoadedPieces;
+        if (target.totalLoadedPieces == target.pieces.length) {
+            this.finalizeTarget(target);
+            ++this._targetIndex;
+            for (var i=0; i<this._onCombineCompleted.length; ++i) {
+                this._onCombineCompleted[i](target.name, target.data);
+            }
+            if (this._targetIndex < this._targets.length) {
+                this.requestContent();
+            } else {
+                this.isCompleted = true;
+                for (i=0; i<this._onAllTargetsBuilt.length; ++i) {
+                    this._onAllTargetsBuilt[i]();
+                }
+            }
+        } else {
+            var next = target.lastRequestedPiece + 1;
+            if (next < target.pieces.length) {
+                this.requestPiece(target, next);
+            }
+        }
+    },
+
+    finalizeTarget: function(target) {
+        var actualSize = 0;
+        for (var i=0;i<target.pieces.length; ++i) {
+            actualSize += target.pieces[i].dataLength;
+        }
+        if (actualSize != target.size) {
+            throw "Unexpected data size";
+        }
+
+        if (1 < target.pieces.length) {
+            var output = target.data;
+            var pieces = target.pieces;
+            for (i=0; i<pieces.length; ++i) {
+                var item = pieces[i];
+                // Bounds check
+                var start = item.offset;
+                var end = start + item.dataLength;
+                if (0 < i) {
+                    var previous = pieces[i - 1];
+                    if (previous.offset + previous.dataLength > start) {
+                        throw "Segment underflow";
+                    }
+                }
+                if (pieces.length - 2 > i) {
+                    var next = pieces[i + 1];
+                    if (end > next.offset) {
+                        throw "Segment overflow";
+                    }
+                }
+            }
+        }
+    }
+};
+
+/* ********************************************************************* */
+/* Default splash and progress visualisation                             */
+/* ********************************************************************* */
+
+var Progress = {
+    progress_id: "defold-progress",
+    bar_id: "defold-progress-bar",
+
+    addProgress : function (canvas) {
+        /* Insert default progress bar below canvas */
+        canvas.insertAdjacentHTML('afterend', '<div id="' + Progress.progress_id + '" class="canvas-app-progress"><div id="' + Progress.bar_id + '" class="canvas-app-progress-bar" style="width: 0%;">0%</div></div>');
+        Progress.bar = document.getElementById(Progress.bar_id);
+        Progress.progress = document.getElementById(Progress.progress_id);
+    },
+
+    updateProgress: function (percentage, text) {
+        Progress.bar.style.width = percentage + "%";
+
+        text = (typeof text === 'undefined') ? Math.round(percentage) + "%" : text;
+        Progress.bar.innerText = text;
+    },
+
+    removeProgress: function () {
+        if (Progress.progress.parentElement !== null) {
+            Progress.progress.parentElement.removeChild(Progress.progress);
+
+            // Remove any background/splash image that was set in runApp().
+            // Workaround for Safari bug DEF-3061.
+            Module.canvas.style.background = "";
+            Module["on_game_start"]();
+        }
+    }
+};
+
+/* ********************************************************************* */
+/* Default input override                                                */
+/* ********************************************************************* */
+
+var CanvasInput = {
+    arrowKeysHandler : function(e) {
+        switch(e.keyCode) {
+            case 37: case 38: case 39:  case 40: // Arrow keys
+            case 32: e.preventDefault(); e.stopPropagation(); // Space
+            default: break; // do not block other keys
+        }
+    },
+
+    onFocusIn : function(e) {
+        window.addEventListener("keydown", CanvasInput.arrowKeysHandler, false);
+    },
+
+    onFocusOut: function(e) {
+        window.removeEventListener("keydown", CanvasInput.arrowKeysHandler, false);
+    },
+
+    addToCanvas : function(canvas) {
+        canvas.addEventListener("focus", CanvasInput.onFocusIn, false);
+        canvas.addEventListener("blur", CanvasInput.onFocusOut, false);
+        canvas.focus();
+        CanvasInput.onFocusIn();
+    }
+};
+
+/* ********************************************************************* */
+/* Module is Emscripten namespace                                        */
+/* ********************************************************************* */
+
+var Module = {
+    noInitialRun: true,
+
+    _filesToPreload: [],
+    _archiveLoaded: false,
+    _preLoadDone: false,
+    _waitingForArchive: false,
+
+    // Persistent storage
+    persistentStorage: true,
+    _syncInProgress: false,
+    _syncNeeded: false,
+    _syncInitial: false,
+    _syncMaxTries: 3,
+    _syncTries: 0,
+
+    print: function(text) { console.log(text); },
+    printErr: function(text) { console.error(text); },
+
+    setStatus: function(text) { console.log(text); },
+
+    isWASMSupported: (function() {
+        try {
+            if (typeof WebAssembly === "object"
+                && typeof WebAssembly.instantiate === "function") {
+                const module = new WebAssembly.Module(Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00));
+                if (module instanceof WebAssembly.Module)
+                    return new WebAssembly.Instance(module) instanceof WebAssembly.Instance;
+            }
+        } catch (e) {
+        }
+        return false;
+    })(),
+
+    prepareErrorObject: function (err, url, line, column, errObj) {
+        line = typeof line == "undefined" ? 0 : line;
+        column = typeof column == "undefined" ? 0 : column;
+        url = typeof url == "undefined" ? "" : url;
+        var errorLine = url + ":" + line + ":" + column;
+
+        var error = errObj || (typeof window.event != "undefined" ? window.event.error : "" ) || err || "Undefined Error";
+        var message = "";
+        var stack = "";
+        var backtrace = "";
+
+        if (typeof error == "object" && typeof error.stack != "undefined" && typeof error.message != "undefined") {
+            stack = String(error.stack);
+            message = String(error.message);
+        } else {
+            stack = String(error).split("\n");
+            message = stack.shift();
+            stack = stack.join("\n");
+        }
+        stack = stack || errorLine;
+
+        var callLine = /at (\S+:\d*$)/.exec(message);
+        if (callLine) {
+            message = message.replace(/(at \S+:\d*$)/, "");
+            stack = callLine[1] + "\n" + stack;
+        }
+
+        message = message.replace(/(abort\(.+\)) at .+/, "$1");
+        stack = stack.replace(/\?{1}\S+(:\d+:\d+)/g, "$1");
+        stack = stack.replace(/ *at (\S+)$/gm, "@$1");
+        stack = stack.replace(/ *at (\S+)(?: \[as \S+\])? +\((.+)\)/g, "$1@$2");
+        stack = stack.replace(/^((?:Object|Array)\.)/gm, "");
+        stack = stack.split("\n");
+
+        return { stack:stack, message:message };
+    },
+
+    hasWebGLSupport: function() {
+        var webgl_support = false;
+        try {
+            var canvas = document.createElement("canvas");
+            var gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
+            if (gl && gl instanceof WebGLRenderingContext) {
+                webgl_support = true;
+            }
+        } catch (error) {
+            console.log("An error occurred while detecting WebGL support: " + error);
+            webgl_support = false;
+        }
+
+        return webgl_support;
+    },
+
+    handleVisibilityChange: function () {
+        GLFW.onFocusChanged(document[Module.hiddenProperty] ? 0 : 1);
+    },
+
+    getHiddenProperty: function () {
+        if ('hidden' in document) return 'hidden';
+        var prefixes = ['webkit','moz','ms','o'];
+        for (var i = 0; i < prefixes.length; i++){
+            if ((prefixes[i] + 'Hidden') in document)
+                return prefixes[i] + 'Hidden';
+        }
+        return null;
+    },
+
+    setupVisibilityChangeListener: function() {
+        Module.hiddenProperty = Module.getHiddenProperty();
+        if( Module.hiddenProperty ) {
+            var eventName = Module.hiddenProperty.replace(/[H|h]idden/,'') + 'visibilitychange';
+            document.addEventListener(eventName, Module.handleVisibilityChange, false);
+        } else {
+            console.log("No document.hidden property found. The focus events won't be enabled.")
+        }
+    },
+
+    /**
+    * Module.runApp - Starts the application given a canvas element id
+    *
+    * 'extra_params' is an optional object that can have the following fields:
+    *
+    *     'splash_image':
+    *         Path to an image that should be used as a background image for
+    *         the canvas element.
+    *
+    *     'archive_location_filter':
+    *         Filter function that will run for each archive path.
+    *
+    *     'unsupported_webgl_callback':
+    *         Function that is called if WebGL is not supported.
+    *
+    *     'engine_arguments':
+    *         List of arguments (strings) that will be passed to the engine.
+    *
+    *     'persistent_storage':
+    *         Boolean toggling the usage of persistent storage.
+    *
+    *     'custom_heap_size':
+    *         Number of bytes specifying the memory heap size.
+    *
+    *     'disable_context_menu':
+    *         Disables the right-click context menu on the canvas element if true.
+    *
+    **/
+    runApp: function(app_canvas_id, extra_params) {
+        app_canvas_id = (typeof app_canvas_id === 'undefined') ?  'canvas' : app_canvas_id;
+
+        var params = {
+            splash_image: undefined,
+            archive_location_filter: function(path) { return 'split' + path; },
+            unsupported_webgl_callback: undefined,
+            engine_arguments: [],
+            persistent_storage: true,
+            custom_heap_size: undefined,
+            disable_context_menu: true
+        };
+
+        for (var k in extra_params) {
+            if (extra_params.hasOwnProperty(k)) {
+                params[k] = extra_params[k];
+            }
+        }
+
+        Module.canvas = document.getElementById(app_canvas_id);
+        if (typeof params["splash_image"] !== 'undefined') {
+            Module.canvas.style.background = 'no-repeat center url("' + params["splash_image"] + '")';
+        }
+        Module.arguments = params["engine_arguments"];
+        Module.persistentStorage = params["persistent_storage"];
+        Module["TOTAL_MEMORY"] = params["custom_heap_size"];
+        Module["on_game_start"] = params["game_start"];
+
+        if (Module.hasWebGLSupport()) {
+            // Override game keys
+            CanvasInput.addToCanvas(Module.canvas);
+
+            Module.setupVisibilityChangeListener();
+
+            // Add progress visuals
+            Progress.addProgress(Module.canvas);
+
+            // Add context menu hide-handler if requested
+            if (params["disable_context_menu"])
+            {
+                Module.canvas.oncontextmenu = function(e) {
+                    e.preventDefault();
+                };
+            }
+
+            // Load and assemble archive
+            Combine.addCombineCompletedListener(Module.onArchiveFileLoaded);
+            Combine.addAllTargetsBuiltListener(Module.onArchiveLoaded);
+            Combine.addProgressListener(Module.onArchiveLoadProgress);
+            Combine._archiveLocationFilter = params["archive_location_filter"];
+            Combine.process(Combine._archiveLocationFilter('/archive_files.json'));
+        } else {
+            Progress.addProgress(Module.canvas);
+            Progress.updateProgress(100, "Unable to start game, WebGL not supported");
+            Module.setStatus = function(text) {
+                if (text) Module.printErr('[missing WebGL] ' + text);
+            };
+
+            if (typeof params["unsupported_webgl_callback"] === "function") {
+                params["unsupported_webgl_callback"]();
+            }
+        }
+    },
+
+    onArchiveLoadProgress: function(downloaded, total) {
+        Progress.updateProgress(downloaded / total * 100);
+    },
+
+    onArchiveFileLoaded: function(name, data) {
+        Module._filesToPreload.push({path: name, data: data});
+    },
+
+    onArchiveLoaded: function() {
+        Combine.cleanUp();
+        Module._archiveLoaded = true;
+        Progress.updateProgress(100, "Starting...");
+
+        if (Module._waitingForArchive) {
+            Module._preloadAndCallMain();
+        }
+    },
+
+    toggleFullscreen: function() {
+        if (GLFW.isFullscreen) {
+            GLFW.cancelFullScreen();
+        } else {
+            GLFW.requestFullScreen();
+        }
+    },
+
+    preSync: function(done) {
+        // Initial persistent sync before main is called
+        FS.syncfs(true, function(err) {
+            if(err) {
+                Module._syncTries += 1;
+                console.error("FS syncfs error: " + err);
+                if (Module._syncMaxTries > Module._syncTries) {
+                    Module.preSync(done);
+                } else {
+                    Module._syncInitial = true;
+                    done();
+                }
+            } else {
+                Module._syncInitial = true;
+                if (done !== undefined) {
+                    done();
+                }
+            }
+        });
+    },
+
+    preloadAll: function() {
+        if (Module._preLoadDone) {
+            return;
+        }
+        Module._preLoadDone = true;
+        for (var i = 0; i < Module._filesToPreload.length; ++i) {
+            var item = Module._filesToPreload[i];
+            FS.createPreloadedFile("", item.path, item.data, true, true);
+        }
+    },
+
+    // Tries to do a MEM->IDB sync
+    // It will flag that another one is needed if there is already one sync running.
+    persistentSync: function() {
+
+        // Need to wait for the initial sync to finish since it
+        // will call close on all its file streams which will trigger
+        // new persistentSync for each.
+        if (Module._syncInitial) {
+            if (Module._syncInProgress) {
+                Module._syncNeeded = true;
+            } else {
+                Module._startSyncFS();
+            }
+        }
+    },
+
+    preInit: [function() {
+        /* Mount filesystem on preinit */
+        var dir = DMSYS.GetUserPersistentDataRoot();
+        FS.mkdir(dir);
+
+        // If IndexedDB is supported we mount the persistent data root as IDBFS,
+        // then try to do a IDB->MEM sync before we start the engine to get
+        // previously saved data before boot.
+        window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+        if (Module.persistentStorage && window.indexedDB) {
+            FS.mount(IDBFS, {}, dir);
+
+            // Patch FS.close so it will try to sync MEM->IDB
+            var _close = FS.close; FS.close = function(stream) { var r = _close(stream); Module.persistentSync(); return r; }
+
+            // Sync IDB->MEM before calling main()
+            Module.preSync(function() {
+                Module._preloadAndCallMain();
+            });
+        } else {
+            Module._preloadAndCallMain();
+        }
+    }],
+
+    preRun: [function() {
+        /* If archive is loaded, preload all its files */
+        if(Module._archiveLoaded) {
+            Module.preloadAll();
+        }
+    }],
+
+    postRun: [function() {
+        if(Module._archiveLoaded) {
+            Progress.removeProgress();
+        }
+    }],
+
+    _preloadAndCallMain: function() {
+        // If the archive isn't loaded,
+        // we will have to wait with calling main.
+        if (!Module._archiveLoaded) {
+            Module._waitingForArchive = true;
+        } else {
+
+            // Need to set heap size before calling main
+            TOTAL_MEMORY = Module["TOTAL_MEMORY"] || TOTAL_MEMORY;
+
+            Module.preloadAll();
+            Progress.removeProgress();
+            if (Module.callMain === undefined) {
+                Module.noInitialRun = false;
+            } else {
+                Module.callMain(Module.arguments);
+            }
+        }
+    },
+
+    // Wrap IDBFS syncfs call with logic to avoid multiple syncs
+    // running at the same time.
+    _startSyncFS: function() {
+        Module._syncInProgress = true;
+
+        if (Module._syncMaxTries > Module._syncTries) {
+            FS.syncfs(false, function(err) {
+                Module._syncInProgress = false;
+
+                if (err) {
+                    console.error("Module._startSyncFS error: " + err);
+                    Module._syncTries += 1;
+                }
+
+                if (Module._syncNeeded) {
+                    Module._syncNeeded = false;
+                    Module._startSyncFS();
+                }
+
+            });
+        }
+    },
+};
+
+window.onerror = function(err, url, line, column, errObj) {
+    var errorObject = Module.prepareErrorObject(err, url, line, column, errObj);
+    Module.ccall('JSWriteDump', 'null', ['string'], [JSON.stringify(errorObject.stack)]);
+    Module.setStatus('Exception thrown, see JavaScript console');
+    Module.setStatus = function(text) {
+        if (text) Module.printErr('[post-exception status] ' + text);
+    };
+};

BIN
docs/assets/easier/easier.wasm


Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 0
docs/assets/easier/easier_asmjs.js


Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 0
docs/assets/easier/easier_wasm.js


BIN
docs/assets/easier/preview.jpg


+ 49 - 36
docs/en/en.json

@@ -154,6 +154,10 @@
                         "path": "/manuals/workflow",
                         "name": "Workflow"
                     },
+                    {
+                        "path": "/manuals/writing-code",
+                        "name": "Writing code"
+                    },
                     {
                         "path": "/manuals/hot-reload",
                         "name": "Hot reloading"
@@ -170,6 +174,10 @@
                         "path": "/manuals/profiling",
                         "name": "Profiling"
                     },
+                    {
+                        "path": "/manuals/bundling",
+                        "name": "Bundling an application"
+                    },
                     {
                         "path": "/manuals/flash",
                         "name": "Defold for Flash users"
@@ -222,12 +230,28 @@
                         "name": "Atlas"
                     },
                     {
-                        "path": "/manuals/spine",
-                        "name": "Spine animation"
+                        "path": "/manuals/collection-factory",
+                        "name": "Collection factory"
                     },
                     {
-                        "path": "/manuals/spinemodel",
-                        "name": "Spine model"
+                        "path": "/manuals/collection-proxy",
+                        "name": "Collection proxy"
+                    },
+                    {
+                        "path": "/manuals/camera",
+                        "name": "Camera"
+                    },
+                    {
+                        "path": "/manuals/font",
+                        "name": "Font"
+                    },
+                    {
+                        "path": "/manuals/factory",
+                        "name": "Factory"
+                    },
+                    {
+                        "path": "/manuals/label",
+                        "name": "Label"
                     },
                     {
                         "path": "/manuals/model",
@@ -250,28 +274,12 @@
                         "name": "Tilemap"
                     },
                     {
-                        "path": "/manuals/font",
-                        "name": "Font"
-                    },
-                    {
-                        "path": "/manuals/label",
-                        "name": "Label"
-                    },
-                    {
-                        "path": "/manuals/factory",
-                        "name": "Factory"
-                    },
-                    {
-                        "path": "/manuals/collection-factory",
-                        "name": "Collection factory"
-                    },
-                    {
-                        "path": "/manuals/collection-proxy",
-                        "name": "Collection proxy"
+                        "path": "/manuals/spine",
+                        "name": "Spine animation"
                     },
                     {
-                        "path": "/manuals/camera",
-                        "name": "Camera"
+                        "path": "/manuals/spinemodel",
+                        "name": "Spine model"
                     }
                 ]
             },
@@ -418,30 +426,35 @@
             },
             {
                 "name": "EXTENSIONS",
+                "items": [
+                    {
+                        "path": "/manuals/iap",
+                        "name": "In-app purchases"
+                    },
+                    {
+                        "path": "/manuals/push",
+                        "name": "Push notifications"
+                    }
+                ]
+            },
+            {
+                "name": "NATIVE EXTENSIONS",
                 "items": [
                     {
                         "path": "/manuals/extensions",
-                        "name": "Native extensions"
+                        "name": "Introduction"
                     },
                     {
                         "path": "/manuals/extensions-details",
-                        "name": "Native extensions - Details"
+                        "name": "Details"
                     },
                     {
                         "path": "/manuals/extensions-best-practices",
-                        "name": "Native extensions - Best Practices"
+                        "name": "Best Practices"
                     },
                     {
                         "path": "/manuals/extensions-build-variants",
-                        "name": "Native extensions - Build Variants"
-                    },
-                    {
-                        "path": "/manuals/iap",
-                        "name": "In-app purchases"
-                    },
-                    {
-                        "path": "/manuals/push",
-                        "name": "Push notifications"
+                        "name": "Build Variants"
                     }
                 ]
             }

+ 4 - 4
docs/en/faq/faq.md

@@ -100,7 +100,7 @@ Can I use external Git tools?
 
   1. Add the folder you selected for your project location to your Git client. (If you run editor 1, the project is found in "Defold/branches/[project_id]/[user_id]/[name_of_branch]")
   2. Specify your Defold username. The password is the "Access token" that you find under "Settings" in the Defold Dashboard (the huge hexadecimal number).
-  
+
   You can now add, commit, revert, branch and merge as much as you want. Any changes are immediately reflected in Defold.
 
 ## Publishing games
@@ -169,7 +169,7 @@ When I try to create a new project, or open an existing one, the editor crashes.
   See the following reports for more information:
 
   - https://github.com/defold/editor2-issues/issues/1905
-  - https://github.com/defold/editor2-issues/issues/1886 
+  - https://github.com/defold/editor2-issues/issues/1886
 
   If this is your problem try the following workaround:
 
@@ -204,7 +204,7 @@ I'm running on Linux and the editor won't start.
 
 ## Android issues
 
-Is it possible to hide the the navigation and status bars on Android?
+Is it possible to hide the navigation and status bars on Android?
 
 : Yes, set the *immersive_mode* setting in the *Android* section of your *game.project* file. This lets your app take over the whole screen and capture all touch events on the screen.
 
@@ -224,7 +224,7 @@ I can't add a game object as a child to another game object, why?
 
 Why can't I broadcast messages to all children of a game object?
 
-: Parent-child relations express nothing else than the scene-graph transform relations 
+: Parent-child relations express nothing else than the scene-graph transform relations
   and should not be mistaken for object orientation aggregates. If you try to focus on your game data and how to best transform it as your game alter its state you will likely find less need to send messages with state data to many objects all the time. In the cases where you will need data hierarchies, these are easily constructed and handled in Lua.
 
 Why am I experiencing visual artifacts around the edges of my sprites?

+ 33 - 5
docs/en/manuals/android.md

@@ -50,7 +50,7 @@ Press <kbd>Create Bundle</kbd> and you will then be prompted to specify where on
 
 ![Android Application Package file](images/android/apk_file.png)
 
-The editor writes an *.apk* file which is an Android application bundle. This file can be copied to your device with the `adb` tool (see below), or to Google Play via the [Google Play developer console](https://play.google.com/apps/publish/). You can specify what icon(s) to use for the app, set version code etc in the "game.project" project settings file.
+The editor writes an *.apk* file which is an Android application bundle. This file can be copied to your device with the `adb` tool (see below), or to Google Play via the [Google Play developer console](https://play.google.com/apps/publish/). You can specify what icon(s) to use for the app, set version code etc in the "game.project" [project settings file](/manuals/project-settings/#_android).
 
 ```
 $ adb install Defold\ examples.apk
@@ -59,11 +59,40 @@ $ adb install Defold\ examples.apk
 Success
 ```
 
+## Permissions
+
+The Defold engine requires a number of different permissions for all engine features to work. The permissions are defined in the `AndroidManifest.xml`, specified in the "game.project" [project settings file](/manuals/project-settings/#_android). You can read more about Android permissions in [the official docs](https://developer.android.com/guide/topics/permissions/overview). The following permissions are requested in the default manifest:
+
+### android.permission.INTERNET and android.permission.ACCESS_NETWORK_STATE (Protection level: normal)
+Allows applications to open network sockets and access information about networks. These permission are needed for internet access. ([Android official docs](https://developer.android.com/reference/android/Manifest.permission#INTERNET)) and ([Android official docs](https://developer.android.com/reference/android/Manifest.permission#ACCESS_NETWORK_STATE)).
+
+### com.android.vending.BILLING
+Google Play Billing is a service that lets you sell digital content from inside an Android app, or in-app. This permission is needed for [in-app purchases](/manuals/iap/) to work.
+
+### android.permission.WRITE_EXTERNAL_STORAGE (Protection level: dangerous)
+Allows an application to write to external storage. Starting in API level 19, this permission is not required to read/write files in your application-specific directories returned by Context.getExternalFilesDir(String) and Context.getExternalCacheDir(). This permission is needed if you intend to save/load files from disk (using io.* or sys.save/load) outside of the folder provided by [sys.get_save_file()](/ref/sys/#sys.get_save_file:application_id-file_name) and have `android:minSdkVersion` set to less than 19 in the Android manifest. ([Android official docs](https://developer.android.com/reference/android/Manifest.permission#WRITE_EXTERNAL_STORAGE)).
+
+### android.permission.READ_PHONE_STATE (Protection level: dangerous)
+Allows read only access to phone state, including the phone number of the device, current cellular network information, the status of any ongoing calls, and a list of any PhoneAccounts registered on the device. This permission is used to detect if a call is ongoing (for [sound.is_phone_call_active()](/ref/sound/#sound.is_phone_call_active)). ([Android official docs](https://developer.android.com/reference/android/Manifest.permission#READ_PHONE_STATE)).
+
+### android.permission.GET_ACCOUNTS (Protection level: dangerous)
+Allows access to the list of accounts in the Accounts Service. This permission was used when registering for push notifications, but it is actually not needed. You can safely remove this permission (it will be removed from the default manifest later). ([Android official docs](https://developer.android.com/reference/android/Manifest.permission#GET_ACCOUNTS)).
+
+### android.permission.WAKE_LOCK (Protection level: normal)
+Allows using PowerManager WakeLocks to keep processor from sleeping or screen from dimming. This permission is needed to temporarily prevent the device from sleeping while receiving a push notification. ([Android official docs](https://developer.android.com/reference/android/Manifest.permission#WAKE_LOCK))
+
+### android.permission.VIBRATE (Protection level: normal)
+Allows access to the vibrator. This permission is needed for the device to vibrate when a push notification is received. ([Android official docs](https://developer.android.com/reference/android/Manifest.permission#VIBRATE))
+
+### com.google.android.c2dm.permission.RECEIVE and {{android.package}}.permission.C2D_MESSAGE
+These permissions are needed to receive push notifications.
+
+
 ## Android Debug Bridge
 
-The `adb` command line tool is an easy to use and versatile program that is used to interact with Android devices. You can download and install `adb` as part of the Android SDK package, for Mac, Linux or Windows.
+The `adb` command line tool is an easy to use and versatile program that is used to interact with Android devices. You can download and install `adb` as part of the Android SDK Platform-Tools, for Mac, Linux or Windows.
 
-Download the Android SDK from: http://developer.android.com/sdk/index.html. You find the *adb* tool in *<sdk>/platform-tools/*. Alternatively, platform specific packages can be installed through respective package managers.
+Download the Android SDK Platform-Tools from: https://developer.android.com/studio/releases/platform-tools. You find the *adb* tool in */platform-tools/*. Alternatively, platform specific packages can be installed through respective package managers.
 
 On Ubuntu Linux:
 
@@ -97,7 +126,7 @@ If your device does not show up, verify that you have enabled *USB debugging* on
 
 ## Debugging an application bundle
 
-A bundle built with the debug mode version of the engine (i.e. "Release mode" unchecked during bundling) will send all its console output to the Android system log. Access the log with the `adb` tool and give the `logcat` command. You probably want to filter the output by a tag (`-s [tagname]`):
+A bundle built with the debug mode version of the engine (i.e. "Debug" selected as variant during bundling) will send all its console output to the Android system log. Access the log with the `adb` tool and give the `logcat` command. You probably want to filter the output by a tag (`-s [tagname]`):
 
 ```
 $ adb logcat -s "defold"
@@ -125,4 +154,3 @@ I'm getting "Failure [INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES]" when inst
           pkg: /data/local/tmp/Defold examples.apk
   Success
   ```
-

+ 99 - 15
docs/en/manuals/animation.md

@@ -329,20 +329,105 @@ The pingpong modes run the animation first forward, then backward. A set of corr
 
 Easing defines how the animated value changes over time. The images below describe the functions applied over time to create the easing.
 
-The corresponding value to use when calling `go.animate()` are `go.EASING_LINEAR`, `go.EASING_INBACK`, `go.EASING_OUTBACK` and so forth.
-
-For `gui.animate()` the values are named `gui.EASING_LINEAR`, `gui.EASING_INBACK`, `gui.EASING_OUTBACK` and so forth.
-
-```linechart
-{
-  "labels": [1, "Tuesday", "Wednesday", "Thursday", "Friday"],
-  "series": [
-    [12, 9, 7, 8, 5],
-    [2, 1, 3.5, 7, 3],
-    [1, 3, 4, 5, 6]
-  ]
-}
-```
+The following are valid easing values for `go.animate()`:
+| | |
+|---|---|
+| go.EASING_LINEAR | |
+| go.EASING_INBACK | go.EASING_OUTBACK |
+| go.EASING_INOUTBACK | go.EASING_OUTINBACK |
+| go.EASING_INBOUNCE | go.EASING_OUTBOUNCE |
+| go.EASING_INOUTBOUNCE | go.EASING_OUTINBOUNCE |
+| go.EASING_INELASTIC | go.EASING_OUTELASTIC |
+| go.EASING_INOUTELASTIC | go.EASING_OUTINELASTIC |
+| go.EASING_INSINE | go.EASING_OUTSINE |
+| go.EASING_INOUTSINE | go.EASING_OUTINSINE |
+| go.EASING_INEXPO | go.EASING_OUTEXPO |
+| go.EASING_INOUTEXPO | go.EASING_OUTINEXPO |
+| go.EASING_INCIRC | go.EASING_OUTCIRC |
+| go.EASING_INOUTCIRC | go.EASING_OUTINCIRC |
+| go.EASING_INQUAD | go.EASING_OUTQUAD |
+| go.EASING_INOUTQUAD | go.EASING_OUTINQUAD |
+| go.EASING_INCUBIC | go.EASING_OUTCUBIC |
+| go.EASING_INOUTCUBIC | go.EASING_OUTINCUBIC |
+| go.EASING_INQUART | go.EASING_OUTQUART |
+| go.EASING_INOUTQUART | go.EASING_OUTINQUART |
+| go.EASING_INQUINT | go.EASING_OUTQUINT |
+| go.EASING_INOUTQUINT | go.EASING_OUTINQUINT |
+
+The following are valid easing values for `gui.animate()`:
+| | |
+|---|---|
+| gui.EASING_LINEAR | |
+| gui.EASING_INBACK | gui.EASING_OUTBACK |
+| gui.EASING_INOUTBACK | gui.EASING_OUTINBACK |
+| gui.EASING_INBOUNCE | gui.EASING_OUTBOUNCE |
+| gui.EASING_INOUTBOUNCE | gui.EASING_OUTINBOUNCE |
+| gui.EASING_INELASTIC | gui.EASING_OUTELASTIC |
+| gui.EASING_INOUTELASTIC | gui.EASING_OUTINELASTIC |
+| gui.EASING_INSINE | gui.EASING_OUTSINE |
+| gui.EASING_INOUTSINE | gui.EASING_OUTINSINE |
+| gui.EASING_INEXPO | gui.EASING_OUTEXPO |
+| gui.EASING_INOUTEXPO | gui.EASING_OUTINEXPO |
+| gui.EASING_INCIRC | gui.EASING_OUTCIRC |
+| gui.EASING_INOUTCIRC | gui.EASING_OUTINCIRC |
+| gui.EASING_INQUAD | gui.EASING_OUTQUAD |
+| gui.EASING_INOUTQUAD | gui.EASING_OUTINQUAD |
+| gui.EASING_INCUBIC | gui.EASING_OUTCUBIC |
+| gui.EASING_INOUTCUBIC | gui.EASING_OUTINCUBIC |
+| gui.EASING_INQUART | gui.EASING_OUTQUART |
+| gui.EASING_INOUTQUART | gui.EASING_OUTINQUART |
+| gui.EASING_INQUINT | gui.EASING_OUTQUINT |
+| gui.EASING_INOUTQUINT | gui.EASING_OUTINQUINT |
+
+<div id="game-container" class="game-container">
+    <img id="game-preview" src="//storage.googleapis.com/defold-doc/assets/easier/preview.jpg"/>
+    <canvas id="game-canvas" tabindex="1" width="640" height="512">
+    </canvas>
+    <button id="game-button">
+        SHOW EXAMPLE <span class="icon"></span>
+    </button>
+    <script src="//storage.googleapis.com/defold-doc/assets/easier/dmloader.js">
+    </script>
+    <script>
+        document.getElementById("game-button").onclick = function (e) {
+            var extra_params = {
+              archive_location_filter: function( path ) {
+                return ('//storage.googleapis.com/defold-doc/assets/easier/archive' + path + '');
+              },
+              splash_image: '//storage.googleapis.com/defold-doc/assets/easier/preview.jpg',
+              custom_heap_size: 268435456,
+              disable_context_menu: true,
+              game_start: function() {
+                  var e = document.getElementById("game-preview");
+                  e.parentElement.removeChild(e);
+              }
+            };
+            Module['onRuntimeInitialized'] = function() {
+              Module.runApp("game-canvas", extra_params);
+            };
+            Module['locateFile'] = function(path, scriptDirectory)
+            {
+              if (path == "dmengine.wasm" || path == "dmengine_release.wasm" || path == "dmengine_headless.wasm") {
+                path = "easier.wasm";
+              }
+              return scriptDirectory + path;
+            };
+            function load_engine() {
+              var engineJS = document.createElement('script');
+              engineJS.type = 'text/javascript';
+              if (Module['isWASMSupported']) {
+                  engineJS.src = '//storage.googleapis.com/defold-doc/assets/easier/easier_wasm.js';
+              } else {
+                  engineJS.src = '//storage.googleapis.com/defold-doc/assets/easier/easier_asmjs.js';
+              }
+              document.head.appendChild(engineJS);
+            }
+            load_engine();
+            document.getElementById("game-button").style.display = 'none';
+            document.getElementById("game-button").onclick = null;
+        };
+    </script>
+</div>
 
 ![Linear interpolation](images/properties/easing_linear.png){.inline}
 ![In back](images/properties/easing_inback.png){.inline}
@@ -433,4 +518,3 @@ function init(self)
     go.animate(".", "position.y", go.PLAYBACK_ONCE_FORWARD, 100, go.EASING_OUTBOUNCE, 2, 0, done_bouncing)
 end
 ```
-

+ 54 - 0
docs/en/manuals/bundling.md

@@ -0,0 +1,54 @@
+---
+title: Bundling an application
+brief: This manual covers how to create an application bundle.
+---
+
+# Bundling an application
+
+While developing your application you should make a habit of testing the game on the target platforms as often as possible. You should do this to detect performance issues early on in the development process where these things are much easier to fix. It is also recommended to test on all target platforms to find discrepancies in for instances shaders early on. When developing on mobile you have the option to use the [mobile development app](/manuals/dev-app/) to push content to the app, instead of having to do a full bundle and uninstall/install cycle.
+
+You can create an application bundle for all platforms that Defold supports from within the Defold editor itself, with no external tools needed. You can also bundle from the command line using our command line tools.
+
+## Bundling from within the editor
+
+You create an application bundle from the Project menu and Bundle option:
+
+![](images/bundling/bundle_menu.png)
+
+Selecting any of the menu options will bring up the Bundle dialog for that specific platform.
+
+### Android
+
+Creating an Android application bundle (.apk file) as well as the prerequisite setup is documented in the [Android manual](/manuals/android/#_creating_an_android_application_bundle).
+
+### iOS
+
+Creating an iOS application bundle (.ipa file) as well as the prerequisite setup is documented in the [iOS manual](/manuals/ios/#_creating_an_ios_application_bundle).
+
+### OSX
+
+Creating an OSX application bundle (.app file) requires no specific setup, but optional platform specific configuration is done in the "game.project" [project settings file](/manuals/project-settings/#_macos_os_x).
+
+### Linux
+
+Creating a Linux application bundle requires no specific setup and no optional platform specific configuration in the "game.project" [project settings file](/manuals/project-settings/).
+
+### Windows
+
+Creating a Windows application bundle (.exe file) requires no specific setup, but optional platform specific configuration is done in the "game.project" [project settings file](/manuals/project-settings/#_windows).
+
+#### Facebook Gameroom
+
+It is possible to create a special version of a Windows application bundle specifically for Facebook Gameroom. This process is documented in the [Facebook Gameroom manual](/manuals/gameroom/).
+
+### HTML5
+
+Creating an HTML5 application bundle as well as optional setup is documented in the [HTML5 manual](/manuals/html5/#_creating_html5_content).
+
+#### Facebook Instant Games
+
+It is possible to create a special version of an HTML5 application bundle specifically for Facebook Instant Games. This process is documented in the [Facebook Instant Games manual](/manuals/instant-games/).
+
+## Bundling from the command line
+
+While doing day to day development of your application it is likely that you build and bundle from within the Defold editor. In other circumstances you may wish to automatically generate application bundles, for instance batch building for all targets when releasing a new version or when creating nightly builds of the latest version of the game, perhaps in a CI environment. Building and bundling of an application can be done outside the normal editor workflow using the [Bob command line tool](/manuals/bob/).

+ 1 - 1
docs/en/manuals/collection-proxy.md

@@ -33,7 +33,7 @@ Since script components need to be able to address all objects in the game, even
 
 ![bootstrap](images/collection-proxy/collection_id.png){srcset="images/collection-proxy/[email protected] 2x"}
 
-If the collectino that is loaded contains collection proxy components, the collections that those refer to are *not* loaded automatically. You need to control the loading of these resources through scripts.
+If the collection that is loaded contains collection proxy components, the collections that those refer to are *not* loaded automatically. You need to control the loading of these resources through scripts.
 
 ## Loading a collection
 

+ 10 - 4
docs/en/manuals/debugging.md

@@ -38,9 +38,9 @@ To run the debugger, either <kbd>Debug ▸ Run with Debugger</kbd> which starts
 As soon as the debugger is attached, you have control of the execution of the game through the debugger control buttons in the console, or through the <kbd>Debug</kbd> menu:
 
 Break
-: ![pause](images/debugging/pause.svg){width=60px .left} 
+: ![pause](images/debugging/pause.svg){width=60px .left}
   Break execution of the game immediately. The game will break at its current point. You are now able to inspect the state of the game, advance the game step by step, or continue running it until the next breakpoint. The current point of execution is marked in the code editor:
-  
+
   ![script](images/debugging/script.png){srcset="images/debugging/[email protected] 2x"}
 
 Continue
@@ -106,6 +106,12 @@ Android
 
   The device will then dump all the output to the current terminal, along with any prints from the game.
 
+  If you want to see only Defold application outputs use next command:
+  ```txt
+  cd <path_to_android_sdk>/platform-tools/
+  adb logcat -s defold
+  ```
+
 iOS
 : On iOS you can attach the LLDB debugger to a game running on device. To debug a game it needs to be signed with a “Apple Developer Provisioning Profile” that include the device you want to debug on. Bundle the game from the editor and supply the provisioning profile in the bundle dialog (bundling for iOS is only available on macOS).
 
@@ -124,7 +130,7 @@ If you enable the *Write Log* setting in "game.project", any game output will be
 
 iOS
 : Connect your device to a computer with macOS and Xcode installed.
-  
+
   Open Xcode and go to <kbd>Window ▸ Devices and Simulators</kbd>.
 
   Select your device in the list, then select the relevant app in the *Installed Apps* list.
@@ -164,4 +170,4 @@ Sometimes finding a bug can be a hard and time consuming process, requiring you
 2. Again, figure out which half, of that half, must contain the bug.
 3. Continue narrowing down the code that must cause the bug until you find it.
 
-Happy hunting!
+Happy hunting!

+ 0 - 2
docs/en/manuals/extensions-best-practices.md

@@ -56,8 +56,6 @@ Always make sure that you have access to your dependencies. E.g. if you depend o
 
 The code in that library will be injected into your game, so make sure the library does what it's supposed to do, and nothing more!
 
-<legal note?>
-
 
 ## Project structure
 

+ 5 - 5
docs/en/manuals/gui-pie.md

@@ -19,8 +19,8 @@ Inner Radius
 : The inner radius of the node, expressed along the X axis.
 
 Outer Bounds
-: The shape of the outer bounds of the node. 
-  
+: The shape of the outer bounds of the node.
+
   - `Ellipse` will extend the node to the outer radius.
   - `Rectangle` will extend the node to the node's bounding box.
 
@@ -30,13 +30,13 @@ Perimeter Vertices
 Pie Fill Angle
 : How much of the pie should be filled. Expressed as a counter-clockwise angle starting from the right.
 
-![Properties](images/gui/properties.png){srcset="images/gui-pie/[email protected] 2x"}
+![Properties](images/gui-pie/properties.png){srcset="images/gui-pie/[email protected] 2x"}
 
-If you set a texture on the node, the texture image is applied flat, with the corners of the texture correlating to the corners of the node bounding box. 
+If you set a texture on the node, the texture image is applied flat, with the corners of the texture correlating to the corners of the node bounding box.
 
 ## Modify pie nodes at runtime
 
-Pie nodes respond to any generic node manipulation functions for setting size, pivot, color and so forth. A few text node only functions and properties exist:
+Pie nodes respond to any generic node manipulation functions for setting size, pivot, color and so forth. A few pie node only functions and properties exist:
 
 ```lua
 local pienode = gui.get_node("my_pie_node")

BIN
docs/en/manuals/images/bundling/bundle_menu.png


BIN
docs/en/manuals/images/render/fixed_fit_projection.png


BIN
docs/en/manuals/images/render/fixed_fit_projection_resized.png


BIN
docs/en/manuals/images/render/fixed_fit_projection_resized_smaller.png


BIN
docs/en/manuals/images/render/fixed_projection_zoom_0_5.png


BIN
docs/en/manuals/images/render/fixed_projection_zoom_2_0.png


BIN
docs/en/manuals/images/render/fixed_projection_zoom_2_0_resized.png


BIN
docs/en/manuals/images/render/stretch_projection.png


BIN
docs/en/manuals/images/render/stretch_projection_resized.png


+ 2 - 2
docs/en/manuals/particlefx.md

@@ -192,7 +192,7 @@ There are four types of modifiers available that affect the velocity of particle
 `Vortex`
 : Affects particles in a circular or spiraling direction around its position.
 
-  ![modifiers](images/particlefx/modifier.png){srcset="images/particlefx/[email protected] 2x"}
+  ![modifiers](images/particlefx/modifiers.png){srcset="images/particlefx/[email protected] 2x"}
 
 ## Modifier properties
 
@@ -217,4 +217,4 @@ particlefx.play("#particles")
 particlefx.stop("#particles")
 ```
 
-See the [Particle FX reference documentation](/ref/particlefx) for more information.
+See the [Particle FX reference documentation](/ref/particlefx) for more information.

+ 1 - 1
docs/en/manuals/physics.md

@@ -25,7 +25,7 @@ Triggers
 
 ## Adding a collision object component
 
-A collision object component has a set of *Properties* that sets its type and physics properties. It also contains one or more *Shapes* that define the
+A collision object component has a set of *Properties* that sets its type and physics properties. It also contains one or more *Shapes* that define the whole shape of the physics object.
 
 To add a collision object component to a game object:
 

+ 18 - 8
docs/en/manuals/properties.md

@@ -56,7 +56,7 @@ Legacy functions for reading and writing game object properties also exist. They
 
 | property   | description                            | type            |                  |
 | ---------- | -------------------------------------- | --------------- | ---------------- |
-| *position* | The local position of the game object. | `vector3`.      | `get+set`{.mark} |
+| *position* | The local position of the game object. | `vector3`      | `get+set`{.mark} |
 | *rotation* | Local rotation of game object, expressed as a quaternion.  | `quaternion` | `get+set`{.mark} |
 | *euler*    | Local rotation of game object, Euler angles. | `vector3` | `get+set`{.mark} |
 | *scale*    | Local non uniform scale of the game object, expressed as a vector where each component contains a multiplier along each axis. To double the size in x and y, provide vmath.vector3(2.0, 2.0, 0) | `vector3` | `get+set`{.mark} |
@@ -66,6 +66,7 @@ Legacy functions for reading and writing game object properties also exist. They
 | property   | description                            | type            |                  |
 | ---------- | -------------------------------------- | --------------- | ---------------- |
 | *size*     | The non scaled size of the sprite---its size as taken from the source atlas. | `vector3` | `get`{.mark} |
+| *texture0* | The texture path hash of the sprite. | `hash` | `get`{.mark}|
 | *scale* | Non uniform scale of the sprite. | `vector3` | `get+set`{.mark}|
 
 *COLLISION OBJECT COMPONENT PROPERTIES*
@@ -83,7 +84,7 @@ Legacy functions for reading and writing game object properties also exist. They
 | property   | description                            | type            |                  |
 | ---------- | -------------------------------------- | --------------- | ---------------- |
 | *animation* | The current animation. | `hash` | `get`{.mark} |
-| *skin*.     | The currently applied model skin. (cannot be animated!) | `hash` | `get+set`{.mark} |
+| *skin*     | The currently applied model skin. (cannot be animated!) | `hash` | `get+set`{.mark} |
 | *cursor*   | The current position (between 0-1) of the animation playback cursor. | `number` | `get+set`{.mark} |
 | *playback_rate* | The playback rate of the animation. A multiplier to the animation playback rate. | `number` | `get+set`{.mark} |
 
@@ -92,9 +93,20 @@ Legacy functions for reading and writing game object properties also exist. They
 | property   | description                            | type            |                  |
 | ---------- | -------------------------------------- | --------------- | ---------------- |
 | *animation* | The current animation.                | `hash`          | `get`{.mark}     |
-| *cursor*.  | Position (between 0--1) of playback cursor. | `number`   | `get+set`{.mark} |
+| *texture0* | The texture path hash of the model. | `hash` | `get`{.mark}|
+| *cursor*  | Position (between 0--1) of playback cursor. | `number`   | `get+set`{.mark} |
 | *playback_rate* | The playback rate of the animation. A multiplier to the animation playback rate. | `number` | `get+set`{.mark} |
 
+*LABEL COMPONENT PROPERTIES*
+
+| property   | description                            | type            |                  |
+| ---------- | -------------------------------------- | --------------- | ---------------- |
+| *scale* | The scale of the label. | `vector3` | `get+set`{.mark} |
+| *color*     | The color of the label. | `vector4` | `get+set`{.mark} |
+| *outline* | The outline color of the label. | `vector4` | `get+set`{.mark} |
+| *shadow* | The shadow color of the label. | `vector4` | `get+set`{.mark} |
+| *size* | The size of the label. The size will constrain the text if line break is enabled. | `vector3` | `get+set`{.mark} |
+
 ## GUI node properties
 
 GUI nodes also contain properties, but they are read and written through special getter and setter functions. For each property there exists one get- and one set- function. There is also a set of constants defined to use as reference to the properties when animating them. If you need to refer to separate property components you have to use the string name of the property, or a hash of the string name.
@@ -128,8 +140,8 @@ Note that all color values are encoded in a vector4 where the components corresp
 
 | property   | description                            | type            |                  |
 | ---------- | -------------------------------------- | --------------- | ---------------- |
-| *color*.   | The face color of the node.            | `vector4`.      | `gui.get_color()` `gui.set_color()` |
-| *outline*. | The outline color of the node.         | `vector4`       | `gui.get_outline()` `gui.set_outline()` |
+| *color*   | The face color of the node.            | `vector4`      | `gui.get_color()` `gui.set_color()` |
+| *outline* | The outline color of the node.         | `vector4`       | `gui.get_outline()` `gui.set_outline()` |
 | *position* | The position of the node. | `vector3` | `gui.get_position()` `gui.set_position()` |
 | *rotation* | The rotation of the node expressed as Euler angles--degrees rotated around each axis. | `vector3` | `gui.get_rotation()` `gui.set_rotation()` |
 | *scale* | The scale of the node expressed as a multiplier along each axis. | `vector3` |`gui.get_scale()` `gui.set_scale()` |
@@ -137,6 +149,4 @@ Note that all color values are encoded in a vector4 where the components corresp
 | *size* | The unscaled size of the node. | `vector3` | `gui.get_size()` `gui.set_size()` |
 | *fill_angle* | The fill angle of a pie node expressed as degrees counter-clockwise. | `number` | `gui.get_fill_angle()` `gui.set_fill_angle()` |
 | *inner_radius* | The inner radius of a pie node. | `number` | `gui.get_inner_radius()` `gui.set_inner_radius()` |
-| *slice9* | The edge distances of a slice9 node. | `vector4` | |
-
-
+| *slice9* | The edge distances of a slice9 node. | `vector4` | `gui.get_slice9()` `gui.set_slice9()` |

+ 87 - 15
docs/en/manuals/render.md

@@ -25,9 +25,81 @@ To set up a custom renderer:
 
 3. Change the *Render* property (under *bootstrap*) in the "game.project" settings file to refer to your copy of the "default.render" file.
 
+### Default view projection
+
+The default render script provides a number of different projections for drawing your game content, with the default being a stretch projection. The other projections provided in the default render script are fixed fit and fixed projections.
+
+#### Stretch projection
+
+The stretch projection will always draw an area of your game that is equal to the dimensions set in "game.project", even when the window is resized. If the aspect ratio changes it will result in game content being stretched either vertically or horizontally:
+
+![Stretch projection](images/render/stretch_projection.png)
+
+*Stretch projection with original window size*
+
+![Stretch projection when resized](images/render/stretch_projection_resized.png)
+
+*Stretch projection with the window stretched horizontally*
+
+The stretch projection is the default projection but if you have changed from it and need to switch back you do it by sending a message to the render script:
+
+```lua
+function init(self)
+    msg.post("@render:", "use_stretch_projection", { near = 1, far = -1, zoom = 2 })
+end
+```
+
+#### Fixed fit projection
+
+Just like the stretch projection the fixed fit projection will always show an area of the game that is equal to the dimensions set in "game.project", but if the window is resized and the aspect ratio changes the game content will retain the original aspect ratio and additional game content will be show vertically or horizontally:
+
+![Fixed fit projection](images/render/fixed_fit_projection.png)
+
+*Fixed with projection with original window size*
+
+![Fixed fit projection when resized](images/render/fixed_fit_projection_resized.png)
+
+*Fixed with projection with the window stretched horizontally*
+
+![Fixed fit projection when smaller](images/render/fixed_fit_projection_resized_smaller.png)
+
+*Fixed with projection with the window reduced to 50% of original size*
+
+You enable the fixed fit projection by sending a message to the render script:
+
+```lua
+function init(self)
+    msg.post("@render:", "use_fixed_fit_projection", { near = 1, far = -1 })
+end
+```
+
+#### Fixed projection
+
+The fixed projection will retain the original aspect ratio and render your game content with a fixed zoom level. This means that it if the zoom level is set to something other than 100% it will show more or less than the area of the game defined by the dimensions in "game.project":
+
+![Fixed projection](images/render/fixed_projection_zoom_2_0.png)
+
+*Fixed projection with zoom set to 2*
+
+![Fixed projection](images/render/fixed_projection_zoom_0_5.png)
+
+*Fixed projection with zoom set to 0.5*
+
+![Fixed projection](images/render/fixed_projection_zoom_2_0_resized.png)
+
+*Fixed projection with zoom set to 2 and window reduced to 50% of original size*
+
+You enable the fixed projection by sending a message to the render script:
+
+```lua
+function init(self)
+    msg.post("@render:", "use_fixed_projection", { near = 1, far = -1, zoom = 2 })
+end
+```
+
 ## Render predicates
 
-To be able to control the draw order of objects, you create render _predicates_. A predicate declares what should be drawn based on a selection of material _tags_. 
+To be able to control the draw order of objects, you create render _predicates_. A predicate declares what should be drawn based on a selection of material _tags_.
 
 Each object that is drawn onto the screen has a material attached to it that controls how the object should be drawn to the screen. In the material, you specify one or more _tags_ that should be associated with the material.
 
@@ -53,13 +125,13 @@ init()
       self.text_pred = render.predicate({"text"})
       self.particle_pred = render.predicate({"particle"})
       self.model_pred = render.predicate({"model"})
-  
+
       self.clear_color = vmath.vector4(0, 0, 0, 0)
       self.clear_color.x = sys.get_config("render.clear_color_red", 0)
       self.clear_color.y = sys.get_config("render.clear_color_green", 0)
       self.clear_color.z = sys.get_config("render.clear_color_blue", 0)
       self.clear_color.w = sys.get_config("render.clear_color_alpha", 0)
-  
+
       -- Define a view matrix to use. If we have a camera object, it will
       -- send "set_view_projection" messages to the render script and we
       -- can update the view matrix with the value the camera provides.
@@ -76,19 +148,19 @@ update()
   function update(self)
       -- Set the depth mask which allows us to modify the depth buffer.
       render.set_depth_mask(true)
-  
+
       -- Clear the color buffer with the clear color value and set the depth buffer to 1.0.
       -- The normal depth values are between 0.0 (near) and 1.0 (far) so maximizing the values
       -- throughout the buffer means that every pixel you draw will be nearer than 1.0 and thus
       -- it will be properly drawn and depth testing will work from thereon.
       render.clear({[render.BUFFER_COLOR_BIT] = self.clear_color, [render.BUFFER_DEPTH_BIT] = 1, [  render.BUFFER_STENCIL_BIT] = 0})  
-  
+
       -- Set the viewport to the window dimensions.
       render.set_viewport(0, 0, render.get_window_width(), render.get_window_height())
-  
+
       -- Set the view to the stored view value (can be set by a camera object)
       render.set_view(self.view)
-  
+
       -- Render 2D space
       render.set_depth_mask(false)
       render.disable_state(render.STATE_DEPTH_TEST)
@@ -96,13 +168,13 @@ update()
       render.enable_state(render.STATE_BLEND)
       render.set_blend_func(render.BLEND_SRC_ALPHA, render.BLEND_ONE_MINUS_SRC_ALPHA)
       render.disable_state(render.STATE_CULL_FACE)
-  
+
       -- Set the projection to orthographic and only render between -200 and 200 Z-depth
       render.set_projection(vmath.matrix4_orthographic(0, render.get_width(), 0,   render.get_height(), -200, 200))  
-  
+
       render.draw(self.tile_pred)
       render.draw(self.particle_pred)
-  
+
       -- Render 3D space, but still orthographic
       -- Face culling and depth test should be enabled
       render.enable_state(render.STATE_CULL_FACE)
@@ -110,16 +182,16 @@ update()
       render.set_depth_mask(true)
       render.draw(self.model_pred)
       render.draw_debug3d()
-  
+
       -- Render the GUI last
       render.set_view(vmath.matrix4())
       render.set_projection(vmath.matrix4_orthographic(0, render.get_window_width(), 0,   render.get_window_height(), -1, 1))  
-  
+
       render.enable_state(render.STATE_STENCIL_TEST)
       render.draw(self.gui_pred)
       render.draw(self.text_pred)
       render.disable_state(render.STATE_STENCIL_TEST)
-  
+
       render.set_depth_mask(false)
       render.draw_debug2d()
   end
@@ -172,7 +244,7 @@ on_message()
 
 `"draw_line"`
 : Draw debug line. Use to visualize ray_casts, vectors and more. Lines are drawn with the `render.draw_debug3d()` call.
-  
+
   ```lua
   -- draw a white line
   local p1 = vmath.vector3(0, 0, 0)
@@ -183,7 +255,7 @@ on_message()
 
 `"draw_text"`
 : Draw debug text. Use to print debug information. The text is drawn with the built in "system_font" font. The system font has a material with tag "text" and is rendered with other text in the default render script.
-  
+
   ```lua
   -- draw a text message
   local pos = vmath.vector3(500, 500, 0)

+ 24 - 0
docs/en/manuals/writing-code.md

@@ -0,0 +1,24 @@
+---
+title: Writing code
+brief: This manual briefly covers how to work with code in Defold.
+---
+
+# Writing code
+
+While Defold allows you to create a lot of your game content using visual tools such as the tilemap and particle effect editors you still create your game logic using a code editor. Game logic is written using the [Lua programming language](https://www.lua.org/) while extensions to the engine itself are written using the native language(s) for the target platform.
+
+Defold has a built in text editor that allows you to open and edit Lua files (.lua), Defold script files (.script, .gui_script and .render_script) as well as any other file with a file extension not natively handled by the editor. Additionally the editor provides syntax highlighting for Lua and script files.
+
+## Writing Lua code
+
+Defold uses Lua 5.1 and LuaJIT (depending on target platform) and you need to follow the language specification for those specific versions of Lua when writing your game logic. For more details on how to work with Lua in Defold see our [Lua in Defold manual](/manuals/lua).
+
+## Writing native code
+
+Defold allows you to extend the game engine with native code to access platform specific functionality not provided by the engine itself. You can also use native code when the performance of Lua isn't enough (resource intensive calculations, image processing etc). Refer to our [manuals on Native Extensions](/manuals/extensions/) to learn more.
+
+## Using an external code editor
+
+The code editor in Defold provides the basic functionality you need to write code, but for more advanced use cases or for power users with a favorite code editor it is possible to let Defold open files using an external editor. In the Preferences window under the Code tab it is possible to define an external editor that should be used when editing code.
+
+The Defold community has created auto-complete plugins for popular editors such as [Atom](https://atom.io/packages/defold-ide), [Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=selimanac.defold-vsc-snippets) and [Sublime](https://forum.defold.com/t/full-autocomplete-defold-api-for-sublime-text-3/10910). In addition to these there is also API reference packages for [Dash and Zeal](https://forum.defold.com/t/defold-docset-for-dash/2417).

+ 1 - 1
docs/en/shared/platforms.md

@@ -1,3 +1,3 @@
 Supported platforms are `ios`, `android`, `osx`, `win32`, `linux`, `web`.
 
-Supported `arc-platform` pairs are `armv7-ios`, `arm64-ios`, `armv7-android`, `x86-osx`, `x86_64-osx`, `x86-win32`, `x86_64-win32`, `x86-linux`, `x86_64-linux`, `js-web` and `wasm-web`.
+Supported `arc-platform` pairs are `armv7-ios`, `arm64-ios`, `armv7-android`, `x86-osx`, `x86_64-osx`, `x86-win32`, `x86_64-win32`, `x86_64-linux`, `js-web` and `wasm-web`.

+ 4 - 1
docs/en/tutorials/car.md

@@ -90,10 +90,13 @@ Select the "car" game object, right-click and select <kbd>Add Component</kbd>, t
 Image
 : This requires an image source for the sprite. Create an atlas image file by marking "main" in the *Project Explorer* view, right-clicking and selecting <kbd>New ▸ Atlas File</kbd>. Name the new atlas file *sprites.atlas* and double click it to open it in the atlas editor. Save the following two image files to your computer and drag them into *main* in the *Project Explorer* view. Now you can mark the Atlas root node in the atlas editor, right click and select <kbd>Add Images</kbd>. Add the car and the tire image to the atlas and save. Now you can select *sprites.atlas* as the image source for the sprite component in the "car" game object in the "car" collection.
 
-![Car image](images/car/start_car.png)
+Images for our game:
 
+![Car image](images/car/start_car.png)
 ![Tire image](images/car/start_tire.png)
 
+Add these images to the atlas:
+
 ![Sprites atlas](images/car/start_sprites_atlas.png)
 
 ![Sprite properties](images/car/start_sprite_properties.png)

+ 1 - 1
docs/en/tutorials/magic-link.md

@@ -86,7 +86,7 @@ The difficulty level govern the number of magic blocks that are put on the board
 
 ## Overview
 
-As with all projects, we need to device a plan how to approach the implementation in broad strokes.There are many ways the game could be structured and built. We could, technically, implement the whole game in the GUI system if we wanted. However, building the game with game objects and sprites and using the GUI APIs for on-screen GUI and heads-up display elements is most often the natural way to build a game so we're gonna take that path.
+As with all projects, we need to devise a plan how to approach the implementation in broad strokes.There are many ways the game could be structured and built. We could, technically, implement the whole game in the GUI system if we wanted. However, building the game with game objects and sprites and using the GUI APIs for on-screen GUI and heads-up display elements is most often the natural way to build a game so we're gonna take that path.
 
 Since we're expecting the number of files to stay fairly low, we're gonna keep the project folder structure very simple:
 

+ 13 - 4
docs/ko/ko.json

@@ -295,6 +295,10 @@
                     {
                         "path": "/manuals/html5",
                         "name": "HTML5"
+                    },
+                    {
+                        "path": "/manuals/facebook",
+                        "name": "Facebook"
                     }
                 ]
             },
@@ -305,10 +309,6 @@
                         "path": "/manuals/extensions",
                         "name": "Native extensions"
                     },
-                    {
-                        "path": "/manuals/facebook",
-                        "name": "Facebook"
-                    },
                     {
                         "path": "/manuals/iap",
                         "name": "In-app purchases"
@@ -318,6 +318,15 @@
                         "name": "Push notifications"
                     }
                 ]
+            },
+            {
+                "name": "NATIVE EXTENSIONS",
+                "items": [
+                    {
+                        "path": "/manuals/extensions",
+                        "name": "Introduction"
+                    }
+                ]
             }
         ]
     }

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff