Repository navigation
Sync upstream develop (2026-10-07): UI redesign part 4, Component SDK C modules, 0.22.0, asset browser fixes - #27
Merged
Conversation
…oldengine#147) * [Feature] Selection: several entities at once, each with its box, one gizmo for them all and one undo step The selection could hold one entity. It now holds several, in the order they were selected; the last one stays the one the Inspector names, and the many places that set the one selected entity still select it alone. - SelectionManager keeps selectedEntities beside selectedEntity, with selectEntities(_:) and toggleSelection(of:). SelectionDelegate gains didSelectEntities and didToggleEntity, with default implementations. - One gizmo for all of them: it stands in the middle of their boxes and moves each by the same distance, turns them round it and scales them and their distance from it, each in its parent's measure. Entities under another selected one follow their parent. After a drag the gizmo goes back to the middle. - A drag is one undo step, "Transform N Entities". - Each selected entity shows its box: the highlight pass draws one per entity from a unit box, in the entity's own space, so the boxes follow what the gizmo moves with nothing rebuilt. An entity that draws nothing gets a small box where it stands. With one entity selected nothing changes. - F frames all of them. Nothing selects several yet: the next two commits bring the rectangle and the Shift click in the viewport, then the hierarchy and the Inspector. * [Feature] Viewport: a rectangle selects what stands inside it, and a Shift click adds an entity or takes it out A drag of the left button that takes no gizmo handle draws a dashed rectangle over the viewport, and its release selects what stands inside it. - An entity is inside when all of its box is: every corner in front of the camera and within the rectangle. What reaches out of it is left out, so the floor under what the rectangle is drawn around, or the wall behind it, is not selected however much of it shows. A light or an entity written in code, which has no box, is inside where it stands. - Of what draws meshes, only what is seen is selected: what stands behind a wall or under a floor is left out though it is inside. An editor-only pass tells: at the release it draws the scene's meshes into a texture of entity numbers the size of the rectangle and a compute kernel gathers which of them show, about a millisecond for a whole viewport. A locked entity hides what is behind it and is not selected; a hidden one hides nothing. When the pass cannot run, being inside is enough. - With Command held the rectangle selects the assets those entities belong to, as a Command click does. With nothing inside, the selection is cleared. - A Shift click adds the entity under the pointer to the selection or takes it out; a Shift drag with a selection still moves that entity. - No rectangle is drawn while playing, over a locked preview or with the editor disabled, and a canvas that loses the keyboard takes it away without selecting. - The hints gain "Add or remove: Shift Click", and "Select" says "Click or drag". * [Feature] Hierarchy and Inspector: several entities selected The panels follow a selection of several entities. - Hierarchy: every selected row is highlighted and the footer counts them. A Shift or Command click on a row adds it to the selection or takes it out; a plain click selects it alone, as before. Deleting an entity from the menu leaves the rest selected. - From Play to Stop the hierarchy selects nothing, as the viewport does not, and the footer says so. - Inspector: with several selected it says how many, unless it is pinned to an entity. With one it shows that entity as before. - H hides every selected entity. * [Test] The highlight box test looks where no edge is, at any pixel density test_anEntityThatDrawsNothing_hasItsBoxWhereItStands checked that the box is drawn as lines by looking at the middle of its near face. The box stands to the right of the view, so its far face shows through the near one a little to the left, and the far face's right edge passes two pixels from that middle where a point of the window is one pixel, as on the CI runner: the test found a line there and failed. On a display with two pixels per point the edge is four pixels away and it passed. It now looks between that edge and the near face's own, clear of both, and says so when a box is too few pixels wide to tell. Checked at both sizes. * [Patch] Rectangle selection: only what reaches into the rectangle is drawn to tell what is seen At each release of the rectangle the pass that tells what is seen drew every mesh of the scene, and the selection asked whether an entity can be selected before it asked where the entity stands. Both grew with the scene: over 100,000 entities one release held the main thread for 625 ms in a debug build and 236 ms in a release one. Nearly all of that came before the wait for the GPU, which took about 20 ms. An entity outside the rectangle neither shows in it nor hides anything in it, so it is left out of the pass now. MarqueeGeometry.Frustum is made once for a rectangle and tells a box inside, across or outside it, by the box the engine culls by. Where an entity stands is asked first, and the rest only of what the rectangle reaches. The same release takes 150 ms and 36 ms, and the pass draws 90 of the 100,000 entities. What is selected is the same: a test compares both ways on 120 cubes, some hiding others, over five rectangles, and another tries 3,000 boxes to see that none told outside shows in its rectangle. * [Patch] Gizmo on several entities: only those with both transforms, and no made-up place in the world A scale of several entities took an entity's place under its parent for its place in the world when the entity had no world transform, which is wrong under a parent that was moved or turned. A turn took the gizmo's own place. The engine gives an entity its two transforms together and takes them away together, so neither was reached, but nothing said so where the gizmo's entities are chosen. takesGizmo and gizmoTransformTargets now ask for both transforms, with hasBothTransforms, and the two fallbacks are gone: the place in the world is always the one the engine keeps. --------- Co-authored-by: Javier Segura <javier@miolabs.com>
…t only CShaderTypes (untoldengine#148) * [Feature] Component SDK: pass the module map of every C module the engine was built with The engine is built without library evolution, so a plugin that imports UntoldEngine makes the compiler load every module the engine imports. The editor passed the module map of CShaderTypes and nothing else, so one more C module on the engine side (a C target of its own, or one that comes with a Swift package such as swift-atomics) broke every plugin build with "missing required module". An editor run from source now passes the module map of every C target it was built with, CShaderTypes first: - The module map the build system generated for the target, beside the CShaderTypes one, in both SwiftPM layouts and in Xcode's. - For a target that brings its own module.modulemap, the one in its package. The packages of a build are the ones SwiftPM's workspace-state.json lists: a cloned one in `checkouts` (SwiftPM) or `SourcePackages/checkouts` (Xcode), one used by path where it is. A target counts when it left objects in the build, so a target the engine declares and the editor does not use is not passed, and a target that is gone from its package and left its objects behind is not passed either. A built C target without any module map is reported in the Plugins tab and the console, because the compiler would only name the missing module. A packaged editor passes the C modules its sdk.json lists under "cModules"; an sdk.json without the list has CShaderTypes alone. With the engine as it is the arguments do not change. * [Feature] Component SDK: package every Swift and C module the editor was built with The app bundle shipped three Swift modules by name and the CShaderTypes headers, found at a fixed path in the engine's checkout. A plugin compiled by a packaged editor needs whatever the engine imports, so the bundle now ships what the editor was built with: - Every Swift module of the build except the editor's own (the engine, the kit, a plugin the editor links, and a module of another package that one of them imports, such as Atomics). - Every C module of the build, by the rule the editor follows when run from source: scripts/copy-component-sdk-c-modules.py copies the public headers of each into ComponentSDK/<Module>/ with a module map that names them by relative path. For a generated module map that is the same file the script wrote for CShaderTypes; a target's own module map is shipped as it is. - sdk.json lists the C modules under "cModules", which is what the editor passes. verify-component-sdk.sh compiles its fixture with the module maps sdk.json lists, refuses a module map that names a path outside the SDK, and checks the exported symbols of every Swift module of the SDK, not only the engine's and the kit's. With the engine as it is the bundle is the same, but for the new key in sdk.json. Two side effects: CShaderTypes is found when the engine is used by path, where it was missing before, and the warning about UntoldGaussianTwins.swiftmodule on an editor that does not link it is gone. The tests run the script on build folders shaped like the real ones and check that it ships the modules the editor finds when run from source, and that a packaged editor passes each of them. --------- Co-authored-by: Javier Segura <javier@miolabs.com>
* [Chores] Fixed warnigns in build and test * [Chores] Formatted files
* [Patch] Hide cook-source folders in asset browser, reveal via context menu Source folders sharing a stem with a runtime asset (e.g. bl/ for bl.untoldpack) cluttered the listing; they're now hidden and reachable through a "Reveal Source Folder" menu item. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * [Chores] Formatted files --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
…URLs (untoldengine#155) The editor no longer serves demo/asset-pack content from AWS, so launch straight into the full editor instead of the Explore gallery, hide the Explore tab in the Asset Browser, and remove the CloudFront URLs from the demo and asset-pack catalogs. Updated tests to match the now-empty catalogs.
…'s C modules, release 0.22.0, the asset browser's cook-source folders, the intro gallery skipped (untoldengine#147, untoldengine#148, untoldengine#149, untoldengine#150, untoldengine#151, untoldengine#154, untoldengine#155) # Conflicts: # Package.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Brings the fork's
developup to upstreamdevelopat2de8117: seven commits.One conflict, in
Package.swift: the fork keeps its dependencies (the fork engine'sdevelopandUntoldGaussianTwinsonfork-engine); upstream's note of the release pin moves to 0.22.0.InspectorView.swift,EditorView.swiftandUntoldEditorApp.swiftmerged by themselves.1261 tests pass, 1 skipped as before.