64bbfe9ed3402f2fb00a95a116e4d6531c54bb21
51
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
e6dc105134 |
Point clouds: insert PLY, XYZ and PTS scans as a modelling reference (#5151) (#5381)
* Point clouds: insert PLY, XYZ and PTS scans as a modelling reference (#5151) A point cloud is kept in the design as a reference, drawn as depth-tested dots and never a body. - io: a PLY reader (ASCII, binary little/big endian; x, y, z of any numeric type, optional colours, other elements skipped; counts checked against the file) and XYZ/PTS text, thinned evenly past max_points. PLY meshes with faces can also come in through file.insert_mesh. - doc: Document.point_clouds (shared f32 points relative to an f64 origin, colours, units, rigid placement, size and colour), stored as a binary container part; format change in pending/point-clouds.rs. - engine: pointcloud.insert / edit / delete / list; doc.open opens a cloud as a new design; selection.delete takes point_clouds; view bounds include them. - gpu: an instanced point-sprite pipeline (16 bytes a point). - ui: Browser Point Clouds folder with eyes, menu and an Edit Point Cloud card; drop, Open, Insert and file dialogs take .ply/.xyz/.pts; a CPU viewport fallback; messages in en, en-GB, ja, zh, de and ko. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Point clouds: colour by the file, one colour or height, from the UI (#5151) The Edit Point Cloud card gets Color By (File Colors, Single Color, Height). Height is a blue-to-red ramp over design Z, between the cloud's own two heights or, by default, a range worked out from the points (all but the lowest and highest 2 %, from an even sample). pointcloud.insert and pointcloud.edit take color_by and height_range; pointcloud.list reports them. The colour of each point is worked out in one place (PointCloud::shade) for the GPU and CPU viewports. Also: the card's dropdowns compare the picked index (a dropdown's response doesn't report the pick, so File Units did not change either). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Point clouds: integrate format registration and viewport caches (#5151) * Point clouds: satisfy current UI audits and document comparisons (#5151) Route model RGB data through the theme conversion boundary, provide a compact ribbon label, and include point clouds in the new document comparison. Gate the Unix-only CLI-link helper and test so Windows all-target checks remain buildable after the rebase. * Point clouds: isolate translations for current main (#5151) Move the existing 74 messages unchanged into one pending locale file and attribute it through a pending row, following the current repository workflow. Repository checks, 50 tooling tests, final workspace Clippy, wasm and generated-catalog equality checks passed after the rebase. * Point clouds: fit the rebased code to main's GpuTarget and Frame Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Compare point clouds when reusing placement-independent results Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Point clouds: complete command help and required translations (#5151) * Point clouds: size the save cap from the raised limit after the rebase Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: bherbruck <brennen.herbruck@gmail.com> |
||
|
|
aae2c5e417 |
Assemblies: edit a linked component in place, with the assembly around it (#7672) (#7819)
* Links: update linked designs that changed while the assembly's tab was away A design coming back to its tab compares the modification time and size of its linked design files with what they were when it went to the background, and runs Update Links on the worker thread for those that changed: saved in another tab, another window or by a checkout. Preference update_changed_links (Design, Linked designs) turns it off. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Docs: the assembly guide says linked designs update when their tab returns Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Links: Vietnamese strings, now that vi is a complete catalog Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Links: remember what each design last read, so an update that fails is tried again A design's linked files are now recorded as the design last read them: when Update Links reads a link without an error, or when the link is first seen. Coming back to the tab reads again what differs, one link per run, so a file that cannot be read holds up no other and is tried again the next time, and a part changed while the assembly was shown is taken up on its next return. Closing several tabs together reads nothing on the way, and the web build, which keeps no file times, looks at nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Links: no read during a save-changes prompt, records for adopted designs and missing files A tab shown to answer "save changes?" reads no link before its save, and Cancel there or on a batch lets the tab left in front read what it skipped. A design opened in place of the blank one records its links at once, a link whose file is missing is recorded as missing so it is read when the file comes back, and a read queued for a design that is no longer shown by the time it starts is dropped. More changed links than can wait at once are read on the next return. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Assemblies: edit a linked component in place, with the assembly around it Activating a linked component opens the design it comes from in a tab of its own, with the rest of the assembly drawn faded around it where the component sits, so the part's own history, browser and commands are at hand. Finish Editing in the browser saves the part, goes back to the assembly and closes the part's tab when the edit opened it; coming back to the assembly updates the changed link (or Finish Editing runs Update Links when that is turned off). Update Links in the part also reads the assembly's links again, off the window thread, and redraws the assembly around the part; a result for an assembly changed meanwhile is dropped with a message. The part is an ordinary tab, so saving, autosave, recovery, closing and quitting treat it as any other design. The model scene's ghost triangles are now drawn (only the preview's were). Preference edit_linked_in_place turns it off. Builds on the update of changed links when an assembly's tab returns. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Edit in place: a double-click opens it, Activate only activates A double-click on a linked component edits it in place, in the browser as on a face in the view (around the placement clicked), and the component's menu gets Edit in Place. Activate and the browser's radio button make it the active component as they always did, so a linked component can still be activated without opening its design. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Double-click on a component's face: edit a linked one in place, activate any other A double-click on a face in the view activates the component the body belongs to, at that placement, as a double-click on its row does; a linked one is edited in place. Bodies of the design itself or of the active component are left alone, and so is a double-click with a modifier. One preference, double_click_components, covers both gestures. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Edit in place: fixes from review An edit whose part never opens is forgotten instead of starting on a later open of the same file, and the web build starts the edit after its synchronous open. Finish Editing goes on only for a save into the linked file and in the part's own tab, waits for a "changed on disk" answer, and says so when the part was saved elsewhere. Showing the assembly no longer drops a refresh, which now records the links it read so coming back reads nothing twice. The faded assembly is worked out once per picture, a bad mesh index skips its whole triangle, and the last two status texts come from the catalogs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Edit in place: Finish Editing on the MODEL tab and the mouse's back button Finish Editing is a command now, component.finish_edit, with its schemas: the app window answers it, anywhere else nothing changes, as with view.fit. While a linked design is edited in place the MODEL tab ends with a FINISH EDITING panel, pinned at the right as FINISH SKETCH is, with a new left-arrow icon; the browser keeps only the line naming the assembly. The mouse's back button, or a keyboard's Back key, finishes too unless a dialog, tool or sketch is open. The assembly guide describes editing in place. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Edit in place: fixes from the second review Saving the assembly waits while it reads its links for the part Finish Editing waits for dialogs, tools, sketches and prompts open in the part, also when run as a command The assembly reads the edited part explicitly when it does not check its links on its own The FINISH EDITING panel cannot be customized A tab opened by an edit stays that edit's to close when the part is entered again The mouse's back button finishes editing; the keyboard's only while no text field has focus Refreshing the assembly keeps its selection and active component Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Edit in place: fixes from the third review component.finish_edit run as a command opens nothing and answers with an error when it cannot finish; engine.batch and engine.script refuse it A double-click or Edit in Place while a dialog, tool or sketch is open in the assembly keeps it open What changes in the assembly while it reads its links without changing its document stays: picks, activation, components dragged but not captured Showing the assembly while it reads its links starts no second read A new or opened design in the part's tab ends the edit Finish Editing keeps the part's tab open while its agent chat runs Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Edit in place: Update Links run as a command in the part refreshes the assembly too Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Edit in place: the ribbon button reads Finish Edit, as Finish Sketch does A bare "Finish" took the catalogs' surface-finish translation (German "Oberfläche"). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Edit in place: fixes from the fourth review Finish Edit waits while the part's agent is in the middle of its turn, instead of keeping the tab of any chat open A part saved while its assembly refreshes is read again when the edit finishes: the refresh records the files as it found them A double-click on a linked component while something is open in the assembly says so instead of activating it Commands are recognised in any spelling the engine takes, so engine.batch and engine.script cannot slip Finish Edit through Update Links run as a command refreshes the assembly from the control channel only, not for the app's own reads Moves of components the refresh removed are not carried over, and a refusal is one message The command description and the guide say that the command does not save the part Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Edit in place: the command is Finish Edit, as Finish Sketch is Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Edit in place: a command to start it, and fixes from the full review Added component.edit_in_place {component, path?}: the double-click and Edit in Place in the menu run it, and as a command it asks nothing, so a network location not allowed yet or a design open elsewhere makes it fail instead Finish Edit asked by the part's own agent finishes once that agent's turn ends; the button still waits for the turn The parameters and design properties panels, with text typed and not applied yet, hold up entering and finishing an edit A refresh is not taken up under an undo, a queued command or a feature still being computed in the assembly Refusals say what holds them up (a refresh, a file being read or written) instead of nothing The browser strip names the assembly that is refreshing, not any assembly The schema description says the command does not save the part Korean strings for every new message Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Edit in place: fixes from the second full review The MCP batch tool refuses component.edit_in_place and component.finish_edit as steps instead of sending them one by one Edit in Place asked while the assembly's agent is in its turn opens the part once the turn ends; a double-click then is refused rather than stopping the agent Both commands answer queued: true when they wait for the agent's turn, and stopping the agent forgets what it queued An undo, a queued command or a delete check running in the design holds up entering and finishing an edit A refresh redraws every edit of the assembly, the parts in other tabs too In an assembly never saved, a double-click activates the linked component as before The control and MCP docs list the new batch and script refusals, and the commands list every way they fail Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Edit in place: fixes from the third full review The MCP batch tool refuses the two commands however a step names them, an execute step too A queued Edit in Place is checked fully when asked for, a second one is refused, and both queued requests wait for what runs in the design instead of being dropped Disconnecting the agent forgets what it queued, as stopping it does Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Edit in place: help text for the Finish Edit button main now requires help for every toolbar command (#7134), and Finish Edit is one. Written in every language the branch's catalog carries. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
a4d1b5b6a9 |
Viewport: fewer ambient occlusion samples while the view moves (#7165) (#7214)
* feat: Fewer ambient occlusion samples while the view moves (#7165) - Draw AO with 8 samples while the view moves, 32 once it has held still for 0.25 s - Share the settle tracking with adaptive supersampling and repaint when it settles - ui.screenshot waits for the full-quality frame (at most half a second) - Test the sample choice, the uniform slot, and ghosting at both counts * fix: Set the AO sample count in the scale test frame - scale_tests.rs, new on main, builds a gpu::Frame without ao_samples - Use AO_SAMPLES, as the other still-frame builders do --------- Co-authored-by: P'tite Tête <asso@ptitetete.com> |
||
|
|
110efa3598 | Render: allow picking in the product view with a Body, Face or Component filter and outline the selection in the product pass only (#6426) | ||
|
|
e0e2c566e7 |
Viewport: clear new resolve targets so AMD Direct3D 12 shows the scene (#6828) (#7399)
* claim: #6828 * Viewport: clear new resolve targets so AMD Direct3D 12 shows the scene (#6828) With anti-aliasing above 1x the scene is drawn multisampled and resolved into textures that nothing but the resolve writes. wgpu counts the resolve as their first write and never clears them. Direct3D 12 requires a render target placed in reused memory to be cleared, discarded or copied over first, and some AMD Radeon drivers then show the uncleared texture as transparent, a flat colour or speckles: no grid, origin planes or bodies (#6828, #7157, #6613, #7052). Each new resolve texture (the frame's colour and the see-through sums) is now cleared once when it is made. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
5dc95ef7f6 |
Viewport: a frame the GPU has no memory for is drawn smaller, not a crash (#7296) (#7398)
* claim: #7296 * Viewport: a frame the GPU has no memory for is drawn smaller, not a crash (#7296) The viewport's offscreen frame, its see-through targets and the cached still picture were created with no error scope, so a texture the card had no video memory for went to wgpu's default handler and closed the app ("wgpu error: Out of Memory" on a GT 740). They are now created under error scopes; a refused frame lowers the renderer's frame budget and is asked for again smaller (less supersampling, or the view's own frame drawn smaller and filtered up), refused OIT targets fall back to sorted see-through surfaces, and the status line says once that the view is drawn at a lower quality. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Locales: Arabic and Hebrew for the new strings ar and he are complete catalogs on main now (#3458): every new message needs them. The pending-messages test compares right-to-left messages in display order once #7532 lands (#7527). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * GPU memory test: targets take the OIT flag main added (#7296) The test's two GpuTarget initializers predate the oit field and no longer compiled once the branch met main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Locales: Vietnamese for the new strings Vietnamese became a complete catalog on main (#5823), so every new English message needs it too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
3574956d29 |
Graphics: the window no longer waits for Direct3D 12 shader compiles (#4860) (#7288)
* claim: #4860 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Graphics: the window no longer waits for Direct3D 12 shader compiles (#4860) On Direct3D 12, wgpu compiles every pipeline's shaders with FXC when the pipeline is made, and nothing is kept between launches, so the window waited seconds for the viewport. - The GPU tessellation shader, most of that time, compiles on a thread of its own. Bodies are built on the CPU until it is ready, then drawn from their plans; where it never compiles they stay on the CPU, as before. - The viewport's pipelines build in parallel, one job per fragment shader (solidcraft_gpu::concurrent). A job that errs, panics or cannot start runs again on the calling thread, so errors reach the caller's scopes. Threads only on Vulkan, Metal and D3D12 with FXC. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
1c109be836 |
Headless pictures: no highlight left over from the picture before (#7225) (#7326)
* claim: #7225 * fix: headless pictures no longer keep the previous picture's highlight Capturer::rgba_highlighted left the highlight slot empty when a picture had no highlight. The renderer keeps its last highlight scene while the slot is empty, so a selected edge's band drawn for one picture showed in the next one on the same capturer. The depth tests share their capturers across test threads, so they failed at random: an edge "192 of 612 px drawn", a washer showing through its plate, a cut showing what lies behind it. A picture now always gets a highlight scene of its own, empty without one. Clearing the leak showed that a_selected_edge_on_a_grazing_face_draws_whole passed at 88 degrees in a design of radius 30 only by counting the leaked band: its reference line lies 143 mm behind the sheet's middle, past that design's far plane, and drew nothing. The small design now holds the edge. New test: a_picture_without_a_highlight_shows_none_of_the_one_before. Full `--test depth` runs on Apple silicon: 10 of 10 failed before, 0 of 20 after. |
||
|
|
76879f8b39 |
Viewport: write hover edges as one record per line, colours interned once (#7416)
Hovering many bodies re-emits every edge in the highlight's colours. Each edge interned its three colours into the palette again, each segment was written in eight small appends, and segments without their faces' normals encoded the same zero normals again. Lines are now one record, the edge colours are interned once per highlight, the buffers are reserved per edge, and the shared width word is worked out once. Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
514b0c84f9 |
Viewport: hold the blocks the sorted glass stream was taken from (#6970)
The no-OIT glass cache compared the blocks' vertex and run buffers by address without holding them, so a freed buffer's address could come back for other contents. It now holds them and compares with Arc::ptr_eq. Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
ddca1054ab |
Viewport: leave bodies out of the view out of their blocks' draws (#7436)
Instanced placements were culled per view, but a block drew every body in it whatever the camera saw. Blocks now keep each body's vertex span and box; when the view changes, each class's runs are drawn without the bodies whose boxes are out of the view. A block whose bodies are all in view draws its runs as they are. Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
efa2cae0b4 |
Viewport: draw faded and see-through bodies from their plans with OIT (#7423)
* Viewport: palette-indexed scene and incremental appearance updates - Move triangle, line and instance colours and opacity into a per-scene palette (an R32Uint texture, WebGL2-safe); appearance edits update palette entries instead of vertex bytes. - Build CPU body triangles as one canonical vertex stream per block with opaque/glass/faded index lists; an opacity class change rewrites only the index list. - Cache resolved body appearances by a per-body key, so an edit resolves only the bodies whose look changed. - Split the model scene key from the session revision: selection and view-only commands no longer rebuild or upload the model scene. - Replace the O(n^2) section-index lookup and per-placement instance scan with hash lookups. Co-Authored-By: Claude Code <noreply@anthropic.com> * Viewport: skip unchanged palette work when rebuilding - Reuse each body's appearance key while the document is unchanged. - Leave a palette slot alone when its value did not change, and allocate every body's slots once before the build loop. Co-Authored-By: Claude Code <noreply@anthropic.com> * Viewport: measure scene rebuild cost by edit kind An ignored scale test times the scene build after selection, appearance, theme and one-body geometry edits at 200, 1,000 and 5,000 bodies. Co-Authored-By: Claude Code <noreply@anthropic.com> * Viewport: read faded grid alphas through the scene palette The grid-fade tests now resolve line palette indices instead of reading the line record's old colour byte. Co-Authored-By: Claude Code <noreply@anthropic.com> * Viewport: measure rebuild cost on few large meshes Adds the 20/100-torus case where a block rebuild used to re-emit a large part of the model. Co-Authored-By: Claude Code <noreply@anthropic.com> * Viewport: measure rebuild cost on an assembly Unique detailed parts plus one component placed many times, timed for selection, part and component colour, opacity, theme, hide and move. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Viewport: draw block classes as vertex runs, not index lists A body's vertices are three per triangle in mesh order, so each draw class is a few runs of the block's vertex buffer: all-opaque blocks need no index buffer, and an opacity class change uploads nothing. A fragmented class (more than 64 runs) falls back to one index buffer. Each triangle is written as one record into a block reserved up front, which takes the cold scene build of a 7.1M-triangle assembly from 97 ms to 55 ms (main: 83 ms). Also fix reindexing a block whose bodies are drawn elsewhere: it walked the mesh's triangles from that body's start, past its own vertices. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Viewport: draw the highlight's own block, and light faded bodies without copies The highlight scene keeps its feedback (a hovered face, a body copied on the CPU) in a block of its own; since blocks became vertex runs, only the model's blocks were drawn, so that feedback was uploaded and never shown. Draw the highlight's blocks with its triangles. Whole faded and see-through bodies (another component active, or an appearance below full opacity) were lit by copying every triangle on the CPU at each hover change: 85 ms for a design row of 812 bodies. They are now drawn again from the model's own block vertices, in the highlight palette with their slots set to the highlight colour, or as placements of the model's shared triangles. The picture is the same as the copy's. Adds a GPU frame benchmark for document-tree hover (ignored test). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Viewport: count scene uploads, and keep the sorted glass stream across colour edits Renderer::uploads reports the bytes the model scene's last change uploaded (geometry, placements, palette rows, planned colours, re-evaluated vertices). Without order-independent transparency the global glass stream is kept while the blocks' see-through triangles are the same, so a colour edit on a glass body uploads palette rows only. Tests assert both on a GPU. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Viewport: keep palette slots and looks without rehashing every body A rebuild found every body's palette slots by name and wrote them back, allocating and hashing a new key per body, and copied every shown name into a set to check the arena still belongs to the design. Slots are written back only when a body's faces grew, and the looks cache is pruned only when it holds more bodies than are shown. Adds the STEP-file benchmark (SOLIDCRAFT_SCALE_STEP) and the colour command's own time to the assembly benchmark. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Viewport: round-pick construction lines through the scene palette The axis and centre feedback for round picks (#4610) drew with a raw colour; on the palette scene it is interned once like the other construction geometry. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Viewport: draw faded and see-through bodies from their plans with OIT A body faded outside the active component, or see-through, left the GPU tessellation path and was built triangle by triangle on the CPU, so working in a component of a large assembly rebuilt every other body. Where the renderer blends see-through surfaces order-independently (GpuTarget::oit, set by the renderer), a body whose faces share one class is drawn from its plan: chunks are split by class, opaque passes, AO and the section draw only opaque chunks, and the OIT pass draws the rest. The sorted fallback keeps them on the CPU. The model and its highlights decide through one rule (model_plan_class). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Code <noreply@anthropic.com> |
||
|
|
4b327bab1f |
Canvas: the value boxes do not cover the command window (#6608) (#6661)
* claim: #6608 * Canvas: keep value boxes clear of the command window (#6608) * Canvas: describe how value boxes clear the command window (#6608) * Canvas: keep the value boxes clear of the gizmo handles (#6608) * ui-egui: format the value box regression test (#6608) * gpu: the startup MSAA check skips when there is no GPU adapter The check needs a real adapter to draw the multisampled view and to resolve it, so on a machine with no software Vulkan adapter it is skipped, with the reason printed, instead of failing the build. SOLIDCRAFT_REQUIRE_GPU=1 still makes a missing adapter a failure, as in the CI job that has a software adapter. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
e29075376c |
Curvature Map: a scale that lightens steadily from flat to tight (#975) (#6136)
The blue, green, red scale's lightness rose and then fell (L* 44 up to 72 and back to 50), so a flat face and a tight radius looked alike with hue lost, and its upper part merged for a red-green loss. The stops are now dark blue, a middle grey-gold and light yellow in one straight blend, as measured in the issue: L* rises the whole way and every quarter step stays clear for normal, protan, deutan and tritan vision. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
c6d361347f |
Section Analysis: the cap is marked by true depth, so far edges no longer take a cap band (#6328) (#6332)
With a section shown, the marking pass decided where the cap shows (the stencil) and wrote the depth everything after it tests against. #1768 gave it the faces' FACE_BIAS for the second job, so edges draw over their own faces (#1434). For the first job its slope part is unfair: next to an edge where a back face seen through the cut meets a front face, the front face won a band about a pixel wide although the back face is nearer. The cap skipped that band, and the edge line showed through the cut. #6363 marked those samples again from the back faces, pulled toward the eye as far as FACE_BIAS pushes. That closes the gaps beside the edges, but the pull also lets back faces win wherever they lie within the push of a front face, along every body's far silhouettes, and the cap hatches that band. On bherbruck's block, the band away from the cut went from 58 px orthographic and 534 px perspective before #6363 to 618 and 780 with it. In the app, his filleted hub showed it in every frame of a 36-step orbit in both projections. This replaces that pass. While a section is shown the opaque model now draws in four steps (`Cut`): 1. mark: the faces by their true depth (no push): colour, the stencil and depth; 2. a triangle over the viewport sets the depth back to the far plane, colour and stencil kept; 3. push: the faces again with FACE_BIAS, depth only, so the depth is what unsectioned frames have and edges draw over their faces as before; 4. cap: depth only, as #6728 made it; the mark pass has drawn the cap's colour and hatch, as fs_solid draws a back face seen through the cut. The window pass's depth reset and this one are one helper, `depth_reset_pipeline`, for either depth direction, and its passes are built by #6728's `solid_writes`. Unsectioned frames are unchanged. The CPU rasterizer already chose the cap by true depth. Tests (crates/gpu/tests/depth.rs), with the device's float depth and the 24-bit fallback: - a_cut_hides_the_edges_behind_it (new): bherbruck's block cut at y = -16, home view, orthographic and perspective. No edge shows through the cap, and away from the cut the picture is a box of just the kept part's: 0 px orthographic and 1 perspective (main: 618 and 780). - bherbruck's pocket and hub tests from #6363 are kept and pass (pocket 0 px; hub 1 and 2 px over its twelve views, as with #6363's pass). - an_edge_on_a_face_draws_whole_at_any_angle and an_edge_just_behind_a_face_stays_hidden_on_a_large_design also run with a section shown. In the app (safe mode, WARP), with 625 patterned cylinders cut by a section, the frame time is that of main (#6363): 33.5 against 34.3 ms at the home view, 34.1 against 35.2 ms with the model filling the view. Co-authored-by: bherbruck <brennen.herbruck@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
30e9b87b48 |
Render workspace uses the window's graphics backend on Windows (#6592) (#6629)
* claim: #6592 * Keep Windows Render setup on the viewport backend |
||
|
|
4ced1d7bcf |
Viewport: the grid fades with the distance instead of cutting off (#4214) (#4629)
* claim: #4214 * Viewport: the grid fades with the distance instead of cutting off (#4214) The ground grid stopped at a fixed distance from the view, so its edge showed as a cut across the picture. It now fades out with the distance from the middle of the view, and it is gone before either of the two lines that used to cut it: its own edge, and the picture's far plane. Each grid line is drawn in pieces, and each piece is as faint as the fade makes it at the distance where it lies. The 'under' batch is drawn by the overlay pipeline with alpha blending, so the colour's alpha reaches the frame. * The headless grid fades with the distance too (#4214) The headless path (solidcraft-cli snapshot, the home-page thumbnail, the MCP screenshot) drew the grid from the engine's palette, where a line had no alpha: the grid still ended in a cut, and at a low camera angle the cut was in the picture. A SceneLine now carries an alpha, the CPU rasterizer blends with it and the GPU capture passes it on, so the engine's grid can fade. The fade itself moves to the engine, next to the grid's other geometry, and both paths use it: the headless grid now reaches as far on the ground as the view is wide (the ground stretches as it is seen at a slant) and dissolves into the distance instead of ending in a line. * Fix the headless/viewport grid fade divergence (#4214) The engine stretched the grid's size with the slant of the plane it is seen at, the viewport stretched it only on the ground, so on a sketch's plane the picture's grid reached further than the window's (153.42 mm against 120.00 mm). Both now share one grid_ext, which the picture and the window draw the same grid from. * The grid fades out before the picture's far plane cuts the ground (#4214) The window's grid faded against a far plane of its own: the scene's radius clipped by the projection's camera (260 mm away at 400 mm of distance), while the picture itself cuts the ground at the far plane of its own projection (223.7 mm at the same distance, because the projection frames the scene's bounds and not its radius). The grid was still a third of its strength where the picture cut the ground, so the cut showed as a straight line across the view. The fade now ends at the far plane the picture's projection uses, and the grid is gone before that plane cuts the ground. The test that watched the fade now measures the ink of each row of the picture, and checks that the grid is already gone in the ten rows above the row where the far plane cuts the ground: the point it compared before lay beyond that plane, where both renders draw nothing at all, so the comparison was always true. |
||
|
|
36a60a70d9 | Graphics: 1x anti-aliasing where the multisampled view draws nothing (#5819, #5870) (#5832) | ||
|
|
0252f0bf30 |
Render preview: test that it never paints the last Design frame (#5119) (#5120)
#5187 fixed the frozen Render preview: product frames now set ss_ready themselves instead of keeping the flag from the last Design frame, so paint() no longer blits that stale offscreen picture. Nothing tested it. The new test draws a see-through Design frame (offscreen, for order-independent transparency) and then an opaque product frame on the same renderer, and checks the middle pixel shows the product. With the product branch's ss_ready update removed it fails with the stale red Design colour, [255, 129, 129, 255]. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
5012f33c85 |
Section Analysis: bodies behind the cut no longer colour the cap (#6328) (#6728)
The cap pass redraws every back face behind a marked pixel with depth test Always to put the section plane's depth there, and it also wrote colour. The last back face drawn painted the cut, so a body behind the cut (one inside another's hollow, an assembly's inner parts) showed through it in its own colour and outline, like an X-ray. The pass now writes depth only; the marking passes have already drawn the nearest back face's colour (the same split as #4622). Test: a_body_behind_the_cut_does_not_colour_the_cap in crates/gpu/tests/capture.rs (a red body in a green box's hollow, 4 mm behind the cut: the picture is the same with and without it, hatched and plain, orthographic and perspective). On main 472 pixels differ. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
13b4f6e98c |
Viewport: a selected edge's highlight no longer shows as a wedge on a grazing face (#3544)
* Viewport: lift selected and hovered edge highlights toward the eye A selected edge's highlight (3 px core, 6 px halo) is a screen-space band that was depth-tested at the edge's own depth. A face next to the edge seen at a grazing angle is pushed back by only about a pixel of its slope, so it buried part of the band, unevenly along the edge: the highlight showed as a thin wedge instead of a line. The band is now drawn like a thin cylinder around the edge: its depth is pulled toward the eye by half its width plus a pixel, measured on screen so it holds at every zoom. Plain model edges keep their depth (#1434 still holds); the part of a highlighted edge the model really hides stays dimmed through hidden_line. Not yet compiled or tested. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Viewport: lift an edge highlight by how steeply its faces are seen The first lift (half the band's width plus a pixel, the same on every edge) was not tied to the faces beside the edge. Each highlight segment now carries the normals of the two faces it borders (octahedral, packed with its width in the line's width slot, read as u32 by vs_line): the band is pulled toward the eye by its half width times how steeply those faces are seen, so a grazing face no longer buries it, and an edge seen square to its faces is not lifted at all. Test: a_selected_edge_on_a_grazing_face_draws_whole (tilts 60 to 88 degrees, small and large designs, orthographic and perspective; the band 5 mm behind a face stays hidden). Capturer::rgba_highlighted draws a highlight scene as the viewport does, for that test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
8d63a9f4cb |
Theme: the viewport keeps the previous colours until the camera moves (#5802) (#5835)
* claim: #5802 * fix: repaint on a theme change and key the frame cache on the theme tints (#5802) theme::apply asks for a repaint, so the new visuals are painted on the next pass instead of waiting for another event to schedule one. The gpu frame cache key now includes the theme's hover and selection tints, so a picture cached under the previous theme's colours is not reused. * test(ui): settle egui's startup repaints before asserting the theme's repaint (#5802) * test(ui): name the call site that asks for the theme's repaint (#5802) * test(ui): apply the theme outside a pass so its repaint request stands alone (#5802) |
||
|
|
2741cd9a8b |
Section Analysis: edges behind the cut no longer show through the cap (#6328) (#6363)
Since #1768 the section's stencil marking draws every face with FACE_BIAS. Where a back face seen through the cut meets a front face along an edge (a pocket's wall and its side wall or floor, a fillet and the face it runs into), the slope push decided which was nearer beside that edge; a front face winning left those samples unmarked, the cap skipped them, and the edge, drawn at its own depth, showed through the hatch. In perspective, and while orbiting in orthographic too, edges popped in and out from frame to frame. A second marking pass draws the back faces only (front faces culled, depth test <=, no depth write), pulled toward the eye as far as FACE_BIAS pushes faces back, before the cap. The depth buffer keeps FACE_BIAS, so edges on visible faces still draw whole (#1434). Tests in crates/gpu/tests/depth.rs: a pocket 2 mm behind the cut, and a filleted hub with a bore and a cross hole seen from twelve directions, both depths, orthographic and perspective. On main the pocket shows 45 px of edges through the cap in perspective and the hub 25 px over the views; with this change 0 and at most 2. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
4b119dd471 |
Performance overlay: frame-time graph and histogram, triangles, draw calls (#2548) (#2549)
* Performance overlay: frame-time graph and histogram, triangles, draw calls (#2548) Net change of the perf-overlay branch, rebased onto main as one commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Document frame_rate_details in ui.prefs Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: bherbruck <brennen.herbruck@gmail.com> |
||
|
|
9e6e0b8df1 |
Render workspace: complete experimental ribbon, resources and effects integration (#5493) (#5494)
* wip(render): reconcile completed material and image pipeline source with 0.20 (#5493) Source-only integration reference for staged review, not a merge-ready aggregate. Donor: 0xlillith/solidcraft@aea20b0115. Upstream: |
||
|
+33 |
b7b25f9e2b |
Render workspace: first basic delivery to main (#6050)
* Normalize UI container violation paths across platforms (#5599) Report repository-relative paths with forward slashes so diagnostics and the existing nested-package regression assertions agree on Windows and Unix. Keep the container detection rules unchanged. Validation: official ui-containers gate and all seven focused xtask tests passed; rustfmt and diff checks passed. Only xtask/dependencies were compiled; no application build or heavy tests. (cherry picked from commit |
||
|
|
9aaa8016e5 |
gpu tests: give the two test frames the new hover and selection tints (#5698)
#5109 added Frame::hover_tint and selection_tint; two test frames that landed alongside it didn't set them, so solidcraft-gpu's tests stopped compiling on main. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
8301d1c48e |
Viewport: whole-body highlights reuse the model's own triangles (#4554) (#5109)
Hovering or selecting whole bodies -- a browser row, a History group, a body under the pointer in body-pick mode -- built a CPU copy of every body's triangles into the highlight scene. On a 40-body 4.3 MB STEP assembly that was 147 bodies, 70 MB of triangle copies and a 519 ms frame. The model already has the same geometry on the GPU. The highlight now names it and the renderer draws it again in the highlight colour: - bodies drawn from a display plan: the model's evaluated plan chunks, with a hover/selection tint uniform (the chunks stay resident in the model scene); - bodies drawn as placements of shared triangles: the same placements of the model's shared triangles, coloured per instance; - bodies the model builds on the CPU: their vertex range in the model scene's block. See-through and faded bodies keep the CPU feedback, which colours them; faces and edges highlighted on their own are unchanged. The highlight looks the same (verified side by side). On the assembly the highlight build drops from 519 ms to 9 ms and no longer copies any triangles; selecting the whole assembly takes 9-20 ms. Co-authored-by: Claude Code <noreply@anthropic.com> |
||
|
|
769dfff1a5 |
Section Analysis: a Hatch option (#4563) (#4565)
* claim: #4563 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Section Analysis: a Hatch option, off for a plain cut in the body's colour (#4563) The Section Analysis dialog gets a Hatch check box beside Flip, and inspect.section a hatch?: bool (default true), so scripts, the CLI and the control channel reach it too. Hatched, a cut is its body's colour tinted toward the cap colour with 45 degree stripes, as before; off, it is the body's own solid colour. The viewport (cap alpha in the uniform), the CPU rasterizer and ui.render follow it, and the section keeps it when hidden and shown again or edited. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
55608665ef |
gpu: open the OpenGL regression device without indirect-call validation (#5101)
NVIDIA's EGL answers wgpu's request for a GL 3.3 context with exactly 3.3 (GLSL 3.30) yet lists GL_ARB_compute_shader. wgpu-hal then reports compute shaders, wgpu-core builds its indirect-call validation pipeline, naga cannot emit compute GLSL below 4.30, and request_device fails as Device(Lost). The test draws nothing indirect, so it opts out of that validation. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
0fb4a3e868 |
GPU tessellation: an empty plan no longer fails buffer validation (#5049) (#5104)
* claim: #5049 * GPU tessellation: an empty plan no longer fails buffer validation (#5049) Empty tessellation inputs were padded to 16 bytes, smaller than the shader's 32-byte vertex and 48-byte surface records, so wgpu refused the dispatch. Skip the dispatch when there is nothing to evaluate, and pad each empty buffer to one whole element of what the shader reads. |
||
|
|
5962f56f87 |
Viewport: reuse still pictures and draw scenes into a 1x window pass (#4820) (#5187)
* Viewport: show the picture it drew last when nothing changed (#4820) A frame redrew the whole scene whenever egui asked for a frame, even when the camera, scene, highlight and overlays were identical: pointer moves over empty space and UI animations over a still view paid for the full scene. The renderer now hashes everything the picture depends on (scene keys, camera, size, section, images, analysis, accessibility map, occlusion) and blits the last offscreen picture when the hash matches. The first still frame filters a supersampled picture down once and later frames copy it as it is. A frame with the same content costs a blit instead of a scene draw. Co-Authored-By: Claude Code <noreply@anthropic.com> * Viewport: draw the scene offscreen, into a 1x window pass (#4820) The scene keeps the app's depth, stencil and MSAA, but egui's window pass now has one sample and no depth. Whenever the two targets differ, the scene (product previews too) is drawn offscreen and blitted, so the UI pass no longer clears and resolves a multisampled window. Over 8 s of pointer moves on the 450E rotor head, the app's GPU intervals fell from 1325 ms to 1006 ms and egui_render from 892 ms to 509 ms; idle stays at 0%. A GPU test checks the split path's picture matches the direct one. Co-Authored-By: Claude Code <noreply@anthropic.com> * 3D mouse: a repeated report at rest asks for no frame (#4820) A device may repeat its latest report while the cap rests. Publishing it again asked egui for a frame although nothing changed. Only a report that changes the reading now asks for one; while the cap moves, the view asks for the next frame itself. Co-Authored-By: Claude Code <noreply@anthropic.com> --------- Co-authored-by: Claude Code <noreply@anthropic.com> |
||
|
|
8b1a722f06 |
Viewport: the ground shadow no longer sends every frame through the transparency path (#5230) (#5255)
* claim: #5230 * Viewport: draw the ground shadow on the direct path (#5230) The ground shadow went into the model's translucent triangles, so every frame with a body counted as see-through and took the order-independent transparency path. Give it its own batch, drawn alpha-blended after the opaque geometry as before, so only truly see-through bodies use that path. |
||
|
|
92d3a2fde5 |
GPU: a lost device stops drawing instead of crashing (#4172) (#4229)
* claim: #4172 * GPU: a lost device stops drawing instead of crashing (#4172) After the driver resets the GPU (Windows TDR), the first queue write to meet the lost device panicked inside wgpu-core (PendingWrites::activate unwrapping DeviceError::Lost). Nothing watched the device for its loss. - egui-wgpu: RenderState::device_lost (DeviceLost) is set by the device's lost callback. The painter draws nothing on a lost device, and before a frame's uploads it submits nothing (DeviceLost::probe), so a loss the driver reports is found by that submission instead of the first write. - Pictures (thumbnails of saves, ui.render) watch the same flag: on a lost device the capturer refuses with GpuError::DeviceLost without touching it, and the picture comes from the CPU rasterizer. Headless capturers watch their own devices. - The app, seeing the loss, closes keeping unsaved changes for recovery (as a forced quit does) and starts again; the new start says what happened. A second loss within ten minutes starts on the software renderer. The loss is noted in the crash journal. |
||
|
|
75261cd797 |
Viewport: order-independent transparency for see-through surfaces (#4734) (#4903)
* Viewport: levels of detail for large meshes (#4724) A large instanced mesh (20 k triangles or more) gets coarser copies, made once on a worker (`mesh_lod`): a quarter, a sixteenth and a sixty-fourth of its triangles, by quadric edge collapse (`geom::simplify`, after Garland and Heckbert 1997; no fold-overs, no sheets joined, open boundaries kept), each with its measured deviation from the full mesh. Each frame, as placements are culled, each is drawn from the coarsest copy whose deviation stays under 0.75 px where it stands (`placement_scale`, `level_for`). Until the copies are made the mesh is drawn in full; the scene is built again when they are. Display only: picking, measuring and exports keep the reference mesh. Outside the kernel. 25 placements of a 2 M-triangle STL, 3600 x 2190 px, 4x MSAA, M2 Max (`instanced_scene_gpu_benchmark`): 20.2 -> 1.2 ms a frame with all in view, 21.9 -> 2.9 ms close up. The copies take 10 s to make, on a worker. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Viewport: see-through and faded parts drawn as instances (#4888) See-through (an appearance's opacity) and faded (context around an active component) bodies in one colour are drawn as instances like opaque ones, their alpha in each placement's colour: one copy of the triangles, levels of detail and culling, no per-placement copies built on the window thread. Their placements are ordered back to front each frame (not their triangles one by one) for devices that sort see-through surfaces. The GPU benchmark gains `SOLIDCRAFT_BENCH_OPACITY` and the CPU share of each frame, and its pictures each placement's own triangles too. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Viewport: order-independent transparency for see-through surfaces (#4734) The model's see-through surfaces (glass, faded context; instanced or not) were sorted back to front triangle by triangle on the window thread whenever the view turned. They are now drawn with weighted blended order- independent transparency (McGuire and Bavoil 2013): when there are any, the frame is drawn into the renderer's own textures (as supersampling does), the see-through surfaces gathered into a weighted colour and a revealage target against the frame's depth, laid over the frame in one full-screen pass, then the overlays drawn over them. Nothing is sorted. A device that cannot blend into float targets keeps the sorted way. 25 placements of a 2 M-triangle STL at opacity 0.5, M2 Max, 3600 x 2190 px: about 10 s a frame sorted, 21.6 ms (17.2 ms instanced, 2.8 ms with levels of detail). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
f843a3f83c |
Picking: remove the GPU pick buffer, the per-body BVHs answer alone (#4665) (#4666)
The pick buffer drew the model's surfaces and edge ids for every still view to narrow which edges a pick tests. Measured against the BVHs alone (release, M2 Max, 1400 x 900 view, 600 cursor positions), a pick costs 2-51 us through the BVHs and the tile saved 0-4 us of it, while each pass cost 0.7-12.5 ms of GPU time per still view, plus gathering its scene on the window thread, read-backs a frame or two late and repaints to wait for them (and, before, a copy of every triangle, which made it refuse models past 6 M triangles). Picks are unchanged: the BVHs give the same answers. `pick_timing_on_curved_models` gains eight layers of bodies seen from above (the pick buffer's best case) and `SOLIDCRAFT_BENCH_MESH` placements. Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
981d23d1d2 |
Viewport: weld a large mesh's shared vertices quicker, and ahead of its first frame (#4679) (#4680)
`SharedTris::new` used the standard SipHash hasher and collected each triangle's corners into a Vec: 451 ms for a 2 M-triangle STL on the window thread. A quick hasher for the coordinates' bits and a fixed array make it 278 ms, and the background mesher that meshes an opened or inserted file's bodies now welds their large meshes too (`warm_shared_tris`), so the first scene that shows them takes the shared vertices ready-made. Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
3d3dd27439 |
Viewport: leave out placements of an instanced mesh that are out of view (#4646) (#4647)
* claim: #4616 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Viewport: draw a part placed many times from one copy of its triangles (#4616) A part placed by many occurrences was drawn, framed and picked from a moved copy of its mesh per placement: on the CPU (the moved mesh and its scene bytes) and on the GPU (its vertices uploaded once per placement). - The model scene draws bodies that share a mesh as GPU instances: the shared triangles once, a rigid move and colour per placement (`InstancedMesh`, `vs_tri_inst`), in the solid, section and AO passes. `GpuScene::merged` expands them, so scene tests see world triangles. - `ModelBody::mesh_in_place`, `plan_mesh_in_place_at`, `mesh_bounds` and `display_identity` give the shared mesh, its placement, the exact box and an identity without making the moved copy. - Display refinement's body ids, Fit/Home bounds, the viewport's body boxes, the background mesher and picking use them (picking moves the ray into the part's frame and shares one pick index). 25 placements of a 2 M-triangle STL on an M2 Max: orbit 45 -> 37 ms a frame, footprint 41 -> 16 GB, 24 copies 39 -> 18 s. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Viewport: draw large meshes from shared, indexed vertices (#4637) An instanced mesh's vertices are shared between its triangles and drawn indexed (`SharedTris`). A flat-faceted mesh (an STL's facets) shares them by position alone and lights each fragment with its triangle's own plane (`vs_tri_inst_flat`, `fs_*_flat`), taken from the fragment's position relative to the eye so it stays exact at any zoom; its vertex outputs are kept few, since a tiled GPU stores every vertex's outputs. A body alone is drawn this way from 50 k triangles. A mesh too large for one buffer falls back to unshared vertices. `instanced_scene_gpu_benchmark` (manual, ignored): 25 placements of a 2 M- triangle STL at 3600 x 2190 px, 4x MSAA, M2 Max: 21.3 ms a frame for the placements' own triangles, 16.1 ms shared and indexed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Viewport: leave out placements of an instanced mesh that are out of view (#4646) Each frame `Batches::cull` keeps the placements whose box may be seen (`placed_box_in_view`: all eight corners past one side of the view in clip space, so it holds behind the eye too) and writes them again only when that set changes. The manual benchmark gains `SOLIDCRAFT_BENCH_CLOSE=1`: close up on the middle of 25 placements of a 2 M-triangle STL (13 in view), 3600 x 2190 px, 4x MSAA, M2 Max: 28.2 ms a frame for the placements' own triangles, 17.2 ms instanced and culled. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
93a2922c5e |
Display plans and the model cache for large STEP assemblies (#2814) (#4021)
* STEP import: mesh band faces that wrap around a closed surface correctly Fixes two related bugs that caused SolidCraft to fail to mesh a face wrapping all the way around a closed, non-periodic surface (a revolved ridge band, or a tube-shaped B-spline surface): a missing face, a folded/self-overlapping triangulation, or a hole in the rendered body. 1. Ring edges that run slightly off their surface. STEP files write a surface and the curves bounding it to the file's own declared uncertainty, so a ring edge can legitimately sit a few micrometres off the surface it bounds. The code finding where a ring edge crosses the planned split line compared against the edge's raw (off-surface) point using a hardcoded tolerance far stricter than the file's own precision, rejecting a valid cut. Now matches against the point on the surface directly below the ring crossing, respecting the file's declared tolerance. 2. Closed B-spline surfaces, their slits and their slivers. truck only treats the rotation of a revolved surface as periodic; a face on a B-spline surface whose control net closes on itself (a tube) wasn't recognized as wrapping around at all. This produced a folded face, a hole (a boundary loop landing a full period away from where it should cut), and one near-zero-width sliver face costing the entire body its tessellation plan. Adds periodicity detection for closed B-spline surfaces, period- aware hole-loop alignment, dropping of zero-width slit boundaries, and isolating a too-thin-to-triangulate face so it no longer takes the rest of the body down with it. The GPU shader's periodic wrap mirrors the CPU math so the two don't drift apart. Regression tests: band_faces_split_when_ring_edges_run_off_their_surface, band_face_with_a_zero_width_slit_is_still_meshed, a_sliver_face_too_thin_to_triangulate_does_not_cost_the_body_its_plan. Ablation-tested: disabling either mechanism in (2) reproduces its target test's original failure message while leaving the other test unaffected. * STEP import: mesh the band's split faces, not just split them jyviko asked whether a band wall missing from the interactive app's render was a shading issue or a genuinely missing face. It was missing: the ring- edge split fix made the band's topology correct, but plan_face still produced zero triangles for the two new sub-faces. Two causes, both in plan_face (crates/kernel/src/tess/mod.rs): 1. The tolerance for how far an imported boundary may lie off its surface was tied to the requested mesh's chord tolerance instead of to the body's own size. A finer display tolerance could then reject a boundary a coarser one had just accepted, so the face would drop out exactly when zooming in on it. 2. Near a sharp corner of this flat-panelled band, several boundary points that are legitimately a few micrometres apart (within the STEP file's own declared precision) all projected onto the same surface point. The boundary loop then repeated a point in (u, v), which a triangulator can't follow, so the face's plan failed outright. One face without a plan costs the whole body its plan, and the fallback mesher can't handle a closed B-spline surface either, leaving both halves of the split band with no triangles at all: present in the topology, invisible in every renderer, and absent from the body's volume. Fix: scale the off-surface tolerance to the body's own extent (new Rules::extent), and collapse a run of boundary nodes that land on the same surface point to one (drop_collapsed) before triangulating. Regression test additions to band_faces_split_when_ring_edges_run_off_their_surface: the body's volume now matches the analytic pentagon prism (was a third of it - only the top cap - before this fix); display_plan leaves no face without triangles from coarse to fine tolerance; and the actual tolerance and facet angle the viewport draws with gives the split band its full lateral area on both halves. Confirmed on review_band_big.step, the fixture behind the review screenshots: volume's relative error against the analytic pentagon prism drops from 1.4e-4 to 4.1e-6, and the band wall now occludes the floor grid behind it in a snapshot the same way the top and bottom caps always did. Full kernel suite: 739 tests, 0 failed. * STEP import: hold an imported boundary to the file's own tolerance, not the part's size jyviko: the off-surface acceptance added in the last commit (rules.extent * OFF_SURFACE) scaled with the part, so a 2 m part silently accepted a boundary 2 mm off its surface while a 20 mm copy of the same part accepted only 0.02 mm. A STEP file's own declared uncertainty does not grow with the part, so the bound shouldn't either. Body gains boundary_tol: Option<f64>, Some(file's declared tolerance) for a body read from STEP (crate::step_in::Units::tol, already used by the ring-split fix in split.rs), None for anything this kernel built. It's set before the import's own unmeshed-face check runs, and carried over by the two face-split operations that re-cut an imported surface (splitface.rs, outline.rs), since the file's uncertainty still describes those boundaries afterward. plan_face's accept now reads: the file's own tolerance when the body declares one, or the old chord-tolerance/extent bound otherwise. The old bound's tol * 10.0 term had to go too, not just the extent term: at a 2 m part's typical display tolerance that term alone is ~20 mm, nearly ten times the extent bound jyviko objected to, so keeping it would have left the exact 2 m/2 mm example still silently accepted. Two new tests in step_in/tests.rs: - band_faces_split_when_a_scaled_copy_runs_off_its_surface: the same band fixture at a realistic 2 m scale with the same absolute slop and declared uncertainty as the small one, meshes the same way at every chord tolerance from coarse to fine. - off_surface_budget_follows_the_file_not_the_part_size: the actual regression. The same off-surface error is accepted or refused the same way whether the part is 20 mm or 2 m; a 2 mm error against a 1 µm declared uncertainty is refused at both sizes now (accepted at 2 m under the old bound, refused at 20 mm - that asymmetry was the bug). Checked at both a coarse and a fine display tolerance. Known gap, not fixed here: a STEP-imported body saved into a .solidcraft design and reopened loses boundary_tol (native.rs's decoder has no field to read it from) and falls back to the old extent-based bound on reload. Today's design format has no concept of this value at all; persisting it is a real format change, out of scope for this fix. Full kernel suite: 776 tests, 0 failed. clippy -D warnings clean. * Display plans for STEP threads and pointed ends (#3847) Three faces cost a threaded or pointed STEP part its whole display plan, so it was drawn from the reference mesh: cracked, faceted, and never refined up close. - A loop through a pole (a cone's apex on the boundary) seemed to wind around the surface: the jump at the apex, unwrapped to the nearest copy, was arbitrary. The loop is turned to end where it leaves the pole, so the step that closes it is an ordinary one (`seam::close_through_pole`). - Projection onto a spline with hundreds of spans (a helical flank) restarted from a 16 x 16 grid and settled on another turn; it now starts from two points per span, capped. - Sag refinement no longer inserts a point exactly on a boundary side, which split the side and failed the face. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * tess: a refused face's edges are divided finer and it is planned again (#2814) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LGeCa5jWWdroMWvXxN3LLM * tess: sliver faces plan empty; a face no method plans is filled flat from its nodes (#2814) A face whose boundary runs out and back along itself (two edges between the same vertices, a rounding apart, as STEP files write slivers) encloses nothing and is planned with no triangles. A face still refused after its edges are divided finer (a cusp, a sliver whose sides sag across each other, a small cap at a pole) is filled flat from its shared boundary nodes, so the rest of the body keeps its display plan instead of falling back to the reference mesh. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LGeCa5jWWdroMWvXxN3LLM * display mesh tests: a rim the chord tolerance leaves a line is divided again (#2814) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LGeCa5jWWdroMWvXxN3LLM * portable B-rep: up to 8192 control points along a spline direction (#2814) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LGeCa5jWWdroMWvXxN3LLM * solidcraft-cli: --debug logs what the engine reports to stderr Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LGeCa5jWWdroMWvXxN3LLM * STEP import: a spline written over a tiny parameter range is read over one (#2814) Some writers parameterize splines over a few millionths (a humanoid robot's edges span 5.4e-6). The kernel tells parameters apart only to 1e-6, so over such a range it evaluated the curve's end wrongly, and trimming an edge to its vertices dropped a control point: the bodies could not be stored exactly and the whole model cache was left out of the design. The knots are now stretched to span one; the curve is the same and edges are trimmed by their vertices, so nothing read from the file refers to the old parameters. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LGeCa5jWWdroMWvXxN3LLM * model cache: a body keeps its file's declared accuracy (#2814) A body restored from the cache dropped the accuracy the file it was read from declares, so the planner held its boundaries to the kernel's own bound and a reopened design drew differently from the import. It is stored with the body's runtime values, and only when there is one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LGeCa5jWWdroMWvXxN3LLM * tess: a boundary within a hundredth of its body lies on its surface, at every quality (#2814) #1721 held a body read from a file to the accuracy the file declares. A writer declares what it aims for, not a bound its edges keep: a 251-body robot assembly declaring 0.01 µm has boundaries 10 to 30 µm off their surfaces, and 95 of its bodies lost their display plans. The bound is a hundredth of the body again, what Normal quality always allowed, and now the same at every quality, so zooming in still never drops a face (#1721's point). A file declaring more raises it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LGeCa5jWWdroMWvXxN3LLM * STEP import: keep faces whose edge vertices sit slightly off their curves Some exporters write an edge's vertex beside the end of its curve, further off than the accuracy the file declares (a surface export declares 0.01 mm and puts a vertex 0.19 mm off two spline ends). The reader refused such edges and left the face, and with single-face bodies the body, out. A vertex may now sit up to the file's tolerance or 1/1000 of the model's size (the diagonal around its VERTEX_POINTs), whichever is larger, never more than the existing 1 mm ceiling. Spline and open-conic edges have the end control point moved onto the vertex, so every such edge meets its vertices exactly. The file's declared accuracy still governs closed-curve, seam and circle checks. * tess, io: review clean-ups (#2814) - A sliver face is one whose loops are all slit: drop_slits finds it in the retry after a failed plan, so the pre-check on every face (folded) is gone. - The flat fill uses cdt::triangulate (a lenient fill that leaves out sides crossing one already kept) and its flood-fill inside test, and the plane from geom::Plane. - Refinement only builds its indexes when a face was refused, takes the faces to plan again from edge_faces, and re-samples edges on the pool; Rules::finer for the finer rules. - One PackageWriter::fits for the model cache, the preview and the thumbnail. - The band split's ring tolerance lives in split.rs; comments say what the off-surface bound is now. - The CLI logger prints Level::as_str(). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LGeCa5jWWdroMWvXxN3LLM --------- Co-authored-by: David Lackovic <lackovicdavid1234@gmail.com> Co-authored-by: bherbruck <brennen.herbruck@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: jyviko <2501648+jyviko@users.noreply.github.com> Co-authored-by: Ray <raykholo@users.noreply.github.com> |
||
|
|
511faedcfa |
Fix OpenGL startup with portable AO depth reads (#2888) (#2933)
* claim: #2888 * fix: preserve AO depth in a portable integer texture (#2888) |
||
|
|
26f42ae09b |
Snapshot: draw a see-through appearance see-through, and show a tool body inside its target (#2329) (#2330)
* Snapshot: draw a see-through appearance see-through, and give the CLI --body, --tool and --section A headless picture dropped a body's opacity: the scene carried only a colour, so a design with a translucent appearance was drawn opaque by `solidcraft-cli snapshot`, by MCP screenshots and in a design's thumbnail, although the window has always drawn it as glass. There was then no way to look at the body a cut would remove inside the material it meets: only a volume to measure and reason about, which hides exactly the errors a picture makes obvious (a tool that stops short, or lands in the wrong place). - `SceneMesh` carries the body's opacity; `view::build_scene` takes it from the design (`model_body_opacity`), and a selected body stays solid so the selection colour reads. - The GPU capture routes a see-through body into the scene's glass at its own alpha, as the viewport does; the CPU rasterizer draws the solid bodies first (they own the depth buffer), then the see-through ones blended over them, far sides before near sides and without writing depth, so what lies inside shows and a line between the two is not hidden. - `snapshot --body NAME:opacity=0.3,color=#rrggbb`, `--tool NAME` (that body solid in the tool colour, the rest see-through) and `--section z=27` run the commands the app itself runs (`appearance.assign`, `inspect.section`): the options are shortcuts, not a second renderer. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Tests: measure the tool colour as it is drawn through a see-through target The tool-colour filter was derived on paper and demanded a red more than twice either other channel, which the target in front of it tints away (measured: (200, 108, 85) through opacity 0.3); and the colour check painted the tool, which a solid target hides. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fmt * Snapshot options: strip the colour's # rather than slicing it; README Slicing `value[1..]` on an input-derived string is what the house rules ask us not to write, even where a length check has already made it safe. The error a failed assignment reports now names the body rather than claiming it came from --body, since --tool reaches it too. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * --tool: assign the bodies around the tool in groups, not one command at a time Each appearance.assign is an undo step with a document snapshot behind it, so one per body made --tool cost grow with the size of the design for no reason: the bodies around the tool all get the same opacity, and the ones that share a colour can be named in one call. A design whose bodies all wear the default grey now costs two commands whatever its size. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Rasterizer: say where its glass and the GPU's differ Splitting each see-through body by facing orders its own two layers; it does not sort across bodies, which the GPU does. Worth stating rather than leaving a reader to find it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: bherbruck <brennen.herbruck@gmail.com> |
||
|
|
a9c7616e7f |
Lines thinner than a pixel no longer vanish without multisampling (grid lines, #2823) (#2871)
* claim: #2823 * fix(view): lines thinner than a pixel no longer vanish without multisampling (#2823) A line quad narrower than a pixel covers no pixel centre when it falls between two rows, so the grid's 0.7 px lines came and went as the view zoomed where the viewport draws without 4x MSAA (some browsers and devices). Such lines are now drawn a pixel wide, faded by the width they lack. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
d8d04c9009 |
Tool modifiers: shared resolve, classic defaults, preview-safe Ctrl (#1616)
* Centralise tool modifiers with classic defaults and preview-safe Ctrl. Route sketch/selection chords through a shared resolver. Keep Alt snap suppress and dual toggle as defaults; optional Shift add-only and Ctrl snap mapping. Skip preview rollback while a manipulator drag is active. * Address #1616 review: classic snap suppress, single viewport owner, docs. Default suppress to Ctrl/Cmd or Alt; drop navigation set_suppressed; remove unused label_key; add preview rollback gate test; document sketch modifiers. * fix(#1616): correct Modifiers primary in tests; simplify rollback fixture. * Treat Ctrl as primary off macOS, and rustfmt the modifier files. |
||
|
|
8e762fee57 |
Add optional ambient occlusion and graphics quality presets (#1135)
Thanks @CypherNaught-0x. |
||
|
|
c5f3515073 |
Viewport: hidden edges no longer show through faces, and thin or coplanar faces stop z-fighting (#1434, #1739) (#1768)
Thanks @CamWight. |
||
|
|
8907da5e86 |
Viewport picking: a BVH per body mesh and a GPU pick buffer for visible edges (#1776)
Thanks @oursland. |
||
|
|
741265f214 |
Create Sketch shows the origin planes through the model (#1755) (#1757)
Thanks @pablopeza. |
||
|
|
1a0b33fcf3 |
Headless pictures draw on the GPU, with the viewport's pipelines (CPU rasterizer as last tier) (#1555)
Thanks @jyviko. |
||
|
|
ec64564f21 |
Fix the startup crash on D3D12 with FXC: CPU fallback for the tessellation pipeline, FXC-friendly shader (#1098) (#1099)
* GPU tessellation: a pipeline the device cannot build falls back to CPU meshing instead of crashing (#1098) Build the tessellation compute pipeline inside error scopes; TessGpu::new returns an error, and the viewport logs it and meshes bodies on the CPU. A Windows CI job builds the pipeline with D3D12's FXC on the WARP adapter. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Tessellation shader: basis functions in one-dimensional local arrays, so D3D12's FXC compiles it (#1098) FXC has to unroll loops that write an array inside a struct (Basis.n0/n1) or a 2-D array (ndu) by a counter, and cannot with run-time trip counts (X3511). A2.2 basis functions in a local 1-D array returned whole; derivatives from the degree p-1 functions; the pole step offsets computed rather than indexed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
587cf865b8 |
Display tessellation plans (4/4): one GPU dispatch for the scene, intersection edges by Newton (#806)
Packs the scene's planned bodies into one GPU upload and dispatch, and evaluates intersection edges by seeded Newton refinement from a fitted B-spline through exactly solved leader points, falling back to the previous evaluation near tangency. Intersection nodes carry their faces' parameters. This changes speed, not what the app draws. Part 4 of 4 of #303. Co-authored-by: jyviko <2501648+jyviko@users.noreply.github.com> |