diff --git a/.wordlist.txt b/.wordlist.txt index 818b39bd..912ae9f9 100644 --- a/.wordlist.txt +++ b/.wordlist.txt @@ -105,6 +105,7 @@ cutscenes ds dt dae +DAP deadzone debuggable decrypt @@ -131,6 +132,7 @@ DotNet drawables dropdown dSYM +DX EDN EFIGS EGL @@ -194,10 +196,12 @@ GPUs Gradle Grafana GUI +GUID GUIs haxe HarfBuzz HD +HDR hercule hidpi Hiero @@ -254,6 +258,7 @@ khronos KiB Klayton Kowalski +KTX LargeXxxhdpi leaderboard leaderboards @@ -296,6 +301,7 @@ mille minification minifying minimap +mip mipmap mipmapping mipmaps @@ -318,6 +324,7 @@ NDA NDK NES normals +Noto NPC NUL NVDA @@ -349,6 +356,7 @@ playtesting plist PNG Poki +POSIX PowerManager pprint pragma @@ -362,6 +370,7 @@ preconnect prehash preinitialization preload +premultiplication premultiplied premultiply prepending @@ -370,6 +379,7 @@ preprocessor prerendered preselect prewarm +prewarms Pro procedurally profi @@ -396,7 +406,9 @@ raycast reactively readme rebundle +recompressing reconfiguring +redeclare reimported reindent Remotery @@ -405,6 +417,7 @@ Rendy repo retune Revolute +RG rgb rgba Ritzl @@ -420,6 +433,7 @@ SD SDK SDKs SDL +SDL's SDF Sergey sha @@ -474,6 +488,7 @@ TestFlight texcoord texel texels +texturec thrusted Tilegrid tilemap @@ -519,12 +534,15 @@ uncompress undoable unloader unlockable +unmapped +UNORM Unreferenced unscaled unstripped untrusted upscaled upscaling +upvalues URI userdata UTF diff --git a/docs/en/en.json b/docs/en/en.json index 01947ddd..70b06e58 100644 --- a/docs/en/en.json +++ b/docs/en/en.json @@ -1783,6 +1783,10 @@ { "path": "/manuals/debugging-game-and-system-logs", "name": "Reading game and system logs" + }, + { + "path": "/manuals/recording", + "name": "Video recording" } ] }, diff --git a/docs/en/manuals/adapting-graphics-to-screen-size.md b/docs/en/manuals/adapting-graphics-to-screen-size.md index 29a6467f..0a6f5600 100644 --- a/docs/en/manuals/adapting-graphics-to-screen-size.md +++ b/docs/en/manuals/adapting-graphics-to-screen-size.md @@ -97,7 +97,9 @@ If you also wish to support high resolution retina screens you can enable this i ![](images/screen_size/highdpi-enabled.png) -This will create a high dpi back buffer on displays that support it. The game will render in double the resolution than what is set in the Width and Height settings, which will still be the logical resolution used in scripts and properties. This means that all measurements stay the same and any content that is rendered at 1x scale will look the same. But if you import high res images and scale them to 0.5x they will be high dpi on screen. +High DPI lets the game use the display's pixel density for its rendering resolution. The *Width* and *Height* settings still define the project's logical resolution, while the rendering scale depends on the platform and display. For example, at a scale of 2, images imported at twice their intended size and drawn at 0.5x can retain their detail on a dense display. + +On HTML5, the scale starts with the browser's device pixel ratio. `html5.min_pixel_ratio` and `html5.max_pixel_ratio` can bound this scale when `display.high_dpi` is enabled. Each limit defaults to `0` (disabled), and fractional ratios, including values below `1`, are supported. These limits change the canvas rendering resolution while preserving its CSS display size. With High DPI disabled, the ratio stays at `1`. See [Pixel ratio limits](/manuals/html5/#pixel-ratio-limits) for an example that caps rendering on dense displays. ## Creating an adaptive GUI diff --git a/docs/en/manuals/android.md b/docs/en/manuals/android.md index 9da4691e..77b5b87f 100644 --- a/docs/en/manuals/android.md +++ b/docs/en/manuals/android.md @@ -85,6 +85,10 @@ For this feature to work, you will need *ADB* installed and *USB debugging* enab An *.aab* file can be uploaded to Google Play via the [Google Play developer console](https://play.google.com/apps/publish/). It is also possible to generate an *`.apk`* file from an *.aab* file to install it locally using the [Android bundletool](https://developer.android.com/studio/command-line/bundletool). +## Display cutouts + +`window.get_reserved_areas()` reports display cutout rectangles on Android 9 (API level 28) and later. Use `window.get_safe_area()` when you need a safe layout rectangle. See [Reserved screen areas](/manuals/porting-guidelines/#reserved-screen-areas) for coordinate units, behavior on unsupported platforms, and how to refresh your layout when the reported areas change. + ## Shrinking Java code and Android resources with R8 {#shrinking-java-code-with-r8} R8 reduces the size of Java code through shrinking, optimization and obfuscation. With Defold 1.14.0 or later and a compatible Extender build server, it also removes unused Android resources, such as layouts, drawables and raw resources supplied by extensions and their Android dependencies. Defold game assets in the game archive are not processed by R8. @@ -102,7 +106,7 @@ Make sure every extension with Java code provides a `.keep` file for the classes Leaving **R8 Keep Rules** empty uses D8 without shrinking. Enabling R8 uses the native extension build service, even for a project without native extensions. -Starting with Defold 1.14.0, Android resource shrinking is enabled by the same **R8 Keep Rules** setting; there is no separate project setting for it. Older Defold SDKs retain code-only R8 shrinking. +Android resource shrinking is enabled by the same **R8 Keep Rules** setting; there is no separate project setting for it. Older Defold SDKs retain code-only R8 shrinking. ### Adding rules to an extension diff --git a/docs/en/manuals/app-manifest.md b/docs/en/manuals/app-manifest.md index 6dcf575c..bbd97cdc 100644 --- a/docs/en/manuals/app-manifest.md +++ b/docs/en/manuals/app-manifest.md @@ -9,8 +9,6 @@ The application manifest controls which features and backends are linked into th ![](images/app_manifest/create-app-manifest.png) -![](images/app_manifest/app-manifest.png) - # Applying the manifest In `game.project`, assign the manifest to `Native Extensions` -> `App Manifest`. @@ -36,7 +34,7 @@ Control rig and model functionality, or select None to exclude model and rig com ## Exclude Record -Excluded the video recording capability from the engine (see the [`start_record`](https://defold.com/ref/sys/#start_record) message documentation). +Exclude native MP4 recording, the [`recorder` Lua module](/ref/recorder/) and the recording HTTP service from desktop debug builds. Recording is already omitted from release, headless, mobile and web builds. See the [recording manual](/manuals/recording) for the workflow. ## Profiler @@ -118,11 +116,14 @@ Use the deprecated Android Support Library instead of Android X. [More info](htt ## Graphics -Select which graphics backends to include for each platform. A combined choice includes both backends so the preferred backend can fall back when it is unavailable. +Select which graphics backends to include for each platform. A combined choice includes multiple backends so the engine can fall back when its preferred backend is unavailable. Including more backends increases engine size. + +Windows and Linux use separate fields. The **DX12** option selects DirectX 12 on Windows. | Field | Platforms | Choices | Default | |---|---|---|---| -| **Graphics** | Windows and Linux | OpenGL, Vulkan, OpenGL & Vulkan | OpenGL | +| **Graphics (Linux)** | Linux | OpenGL, Vulkan, OpenGL & Vulkan | OpenGL | +| **Graphics (Windows)** | Windows | OpenGL, Vulkan, DX12, OpenGL & Vulkan, OpenGL & DX12, Vulkan & DX12, OpenGL & Vulkan & DX12 | OpenGL | | **Graphics (macOS)** | macOS | OpenGL, Metal, Vulkan, OpenGL & Metal, OpenGL & Vulkan | Metal | | **Graphics (iOS)** | iOS | OpenGL, Metal, Vulkan, OpenGL & Metal, OpenGL & Vulkan | OpenGL | | **Graphics (Android)** | Android | OpenGL+Vulkan, OpenGL, Vulkan | OpenGL+Vulkan | @@ -130,11 +131,11 @@ Select which graphics backends to include for each platform. A combined choice i On Linux ARM64, the **OpenGL** choice uses the OpenGL ES backend. The Android combined default prefers Vulkan when available and falls back to OpenGL ES. -Since Defold 1.14.0, macOS uses the native Metal backend by default. The **Vulkan** choice on macOS and iOS uses Vulkan through MoltenVK. The iOS simulator (`arm64_sim-ios`) always uses Metal, regardless of the **Graphics (iOS)** choice for devices. +macOS uses the native Metal backend by default. The **Vulkan** choice on macOS and iOS uses Vulkan through MoltenVK. The iOS simulator (`arm64_sim-ios`) always uses Metal, regardless of the **Graphics (iOS)** choice for devices. ## Use full text layout system -If enabled (`true`), this includes the full text layout system for shaping text, including right-to-left languages. Enable this option together with `font.runtime_generation` in *game.project* to use runtime generation for SDF fonts from TrueType (`.ttf`) or OpenType (`.otf`) resources. Runtime generation from `.otf` resources is supported since Defold 1.13.2. Read more in the [Font Manual](/manuals/font/#enabling-runtime-fonts). +If enabled (`true`), this includes the full text layout system for shaping text, including right-to-left languages. Enable this option to use runtime generation for TrueType (`.ttf`) or OpenType (`.otf`) fonts, and set *Glyph Generation* to **Dynamic** in each font resource that needs it. Dynamic generation supports both **SDF** and **Vector** modes. Read more in the [Font Manual](/manuals/font/#enabling-runtime-fonts). ## Use Rich Text diff --git a/docs/en/manuals/application-lifecycle.md b/docs/en/manuals/application-lifecycle.md index 33e36919..24119d6e 100644 --- a/docs/en/manuals/application-lifecycle.md +++ b/docs/en/manuals/application-lifecycle.md @@ -120,7 +120,7 @@ The high-level order of *script* component Lua callback stages is: Each game object component in the main collection is traversed. If any of these components has a script with a `fixed_update()`/`update()`/`late_update()` function, then that will be called. If the component is a collection proxy, each component in the proxy collection is recursively updated with all the steps in the `Update` phase. ::: sidenote -The order in which game object component `update()` functions are called is unspecified. You should not assume that the engine updates objects belonging to the same collection in a certain order. The same is true for `fixed_update()` and `late_update()` (since 1.12.0). +The order in which game object component `update()` functions are called is unspecified. You should not assume that the engine updates objects belonging to the same collection in a certain order. The same is true for `fixed_update()` and `late_update()`. ::: #### Physics @@ -204,7 +204,7 @@ The number of frame updates per second (which equals the number of update-loop r #### Engine throttling -Defold 1.12.0 introduced an engine throttling API that can skip engine updates and rendering entirely, while still detecting input. Any input wakes up the engine again, and the engine can re-enter throttling after a cooldown. +Defold provides an engine throttling API that can skip engine updates and rendering entirely, while still detecting input. Any input wakes up the engine again, and the engine can re-enter throttling after a cooldown. See `sys.set_engine_throttle()` API for details and usage examples. diff --git a/docs/en/manuals/bob.md b/docs/en/manuals/bob.md index 65e0dc87..7d0ff4ea 100644 --- a/docs/en/manuals/bob.md +++ b/docs/en/manuals/bob.md @@ -240,7 +240,7 @@ $ ## Build server -Since Defold 1.14.0, Bob selects the default native extension build server from the release channel of its distribution: +Bob selects the default native extension build server from the release channel of its distribution: | Bob release channel | Default build server | |---|---| diff --git a/docs/en/manuals/bundling.md b/docs/en/manuals/bundling.md index 71d0c434..00efcd5e 100644 --- a/docs/en/manuals/bundling.md +++ b/docs/en/manuals/bundling.md @@ -82,7 +82,7 @@ These assets can be accessed via the [`sys.load_resource()`](https://defold.com/ When creating an application bundle you have an option of creating a debug or release bundle. The differences between the two bundles are small but important to keep in mind: * Release builds do not include the [profiler](/manuals/profiling) by default. Set **Profiler** to **Always** in the [App Manifest](/manuals/app-manifest/#profiler) to include profiler support in both debug and release builds. -* Release builds do not include the [screen recorder](/ref/sys/#start_record) +* Release builds do not include [video recording](/manuals/recording) or the [`recorder` Lua module](/ref/recorder/). Recording is available in desktop debug builds unless **Exclude Record** is enabled in the [App Manifest](/manuals/app-manifest/#exclude-record). * Release builds do not show the output of any calls to `print()` or the output from any native extensions * Release builds have the `is_debug` value in `sys.get_engine_info()` set to`false` * Release builds will not do reverse lookups of `hash` values when calling `tostring()`. What this means in practice is that a `tostring()` for a value of type `url` or `hash` will return its numeric representation and not the original string (`'hash: [/camera_001]'` vs `'hash: [11844936738040519888 (unknown)]'`) diff --git a/docs/en/manuals/debugging-game-logic.md b/docs/en/manuals/debugging-game-logic.md index 29dee8f7..62f43fcb 100644 --- a/docs/en/manuals/debugging-game-logic.md +++ b/docs/en/manuals/debugging-game-logic.md @@ -38,7 +38,11 @@ Note that you probably want to update this data every frame so posting the messa ## Running the debugger -To run the debugger, select Debug ▸ Start/Attach which either starts up the game with the debugger attached or attaches the debugger to an already running game. +The Lua debugger is available in native debug and headless builds. Use an engine from the same Defold version as the editor. Release and Web builds do not support attaching the debugger. + +To run the debugger, select Debug ▸ Start/Attach. This starts the game with the debugger attached, or attaches to an already running game. When starting a game for debugging, the editor installs enabled breakpoints before startup scripts run, so you can set a breakpoint in `init()` before launching. + +To attach to a device, select it under Project ▸ Targets, then choose Debug ▸ Start/Attach. Attachment pauses at the next Lua line. The editor sets up the debugger connection automatically for supported local and remote targets. See [Remote targets](#remote-targets) for connection requirements, or learn how to [connect an external debugger](#native-dap-connections). ![overview](images/debugging/overview.png) @@ -46,7 +50,7 @@ As soon as the debugger is attached, you have control of the execution of the ga Break : ![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: + Pause Lua execution at the next source line. 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) @@ -67,7 +71,7 @@ Step Over ![step](images/debugging/step.png) ::: sidenote -A line of Lua code does not correspond to a single expression. Stepping in the debugger moves ahead one expression at a time, meaning that currently you may have to hit the step button more than once to advance to the next line. +Stepping follows Lua source lines. A step can revisit the same line, for example when a loop repeats, so it does not always advance to the next line in the file. ::: Step Into @@ -100,14 +104,103 @@ Setting conditional breakpoints To edit the breakpoint condition, right-click in the column just right of the line numbers in the code editor, or select Edit ▸ Edit Breakpoint from the menu. Evaluating Lua expressions -: With the debugger attached and the game stopped at a breakpoint, a Lua runtime is available with the current context. Type Lua expressions in the bottom of the console and press Enter to evaluate them: +: With the game paused, select a frame in the *Call Stack*, type a Lua expression or statement in the bottom of the console, and press Enter. Evaluation uses the selected frame's locals, upvalues, and globals. Table results include their nested contents. ![console](images/debugging/console.png) - It is currently not possible to modify variables through the evaluator. + You can also change values through assignments, for example `self.score = 100` in a frame where `self` is available. Evaluated code has the same effects on game state as code executed by your game. + +Inspecting variables +: Select a frame in the *Call Stack* to inspect its locals and upvalues in the *Variables* view. Expand `_G` to inspect globals, and expand tables or `self` to inspect their fields. The editor preserves expanded paths, selection, and scroll position when stepping, switching frames, or refreshing after evaluation, while fetching current values. Detaching the debugger -: Select Debug ▸ Detach Debugger to detach the debugger from the game. It will continue running immediately. +: Select Debug ▸ Detach Debugger to detach the debugger from the game. It will continue running immediately. Use Debug ▸ Start/Attach to attach again without restarting the game. + +## Native DAP connections + +The engine provides a native Debug Adapter Protocol (DAP) server over TCP. For an external DAP client, start the listener in a native Defold debug or headless engine, then connect the client to the engine's address and port. The editor handles listener setup automatically when you use Debug ▸ Start/Attach. + +The current editor cannot connect to older engines that only support MobDebug. No `require "builtins.scripts.mobdebug"` call is needed or available in current versions. + +### Starting the listener + +Build your project first. From the project directory containing `build/default/game.projectc`, run the native debug engine with these [startup configuration overrides](/manuals/project-settings/#setting-config-values-on-engine-startup): + +```sh +dmengine --config=debugger.enabled=1 \ + --config=debugger.port=8172 --config=debugger.wait=1 +``` + +Connect your DAP client to `127.0.0.1:8172`. The engine waits for the client to configure breakpoints before running startup scripts. + +| Setting | Default | Purpose | +| --- | --- | --- | +| `debugger.enabled` | `0` | Set to `1` to start the listener during engine startup. | +| `debugger.address` | `127.0.0.1` | IPv4 address on which to listen. The default accepts connections from the same computer. | +| `debugger.port` | `8172` | TCP listening port. Use `0` to select an available port. | +| `debugger.wait` | `0` | Set to `1` to wait for the debugger client's configuration before running startup scripts. | + +You can also add these values to the [Debugger section of game.project](/manuals/project-settings/#debugger). The editor configures the listener automatically for Debug ▸ Start/Attach, so manual configuration is only needed when starting the listener yourself. + +The engine log reports the selected address and port. With `debugger.wait=0`, the game starts immediately and you can attach later. With `debugger.wait=1`, it waits until the client has finished configuring the session, including breakpoints. For local debug launches, the editor selects an available port automatically. + +Disconnecting a client resumes execution and leaves the listener available for another attachment. A disconnect while waiting for startup configuration also releases the engine. If the listener cannot start, the engine logs the error and continues startup; you can retry from Lua with `debugger.start(0)` to select an available port. + +### Enabling the listener while running + +To enable the listener from a script without restarting the game: + +```lua +if debugger then + local port = debugger.start(0) + print("DAP listener port:", port) +end +``` + +`debugger.start([port [, address]])` returns the listening port immediately. It does not wait for a client or pause the game. Omitted arguments use `debugger.port` and `debugger.address`; passing `0` selects an available port. Repeated calls return the existing listener's port and do not change its address or port. The `debugger` module is provided by native debug and headless engines. + +The port must be an integer from `0` to `65535`. Pass `nil` as the first argument to override only the address. Invalid arguments or a failure to bind the listener raise a Lua error. + +### Remote targets + +For a direct connection from another computer, bind the listener to the device's IPv4 interface or to `0.0.0.0` (all IPv4 interfaces). For example, use `debugger.start(8172, "0.0.0.0")`, or add `--config=debugger.address=0.0.0.0` to the startup command above. Connect the client to the device's actual IP address and allow TCP access to the listening port. `0.0.0.0` is a bind address, not the address to enter in the client. + +The Defold editor requests this remote bind automatically and uses port `8172 + project.instance_index` for remote targets. It cannot discover a dynamically selected remote port. If you already started the remote listener on localhost or a different port, restart the engine before attaching from the editor. + +The debugger can evaluate Lua and has no authentication. Enable remote access only on a trusted development network. + +### External clients + +Use a client that supports attaching directly to a DAP server over TCP. Configure its source mapping to the folder containing `game.project` (the DAP `localRoot` attach argument). Start the engine listener first, then attach the client. + +#### VS Code + +Install the [Lua Debug extension](https://marketplace.visualstudio.com/items?itemName=actboy168.lua-debug) (`actboy168.lua-debug`), open the folder containing `game.project` in VS Code, and add this configuration to `.vscode/launch.json`: + +```json +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Attach to Defold Lua", + "type": "lua", + "request": "attach", + "address": "127.0.0.1:8172", + "debugServer": 8172, + "localRoot": "${workspaceFolder}", + "stopOnEntry": false + } + ] +} +``` + +If VS Code opens a `.script`, `.gui_script` or `.render_script` file as plain text, select **Lua** from the language indicator in the status bar before setting breakpoints. + +Set a breakpoint, for example in a script's `init()` function. Start the engine using the [startup command above](#starting-the-listener), then select **Attach to Defold Lua** in VS Code's **Run and Debug** view. With `debugger.wait=1`, the engine runs startup scripts after the client has installed the breakpoints. Set `stopOnEntry` to `true` if you also want to pause at the next Lua line after attachment. + +VS Code's [`debugServer` setting](https://code.visualstudio.com/api/extension-guides/debugger-extension#development-setup-for-mock-debug) connects directly to the engine's local TCP listener. The `address` field is required by the Lua Debug extension's attach configuration. If you change the listener port, update both fields. `localRoot` must point to the project folder so the client can map the engine's Lua source names to your files. + +For a remote engine, forward its DAP port to localhost and put the forwarded port in both fields, or use a DAP client that connects directly to the remote host. ## Breakpoints Tab diff --git a/docs/en/manuals/debugging.md b/docs/en/manuals/debugging.md index f23295a2..5f5ed3f6 100644 --- a/docs/en/manuals/debugging.md +++ b/docs/en/manuals/debugging.md @@ -7,5 +7,9 @@ brief: This manual explains the debugging facilities present in Defold. Defold contains an integrated Lua debugger with an inspection facility. Together with the built-in [profiling tools](/manuals/profiling) it is a powerful tool that can help finding the cause of bugs in your game logic or help analyze performance issues. Defold also provides crash logs for the rare occasions when the engine itself crashes. +The Lua debugger is available in native debug and headless builds. Release and Web builds do not support attaching the debugger. + * Learn more about [debugging your game logic](/manuals/debugging-game-logic). +* Learn how to [connect an external debugger](/manuals/debugging-game-logic/#native-dap-connections), including a [VS Code setup example](/manuals/debugging-game-logic/#vs-code). * Learn more about [debugging native code](/manuals/debugging-native-code). +* Learn how to [record the game window to an MP4 file](/manuals/recording) from Lua or development tools. diff --git a/docs/en/manuals/editor-scripts.md b/docs/en/manuals/editor-scripts.md index 0fdd5f9c..e242d424 100644 --- a/docs/en/manuals/editor-scripts.md +++ b/docs/en/manuals/editor-scripts.md @@ -50,7 +50,7 @@ You can interact with the editor using `editor` package that defines this API: - `editor.editor_sha1` — a string, SHA1 of Defold editor - `editor.get(node_id, property)` — get a value of some node inside the editor. Nodes in the editor are various entities, such as script or collection files, game objects inside collections, json files loaded as resources, etc. `node_id` is a userdata that is passed to the editor script by the editor. Alternatively, you can pass resource path instead of node id, for example `"/main/game.script"`. `property` is a string. Currently these properties are supported: - `"path"` — file path from the project folder for *resources* — entities that exist as files or directories. Example of returned value: `"/main/game.script"` - - `"children"` — list of children resource paths for directory resources + - `"children"` — list of children resource paths for directory resources. To traverse resources inside files as well, see [Traversing project resources](#traversing-project-resources). - `"parent"` — parent editor node for an Outline node that has a parent - `"text"` — text content of a resource editable as text (such as script files or json). Example of returned value: `"function init(self)\nend"`. Please note that this is not the same as reading file with `io.open()`, because you can edit a file without saving it, and these edits are available only when accessing `"text"` property. - for atlases: `images` (list of editor nodes for images in the atlas) and `animations` (list of animation nodes) @@ -72,6 +72,7 @@ You can interact with the editor using `editor` package that defines this API: - `editor.properties(node_id)` — return a sorted, context-sensitive list of property names that can be read from a node, for example `pprint(editor.properties("/game.project"))`. Use the `editor.can_*` functions to check whether a listed property can also be changed, reset, added to, or reordered. - `editor.can_get(node_id, property)` — check if you can get this property so `editor.get()` won't throw an error. - `editor.can_set(node_id, property)` — check if `editor.tx.set()` transaction step with this property won't throw an error. +- `editor.resource_children(path)` — list the resource paths directly inside a folder or file, including resources contained in glTF/GLB files. See [Traversing project resources](#traversing-project-resources). - `editor.create_directory(resource_path)` — create a directory if it does not exist, and all non-existent parent directories. - `editor.create_resources(resources)` — create 1 or more resources, either from templates or with custom content - `editor.delete_directory(resource_path)` — delete a directory if it exists, and all existent child directories and files. @@ -148,6 +149,42 @@ Editor expects `get_commands()` to return an array of tables, each describing a - `active` - a callback that is executed to check that command is active, expected to return boolean. If `locations` include `"Assets"`, `"Scene"` or `"Outline"`, `active` will be called when showing context menu. If locations include `"Edit"` or `"View"`, active will be called on every user interaction, such as typing on keyboard or clicking with mouse, so be sure that `active` is relatively fast. - `run` - a callback that is executed when user selects the menu item. +### Traversing project resources + +`editor.resource_children(path)` returns an array of resource paths directly inside a folder or file. Both the input path and the returned paths start with `/`, relative to the project root. Use `/` to start at the project root. A *.gltf* or *.glb* file can expose meshes, materials and embedded images as resource children, just as it does in the *Assets* pane. + +If your script walks directories with `editor.get(path, "children")`, switch its traversal to `editor.resource_children(path)` and visit every returned path. Files can also contain resources, so restricting recursion to paths whose `editor.resource_attributes(path).is_directory` is `true` will skip those contents. + +The function returns an empty table (`{}`) for a folder or file with no resource children. A nonexistent path raises an error; if a path might be missing, check `editor.resource_attributes(path).exists` before querying its children. Resource children follow the *Assets* hierarchy. Game objects inside a collection are accessed through `editor.get(collection_path, "children")`. + +For example, save this as `list_resources.editor_script` and select **Project → Reload Editor Scripts**. Right-click a folder or a *.gltf* or *.glb* file in *Assets*, then select **List Resource Contents** to print its resource tree to the console: + +```lua +local M = {} + +local function walk(path) + print(path) + for _, child in ipairs(editor.resource_children(path)) do + walk(child) + end +end + +function M.get_commands() + return { + { + label = "List Resource Contents", + locations = {"Assets"}, + query = {selection = {type = "resource", cardinality = "one"}}, + run = function(opts) + walk(editor.get(opts.selection, "path")) + end + } + } +end + +return M +``` + ### Use commands to change the in-memory editor state Inside the `run` handler, you can query and change the in-memory editor state. Querying is done using `editor.get()` function, where you can ask the editor about the current state of files and selection (if using `query = {selection = ...}`). You can get the `"text"` property of resources editable as text, and also some properties shown in the Properties view — hover over property name to see a tooltip with information about how this property is named in editor scripts. Changing the editor state is done using `editor.transact()`, where you bundle 1 or more modifications in a single undoable step. For example, if you want to be able to reset transform of a game object, you could write a command like that: @@ -243,6 +280,7 @@ editor.transact({ #### Editing tilesources In addition to outline properties, tilesources define the following properties: + - `animations` - a list of animation nodes of the tilesource - `collision_groups` - a list of collision group nodes of the tilesource - `tile_collision_groups` - a table of collision group assignments for tiles in the tilesource @@ -251,8 +289,8 @@ For example, here is how you can setup a tilesource: ```lua local tilesource = "/game/world.tilesource" editor.transact({ - editor.tx.add(tilesource, "animations", {id = "idle", start_tile = 1, end_tile = 1, playback = "playback-loop-forward"}), - editor.tx.add(tilesource, "animations", {id = "walk", start_tile = 2, end_tile = 6, fps = 10}), + editor.tx.add(tilesource, "animations", {id = "idle", frames = {1}, playback = "playback-loop-forward"}), + editor.tx.add(tilesource, "animations", {id = "walk", frames = {2, 3, 4, 5, 6}, fps = 10}), editor.tx.add(tilesource, "collision_groups", {id = "player"}), editor.tx.add(tilesource, "collision_groups", {id = "obstacle"}), editor.tx.set(tilesource, "tile_collision_groups", { @@ -263,6 +301,25 @@ editor.transact({ }) ``` +Animation nodes expose a `frames` property containing a Lua array of one-based tile numbers in animation order. Unlike the *Frames* text field in the editor, editor scripts take an integer array, not a string such as `"2-6"`. Expand ranges into individual tile numbers in the array. Tiles can appear in any order and may be repeated. + +To read and modify the `walk` animation from the example above: + +```lua +local animations = editor.get("/game/world.tilesource", "animations") +for _, animation in ipairs(animations) do + if editor.get(animation, "id") == "walk" then + local frames = editor.get(animation, "frames") + table.insert(frames, 2) + editor.transact({editor.tx.set(animation, "frames", frames)}) + -- The animation now uses {2, 3, 4, 5, 6, 2}. + break + end +end +``` + +Changing the returned array does not update the animation until you pass it to `editor.tx.set()` and apply the transaction. See the [Tile source manual](/manuals/tilesource/#tile-source-flip-book-animations) for tile numbering and playback settings. + #### Editing tilemaps Tilemaps define `layers` property, a node list of tilemap layers. Each layer also defines a `tiles` property that holds an unbounded 2d grid of tiles on this layer. This is different from the engine: tiles have no bounds and may be added anywhere, including negative coordinates. To edit tiles, the editor script API defines a `tilemap.tiles` module with the following functions: diff --git a/docs/en/manuals/editor.md b/docs/en/manuals/editor.md index 7a76fd49..8634ec1a 100644 --- a/docs/en/manuals/editor.md +++ b/docs/en/manuals/editor.md @@ -130,6 +130,22 @@ On the bottom bar of the Editor you can find a narrow space in which the Status - when a new update is available a clickable button `Update Available` will be visible - check section Updating the Editor in this manual below. - when building or bundling a progress of it will be presented there. +## Engine window placement + +On desktop platforms, engine windows opened from the editor remember their normal windowed size and position across launches and engine reboots. Placement is saved separately for each project and engine instance. Launching a single engine instance uses the same saved placement as the first instance when launching several. + +If you move or resize the engine window, a later launch restores that placement. A remembered size is used while the configured window dimensions are unchanged; changing those dimensions makes the next launch use the new size. On Linux Wayland, only the size is restored because the desktop compositor controls window positioning. + +### Resetting the engine window size + +Choose Debug ▸ Reset Simulated Resolution to return to the configured size. This command: + +- Clears remembered window sizes for all engine instances in the current project, including instances that are not running. +- Clears the selected simulated resolution and turns off **Rotated Device**. +- Keeps saved window positions. + +Windows for the selected running engine instances are resized to the project's [Display Width and Height](/manuals/project-settings/#display). You can also reset with no engine running; the next launch uses the configured size. Moving or resizing the window afterward saves its new placement again. + ## Panes Size and Visibility Panes size can be adjusted inside the Editor by Dragging the section borders between all described above 6 Panes. diff --git a/docs/en/manuals/engine-service.md b/docs/en/manuals/engine-service.md index 4a17f60e..75ca2955 100644 --- a/docs/en/manuals/engine-service.md +++ b/docs/en/manuals/engine-service.md @@ -7,7 +7,7 @@ brief: This manual explains the development HTTP service in a running Defold deb Running a project in Debug mode creates a process for a given runtime instance of the engine with your game and a special engine service that can be accessed for development and profiling infrastructure, runtime logic and messages, engine state and extensions. -The engine service is a development HTTP service owned by a running debug engine (`dmengine`). +The engine service is a development HTTP service owned by a running debug or headless engine (`dmengine` or `dmengine_headless`). It is separate from the [editor server](/manuals/editor-http-api), which belongs to the Defold editor and controls the open project. @@ -17,7 +17,7 @@ The engine service is part of debug, development and profiling infrastructure. R ## Availability and port discovery -When the editor starts a debug engine, it requests a dynamically assigned service port. The engine reports the selected port in `Console` (`and its log if run from a CLI): +When the editor starts a debug engine, it requests a dynamically assigned service port. The engine reports the selected port in the *Console* and in its log when run from a CLI: ![Engine service port information in Defold debug build](images/automation/engine-service.png) @@ -25,7 +25,13 @@ When the editor starts a debug engine, it requests a dynamically assigned servic INFO:ENGINE: Engine service started on port ``` -The line appears in the editor console when the game was launched from the editor. A simple local controller can parse this line, but a reusable integration should let the editor or its wrapper track the engine instance and registered port. This avoids confusing an old port with a newly started or reused process. +The engine also logs the full OpenAPI discovery URL using its actual address and assigned port: + +```text +INFO:ENGINE: OpenAPI: http://
:/openapi.json +``` + +These lines appear in the editor console when the game was launched from the editor. A simple local controller can parse them, but a reusable integration should let the editor or its wrapper track the engine instance and registered port. This avoids confusing an old port with a newly started or reused process. The engine also advertises development targets through service discovery on supported platforms. That mechanism is primarily used by Defold tooling and should not be replaced with a permanently hard-coded port. @@ -33,12 +39,28 @@ Server is accessible on localhost (`127.0.0.1`) at a given port: ![Engine server access](images/automation/engine-server.png) +## Discovering operations through OpenAPI + +`GET /openapi.json` returns an OpenAPI 3.0.3 document describing the runtime HTTP API. Use the engine service port from the log. For a local engine, replace `` below with that port: + +```sh +ENGINE_URL="http://127.0.0.1:" +curl -fsS "$ENGINE_URL/openapi.json" | jq +``` + +The document describes paths, methods, parameters, request bodies, and responses supplied by currently registered handlers, including native extensions that provide OpenAPI metadata. Its `paths` object changes when handlers are added or removed. Profiler and extension routes depend on the running engine's platform, configuration, and registered extensions, so fetch the document from the instance you are using. + +Handlers registered without OpenAPI metadata remain callable but do not appear in the document. A documented route can also report an unavailable capability; inspect its response descriptions and any capability endpoint before using platform-dependent operations. + +The editor has its own [OpenAPI document](/manuals/editor-http-api/#discovering-operations-through-openapi) on the editor port. Use the engine's document for runtime operations. + ## Built-in endpoints The current debug engine registers a small set of core routes. | Endpoint | Purpose | | --- | --- | +| `GET /openapi.json` | Discover the currently registered runtime HTTP operations that provide OpenAPI metadata | | `GET /ping` | Check that the engine service responds | | `GET /info` | Read engine version, platform, build identifier, and log-service information | | `GET /state` | Read development connection state used by Defold tooling | @@ -56,6 +78,35 @@ The `/post` route is used by development operations such as hot reload, reboot, These routes are development infrastructure, and additional profiler and resource-inspection routes exist in the engine implementation. +## Recording endpoints + +Desktop debug engines also expose native MP4 recording through the following routes. They are omitted from release, headless, mobile and web builds, and when **Exclude Record** is enabled in the [App Manifest](/manuals/app-manifest/#exclude-record). + +| Endpoint | Purpose | +| --- | --- | +| `GET /recording/capabilities` | Discover video/audio support, backend requirements and the recording service's `instance_id` | +| `GET /recording/status` | Read the current operation, asynchronous progress and finalized file information | +| `POST /recording/start` | Request recording and receive its `operation_id` | +| `POST /recording/stop` | Request stopping and finalization for the specified operation | +| `GET /recording/files/{id}` | Download a finalized MP4 | +| `DELETE /recording/files/{id}` | Delete a completed file retained by the service | + +Discover these routes through `/openapi.json`, then check `/recording/capabilities` for the current platform's support. Recording mutations require the `X-Recording-Instance` header, and stopping also requires the accepted `operation_id`. Start and stop are asynchronous; wait for finalization before downloading the file. See the [recording manual](/manuals/recording/#recording-through-http) for the complete workflow. + +The HTTP service shares the recorder with Lua. HTTP starts enable application audio by default when supported; Lua starts default to video only. Only recordings started through HTTP have a downloadable `file` receipt. Before downloading, wait for `pending: false`, `finalized: true` and `file.state: "complete"`, then [verify the file's size and SHA-256](/manuals/recording/#download-and-release-the-file). See [sharing the recorder](/manuals/recording/#sharing-the-recorder-with-http-clients) when combining Lua and HTTP clients. + +## Metal GPU trace endpoint + +On macOS, debug engines expose `/profiler/gputrace` for capturing Metal GPU traces. The route appears in `/openapi.json` only on macOS. Capture requires the native Metal adapter and `METAL_CAPTURE_ENABLED=1` in the engine's launch environment. A request returns HTTP 501 with `error.code: "gputrace_unsupported"` if capture is unavailable. + +| Endpoint | Purpose | +| --- | --- | +| `POST /profiler/gputrace` | Schedule capture to a writable absolute `.gputrace` path; `frames` defaults to `1` and may be `1`–`10000`. | +| `GET /profiler/gputrace` | Read the current or most recent capture's state, path and frame counts. | +| `DELETE /profiler/gputrace` | Cancel a pending capture or finish an active capture after the current rendered frame; retain the trace on disk. | + +Accepted requests return HTTP 200 with `ok: true` and a `data` object. Capture progresses asynchronously: poll `GET` until `data.state` is `complete`, `canceled` or `failed`. Native startup failures are reported in `data.error`. The trace is written on the engine host. See the [Metal GPU trace capture guide](/manuals/profiling/#metal-gpu-trace-capture) for launch commands, support discovery, capture examples and opening the result in Xcode. + ## Extension-defined runtime routes In debug builds, the native extension SDK can provide access to the engine web server. An extension can register a route prefix on that server and expose operations that depend on runtime data. @@ -71,6 +122,55 @@ An extension-defined runtime automation API should: * keep operations local to development and testing; * document whether it is omitted from release builds. +### Publishing extension operations in OpenAPI + +In a native extension's application initialization callback, obtain the server with `dmEngine::GetWebServer(app_params)` and register handlers only when the returned handle is non-null. See the [extension lifecycle](/manuals/extensions/#extension-lifecycle) for the callback setup. + +The four-argument `dmWebServer::AddHandler()` overload accepts an OpenAPI 3.0.3 Paths Object as a JSON string. The object has route paths as its top-level keys. Each path must start with the registered prefix and must not already be documented by another handler. Use inline schemas, or references to paths in the resulting document. + +For example, this helper registers a callback and its status endpoint description: + +```cpp +#include + +static const char STATUS_OPENAPI[] = R"json( +{ + "/example/v1/status": { + "get": { + "summary": "Get extension status", + "responses": { + "200": { + "description": "Current extension status", + "content": { + "text/plain": { + "schema": { "type": "string" } + } + } + } + } + } + } +} +)json"; + +dmWebServer::Result RegisterStatusHandler(dmWebServer::HServer server, + dmWebServer::Handler callback, + void* context) +{ + dmWebServer::HandlerParams params; + params.m_Handler = callback; + params.m_Userdata = context; + return dmWebServer::AddHandler( + server, "/example/v1", ¶ms, STATUS_OPENAPI); +} +``` + +Pass a callback that implements `GET /example/v1/status` and returns the documented `text/plain` response. The callback remains responsible for checking request paths and methods and producing responses. Check the registration result: invalid or conflicting metadata returns `dmWebServer::RESULT_ERROR_INVAL`. + +The server retains the JSON pointer without copying the string. Keep its storage unchanged and valid until the handler is removed with `dmWebServer::RemoveHandler()` or the server is destroyed. The `static const char` array in the example satisfies this requirement. Removing the handler also removes its paths from subsequent `/openapi.json` responses. + +The three-argument `dmWebServer::AddHandler(server, prefix, ¶ms)` overload remains supported. It is equivalent to passing `0` as the fourth argument: the handler is registered without OpenAPI metadata and is omitted from discovery. + ## Automation Bridge extension The official Defold [Automation Bridge](https://github.com/defold/extension-automation-bridge) is a debug-only native extension built on the engine service. It registers a versioned runtime automation API under: @@ -114,7 +214,7 @@ game = project.build_and_run() The engine service and extension-defined routes are development tools, and should be treated as such. ::: important -The engine service does not currently publish an OpenAPI document. Integrations should limit themselves to documented behavior or to an extension's versioned API. +Use the running engine's `/openapi.json` document for discovery in Defold 1.14.1 and later. Earlier engines do not provide this endpoint. For handlers registered without OpenAPI metadata, consult the extension's versioned API documentation. ::: Runtime scripts, physics, input, dynamically created objects, and platform rendering require a running engine and should be verified through [automated runtime testing](/manuals/automated-testing). diff --git a/docs/en/manuals/extensions.md b/docs/en/manuals/extensions.md index ba9ba83b..1ad7cc12 100644 --- a/docs/en/manuals/extensions.md +++ b/docs/en/manuals/extensions.md @@ -97,7 +97,7 @@ If the extension relies on annotations at runtime, also include: These rules are combined with the project's selected keep file when [R8 is enabled](/manuals/android/#enabling-r8). -With Defold 1.14.0 or later and a compatible Extender server, R8 also shrinks Android resources. If the extension looks up resources dynamically by name, add [XML resource keep rules](/manuals/android/#keeping-android-resources) under `res/android/res/raw` in the extension folder. +With a compatible Extender server, R8 also shrinks Android resources. If the extension looks up resources dynamically by name, add [XML resource keep rules](/manuals/android/#keeping-android-resources) under `res/android/res/raw` in the extension folder. ## Custom resources diff --git a/docs/en/manuals/flipbook-animation.md b/docs/en/manuals/flipbook-animation.md index 50cc60e6..5c94b633 100644 --- a/docs/en/manuals/flipbook-animation.md +++ b/docs/en/manuals/flipbook-animation.md @@ -5,7 +5,7 @@ brief: This manual describes how to use flipbook animations in Defold. # Flip-book animation -A flipbook animation consists of a series of still images that are shown in succession. The technique is very similar to traditional cell animation (see http://en.wikipedia.org/wiki/Traditional_animation). The technique offers limitless opportunities since each frame can be manipulated individually. However, since each frame is stored in a unique image, the memory footprint can be high. The smoothness of animation is also dependent on the number of images shown each second but increasing the number of images usually also increase the amount of work. Defold flipbook animations are either stored as individual images added to an [Atlas](/manuals/atlas), or as a [Tile Source](/manuals/tilesource) with all frames laid out in a horizontal sequence. +A flipbook animation consists of a series of still images that are shown in succession. The technique is very similar to traditional cell animation (see http://en.wikipedia.org/wiki/Traditional_animation). The technique offers limitless opportunities since each frame can be manipulated individually. However, storing many distinct images can require a lot of texture memory. The smoothness of animation is also dependent on the number of images shown each second but increasing the number of images usually also increase the amount of work. Defold flipbook animations are either stored as individual images added to an [Atlas](/manuals/atlas), or as tiles in a [Tile Source](/manuals/tilesource). Tile source animations use a *Frames* list to select tiles from the image grid in any order, including repetitions. ![Animation sheet](images/animation/animsheet.png){.inline} ![Run loop](images/animation/runloop.gif){.inline} diff --git a/docs/en/manuals/font.md b/docs/en/manuals/font.md index 91ead380..eda4d82b 100644 --- a/docs/en/manuals/font.md +++ b/docs/en/manuals/font.md @@ -11,20 +11,30 @@ Fonts are used to render text on Label components and GUI text nodes. Defold sup - OpenType - BMFont -Since Defold 1.13.2, both the legacy and full text layout engines support TrueType outlines and OpenType CFF1/CFF2 outlines, including runtime generation from `.ttf` and `.otf` resources. +Both the legacy and full text layout engines support TrueType outlines and OpenType CFF1/CFF2 outlines, including runtime generation from `.ttf` and `.otf` resources. For information about styling individual text spans and working with links and inline sprites, see the [Rich text markup manual](/manuals/font-richtext). -Fonts added to your project are automatically converted into a texture format that Defold can render. Two font rendering techniques are available, each with its own specific benefits and drawbacks: +For TrueType and OpenType fonts, the *Mode* property selects how glyphs are rendered: -- Bitmap -- Distance field +- **Bitmap** uses rasterized glyph images. +- **SDF** (signed distance field) stores distances to glyph edges in a texture, allowing more flexible scaling than Bitmap. +- **Vector** renders glyph faces from curve data, keeping them sharp when scaled. Outline and shadow effects still use bitmap data. + +Newly created font resources use **Vector** mode and **Dynamic** glyph generation. Existing font resources keep their Bitmap or SDF mode. BMFont sources always use their supplied bitmap. + +Vector mode requires graphics support for `RGBA16F` and `R32UI` textures and is not supported on OpenGL ES 2 or WebGL 1. Use Bitmap or SDF fonts and matching materials when targeting unsupported graphics adapters; there is no automatic fallback from Vector to SDF. See [Vector fonts](#vector-fonts) for setup. ## Offline or Runtime fonts -By default, the conversion to rasterized glyph images happens at build time (offline). This has the drawback that each font needs to rasterize all possible glyphs in the build stage, producing potentially very large textures that consume memory and also increase the bundle size. +The *Glyph Generation* property selects when each font's glyph data is generated: + +- **Static** generates the selected glyphs at build time (offline). *Characters* and *All Chars* control which glyphs are included. The source `.ttf` or `.otf` file is not bundled for runtime generation. +- **Dynamic** bundles the source `.ttf` or `.otf` file and generates glyphs on demand at runtime. *Prewarm Text* prepares glyphs when the font loads. Other glyphs can be generated later as needed. -By using "runtime fonts", the `.ttf` and `.otf` fonts will be bundled as-is, and the rasterization will happen on-demand at runtime. This minimizes both runtime memory usage and the bundle size. +SDF and Vector fonts support both choices. Bitmap fonts and BMFont sources use Static generation. Each font resource is configured independently, so a project can mix Static and Dynamic fonts. + +Dynamic generation can reduce bundle size and runtime memory use, particularly for fonts with large character sets. It requires the full text layout system in the engine; see [Enabling Runtime Fonts](#enabling-runtime-fonts). ## Text layout support (e.g. Right-to-left) @@ -51,11 +61,15 @@ To create a font for use in Defold, create a new Font file by selecting Fil Give the new font file a name and click Ok. The new font file now opens in the editor. -![New font](images/font/new_font.png) - Drag the font you wish to use into the *Assets* browser and drop it in a good spot. -Set the *Font* property to the font file and set the font properties as needed. +Set the *Font* property to the font file. For a `.ttf` or `.otf` source, select *Mode* and *Glyph Generation*, then configure the remaining properties as needed. For Dynamic generation, also complete the [runtime font setup](#enabling-runtime-fonts). + +![Font properties with Vector mode and Dynamic glyph generation](images/font/font_properties.png) + +For Vector fonts, use *Font Size* on a Label component or GUI text node to change the displayed text size. *Outline/Shadow Bitmap Size* controls the resolution of the effect bitmaps independently of the displayed text size. + +For Bitmap and SDF fonts, set *Size* in the font resource to choose the generated glyph size. BMFont sizes come from the source `.fnt` file. To change the displayed size of these fonts, scale the Label component or GUI text node. ## Properties @@ -63,25 +77,28 @@ Set the *Font* property to the font file and set the font properties as needed. : The TTF, OTF or *`.fnt`* file to use for generating the font data. *Material* -: The material to use when rendering this font. Make sure to change this for distance field and BMFonts (see below for details). +: The material to use when rendering this font. It must match the font mode; see [Font materials](#font-materials). -*Output Format* -: The type of font data that is generated. +*Mode* +: The rendering technique for a `.ttf` or `.otf` source: **Bitmap**, **SDF** or **Vector**. This replaces the former *Output Format* property. The property is not shown for BMFont sources. - - `TYPE_BITMAP` converts the imported OTF or TTF file into a font sheet texture where the bitmap data is used to render text nodes. The color channels are used to encode the face shape, outline and drop shadow. For *`.fnt`* files, the source texture bitmap is used as is. - - `TYPE_DISTANCE_FIELD` The imported font is converted into a font sheet texture where the pixel data represents not screen pixels but distances to the font edge. See below for details. +*Glyph Generation* +: **Static** generates glyph data at build time. **Dynamic** generates it at runtime and requires the [full text layout system](#enabling-runtime-fonts). This property is available for SDF and Vector fonts. For Bitmap mode it is fixed to Static, and it is not shown for BMFont sources. *Render Mode* -: The render mode to use for glyph rendering. +: The layer arrangement for generated Bitmap fonts. This property is only shown in Bitmap mode for `.ttf` and `.otf` sources. For SDF, Vector and BMFont sources, Defold selects the layer arrangement automatically. - - `MODE_SINGLE_LAYER` produces a single quad for each character. - - `MODE_MULTI_LAYER` produces separate quads for the glyph shape, outline and shadows respectively. The layers are rendered in back-to-front order, which prevents a character from obscuring previously rendered characters if the outline is wider than the distance between glyphs. This render mode also enables proper drop shadow offsetting, as specified by the Shadow X/Y properties in the font resource. + - **Single Layer** produces a single quad for each character. + - **Multi Layer** produces separate quads for the glyph shape, outline and shadow. The layers are rendered in back-to-front order, which prevents a character from obscuring previously rendered characters if the outline is wider than the distance between glyphs. This also enables shadow offsets from the *Shadow X/Y* properties. *Size* -: The target size of the glyphs in pixels. +: The glyph size in pixels used when generating Bitmap or SDF font data. For BMFont sources, the size is read from the `.fnt` file and cannot be edited here. + +*Outline/Shadow Bitmap Size* +: In Vector mode, this replaces *Size*. It controls the bitmap resolution of enabled outline and shadow effects for both Static and Dynamic generation. It is disabled when neither effect is enabled, because the glyph faces use curve data. Changing a Label or GUI text node's *Font Size* does not change this shared bitmap resolution. *Antialias* -: If the font should be antialiased when baked onto the target bitmap. Set to 0 if you want pixel perfect font rendering. +: Whether to antialias glyphs when generating Bitmap font data. Disable it for pixel perfect rendering. This property is only shown in Bitmap mode for `.ttf` and `.otf` sources. *Alpha* : The transparency of the glyph. 0.0--1.0 where 0.0 means transparent and 1.0 opaque. @@ -96,19 +113,20 @@ Set the *Font* property to the font file and set the font properties as needed. : The transparency of the generated shadow. 0.0--1.0. ::: sidenote -Shadow support is enabled by the built-in font material shaders and handles both the single and multi layered render mode. If you don't need layered font rendering or shadow support, it is best to use a simpler shader such as the *`builtins/font-singlelayer.fp`*. +The built-in Bitmap font shader supports shadows in both *Single Layer* and *Multi Layer* render modes. For generated Bitmap fonts that use *Single Layer* rendering and do not need shadows, a custom material can use `/builtins/fonts/font-singlelayer.fp`. SDF and Vector fonts require shaders matching their mode; see [Font materials](#font-materials). ::: *Shadow Blur* -: For bitmap fonts, this setting indicates the number of times a small blur kernel will be applied to each font glyph. For distance field fonts, this setting equals the actual pixel width of the blur. +: The amount of blur applied to the generated shadow. Set to 0 for a sharp shadow. *Shadow X/Y* -: The horizontal and vertical offset in pixels of the generated shadow. This setting will only affect the glyph shadow when the Render Mode is set to `MODE_MULTI_LAYER`. +: The horizontal and vertical offset in pixels of the generated shadow. For generated Bitmap fonts, use *Multi Layer* render mode to apply these offsets. Defold selects the appropriate layers automatically for SDF and Vector fonts. *Characters* -: Which characters to include in the font. By default this field include the ASCII printable characters (character codes 32-126). You can add or remove characters from this field to include more or less characters in the font.. +: For Static generation, the characters to include in the built font. By default this field contains the ASCII printable characters (character codes 32-126). Add or remove characters to control which glyphs are available at runtime. -For runtime fonts, this text acts as a cache prewarming with the correct glyphs. This happens during load time. See `font.prewarm_text()`. +*Prewarm Text* +: For Dynamic generation, this replaces *Characters*. The text is used to generate glyphs and prewarm the cache when the font loads. It does not restrict which characters can be generated later. You can also prewarm text from a script with [`font.prewarm_text()`](/ref/font/#font.prewarm_text). ::: sidenote The ASCII printable characters are: @@ -116,20 +134,62 @@ space ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E ::: *All Chars* -: If you check this property all glyphs available in the source file will be included in the output. +: For Static generation, include every glyph available in the source instead of limiting the font to *Characters*. This property is hidden for Dynamic fonts. *Cache Width/Height* -: Constrains the size of the glyph cache bitmap. When the engine renders text, it looks up the glyph from the cache bitmap. If it does not exist there, it will be added to the cache before rendering. If the cache bitmap is too small to contain all the glyphs the engine is asked to render, an error is signalled (`ERROR:RENDER: Out of available cache cells! Consider increasing cache_width or cache_height for the font.`). +: Constrains the size of the glyph cache bitmap used by Bitmap and SDF fonts, and by Vector outline and shadow effects. When the engine renders text, it looks up the glyph from the cache bitmap. If it does not exist there, it will be added to the cache before rendering. If the cache bitmap is too small to contain all the glyphs the engine is asked to render, an error is signalled (`ERROR:RENDER: Out of available cache cells! Consider increasing cache_width or cache_height for the font.`). If set to 0 the cache size is set automatically, and will grow to 2048x4096 max. +## Font materials + +Use a material that matches the font mode. The font resource's *Material* is used by GUI text nodes. Label components have a separate *Material* property that must also match the font: + +| Font mode or source | Font material for GUI text | Label component material | +| --- | --- | --- | +| Bitmap | `/builtins/fonts/font.material` | `/builtins/fonts/label.material` | +| SDF | `/builtins/fonts/font-df.material` | `/builtins/fonts/label-df.material` | +| Vector | `/builtins/fonts/font-vector.material` | `/builtins/fonts/label-vector.material` | +| BMFont (`.fnt`) | `/builtins/fonts/font-fnt.material` | `/builtins/fonts/label-fnt.material` | + +Changing *Mode* in the font editor switches between the corresponding built-in Bitmap, SDF and Vector materials when one of those materials is already assigned to the font. Custom materials are not replaced automatically. Check the *Material* property on any Label components that use the font as well. + +## Vector fonts + +Vector fonts render glyph faces from curves so they remain sharp as the displayed text size changes. To set up a font that generates its glyphs at runtime: + +1. Create a `.font` resource, for example `/fonts/ui.font`, and select a TrueType or OpenType source in its *Font* property. The built-in `/builtins/fonts/vera_mo_bd.ttf` can be used for ordinary text. +2. Set *Mode* to **Vector**, *Glyph Generation* to **Dynamic**, and *Material* to `/builtins/fonts/font-vector.material`. These are the defaults for newly created font resources. +3. Enable **Use full text layout system** in an App Manifest assigned to your project. Follow [Enabling Runtime Fonts](#enabling-runtime-fonts) to configure the custom engine. +4. Enable [Shader ▸ Exclude GLES 2.0](/manuals/project-settings/#exclude-gles-20) in *game.project*. +5. Assign the font to a [Label](/manuals/label/) or add it to a GUI scene's *Fonts* and select it on a [text node](/manuals/gui-text/). For a Label, also set the component's *Material* to `/builtins/fonts/label-vector.material`. Set the component or node's *Font Size* to the desired display size. + +Vector glyph faces use curve textures, but enabled outlines and shadows still generate SDF bitmap data and consume glyph-cache texture memory. *Outline/Shadow Bitmap Size* sets that bitmap resolution independently of the Label or GUI text node's *Font Size*. Set *Outline Alpha* and *Shadow Alpha* to `0` when those effects are not needed to avoid generating their bitmap data. + +### Color emoji + +Vector fonts can render COLRv1 color emoji, including palette colors and linear and radial gradients. Bitmap and SDF modes do not render COLRv1 colors. Use the Dynamic Vector setup above, then add a COLRv1 emoji font as a fallback to the font collection. Ordinary text continues using the original font. + +For example, copy the COLRv1 [Noto Color Emoji font](https://github.com/google/fonts/blob/main/ofl/notocoloremoji/NotoColorEmoji-Regular.ttf) into your project as `/fonts/NotoColorEmoji-Regular.ttf`. Choose the COLRv1 version: other emoji fonts may use a different color format even when their filename ends in `.ttf`. + +Append `/fonts/NotoColorEmoji-Regular.ttf` to **Project ▸ Custom Resources** in *game.project*. With no other custom resources, the setting is: + +```ini +[project] +custom_resources = /fonts/NotoColorEmoji-Regular.ttf +``` + +A font path written in Lua does not cause the font file to be bundled. [Custom Resources](/manuals/project-settings/#custom-resources) makes this source font available to [`font.add_font()`](/ref/font/#font.add_font), which loads it through the resource system. Pass the source font's string path when loading it from the bundle. + +Add the fallback once per shared font resource. The change affects every Label and GUI text node using that font, and adding the same fallback twice raises an error. If using both the [Label example](/manuals/label/#vector-fonts-and-color-emoji) and the [GUI example](/manuals/gui-text/#vector-fonts-and-color-emoji) with the same `.font`, coordinate initialization so the fallback is added once before either example prewarms or displays text. The examples prewarm the complete text after adding the fallback and display it when the callback succeeds. + ## Distance field fonts Distance field fonts store the distance to the edge of the glyph in the texture instead of bitmap data. When the engine renders the font, a special shader is required to interpret the distance data and use that to draw the glyph. Distance field fonts are more resource intensive than bitmap fonts, but allow for greater sizing flexibility. ![Distance field font](images/font/df_font.png) -Make sure to change the *Material* property of the font to *`builtins/fonts/font-df.material`* (or any other material that can handle the distance field data) when you create the font---or the font will not use the correct shader when it is rendered to screen. +Select **SDF** in *Mode* and choose **Static** or **Dynamic** in *Glyph Generation*. Use *`/builtins/fonts/font-df.material`* for the font and *`/builtins/fonts/label-df.material`* for Label components, or custom materials that handle distance field data. ## Bitmap BMFonts @@ -137,7 +197,7 @@ In addition to generated bitmaps Defold supports prebaked bitmap "BMFont" format These types of fonts provide no performance improvement from bitmap fonts generated from TrueType or OpenType font files, but can include arbitrary graphics, coloring and shadows right in the image. -Add the generated *`.fnt`* and *`.png`* files to your Defold project. These files should reside in the same folder. Create a new font file and set the *font* property to the *`.fnt`* file. Make sure that *output_format* is set to `TYPE_BITMAP`. Defold will not generate a bitmap but use the one provided in the PNG. +Add the generated *`.fnt`* and *`.png`* files to your Defold project. These files should reside in the same folder. Create a new font file and set the *Font* property to the *`.fnt`* file. Defold uses the supplied bitmap and reads its size from the `.fnt` file. *Mode* and *Glyph Generation* are not shown for BMFont sources. ::: sidenote To create a BMFont, you need to use a tool that can generate the appropriate files. Several options exist: @@ -151,7 +211,7 @@ To create a BMFont, you need to use a tool that can generate the appropriate fil ![BMfont](images/font/bm_font.png) -For the font to render correctly, don't forget to set the material property to *`builtins/fonts/font-fnt.material`* when you create the font. +Set the font's *Material* to *`/builtins/fonts/font-fnt.material`*. For Label components, use *`/builtins/fonts/label-fnt.material`*. ## Artifacts and best practices @@ -169,10 +229,10 @@ Distance field fonts need to be rendered to a target size that is big enough to ![Distance field artifacts](images/font/df_artifacts.png) -If you don't want shadow or outline support, set their respective alpha values to zero. Otherwise, shadow and outline data will still be generated, taking up unnecessary memory. +If you don't want shadow or outline support, set their respective alpha values to zero. Otherwise, shadow and outline data will still be generated, taking up unnecessary memory. In Vector mode, disabling both effects avoids generating their bitmap data; the glyph faces continue to use curve data. ## Font Cache -A font resource in Defold will result in two things at runtime, a texture and the font data. +Bitmap and SDF font resources use a glyph cache texture and font data at runtime. Vector fonts store their glyph faces as curve data and use a bitmap cache for enabled outline and shadow effects. The texture layout described below applies to Bitmap and SDF fonts. * The font data consist of a list of glyph entries, each containing some basic kerning info and the bitmap data for that glyph. * The texture is internally called the "glyph cache texture" and it will be used when rendering text for a specific font. @@ -194,42 +254,27 @@ For more information about shader uniforms, see the [Shader manual](/manuals/sha ## Enabling Runtime Fonts -It is possible to use runtime generation for SDF type fonts, when using TrueType (`.ttf`) or OpenType (`.otf`) fonts. Runtime generation from `.otf` resources is supported since Defold 1.13.2. -This approach can greatly reduce the download size and runtime memory consumption of a Defold game. -The small downside is the asynchronous nature of generating each glyph. - -* Enable the feature by setting `font.runtime_generation` in game.project. - -* Add an [App Manifest](/manuals/app-manifest) and enable the `Use full text layout system` option. -This builds a custom engine that has this feature enabled. +Runtime generation is configured per font resource: -::: sidenote -This feature is currently experimental, but with the intention to be used as the default workflow in the future. -::: - -::: important -The `font.runtime_generation` setting affects all `.ttf` and `.otf` fonts in the project. -::: +1. Open the `.font` resource and select a TrueType (`.ttf`) or OpenType (`.otf`) source. +2. Set *Mode* to **SDF** or **Vector** and *Glyph Generation* to **Dynamic**. +3. Choose the matching [font and Label materials](#font-materials). +4. Add an [App Manifest](/manuals/app-manifest), assign it to *Native Extensions ▸ App Manifest* in *game.project*, and enable **Use full text layout system**. This builds a custom engine with runtime font generation and full text layout support. +5. Set *Prewarm Text* to text that will be displayed soon after the font loads. For text needed later, use [`font.prewarm_text()`](/ref/font/#font.prewarm_text) and wait for its callback before displaying it. +New font resources already use Vector mode and Dynamic generation, but still require the App Manifest configuration above. ### Font Scripting #### Prewarming glyph cache -In order to make the runtime fonts easier to use, they support prewarming of the glyph cache. -This means the font will generate the glyphs listed in *Characters* in the font. - -::: sidenote -If `All Chars` is selected, there will be no prewarming as it defeats the purpose of not having to generate all glyphs at the same time. -::: - -If the `Characters` field of the `.fontc` file is set, this is used as a text, to figure out which glyphs needs to be updated in the glyph cache. +Dynamic fonts generate the glyphs needed by *Prewarm Text* when the font loads. The field is interpreted as text to be laid out, so the cache is prepared for the glyphs that the text needs. *All Chars* is not available for Dynamic fonts. -It is also possible to manually update the glyph cache by calling `font.prewarm_text(font_collection, text, callback)`. It provides a callback to let you know when all the missing glyphs have been added to the glyph cache, and it's safe to present the text on screen. +You can also call `font.prewarm_text(font_collection, text, callback)` for a Dynamic font. The callback tells you when all the missing glyphs have been added to the cache and it is safe to display the text. This function cannot be used with Static fonts. ### Adding/removing fonts to a font collection -For runtime fonts, it's possible to add or remove fonts (`.ttf`) to a font collection. +For Dynamic fonts, it's possible to add or remove source fonts (`.ttf` or `.otf`) to a font collection. This is useful when a large font has been split up into multiple files for different character sets (e.g. CJK) ::: important diff --git a/docs/en/manuals/gui-layouts.md b/docs/en/manuals/gui-layouts.md index d26a6504..acf2b384 100644 --- a/docs/en/manuals/gui-layouts.md +++ b/docs/en/manuals/gui-layouts.md @@ -99,6 +99,8 @@ end When orientation is switched, the GUI layout manager will automatically scale and reposition GUI nodes according to your layout and node properties. In-game content, however, is rendered in a separate pass (by default) with a stretch-fit projection into the current window. To change this behavior, either supply your own modified render script, or use a camera [library](/assets/). +For custom UI placement around camera cutouts, refresh `window.get_reserved_areas()` on `window.WINDOW_EVENT_RESIZED` even when the selected GUI layout stays the same. On iOS, a 180° rotation can leave the window dimensions and safe-area insets unchanged while moving the obstruction. See [Reserved screen areas](/manuals/porting-guidelines/#reserved-screen-areas) for the refresh example and how its coordinates in window pixels relate to GUI adjustment. + ## Manual layout selection (Lua) When Auto Layout Selection is OFF for the Display Profiles in use, the engine won’t switch layouts automatically. Use these functions from a GUI script to manage layouts manually: diff --git a/docs/en/manuals/gui-script.md b/docs/en/manuals/gui-script.md index 73c5fc0a..cb1f803a 100644 --- a/docs/en/manuals/gui-script.md +++ b/docs/en/manuals/gui-script.md @@ -51,6 +51,12 @@ To attach the script to a GUI component, open the GUI component prototype file ( If the GUI component has been added to a game object somewhere in your game, the script will now run. +## Input + +To receive input in a GUI script, send `msg.post(".", "acquire_input_focus")` from `init()` and handle actions in `on_input(self, action_id, action)`. + +GUI scripts use the same `action.source` hashes as game object scripts, so you can distinguish a physical mouse click from a tap even on the initial press. See [Input device source](/manuals/input/#input-device-source) and the [mouse and touch example](/manuals/input-mouse-and-touch/#distinguishing-mouse-clicks-from-touch). Pointer movement and accelerometer samples both use `action_id == nil`; use their source to tell them apart. + ## The "gui" namespace GUI scripts have access to the `gui` name space and [all the `gui` functions](/ref/gui). The `go` namespace is not available so you will need to separate game object logic into script components and communicate between the GUI and game object scripts. Any attempt to use the `go` functions will cause an error: diff --git a/docs/en/manuals/gui-text.md b/docs/en/manuals/gui-text.md index 17c4441e..e98a1ac6 100644 --- a/docs/en/manuals/gui-text.md +++ b/docs/en/manuals/gui-text.md @@ -26,6 +26,31 @@ Text nodes have a set of special properties: *Line Break* : Text alignment follows the pivot setting and setting this property allows the text to flow over several lines. The width of the node determines where the text will wrap. +## Vector fonts and color emoji + +Follow the [Vector font setup](/manuals/font/#vector-fonts), add the `.font` resource to the GUI scene's *Fonts*, and select it on the text node. Set the font resource's *Material* to `/builtins/fonts/font-vector.material`. Use the node's *Font Size* to control the displayed size. + +For color emoji, also complete the [COLRv1 fallback and bundling setup](/manuals/font/#color-emoji). Create a text node with the id `text`, leave its *Text* empty, and add the following to the GUI scene's `.gui_script`: + +```lua +function init(self) + local node = gui.get_node("text") + local text = "Hello 😀 🍎 🚀" + local font_resource = gui.get_font_resource(gui.get_font(node)) + -- Add the fallback once for this shared font resource. + font.add_font(font_resource, "/fonts/NotoColorEmoji-Regular.ttf") + font.prewarm_text(font_resource, text, function(self, request_id, result, err) + if result then + gui.set_text(node, text) + else + print("Could not prepare GUI text:", err) + end + end) +end +``` + +[`gui.get_font()`](/ref/gui/#gui.get_font) returns the font name within the GUI scene; [`gui.get_font_resource()`](/ref/gui/#gui.get_font_resource) resolves that name to the font resource used by `font.add_font()`. Other nodes and Labels sharing that resource also receive the fallback, so initialize it only once. The text is set after prewarming succeeds. + ## Alignment By setting the node pivot you can change the alignment mode for the text. diff --git a/docs/en/manuals/html5.md b/docs/en/manuals/html5.md index 41ea374c..6f1e4824 100644 --- a/docs/en/manuals/html5.md +++ b/docs/en/manuals/html5.md @@ -83,6 +83,39 @@ When you click on the Create bundle button you will be prompted to se Select the requested graphics context through [`graphics.webgl_version_hint`](/manuals/project-settings/#webgl-version-hint). Its default is WebGL 2; request WebGL 1 to test or target that context on browsers that support both versions. +Since Defold 1.14.1, WebGL 1 shaders are excluded by default. Disable [Exclude GLES 2.0](/manuals/project-settings/#exclude-gles-20) to include them, whether requesting WebGL 1 directly or allowing fallback from WebGL 2. To request WebGL 1 explicitly, set both options in *game.project*: + +```ini +[graphics] +webgl_version_hint = 1 + +[shader] +exclude_gles_sm100 = 0 +``` + +## Pixel ratio limits + +`html5.min_pixel_ratio` and `html5.max_pixel_ratio` control how many canvas render pixels are used per CSS pixel. The canvas's CSS size determines how large the game appears on the page; its rendering resolution determines how many pixels the engine draws. + +Enable *High Dpi* in the *Display* section of *game.project* to use these limits. The browser's device pixel ratio is then clamped to the enabled bounds. Both limits default to `0`, which disables that bound. Values must be finite and non-negative; if both are positive, the minimum must not exceed the maximum. + +For example, cap the ratio at `1.5` to limit rendering resolution on dense displays: + +```ini +[display] +high_dpi = 1 + +[html5] +min_pixel_ratio = 0 +max_pixel_ratio = 1.5 +``` + +On a browser reporting a device pixel ratio of `3`, a canvas displayed at 800 × 600 CSS pixels will render at 1200 × 900 pixels with this configuration. Its displayed size stays the same. On a browser reporting a ratio of `1`, the same canvas still renders at 800 × 600 pixels because the maximum does not raise the ratio. + +Fractional ratios below `1` are also supported: for example, a maximum of `0.75` renders fewer pixels than the CSS display size. A minimum above the browser's device pixel ratio increases the rendering resolution for supersampling. The limits apply to all four *Scale Mode* options while preserving their CSS layout. + +With *High Dpi* disabled, the ratio stays at `1`, regardless of the limits. On HTML5, [`window.get_display_scale()`](/ref/window/#window.get_display_scale) returns the effective rendering ratio after applying the High DPI setting and limits. + ## Download verification The HTML5 loader checks the sizes of downloaded engine and archive files by default. Failed checks cause downloads to be retried before the loader reports an error: @@ -130,7 +163,7 @@ In *game.project* it is possible to turn-off the `Fullscreen` button and the `Ma Defold provides a dark and light theme for the `index.html`. The light theme is set by default but it is possible to change by changing `Custom CSS` file. There is also four predefined scale modes to chose from in the `Scale Mode` field. ::: important -The calculations for all scale modes include current screen DPI in case if you turn on `High Dpi` option in *game.project* (`Display` section) +With *High Dpi* enabled in the *Display* section of *game.project*, all scale modes use the effective pixel ratio, including any [pixel ratio limits](#pixel-ratio-limits), to size the canvas rendering buffer. ::: ### Downscale Fit and Fit @@ -146,7 +179,7 @@ For the `Stretch` mode canvas size will be changed to fully fill the inner size ![HTML5 Section](images/html5/html5_stretch.png) ### No Scale -With `No Scale` mode the canvas size is exactly the same as you predefined in *game.project* file, `[display]` section. +With `No Scale` mode the canvas's CSS width and height match the *Width* and *Height* values in the *Display* section of *game.project*. Its rendering resolution still uses the effective pixel ratio. ![HTML5 Section](images/html5/html5_no_scale.png) @@ -197,10 +230,10 @@ DEFOLD_ARCHIVE_LOCATION_SUFFIX : The resolved suffix appended to archive URLs, based on `html5.archive_location_suffix`. DEFOLD_HAS_ARCHIVE_ORIGIN -: `true` when the archive prefix specifies an HTTP or HTTPS origin, including a protocol-relative URL such as `//cdn.example.com/archive`. It is `false` for relative archive prefixes. Available since Defold 1.13.2. +: `true` when the archive prefix specifies an HTTP or HTTPS origin, including a protocol-relative URL such as `//cdn.example.com/archive`. It is `false` for relative archive prefixes. DEFOLD_ARCHIVE_ORIGIN -: The archive origin, including the scheme, host and optional port, or an empty string when no origin is specified. A protocol-relative prefix produces a protocol-relative origin. Used for the preconnect hint and available since Defold 1.13.2. +: The archive origin, including the scheme, host and optional port, or an empty string when no origin is specified. A protocol-relative prefix produces a protocol-relative origin. Used for the preconnect hint. DEFOLD_HAS_WASM_ENGINE : `true` if the bundle includes a WebAssembly engine, either `wasm-web` or `wasm_pthread-web`. diff --git a/docs/en/manuals/images/editor/axis_gizmo.gif b/docs/en/manuals/images/editor/axis_gizmo.gif new file mode 100644 index 00000000..3dfc7dc3 Binary files /dev/null and b/docs/en/manuals/images/editor/axis_gizmo.gif differ diff --git a/docs/en/manuals/images/font/font_properties.png b/docs/en/manuals/images/font/font_properties.png new file mode 100644 index 00000000..74abad3a Binary files /dev/null and b/docs/en/manuals/images/font/font_properties.png differ diff --git a/docs/en/manuals/importing-assets.md b/docs/en/manuals/importing-assets.md index a1d82e9f..587676c1 100644 --- a/docs/en/manuals/importing-assets.md +++ b/docs/en/manuals/importing-assets.md @@ -15,7 +15,7 @@ Defold needs all the assets used in your project to be located somewhere in the ![Importing files](images/graphics/import.png) ::: sidenote -Defold supports images in the PNG and JPEG image formats. PNG images must be in 32 bit RGBA format. Other image formats need to be converted before they can be used. +Use PNG or JPEG images for atlases and tile sources. PNG support includes RGB, RGBA and indexed color (palette) images. [KTX2 source textures](/manuals/importing-graphics/#ktx2-textures) can also be imported for use as model textures. ::: @@ -26,7 +26,7 @@ When the assets are imported into Defold they can be used by the various compone * Images can be used to create many kinds of visual components frequently used in 2D games. Read more about [how to import and use 2D graphics here](/manuals/importing-graphics). * Sounds can be used by the [Sound component](/manuals/sound) to play sounds. * Fonts are used by the [Label component](/manuals/label) and by [text nodes](/manuals/gui-text) in a GUI. -* glTF models (*.gltf* and *.glb*) can be used by the [Model component](/manuals/model) to show 3D models with animations. Import any texture images used by the model as separate assets and assign them on the Model component material texture properties. Read more about [how to import and use 3D models here](/manuals/importing-models). +* glTF models (*.gltf* and *.glb*) can be used by the [Model component](/manuals/model) to show 3D models with animations. Expand these files in the *Assets* pane to browse their meshes, generated materials and embedded images. Embedded images can be used directly; include any externally referenced images and buffers as separate project files. [Draco- and Meshopt-compressed geometry](/manuals/importing-models/#compressed-geometry) is also supported and is decoded during import/build. When selecting a scene or mesh in a Model component, the editor can offer to fill its material and texture bindings. Choose Auto Fill to apply them, replacing existing bindings, or Keep Current to preserve your own. Read more about [how to import and use 3D models here](/manuals/importing-models). ## Editing external assets diff --git a/docs/en/manuals/importing-graphics.md b/docs/en/manuals/importing-graphics.md index eaae60b7..308fe64a 100644 --- a/docs/en/manuals/importing-graphics.md +++ b/docs/en/manuals/importing-graphics.md @@ -10,9 +10,19 @@ Defold supports many kinds of visual components frequently used in 2D games. You ![Importing files](images/graphics/import.png) ::: sidenote -Defold supports images in the PNG and JPEG image formats. Other image formats need to be converted before they can be used. +Use PNG or JPEG images for atlases and tile sources. KTX2 source textures can also be imported for use as model textures; see below. ::: +## KTX2 textures + +Import a standalone *.ktx2* file by dragging it into the *Assets* pane, then assign it to a Model component's material texture field. [glTF and GLB models](/manuals/importing-models/#ktx2-textures) can also reference external KTX2 files or contain embedded KTX2 images. Atlas, tile-source and cubemap-face inputs continue to use their existing image formats. + +Supported KTX2 inputs are 2D textures using ETC1S/BasisLZ, UASTC, BC7, or 8-bit R/RG/RGB/RGBA UNORM or sRGB data. KTX2 arrays, cubemaps, volumes and HDR textures are not supported. KTX2 is processed at build time into Defold's *.texturec* resources; the runtime does not read KTX2 containers. + +Open a KTX2 asset to inspect its source format, dimensions, color space, alpha metadata and mip levels. The *Outline* lets you select individual authored mip levels. These show the source images even if a texture profile resizes the compiled texture or disables its mipmaps. + +Use [texture profiles](/manuals/texture-profiles/#ktx2-source-textures) to choose between keeping the source format and converting it to other formats. Choose output formats supported by your target devices. Recompressing an already lossy source can reduce quality further, including when **Keep KTX2 Format** needs to re-encode after image processing. + ## Creating Defold assets diff --git a/docs/en/manuals/importing-models.md b/docs/en/manuals/importing-models.md index 6eb4aad5..23242a92 100644 --- a/docs/en/manuals/importing-models.md +++ b/docs/en/manuals/importing-models.md @@ -18,29 +18,62 @@ To import a model, drag and drop the *.gltf* or *.glb* file into the Defold edit glTF can be stored in two common ways: * *.glb* is a single binary file. It contains the model data and may also contain packed texture images. This is convenient when you want to move or store a model as one file. -* *.gltf* is a text-based JSON file. It usually references a separate *.bin* file for mesh data and separate texture images such as *.png* or *.jpg*. When using this variant, add all referenced files to the project and keep their relative paths intact. +* *.gltf* is a text-based JSON file. It usually references a separate *.bin* file for mesh data and separate texture images such as *.png*, *.jpg* or *.ktx2*. When using this variant, add all referenced files to the project and keep their relative paths intact. -If the model should use a texture in Defold, import the texture image as a separate asset. Even when the source glTF/GLB file contains embedded images, textures must be assigned to the Model component through the component material texture properties. - -![Imported model assets](images/model/assets_gltf.png) +Embedded images can be used directly from a glTF or GLB file without extracting them into separate assets. External image and buffer files must still be imported with the model, with their relative paths preserved. ::: sidenote -Starting with Defold 1.13.0, Defold preserves the positions and transforms from the imported glTF file and does not automatically re-center the model during import. The editor preview and runtime use the imported transforms consistently: skinned or bone-parented meshes preserve their local, skeleton-relative transforms, while rigid meshes retain their flattened world placement. +Defold preserves the positions and transforms from the imported glTF file and does not automatically re-center the model during import. The editor preview and runtime use the imported transforms consistently: skinned or bone-parented meshes preserve their local, skeleton-relative transforms, while rigid meshes retain their flattened world placement. -Since Defold 1.13.2, a [Model component](/manuals/model/#model-properties) can select a single named mesh from the imported scene. Leaving its *Mesh* field empty uses the whole scene and preserves the transforms described above. Selecting a mesh uses its local geometry without the glTF node transforms, so place it using the model component or game object's transform. +A [Model component](/manuals/model/#model-properties) can select a single named mesh from the imported scene. Leaving its *Mesh* field empty uses the whole scene and preserves the transforms described above. Selecting a mesh uses its local geometry without the glTF node transforms, so place it using the model component or game object's transform. If a model created with an older version of Defold changes position or orientation after being reimported, correct the transform in Blender or another authoring tool and export the *.gltf* or *.glb* file again. ::: +### Compressed geometry + +*.gltf* and *.glb* sources can contain geometry compressed with Draco or Meshopt. The supported glTF compression extensions are: + +| Compression | glTF extension | +| --- | --- | +| Draco | `KHR_draco_mesh_compression` | +| Meshopt | `EXT_meshopt_compression` and `KHR_meshopt_compression` | + +Export or optimize your glTF 2.0 asset using one of these extensions, then import it using the same steps as an uncompressed model. Include any external buffers and textures and preserve their relative paths. Assign the imported file to a Model component's *Scene* property as usual. + +Defold decodes the compressed geometry during import and build. The resulting model uses Defold's normal runtime geometry representation. This support does not enable Draco or Meshopt compression in the running engine, and a smaller source file does not guarantee a smaller game bundle. + +### Browsing the imported scene + +Expand a *.gltf* or *.glb* file in the *Assets* pane to browse its meshes, generated materials and embedded images. Opening the scene previews it with its defined materials and textures. You can also open an individual mesh for a preview. + +The resources exposed inside the file are read-only. To create an editable Model resource for a mesh, copy the mesh and paste it into a project folder. The resulting *.model* file still references the imported glTF or GLB file. To change the source geometry or embedded images, edit the asset in your authoring tool and export it again. + +Editor scripts can enumerate these resources with `editor.resource_children(path)`. See [Traversing project resources](/manuals/editor-scripts/#traversing-project-resources) for an example that recursively visits resources inside folders and glTF/GLB files. + +### KTX2 textures + +Model textures can use *.ktx2* sources, either as external files or as images embedded in a *.gltf* or *.glb* file. Import external files alongside the model. Embedded KTX2 images appear under the scene in the *Assets* pane and can be assigned directly to material texture fields or through Auto Fill. + +[Texture profiles](/manuals/texture-profiles/#ktx2-source-textures) determine whether to keep the KTX2 source format or convert it to the configured output formats. **Keep KTX2 Format** preserves the source encoding format when texture compression is enabled, but image processing can still require re-encoding. Check the format's support on your target devices and account for possible additional quality loss when recompressing an already compressed texture. See [KTX2 input formats and previews](/manuals/importing-graphics/#ktx2-textures). + ## Using a model Once you have imported the model, use it in a [Model component](/manuals/model): 1. Create a Model file from the *Assets* pane with New... ▸ Model, or add a Model component directly to a game object with Add Component ▸ Model. -2. Set the *Scene* property to the imported *.gltf* or *.glb* file. Leave *Mesh* empty to use the whole scene, or select a named mesh to use only its local geometry. -3. For an animated model, set the *Skeleton* property to the *.gltf* or *.glb* file containing the skeleton. This is often the same file used for *Scene* when mesh, skeleton and animations are exported together. -4. Create an *Animation Set* file for the animations and assign it to the *Animations* property. Set *Default Animation* if you want an animation to start automatically. -5. Set the *Material* property to a material suitable for the model. The built-in *model.material*, *model_instanced.material*, *model_skinned.material* and *model_skinned_instanced.material* files are useful starting points. The skinned materials use local vertex space so skinning can run on the GPU; custom materials for GPU-skinned or instanced models should also use local vertex space. See the [Model manual](/manuals/model/#material) for the graphics-adapter requirement. -6. Set the material texture properties, such as *Texture*, to the imported texture image files. If the material uses multiple textures, assign each texture in the corresponding material texture field. +2. Set the *Scene* property to the imported *.gltf* or *.glb* file. +3. When the *Auto Fill Model Fields?* dialog appears, choose Auto Fill to assign the scene's generated materials and referenced textures. This replaces existing material and texture bindings. Choose Keep Current to preserve your bindings; the new scene selection still takes effect. +4. Leave *Mesh* empty to use the whole scene, or select a named mesh to use only its local geometry. Changing the mesh selection can show the same dialog: selecting a mesh offers its materials, while clearing the selection offers all materials in the scene. Keep Current preserves bindings while applying the new mesh selection. +5. For an animated model, set the *Skeleton* property to the *.gltf* or *.glb* file containing the skeleton. This is often the same file used for *Scene* when mesh, skeleton and animations are exported together. +6. Create an *Animation Set* file for the animations and assign it to the *Animations* property. Set *Default Animation* if you want an animation to start automatically. + +The editor offers to fill bindings when the selected glTF or GLB source exposes materials. It resolves both embedded images and external image references. The generated materials use the built-in glTF shaders; see the [PBR manual](/manuals/physically-based-rendering/#built-in-pbr-materials) for lighting and supported material effects. + +### Assigning materials and textures manually + +If you choose Keep Current, or need custom shading, set each *Material* property to a suitable material. The built-in `gltf` materials provide PBR shading; the built-in `model` materials and your own materials are also available. See the [Model manual](/manuals/model/#material) for the static, skinned and instanced variants and their requirements. + +Assign each texture to the corresponding material texture field. You can use an embedded image exposed under the glTF or GLB file in the *Assets* pane, or a separate image asset in the project. For materials with multiple samplers, match each texture to its intended sampler; the [PBR manual lists the built-in glTF sampler names](/manuals/physically-based-rendering/#built-in-pbr-materials). ## Exporting to glTF @@ -57,13 +90,13 @@ Defold imposes some limitations on exported animation data: * Animations are also linearly interpolated. If you do more advanced curve interpolation the animations needs to be prebaked from the exporter. ### Requirements -When you export a model, keep in mind that glTF support can differ between tools and engines. Use glTF 2.0, make sure the model has correct UV coordinates if it uses textures, and import texture images separately when they should be assigned to a Model component. +When you export a model, keep in mind that glTF support can differ between tools and engines. Use glTF 2.0 and make sure the model has correct UV coordinates if it uses textures. Images can be embedded in the glTF or GLB file, or stored in separate files referenced by the scene. Include all external image and buffer files when importing the model into Defold. While our ambition is to fully support the glTF format, we're not fully there yet. If a feature is missing, please make a feature request for it in [our repo](https://github.com/defold/defold/issues) ### Exporting a texture -If you do not already have a texture for your model you can use Blender to generate a texture. You should do this before you remove extra materials from the model. Start by selecting the mesh and all of its vertices: +If you want to create a texture image manually, you can export the UV layout from Blender as a template. Start by selecting the mesh and all of its vertices: ![Select all](images/model/blender_select_all_vertices.png) diff --git a/docs/en/manuals/input-gamepads.md b/docs/en/manuals/input-gamepads.md index f588048f..2a7faf3c 100644 --- a/docs/en/manuals/input-gamepads.md +++ b/docs/en/manuals/input-gamepads.md @@ -104,11 +104,23 @@ end ``` ## Gamepads settings file -Gamepad input setup uses a separate mapping file for each hardware gamepad type. Gamepad mappings for specific hardware gamepads are set in a *gamepads* file. Defold ships with a built-in gamepads file with settings for common gamepads: + +Gamepad mappings translate a controller's buttons, axes and hats into the standard controls used by your input bindings. Defold combines two mapping sources configured in the *Input* section of *game.project*: + +| Setting | Mapping format | Default | +| --- | --- | --- | +| [Gamepad Database](/manuals/project-settings/#gamepad-database) | SDL-format text database, matched using the controller's GUID | `/builtins/input/gamecontrollerdb.txt` | +| [Gamepads](/manuals/project-settings/#gamepads) | Legacy `.gamepads` entries for device names and platforms | `/builtins/input/default.gamepads` | + +SDL database mappings and automatic platform mappings use [Gamepad Deadzone](/manuals/project-settings/#gamepad-deadzone). Legacy `.gamepads` entries define their own dead zones. On Android, a controller without a database entry may also receive an [automatic mapping](#gamepads-on-android). + +### Legacy .gamepads mappings + +A `.gamepads` file can contain mappings for multiple controllers. Existing legacy mappings remain supported. Defold includes mappings for common controllers in the default file: ![Gamepad settings](images/input/gamepads.png) -If you need to create a new gamepad settings file, we have a simple tool to help: +If you need to create a legacy `.gamepads` mapping on a desktop platform, the following tool can help. For Android, see [Gamepads on Android](#gamepads-on-android). [Click to download gdc.zip](https://forum.defold.com/t/big-thread-of-gamepad-testing/56032). @@ -124,7 +136,7 @@ The tool will ask you to press different buttons on your connected controller. I ### Unidentified gamepads -When a gamepad is connected and no mapping exists for the gamepad the gamepad will only generate `connected`, `disconnected` and `raw` actions. In this case you need to manually map the raw gamepad data to actions in your game. +When neither a configured mapping nor an automatic platform mapping is available, the gamepad only generates the actions bound to `Connected`, `Disconnected` and `Raw`. You can add a controller mapping or handle its raw input in your game. It is possible to check if an input action for a gamepad is from an unknown gamepad or not by reading the `gamepad_unknown` value from the `action`: @@ -138,7 +150,7 @@ function on_input(self, action_id, action) end end end -``` +``` ## Gamepads in HTML5 Gamepads are supported in HTML5 builds and generate the same input events as on other platforms. Support for gamepads is based on the [Gamepad API](https://www.w3.org/TR/gamepad/) which is supported in most browsers ([refer to this support chart](https://caniuse.com/?search=gamepad)). If the browser doesn't support the Gamepad API Defold will silently ignore any Gamepad triggers in your project. You can check if the browser supports the Gamepad API by checking if the `getGamepads` function exists on the `navigator` object: @@ -168,62 +180,6 @@ On Windows, only XBox 360 controllers are currently supported. To hook up your 3 ## Gamepads on Android -Gamepads are supported in Android builds and generate the same input events as on other platforms. Support for gamepads is based on the [Android input system for key and motion events](https://developer.android.com/training/game-controllers/controller-input). The Android input events will be translated to Defold gamepad events using the same *gamepad* file as described above. - -When adding additional gamepad bindings on Android you can use the following lookup tables to translate from the Android input events to *gamepad* file values: - -| Key event to button index | Index | -|-----------------------------|-------| -| `AKEYCODE_BUTTON_A` | 0 | -| `AKEYCODE_BUTTON_B` | 1 | -| `AKEYCODE_BUTTON_C` | 2 | -| `AKEYCODE_BUTTON_X` | 3 | -| `AKEYCODE_BUTTON_L1` | 4 | -| `AKEYCODE_BUTTON_R1` | 5 | -| `AKEYCODE_BUTTON_Y` | 6 | -| `AKEYCODE_BUTTON_Z` | 7 | -| `AKEYCODE_BUTTON_L2` | 8 | -| `AKEYCODE_BUTTON_R2` | 9 | -| `AKEYCODE_DPAD_CENTER` | 10 | -| `AKEYCODE_DPAD_DOWN` | 11 | -| `AKEYCODE_DPAD_LEFT` | 12 | -| `AKEYCODE_DPAD_RIGHT` | 13 | -| `AKEYCODE_DPAD_UP` | 14 | -| `AKEYCODE_BUTTON_START` | 15 | -| `AKEYCODE_BUTTON_SELECT` | 16 | -| `AKEYCODE_BUTTON_THUMBL` | 17 | -| `AKEYCODE_BUTTON_THUMBR` | 18 | -| `AKEYCODE_BUTTON_MODE` | 19 | -| `AKEYCODE_BUTTON_1` | 20 | -| `AKEYCODE_BUTTON_2` | 21 | -| `AKEYCODE_BUTTON_3` | 22 | -| `AKEYCODE_BUTTON_4` | 23 | -| `AKEYCODE_BUTTON_5` | 24 | -| `AKEYCODE_BUTTON_6` | 25 | -| `AKEYCODE_BUTTON_7` | 26 | -| `AKEYCODE_BUTTON_8` | 27 | -| `AKEYCODE_BUTTON_9` | 28 | -| `AKEYCODE_BUTTON_10` | 29 | -| `AKEYCODE_BUTTON_11` | 30 | -| `AKEYCODE_BUTTON_12` | 31 | -| `AKEYCODE_BUTTON_13` | 32 | -| `AKEYCODE_BUTTON_14` | 33 | -| `AKEYCODE_BUTTON_15` | 34 | -| `AKEYCODE_BUTTON_16` | 35 | - -([Android `KeyEvent` definitions](https://developer.android.com/ndk/reference/group/input#group___input_1gafccd240f973cf154952fb917c9209719)) - -| Motion event to axis index | Index | -|-----------------------------|-------| -| `AMOTION_EVENT_AXIS_X` | 0 | -| `AMOTION_EVENT_AXIS_Y` | 1 | -| `AMOTION_EVENT_AXIS_Z` | 2 | -| `AMOTION_EVENT_AXIS_RZ` | 3 | -| `AMOTION_EVENT_AXIS_LTRIGGER` | 4 | -| `AMOTION_EVENT_AXIS_RTRIGGER` | 5 | -| `AMOTION_EVENT_AXIS_HAT_X` | 6 | -| `AMOTION_EVENT_AXIS_HAT_Y` | 7 | - -([Android `MotionEvent` definitions](https://developer.android.com/ndk/reference/group/input#group___input_1ga157d5577a5b2f5986037d0d09c7dc77d)) - -Use this lookup table in combination with a gamepad test app from the Google Play Store to figure out which key event each button on your gamepad is mapped to. +Gamepads are supported in Android builds and generate the same input actions as on other platforms. Defold uses the configured [gamepad mappings](#gamepads-settings-file) and can automatically map some controllers that have no matching entry. + +If a controller is unidentified or its controls are incorrect, test it on the Android device and add or update its mapping. See [Unidentified gamepads](#unidentified-gamepads) and [Raw gamepads](#raw-gamepads) for troubleshooting. diff --git a/docs/en/manuals/input-mouse-and-touch.md b/docs/en/manuals/input-mouse-and-touch.md index 950ba40d..4d6b7b98 100644 --- a/docs/en/manuals/input-mouse-and-touch.md +++ b/docs/en/manuals/input-mouse-and-touch.md @@ -39,6 +39,30 @@ end `MOUSE_BUTTON_LEFT` (or `MOUSE_BUTTON_1`) input actions are sent for single touch inputs as well. ::: +### Distinguishing mouse clicks from touch + +`action.source` distinguishes a physical mouse press from a click simulated by touch, including the initial press. Bind `MOUSE_BUTTON_LEFT` to `mouse_button_left` and use this code in a script or GUI script: + +```lua +function init(self) + msg.post(".", "acquire_input_focus") +end + +function on_input(self, action_id, action) + if action_id == hash("mouse_button_left") and action.pressed then + if action.source == hash("mouse") then + print("Mouse pressed at:", action.x, action.y) + elseif action.source == hash("touch") then + print("Touch pressed at:", action.x, action.y) + end + end +end +``` + +A touch simulated as a mouse click reports `hash("touch")` even without a separate Touch Trigger. You do not need an `action.touch` table or a previous movement event to identify the tap. See [Input device source](/manuals/input/#input-device-source) for all source values and how sources work when several bindings share an action name. + +On iOS, a custom `Info.plist` must enable `UIApplicationSupportsIndirectInputEvents` for this distinction to work. The built-in manifest already enables it. + ## Mouse wheel Mouse wheel inputs detect scroll actions. The field `action.value` is `1` if the wheel is scrolled and `0` otherwise. (Scroll actions are dealt with as they were button presses. Defold does not currently support fine grained scroll input on touch pads.) @@ -55,11 +79,12 @@ end ## Mouse movement Mouse movement is handled separately. Mouse movement events are not received unless at least one mouse trigger is set up in your input bindings. -Mouse movement are not bound in the input bindings but `action_id` is set to `nil` and the `action` table is populated with the location and delta movement of the mouse position. +Pointer movement is not bound to an action name: `action_id` is `nil` and the `action` table contains the pointer's position and movement delta. Its source is `hash("mouse")` for a physical mouse or `hash("touch")` for movement simulated from touch. Accelerometer samples also use `action_id == nil`, so check the source to distinguish them, as shown in [Input device source](/manuals/input/#input-device-source). ```lua function on_input(self, action_id, action) - if action.x and action.y then + if action_id == nil and + (action.source == hash("mouse") or action.source == hash("touch")) then -- let game object follow mouse/touch movement local pos = vmath.vector3(action.x, action.y, 0) go.set_position(pos) diff --git a/docs/en/manuals/input.md b/docs/en/manuals/input.md index 16ce71da..f2813167 100644 --- a/docs/en/manuals/input.md +++ b/docs/en/manuals/input.md @@ -17,7 +17,7 @@ Devices 1. Keyboard (single key as well as text input) 2. Mouse (position, button clicks and mouse wheel actions) 3. Single and multi-touch (on iOS and Android devices and HTML5 on mobile) - 4. Gamepads (as supported through the operating system and mapped in the [gamepads](/manuals/input-gamepads/#gamepads-settings-file) file) + 4. Gamepads (using [controller mappings and platform support](/manuals/input-gamepads/#gamepads-settings-file)) Input bindings : Before input is sent to a script the raw input from the device is translated into meaningful *actions* via the input bindings table. @@ -111,7 +111,7 @@ Any component that is on the stack containing an `on_input()` function will have : The current script instance. `action_id` -: The hashed name of the action, as set up in the input bindings. +: The hashed name of the action, as set up in the input bindings, or `nil` for pointer movement and accelerometer samples. Use `action.source` to distinguish these unnamed actions. `action` : A table containing the useful data about the action, like the value of the input, its location (absolute and delta positions), whether button input was `pressed` etc. See [on_input()](/ref/go#on_input) for details on the available action fields. @@ -132,6 +132,43 @@ function on_input(self, action_id, action) end ``` +### Input device source + +`action.source` identifies the input device category independently of the action name. It is available in both script and GUI script `on_input()` callbacks and is one of these hashes: + +| `action.source` | Input category | +|-----------------|----------------| +| `hash("keyboard")` | Individual key input from Key Triggers. | +| `hash("text")` | Text and marked-text input from Text Triggers, including text entered with a physical keyboard. | +| `hash("mouse")` | Physical mouse buttons, wheel input and pointer movement. | +| `hash("touch")` | Touch input, including mouse clicks and pointer movement simulated from touch. | +| `hash("gamepad")` | Gamepad input, including raw input and connection events. | +| `hash("accelerometer")` | Accelerometer samples. | + +Compare `action.source` with a hash, such as `hash("touch")`, rather than a string. For example, a left mouse button action can come from either a physical mouse or a tap. The source distinguishes them even on the initial press; see [Distinguishing mouse clicks from touch](/manuals/input-mouse-and-touch/#distinguishing-mouse-clicks-from-touch). + +When several devices share a named action, their contributions can be combined. Sources are processed in this order: keyboard, text, mouse, then touch; the last source contributing to the action is reported. Key and mouse button releases keep the previous source unless another input contributes in the same frame. Gamepad actions remain separate per controller. Use separate action names when you need to handle each binding independently. + +Pointer movement and accelerometer samples have no action name, so both use `action_id == nil`. They arrive in separate callbacks: pointer movement has coordinates and a mouse or touch source, while accelerometer samples have `acc_x`, `acc_y` and `acc_z` and an accelerometer source. If both occur in a frame, each callback can be consumed independently. Accelerometer samples are delivered even if their values have not changed. + +The following example handles these unnamed actions. Set up at least one Mouse Trigger to receive pointer movement, and enable [Use Accelerometer](/manuals/project-settings/#use-accelerometer) on a supported device to receive accelerometer samples: + +```lua +function init(self) + msg.post(".", "acquire_input_focus") +end + +function on_input(self, action_id, action) + if action_id == nil then + if action.source == hash("mouse") or action.source == hash("touch") then + print("Pointer position:", action.x, action.y) + elseif action.source == hash("accelerometer") then + print("Acceleration:", action.acc_x, action.acc_y, action.acc_z) + end + end +end +``` + ### Input focus and collection proxy components diff --git a/docs/en/manuals/ios.md b/docs/en/manuals/ios.md index 12186c73..89e2a35d 100644 --- a/docs/en/manuals/ios.md +++ b/docs/en/manuals/ios.md @@ -103,6 +103,23 @@ Press *Create Bundle* and you will then be prompted to specify where on your com You specify what icon to use for the app, the launch screen storyboard and so forth in the *game.project* project settings file in the [iOS section](/manuals/project-settings/#ios). +### Home Indicator behavior + +You can choose *Home Indicator Mode* in the *iOS* section of *game.project*. The default, *Deferred*, protects all screen edges and requires two swipes to return Home. Choose *System* to use normal system gestures, including a single swipe to return Home. + +Choose *Auto Hide* to use normal system gestures and also request automatic hiding of the Home Indicator. You can set this mode directly in *game.project*: + +```ini +[ios] +home_indicator_mode = auto_hide +``` + +Rebundle and test on a device with a Home Indicator. iOS decides when the indicator is visible; choosing *Auto Hide* does not guarantee that it stays hidden. On iOS 26 and later, the system may hide it in both *System* and *Auto Hide* modes. See [Home Indicator Mode](/manuals/project-settings/#home-indicator-mode) for all values and their gesture behavior. + +### Reserved areas and rotation + +`window.get_reserved_areas()` reports camera cutouts and the Dynamic Island on iOS 27.1 and later, including UIKit's interaction margins. iOS orientation transitions also send `window.WINDOW_EVENT_RESIZED`, including rotations that leave the window dimensions and safe-area insets unchanged. Refresh any UI placement based on these areas on every resize callback. See [Reserved screen areas](/manuals/porting-guidelines/#reserved-screen-areas) for coordinates, limitations and a refresh example. + ### Custom Info.plist and local target discovery The built-in iOS `Info.plist` contains the Bonjour service and local-network usage description required for automatic Editor target discovery in non-release builds. A custom `Info.plist` replaces that built-in base manifest. If a custom manifest is used for a debug build and you need target discovery, profiling, hot reload, or log streaming over the local network, include these entries: diff --git a/docs/en/manuals/label.md b/docs/en/manuals/label.md index 6c358730..48251c9c 100644 --- a/docs/en/manuals/label.md +++ b/docs/en/manuals/label.md @@ -21,6 +21,30 @@ Set the *Font* property to the font you want to use and make sure to set the *Ma ![Font and material](images/label/font_material.png) +## Vector fonts and color emoji + +To use a Vector font, follow the [Vector font setup](/manuals/font/#vector-fonts), assign the `.font` resource to the Label's *Font* property, and set the Label's *Material* to `/builtins/fonts/label-vector.material`. Use *Font Size* to control the displayed size. + +For color emoji, also complete the [COLRv1 fallback and bundling setup](/manuals/font/#color-emoji). The example below assumes a Label with the id `label` and a script on the same game object. Leave the Label's *Text* empty to display the greeting only after its glyphs are ready: + +```lua +function init(self) + local text = "Hello 😀 🍎 🚀" + local font_resource = go.get("#label", "font") + -- Add the fallback once for this shared font resource. + font.add_font(font_resource, "/fonts/NotoColorEmoji-Regular.ttf") + font.prewarm_text(font_resource, text, function(self, request_id, result, err) + if result then + go.set("#label", "text", text) + else + print("Could not prepare label text:", err) + end + end) +end +``` + +The ordinary letters use the original font, and the emoji use the added color font. If other Labels or GUI text nodes share this font resource, initialize the fallback in one place and reuse it. + ## Label properties Apart from the properties *Id*, *Position*, *Rotation* and *Scale* the following component specific properties exist: @@ -63,7 +87,7 @@ Note that the default material has shadow rendering disabled for performance rea : The font resource to use for this label. *Material* -: The material to use for rendering this label. Make sure to select a material that is created for the font type that you use (bitmap, distance field or BMFont). +: The material to use for rendering this label. Select a material that matches the font's mode or source (Bitmap, SDF, Vector or BMFont). See [Font materials](/manuals/font/#font-materials) for the matching built-in Label materials. ### Blend modes :[blend-modes](../shared/blend-modes.md) @@ -88,7 +112,7 @@ By setting the *Pivot* property you can change the alignment mode for the text. You can manipulate labels in runtime by getting and setting the label text as well as the various other properties. `text` -: The text content of the label (`string`). Available through `go.get()` and `go.set()` since Defold 1.13.2. +: The text content of the label (`string`). Available through `go.get()` and `go.set()`. `color` : The label color (`vector4`) @@ -116,7 +140,7 @@ end ``` ::: sidenote -Since Defold 1.13.2, `label.set_text()` and `label.get_text()` are deprecated in favor of the `text` property. The old functions remain available for compatibility. The old setter queues a message, while `go.set()` updates the text immediately. +`label.set_text()` and `label.get_text()` are deprecated in favor of the `text` property. The old functions remain available for compatibility. The old setter queues a message, while `go.set()` updates the text immediately. ::: ```lua diff --git a/docs/en/manuals/material.md b/docs/en/manuals/material.md index 8b69de5e..57cbbc81 100644 --- a/docs/en/manuals/material.md +++ b/docs/en/manuals/material.md @@ -156,7 +156,7 @@ go.set("#sprite", "sprite_position_2d", vmath.vector4(my_x,my_y,0,0)) go.animate("#sprite", "sprite_position_2d", go.PLAYBACK_LOOP_PINGPONG, vmath.vector4(1,2,0,0), go.EASING_LINEAR, 2) ``` -Since Defold 1.14.0, `Mat2`, `Mat3` and `Mat4` attributes all use `vmath.matrix4` values with `go.set()` and `go.get()`. Setting a `Mat2` or `Mat3` attribute takes the upper-left 2×2 or 3×3 part of the matrix. Reading it returns a `vmath.matrix4` with the unused rows and columns filled from an identity matrix. +`Mat2`, `Mat3` and `Mat4` attributes all use `vmath.matrix4` values with `go.set()` and `go.get()`. Setting a `Mat2` or `Mat3` attribute takes the upper-left 2×2 or 3×3 part of the matrix. Reading it returns a `vmath.matrix4` with the unused rows and columns filled from an identity matrix. For example, with a `Mat2` attribute named `custom_mat2` and semantic type `None` in a model's material: diff --git a/docs/en/manuals/model.md b/docs/en/manuals/model.md index 6d792d4e..7ee0187b 100644 --- a/docs/en/manuals/model.md +++ b/docs/en/manuals/model.md @@ -23,10 +23,10 @@ With the model created you need to specify a number of properties: Apart from the properties *Id*, *Position* and *Rotation* the following component specific properties exist: *Scene* -: The glTF *.gltf* or *.glb* file that contains the model's geometry. If the file contains morph targets, they are imported together with the scene. This property was named *Mesh* before Defold 1.13.2. +: The glTF *.gltf* or *.glb* file that contains the model's geometry. If the file contains morph targets, they are imported together with the scene. This property was previously named *Mesh*. *Mesh* -: An optional named mesh from the selected *Scene*, available since Defold 1.13.2. Leave this field empty to render the whole scene with its imported transforms. Select a mesh to render that mesh once in its local coordinates, without the glTF node transforms. Position, rotate and scale the model component or its game object to place the selected mesh. +: An optional named mesh from the selected *Scene*. Leave this field empty to render the whole scene with its imported transforms. Select a mesh to render that mesh once in its local coordinates, without the glTF node transforms. Position, rotate and scale the model component or its game object to place the selected mesh. *Create GO Bones* : Check this to create a game object for every bone of the model. You can use the game objects to attach other game objects such as weapons to hand bones and so on. @@ -43,17 +43,14 @@ Apart from the properties *Id*, *Position* and *Rotation* the following componen In addition to the properties above there will also be a field to assign a material for every mesh of the model: *Material* -: Set this property to a material you have created that is suitable for a textured 3D object. There are a number of built-in materials that you can use as a starting point: - - * Use *model.material* for static non-instanced models - * Use *model_instanced.material* for static instanced models - * Use *model_skinned.material* for skinned (animated) non-instanced models - * Use *model_skinned_instanced.material* for skinned (animated) instanced models +: Set this property to a material suitable for the model. Use a built-in `gltf` material for physically based rendering of glTF material properties, a built-in `model` material for general model shading, or your own custom material. See the [material variants below](#material) and the [PBR manual](/manuals/physically-based-rendering/#built-in-pbr-materials). Depending on the material there will be one or more texture properties: *Texture* -: This property should point to the texture image file that you want applied to the object. +: This property should point to the texture image that you want applied to the object. It can be a separate project asset or an embedded image exposed under a glTF or GLB file in the *Assets* pane. + +Selecting a glTF or GLB *Scene*, or changing its *Mesh* selection, can offer to fill the material and texture bindings. Auto Fill replaces existing bindings with those from the source; Keep Current preserves your bindings while applying the new scene or mesh selection. See the [model import workflow](/manuals/importing-models/#using-a-model). ## Editor manipulation @@ -110,14 +107,18 @@ A model also has a number of different properties that can be manipulated using 3D software commonly allows you to set properties on your object vertices, like coloring and texturing. This information goes into the glTF *.gltf* or *.glb* file that you export from your 3D software. Depending on the requirements of your game you will have to select and/or create appropriate and _performant_ materials for your objects. A material combines _shader programs_ with a set of parameters for rendering of the object. -There are a number of built-in materials that you can use as a starting point: +The following built-in materials are available in `/builtins/materials/`: + +| Model type | General model shading | glTF PBR shading | +|---|---|---| +| Static, non-instanced | `model.material` | `gltf.material` | +| Static, instanced | `model_instanced.material` | `gltf_instanced.material` | +| Skinned (animated), non-instanced | `model_skinned.material` | `gltf_skinned.material` | +| Skinned (animated), instanced | `model_skinned_instanced.material` | `gltf_skinned_instanced.material` | - * Use *model.material* for static non-instanced models - * Use *model_instanced.material* for static instanced models - * Use *model_skinned.material* for skinned (animated) non-instanced models - * Use *model_skinned_instanced.material* for skinned (animated) instanced models +The `gltf` materials provide built-in metallic/roughness lighting using the imported glTF material data. See the [PBR manual](/manuals/physically-based-rendering/#built-in-pbr-materials) for texture bindings, lights and custom shaders. -The built-in model materials use local vertex space. For skinned models, local vertex space allows the vertex shader to perform skinning on the GPU using a bone-matrix texture; local vertex space is also required for model instancing. A custom material intended for GPU-skinned or instanced models should therefore use the *Local* vertex-space setting. +All of these built-in materials use local vertex space. For skinned models, local vertex space allows the vertex shader to perform skinning on the GPU using a bone-matrix texture; local vertex space is also required for model instancing. A custom material intended for GPU-skinned or instanced models should therefore use the *Local* vertex-space setting. The bone-matrix cache uses an `RGBA32F` texture. If the active graphics adapter does not support that texture format, Defold cannot create an animated Model component that uses a local-space material. On OpenGL ES 2.0 and WebGL 1.0, support therefore depends on the adapter's floating-point texture extension. For compatibility with an adapter that lacks it, use a custom world-space material, which uses CPU skinning and cannot use model instancing. The cache dimensions can be adjusted with the [Model project settings](/manuals/project-settings/#model). @@ -134,7 +135,7 @@ If you need to create custom materials for your models, see the [Material docume ## Rendering -The default render script is tailor made for 2D games and does not work with 3D models. But by copying the default render script and adding a handful of lines of code to the render script you can enable rendering of your models. For instance: +The default render script draws materials with the `model` tag, including the built-in model and glTF materials. To render them in a custom render script, create a matching predicate and draw it with a view and projection suitable for your scene. For instance: ```lua diff --git a/docs/en/manuals/optimization-size.md b/docs/en/manuals/optimization-size.md index 30ab2a03..9a5e6752 100644 --- a/docs/en/manuals/optimization-size.md +++ b/docs/en/manuals/optimization-size.md @@ -94,7 +94,7 @@ Excluded content can be anything from entire levels to unlockable characters, sk ## Android specific size optimizations -Enable [R8 shrinking](/manuals/android/#shrinking-java-code-with-r8) to remove unused Java code. With Defold 1.14.0 or later and a compatible Extender server, this also removes unused Android resources from extensions and their dependencies. +Enable [R8 shrinking](/manuals/android/#shrinking-java-code-with-r8) to remove unused Java code. With a compatible Extender server, this also removes unused Android resources from extensions and their dependencies. Android builds must support both 32-bit and 64-bit CPU architectures. When you [bundle for Android](/manuals/android) you can specify which CPU architectures to include: diff --git a/docs/en/manuals/physically-based-rendering.md b/docs/en/manuals/physically-based-rendering.md index 3930a42a..9d4aa9d5 100644 --- a/docs/en/manuals/physically-based-rendering.md +++ b/docs/en/manuals/physically-based-rendering.md @@ -1,30 +1,58 @@ --- title: Physically based rendering in Defold -brief: This manual explains the basics of how to access material data for physically based rendering in Defold. +brief: This manual explains how to use built-in PBR materials and customize physically based shading in Defold. --- # Physically Based Rendering (PBR) -Physically Based Rendering (PBR) is a shading approach that models how light interacts with surfaces using real-world physical principles. It produces consistent, realistic lighting across different environments and allows assets to look correct under a wide range of lighting conditions. +Physically Based Rendering (PBR) is a shading approach that models how light interacts with surfaces using physical principles. Material properties such as base color, metallic factor and roughness describe the surface independently of the scene's lighting. -Defold’s PBR implementation follows the glTF 2.0 material specification and associated Khronos extensions. When you import glTF assets into Defold, material properties are automatically parsed and stored as structured material data that can be accessed in shaders at runtime. +Built-in glTF materials provide PBR lighting. Defold also exposes imported glTF 2.0 material properties and supported Khronos extension data to custom shaders. -PBR materials can include effects such as metallic reflections, surface roughness, transmission, clearcoat, subsurface scattering, iridescence, and more. +## Built-in PBR materials -::: sidenote -Defold currently exposes PBR material data to shaders, but does not provide a built-in PBR lighting model. You can use this data in your own lighting and reflection shaders to achieve physically based rendering. A default PBR lighting model will be added to Defold at a later stage. -::: +Assign a glTF or GLB file to the *Scene* property of a [Model component](/manuals/model). When the editor offers to fill in materials and textures, choose Auto Fill to apply the scene's generated material bindings, replacing existing bindings if present. These materials use the built-in glTF shaders and can reference embedded images directly. Choose Keep Current to preserve your bindings and assign materials and textures manually. See the [model import workflow](/manuals/importing-models/#using-a-model) for browsing embedded resources and selecting individual meshes. -::: sidenote -Embedded textures from glTF files are currently not automatically assigned in Defold. Only material parameters are exposed to shaders. You can still manually assign textures to model components and sample them in your shader. -::: +The following materials are available in `/builtins/materials/`. Choose the variant that matches your model and whether it uses instancing: + +| Model type | Material | +|---|---| +| Static, non-instanced | `gltf.material` | +| Static, instanced | `gltf_instanced.material` | +| Skinned (animated), non-instanced | `gltf_skinned.material` | +| Skinned (animated), instanced | `gltf_skinned_instanced.material` | + +All four use local vertex space and the same `gltf.fp` fragment shader. The skinned variants perform skinning on the GPU. See the [model material requirements](/manuals/model/#material) for GPU skinning and instancing. + +For manual texture bindings, the built-in materials use these sampler names: + +| Texture | Sampler | Data used | +|---|---|---| +| Base color | `PbrMetallicRoughness_baseColorTexture` | RGB color and alpha | +| Metallic/roughness | `PbrMetallicRoughness_metallicRoughnessTexture` | Roughness in G, metallic in B | +| Normal | `PbrMaterial_normalTexture` | Tangent-space normal in RGB | +| Occlusion | `PbrMaterial_occlusionTexture` | Occlusion in R | +| Emissive | `PbrMaterial_emissiveTexture` | RGB color | + +Set up a [camera](/manuals/camera/#using-the-camera) and add [light components](/manuals/light) to illuminate the model. The shader uses directional, point and spot lights for direct lighting, plus ambient lights for a simple ambient contribution. The materials have the `model` tag, which the default render script draws. A custom render script must draw a matching predicate. + +### Built-in shader behavior + +The built-in shaders implement metallic/roughness shading, base color and vertex color, normal mapping when tangent data is available, occlusion, and emission including emissive strength. Base-color and emissive textures are decoded from sRGB for lighting, and the final color is converted back to sRGB. Metallic/roughness, normal and occlusion maps contain linear data. + +The shader honors unlit materials and masked alpha, and adjusts normals for double-sided surfaces. Render state still matters: + +- For double-sided materials, disable face culling in the relevant render pass so back faces reach the shader. +- For blended alpha, the shader outputs straight alpha. Enable blending with `graphics.BLEND_FACTOR_SRC_ALPHA` and `graphics.BLEND_FACTOR_ONE_MINUS_SRC_ALPHA`, and manage transparent-object draw order and depth writes in your render script. The default model pass does not enable blending automatically. + +The built-in ambient contribution is an approximation, without environment-map lighting or shadows. Effects such as clearcoat, transmission, sheen, iridescence and the specular/glossiness workflow require custom shading; importing their parameters does not enable these effects in `gltf.fp`. ## Material properties overview -The material properties are parsed from the glTF 2.0 source files assigned to a model component. Not all properties are standard. Some are provided through optional glTF extensions that may or may not be included by the tool used to export the glTF file. The relevant extension is denoted in parentheses after the property name below. +The following properties are parsed from glTF 2.0 source files assigned to a model component. This list describes the available material data; the built-in lighting uses the subset described above. Not all properties are standard. Some are provided through optional glTF extensions that may or may not be included by the tool used to export the glTF file. The relevant extension is denoted in parentheses after the property name below. Metallic roughness -: Describes how light interact with the material. The default PBR model. +: Describes how light interacts with the material. The default PBR model. Specular glossiness (KHR_materials_pbrSpecularGlossiness) : An alternative to metallic roughness. Often used in older assets. @@ -72,157 +100,66 @@ Alpha mode : Opaque, Masked, or Blended transparency modes. Double sided -: If true, both sides of the surface are rendered. +: Requests rendering of both sides of the surface. The render pass must allow back faces to reach the shader. Unlit : If true, the material bypasses lighting calculations. -::: sidenote -Some of these properties provides hints on how the material should be rendered. The data for the properties (alpha cutoff, alpha mode, double sided and unlit) is available in the shaders, but does not affect how the material is rendered in Defold. -::: - ## Shader integration -The PBR material data is exposed to the shaders based on types and name convention. The PBR material system provides all parsed material parameters to shaders via a structured uniform block named `PbrMaterial`. Each supported glTF extension corresponds to a struct within this block, which can be conditionally compiled using `#define` flags. - -```glsl -uniform PbrMaterial -{ - // Material properties -}; -``` - -The various features of the material is specified as fixed structs in the shader. Data has been packed as much as possible in `vec4`'s since that is how constants are set internally in Defold. In those cases where data has been packed, it is denoted as comments in the shader snippets for each feature below: +The following sections cover custom shaders. Copy the appropriate built-in `.material` resource and `gltf.fp` into your project, then point the copied material's *Fragment Program* to your shader. Keep the matching glTF vertex program, sampler names and local vertex space unless you are also replacing those interfaces. -```glsl -struct PbrMetallicRoughness -{ - vec4 baseColorFactor; - // R: metallic (Default=1.0), G: roughness (Default=1.0) - vec4 metallicAndRoughnessFactor; - // R: use baseColorTexture, G: use metallicRoughnessTexture - vec4 metallicRoughnessTextures; -}; - -struct PbrSpecularGlossiness -{ - vec4 diffuseFactor; - // RGB: specular (Default=1.0), A: glossiness (Default=1.0) - vec4 specularAndSpecularGlossinessFactor; - // R: use diffuseTexture, G: use specularGlossinessTexture - vec4 specularGlossinessTextures; -}; - -struct PbrClearCoat -{ - // R: clearCoat (Default=0.0), G: clearCoatRoughness (Default=0.0) - vec4 clearCoatAndClearCoatRoughnessFactor; - // R: use clearCoatTexture, G: use clearCoatRoughnessTexture, B: use clearCoatNormalTexture - vec4 clearCoatTextures; -}; - -struct PbrTransmission -{ - // R: transmission (Default=0.0) - vec4 transmissionFactor; - // R: use transmissionTexture - vec4 transmissionTextures; -}; +The built-in helpers separate texture sampling from surface preparation, BRDF calculations and lighting. `gltf_sampling.glsl` reads the raw `PbrMaterial` uniform block and produces a `PBRMaterial` value containing resolved, linear material inputs. `gltf_lighting.glsl` provides direct and ambient lighting and combines their contributions. The capitalization distinguishes the raw uniform block from the sampled material struct. -struct PbrIor -{ - // R: ior (Default=0.0) - vec4 ior; -}; +### Example shader -struct PbrSpecular -{ - // RGB: specularColor, A: specularFactor (Default=1.0); - vec4 specularColorAndSpecularFactor; - // R: use specularTexture, G: use specularColorTexture - vec4 specularTextures; -}; +This fragment shader raises the minimum roughness while retaining the built-in lighting. It works with the vertex programs used by all four glTF material variants: -struct PbrVolume -{ - // R: thicknessFactor (Default=0.0), RGB: attenuationColor - vec4 thicknessFactorAndAttenuationColor; - // R: attentuationDistance (Default=-1.0) - vec4 attenuationDistance; - // R: use thicknessTexture - vec4 volumeTextures; -}; +```glsl +#version 140 -struct PbrSheen -{ - // RGB: sheenColor, A: sheenRoughnessFactor (Default=0.0) - vec4 sheenColorAndRoughnessFactor; - // R: use sheenColorTexture, G: use sheenRoughnessTexture - vec4 sheenTextures; -}; +#include "/builtins/materials/gltf_sampling.glsl" +#include "/builtins/materials/gltf_lighting.glsl" -struct PbrEmissiveStrength -{ - // R: emissiveStrength (Default=1.0) - vec4 emissiveStrength; -}; +out vec4 out_fragColor; -struct PbrIridescence +void main() { - // R: iridescenceFactor (Default=0.0), G: iridescenceIor (Default=1.3), B: iridescenceThicknessMin (Default=100.0), A: iridescenceThicknessMax (Default=400.0) - vec4 iridescenceFactorAndIorAndThicknessMinMax; - // R: use iridescenceTexture, G: use iridescenceThicknessTexture - vec4 iridescenceTextures; -}; + PBRMaterial inputs = pbr_sample_material(var_texcoord0, var_color); + inputs.roughness = max(inputs.roughness, 0.35); + + // Sample textures, including the normal map, before discarding fragments. + PBRSurface surface = pbr_sample_surface(inputs, var_texcoord0); + if ((!inputs.doubleSided && !gl_FrontFacing) || pbr_should_discard_alpha(inputs)) + { + discard; + } + + // Derive BRDF values after editing the material inputs. + MaterialInfo material = pbr_create_material_info(inputs); + PBRLighting lighting = pbr_create_lighting(); + if (!inputs.unlit) + { + lighting.direct = pbr_evaluate_direct_lighting(material, surface, var_view); + lighting.indirect = pbr_evaluate_ambient_lighting(material, ambient_light()); + } + + vec3 color = pbr_compose_lighting(inputs, lighting, inputs.occlusion, inputs.occlusion); + out_fragColor = vec4(pbr_linear_to_srgb(color), pbr_get_alpha(inputs)); +} ``` -The common properties are set on the material uniform itself (and once again, note the data packing into `vec4`). +Edit sampled material inputs before calling `pbr_create_material_info()`. If you change a surface's view-space position or normals, call `pbr_finalize_surface(surface, var_view)` to update its derived world-space fields. For a custom BRDF or individual light contributions, use or replace `pbr_evaluate_brdf()` and `pbr_evaluate_light()` from the built-in helpers. -```glsl -// Common textures -uniform sampler2D PbrMaterial_normalTexture; -uniform sampler2D PbrMaterial_occlusionTexture; -uniform sampler2D PbrMaterial_emissiveTexture; +You can replace `lighting.indirect` with your own environment lighting or global illumination. Its diffuse and specular contributions are linear outgoing light, so do not apply the material's BRDF a second time. Apply shadow visibility to the appropriate direct-light contribution; the visibility arguments to `pbr_compose_lighting()` affect indirect lighting only. For an HDR pipeline, write linear color to the intermediate target and perform the sRGB conversion in the final pass. -uniform PbrMaterial -{ - // Common properties: - - // R: alphaCutoff (Default=0.5), G: doubleSided (Default=false), B: unlit (Default=false) - vec4 pbrAlphaCutoffAndDoubleSidedAndIsUnlit; - // R: use normalTexture, G: use occlusionTexture, B: use emissiveTexture - vec4 pbrCommonTextures; - - // Other properties... -}; -``` +### Raw material data -### Example shader +For a fully custom shader, declare a uniform block named `PbrMaterial` with the recognized member names and types. Defold fills matching fields from the source glTF material. The declarations below describe the available feature structs; include only those your shader needs. Declaring a struct supplies data, but your shader must implement its sampling and lighting behavior. -Here is an example shader that contains all features and a proposed naming scheme for texture bindings (again, this must be handled manually). Note that you can turn off features simply by using `#define`s around each member of the `PbrMaterial` itself, as shown in the example below: +Do not redeclare the uniform block or `PbrMetallicRoughness` when including `gltf_sampling.glsl`, which already declares them. The following declarations are an alternative for shaders that manage their own material inputs. ```glsl -// Feature flags, comment or remove these to slim down the shader. -#define PBR_METALLIC_ROUGHNESS -#define PBR_SPECULAR_GLOSSINESS -#define PBR_CLEARCOAT -#define PBR_TRANSMISSION -#define PBR_IOR -#define PBR_SPECULAR -#define PBR_VOLUME -#define PBR_SHEEN -#define PBR_EMISSIVE_STRENGTH -#define PBR_IRIDESCENCE - -// Common -uniform sampler2D PbrMaterial_normalTexture; -uniform sampler2D PbrMaterial_occlusionTexture; -uniform sampler2D PbrMaterial_emissiveTexture; - -// PbrMetallicRoughness -uniform sampler2D PbrMetallicRoughness_baseColorTexture; -uniform sampler2D PbrMetallicRoughness_metallicRoughnessTexture; - struct PbrMetallicRoughness { vec4 baseColorFactor; @@ -232,161 +169,122 @@ struct PbrMetallicRoughness vec4 metallicRoughnessTextures; }; -// PbrSpecularGlossiness -uniform sampler2D PbrSpecularGlossiness_diffuseTexture; -uniform sampler2D PbrSpecularGlossiness_specularGlossinessTexture; - struct PbrSpecularGlossiness { - vec4 diffuseFactor; - // RGB: specular (Default=1.0), A: glossiness (Default=1.0) - vec4 specularAndSpecularGlossinessFactor; - // R: use diffuseTexture, G: use specularGlossinessTexture - vec4 specularGlossinessTextures; + vec4 diffuseFactor; + // RGB: specular (Default=1.0), A: glossiness (Default=1.0) + vec4 specularAndSpecularGlossinessFactor; + // R: use diffuseTexture, G: use specularGlossinessTexture + vec4 specularGlossinessTextures; }; -// PbrClearCoat -uniform sampler2D PbrClearCoat_clearcoatTexture; -uniform sampler2D PbrClearCoat_clearcoatRoughnessTexture; -uniform sampler2D PbrClearCoat_clearcoatNormalTexture; - struct PbrClearCoat { - // R: clearCoat (Default=0.0), G: clearCoatRoughness (Default=0.0) - vec4 clearCoatAndClearCoatRoughnessFactor; - // R: use clearCoatTexture, G: use clearCoatRoughnessTexture, B: use clearCoatNormalTexture - vec4 clearCoatTextures; + // R: clearCoat (Default=0.0), G: clearCoatRoughness (Default=0.0) + vec4 clearCoatAndClearCoatRoughnessFactor; + // R: use clearCoatTexture, G: use clearCoatRoughnessTexture, B: use clearCoatNormalTexture + vec4 clearCoatTextures; }; -// PbrTransmission -uniform sampler2D PbrTransmission_transmissionTexture; - struct PbrTransmission { - // R: transmission (Default=0.0) - vec4 transmissionFactor; - // R: use transmissionTexture - vec4 transmissionTextures; + // R: transmission (Default=0.0) + vec4 transmissionFactor; + // R: use transmissionTexture + vec4 transmissionTextures; }; struct PbrIor { - // R: ior (Default=0.0) - vec4 ior; + // R: ior (Default=0.0) + vec4 ior; }; -// PbrSpecular -uniform sampler2D PbrSpecular_specularTexture; -uniform sampler2D PbrSpecular_specularColorTexture; - struct PbrSpecular { - // RGB: specularColor, A: specularFactor (Default=1.0); - vec4 specularColorAndSpecularFactor; - // R: use specularTexture, G: use specularColorTexture - vec4 specularTextures; + // RGB: specularColor, A: specularFactor (Default=1.0); + vec4 specularColorAndSpecularFactor; + // R: use specularTexture, G: use specularColorTexture + vec4 specularTextures; }; -// PbrVolume -uniform sampler2D PbrVolume_thicknessTexture; - struct PbrVolume { - // R: thicknessFactor (Default=0.0), RGB: attenuationColor - vec4 thicknessFactorAndAttenuationColor; - // R: attentuationDistance (Default=-1.0) - vec4 attenuationDistance; - // R: use thicknessTexture - vec4 volumeTextures; + // R: thicknessFactor (Default=0.0), GBA: attenuationColor + vec4 thicknessFactorAndAttenuationColor; + // R: attenuationDistance (Default=-1.0) + vec4 attenuationDistance; + // R: use thicknessTexture + vec4 volumeTextures; }; -// PbrSheen -uniform sampler2D PbrSheen_sheenColorTexture; -uniform sampler2D PbrSheen_sheenRoughnessTexture; - struct PbrSheen { - // RGB: sheenColor, A: sheenRoughnessFactor (Default=0.0) - vec4 sheenColorAndRoughnessFactor; - // R: use sheenColorTexture, G: use sheenRoughnessTexture - vec4 sheenTextures; + // RGB: sheenColor, A: sheenRoughnessFactor (Default=0.0) + vec4 sheenColorAndRoughnessFactor; + // R: use sheenColorTexture, G: use sheenRoughnessTexture + vec4 sheenTextures; }; struct PbrEmissiveStrength { - // R: emissiveStrength (Default=1.0) - vec4 emissiveStrength; + // R: emissiveStrength (Default=1.0) + vec4 emissiveStrength; }; -// PbrIridescence -uniform sampler2D PbrEmissive_iridescenceTexture; -uniform sampler2D PbrEmissive_iridescenceThicknessTexture; - struct PbrIridescence { - // R: iridescenceFactor (Default=0.0), G: iridescenceIor (Default=1.3), B: iridescenceThicknessMin (Default=100.0), A: iridescenceThicknessMax (Default=400.0) - vec4 iridescenceFactorAndIorAndThicknessMinMax; - // R: use iridescenceTexture, G: use iridescenceThicknessTexture - vec4 iridescenceTextures; + // R: iridescenceFactor (Default=0.0), G: iridescenceIor (Default=1.3), B: iridescenceThicknessMin (Default=100.0), A: iridescenceThicknessMax (Default=400.0) + vec4 iridescenceFactorAndIorAndThicknessMinMax; + // R: use iridescenceTexture, G: use iridescenceThicknessTexture + vec4 iridescenceTextures; }; +``` + +The common properties and feature structs are members of the uniform block. The packed components are: +```glsl uniform PbrMaterial { - // Common properties - // R: alphaCutoff (Default=0.5), G: doubleSided (Default=false), B: unlit (Default=false) - vec4 pbrAlphaCutoffAndDoubleSidedAndIsUnlit; - // R: use normalTexture, G: use occlusionTexture, B: use emissiveTexture - vec4 pbrCommonTextures; - - // Features -#ifdef PBR_METALLIC_ROUGHNESS - PbrMetallicRoughness pbrMetallicRoughness; -#endif -#ifdef PBR_SPECULAR_GLOSSINESS - PbrSpecularGlossiness pbrSpecularGlossiness; -#endif -#ifdef PBR_CLEARCOAT - PbrClearCoat pbrClearCoat; -#endif -#ifdef PBR_TRANSMISSION - PbrTransmission pbrTransmission; -#endif -#ifdef PBR_IOR - PbrIor pbrIor; -#endif -#ifdef PBR_SPECULAR - PbrSpecular pbrSpecular; -#endif -#ifdef PBR_VOLUME - PbrVolume pbrVolume; -#endif -#ifdef PBR_SHEEN - PbrSheen pbrSheen; -#endif -#ifdef PBR_EMISSIVE_STRENGTH - PbrEmissiveStrength pbrEmissiveStrength; -#endif -#ifdef PBR_IRIDESCENCE - PbrIridescence pbrIridescence; -#endif + // X: alpha cutoff, Y: double-sided, Z: unlit, + // W: alpha mode (0 = opaque, 1 = mask, 2 = blend) + vec4 pbrAlphaCutoffAndDoubleSidedAndIsUnlit; + // X: has normal texture, Y: has occlusion texture, Z: has emissive texture + vec4 pbrCommonTextures; + // RGB: emissive factor, W: emissive strength + vec4 pbrEmissiveFactorAndStrength; + // X: normal scale, Y: occlusion strength + vec4 pbrNormalScaleAndOcclusionStrength; + + PbrMetallicRoughness pbrMetallicRoughness; + PbrSpecularGlossiness pbrSpecularGlossiness; + PbrClearCoat pbrClearCoat; + PbrTransmission pbrTransmission; + PbrIor pbrIor; + PbrSpecular pbrSpecular; + PbrVolume pbrVolume; + PbrSheen pbrSheen; + PbrEmissiveStrength pbrEmissiveStrength; + PbrIridescence pbrIridescence; }; ``` -::: sidenote -If specific data points in the material struct are not found, the data for those features will not be set. E.g if there is no `pbrClearCoat` in the material struct, no clear coat data will be set. If the uniform block is not found, no data at all will be set during rendering. -::: +Omit unused feature members from the block. If the block or a feature's recognized fields are absent, the corresponding data is not supplied. Texture-presence flags describe the source material's texture references; a custom material still needs matching sampler declarations and texture bindings for the maps it samples. ### Constants -Each material property corresponds to an internal render constant in Defold. You can override default values by defining constants on the material resource itself, following the naming pattern `pbrFeature.structMember`. These values will be applied automatically if the matching data is missing in the glTF material. +Feature fields use names such as `pbrMetallicRoughness.baseColorFactor`; common fields use names such as `pbrEmissiveFactorAndStrength`. The engine populates these constants from the imported material, or from a default material when the model has no material data. Setting defaults in the `.material` resource does not override the imported values. -![Material constants](images/physically-based-rendering/material-constants.png) +To customize the built-in shading, edit the sampled `PBRMaterial` before deriving its BRDF values, as in the example above. For additional runtime controls, declare your own shader constants and use the [model material constant API](/manuals/model/#material-constants). ## Next steps -To use the material data for physically based lighting, implement a BRDF in your fragment shader using the parameters provided in the `PbrMaterial` block. +Use the built-in materials for the standard glTF metallic/roughness workflow. Extend the shader helpers or provide your own material when you need a different BRDF, environment lighting, shadows or additional glTF material effects. + See also: +* [Light manual](/manuals/light) +* [Material manual](/manuals/material) * [Shaders manual](/manuals/shader) * [Render manual](/manuals/render) * [glTF 2.0 specification](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html) diff --git a/docs/en/manuals/physics-joints.md b/docs/en/manuals/physics-joints.md index bcaebd29..f07e5f61 100644 --- a/docs/en/manuals/physics-joints.md +++ b/docs/en/manuals/physics-joints.md @@ -7,7 +7,7 @@ brief: Defold supports joints for 2D physics. This manual explains how to create A joint connects two collision objects using a constraint. Defold supports joints in both 2D and 3D physics, through different APIs. -This manual describes the 2D joints exposed by the `physics` module. Since Defold 1.13.2, 3D projects can create and control constraints through [`bullet3d.constraint`](/ref/beta/bullet3d.constraint/), including hinges, sliders and springs. Use that API with rigid bodies obtained through [`bullet3d.get_rigid_body()`](/ref/beta/bullet3d/#bullet3d.get_rigid_body). +This manual describes the 2D joints exposed by the `physics` module. 3D projects can create and control constraints through [`bullet3d.constraint`](/ref/beta/bullet3d.constraint/), including hinges, sliders and springs. Use that API with rigid bodies obtained through [`bullet3d.get_rigid_body()`](/ref/beta/bullet3d/#bullet3d.get_rigid_body). The supported joint types in the 2D `physics` API are: diff --git a/docs/en/manuals/physics-objects.md b/docs/en/manuals/physics-objects.md index 3b87a876..90c95089 100644 --- a/docs/en/manuals/physics-objects.md +++ b/docs/en/manuals/physics-objects.md @@ -27,7 +27,7 @@ A collision object component has a set of *Properties* that sets its type and ph To add a collision object component to a game object: 1. In the *Outline* view, right click the game object and select Add Component ▸ Collision Object from the context menu. This creates a new component with no shapes. -2. Right click the new component and select Add Shape, then choose a shape: Box, Capsule, Sphere, Hull or Mesh in projects using 3D physics, Box or Circle in projects using 2D physics. Hull and Mesh shapes are available since Defold 1.13.2 and use a named mesh from a glTF or GLB scene. You can add several shapes to the component. You can also use a tilemap or a `.convexshape` resource through the *Collision Shape* property. +2. Right click the new component and select Add Shape, then choose a shape: Box, Capsule, Sphere, Hull or Mesh in projects using 3D physics, Box or Circle in projects using 2D physics. Hull and Mesh shapes use a named mesh from a glTF or GLB scene. You can add several shapes to the component. You can also use a tilemap or a `.convexshape` resource through the *Collision Shape* property. 3. Use the move, rotate and scale tools to edit the shapes. 4. Select the component in the *Outline* and edit the collision object's *Properties*. diff --git a/docs/en/manuals/physics-shapes.md b/docs/en/manuals/physics-shapes.md index 3a049b7c..b07ff46d 100644 --- a/docs/en/manuals/physics-shapes.md +++ b/docs/en/manuals/physics-shapes.md @@ -32,7 +32,7 @@ Capsule shapes are only supported when using 3D physics (configured in the Physi ::: ### Complex shapes -Complex shapes can use tilemap geometry or convex hull data. Since Defold 1.13.2, 3D collision objects can also create hulls and triangle mesh shapes from meshes in glTF or GLB scenes. +Complex shapes can use tilemap geometry or convex hull data. 3D collision objects can also create hulls and triangle mesh shapes from meshes in glTF or GLB scenes. ## Hull and mesh shapes in 3D diff --git a/docs/en/manuals/porting-guidelines.md b/docs/en/manuals/porting-guidelines.md index 8e770379..4ba13dbb 100644 --- a/docs/en/manuals/porting-guidelines.md +++ b/docs/en/manuals/porting-guidelines.md @@ -93,6 +93,53 @@ Defold has built-in safe-area support on Android and iOS. Set `gui.safe_area_mod The [Safe Area extension](/extension-safearea) remains an alternative for legacy projects or workflows that need behavior beyond the built-in APIs; it is not required for standard Android and iOS safe-area handling. +### Reserved screen areas + +[`window.get_reserved_areas()`](/ref/window/#window.get_reserved_areas) reports individual regions that obstruct the game window, such as camera cutouts and the Dynamic Island. Use these rectangles when positioning content around individual obstructions. Use `window.get_safe_area()` when you need a single safe layout rectangle and its edge insets. + +The result is an array of tables with `x`, `y`, `width` and `height` fields. Each rectangle is clipped to the game window. The origin is at the bottom left: `x` is the left edge and `y` is the bottom edge, in window pixels matching [`window.get_size()`](/ref/window/#window.get_size). These coordinates are independent of GUI adjustment and the logical resolution in *game.project*, so account for your GUI transforms before using them as node positions. + +Platform support is: + +- **iOS 27.1 and later:** active occlusions reported by UIKit, including its interaction margins. +- **Android 9 (API level 28) and later:** display cutout rectangles. + +The function returns an empty table on unsupported platforms and OS versions, or when no obstructions are reported for the window. An empty table does not mean the entire window is safe for important content: folds, system bars, keyboards and gesture regions are outside this API. Use `window.get_safe_area()` for the platform's safe rectangle. + +### Refreshing areas after window events + +Query reserved areas during initialization and again on every [`window.WINDOW_EVENT_RESIZED`](/ref/window/#window.WINDOW_EVENT_RESIZED) callback. After the first query, changes to reserved-area geometry also trigger this event on supported platforms, even when the window size stays the same. Each returned table is a snapshot; saved tables are not updated automatically. + +On iOS, this event is also sent after orientation transitions and safe-area inset changes. A 180° landscape rotation can move a camera cutout or the Dynamic Island to the other side while both the window dimensions and safe-area insets stay the same. Refresh your geometry on the event even if `data.width` and `data.height` equal their previous values. + +The following script keeps both sets of geometry current: + +```lua +local function refresh_screen_areas(self) + self.safe_area = window.get_safe_area() + self.reserved_areas = window.get_reserved_areas() + -- Update your UI using the new safe rectangle and reserved areas. +end + +local function on_window_event(self, event, data) + if event == window.WINDOW_EVENT_RESIZED then + -- Refresh even when the width and height have not changed. + refresh_screen_areas(self) + end +end + +function init(self) + refresh_screen_areas(self) + window.set_listener(on_window_event) +end + +function final(self) + window.set_listener(nil) +end +``` + +Only one window event listener can be registered at a time. If your game already has one, add this refresh logic to that listener. Replacing the saved array on each refresh also clears obsolete rectangles when the result becomes empty. + ## Platform specific guidelines diff --git a/docs/en/manuals/profiling.md b/docs/en/manuals/profiling.md index 7b641754..c0508645 100644 --- a/docs/en/manuals/profiling.md +++ b/docs/en/manuals/profiling.md @@ -9,6 +9,7 @@ Defold includes profiling tools integrated with the engine and build pipeline. T * The basic profiler and in-game visual profiler are available on all platforms. * The [Remotery profiler](https://github.com/Celtoys/Remotery) and interactive web frame profiler are available on desktop and mobile platforms. +* macOS debug builds using Metal can save [GPU traces](#metal-gpu-trace-capture) for inspection in Xcode. * HTML5 builds can publish Defold scopes to the browser's Web Performance API. The **Profiler** setting in the [App Manifest](/manuals/app-manifest/#profiler) controls whether profiler code is linked into a build. **Debug Only** is the default, **None** excludes it, and **Always** includes it in both debug and release builds. The `profiler` settings in *game.project* control runtime behavior but do not link excluded profiler code back into a build. In particular, **Track CPU** controls CPU usage sampling; it is separate from the App Manifest choice. @@ -88,8 +89,8 @@ The [Max Sample Count setting](/manuals/project-settings/#max-sample-count) limi ### Resource profiler The Resource profiler allows you to inspect your game while it is running and analyze resource use in detail. To access the profiler: -1. Start your game on your target device. -2. Open a browser and browse to http://localhost:8002 +1. Start a debug build of your game on your target device. +2. Open the [engine service address](/manuals/engine-service/#availability-and-port-discovery) in a browser: `http://
:/`. Use the address and port reported by the running engine in the console. The resource profiler is divided into 2 sections, one showing a hierarchical view of the collections, game objects and components currently instantiated in your game, and the other showing all currently loaded resources. @@ -101,6 +102,110 @@ Collection view Resources view : The resources view shows all resources currently loaded into memory, their size and the number of references to each resource. This is useful when optimizing memory usage in your application when you need to understand what is loaded into memory at any given time. +#### Resource loading times + +You can also inspect how long individual resources take to load. Enable [Resource → Profile](/manuals/project-settings/#profile) in *game.project* before launching the game. In the text view, this setting is: + +```ini +[resource] +profile = 1 +``` + +The setting is disabled by default. Restart the game after enabling it to measure startup loads. Each completed or failed load writes an INFO-level log entry with the resource path, total time, and times for preload, read, create, post-create, queue and wait stages. Cache hits do not produce new loading records. + +In the resource profiler, click **Capture**, then **Show load times** to reveal the timing columns. **Capture** refreshes the view of retained measurements; it does not enable profiling or measure earlier loads retroactively. + +| Column | Meaning | +| --- | --- | +| **Load (ms)** | Total elapsed time for the initial load, including dependencies, post-create work, queueing and waiting. | +| **Preload (ms)** | Time spent preparing the resource in its preload callback. | +| **Read (ms)** | Time spent reading the resource data. | +| **Create (ms)** | Time spent creating the runtime resource in its create callback. | + +Showing load times sorts the table by total load time, with the slowest resources first. Click a timing column heading to sort by that stage; click it again to reverse the order. The bars in the **Load** column show each total relative to the slowest visible resource. Click **Hide load times** to hide the columns again. + +Load and callback times include any nested dependency work. Do not sum totals across resources to calculate startup time, since the same work can appear in more than one resource's measurement. The **Preload**, **Read** and **Create** columns also do not account for all of the total load time; the log provides the additional stages. + +An em dash (`—`) means no completed measurement is available, for example because profiling was disabled or the initial load has not finished. A measured zero is displayed as `0.000`. Measurements describe the initial load: cache hits and hot reloads leave them unchanged, and unloading a resource removes its retained measurement. + +## Metal GPU trace capture + +The [engine HTTP service](/manuals/engine-service/#metal-gpu-trace-endpoint) can capture Metal GPU commands to a *.gputrace* document on macOS. Open the completed trace in Xcode to inspect the captured frames. This feature is built into the debug engine. + +### Launch and check support + +Create a macOS [Debug bundle](/manuals/bundling/#release-vs-debug) with the native Metal graphics backend included. If you use an App Manifest, select a **Graphics (macOS)** option that includes Metal; see [graphics backends](/manuals/app-manifest/#graphics). + +Launch the bundle's executable from a terminal with `METAL_CAPTURE_ENABLED=1` and select the Metal adapter. Replace the bundle path and executable name in this example: + +```sh +METAL_CAPTURE_ENABLED=1 \ + "/absolute/path/MyGame.app/Contents/MacOS/MyGame" --graphics-adapter=metal +``` + +The environment variable must be set when the engine starts. Setting it only in a terminal used for HTTP requests does not enable capture in an already running engine. + +In a second terminal, use the [engine service port printed in the log](/manuals/engine-service/#availability-and-port-discovery). The following examples use `curl` and `jq`: + +```sh +ENGINE_URL="http://127.0.0.1:" +curl -fsS "$ENGINE_URL/openapi.json" | jq '.paths["/profiler/gputrace"]' +curl -sS -i "$ENGINE_URL/profiler/gputrace" +``` + +The route is registered only on macOS. A `null` entry in the OpenAPI document means this engine does not expose it. Even when the route is present, capture support depends on the graphics adapter and launch environment. `GET /profiler/gputrace` returns HTTP 501 with `error.code: "gputrace_unsupported"` when Metal capture is unavailable. Check that the engine is using Metal and was launched with `METAL_CAPTURE_ENABLED=1` before proceeding. A supported request returns HTTP 200 with capture status. + +### Capture and inspect frames + +Choose a writable absolute output path ending in `.gputrace`, with an existing parent directory and no trace already at that path. The path is on the computer running the engine. For a local engine, this example creates a fresh temporary directory and requests one frame: + +```sh +GPU_TRACE_DIR=$(mktemp -d /tmp/defold-gputrace.XXXXXX) +GPU_TRACE_PATH="$GPU_TRACE_DIR/frame.gputrace" +GPU_TRACE_REQUEST=$(jq -n --arg path "$GPU_TRACE_PATH" '{path: $path, frames: 1}') +curl -fsS -X POST \ + -H 'Content-Type: application/json' \ + --data "$GPU_TRACE_REQUEST" \ + "$ENGINE_URL/profiler/gputrace" | jq +``` + +`frames` is optional, defaults to `1`, and accepts integers from `1` to `10000`. Capture starts before the next rendered frame and stops after the requested number of complete frames have been submitted. Keep the game rendering while waiting. Only one capture can be pending or active; another start request returns HTTP 409 with `error.code: "gputrace_active"`. + +`POST` returns HTTP 200 with `ok: true` and `data.state: "pending"` when the capture is scheduled. Capture completion is reported by later status requests. Repeat the status request until `data.state` becomes `complete`, `canceled` or `failed`: + +```sh +curl -fsS "$ENGINE_URL/profiler/gputrace" | jq +``` + +| `data.state` | Meaning | +| --- | --- | +| `idle` | No capture has been scheduled. | +| `pending` | Capture is waiting for rendering to begin. | +| `capturing` | Capture is active; `data.frames_captured` reports completed frames. | +| `complete` | Capture has finished and the trace can be opened. | +| `canceled` | A pending capture was canceled before it started. | +| `failed` | Capture could not start; inspect `data.error` for the native error. | + +`GET` describes the current or most recent capture. Check that `data.path` matches your requested path. A failed capture still returns HTTP 200 with `ok: true`; inspect `data.state` and `data.error` to determine the result. For an automated client, poll with a delay and a timeout. + +After the state is `complete`, open the trace in Xcode on the engine's Mac: + +```sh +open -a Xcode "$GPU_TRACE_PATH" +``` + +The HTTP endpoint returns status; the trace is saved at `data.path` on the engine host. For a remote engine, retrieve the completed document from that host before opening it locally. + +### Cancel or stop a capture + +To cancel a pending capture or finish an active capture early: + +```sh +curl -fsS -X DELETE "$ENGINE_URL/profiler/gputrace" | jq +``` + +A pending capture changes to `canceled`. For an active capture, `data.stop_requested` becomes `true`, and capture finishes after the current rendered frame is submitted. Continue polling `GET` until it reaches a terminal state. `DELETE` leaves any trace already written on disk. If no capture is pending or active, it returns HTTP 409 with `error.code: "gputrace_inactive"`. + ## HTML5 browser performance timeline HTML5 uses the Web Performance API instead of Remotery for its browser timeline. To record Defold scopes: diff --git a/docs/en/manuals/project-settings.md b/docs/en/manuals/project-settings.md index 5006397c..5ac7ac19 100644 --- a/docs/en/manuals/project-settings.md +++ b/docs/en/manuals/project-settings.md @@ -154,6 +154,8 @@ If the time step becomes too large during a single frame, it will be capped to t ### Display +On desktop platforms, engine windows opened from the editor can restore a size saved during an earlier run. Choose Debug ▸ Reset Simulated Resolution to clear remembered sizes and return to the configured size while keeping saved window positions. See [engine window placement and reset](/manuals/editor/#engine-window-placement) for details. + #### Width The width in pixels of the application window. @@ -163,6 +165,8 @@ The height in pixels of the application window. #### High Dpi Creates a high dpi back buffer on displays that support it. Typically the game will render in double the resolution than what is set in the *Width* and *Height* settings, which will still be the logical resolution used in scripts and properties. +On HTML5, use [Min Pixel Ratio](#min-pixel-ratio) and [Max Pixel Ratio](#max-pixel-ratio) to bound the rendering scale when this setting is enabled. + #### Samples How many samples to use for super sampling anti-aliasing. It sets the `GLFW_FSAA_SAMPLES` window hint. A value of `0` means that anti-aliasing is turned off. @@ -207,13 +211,6 @@ Clear color alpha channel, used by the render script and when the window is crea --- -### Font - -#### Runtime Generation -Use runtime font generation. - ---- - ### Physics #### Max Collision Object Count @@ -305,7 +302,7 @@ The texture profiles file to use for this project, `/builtins/graphics/default.t Verify the return value after each graphics call and report any errors in the log. #### WebGL Version Hint -`graphics.webgl_version_hint` selects the WebGL context version to request for HTML5. Valid values are `1` (WebGL 1) and `2` (WebGL 2, the default). Set it to `1` to target or test WebGL 1 even on a browser that supports WebGL 2. Keep [Exclude GLES 2.0](#exclude-gles-20) disabled when targeting WebGL 1 so the required shaders are included. +`graphics.webgl_version_hint` selects the WebGL context version to request for HTML5. Valid values are `1` (WebGL 1) and `2` (WebGL 2, the default). Set it to `1` to target or test WebGL 1 even on a browser that supports WebGL 2. Disable [Exclude GLES 2.0](#exclude-gles-20) when targeting WebGL 1 so the required shaders are included. #### OpenGL Version Hint OpenGL context version hint. If a specific version is selected, this will be used as the minimum version required (does not apply to OpenGL ES). @@ -324,7 +321,16 @@ Set the 'core' OpenGL profile hint when creating the context. The core profile r ### Shader #### Exclude GLES 2.0 -Don't compile shaders for devices running OpenGLES 2.0 / WebGL 1.0. +`shader.exclude_gles_sm100` excludes shaders for OpenGLES 2.0 and WebGL 1.0. Enabled by default (`1`). + +To target these graphics APIs or allow fallback to them, uncheck **Shader ▸ Exclude GLES 2.0** in *game.project*, or set: + +```ini +[shader] +exclude_gles_sm100 = 0 +``` + +Projects that do not explicitly set this option use the default. Set it to `0` explicitly if the project needs OpenGLES 2.0 or WebGL 1.0 support. #### GLSL ES Default Precision Float `shader.glsl_es_default_precision_float` sets the default global precision qualifier for floating-point values in cross-compiled GLSL ES shaders. Valid values are `mediump` and `highp`; the default is `mediump`. @@ -370,6 +376,9 @@ Where to find the project build data, in URI format. #### Max Resources The max number of resources that can be loaded at the same time. +#### Profile +`resource.profile` enables resource loading timings and INFO-level logs for each completed or failed load. Disabled by default (`0`). Enable it (`1`) before launching the game to measure startup loads. The resource profiler shows retained initial-load measurements for currently loaded resources; click **Capture**, then **Show load times** to inspect them. See [Resource loading times](/manuals/profiling/#resource-loading-times) for the timing columns and how to interpret them. + --- ### Network @@ -594,6 +603,17 @@ Max number of game object factories. [(See information about component max count ### iOS +#### Home Indicator Mode +`ios.home_indicator_mode` controls system gestures at the screen edges and whether the game requests automatic hiding of the Home Indicator. + +| Value | System gestures | Request automatic hiding | +|-------|-----------------|--------------------------| +| `deferred` (default) | Protects all screen edges by deferring system gestures. Returning Home requires two swipes. | No | +| `system` | Uses normal system gestures, allowing a single swipe to return Home. | No | +| `auto_hide` | Uses normal system gestures, allowing a single swipe to return Home. | Yes | + +iOS controls the indicator's actual visibility. Automatic hiding is a request, and on iOS 26 and later the system may hide the indicator in both `system` and `auto_hide` modes. See [Home Indicator behavior](/manuals/ios/#home-indicator-behavior) for a configuration example. + #### App Icon 57x57--180x180 Image file (.png) to use as application icon at given width and height dimensions `W` × `H`. @@ -616,7 +636,7 @@ The bundle short name (15 characters) (see [`CFBundleName`](https://developer.ap The bundle version, either a number or x.y.z. (see [`CFBundleVersion`](https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html#//apple_ref/doc/uid/20001431-130430)) #### Info.plist -If specified, use this *`Info.plist`* file instead of the built-in iOS base manifest when bundling your app. The built-in manifest contains the local-network and Bonjour entries needed for Editor target discovery in non-release builds. If you supply a custom manifest and need target discovery, profiling, hot reload, or log streaming on a device, preserve those entries as described in the [iOS manual](/manuals/ios/#creating-an-ios-application-bundle). +If specified, use this *`Info.plist`* file instead of the built-in iOS base manifest, `/builtins/manifests/ios/Info.plist`, when bundling your app. Projects using the built-in template receive manifest updates automatically; custom files need to be updated explicitly. #### Privacy Manifest The Apple Privacy Manifest for the application. The field will default to `/builtins/manifests/ios/PrivacyInfo.xcprivacy`. @@ -685,7 +705,7 @@ Whether or not the application can be debugged using tools such as [GAPID](https #### R8 Keep Rules `android.r8_keep_rules` selects a `.keep` file to enable R8 shrinking, optimization and obfuscation of Java code in Android builds. Leave the setting empty to use D8 without shrinking. -With Defold 1.14.0 or later and a compatible Extender build server, this also removes unused Android resources. Resources loaded dynamically may need separate [XML keep rules](/manuals/android/#keeping-android-resources). +With a compatible Extender build server, this also removes unused Android resources. Resources loaded dynamically may need separate [XML keep rules](/manuals/android/#keeping-android-resources). Select `/builtins/manifests/android/dmengine.keep` to use Defold's default rules directly. Extensions supply their own [keep rules](/manuals/extensions/#r8-keep-rules-for-android), which are combined with this file. @@ -773,6 +793,14 @@ When enabled this option will print information about the engine and engine vers #### Scale Mode Specifies which method to use to scale the game canvas. +#### Min Pixel Ratio +`html5.min_pixel_ratio` sets the minimum number of canvas render pixels per CSS pixel when [High Dpi](#high-dpi) is enabled. The default is `0`, which disables the lower bound. Positive fractional values are supported, including values below `1`. + +#### Max Pixel Ratio +`html5.max_pixel_ratio` sets the maximum number of canvas render pixels per CSS pixel when [High Dpi](#high-dpi) is enabled. The default is `0`, which disables the upper bound. Positive fractional values are supported, including values below `1`. + +Both limits must be finite, non-negative numbers. When both bounds are enabled, the minimum must not exceed the maximum. With *High Dpi* disabled, the ratio is `1` and neither bound is applied. These limits affect rendering resolution while preserving the canvas's CSS display size. See [Pixel ratio limits](/manuals/html5/#pixel-ratio-limits) for a configuration example. + #### Retry Count The number of retries after a failed download during startup, including network errors, failed HTTP statuses and size mismatches in the engine's JavaScript or WebAssembly file. The initial request is separate. Archive-file verification has its own retry limit; see [download verification](/manuals/html5/#download-verification) and `Retry Time`. @@ -811,6 +839,34 @@ If set, use the app manifest to customize the engine build. This allows you to r --- +### Debugger + +These settings control [debugger connections](/manuals/debugging-game-logic/#native-dap-connections) in native debug and headless builds. Release and Web builds do not support attaching the debugger. Add these settings by editing *game.project* as text, or use [configuration overrides on engine startup](#setting-config-values-on-engine-startup). They are not shown in the project settings form. The editor configures the connection automatically when you use Debug ▸ Start/Attach. + +For example, to start a local listener and wait for a client to configure breakpoints before startup scripts run: + +```ini +[debugger] +enabled = 1 +address = 127.0.0.1 +port = 8172 +wait = 1 +``` + +#### Enabled {#debugger-enabled} +`debugger.enabled` starts the listener during engine startup when set to `1`. Disabled by default (`0`). A running game can also start the listener with [`debugger.start()`](/manuals/debugging-game-logic/#enabling-the-listener-while-running). + +#### Address {#debugger-address} +`debugger.address` is the IPv4 address on which the listener accepts connections. The default, `127.0.0.1`, accepts local connections only. Use a device interface address or `0.0.0.0` for [remote connections](/manuals/debugging-game-logic/#remote-targets). + +#### Port {#debugger-port} +`debugger.port` is the TCP listening port, from `0` to `65535`. The default is `8172`. Set it to `0` to select an available port, which the engine reports in its log. + +#### Wait {#debugger-wait} +`debugger.wait` makes the engine wait for the client to finish configuring the debug session, including breakpoints, before running startup scripts. Disabled by default (`0`). Set it to `1` together with `debugger.enabled=1` to debug startup code. Starting the listener later with `debugger.start()` does not wait or pause the game. See the [startup and attach guide](/manuals/debugging-game-logic/#native-dap-connections). + +--- + ### Profiler The App Manifest **Profiler** setting controls whether profiler code is linked into debug and release builds. The settings below control the runtime behavior of profiler code that is present in the selected build. See the [Profiling manual](/manuals/profiling/) for details. diff --git a/docs/en/manuals/properties.md b/docs/en/manuals/properties.md index 45b41839..4c68c403 100644 --- a/docs/en/manuals/properties.md +++ b/docs/en/manuals/properties.md @@ -102,7 +102,7 @@ Specific functions for working with the game object transform also exist; they a | property | description | type | | | ---------- | -------------------------------------- | --------------- | ---------------- | -| *text* | The text content of the label. Available since Defold 1.13.2. | `string` | `get+set`{.mark} | +| *text* | The text content of the label. | `string` | `get+set`{.mark} | | *scale* | The scale of the label. | `vector3` | `get+set`{.mark} | | *scale.xy* | The scale of the label along X and Y axis. | `vector3` | `get+set`{.mark}| | *color* | The color of the label. | `vector4` | `get+set`{.mark} | diff --git a/docs/en/manuals/recording.md b/docs/en/manuals/recording.md new file mode 100644 index 00000000..6512c030 --- /dev/null +++ b/docs/en/manuals/recording.md @@ -0,0 +1,217 @@ +--- +title: Video recording in Defold +brief: This manual explains how to record the game window to MP4 using Lua or the engine HTTP service. +--- + +# Video recording + +Defold can record the game window to an H.264 video in an MP4 file through the [`recorder` Lua module](/ref/recorder/) or the [engine HTTP service](/manuals/engine-service/#recording-endpoints). Both interfaces share one recorder, so only one recording can start, run or finalize at a time. + +## Availability + +Recording is included in desktop **debug** engines. It is omitted from release, headless, mobile and web builds. Enabling **Exclude Record** in an [App Manifest](/manuals/app-manifest/#exclude-record) also removes the Lua module and HTTP routes. + +| Platform | Video requirements | Application audio | +| --- | --- | --- | +| macOS | macOS 15 or later, using ScreenCaptureKit | Supported | +| Windows | Windows 10 version 1903 or later, using Windows Graphics Capture and Media Foundation | Supported on Windows build 20348 or later | +| Linux | OpenGL, OpenGL ES or Vulkan, using framebuffer capture | Not supported | + +Video and audio support are checked separately. HTTP clients can inspect `/recording/capabilities`; Lua callers receive an error if the requested capture is unsupported. Operating-system permissions and capture-device failures can also cause an asynchronous error after a start request is accepted. + +The recorder captures the game window's content at its native size in physical pixels. It may crop one row or column to produce even video dimensions. Resizing the window or changing its pixel density stops and finalizes the recording. Capture rate is 1–60 frames per second, with a default of 30. + +## Recording from Lua + +Use [`recorder.start()`](/ref/recorder/#recorder.start) with a writable output path and a callback. The parent directory must exist; [`sys.get_save_file()`](/ref/sys/#sys.get_save_file) supplies a suitable application save path. An existing output file may be overwritten. Lua recordings belong to the caller and remain on disk after the engine exits. + +Paths use the Windows ANSI code page on Windows and UTF-8 elsewhere, as with Lua file I/O. The callback's `result.path` preserves the path passed to `recorder.start()`. + +This `.script` example records for five seconds after capture starts: + +```lua +local function on_recording_event(self, event, result) + if event == recorder.EVENT_STARTED then + self.recording = true + timer.delay(5, false, function(self) + if self.recording then + local ok, err = recorder.stop() + if not ok then + print("Could not stop recording:", err) + end + end + end) + elseif event == recorder.EVENT_STOPPED then + self.recording = false + print("MP4 ready:", result.path) + elseif event == recorder.EVENT_ERROR then + self.recording = false + print("Recording failed:", result.error) + end +end + +function init(self) + self.recording = false + if not recorder then + print("Recording is not included in this engine build") + return + end + + local ok, err = recorder.start({ + path = sys.get_save_file("recording_example", "capture.mp4"), + fps = 30, + audio = false, + }, on_recording_event) + if not ok then + print("Could not start recording:", err) + end +end +``` + +`recorder.start()` and [`recorder.stop()`](/ref/recorder/#recorder.stop) return `true` when accepted, or `nil, error` when rejected. Acceptance does not mean capture or file finalization has finished. Invalid options raise Lua errors. + +Callbacks run during engine updates: + +| Event | Meaning | +| --- | --- | +| `recorder.EVENT_STARTED` | Capture is active; it can now be stopped. | +| `recorder.EVENT_STOPPED` | The MP4 has been finalized and is ready to read. This also occurs after an automatic stop on resize. | +| `recorder.EVENT_ERROR` | Capture failed; inspect `result.error`. Startup failure can produce this event without `EVENT_STARTED`. | + +The result also contains `path`, `width`, `height`, `fps` and `audio`. Read or upload the output only after `EVENT_STOPPED`. Keep the initiating script alive to receive the callback: deleting it discards callbacks without stopping capture. Engine shutdown finalizes capture without invoking Lua callbacks. + +Audio is **disabled by default in Lua**. Set `audio = true` to request application audio on a supported platform. Requesting unsupported audio returns an error. + +### Sharing the recorder with HTTP clients + +`recorder.stop()` targets the current shared recording, including one started through HTTP. It returns an error while an operation is pending or when no recording is active. If an HTTP client stops a Lua recording, the original Lua callback still receives its completion event. Starting through HTTP does not create a Lua callback; use HTTP status to observe its completion. + +HTTP status can describe a Lua recording, but its `file` field is `null`: the service only prepares downloads for recordings started through HTTP. Read a Lua recording from `result.path` after `EVENT_STOPPED`. + +## Recording through HTTP + +The recording routes use the engine service port printed in the game log. Discover them through `/openapi.json` as described in the [engine service manual](/manuals/engine-service/#discovering-operations-through-openapi). A headless or release engine will not expose them. + +The following commands use a POSIX shell, `curl` and `jq`; the download verification step also uses Python 3. Run them in the same shell and replace `` with the running engine's port. First query capabilities and retain the service identity: + +```sh +set -eu +ENGINE_URL="http://127.0.0.1:" +CAPABILITIES=$(curl -fsS "$ENGINE_URL/recording/capabilities") +printf '%s\n' "$CAPABILITIES" | jq +INSTANCE_ID=$(printf '%s\n' "$CAPABILITIES" | jq -er 'select(.supported) | .instance_id') +``` + +Proceed only if `supported` is `true`; otherwise inspect `unsupported_reason` and `minimum_platform_version`. The `audio` field reports audio support. Unlike Lua, **HTTP recording enables audio by default when the backend supports it**. The example below explicitly disables audio. + +### Start and inspect the recording + +Start with an optional JSON object containing `fps` and/or `audio`. The service chooses the output file; it does not accept a path, width, height or scale. + +```sh +START=$(curl -fsS -X POST \ + -H 'Content-Type: application/json' \ + -H "X-Recording-Instance: $INSTANCE_ID" \ + --data '{"fps":30,"audio":false}' \ + "$ENGINE_URL/recording/start") +OPERATION_ID=$(printf '%s\n' "$START" | jq -er '.operation_id') +printf '%s\n' "$START" | jq +``` + +HTTP 202 means the request was accepted. Re-run the following status command until `pending` is `false` and `active` is `true`. The check rejects a response for another operation and reports capture or file-preparation failures. If an automatic stop has already finalized the recording, continue with [finalization](#stop-and-wait-for-finalization) before downloading. + +```sh +STATUS=$(curl -fsS \ + -H "X-Recording-Instance: $INSTANCE_ID" \ + "$ENGINE_URL/recording/status") +printf '%s\n' "$STATUS" | jq -e --argjson id "$OPERATION_ID" ' + if .operation_id != $id then error("Recording operation changed") + elif .state == "failed" then error(.failure) + elif .file.state == "failed" then error("Recording file preparation failed") + else . end' +``` + +Let the game run for the duration you want to capture, then request a stop. If the window resized and the recording already completed, skip the stop request and continue with finalization below. + +### Stop and wait for finalization + +Stop the operation whose ID you retained from the start response: + +```sh +STOP_BODY=$(jq -n --argjson id "$OPERATION_ID" '{operation_id: $id}') +STOP=$(curl -fsS -X POST \ + -H 'Content-Type: application/json' \ + -H "X-Recording-Instance: $INSTANCE_ID" \ + --data "$STOP_BODY" \ + "$ENGINE_URL/recording/stop") +printf '%s\n' "$STOP" | jq +``` + +HTTP 202 only accepts the stop request. Repeat the status command until `pending` is `false`, `finalized` is `true`, and `file.state` is `complete`. The service prepares the file's size and SHA-256 after native capture finishes, so `state: "complete"` and `finalized: true` alone do not mean the download is ready. Stop waiting if `state` or `file.state` becomes `failed`; do not download a file whose state is `pending` or `failed`. + +An automated client should poll with a delay and a timeout, checking the retained operation ID on every response. Allow the engine to keep updating while waiting for capture and finalization. + +### Download and release the file + +Use the completed file's relative URL from the status response. The check below also ensures that the response still belongs to your operation: + +```sh +FILE_URL=$(printf '%s\n' "$STATUS" | jq -er --argjson id "$OPERATION_ID" \ + 'select(.operation_id == $id and .pending == false and .finalized == true and .file.state == "complete") | .file.url') +curl -fsS -H "X-Recording-Instance: $INSTANCE_ID" \ + "$ENGINE_URL$FILE_URL" -o capture.mp4 +printf '%s\n' "$STATUS" > capture.json +``` + +Keep the completed status receipt in `capture.json` with the MP4. `/recording/status` describes the current operation, so a later recording replaces the status response even while earlier HTTP files remain available. + +Verify the downloaded file's byte size and SHA-256 before using it or deleting the service's copy: + +```sh +python3 - <<'PY' +import hashlib +import json +from pathlib import Path + +receipt = json.loads(Path("capture.json").read_text(encoding="utf-8")) +capture = Path("capture.mp4") +if capture.stat().st_size != receipt["file"]["size"]: + raise SystemExit("Recording download size mismatch") + +digest = hashlib.sha256() +with capture.open("rb") as stream: + for chunk in iter(lambda: stream.read(65536), b""): + digest.update(chunk) +if digest.hexdigest() != receipt["file"]["sha256"]: + raise SystemExit("Recording download SHA-256 mismatch") +print("Verified capture.mp4") +PY +``` + +A GET without a `Range` header downloads the whole MP4. The service also supports closed byte ranges, such as `Range: bytes=0-1023`, if a client needs partial downloads. Verify the assembled file against the same receipt. + +After downloading and verifying the file, you can release the service's retained copy: + +```sh +curl -fsS -X DELETE -H "X-Recording-Instance: $INSTANCE_ID" \ + "$ENGINE_URL$FILE_URL" +``` + +HTTP recording files remain available until explicitly deleted or the engine shuts down or reboots. Download them before closing the engine. The service retains at most 128 files; delete completed files you have saved to make room for further recordings. + +### Keeping operation identities together + +Every POST and DELETE requires `X-Recording-Instance`. The examples also send it on status and download requests to reject responses from a replacement engine. Keep `instance_id`, `operation_id` and the file information together: the service identity changes on restart or reboot, and a new process can reuse operation numbers. + +A missing identity returns HTTP 400. A stale identity, stale stop operation or deleted file returns HTTP 410. Do not fetch a new identity and reuse it to retry an old operation. Discover the new service and start a new recording instead. + +### Handling HTTP failures + +Rejected requests return JSON with `error.code` and `error.message`. For troubleshooting, run the individual `curl` request with `-i` and without `-f` to see the HTTP status and error body. + +| HTTP status | What to check | +| --- | --- | +| 409 | Another recording is active or pending, the current recording is not ready to stop, or the file is still being prepared. Read status before retrying. | +| 500 | Recording startup, storage initialization or file preparation/read failed. Inspect the error message; a failed capture also reports `failure` in status. | +| 501 | Video or the requested audio is unsupported. Inspect capabilities; use `audio: false` if only audio is unavailable. | +| 507 | The service's retained-file limit was reached. Download and delete completed files before starting another recording. | diff --git a/docs/en/manuals/render.md b/docs/en/manuals/render.md index d7d1de21..4f5df9a5 100644 --- a/docs/en/manuals/render.md +++ b/docs/en/manuals/render.md @@ -189,7 +189,7 @@ Frustum culling is implemented in the engine per component type. Current status: ::: sidenote -Starting with Defold 1.13.0, component primitives use counter-clockwise vertex winding, with the primitive normal pointing towards the camera. Sprites, GUI nodes, tilemaps (tilegrids), and Particle FX use the same winding as other component types, so the same face-culling settings can be used for all components. +Component primitives use counter-clockwise vertex winding, with the primitive normal pointing towards the camera. Sprites, GUI nodes, tilemaps (tilegrids), and Particle FX use the same winding as other component types, so the same face-culling settings can be used for all components. This may affect projects that set face culling for components other than models. If a component is unexpectedly culled, make sure back faces are selected with `render.set_cull_face(graphics.FACE_TYPE_BACK)`, or remove the `render.set_cull_face()` call to use the default `graphics.FACE_TYPE_BACK` mode. ::: diff --git a/docs/en/manuals/scene-editing.md b/docs/en/manuals/scene-editing.md index 7ab1bd06..30b6611b 100644 --- a/docs/en/manuals/scene-editing.md +++ b/docs/en/manuals/scene-editing.md @@ -46,6 +46,22 @@ These controls are available in visual editors: You may also use **Frame Selection** (F) to focus the camera on the current selection. +### Axis gizmo + +The **Scene View Axis Gizmo** appears in the bottom-right corner of the scene view in 3D mode. It shows the camera's orientation relative to the world axes: **X** is red, **Y** is green and **Z** is blue. + +![Scene view with the axis gizmo in the bottom-right corner](images/editor/axis_gizmo.gif) + +| Control | Action | +| --- | --- | +| Left Mouse Click on an axis handle | Align the camera to view along that axis. The opposite handles provide views from the other side. | +| Click an already aligned axis handle | Switch to the opposite view along the same axis. | +| Hold Left Mouse Button and drag the gizmo | Orbit around the camera's current focus point. You can drag from an axis handle or the circular area around the handles, without holding a modifier key. | + +Axis alignment preserves the camera's focus point, distance and projection. Use **Frame Selection** (F) first to focus on an object, then use the gizmo to inspect it from different directions. Standard pan, zoom and Ctrl/^ Control + Left Mouse Button orbit controls remain available. + +The gizmo is available with both perspective and orthographic projection in 3D mode. In 2D mode it is hidden; use **Align/Realign Camera 2D/3D** in the [toolbar](#toolbar-overview), or press ., to switch to 3D. Use the separate [camera projection toggle](#camera-type-perspective-vs-orthographic) to choose perspective or orthographic projection. The gizmo controls the Scene Editor's view of your scene. + ## 2D and 3D scene orientation The scene view can be used in both 2D and 3D workflows: @@ -56,7 +72,7 @@ The scene view can be used in both 2D and 3D workflows: - Use a **perspective** camera, - Choose an appropriate grid plane (often **Y** for “ground”). -You can access these functions via the toolbar and the **View** menu. +You can access these functions via the toolbar and the **View** menu. Use the [axis gizmo](#axis-gizmo) in 3D mode to align the view to an axis or orbit with the mouse. ![Scene Editor 3D](images/editor/3d_scene.png) diff --git a/docs/en/manuals/script-properties.md b/docs/en/manuals/script-properties.md index 08b896e8..60373a7a 100644 --- a/docs/en/manuals/script-properties.md +++ b/docs/en/manuals/script-properties.md @@ -64,7 +64,7 @@ Script properties are parsed when building the project. Value expressions are no ### Text properties -Since Defold 1.13.2, a string default defines a text property. Text properties support UTF-8 and newline characters and are edited in a multiline field in the editor: +A string default defines a text property. Text properties support UTF-8 and newline characters and are edited in a multiline field in the editor: ```lua go.property("greeting", "Hello!\nWelcome, José!") diff --git a/docs/en/manuals/shader.md b/docs/en/manuals/shader.md index 26f57872..7dc38c28 100644 --- a/docs/en/manuals/shader.md +++ b/docs/en/manuals/shader.md @@ -112,7 +112,7 @@ Since the Defold engine supports multiple platforms and graphics APIs, it must b 1. The legacy pipeline, where shaders are written in ES2 compatible GLSL code. 2. The modern pipeline, where shaders are written in SPIR-v compatible GLSL code. -Starting with Defold 1.9.2, it is encouraged to write shaders that utilize the new pipeline, and to achieve this most shaders need to be migrated into shaders written in at least version 140 (OpenGL 3.1). To migrate a shader, make sure these requirements are met: +Write shaders for the modern pipeline using at least GLSL version 140 (OpenGL 3.1). To migrate a shader, make sure these requirements are met: ### Version declaration Put at least #version 140 at the top of the shader: diff --git a/docs/en/manuals/sound.md b/docs/en/manuals/sound.md index 21d62f30..31dfb0b2 100644 --- a/docs/en/manuals/sound.md +++ b/docs/en/manuals/sound.md @@ -50,14 +50,44 @@ The created component has a set of properties that should be set: When you have a sound component set up properly, you can cause it to play its sound by calling [`sound.play()`](/ref/sound/#sound.play:url-[play_properties]-[complete_function]): ```lua -sound.play("go#sound", {delay = 1, gain = 0.5, pan = -1.0, speed = 1.25}) +local play_id = sound.play("go#sound", {delay = 1, gain = 0.5, pan = -1.0, speed = 1.25}) ``` +Each playback is a separate *voice*. `sound.play()` returns its numeric playback identifier (`play_id`); save this ID to [control that individual voice](#controlling-individual-voices). + ::: sidenote A sound will continue to play even if the game object the sound component belonged to is deleted. You can call [`sound.stop()`](/ref/sound/#sound.stop:url) to stop the sound (see below). ::: Each message sent to a component will cause it to play another instance of the sound, until the available sound buffer is full and the engine will print errors in the console. It is advised that you implement some sort of gating and sound grouping mechanism. +### Controlling individual voices + +[`sound.set_gain()`](/ref/sound/#sound.set_gain) and [`sound.set_pan()`](/ref/sound/#sound.set_pan) accept an optional third argument with a `play_id`. Use the ID returned by `sound.play()` and the URL of the same sound component: + +```lua +function init(self) + -- Save the ID of a voice that will start in one second. + self.voice_id = sound.play("go#sound", { delay = 1 }) + -- Start another voice on the same component. + sound.play("go#sound") + + -- Change only the delayed voice. + sound.set_gain("go#sound", 0.4, { play_id = self.voice_id }) + sound.set_pan("go#sound", -0.5, { play_id = self.voice_id }) +end +``` + +These targeted calls leave other voices and the component's gain and pan defaults unchanged. They work for delayed and paused voices, so the new values apply when the voice starts or resumes. An unknown ID or an ID whose playback has finished has no effect. + +Omit `play_id` to update all voices and the component defaults used for future playback: + +```lua +sound.set_gain("go#sound", 0.8) +sound.set_pan("go#sound", 0.0) +``` + +Passing `{ play_id = nil }` also omits the ID. If you clear a saved ID when playback ends, check that it is not `nil` before using it for a targeted update. + ## Stopping the sound If you wish to stop playing a sound you can call [`sound.stop()`](/ref/sound/#sound.stop:url): @@ -73,7 +103,7 @@ sound.stop("go#sound") The sound system has 4 levels of gain: - The gain set on the sound component. -- The gain set when starting the sound via a call to `sound.play()` or when changing the gain on the voice via a call to `sound.set_gain()`. +- The gain set when starting the sound via a call to `sound.play()` or when changing the gain on [one or all voices](#controlling-individual-voices) via a call to `sound.set_gain()`. - The gain set on the group via a [`sound.set_group_gain()`](/ref/sound#sound.set_group_gain) function call. - The gain set on the `master` group. This can be altered with `sound.set_group_gain(hash("master"), gain)`. diff --git a/docs/en/manuals/texture-profiles.md b/docs/en/manuals/texture-profiles.md index 40fae66c..7aa9d189 100644 --- a/docs/en/manuals/texture-profiles.md +++ b/docs/en/manuals/texture-profiles.md @@ -80,7 +80,7 @@ To add texture compression: ![Setting the texture profile](images/texture_profiles/texture_profiles_game_project.png) -You can turn on and off the use of texture profiles in the editor preferences. Select File ▸ Preferences.... The *General* tab contains a checkbox item *Enable texture profiles*. +To apply texture compression when building from the editor, select File ▸ Preferences... and check **Enable Texture Compression** in the *General* tab. For builds made with Bob, pass [`--texture-compression`](/manuals/bob/#usage). Profile settings such as image size and mipmaps still apply when compression is disabled. ![Texture profiles preferences](images/texture_profiles/texture_profiles_preferences.png) @@ -127,6 +127,9 @@ If two [path settings](#path-settings) matches the same file and the path uses d *Formats* : One or more texture formats to generate. If several formats are specified, textures for each format are generated and included in the bundle. The engine selects textures of a format that is supported by the runtime platform. +*Keep KTX2 Format* +: Keeps a KTX2 source's encoding format instead of using the platform's *Formats* alternatives. Unchecked by default (`keep_ktx2_format: false`). Other image types, such as PNG and JPEG, continue to use *Formats*. Keeping a compressed source format requires texture compression to be enabled. See [KTX2 source textures](#ktx2-source-textures) for processing and compatibility details. + *Mipmaps* : If checked, mipmaps are generated for the platform. Unchecked by default. @@ -157,6 +160,38 @@ The *Formats* added to a profile each have the following properties: Note that the `uncompressed` compressor only has one preset called `uncompressed`, which means no compression will be applied to the textures. To see the list of available compressors, see [Compressors](#compressors) +## KTX2 source textures + +Texture profiles apply to standalone *.ktx2* files and to KTX2 images embedded in glTF or GLB files. Path settings match the source image path, including virtual paths such as `/models/robot.glb/images/0.ktx2` for embedded images. Place a specific KTX2 path setting before broader matching patterns. + +Select the profile and platform, then choose how to process the KTX2 input: + +| Keep KTX2 Format | Compiled output when texture compression is enabled | +| --- | --- | +| Enabled | ETC1S stays ETC1S, UASTC stays UASTC, BC7 stays BC7, and raw source data remains uncompressed. The platform's *Formats* alternatives are bypassed for KTX2 input. | +| Disabled (default) | Source images are decoded and encoded using the profile's *Format*, *Compressor* and *Compressor Preset*, even if the chosen encoding is the same as the source. | + +For example, this profile matches KTX2 sources, keeps their format and mipmaps, and disables alpha premultiplication: + +```protobuf +path_settings { path: "**/*.ktx2" profile: "KTX2" } +profiles { + name: "KTX2" + platforms { + os: OS_ID_GENERIC + mipmaps: true + premultiply_alpha: false + keep_ktx2_format: true + } +} +``` + +Merge these entries into the texture profiles file assigned in *game.project* and enable texture compression for the build. With compression disabled, or with no matching profile, KTX2 sources produce uncompressed output. + +**Keep KTX2 Format** reuses encoded source levels when possible. Changes to orientation, alpha premultiplication, image size or mipmaps can require decoding and re-encoding into the same format. Standard glTF KTX2 textures normally require Defold's Y flip, so keeping the format does not guarantee that the encoded data is reused. Re-encoding can introduce additional quality loss, including with this option enabled. + +Ensure the retained source format is supported on your target devices. The option does not add runtime decoders or GPU format support. If a source format is unsuitable for a target, disable the option for that platform and choose compatible output formats and compression settings. + ## Texture formats Graphics hardware textures can be processed into uncompressed or *lossy* compressed data with various numbers of channels and bit depths. Hardware compression that is fixed means that the resulting image will be of a fixed size, regardless of the image content. This means that the quality loss during compression depends on the content of the original texture. diff --git a/docs/en/manuals/tilesource.md b/docs/en/manuals/tilesource.md index 1a940d60..4bdbc989 100644 --- a/docs/en/manuals/tilesource.md +++ b/docs/en/manuals/tilesource.md @@ -50,28 +50,33 @@ Collision ## Tile source flip-book animations -To define an animation in a tile source the animation frame tiles must lie next to each other in a sequence left to right. The sequence can wrap from one row to the next. All newly created tile sources have a default animation named "`anim`". You can add new animations by right clicking the tile source root in the *Outline* and selecting Add ▸ Animation. +To define an animation in a tile source, select the tiles to play using the animation's *Frames* property. Tiles can appear in any order, including repetitions, so you do not need to rearrange the source image. All newly created tile sources have a default animation named "`anim`". You can add new animations by right clicking the tile source root in the *Outline* and selecting Add ▸ Animation. Selecting an animation displays the animation *Properties*. -![Tile Source animation](images/tilemap/animation.png) - Id : The identity of the animation. Must be unique for the tile source. -Start Tile -: The first tile of the animation. Numbering starts at 1 in the top left corner and goes to the right, line by line down to the bottom right corner. +Frames +: The tile numbers in animation order, separated by commas. Numbering starts at 1 in the top left corner and goes to the right, line by line down to the bottom right corner. You can repeat tile numbers and use inclusive ranges in either direction. + +| Frames | Expanded sequence | +| --- | --- | +| `1, 3, 6, 3` | `1, 3, 6, 3` | +| `1-4, 8` | `1, 2, 3, 4, 8` | +| `4-2` | `4, 3, 2` | + +The editor displays consecutive runs of at least three frames as ranges. For example, `1, 2, 3` becomes `1-3`, while `1, 2` stays as two tile numbers. Frame order and repetitions are preserved. The list must contain at least one frame, and every tile number must exist in the source image. -End Tile -: The last tile of the animation. +*Frames* replaces *Start Tile* and *End Tile*. The editor converts valid ranges in older tile source files to frame lists. For editor scripts, use the `frames` integer array instead of `start_tile` and `end_tile`; see [Editing tilesources](/manuals/editor-scripts/#editing-tilesources). Playback -: Specifies how the animation should play: +: Specifies how the animation should play through the *Frames* list: - `None` does not play back at all, the first image is displayed. - `Once Forward` plays the animation one time from the first to the last image. - `Once Backward` plays the animation one time from the last to the first image. - - `Once Ping Pong` plays the animation one time from the first to the last image and then back to the first image. + - `Once Ping Pong` plays the animation one time from the first to the last image and then back to the second image. - `Loop Forward` plays the animation repeatedly from the first to the last image. - `Loop Backward` plays the animation repeatedly from the last to the first image. - `Loop Ping Pong` plays the animation repeatedly from the first to the last image and then back to the first image. diff --git a/docs/en/manuals/unity.md b/docs/en/manuals/unity.md index 47e3b586..254e9c17 100644 --- a/docs/en/manuals/unity.md +++ b/docs/en/manuals/unity.md @@ -164,7 +164,7 @@ The table below presents similar Unity components for quick lookup, with links f |---|---|---| | [Sprite](/manuals/sprite/) | Sprite Renderer | In Defold, you can change the tint (color property) only via code. | | [Tilemap](/manuals/tilemap/) | Tilemap / Grid | Defold has a built-in Tilemap Editor that supports square grids (but there’s an extension for, e.g. [Hexagon](https://github.com/selimanac/defold-hexagon/)) and has no built-in autotiling rules. Tools like [Tiled](https://defold.com/assets/tiled/), [TileSetter](https://defold.com/assets/tilesetter/) or [Sprite Fusion](https://defold.com/assets/spritefusion/) have export to Defold options. | -| [Label](/manuals/label/) | Text / TextMeshPro | Since Defold 1.13.2, Label components and GUI text nodes support built-in [rich text markup](/manuals/font-richtext/) for colors, gradients, outlines and animated effects. A separate [RichText extension](https://defold.com/assets/richtext/) is also available. | +| [Label](/manuals/label/) | Text / TextMeshPro | Label components and GUI text nodes support built-in [rich text markup](/manuals/font-richtext/) for colors, gradients, outlines and animated effects. A separate [RichText extension](https://defold.com/assets/richtext/) is also available. | | [Sound](/manuals/sound/) | AudioSource | Defold has only a global sound source (not spatial). There is an official [FMOD extension](https://github.com/defold/extension-fmod) for Defold. | | [Factory](/manuals/factory/) | Prefab Instantiate() | In Defold, a Factory is a component with a specific prototype (prefab). | | [Collection Factory](/manuals/collection-factory/) | - (No direct component equivalent) | A Collection Factory component in Defold can spawn multiple Game Objects with parent-child relationships at once. | @@ -590,7 +590,7 @@ Here’s a comparison: |-|-|-| | `init()` | `Awake()` / `Start()` / `OnEnable()`| Defold has a single initialization entry point and callback - init(). It is called on every component on its creation. | | `on_input` | Input Methods | Defold receives inputs, when [input focus is set for the script](/manuals/input/#input-focus). Processed first in the update loop. | -| `fixed_update()` | `FixedUpdate()` | Called at fixed timestep. To enable it in Defold, you have to set the `Use Fixed Timestep` - [details](https://defold.com/manuals/project-settings/#use-fixed-timestep). Since 1.12.0 it runs before `update()`. | +| `fixed_update()` | `FixedUpdate()` | Called at fixed timestep. To enable it in Defold, you have to set the `Use Fixed Timestep` - [details](https://defold.com/manuals/project-settings/#use-fixed-timestep). It runs before `update()`. | | `update()` | `Update()` | Called once per frame with delta time. | | `late_update()` | `LateUpdate()` | Called after `update()`, just before the frame renders. Available since 1.12.0. | | `on_message` | Message Receiver | Defold's core callback for receiving messages. Processed when any message is in a queue. | diff --git a/docs/en/manuals/windows.md b/docs/en/manuals/windows.md index 56613699..8a1ff2d3 100644 --- a/docs/en/manuals/windows.md +++ b/docs/en/manuals/windows.md @@ -7,6 +7,10 @@ brief: This manual describes how to build and run Defold applications on Windows Developing Defold applications for the Windows platform is a straight forward process with very few considerations to make. +## Graphics backends + +Windows builds use OpenGL by default. Use **Graphics (Windows)** in an [application manifest](/manuals/app-manifest/#graphics) to select OpenGL, Vulkan or DirectX 12 (**DX12**). You can include multiple backends to allow fallback when the preferred backend is unavailable. + ## Project settings Windows specific application configuration is done from the [Windows section](/manuals/project-settings/#windows) of the *game.project* settings file. diff --git a/docs/en/manuals/zerobrane.md b/docs/en/manuals/zerobrane.md deleted file mode 100644 index cb1d867e..00000000 --- a/docs/en/manuals/zerobrane.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -title: Debugging with ZeroBrane Studio -brief: This manual explains how to use ZeroBrane Studio to debug Lua code in Defold. ---- - -# Debugging Lua scripts with ZeroBrane Studio - -Defold contains a built-in debugger, but it is also possible to run the free and open-source Lua IDE _ZeroBrane Studio_ as an external debugger. ZeroBrane Studio needs to be installed in order to use the debugging features. The program is cross-platform and runs on both macOS and Windows. - -Download "ZeroBrane Studio" from http://studio.zerobrane.com - -## ZeroBrane configuration - -In order for ZeroBrane to find the files in your project, you need to point it to the location of your Defold project directory. A convenient way of finding this out is by using the Show in Desktop option on a file the root of your Defold project. - -1. Right click on *game.project* -2. Choose Show in Desktop - -![Show in Finder](images/zerobrane/show_in_desktop.png) - -## To set up ZeroBrane - -To set up ZeroBrane, select Project ▸ Project Directory ▸ Choose...: - -![Set up](images/zerobrane/setup.png) - -Once this has been set up to match the current Defold project directory, it should be possible to see the directory tree of the Defold project in ZeroBrane, and to navigate and open the files. - -Other recommended, but not necessary configuration changes can be found further down in the document. - -## Starting the debugging server - -Before starting a debugging session, the ZeroBrane built-in debugging server needs to be started. The menu option for starting it can be found under the Project menu. Just select Project ▸ Start Debugger Server: - -![Start debugger](images/zerobrane/startdebug.png) - -## Connecting your application to the debugger - -Debugging can be started at any point in the lifetime of the Defold application, but needs to be actively initiated from Lua script. The Lua code to start a debugging session looks like this: - -::: sidenote -If your game exits when `dbg.start()` is called, it might be because ZeroBrane has detected a problem and sends the exit command to the game. For some reason, ZeroBrane needs a file opened to start the debug session, otherwise it will output: -"Can't start debugging without an opened file or with the current file not being saved 'untitled.lua')." -In ZeroBrane, open the file you added `dbg.start()` to fix this error. -::: - -```lua -dbg = require "builtins.scripts.mobdebug" -dbg.start() -``` - -By inserting the above code into the application, it will connect to ZeroBrane's debugging server (through "localhost", by default) and pause at the next statement to be executed. - -```txt -Debugger server started at localhost:8172. -Mapped remote request for '/' to '/Users/my_user/Documents/Projects/Defold_project/'. -Debugging session started in '/Users/my_user/Documents/Projects/Defold_project'. -``` - -Now it is possible to use the debugging features available in ZeroBrane; you can step, inspect, add and remove breakpoints etc. - -![Stepping](images/zerobrane/code.png) - -Should the connection attempt fail (possibly because the debugging server is not running), your application will continue to run as normal after the connection attempt has been made. - -## Remote debugging - -As debugging happens over regular network connections (TCP), this allows for debugging remotely. This means it is possible to debug your application while it is running on a mobile device. - -The only change needed is to the command which starts the debugging. By default, `start()` will try to connect to localhost, but for remote debugging, we need to manually specify the address to ZeroBrane's debugging server, like this: - -```lua -dbg = require "builtins.scripts.mobdebug" -dbg.start("192.168.5.101") -``` - -This also means it is important to make sure to have network connectivity from the remote device, and that any firewalls or similar software allows TCP connections through on port 8172. Otherwise the application might stall when launching when it attempts to make the connection to your debugging server. - -## Other recommended ZeroBrane setting - -It is possible to make ZeroBrane automatically open Lua script files during debugging. This makes it possible to step into functions in other source files without having to open them manually. - -The first step is to access the editor configuration file. It is recommended that you change the user version of the file. - -- Select Edit ▸ Preferences ▸ Settings: User -- Add the following to the configuration file: - - ```txt - - to automatically open files requested during debugging - editor.autoactivate = true - ``` - -- Restart ZeroBrane - -![Other recommended settings](images/zerobrane/otherrecommended.png) diff --git a/docs/en/shared/graphics-api.md b/docs/en/shared/graphics-api.md index ee40b620..6ac4b581 100644 --- a/docs/en/shared/graphics-api.md +++ b/docs/en/shared/graphics-api.md @@ -1,10 +1,12 @@ | System | Graphics API | Note | |----------|----------------------------|--------------------------| -| macOS | Metal, OpenGL 3.3 or Vulkan | Metal is the default since Defold 1.14.0; Vulkan via MoltenVK | -| Windows | OpenGL 3.3 or Vulkan 1.1 | | +| macOS | Metal, OpenGL 3.3 or Vulkan | Metal is the default; Vulkan via MoltenVK | +| Windows | OpenGL 3.3, Vulkan 1.1 or DirectX 12 | OpenGL is the default; select backends in the [app manifest](/manuals/app-manifest/#graphics) | | Linux x86-64 | OpenGL 3.3 or Vulkan 1.1 | | | Linux ARM64 | OpenGL ES or Vulkan 1.1 | EGL/GLES is the default | -| Android | OpenGLES 3.0 or Vulkan 1.1 | Fallback to OpenGLES 2.0 | +| Android | OpenGLES 3.0 or Vulkan 1.1 | Optional fallback to OpenGLES 2.0 (see below) | | iOS devices | OpenGLES 3.0, Metal or Vulkan | OpenGLES is the default; Vulkan via MoltenVK | -| iOS simulator | Metal | Always Metal since Defold 1.14.0 | -| HTML5 | WebGL 2.0 or WebGPU | Fallback to WebGL 1.0 | +| iOS simulator | Metal | Always Metal | +| HTML5 | WebGL 2.0 or WebGPU | Optional fallback to WebGL 1.0 (see below) | + +Since Defold 1.14.1, OpenGLES 2.0 and WebGL 1.0 shaders are excluded by default. To support these graphics APIs, disable [Exclude GLES 2.0](/manuals/project-settings/#exclude-gles-20) in *game.project* (`shader.exclude_gles_sm100 = 0`). diff --git a/docs/en/tutorials/shadertoy.md b/docs/en/tutorials/shadertoy.md index 5eaa4c2e..6631c44e 100644 --- a/docs/en/tutorials/shadertoy.md +++ b/docs/en/tutorials/shadertoy.md @@ -172,7 +172,7 @@ We will use a modern pipeline with GLSL in version 140 - to do so, we'll declare ``` The exact `aspect` value depends on how the example is set up. If the effect is rendered on a full-screen quad with a known display size, the aspect ratio can be hardcoded for the tutorial. If the effect needs to support arbitrary window sizes, pass the resolution as a fragment constant and place it inside a GLSL 140 uniform block. - Time is also set up here. It is passed to the shader as `uniform float iGlobalTime`. Defold (since 1.12.3) provides time to shaders via a special `Time` constant that we'll use. + Time is also set up here. It is passed to the shader as `uniform float iGlobalTime`. Defold provides time to shaders via a special `Time` constant that we'll use. In modern Defold, non-opaque uniforms are declared inside uniform blocks. In the fragment shader we declare it like this: @@ -323,7 +323,7 @@ Save the fragment shader program. The model should now be nicely textured with a ## Animation -The final piece of the puzzle is the introduction of time to make the stars move. Defold (since 1.12.3) provides this automatically through a fragment constant of type `Time`. +The final piece of the puzzle is the introduction of time to make the stars move. Defold provides this automatically through a fragment constant of type `Time`. 1. Open *star-nest.material*. 2. Add a *Fragment Constant* and name it "time".