forgecad 0.10.1 → 0.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{AdminPage-DcCnj0qo.js → AdminPage-CHY6ZN-p.js} +1 -1
- package/dist/assets/{BenchmarkPage-BVEpJSVk.js → BenchmarkPage-BcRT5iGN.js} +1 -1
- package/dist/assets/{BlogPage-DHaGP50_.js → BlogPage-BssBbnb-.js} +1 -1
- package/dist/assets/{DocsPage-CDoxHkz8.js → DocsPage-DsvdiRNK.js} +1 -1
- package/dist/assets/{EditorApp-BJ0Dloyh.js → EditorApp-Bfd3jbtC.js} +18 -16
- package/dist/assets/{EmbedViewer-CRKZbY0y.js → EmbedViewer-D5t8WamV.js} +3 -3
- package/dist/assets/{LandingPageProofDriven-BxHkYRE7.js → LandingPageProofDriven-DbN7o-Be.js} +1 -1
- package/dist/assets/{LegalPage-B-u6FrVv.js → LegalPage-DNGrrY0p.js} +1 -1
- package/dist/assets/{PricingPage-CzpZ6-Ce.js → PricingPage-Nczr3pRz.js} +1 -1
- package/dist/assets/{SettingsPage-CIZSSAd0.js → SettingsPage-DZlyu4d4.js} +1 -1
- package/dist/assets/{app-DaTMg3nH.js → app-C9ct2hRD.js} +1154 -368
- package/dist/assets/{scalar-sampling-budget-prBw_s8t.js → backendInit-ymjonyQp.js} +84920 -78304
- package/dist/assets/cli/{render-DPf4AYJK.js → render-B_0lQwKU.js} +35 -179
- package/dist/assets/{constructionHistoryWorker-AwMMWSxg.js → constructionHistoryWorker-CZ42Dksy.js} +8058 -1225
- package/dist/assets/{evalWorker-CjZZWRWW.js → evalWorker-C2pm8LHP.js} +21596 -14770
- package/dist/assets/{forgecad_geometry-Dgceylq9.js → forgecad_geometry-BlMtqluF.js} +120 -1
- package/dist/assets/{forgecad_geometry_bg-dD4RNQF1.wasm → forgecad_geometry_bg-BllP_WiL.wasm} +0 -0
- package/dist/assets/{inspectWorker-CZsCFtQT.js → inspectWorker-D5T5VbfK.js} +31375 -32603
- package/dist/assets/{jointPose-DzQOViQH.js → jointPose-4r8ed8_5.js} +1 -1
- package/dist/assets/{manifold-K1SkarlQ.js → manifold-5PP1eGLN.js} +1 -1
- package/dist/assets/{manifold-DgXo0T5P.js → manifold-C4r6B-XY.js} +2 -2
- package/dist/assets/{manifold-BYlzU521.js → manifold-DjBkyIc8.js} +1 -1
- package/dist/assets/{reportWorker-B9nWwSrB.js → reportWorker-CwenM7wB.js} +45719 -44425
- package/dist/cli/render.html +1 -1
- package/dist/docs/index.html +1 -1
- package/dist/docs-raw/CLI.md +27 -15
- package/dist/docs-raw/generated/assembly.md +1 -1
- package/dist/docs-raw/generated/concepts.md +1 -1
- package/dist/docs-raw/generated/core.md +1 -1
- package/dist/docs-raw/generated/lib.md +1 -1
- package/dist/docs-raw/generated/sdf.md +2 -2
- package/dist/docs-raw/guides/simready-quickstart.md +3 -1
- package/dist/index.html +1 -1
- package/dist/sitemap.xml +15 -15
- package/dist-cli/{check-compiler-II7NLPAB.js → check-compiler-SP7FAL7R.js} +1 -1
- package/dist-cli/{check-query-propagation-7462TR3R.js → check-query-propagation-BRLSHP22.js} +1 -1
- package/dist-cli/{chunk-UWTJCGXF.js → chunk-RQQ42YCP.js} +50429 -43409
- package/dist-cli/forgecad.js +3017 -1390
- package/dist-cli/{forgecad_geometry-QOQIIP53.js → forgecad_geometry-7TVSNVUB.js} +119 -0
- package/dist-cli/forgecad_geometry_bg.wasm +0 -0
- package/dist-skill/CONTEXT.md +13 -13
- package/dist-skill/docs/API/core/concepts.md +1 -1
- package/dist-skill/docs/CLI.md +27 -15
- package/dist-skill/docs/generated/assembly.md +1 -1
- package/dist-skill/docs/generated/core.md +1 -1
- package/dist-skill/docs/generated/lib.md +1 -1
- package/dist-skill/docs/generated/sdf.md +2 -2
- package/examples/api/gyroid-voronoi-blend.forge.js +1 -1
- package/examples/api/organic-noise-sculpture.forge.js +1 -1
- package/examples/api/sdf-circular-array-knurling.forge.js +1 -1
- package/examples/api/{sdf-custom-raymarch.forge.js → sdf-custom-field-mesh-preview.forge.js} +3 -4
- package/examples/api/sdf-materialize-tree.forge.js +2 -2
- package/examples/api/sdf-plain-return.forge.js +3 -2
- package/examples/api/sdf-shapes.forge.js +2 -2
- package/examples/api/sdf-surface-basket-weave.forge.js +2 -2
- package/examples/generative/twisted-lattice-tower.forge.js +1 -1
- package/examples/generative/voronoi-lampshade.forge.js +1 -1
- package/package.json +2 -2
- package/dist/assets/manifold-CzYf_iub.js +0 -3023
|
@@ -4,7 +4,7 @@ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { en
|
|
|
4
4
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5
5
|
var _a2;
|
|
6
6
|
import { c as create, j as jsxRuntimeExports, r as reactExports, a as createWithEqualityFn, R as React, T as Tb, s as schedulerExports, b as clientExports, d as reactDomExports, u as useParams, e as useSearchParams, f as useNavigate, L as Link, g as useLocation, B as BrowserRouter, h as Routes, i as Route, N as Navigate } from "./vendor-react-6j1Kke-Y.js";
|
|
7
|
-
import { _ as __vitePreload, z as zipSync, s as strToU8, W as WebGLRenderer, R as Raycaster, O as OrthographicCamera$1, P as PerspectiveCamera$1,
|
|
7
|
+
import { _ as __vitePreload, S as SDF_PROGRAM_OP, z as zipSync, s as strToU8, W as WebGLRenderer, R as Raycaster, O as OrthographicCamera$1, P as PerspectiveCamera$1, a as Scene, b as PCFSoftShadowMap, V as VSMShadowMap, c as PCFShadowMap, B as BasicShadowMap, C as ColorManagement, L as LinearSRGBColorSpace, d as SRGBColorSpace, N as NoToneMapping, A as ACESFilmicToneMapping, e as Layers, f as Color, g as RGBAFormat, U as UnsignedByteType, h as Vector3, i as Vector2, j as Clock, T as THREE, D as DoubleSide, k as REVISION, M as Mesh, I as IcosahedronGeometry, l as ShaderMaterial, m as Spherical, Q as Quaternion, n as MOUSE, o as TOUCH, p as Ray, q as Plane, r as DataTextureLoader, H as HalfFloatType, F as FloatType, t as DataUtils, u as LinearFilter, v as RedFormat, w as InstancedBufferGeometry, x as Float32BufferAttribute, y as InstancedInterleavedBuffer, E as InterleavedBufferAttribute, G as WireframeGeometry, J as Box3, K as Sphere, X as UniformsUtils, Y as UniformsLib, Z as Vector4, $ as Line3, a0 as Matrix4, a1 as MathUtils, a2 as Uniform, a3 as WebGLRenderTarget, a4 as DepthTexture, a5 as BackSide, a6 as ClampToEdgeWrapping, a7 as PlaneGeometry, a8 as UVMapping, a9 as DataTexture, aa as Texture, ab as MeshBasicMaterial, ac as IntType, ad as ShortType, ae as ByteType, af as UnsignedIntType, ag as Loader, ah as LoadingManager, ai as LinearMipMapLinearFilter, aj as FileLoader, ak as NoBlending, al as CubeReflectionMapping, am as EquirectangularReflectionMapping, an as CubeTextureLoader, ao as WebGLCubeRenderTarget, ap as ConstraintSketch, aq as setSketchPlacement3D, ar as Sketch, as as PROFILE_BACKEND_MARKER, at as FrozenShape, au as setShapeCompilePlan, av as hasAnyPorts, aw as setShapePortsInternal, ax as markShapePortsUsed, ay as setParamOverrides, az as resolveForgeRenderStyle, aA as DEFAULT_ACTIVE_BACKEND, aB as isConstraintSketch, aC as updateConstraintValue, aD as linearizeMultiObjectSteps, aE as getShapeCompilePlan, aF as SCAN_PROXY_GRANULARITY_DEFAULT, aG as publishSolverWasmRunDebug, aH as resolveForgeQualityPreset, aI as SCAN_PROXY_MATRIX_GRANULARITY_MAX, aJ as findJointAnimationClip, aK as resolveJointAnimation, aL as resolveJointViewValues, aM as resolveImportPath, aN as resolveScanProxyGranularity, aO as BufferGeometry, aP as LineBasicMaterial, aQ as Line$1, aR as LineDashedMaterial, aS as DepthStencilFormat, aT as UnsignedInt248Type, aU as MeshNormalMaterial, aV as NearestFilter, aW as BasicDepthPacking, aX as EventDispatcher$1, aY as NoColorSpace, aZ as FrontSide, a_ as Material, a$ as AlwaysDepth, b0 as BufferAttribute, b1 as CanvasTexture, b2 as Object3D, b3 as FogExp2, b4 as Fog, b5 as AmbientLight, b6 as HemisphereLight, b7 as SpotLight, b8 as PointLight, b9 as DirectionalLight, ba as heatPointsForSide, bb as COMPARISON_COLORS, bc as comparisonHeatDepthTest, bd as comparisonHeatEdgeOpacity, be as comparisonHeatPatchOpacity, bf as shapeToGeometry, bg as buildComparisonHeatPatchGeometry, bh as EdgesGeometry, bi as buildShapeFromCompilePlan, bj as buildVisibleHistoryStacks, bk as sketchToSvg, bl as sketchToDxf, bm as runScript, bn as MeshPhysicalMaterial, bo as LineSegments, bp as findDesignTraceNodeForConstructionStep, bq as formatDesignTraceAnchor, br as waitForAnimationFrame, bs as selectBuildLedgerNodes, bt as worldAuthorPlaneToLocal, bu as compileSdfProgramEvaluator3, bv as SDF_LINEAR_OUTPUT_COLOR_GLSL, bw as GLSL3, bx as BoxGeometry, by as Data3DTexture, bz as buildSdfRaymarchFragmentShader, bA as SDF_RAYMARCH_PROXY_VERTEX_SHADER, bB as scanProxySourceBytes, bC as disposeScanProxyGeometry, bD as scanProxyGeometryFromPayload, bE as AdditiveBlending, bF as geometryWithVisibleVertexColors, bG as getRenderStylePreset, bH as SCAN_RENDER_COLORS, bI as NormalBlending, bJ as scanMaterialShellColor, bK as ZEBRA_STRIPE_SOFTNESS, bL as ZEBRA_STRIPE_SCALE, bM as ZEBRA_LIGHT_COLOR, bN as ZEBRA_DARK_COLOR, bO as ZEBRA_ACCENT_COLOR, bP as ZEBRA_STRIPE_FRAGMENT_SHADER, bQ as ZEBRA_STRIPE_VERTEX_SHADER, bR as SCAN_PROXY_LAYER_STYLES, bS as scanMaterialLayerStyles, bT as SURFACE_FIELD_FRAGMENT_SHADER, bU as SURFACE_FIELD_VERTEX_SHADER, bV as WORLD_UP, bW as CatmullRomCurve3, bX as TubeGeometry, bY as THICKNESS_GRADIENT_COLORS, bZ as ROUGHNESS_COLORS, b_ as DEFAULT_ROUGHNESS_INSPECTION_OPTIONS, b$ as PERFORMANCE_SAMPLE_INTERVAL_SEC, c0 as formatPerformanceCount, c1 as NON_TEXT_INPUT_TYPES, c2 as MeshStandardMaterial, c3 as Shape, c4 as ShapeGeometry, c5 as ShaderLib, c6 as CylinderGeometry, c7 as VIEWPORT_CAMERA_STORAGE_KEY, c8 as parseViewportCameraState, c9 as createResolvedExplodeConfig, ca as explodeBoundsCenter, cb as explodeMergeBounds, cc as resolveExplodeDirective, cd as computeExplodeMotion, ce as getSketchWorldMatrix, cf as explodeAdd, cg as hasExplodeOverride, ch as resolveExplodeLocalFanDirection, ci as explodeMul, cj as explodeLeafFanStage, ck as normalizeCutPlane, cl as toClippingPlane, cm as isObjectExcludedFromCutPlane, cn as getShapePorts, co as getShapeUsedPorts, cp as DEFAULT_VIEW_CONFIG, cq as SECTION_EXPLORER_PLANE_NAME, cr as ZERO_OFFSET, cs as scanProxyGridForBounds, ct as IDENTITY_MATRIX$2, cu as OBJECT_CONTEXT_MENU_MARGIN, cv as OBJECT_CONTEXT_MENU_WIDTH, cw as OBJECT_CONTEXT_MENU_HEIGHT, cx as getKernelFaceNameForTriangle, cy as triangleSoupFromMeshes, cz as compareTriangleSoups, cA as buildGeometryComparisonPointCloud, cB as aabbOverlaps, cC as aabbOverlapVolume, cD as DEFAULT_COLLISION_INSPECTION_OPTIONS, cE as resolveScalarSceneSampleBudget, cF as FOCUS_MODE_DIM_OPACITY, cG as comparisonCandidateContextOpacity, cH as Matrix3, cI as initBackendForEvaluation } from "./backendInit-ymjonyQp.js";
|
|
8
8
|
function getCsrfToken() {
|
|
9
9
|
const match = document.cookie.match(/(?:^|;\s*)fc-csrf-token=([^;]+)/);
|
|
10
10
|
return match == null ? void 0 : match[1];
|
|
@@ -880,6 +880,136 @@ function detectMobile() {
|
|
|
880
880
|
return hasTouch && isNarrow;
|
|
881
881
|
}
|
|
882
882
|
const isMobile = detectMobile();
|
|
883
|
+
function buildSdfProgramWgslFunction(program, options = {}) {
|
|
884
|
+
const functionName = requireWgslIdentifier(options.functionName ?? "sdfProgram", "functionName");
|
|
885
|
+
const lines = [`fn ${functionName}(p: vec3f) -> f32 {`, " var v0: f32 = p.x;", " var v1: f32 = p.y;", " var v2: f32 = p.z;"];
|
|
886
|
+
const { opcodes, argA, argB, argC, constants, output } = program;
|
|
887
|
+
for (let index = 0; index < opcodes.length; index += 1) {
|
|
888
|
+
const slot = `v${index + 3}`;
|
|
889
|
+
const a2 = `v${argA[index]}`;
|
|
890
|
+
const b2 = `v${argB[index]}`;
|
|
891
|
+
switch (opcodes[index]) {
|
|
892
|
+
case SDF_PROGRAM_OP.Const:
|
|
893
|
+
lines.push(` var ${slot}: f32 = ${wgslNumber(constants[argC[index]] ?? 0)};`);
|
|
894
|
+
break;
|
|
895
|
+
case SDF_PROGRAM_OP.Neg:
|
|
896
|
+
lines.push(` var ${slot}: f32 = -${a2};`);
|
|
897
|
+
break;
|
|
898
|
+
case SDF_PROGRAM_OP.Abs:
|
|
899
|
+
lines.push(` var ${slot}: f32 = abs(${a2});`);
|
|
900
|
+
break;
|
|
901
|
+
case SDF_PROGRAM_OP.Sqrt:
|
|
902
|
+
lines.push(` var ${slot}: f32 = sqrt(${a2});`);
|
|
903
|
+
break;
|
|
904
|
+
case SDF_PROGRAM_OP.Sin:
|
|
905
|
+
lines.push(` var ${slot}: f32 = sin(${a2});`);
|
|
906
|
+
break;
|
|
907
|
+
case SDF_PROGRAM_OP.Cos:
|
|
908
|
+
lines.push(` var ${slot}: f32 = cos(${a2});`);
|
|
909
|
+
break;
|
|
910
|
+
case SDF_PROGRAM_OP.Round:
|
|
911
|
+
lines.push(` var ${slot}: f32 = round(${a2});`);
|
|
912
|
+
break;
|
|
913
|
+
case SDF_PROGRAM_OP.Add:
|
|
914
|
+
lines.push(` var ${slot}: f32 = ${a2} + ${b2};`);
|
|
915
|
+
break;
|
|
916
|
+
case SDF_PROGRAM_OP.Sub:
|
|
917
|
+
lines.push(` var ${slot}: f32 = ${a2} - ${b2};`);
|
|
918
|
+
break;
|
|
919
|
+
case SDF_PROGRAM_OP.Mul:
|
|
920
|
+
lines.push(` var ${slot}: f32 = ${a2} * ${b2};`);
|
|
921
|
+
break;
|
|
922
|
+
case SDF_PROGRAM_OP.Div:
|
|
923
|
+
lines.push(` var ${slot}: f32 = ${a2} / ${b2};`);
|
|
924
|
+
break;
|
|
925
|
+
case SDF_PROGRAM_OP.Min:
|
|
926
|
+
lines.push(` var ${slot}: f32 = min(${a2}, ${b2});`);
|
|
927
|
+
break;
|
|
928
|
+
case SDF_PROGRAM_OP.Max:
|
|
929
|
+
lines.push(` var ${slot}: f32 = max(${a2}, ${b2});`);
|
|
930
|
+
break;
|
|
931
|
+
case SDF_PROGRAM_OP.Atan2:
|
|
932
|
+
lines.push(` var ${slot}: f32 = atan2(${a2}, ${b2});`);
|
|
933
|
+
break;
|
|
934
|
+
case SDF_PROGRAM_OP.LessThan:
|
|
935
|
+
lines.push(` var ${slot}: f32 = select(0.0, 1.0, ${a2} < ${b2});`);
|
|
936
|
+
break;
|
|
937
|
+
case SDF_PROGRAM_OP.Mod:
|
|
938
|
+
lines.push(` var ${slot}: f32 = ${a2} % ${b2};`);
|
|
939
|
+
break;
|
|
940
|
+
default:
|
|
941
|
+
throw new Error(`Unknown SdfProgram opcode ${opcodes[index]} at instruction ${index}.`);
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
lines.push(` return v${output};`);
|
|
945
|
+
lines.push("}");
|
|
946
|
+
return lines.join("\n");
|
|
947
|
+
}
|
|
948
|
+
function buildSdfProgramBrickComputeWgsl(program, options = {}) {
|
|
949
|
+
const functionName = requireWgslIdentifier(options.functionName ?? "sdfProgram", "functionName");
|
|
950
|
+
const entryPoint = requireWgslIdentifier(options.entryPoint ?? "sampleSdfBrick", "entryPoint");
|
|
951
|
+
const [workgroupX, workgroupY, workgroupZ] = requireWorkgroupSize(options.workgroupSize ?? [4, 4, 4]);
|
|
952
|
+
const bindingGroup = requireBindingIndex(options.bindingGroup ?? 0, "bindingGroup");
|
|
953
|
+
const paramsBinding = requireBindingIndex(options.paramsBinding ?? 0, "paramsBinding");
|
|
954
|
+
const distancesBinding = requireBindingIndex(options.distancesBinding ?? 1, "distancesBinding");
|
|
955
|
+
return [
|
|
956
|
+
buildSdfProgramWgslFunction(program, { functionName }),
|
|
957
|
+
"",
|
|
958
|
+
"struct SdfBrickParams {",
|
|
959
|
+
" origin: vec4f,",
|
|
960
|
+
" step: vec4f,",
|
|
961
|
+
" dims: vec4u,",
|
|
962
|
+
"};",
|
|
963
|
+
"",
|
|
964
|
+
`@group(${bindingGroup}) @binding(${paramsBinding}) var<uniform> brick: SdfBrickParams;`,
|
|
965
|
+
`@group(${bindingGroup}) @binding(${distancesBinding}) var<storage, read_write> distances: array<f32>;`,
|
|
966
|
+
"",
|
|
967
|
+
`@compute @workgroup_size(${workgroupX}, ${workgroupY}, ${workgroupZ})`,
|
|
968
|
+
`fn ${entryPoint}(@builtin(global_invocation_id) gid: vec3u) {`,
|
|
969
|
+
" let dims = brick.dims.xyz;",
|
|
970
|
+
" if (any(gid >= dims)) {",
|
|
971
|
+
" return;",
|
|
972
|
+
" }",
|
|
973
|
+
" let index = gid.x + dims.x * (gid.y + dims.y * gid.z);",
|
|
974
|
+
" let voxel = vec3f(f32(gid.x), f32(gid.y), f32(gid.z));",
|
|
975
|
+
" let p = brick.origin.xyz + voxel * brick.step.xyz;",
|
|
976
|
+
` distances[index] = ${functionName}(p);`,
|
|
977
|
+
"}"
|
|
978
|
+
].join("\n");
|
|
979
|
+
}
|
|
980
|
+
function wgslNumber(value) {
|
|
981
|
+
if (!Number.isFinite(value)) return "0.0";
|
|
982
|
+
const text = Number(value.toPrecision(9)).toString();
|
|
983
|
+
return text.includes(".") || text.includes("e") ? text : `${text}.0`;
|
|
984
|
+
}
|
|
985
|
+
function requireWgslIdentifier(value, name) {
|
|
986
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(value)) {
|
|
987
|
+
throw new Error(`${name} must be a valid WGSL identifier.`);
|
|
988
|
+
}
|
|
989
|
+
return value;
|
|
990
|
+
}
|
|
991
|
+
function requireWorkgroupSize(value) {
|
|
992
|
+
const [x, y, z] = value;
|
|
993
|
+
for (const [name, size] of [
|
|
994
|
+
["x", x],
|
|
995
|
+
["y", y],
|
|
996
|
+
["z", z]
|
|
997
|
+
]) {
|
|
998
|
+
if (!Number.isInteger(size) || size < 1 || size > 256) {
|
|
999
|
+
throw new Error(`workgroupSize.${name} must be an integer from 1 to 256.`);
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
if (x * y * z > 256) {
|
|
1003
|
+
throw new Error("workgroupSize product must be at most 256 for portable WebGPU compute.");
|
|
1004
|
+
}
|
|
1005
|
+
return [x, y, z];
|
|
1006
|
+
}
|
|
1007
|
+
function requireBindingIndex(value, name) {
|
|
1008
|
+
if (!Number.isInteger(value) || value < 0) {
|
|
1009
|
+
throw new Error(`${name} must be a non-negative integer.`);
|
|
1010
|
+
}
|
|
1011
|
+
return value;
|
|
1012
|
+
}
|
|
883
1013
|
function escapeXml(value) {
|
|
884
1014
|
return value.replace(/[^\u0009\u000A\u000D\u0020-\uD7FF\uE000-\uFFFD]/g, " ").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
885
1015
|
}
|
|
@@ -15157,8 +15287,12 @@ const runResultDeserializer = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Obje
|
|
|
15157
15287
|
__proto__: null,
|
|
15158
15288
|
deserializeRunResult
|
|
15159
15289
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
15290
|
+
function compilePlanNeedsNativeShapeLowering(plan) {
|
|
15291
|
+
if (plan.kind === "queryOwner") return compilePlanNeedsNativeShapeLowering(plan.base);
|
|
15292
|
+
return plan.kind !== "sdf";
|
|
15293
|
+
}
|
|
15160
15294
|
function serializedSceneObjectNeedsNativeShapeLowering(object) {
|
|
15161
|
-
return object.compilePlan !== null && object.compilePlan !== void 0;
|
|
15295
|
+
return object.compilePlan !== null && object.compilePlan !== void 0 && compilePlanNeedsNativeShapeLowering(object.compilePlan);
|
|
15162
15296
|
}
|
|
15163
15297
|
function serializedRunResultNeedsNativeOcctLowering(result) {
|
|
15164
15298
|
return result.objects.some(serializedSceneObjectNeedsNativeShapeLowering);
|
|
@@ -15841,7 +15975,7 @@ const CRASH_COOLDOWN_MS = 2e3;
|
|
|
15841
15975
|
class EvalWorkerClient {
|
|
15842
15976
|
constructor(workerFactory = () => new Worker(new URL(
|
|
15843
15977
|
/* @vite-ignore */
|
|
15844
|
-
"/assets/evalWorker-
|
|
15978
|
+
"/assets/evalWorker-C2pm8LHP.js",
|
|
15845
15979
|
import.meta.url
|
|
15846
15980
|
), { type: "module" })) {
|
|
15847
15981
|
__publicField(this, "worker", null);
|
|
@@ -17327,6 +17461,8 @@ function formatComputeBackendLabel(backend) {
|
|
|
17327
17461
|
return "Local OCCT";
|
|
17328
17462
|
case "truck":
|
|
17329
17463
|
return "Local Truck";
|
|
17464
|
+
case "sdf":
|
|
17465
|
+
return "Local SDF";
|
|
17330
17466
|
case "server-occt":
|
|
17331
17467
|
return "Server OCCT";
|
|
17332
17468
|
}
|
|
@@ -17640,6 +17776,28 @@ function resolveViewportScanGranularity(granularity, renderStyle) {
|
|
|
17640
17776
|
return renderStyle === "matrix" ? Math.min(next, SCAN_PROXY_MATRIX_GRANULARITY_MAX) : next;
|
|
17641
17777
|
}
|
|
17642
17778
|
const initialPreviewFile = resolvePreviewFile(initialActive, INITIAL_FILES);
|
|
17779
|
+
function openCodeEditorPatch() {
|
|
17780
|
+
writeViewPreferences({ codeEditorOpen: true });
|
|
17781
|
+
return { codeEditorOpen: true };
|
|
17782
|
+
}
|
|
17783
|
+
function activeFileHasViewportPreview(activeFile, files, meshPreviewFile) {
|
|
17784
|
+
if (meshPreviewFile) return true;
|
|
17785
|
+
if (!activeFile || !(activeFile in files)) return false;
|
|
17786
|
+
if (resolvePreviewFile(activeFile, files)) return true;
|
|
17787
|
+
return activeFile.toLowerCase().endsWith(".svg");
|
|
17788
|
+
}
|
|
17789
|
+
function codeEditorPatchForActiveFile(activeFile, files, meshPreviewFile) {
|
|
17790
|
+
if (!activeFile || !(activeFile in files)) return {};
|
|
17791
|
+
return activeFileHasViewportPreview(activeFile, files, meshPreviewFile) ? {} : openCodeEditorPatch();
|
|
17792
|
+
}
|
|
17793
|
+
function runResultHasViewportContent(result) {
|
|
17794
|
+
var _a3, _b2, _c, _d;
|
|
17795
|
+
return result.objects.length > 0 || !!result.assemblyKinematics || (((_a3 = result.jointsView) == null ? void 0 : _a3.joints.length) ?? 0) > 0 && ((_b2 = result.jointsView) == null ? void 0 : _b2.enabled) !== false || (((_c = result.renderLabels) == null ? void 0 : _c.length) ?? 0) > 0 || (((_d = result.debugHighlights3D) == null ? void 0 : _d.length) ?? 0) > 0;
|
|
17796
|
+
}
|
|
17797
|
+
function codeEditorPatchForRunResult(result, meshPreviewFile) {
|
|
17798
|
+
if (meshPreviewFile || runResultHasViewportContent(result)) return {};
|
|
17799
|
+
return openCodeEditorPatch();
|
|
17800
|
+
}
|
|
17643
17801
|
const initialObjectSettingsByFile = (() => {
|
|
17644
17802
|
const viewPreferences = initialViewPreferences;
|
|
17645
17803
|
if (viewPreferences.objectSettingsByFile && typeof viewPreferences.objectSettingsByFile === "object") {
|
|
@@ -17819,6 +17977,7 @@ const useForgeStore = create((set, get) => ({
|
|
|
17819
17977
|
const restored = targetPreviewFile && nextByFile[targetPreviewFile] ? nextByFile[targetPreviewFile] : {};
|
|
17820
17978
|
set({
|
|
17821
17979
|
activeFile: name,
|
|
17980
|
+
...codeEditorPatchForActiveFile(name, files, null),
|
|
17822
17981
|
recentFiles: touchAndPersistRecentFile(get().recentFiles, files, name),
|
|
17823
17982
|
meshPreviewFile: null,
|
|
17824
17983
|
// Clear mesh preview when switching files
|
|
@@ -17869,11 +18028,13 @@ const useForgeStore = create((set, get) => ({
|
|
|
17869
18028
|
if (get().files[normalized] !== void 0) return;
|
|
17870
18029
|
if (get().folders.includes(normalized)) return;
|
|
17871
18030
|
const template = projectTextFileTemplate(normalized);
|
|
18031
|
+
const nextFilesForEditor = { ...get().files, [normalized]: template };
|
|
17872
18032
|
const newFolders = Array.from(/* @__PURE__ */ new Set([...get().folders, ...collectParentPaths(normalized)])).sort();
|
|
17873
18033
|
set((s) => ({
|
|
17874
18034
|
files: { ...s.files, [normalized]: template },
|
|
17875
18035
|
savedFiles: { ...s.savedFiles, [normalized]: template },
|
|
17876
18036
|
activeFile: normalized,
|
|
18037
|
+
...codeEditorPatchForActiveFile(normalized, nextFilesForEditor, null),
|
|
17877
18038
|
recentFiles: touchAndPersistRecentFile(s.recentFiles, { ...s.files, [normalized]: template }, normalized),
|
|
17878
18039
|
paramOverrides: {},
|
|
17879
18040
|
jointValues: {},
|
|
@@ -17912,6 +18073,7 @@ const useForgeStore = create((set, get) => ({
|
|
|
17912
18073
|
files: remaining,
|
|
17913
18074
|
savedFiles: remainingSaved,
|
|
17914
18075
|
activeFile: newActive,
|
|
18076
|
+
...codeEditorPatchForActiveFile(newActive, remaining, null),
|
|
17915
18077
|
recentFiles: touchAndPersistRecentFile(get().recentFiles, remaining, newActive),
|
|
17916
18078
|
objectSettingsByFile: nextObjectSettingsByFile,
|
|
17917
18079
|
paramSnapshotsByFile: nextParamSnapshotsByFile,
|
|
@@ -17942,10 +18104,12 @@ const useForgeStore = create((set, get) => ({
|
|
|
17942
18104
|
const nextObjectSettingsByFile = remapObjectSettingsByFile(objectSettingsByFile, oldName, normalized);
|
|
17943
18105
|
const nextParamSnapshotsByFile = remapParamSnapshotsByFile(paramSnapshotsByFile, oldName, normalized);
|
|
17944
18106
|
writeViewPreferences({ objectSettingsByFile: nextObjectSettingsByFile, paramSnapshotsByFile: nextParamSnapshotsByFile });
|
|
18107
|
+
const nextActive = oldName === activeFile ? normalized : activeFile;
|
|
17945
18108
|
set({
|
|
17946
18109
|
files: remaining,
|
|
17947
18110
|
savedFiles: remainingSaved,
|
|
17948
|
-
activeFile:
|
|
18111
|
+
activeFile: nextActive,
|
|
18112
|
+
...codeEditorPatchForActiveFile(nextActive, remaining, null),
|
|
17949
18113
|
recentFiles: remapAndPersistRecentFiles(get().recentFiles, remaining, oldName, normalized),
|
|
17950
18114
|
objectSettingsByFile: nextObjectSettingsByFile,
|
|
17951
18115
|
paramSnapshotsByFile: nextParamSnapshotsByFile,
|
|
@@ -18003,6 +18167,7 @@ const useForgeStore = create((set, get) => ({
|
|
|
18003
18167
|
savedFiles: updatedSaved,
|
|
18004
18168
|
folders: updatedFolders,
|
|
18005
18169
|
activeFile: nextActive,
|
|
18170
|
+
...codeEditorPatchForActiveFile(nextActive, updatedFiles, null),
|
|
18006
18171
|
recentFiles: remapAndPersistRecentFiles(get().recentFiles, updatedFiles, normalizedOld, normalizedNew),
|
|
18007
18172
|
objectSettingsByFile: nextObjectSettingsByFile,
|
|
18008
18173
|
paramSnapshotsByFile: nextParamSnapshotsByFile,
|
|
@@ -18061,6 +18226,7 @@ const useForgeStore = create((set, get) => ({
|
|
|
18061
18226
|
savedFiles: remainingSaved,
|
|
18062
18227
|
folders: remainingFolders,
|
|
18063
18228
|
activeFile: newActive,
|
|
18229
|
+
...codeEditorPatchForActiveFile(newActive, remainingFiles, null),
|
|
18064
18230
|
recentFiles: touchAndPersistRecentFile(get().recentFiles, remainingFiles, newActive),
|
|
18065
18231
|
objectSettingsByFile: nextObjectSettingsByFile,
|
|
18066
18232
|
paramSnapshotsByFile: nextParamSnapshotsByFile,
|
|
@@ -18215,7 +18381,14 @@ const useForgeStore = create((set, get) => ({
|
|
|
18215
18381
|
if (cached) {
|
|
18216
18382
|
const applied = buildRunState(previewFile, cached, get());
|
|
18217
18383
|
rememberAcceptedAssemblyPoseState(cached, readAssemblyPoseControlState(applied.nextState));
|
|
18218
|
-
set({
|
|
18384
|
+
set({
|
|
18385
|
+
...applied.nextState,
|
|
18386
|
+
...codeEditorPatchForRunResult(cached, meshPreviewFile),
|
|
18387
|
+
lastValidResult: cached,
|
|
18388
|
+
isEvaluating: false,
|
|
18389
|
+
evaluationPhase: "idle",
|
|
18390
|
+
buildLedgerEvents: []
|
|
18391
|
+
});
|
|
18219
18392
|
writeViewPreferences({ objectSettingsByFile: applied.nextObjectSettingsByFile, cutPlaneEnabled: applied.nextCutPlaneEnabled });
|
|
18220
18393
|
return;
|
|
18221
18394
|
}
|
|
@@ -18267,10 +18440,12 @@ const useForgeStore = create((set, get) => ({
|
|
|
18267
18440
|
const message = serverError instanceof Error ? serverError.message : String(serverError);
|
|
18268
18441
|
if (execId !== currentExecutionId) return;
|
|
18269
18442
|
rememberAcceptedAssemblyPoseState(null, EMPTY_ASSEMBLY_POSE_CONTROL_STATE);
|
|
18443
|
+
const failedResult = errorRunResult(`Server compute failed: ${message}`, performance.now() - tDispatch);
|
|
18270
18444
|
set({
|
|
18271
|
-
result:
|
|
18445
|
+
result: failedResult,
|
|
18272
18446
|
consoleLogs: [],
|
|
18273
18447
|
previewFile,
|
|
18448
|
+
...codeEditorPatchForRunResult(failedResult, meshPreviewFile),
|
|
18274
18449
|
isEvaluating: false,
|
|
18275
18450
|
evaluationPhase: "idle",
|
|
18276
18451
|
buildLedgerEvents: []
|
|
@@ -18301,12 +18476,25 @@ const useForgeStore = create((set, get) => ({
|
|
|
18301
18476
|
);
|
|
18302
18477
|
if (runResult.error) {
|
|
18303
18478
|
rememberAcceptedAssemblyPoseState(null, EMPTY_ASSEMBLY_POSE_CONTROL_STATE);
|
|
18304
|
-
set({
|
|
18479
|
+
set({
|
|
18480
|
+
result: runResult,
|
|
18481
|
+
consoleLogs: runResult.logs,
|
|
18482
|
+
previewFile,
|
|
18483
|
+
...codeEditorPatchForRunResult(runResult, meshPreviewFile),
|
|
18484
|
+
isEvaluating: false,
|
|
18485
|
+
evaluationPhase: "idle"
|
|
18486
|
+
});
|
|
18305
18487
|
} else {
|
|
18306
18488
|
storeCache(previewFile, code, files, paramOverrides, assemblyState, runQuality, executionBackend, runResult, serialized);
|
|
18307
18489
|
const applied = buildRunState(previewFile, runResult, get());
|
|
18308
18490
|
rememberAcceptedAssemblyPoseState(runResult, readAssemblyPoseControlState(applied.nextState));
|
|
18309
|
-
set({
|
|
18491
|
+
set({
|
|
18492
|
+
...applied.nextState,
|
|
18493
|
+
...codeEditorPatchForRunResult(runResult, meshPreviewFile),
|
|
18494
|
+
lastValidResult: runResult,
|
|
18495
|
+
isEvaluating: false,
|
|
18496
|
+
evaluationPhase: "idle"
|
|
18497
|
+
});
|
|
18310
18498
|
writeViewPreferences({ objectSettingsByFile: applied.nextObjectSettingsByFile, cutPlaneEnabled: applied.nextCutPlaneEnabled });
|
|
18311
18499
|
}
|
|
18312
18500
|
} catch (error) {
|
|
@@ -18315,7 +18503,14 @@ const useForgeStore = create((set, get) => ({
|
|
|
18315
18503
|
const message = error instanceof Error ? error.message : String(error);
|
|
18316
18504
|
const errResult = createErrorRunResult(message, runQuality);
|
|
18317
18505
|
rememberAcceptedAssemblyPoseState(null, EMPTY_ASSEMBLY_POSE_CONTROL_STATE);
|
|
18318
|
-
set({
|
|
18506
|
+
set({
|
|
18507
|
+
result: errResult,
|
|
18508
|
+
consoleLogs: errResult.logs,
|
|
18509
|
+
previewFile,
|
|
18510
|
+
...codeEditorPatchForRunResult(errResult, meshPreviewFile),
|
|
18511
|
+
isEvaluating: false,
|
|
18512
|
+
evaluationPhase: "idle"
|
|
18513
|
+
});
|
|
18319
18514
|
}
|
|
18320
18515
|
},
|
|
18321
18516
|
updateAssemblyPose: async () => {
|
|
@@ -19304,10 +19499,12 @@ const useForgeStore = create((set, get) => ({
|
|
|
19304
19499
|
loadFromText: (text, name) => {
|
|
19305
19500
|
const normalized = normalizePath(name);
|
|
19306
19501
|
const newFolders = Array.from(/* @__PURE__ */ new Set([...get().folders, ...collectParentPaths(normalized)])).sort();
|
|
19502
|
+
const nextFilesForEditor = { ...get().files, [normalized]: text };
|
|
19307
19503
|
set((s) => ({
|
|
19308
19504
|
files: { ...s.files, [normalized]: text },
|
|
19309
19505
|
savedFiles: { ...s.savedFiles, [normalized]: text },
|
|
19310
19506
|
activeFile: normalized,
|
|
19507
|
+
...codeEditorPatchForActiveFile(normalized, nextFilesForEditor, null),
|
|
19311
19508
|
recentFiles: touchAndPersistRecentFile(s.recentFiles, { ...s.files, [normalized]: text }, normalized),
|
|
19312
19509
|
fileHandle: null,
|
|
19313
19510
|
dirty: false,
|
|
@@ -19367,6 +19564,7 @@ const useForgeStore = create((set, get) => ({
|
|
|
19367
19564
|
return {
|
|
19368
19565
|
files: nextFiles,
|
|
19369
19566
|
activeFile: nextActive,
|
|
19567
|
+
...codeEditorPatchForActiveFile(nextActive, nextFiles, nextMeshPreview),
|
|
19370
19568
|
recentFiles: touchAndPersistRecentFile(s.recentFiles, nextFiles, nextActive),
|
|
19371
19569
|
fileHandle: null,
|
|
19372
19570
|
dirty: true,
|
|
@@ -19458,6 +19656,7 @@ const useForgeStore = create((set, get) => ({
|
|
|
19458
19656
|
set({
|
|
19459
19657
|
...nextState,
|
|
19460
19658
|
activeFile: newActiveFile,
|
|
19659
|
+
...codeEditorPatchForActiveFile(newActiveFile, nextFiles, nextState.meshPreviewFile),
|
|
19461
19660
|
recentFiles: touchAndPersistRecentFile(baseRecentFiles, nextFiles, newActiveFile),
|
|
19462
19661
|
filesLoading: false
|
|
19463
19662
|
});
|
|
@@ -19494,6 +19693,7 @@ const useForgeStore = create((set, get) => ({
|
|
|
19494
19693
|
set({
|
|
19495
19694
|
...nextState,
|
|
19496
19695
|
activeFile: newActiveFile,
|
|
19696
|
+
...codeEditorPatchForActiveFile(newActiveFile, nextState.files, null),
|
|
19497
19697
|
recentFiles: touchAndPersistRecentFile(state2.recentFiles, nextState.files, newActiveFile)
|
|
19498
19698
|
});
|
|
19499
19699
|
if (newActiveFile && newActiveFile !== prevActiveFile) {
|
|
@@ -27660,7 +27860,7 @@ function ConstructionGhostOverlay({ matrix }) {
|
|
|
27660
27860
|
class ConstructionHistoryWorkerClient {
|
|
27661
27861
|
constructor(workerFactory = () => new Worker(new URL(
|
|
27662
27862
|
/* @vite-ignore */
|
|
27663
|
-
"/assets/constructionHistoryWorker-
|
|
27863
|
+
"/assets/constructionHistoryWorker-CZ42Dksy.js",
|
|
27664
27864
|
import.meta.url
|
|
27665
27865
|
), { type: "module" })) {
|
|
27666
27866
|
__publicField(this, "worker", null);
|
|
@@ -30172,7 +30372,7 @@ function generateReportInWorker(options) {
|
|
|
30172
30372
|
return new Promise((resolve2, reject) => {
|
|
30173
30373
|
const worker = new Worker(new URL(
|
|
30174
30374
|
/* @vite-ignore */
|
|
30175
|
-
"/assets/reportWorker-
|
|
30375
|
+
"/assets/reportWorker-CwenM7wB.js",
|
|
30176
30376
|
import.meta.url
|
|
30177
30377
|
), { type: "module" });
|
|
30178
30378
|
const cleanup = () => {
|
|
@@ -30377,7 +30577,7 @@ const SURFACE_PALETTE = ["#4488cc", "#44cc88", "#cc8844", "#cc44aa", "#88cc44",
|
|
|
30377
30577
|
function toPage(tx, x, y) {
|
|
30378
30578
|
return [x * tx.scale + tx.offsetX, y * tx.scale + tx.offsetY];
|
|
30379
30579
|
}
|
|
30380
|
-
function computeBounds
|
|
30580
|
+
function computeBounds(meta) {
|
|
30381
30581
|
const bounds = { min: [Infinity, Infinity], max: [-Infinity, -Infinity] };
|
|
30382
30582
|
function expand(x, y) {
|
|
30383
30583
|
bounds.min[0] = Math.min(bounds.min[0], x);
|
|
@@ -30443,7 +30643,7 @@ function computeBounds$1(meta) {
|
|
|
30443
30643
|
return bounds;
|
|
30444
30644
|
}
|
|
30445
30645
|
function computeTransform(meta, ptsPerMm, marginPts) {
|
|
30446
|
-
const bounds = computeBounds
|
|
30646
|
+
const bounds = computeBounds(meta);
|
|
30447
30647
|
const sketchW = bounds.max[0] - bounds.min[0];
|
|
30448
30648
|
const sketchH = bounds.max[1] - bounds.min[1];
|
|
30449
30649
|
return {
|
|
@@ -30739,7 +30939,7 @@ function generateSketchPdf(meta, options) {
|
|
|
30739
30939
|
const tx = computeTransform(meta, POINTS_PER_MM, MARGIN);
|
|
30740
30940
|
tx.pageWidth = Math.max(tx.pageWidth, 600);
|
|
30741
30941
|
tx.pageHeight = Math.max(tx.pageHeight, 400);
|
|
30742
|
-
const bounds = computeBounds
|
|
30942
|
+
const bounds = computeBounds(meta);
|
|
30743
30943
|
const extent = Math.max(bounds.max[0] - bounds.min[0], bounds.max[1] - bounds.min[1], 1);
|
|
30744
30944
|
const baseExtent = 100;
|
|
30745
30945
|
const autoFontScale = Math.max(1, extent / baseExtent);
|
|
@@ -30919,9 +31119,14 @@ async function exportMeshFromStore(format, preferredStem, options = {}) {
|
|
|
30919
31119
|
downloadExportArtifact(await buildMeshExportArtifact(format, stem, runResult, objectSettings));
|
|
30920
31120
|
}
|
|
30921
31121
|
async function exportExactFromStore(format, preferredStem) {
|
|
30922
|
-
const { result, activeFile, files, paramOverrides, runQuality } = useForgeStore.getState();
|
|
31122
|
+
const { result, activeFile, files, paramOverrides, runQuality, activeBackend } = useForgeStore.getState();
|
|
30923
31123
|
const assemblyState = resolveAssemblyStateForExport();
|
|
30924
31124
|
requireSuccessfulRunResult(result);
|
|
31125
|
+
if (activeBackend === "sdf") {
|
|
31126
|
+
throw new Error(
|
|
31127
|
+
"STEP/BREP exact export is not available from the SDF backend. Use 3MF, OBJ, or STL mesh export, or switch to OCCT for exact B-rep export."
|
|
31128
|
+
);
|
|
31129
|
+
}
|
|
30925
31130
|
const stem = sanitizeExportStem(preferredStem ?? deriveExportStem(activeFile));
|
|
30926
31131
|
const code = files[activeFile];
|
|
30927
31132
|
if (!code) throw new Error(`Active file "${activeFile}" is missing.`);
|
|
@@ -30933,7 +31138,8 @@ async function exportExactFromStore(format, preferredStem) {
|
|
|
30933
31138
|
quality: runQuality,
|
|
30934
31139
|
paramOverrides,
|
|
30935
31140
|
assemblyState,
|
|
30936
|
-
isNotebook: false
|
|
31141
|
+
isNotebook: false,
|
|
31142
|
+
activeBackend
|
|
30937
31143
|
});
|
|
30938
31144
|
triggerDownload(blob, `${stem}.${format}`);
|
|
30939
31145
|
} finally {
|
|
@@ -33624,7 +33830,7 @@ const PHASE_CONFIG = {
|
|
|
33624
33830
|
};
|
|
33625
33831
|
const PHASE_ORDER = ["kernel-init", "evaluating", "serializing"];
|
|
33626
33832
|
function formatEvaluationBackendLabel(activeBackend, computeTarget) {
|
|
33627
|
-
const backend = activeBackend === "occt" ? "OCCT" : activeBackend === "manifold" ? "Manifold" : activeBackend === "truck" ? "Truck" : "kernel";
|
|
33833
|
+
const backend = activeBackend === "occt" ? "OCCT" : activeBackend === "manifold" ? "Manifold" : activeBackend === "truck" ? "Truck" : activeBackend === "sdf" ? "SDF" : "kernel";
|
|
33628
33834
|
return computeTarget === "server" ? "Server OCCT" : `Local ${backend}`;
|
|
33629
33835
|
}
|
|
33630
33836
|
function EvaluationIndicator({
|
|
@@ -34218,6 +34424,712 @@ function SectionCapPreview({
|
|
|
34218
34424
|
if (previewPlanes.length === 0) return null;
|
|
34219
34425
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: previewPlanes.map((plane) => /* @__PURE__ */ jsxRuntimeExports.jsx("mesh", { geometry: plane.geometry, renderOrder: plane.renderOrder, raycast: () => null, children: /* @__PURE__ */ jsxRuntimeExports.jsx(PreviewCapMaterial, { color: color2, opacity, plane }) }, plane.planeId)) });
|
|
34220
34426
|
}
|
|
34427
|
+
const DEFAULT_TARGET_LONGEST_AXIS_SAMPLES = 96;
|
|
34428
|
+
const DEFAULT_MAX_VOXELS = 18e4;
|
|
34429
|
+
const DEFAULT_MIN_AXIS_SAMPLES = 8;
|
|
34430
|
+
const BRICK_PROGRAM_OPCODE_THRESHOLD = 768;
|
|
34431
|
+
function compiledSdfProgramFromSceneData(program) {
|
|
34432
|
+
return {
|
|
34433
|
+
opcodes: Uint8Array.from(program.opcodes),
|
|
34434
|
+
argA: Int32Array.from(program.argA),
|
|
34435
|
+
argB: Int32Array.from(program.argB),
|
|
34436
|
+
argC: Int32Array.from(program.argC),
|
|
34437
|
+
constants: Float64Array.from(program.constants),
|
|
34438
|
+
output: program.output,
|
|
34439
|
+
slotCount: program.slotCount
|
|
34440
|
+
};
|
|
34441
|
+
}
|
|
34442
|
+
function shouldUseSdfDistanceBrick(data, opcodeThreshold = BRICK_PROGRAM_OPCODE_THRESHOLD) {
|
|
34443
|
+
return Boolean((data == null ? void 0 : data.program) && data.program.opcodes.length >= opcodeThreshold && finitePositiveBounds(data.bounds));
|
|
34444
|
+
}
|
|
34445
|
+
function chooseSdfDistanceBrickResolution(bounds, options = {}) {
|
|
34446
|
+
const targetLongestAxisSamples = clampInteger(options.targetLongestAxisSamples ?? DEFAULT_TARGET_LONGEST_AXIS_SAMPLES, 4, 256);
|
|
34447
|
+
const maxVoxels = clampInteger(options.maxVoxels ?? DEFAULT_MAX_VOXELS, 512, 16e6);
|
|
34448
|
+
const minAxisSamples = clampInteger(options.minAxisSamples ?? DEFAULT_MIN_AXIS_SAMPLES, 2, 64);
|
|
34449
|
+
const size = boundsSize(bounds);
|
|
34450
|
+
const longest = Math.max(...size);
|
|
34451
|
+
if (!Number.isFinite(longest) || longest <= 0) {
|
|
34452
|
+
return { dims: [minAxisSamples, minAxisSamples, minAxisSamples], cellSize: 1, voxelCount: minAxisSamples ** 3 };
|
|
34453
|
+
}
|
|
34454
|
+
let samples = targetLongestAxisSamples;
|
|
34455
|
+
while (samples >= minAxisSamples) {
|
|
34456
|
+
const cellSize = longest / Math.max(1, samples - 1);
|
|
34457
|
+
const dims = size.map((axis) => Math.max(minAxisSamples, Math.ceil(axis / cellSize) + 1));
|
|
34458
|
+
const voxelCount = dims[0] * dims[1] * dims[2];
|
|
34459
|
+
if (voxelCount <= maxVoxels || samples === minAxisSamples) return { dims, cellSize, voxelCount };
|
|
34460
|
+
samples = Math.max(minAxisSamples, Math.floor(samples * 0.9));
|
|
34461
|
+
}
|
|
34462
|
+
return {
|
|
34463
|
+
dims: [minAxisSamples, minAxisSamples, minAxisSamples],
|
|
34464
|
+
cellSize: longest / Math.max(1, minAxisSamples - 1),
|
|
34465
|
+
voxelCount: minAxisSamples ** 3
|
|
34466
|
+
};
|
|
34467
|
+
}
|
|
34468
|
+
function buildSdfDistanceBrick(data, options = {}) {
|
|
34469
|
+
const startedAt = performance.now();
|
|
34470
|
+
const resolution = chooseSdfDistanceBrickResolution(data.bounds, options);
|
|
34471
|
+
const program = compiledSdfProgramFromSceneData(data.program);
|
|
34472
|
+
const evalSdf = compileSdfProgramEvaluator3(program);
|
|
34473
|
+
const distances = new Float32Array(resolution.voxelCount);
|
|
34474
|
+
const min = [...data.bounds.min];
|
|
34475
|
+
const max2 = [...data.bounds.max];
|
|
34476
|
+
const size = boundsSize(data.bounds);
|
|
34477
|
+
const [nx, ny, nz] = resolution.dims;
|
|
34478
|
+
let offset = 0;
|
|
34479
|
+
for (let z = 0; z < nz; z += 1) {
|
|
34480
|
+
const pz = coordinateAt(min[2], size[2], z, nz);
|
|
34481
|
+
for (let y = 0; y < ny; y += 1) {
|
|
34482
|
+
const py = coordinateAt(min[1], size[1], y, ny);
|
|
34483
|
+
for (let x = 0; x < nx; x += 1) {
|
|
34484
|
+
const px = coordinateAt(min[0], size[0], x, nx);
|
|
34485
|
+
const d = evalSdf(px, py, pz);
|
|
34486
|
+
distances[offset] = Number.isFinite(d) ? d : 1e9;
|
|
34487
|
+
offset += 1;
|
|
34488
|
+
}
|
|
34489
|
+
}
|
|
34490
|
+
}
|
|
34491
|
+
return {
|
|
34492
|
+
...resolution,
|
|
34493
|
+
min,
|
|
34494
|
+
max: max2,
|
|
34495
|
+
distances,
|
|
34496
|
+
buildMs: performance.now() - startedAt,
|
|
34497
|
+
buildSource: "cpu"
|
|
34498
|
+
};
|
|
34499
|
+
}
|
|
34500
|
+
function finitePositiveBounds(bounds) {
|
|
34501
|
+
const size = boundsSize(bounds);
|
|
34502
|
+
return [...bounds.min, ...bounds.max, ...size].every(Number.isFinite) && size.every((axis) => axis > 0);
|
|
34503
|
+
}
|
|
34504
|
+
function boundsSize(bounds) {
|
|
34505
|
+
return [bounds.max[0] - bounds.min[0], bounds.max[1] - bounds.min[1], bounds.max[2] - bounds.min[2]];
|
|
34506
|
+
}
|
|
34507
|
+
function coordinateAt(min, size, index, count) {
|
|
34508
|
+
if (count <= 1) return min;
|
|
34509
|
+
return min + size * (index / (count - 1));
|
|
34510
|
+
}
|
|
34511
|
+
function clampInteger(value, min, max2) {
|
|
34512
|
+
if (!Number.isFinite(value)) return min;
|
|
34513
|
+
return Math.max(min, Math.min(max2, Math.round(value)));
|
|
34514
|
+
}
|
|
34515
|
+
const DEFAULT_WORKGROUP_SIZE = [4, 4, 4];
|
|
34516
|
+
const BRICK_PARAMS_BYTE_LENGTH = 48;
|
|
34517
|
+
async function buildSdfDistanceBrickWebGpu(data, options = {}) {
|
|
34518
|
+
var _a3, _b2, _c, _d;
|
|
34519
|
+
const gpu = options.gpu ?? currentBrowserGpu();
|
|
34520
|
+
if (!gpu) return null;
|
|
34521
|
+
const adapter = await gpu.requestAdapter();
|
|
34522
|
+
if (!adapter) return null;
|
|
34523
|
+
const startedAt = performance.now();
|
|
34524
|
+
const device = await adapter.requestDevice();
|
|
34525
|
+
const buffers = [];
|
|
34526
|
+
try {
|
|
34527
|
+
const resolution = chooseSdfDistanceBrickResolution(data.bounds, options);
|
|
34528
|
+
const min = [...data.bounds.min];
|
|
34529
|
+
const max2 = [...data.bounds.max];
|
|
34530
|
+
const step = brickStep(data.bounds, resolution.dims);
|
|
34531
|
+
const byteLength2 = resolution.voxelCount * Float32Array.BYTES_PER_ELEMENT;
|
|
34532
|
+
const workgroupSize = options.workgroupSize ?? DEFAULT_WORKGROUP_SIZE;
|
|
34533
|
+
const entryPoint = "sampleSdfBrick";
|
|
34534
|
+
const module = device.createShaderModule({
|
|
34535
|
+
label: "ForgeCAD SDF distance brick compute shader",
|
|
34536
|
+
code: buildSdfProgramBrickComputeWgsl(compiledSdfProgramFromSceneData(data.program), { entryPoint, workgroupSize })
|
|
34537
|
+
});
|
|
34538
|
+
const pipeline = device.createComputePipeline({
|
|
34539
|
+
label: "ForgeCAD SDF distance brick compute pipeline",
|
|
34540
|
+
layout: "auto",
|
|
34541
|
+
compute: { module, entryPoint }
|
|
34542
|
+
});
|
|
34543
|
+
const usage = webGpuUsage();
|
|
34544
|
+
const paramsBuffer = device.createBuffer({
|
|
34545
|
+
label: "ForgeCAD SDF distance brick params",
|
|
34546
|
+
size: BRICK_PARAMS_BYTE_LENGTH,
|
|
34547
|
+
usage: usage.UNIFORM | usage.COPY_DST
|
|
34548
|
+
});
|
|
34549
|
+
const distancesBuffer = device.createBuffer({
|
|
34550
|
+
label: "ForgeCAD SDF distance brick distances",
|
|
34551
|
+
size: byteLength2,
|
|
34552
|
+
usage: usage.STORAGE | usage.COPY_SRC
|
|
34553
|
+
});
|
|
34554
|
+
const readBuffer = device.createBuffer({
|
|
34555
|
+
label: "ForgeCAD SDF distance brick readback",
|
|
34556
|
+
size: byteLength2,
|
|
34557
|
+
usage: usage.MAP_READ | usage.COPY_DST
|
|
34558
|
+
});
|
|
34559
|
+
buffers.push(paramsBuffer, distancesBuffer, readBuffer);
|
|
34560
|
+
device.queue.writeBuffer(paramsBuffer, 0, packSdfDistanceBrickWebGpuParams(min, step, resolution.dims));
|
|
34561
|
+
const bindGroup = device.createBindGroup({
|
|
34562
|
+
label: "ForgeCAD SDF distance brick bind group",
|
|
34563
|
+
layout: pipeline.getBindGroupLayout(0),
|
|
34564
|
+
entries: [
|
|
34565
|
+
{ binding: 0, resource: { buffer: paramsBuffer } },
|
|
34566
|
+
{ binding: 1, resource: { buffer: distancesBuffer } }
|
|
34567
|
+
]
|
|
34568
|
+
});
|
|
34569
|
+
const encoder2 = device.createCommandEncoder({ label: "ForgeCAD SDF distance brick command encoder" });
|
|
34570
|
+
const pass = encoder2.beginComputePass({ label: "ForgeCAD SDF distance brick compute pass" });
|
|
34571
|
+
pass.setPipeline(pipeline);
|
|
34572
|
+
pass.setBindGroup(0, bindGroup);
|
|
34573
|
+
pass.dispatchWorkgroups(
|
|
34574
|
+
Math.ceil(resolution.dims[0] / workgroupSize[0]),
|
|
34575
|
+
Math.ceil(resolution.dims[1] / workgroupSize[1]),
|
|
34576
|
+
Math.ceil(resolution.dims[2] / workgroupSize[2])
|
|
34577
|
+
);
|
|
34578
|
+
pass.end();
|
|
34579
|
+
encoder2.copyBufferToBuffer(distancesBuffer, 0, readBuffer, 0, byteLength2);
|
|
34580
|
+
device.queue.submit([encoder2.finish()]);
|
|
34581
|
+
await ((_b2 = (_a3 = device.queue).onSubmittedWorkDone) == null ? void 0 : _b2.call(_a3));
|
|
34582
|
+
await readBuffer.mapAsync(webGpuMapModeRead());
|
|
34583
|
+
const mapped = readBuffer.getMappedRange();
|
|
34584
|
+
const distances = new Float32Array(mapped.slice(0, byteLength2));
|
|
34585
|
+
readBuffer.unmap();
|
|
34586
|
+
return {
|
|
34587
|
+
...resolution,
|
|
34588
|
+
min,
|
|
34589
|
+
max: max2,
|
|
34590
|
+
distances,
|
|
34591
|
+
buildMs: performance.now() - startedAt,
|
|
34592
|
+
buildSource: "webgpu"
|
|
34593
|
+
};
|
|
34594
|
+
} finally {
|
|
34595
|
+
for (const buffer of buffers) (_c = buffer.destroy) == null ? void 0 : _c.call(buffer);
|
|
34596
|
+
(_d = device.destroy) == null ? void 0 : _d.call(device);
|
|
34597
|
+
}
|
|
34598
|
+
}
|
|
34599
|
+
function isSdfDistanceBrickWebGpuEnabled() {
|
|
34600
|
+
if (typeof window === "undefined") return false;
|
|
34601
|
+
const params = new URLSearchParams(window.location.search);
|
|
34602
|
+
return params.has("sdf-webgpu-bricks") || window.localStorage.getItem("fc-sdf-webgpu-bricks") === "1";
|
|
34603
|
+
}
|
|
34604
|
+
function packSdfDistanceBrickWebGpuParams(origin, step, dims) {
|
|
34605
|
+
const buffer = new ArrayBuffer(BRICK_PARAMS_BYTE_LENGTH);
|
|
34606
|
+
const floats = new Float32Array(buffer, 0, 8);
|
|
34607
|
+
floats[0] = origin[0];
|
|
34608
|
+
floats[1] = origin[1];
|
|
34609
|
+
floats[2] = origin[2];
|
|
34610
|
+
floats[3] = 0;
|
|
34611
|
+
floats[4] = step[0];
|
|
34612
|
+
floats[5] = step[1];
|
|
34613
|
+
floats[6] = step[2];
|
|
34614
|
+
floats[7] = 0;
|
|
34615
|
+
const uints = new Uint32Array(buffer, 32, 4);
|
|
34616
|
+
uints[0] = dims[0];
|
|
34617
|
+
uints[1] = dims[1];
|
|
34618
|
+
uints[2] = dims[2];
|
|
34619
|
+
uints[3] = 0;
|
|
34620
|
+
return buffer;
|
|
34621
|
+
}
|
|
34622
|
+
function brickStep(bounds, dims) {
|
|
34623
|
+
return [
|
|
34624
|
+
axisStep(bounds.min[0], bounds.max[0], dims[0]),
|
|
34625
|
+
axisStep(bounds.min[1], bounds.max[1], dims[1]),
|
|
34626
|
+
axisStep(bounds.min[2], bounds.max[2], dims[2])
|
|
34627
|
+
];
|
|
34628
|
+
}
|
|
34629
|
+
function axisStep(min, max2, count) {
|
|
34630
|
+
if (count <= 1) return 0;
|
|
34631
|
+
return (max2 - min) / (count - 1);
|
|
34632
|
+
}
|
|
34633
|
+
function currentBrowserGpu() {
|
|
34634
|
+
const nav = globalThis.navigator;
|
|
34635
|
+
return (nav == null ? void 0 : nav.gpu) ?? null;
|
|
34636
|
+
}
|
|
34637
|
+
function webGpuUsage() {
|
|
34638
|
+
return globalThis.GPUBufferUsage ?? {
|
|
34639
|
+
MAP_READ: 1,
|
|
34640
|
+
COPY_SRC: 4,
|
|
34641
|
+
COPY_DST: 8,
|
|
34642
|
+
UNIFORM: 64,
|
|
34643
|
+
STORAGE: 128
|
|
34644
|
+
};
|
|
34645
|
+
}
|
|
34646
|
+
function webGpuMapModeRead() {
|
|
34647
|
+
var _a3;
|
|
34648
|
+
return ((_a3 = globalThis.GPUMapMode) == null ? void 0 : _a3.READ) ?? 1;
|
|
34649
|
+
}
|
|
34650
|
+
const MAX_CLIP_PLANES$1 = 8;
|
|
34651
|
+
const SDF_BRICK_VERTEX_SHADER = `precision highp float;
|
|
34652
|
+
|
|
34653
|
+
out vec3 vLocalPosition;
|
|
34654
|
+
|
|
34655
|
+
void main() {
|
|
34656
|
+
vLocalPosition = position;
|
|
34657
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
34658
|
+
}
|
|
34659
|
+
`;
|
|
34660
|
+
const SDF_BRICK_FRAGMENT_SHADER = `precision highp float;
|
|
34661
|
+
precision highp sampler3D;
|
|
34662
|
+
|
|
34663
|
+
in vec3 vLocalPosition;
|
|
34664
|
+
out vec4 outColor;
|
|
34665
|
+
|
|
34666
|
+
${SDF_LINEAR_OUTPUT_COLOR_GLSL}
|
|
34667
|
+
|
|
34668
|
+
uniform sampler3D uDistanceTexture;
|
|
34669
|
+
uniform mat4 uCameraMatrixWorld;
|
|
34670
|
+
uniform mat4 uLocalToWorld;
|
|
34671
|
+
uniform mat4 uWorldToLocal;
|
|
34672
|
+
uniform mat4 uViewProjectionMatrix;
|
|
34673
|
+
uniform vec3 uBrickMin;
|
|
34674
|
+
uniform vec3 uBrickMax;
|
|
34675
|
+
uniform vec3 uColor;
|
|
34676
|
+
uniform vec3 uHoverColor;
|
|
34677
|
+
uniform float uAlpha;
|
|
34678
|
+
uniform float uHoverIntensity;
|
|
34679
|
+
uniform float uRayStep;
|
|
34680
|
+
uniform float uIsoEps;
|
|
34681
|
+
uniform float uNormalStep;
|
|
34682
|
+
uniform float uIsOrthographic;
|
|
34683
|
+
uniform int uClipPlaneCount;
|
|
34684
|
+
uniform vec4 uClipPlanes[8];
|
|
34685
|
+
|
|
34686
|
+
const int MAX_STEPS = 420;
|
|
34687
|
+
const int REFINE_STEPS = 7;
|
|
34688
|
+
|
|
34689
|
+
bool intersectAabb(vec3 ro, vec3 rd, vec3 bmin, vec3 bmax, out float tNear, out float tFar) {
|
|
34690
|
+
vec3 inv = 1.0 / rd;
|
|
34691
|
+
vec3 t0 = (bmin - ro) * inv;
|
|
34692
|
+
vec3 t1 = (bmax - ro) * inv;
|
|
34693
|
+
vec3 tmin = min(t0, t1);
|
|
34694
|
+
vec3 tmax = max(t0, t1);
|
|
34695
|
+
tNear = max(max(tmin.x, tmin.y), tmin.z);
|
|
34696
|
+
tFar = min(min(tmax.x, tmax.y), tmax.z);
|
|
34697
|
+
return tFar >= max(tNear, 0.0);
|
|
34698
|
+
}
|
|
34699
|
+
|
|
34700
|
+
float brickSdf(vec3 p) {
|
|
34701
|
+
vec3 uv = clamp((p - uBrickMin) / max(uBrickMax - uBrickMin, vec3(1e-6)), vec3(0.0), vec3(1.0));
|
|
34702
|
+
return texture(uDistanceTexture, uv).r;
|
|
34703
|
+
}
|
|
34704
|
+
|
|
34705
|
+
float clippedBrickSdf(vec3 p) {
|
|
34706
|
+
float d = brickSdf(p);
|
|
34707
|
+
for (int i = 0; i < 8; i++) {
|
|
34708
|
+
if (i >= uClipPlaneCount) break;
|
|
34709
|
+
vec4 plane = uClipPlanes[i];
|
|
34710
|
+
d = max(d, dot(plane.xyz, p) + plane.w);
|
|
34711
|
+
}
|
|
34712
|
+
return d;
|
|
34713
|
+
}
|
|
34714
|
+
|
|
34715
|
+
bool crossedSurface(float a, float b) {
|
|
34716
|
+
return (a < 0.0 && b > 0.0) || (a > 0.0 && b < 0.0);
|
|
34717
|
+
}
|
|
34718
|
+
|
|
34719
|
+
float refineSurface(vec3 ro, vec3 rd, float lo, float hi) {
|
|
34720
|
+
float dLo = clippedBrickSdf(ro + rd * lo);
|
|
34721
|
+
for (int i = 0; i < REFINE_STEPS; i++) {
|
|
34722
|
+
float mid = 0.5 * (lo + hi);
|
|
34723
|
+
float dMid = clippedBrickSdf(ro + rd * mid);
|
|
34724
|
+
if (abs(dMid) < uIsoEps) return mid;
|
|
34725
|
+
if (crossedSurface(dLo, dMid)) {
|
|
34726
|
+
hi = mid;
|
|
34727
|
+
} else {
|
|
34728
|
+
lo = mid;
|
|
34729
|
+
dLo = dMid;
|
|
34730
|
+
}
|
|
34731
|
+
}
|
|
34732
|
+
return 0.5 * (lo + hi);
|
|
34733
|
+
}
|
|
34734
|
+
|
|
34735
|
+
vec3 estimateNormal(vec3 p) {
|
|
34736
|
+
vec2 e = vec2(uNormalStep, 0.0);
|
|
34737
|
+
return normalize(vec3(
|
|
34738
|
+
brickSdf(p + e.xyy) - brickSdf(p - e.xyy),
|
|
34739
|
+
brickSdf(p + e.yxy) - brickSdf(p - e.yxy),
|
|
34740
|
+
brickSdf(p + e.yyx) - brickSdf(p - e.yyx)
|
|
34741
|
+
));
|
|
34742
|
+
}
|
|
34743
|
+
|
|
34744
|
+
void writeFragmentDepth(vec3 pLocal) {
|
|
34745
|
+
vec4 world = uLocalToWorld * vec4(pLocal, 1.0);
|
|
34746
|
+
vec4 clip = uViewProjectionMatrix * world;
|
|
34747
|
+
float ndcDepth = clip.z / clip.w;
|
|
34748
|
+
gl_FragDepth = ndcDepth * 0.5 + 0.5;
|
|
34749
|
+
}
|
|
34750
|
+
|
|
34751
|
+
void main() {
|
|
34752
|
+
float sceneDiag = max(length(uBrickMax - uBrickMin), 1.0);
|
|
34753
|
+
vec3 roWorld = uCameraMatrixWorld[3].xyz;
|
|
34754
|
+
vec3 ro = (uWorldToLocal * vec4(roWorld, 1.0)).xyz;
|
|
34755
|
+
vec3 rd = normalize(vLocalPosition - ro);
|
|
34756
|
+
if (uIsOrthographic > 0.5) {
|
|
34757
|
+
vec3 rdWorld = normalize((uCameraMatrixWorld * vec4(0.0, 0.0, -1.0, 0.0)).xyz);
|
|
34758
|
+
rd = normalize((uWorldToLocal * vec4(rdWorld, 0.0)).xyz);
|
|
34759
|
+
ro = vLocalPosition - rd * sceneDiag * 2.0;
|
|
34760
|
+
}
|
|
34761
|
+
|
|
34762
|
+
float tNear = 0.0;
|
|
34763
|
+
float tFar = 0.0;
|
|
34764
|
+
if (!intersectAabb(ro, rd, uBrickMin, uBrickMax, tNear, tFar)) discard;
|
|
34765
|
+
|
|
34766
|
+
float t = max(tNear, 0.0);
|
|
34767
|
+
float prevT = t;
|
|
34768
|
+
float prevD = clippedBrickSdf(ro + rd * t);
|
|
34769
|
+
bool hit = prevD <= 0.0 && abs(prevD) < uIsoEps;
|
|
34770
|
+
|
|
34771
|
+
for (int i = 0; i < MAX_STEPS; i++) {
|
|
34772
|
+
if (hit) break;
|
|
34773
|
+
t += clamp(abs(prevD) * 0.8, uRayStep, uRayStep * 4.0);
|
|
34774
|
+
if (t > tFar) break;
|
|
34775
|
+
float d = clippedBrickSdf(ro + rd * t);
|
|
34776
|
+
float absD = abs(d);
|
|
34777
|
+
if (d <= 0.0 && absD < uIsoEps) {
|
|
34778
|
+
hit = true;
|
|
34779
|
+
break;
|
|
34780
|
+
}
|
|
34781
|
+
if (crossedSurface(prevD, d)) {
|
|
34782
|
+
t = refineSurface(ro, rd, prevT, t);
|
|
34783
|
+
hit = true;
|
|
34784
|
+
break;
|
|
34785
|
+
}
|
|
34786
|
+
prevT = t;
|
|
34787
|
+
prevD = d;
|
|
34788
|
+
}
|
|
34789
|
+
|
|
34790
|
+
if (!hit) discard;
|
|
34791
|
+
|
|
34792
|
+
vec3 p = ro + rd * t;
|
|
34793
|
+
writeFragmentDepth(p);
|
|
34794
|
+
vec3 pWorld = (uLocalToWorld * vec4(p, 1.0)).xyz;
|
|
34795
|
+
vec3 normal = normalize(mat3(transpose(uWorldToLocal)) * estimateNormal(p));
|
|
34796
|
+
vec3 viewDir = normalize(roWorld - pWorld);
|
|
34797
|
+
vec3 keyDir = normalize(vec3(0.45, 0.62, 0.64));
|
|
34798
|
+
vec3 fillDir = normalize(vec3(-0.68, -0.18, 0.42));
|
|
34799
|
+
float diffuse = max(dot(normal, keyDir), 0.0) * 0.72 + max(dot(normal, fillDir), 0.0) * 0.22 + 0.16;
|
|
34800
|
+
float fresnel = pow(1.0 - max(dot(normal, viewDir), 0.0), 3.0);
|
|
34801
|
+
vec3 base = mix(uColor, uHoverColor, uHoverIntensity);
|
|
34802
|
+
vec3 shaded = base * diffuse + base * fresnel * 0.18;
|
|
34803
|
+
outColor = forgeLinearToOutputColor(shaded, uAlpha);
|
|
34804
|
+
}
|
|
34805
|
+
`;
|
|
34806
|
+
function colorToRgb$1(color2, fallback) {
|
|
34807
|
+
const resolved = new Color(color2 ?? fallback);
|
|
34808
|
+
return [resolved.r, resolved.g, resolved.b];
|
|
34809
|
+
}
|
|
34810
|
+
function createProxyGeometry$1(data) {
|
|
34811
|
+
const { min, max: max2 } = data.bounds;
|
|
34812
|
+
const size = [max2[0] - min[0], max2[1] - min[1], max2[2] - min[2]];
|
|
34813
|
+
if (!size.every((value) => Number.isFinite(value) && value > 0)) return null;
|
|
34814
|
+
const geometry = new BoxGeometry(size[0], size[1], size[2]);
|
|
34815
|
+
geometry.translate((min[0] + max2[0]) / 2, (min[1] + max2[1]) / 2, (min[2] + max2[2]) / 2);
|
|
34816
|
+
return geometry;
|
|
34817
|
+
}
|
|
34818
|
+
function createClipPlaneUniforms$1() {
|
|
34819
|
+
return Array.from({ length: MAX_CLIP_PLANES$1 }, () => new Vector4(0, 0, 0, 0));
|
|
34820
|
+
}
|
|
34821
|
+
function createDistanceTexture(brick) {
|
|
34822
|
+
const texture = new Data3DTexture(brick.distances, brick.dims[0], brick.dims[1], brick.dims[2]);
|
|
34823
|
+
texture.format = RedFormat;
|
|
34824
|
+
texture.type = FloatType;
|
|
34825
|
+
texture.minFilter = LinearFilter;
|
|
34826
|
+
texture.magFilter = LinearFilter;
|
|
34827
|
+
texture.wrapS = ClampToEdgeWrapping;
|
|
34828
|
+
texture.wrapT = ClampToEdgeWrapping;
|
|
34829
|
+
texture.wrapR = ClampToEdgeWrapping;
|
|
34830
|
+
texture.unpackAlignment = 1;
|
|
34831
|
+
texture.needsUpdate = true;
|
|
34832
|
+
return texture;
|
|
34833
|
+
}
|
|
34834
|
+
async function buildViewportDistanceBrick(sdf) {
|
|
34835
|
+
if (!shouldUseSdfDistanceBrick(sdf)) return null;
|
|
34836
|
+
if (isSdfDistanceBrickWebGpuEnabled()) {
|
|
34837
|
+
const webGpuBrick = await buildSdfDistanceBrickWebGpu(sdf);
|
|
34838
|
+
if (webGpuBrick) return webGpuBrick;
|
|
34839
|
+
}
|
|
34840
|
+
return buildSdfDistanceBrick(sdf);
|
|
34841
|
+
}
|
|
34842
|
+
function SdfDistanceBrickObject({
|
|
34843
|
+
sdf,
|
|
34844
|
+
settings,
|
|
34845
|
+
matrix,
|
|
34846
|
+
materialProps,
|
|
34847
|
+
isHovered,
|
|
34848
|
+
clippingPlanes = [],
|
|
34849
|
+
onPointerEnter,
|
|
34850
|
+
onPointerMove,
|
|
34851
|
+
onPointerLeave,
|
|
34852
|
+
onClick,
|
|
34853
|
+
onDoubleClick,
|
|
34854
|
+
onContextMenu
|
|
34855
|
+
}) {
|
|
34856
|
+
const meshRef = reactExports.useRef(null);
|
|
34857
|
+
const materialRef = reactExports.useRef(null);
|
|
34858
|
+
const { camera } = useThree();
|
|
34859
|
+
const viewProjection = reactExports.useMemo(() => new Matrix4(), []);
|
|
34860
|
+
const worldToLocal = reactExports.useMemo(() => new Matrix4(), []);
|
|
34861
|
+
const localClipPlane = reactExports.useMemo(() => new Plane(), []);
|
|
34862
|
+
const [brick, setBrick] = reactExports.useState(null);
|
|
34863
|
+
const [brickError, setBrickError] = reactExports.useState(null);
|
|
34864
|
+
reactExports.useEffect(() => {
|
|
34865
|
+
let cancelled = false;
|
|
34866
|
+
setBrick(null);
|
|
34867
|
+
setBrickError(null);
|
|
34868
|
+
buildViewportDistanceBrick(sdf).then((nextBrick) => {
|
|
34869
|
+
if (!cancelled) setBrick(nextBrick);
|
|
34870
|
+
}).catch((error) => {
|
|
34871
|
+
const nextError = error instanceof Error ? error : new Error(String(error));
|
|
34872
|
+
console.error("ForgeCAD SDF distance brick build failed.", nextError);
|
|
34873
|
+
if (!cancelled) setBrickError(nextError);
|
|
34874
|
+
});
|
|
34875
|
+
return () => {
|
|
34876
|
+
cancelled = true;
|
|
34877
|
+
};
|
|
34878
|
+
}, [sdf]);
|
|
34879
|
+
const geometry = reactExports.useMemo(() => createProxyGeometry$1(sdf), [sdf]);
|
|
34880
|
+
const texture = reactExports.useMemo(() => brick ? createDistanceTexture(brick) : null, [brick]);
|
|
34881
|
+
const opacity = Math.min(settings.opacity, (materialProps == null ? void 0 : materialProps.opacity) ?? 1);
|
|
34882
|
+
const color2 = reactExports.useMemo(() => colorToRgb$1(settings.color ?? sdf.colorHex, "#5b9bd5"), [settings.color, sdf.colorHex]);
|
|
34883
|
+
const uniforms = reactExports.useMemo(
|
|
34884
|
+
() => ({
|
|
34885
|
+
uDistanceTexture: { value: texture },
|
|
34886
|
+
uCameraMatrixWorld: { value: new Matrix4() },
|
|
34887
|
+
uLocalToWorld: { value: new Matrix4() },
|
|
34888
|
+
uWorldToLocal: { value: new Matrix4() },
|
|
34889
|
+
uViewProjectionMatrix: { value: new Matrix4() },
|
|
34890
|
+
uBrickMin: { value: new Vector3((brick == null ? void 0 : brick.min[0]) ?? 0, (brick == null ? void 0 : brick.min[1]) ?? 0, (brick == null ? void 0 : brick.min[2]) ?? 0) },
|
|
34891
|
+
uBrickMax: { value: new Vector3((brick == null ? void 0 : brick.max[0]) ?? 1, (brick == null ? void 0 : brick.max[1]) ?? 1, (brick == null ? void 0 : brick.max[2]) ?? 1) },
|
|
34892
|
+
uColor: { value: new Vector3(...color2) },
|
|
34893
|
+
uHoverColor: { value: new Color(settings.color) },
|
|
34894
|
+
uAlpha: { value: opacity },
|
|
34895
|
+
uHoverIntensity: { value: 0 },
|
|
34896
|
+
uRayStep: { value: Math.max(0.05, ((brick == null ? void 0 : brick.cellSize) ?? 1) * 0.65) },
|
|
34897
|
+
uIsoEps: { value: Math.max(0.05, ((brick == null ? void 0 : brick.cellSize) ?? 1) * 0.55) },
|
|
34898
|
+
uNormalStep: { value: Math.max(0.05, (brick == null ? void 0 : brick.cellSize) ?? 1) },
|
|
34899
|
+
uIsOrthographic: { value: 0 },
|
|
34900
|
+
uClipPlaneCount: { value: 0 },
|
|
34901
|
+
uClipPlanes: { value: createClipPlaneUniforms$1() }
|
|
34902
|
+
}),
|
|
34903
|
+
[brick, color2, opacity, settings.color, texture]
|
|
34904
|
+
);
|
|
34905
|
+
useFrame(() => {
|
|
34906
|
+
const material = materialRef.current;
|
|
34907
|
+
const mesh = meshRef.current;
|
|
34908
|
+
if (!material || !mesh) return;
|
|
34909
|
+
mesh.updateMatrixWorld();
|
|
34910
|
+
camera.updateMatrixWorld();
|
|
34911
|
+
viewProjection.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
|
|
34912
|
+
worldToLocal.copy(mesh.matrixWorld).invert();
|
|
34913
|
+
material.uniforms.uCameraMatrixWorld.value.copy(camera.matrixWorld);
|
|
34914
|
+
material.uniforms.uLocalToWorld.value.copy(mesh.matrixWorld);
|
|
34915
|
+
material.uniforms.uWorldToLocal.value.copy(worldToLocal);
|
|
34916
|
+
material.uniforms.uViewProjectionMatrix.value.copy(viewProjection);
|
|
34917
|
+
material.uniforms.uIsOrthographic.value = camera.isOrthographicCamera ? 1 : 0;
|
|
34918
|
+
material.uniforms.uHoverColor.value.set(settings.color);
|
|
34919
|
+
material.uniforms.uHoverIntensity.value = isHovered ? 0.3 : 0;
|
|
34920
|
+
material.uniforms.uClipPlaneCount.value = Math.min(clippingPlanes.length, MAX_CLIP_PLANES$1);
|
|
34921
|
+
const clipUniforms = material.uniforms.uClipPlanes.value;
|
|
34922
|
+
for (let i = 0; i < MAX_CLIP_PLANES$1; i += 1) {
|
|
34923
|
+
const source = clippingPlanes[i];
|
|
34924
|
+
if (!source) {
|
|
34925
|
+
clipUniforms[i].set(0, 0, 0, 0);
|
|
34926
|
+
continue;
|
|
34927
|
+
}
|
|
34928
|
+
localClipPlane.copy(source).applyMatrix4(worldToLocal);
|
|
34929
|
+
clipUniforms[i].set(localClipPlane.normal.x, localClipPlane.normal.y, localClipPlane.normal.z, localClipPlane.constant);
|
|
34930
|
+
}
|
|
34931
|
+
});
|
|
34932
|
+
reactExports.useEffect(() => {
|
|
34933
|
+
return () => {
|
|
34934
|
+
geometry == null ? void 0 : geometry.dispose();
|
|
34935
|
+
};
|
|
34936
|
+
}, [geometry]);
|
|
34937
|
+
reactExports.useEffect(() => {
|
|
34938
|
+
return () => {
|
|
34939
|
+
texture == null ? void 0 : texture.dispose();
|
|
34940
|
+
};
|
|
34941
|
+
}, [texture]);
|
|
34942
|
+
if (brickError || !brick || !geometry || !texture) return null;
|
|
34943
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
34944
|
+
"group",
|
|
34945
|
+
{
|
|
34946
|
+
matrixAutoUpdate: false,
|
|
34947
|
+
matrix,
|
|
34948
|
+
onPointerEnter,
|
|
34949
|
+
onPointerMove,
|
|
34950
|
+
onPointerLeave,
|
|
34951
|
+
onClick,
|
|
34952
|
+
onDoubleClick,
|
|
34953
|
+
onContextMenu,
|
|
34954
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
34955
|
+
"mesh",
|
|
34956
|
+
{
|
|
34957
|
+
ref: meshRef,
|
|
34958
|
+
geometry,
|
|
34959
|
+
userData: {
|
|
34960
|
+
forgeMesh: true,
|
|
34961
|
+
forgeSdfDirect: true,
|
|
34962
|
+
forgeSdfRenderer: "distance-brick",
|
|
34963
|
+
forgeSdfDistanceBrick: true,
|
|
34964
|
+
forgeSdfDistanceBrickBuildSource: brick.buildSource,
|
|
34965
|
+
forgeSdfDistanceBrickBuildMs: brick.buildMs,
|
|
34966
|
+
forgeSdfDistanceBrickVoxels: brick.voxelCount
|
|
34967
|
+
},
|
|
34968
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
34969
|
+
"shaderMaterial",
|
|
34970
|
+
{
|
|
34971
|
+
ref: materialRef,
|
|
34972
|
+
glslVersion: GLSL3,
|
|
34973
|
+
vertexShader: SDF_BRICK_VERTEX_SHADER,
|
|
34974
|
+
fragmentShader: SDF_BRICK_FRAGMENT_SHADER,
|
|
34975
|
+
uniforms,
|
|
34976
|
+
side: DoubleSide,
|
|
34977
|
+
transparent: opacity < 1 || ((materialProps == null ? void 0 : materialProps.transmission) ?? 0) > 0,
|
|
34978
|
+
depthWrite: opacity >= 1 && ((materialProps == null ? void 0 : materialProps.transmission) ?? 0) <= 0,
|
|
34979
|
+
toneMapped: false
|
|
34980
|
+
}
|
|
34981
|
+
)
|
|
34982
|
+
}
|
|
34983
|
+
)
|
|
34984
|
+
}
|
|
34985
|
+
);
|
|
34986
|
+
}
|
|
34987
|
+
const MAX_CLIP_PLANES = 8;
|
|
34988
|
+
function colorToRgb(color2, fallback) {
|
|
34989
|
+
const resolved = new Color(color2 ?? fallback);
|
|
34990
|
+
return [resolved.r, resolved.g, resolved.b];
|
|
34991
|
+
}
|
|
34992
|
+
function sdfLeaf(data, settings, materialProps) {
|
|
34993
|
+
const opacity = Math.min(settings.opacity, (materialProps == null ? void 0 : materialProps.opacity) ?? 1);
|
|
34994
|
+
return {
|
|
34995
|
+
node: data.node,
|
|
34996
|
+
...data.program ? { program: data.program } : {},
|
|
34997
|
+
color: colorToRgb(settings.color ?? data.colorHex, "#5b9bd5"),
|
|
34998
|
+
alpha: opacity,
|
|
34999
|
+
emissive: colorToRgb(materialProps == null ? void 0 : materialProps.emissive, "#000000"),
|
|
35000
|
+
emissiveIntensity: (materialProps == null ? void 0 : materialProps.emissiveIntensity) ?? 0,
|
|
35001
|
+
metalness: (materialProps == null ? void 0 : materialProps.metalness) ?? 0.05,
|
|
35002
|
+
roughness: (materialProps == null ? void 0 : materialProps.roughness) ?? 0.35,
|
|
35003
|
+
clearcoat: (materialProps == null ? void 0 : materialProps.clearcoat) ?? 0.1,
|
|
35004
|
+
clearcoatRoughness: (materialProps == null ? void 0 : materialProps.clearcoatRoughness) ?? 0.4,
|
|
35005
|
+
transmission: (materialProps == null ? void 0 : materialProps.transmission) ?? 0,
|
|
35006
|
+
reflectivity: (materialProps == null ? void 0 : materialProps.reflectivity) ?? 0.5
|
|
35007
|
+
};
|
|
35008
|
+
}
|
|
35009
|
+
function canRenderSdfDirectly(data) {
|
|
35010
|
+
return Boolean(data && data.preview.mode === "raymarch");
|
|
35011
|
+
}
|
|
35012
|
+
function createProxyGeometry(data) {
|
|
35013
|
+
const { min, max: max2 } = data.bounds;
|
|
35014
|
+
const size = [max2[0] - min[0], max2[1] - min[1], max2[2] - min[2]];
|
|
35015
|
+
if (!size.every((value) => Number.isFinite(value) && value > 0)) return null;
|
|
35016
|
+
const geometry = new BoxGeometry(size[0], size[1], size[2]);
|
|
35017
|
+
geometry.translate((min[0] + max2[0]) / 2, (min[1] + max2[1]) / 2, (min[2] + max2[2]) / 2);
|
|
35018
|
+
return geometry;
|
|
35019
|
+
}
|
|
35020
|
+
function createClipPlaneUniforms() {
|
|
35021
|
+
return Array.from({ length: MAX_CLIP_PLANES }, () => new Vector4(0, 0, 0, 0));
|
|
35022
|
+
}
|
|
35023
|
+
function SdfDirectObject(props) {
|
|
35024
|
+
const gl = useThree((state2) => state2.gl);
|
|
35025
|
+
if (shouldUseSdfDistanceBrick(props.sdf) && gl.capabilities.isWebGL2) {
|
|
35026
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(SdfDistanceBrickObject, { ...props });
|
|
35027
|
+
}
|
|
35028
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(SdfRaymarchObject, { ...props });
|
|
35029
|
+
}
|
|
35030
|
+
function SdfRaymarchObject({
|
|
35031
|
+
sdf,
|
|
35032
|
+
settings,
|
|
35033
|
+
matrix,
|
|
35034
|
+
materialProps,
|
|
35035
|
+
isHovered,
|
|
35036
|
+
clippingPlanes = [],
|
|
35037
|
+
onPointerEnter,
|
|
35038
|
+
onPointerMove,
|
|
35039
|
+
onPointerLeave,
|
|
35040
|
+
onClick,
|
|
35041
|
+
onDoubleClick,
|
|
35042
|
+
onContextMenu
|
|
35043
|
+
}) {
|
|
35044
|
+
const meshRef = reactExports.useRef(null);
|
|
35045
|
+
const materialRef = reactExports.useRef(null);
|
|
35046
|
+
const { camera } = useThree();
|
|
35047
|
+
const viewProjection = reactExports.useMemo(() => new Matrix4(), []);
|
|
35048
|
+
const worldToLocal = reactExports.useMemo(() => new Matrix4(), []);
|
|
35049
|
+
const localClipPlane = reactExports.useMemo(() => new Plane(), []);
|
|
35050
|
+
const geometry = reactExports.useMemo(() => createProxyGeometry(sdf), [sdf]);
|
|
35051
|
+
const fragmentShader2 = reactExports.useMemo(
|
|
35052
|
+
() => buildSdfRaymarchFragmentShader([sdfLeaf(sdf, settings, materialProps)]),
|
|
35053
|
+
[materialProps, settings, sdf]
|
|
35054
|
+
);
|
|
35055
|
+
const uniforms = reactExports.useMemo(
|
|
35056
|
+
() => ({
|
|
35057
|
+
uCameraMatrixWorld: { value: new Matrix4() },
|
|
35058
|
+
uLocalToWorld: { value: new Matrix4() },
|
|
35059
|
+
uWorldToLocal: { value: new Matrix4() },
|
|
35060
|
+
uViewProjectionMatrix: { value: new Matrix4() },
|
|
35061
|
+
uSceneMin: { value: new Vector3(sdf.bounds.min[0], sdf.bounds.min[1], sdf.bounds.min[2]) },
|
|
35062
|
+
uSceneMax: { value: new Vector3(sdf.bounds.max[0], sdf.bounds.max[1], sdf.bounds.max[2]) },
|
|
35063
|
+
uClipPlaneCount: { value: 0 },
|
|
35064
|
+
uClipPlanes: { value: createClipPlaneUniforms() },
|
|
35065
|
+
uHoverLeafIndex: { value: -1 },
|
|
35066
|
+
uHoverColor: { value: new Color(settings.color) },
|
|
35067
|
+
uHoverIntensity: { value: 0 },
|
|
35068
|
+
uIsOrthographic: { value: 0 }
|
|
35069
|
+
}),
|
|
35070
|
+
[sdf.bounds.max, sdf.bounds.min, settings.color]
|
|
35071
|
+
);
|
|
35072
|
+
useFrame(() => {
|
|
35073
|
+
const material = materialRef.current;
|
|
35074
|
+
const mesh = meshRef.current;
|
|
35075
|
+
if (!material || !mesh) return;
|
|
35076
|
+
mesh.updateMatrixWorld();
|
|
35077
|
+
camera.updateMatrixWorld();
|
|
35078
|
+
viewProjection.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
|
|
35079
|
+
worldToLocal.copy(mesh.matrixWorld).invert();
|
|
35080
|
+
material.uniforms.uCameraMatrixWorld.value.copy(camera.matrixWorld);
|
|
35081
|
+
material.uniforms.uLocalToWorld.value.copy(mesh.matrixWorld);
|
|
35082
|
+
material.uniforms.uWorldToLocal.value.copy(worldToLocal);
|
|
35083
|
+
material.uniforms.uViewProjectionMatrix.value.copy(viewProjection);
|
|
35084
|
+
material.uniforms.uIsOrthographic.value = camera.isOrthographicCamera ? 1 : 0;
|
|
35085
|
+
material.uniforms.uHoverLeafIndex.value = isHovered ? 0 : -1;
|
|
35086
|
+
material.uniforms.uHoverColor.value.set(settings.color);
|
|
35087
|
+
material.uniforms.uHoverIntensity.value = isHovered ? 0.3 : 0;
|
|
35088
|
+
material.uniforms.uClipPlaneCount.value = Math.min(clippingPlanes.length, MAX_CLIP_PLANES);
|
|
35089
|
+
const clipUniforms = material.uniforms.uClipPlanes.value;
|
|
35090
|
+
for (let i = 0; i < MAX_CLIP_PLANES; i += 1) {
|
|
35091
|
+
const source = clippingPlanes[i];
|
|
35092
|
+
if (!source) {
|
|
35093
|
+
clipUniforms[i].set(0, 0, 0, 0);
|
|
35094
|
+
continue;
|
|
35095
|
+
}
|
|
35096
|
+
localClipPlane.copy(source).applyMatrix4(worldToLocal);
|
|
35097
|
+
clipUniforms[i].set(localClipPlane.normal.x, localClipPlane.normal.y, localClipPlane.normal.z, localClipPlane.constant);
|
|
35098
|
+
}
|
|
35099
|
+
});
|
|
35100
|
+
reactExports.useEffect(() => {
|
|
35101
|
+
return () => geometry == null ? void 0 : geometry.dispose();
|
|
35102
|
+
}, [geometry]);
|
|
35103
|
+
if (!geometry) return null;
|
|
35104
|
+
const opacity = Math.min(settings.opacity, (materialProps == null ? void 0 : materialProps.opacity) ?? 1);
|
|
35105
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
35106
|
+
"group",
|
|
35107
|
+
{
|
|
35108
|
+
matrixAutoUpdate: false,
|
|
35109
|
+
matrix,
|
|
35110
|
+
onPointerEnter,
|
|
35111
|
+
onPointerMove,
|
|
35112
|
+
onPointerLeave,
|
|
35113
|
+
onClick,
|
|
35114
|
+
onDoubleClick,
|
|
35115
|
+
onContextMenu,
|
|
35116
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx("mesh", { ref: meshRef, geometry, userData: { forgeMesh: true, forgeSdfDirect: true, forgeSdfRenderer: "raymarch" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
35117
|
+
"shaderMaterial",
|
|
35118
|
+
{
|
|
35119
|
+
ref: materialRef,
|
|
35120
|
+
vertexShader: SDF_RAYMARCH_PROXY_VERTEX_SHADER,
|
|
35121
|
+
fragmentShader: fragmentShader2,
|
|
35122
|
+
uniforms,
|
|
35123
|
+
side: DoubleSide,
|
|
35124
|
+
transparent: opacity < 1 || ((materialProps == null ? void 0 : materialProps.transmission) ?? 0) > 0,
|
|
35125
|
+
depthWrite: opacity >= 1 && ((materialProps == null ? void 0 : materialProps.transmission) ?? 0) <= 0,
|
|
35126
|
+
toneMapped: false,
|
|
35127
|
+
extensions: { fragDepth: true }
|
|
35128
|
+
}
|
|
35129
|
+
) })
|
|
35130
|
+
}
|
|
35131
|
+
);
|
|
35132
|
+
}
|
|
34221
35133
|
class ScanProxyWorkerClient {
|
|
34222
35134
|
constructor(workerFactory = () => new Worker(new URL(
|
|
34223
35135
|
/* @vite-ignore */
|
|
@@ -34853,7 +35765,17 @@ function ForgeObject({
|
|
|
34853
35765
|
onContextMenu
|
|
34854
35766
|
}) {
|
|
34855
35767
|
var _a3, _b2, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
|
|
35768
|
+
const wantsDirectSdf = Boolean(
|
|
35769
|
+
canRenderSdfDirectly(obj.sdf) && inspectChannel === "none" && renderStyle !== "scan" && renderStyle !== "matrix" && renderMode !== "wireframe" && !debugHighlightColor
|
|
35770
|
+
);
|
|
34856
35771
|
const { solidGeo, edgesGeo, hasSmoothNormals } = reactExports.useMemo(() => {
|
|
35772
|
+
if (wantsDirectSdf) {
|
|
35773
|
+
return {
|
|
35774
|
+
solidGeo: null,
|
|
35775
|
+
edgesGeo: null,
|
|
35776
|
+
hasSmoothNormals: false
|
|
35777
|
+
};
|
|
35778
|
+
}
|
|
34857
35779
|
if (!obj.shape) {
|
|
34858
35780
|
return {
|
|
34859
35781
|
solidGeo: null,
|
|
@@ -34875,7 +35797,7 @@ function ForgeObject({
|
|
|
34875
35797
|
hasSmoothNormals: false
|
|
34876
35798
|
};
|
|
34877
35799
|
}
|
|
34878
|
-
}, [obj.shape]);
|
|
35800
|
+
}, [obj.shape, wantsDirectSdf]);
|
|
34879
35801
|
const isScalarInspect = inspectChannel === "thickness" || inspectChannel === "roughness";
|
|
34880
35802
|
const isScalarScan = isScalarInspect && inspectDisplayMode === "scan";
|
|
34881
35803
|
const inspectPointGeo = reactExports.useMemo(() => {
|
|
@@ -34934,7 +35856,7 @@ function ForgeObject({
|
|
|
34934
35856
|
Object.values(scanAnalysisGeometries ?? {}).forEach((geometry) => geometry == null ? void 0 : geometry.dispose());
|
|
34935
35857
|
};
|
|
34936
35858
|
}, [scanAnalysisGeometries]);
|
|
34937
|
-
if (!
|
|
35859
|
+
if (!settings.visible) return null;
|
|
34938
35860
|
const effectiveRenderMode = isInteracting && renderMode === "overlay" ? "solid" : renderMode;
|
|
34939
35861
|
const renderStylePreset = getRenderStylePreset(renderStyle);
|
|
34940
35862
|
const materialDefaults = renderStylePreset.material;
|
|
@@ -34954,7 +35876,6 @@ function ForgeObject({
|
|
|
34954
35876
|
const showWire = !isInspecting && effectiveRenderMode === "wireframe";
|
|
34955
35877
|
const effectiveClippingPlanes = clippingPlanes ?? EMPTY_CLIPPING_PLANES$1;
|
|
34956
35878
|
const effectiveSectionPlanes = sectionPlanes ?? EMPTY_SECTION_PLANES$1;
|
|
34957
|
-
const inspectSolidGeo = inspectMeshColorGeo ?? solidGeo;
|
|
34958
35879
|
const hasInspectMeshColors = inspectMeshColorGeo !== null;
|
|
34959
35880
|
const showFloatingContext = showSolid && inspectChannel === "floating";
|
|
34960
35881
|
const showFloatingObject = inspectChannel !== "floating" || hasInspectMeshColors || inspectColor !== "#000000";
|
|
@@ -34976,6 +35897,27 @@ function ForgeObject({
|
|
|
34976
35897
|
const showSectionCapPreview = Boolean(
|
|
34977
35898
|
isInteracting && showSolid && effectiveRenderMode !== "wireframe" && effectiveSectionPlanes.length > 0
|
|
34978
35899
|
);
|
|
35900
|
+
if (wantsDirectSdf && obj.sdf) {
|
|
35901
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
35902
|
+
SdfDirectObject,
|
|
35903
|
+
{
|
|
35904
|
+
sdf: obj.sdf,
|
|
35905
|
+
settings,
|
|
35906
|
+
matrix,
|
|
35907
|
+
materialProps: obj.materialProps,
|
|
35908
|
+
isHovered,
|
|
35909
|
+
clippingPlanes: effectiveClippingPlanes,
|
|
35910
|
+
onPointerEnter,
|
|
35911
|
+
onPointerMove,
|
|
35912
|
+
onPointerLeave,
|
|
35913
|
+
onClick,
|
|
35914
|
+
onDoubleClick,
|
|
35915
|
+
onContextMenu
|
|
35916
|
+
}
|
|
35917
|
+
);
|
|
35918
|
+
}
|
|
35919
|
+
if (!solidGeo) return null;
|
|
35920
|
+
const inspectSolidGeo = inspectMeshColorGeo ?? solidGeo;
|
|
34979
35921
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
34980
35922
|
"group",
|
|
34981
35923
|
{
|
|
@@ -37121,6 +38063,7 @@ function MeasureInfoPanel() {
|
|
|
37121
38063
|
}
|
|
37122
38064
|
return null;
|
|
37123
38065
|
}
|
|
38066
|
+
const MAX_VIEWPORT_PERFORMANCE_SAMPLES = 240;
|
|
37124
38067
|
const getProgramCount = (gl) => {
|
|
37125
38068
|
const info = gl.info;
|
|
37126
38069
|
return Array.isArray(info.programs) ? info.programs.length : 0;
|
|
@@ -37161,6 +38104,26 @@ function collectScanProxyPerformanceInfo(scene) {
|
|
|
37161
38104
|
performanceReplacementCount
|
|
37162
38105
|
} : null;
|
|
37163
38106
|
}
|
|
38107
|
+
function collectSdfDistanceBrickPerformanceInfo(scene) {
|
|
38108
|
+
let count = 0;
|
|
38109
|
+
let voxels = 0;
|
|
38110
|
+
let buildMs = 0;
|
|
38111
|
+
let cpuCount = 0;
|
|
38112
|
+
let webGpuCount = 0;
|
|
38113
|
+
scene.traverse((object) => {
|
|
38114
|
+
const userData = object.userData;
|
|
38115
|
+
if (!userData.forgeSdfDistanceBrick) return;
|
|
38116
|
+
count += 1;
|
|
38117
|
+
voxels += userData.forgeSdfDistanceBrickVoxels ?? 0;
|
|
38118
|
+
buildMs += userData.forgeSdfDistanceBrickBuildMs ?? 0;
|
|
38119
|
+
if (userData.forgeSdfDistanceBrickBuildSource === "webgpu") {
|
|
38120
|
+
webGpuCount += 1;
|
|
38121
|
+
} else {
|
|
38122
|
+
cpuCount += 1;
|
|
38123
|
+
}
|
|
38124
|
+
});
|
|
38125
|
+
return count > 0 ? { count, voxels, buildMs, cpuCount, webGpuCount } : null;
|
|
38126
|
+
}
|
|
37164
38127
|
const TREND_WINDOW = 20;
|
|
37165
38128
|
class TrendTracker {
|
|
37166
38129
|
constructor(size) {
|
|
@@ -37212,6 +38175,88 @@ const formatWorkerStatus = (message) => {
|
|
|
37212
38175
|
if (/timed out/i.test(message)) return "restarted after timeout";
|
|
37213
38176
|
return "restarted after worker error";
|
|
37214
38177
|
};
|
|
38178
|
+
function summarizeViewportPerformanceSamples(samples) {
|
|
38179
|
+
var _a3, _b2, _c, _d;
|
|
38180
|
+
if (samples.length === 0) {
|
|
38181
|
+
return {
|
|
38182
|
+
samples: 0,
|
|
38183
|
+
latestFps: null,
|
|
38184
|
+
averageFps: null,
|
|
38185
|
+
minFps: null,
|
|
38186
|
+
p10Fps: null,
|
|
38187
|
+
averageFrameTimeMs: null,
|
|
38188
|
+
latestDrawCalls: null,
|
|
38189
|
+
latestRenderTriangles: null,
|
|
38190
|
+
latestModelTriangles: null,
|
|
38191
|
+
latestProgramCount: null,
|
|
38192
|
+
latestSdfDistanceBrickCount: null,
|
|
38193
|
+
latestSdfDistanceBrickVoxels: null,
|
|
38194
|
+
latestSdfDistanceBrickCpuCount: null,
|
|
38195
|
+
latestSdfDistanceBrickWebGpuCount: null
|
|
38196
|
+
};
|
|
38197
|
+
}
|
|
38198
|
+
const latest = samples[samples.length - 1];
|
|
38199
|
+
const fpsValues = samples.map((sample) => sample.fps).sort((a2, b2) => a2 - b2);
|
|
38200
|
+
const fpsTotal = samples.reduce((sum, sample) => sum + sample.fps, 0);
|
|
38201
|
+
const frameTimeTotal = samples.reduce((sum, sample) => sum + sample.frameTimeMs, 0);
|
|
38202
|
+
const p10Index = Math.floor((fpsValues.length - 1) * 0.1);
|
|
38203
|
+
return {
|
|
38204
|
+
samples: samples.length,
|
|
38205
|
+
latestFps: latest.fps,
|
|
38206
|
+
averageFps: fpsTotal / samples.length,
|
|
38207
|
+
minFps: fpsValues[0],
|
|
38208
|
+
p10Fps: fpsValues[p10Index],
|
|
38209
|
+
averageFrameTimeMs: frameTimeTotal / samples.length,
|
|
38210
|
+
latestDrawCalls: latest.drawCalls,
|
|
38211
|
+
latestRenderTriangles: latest.renderTriangles,
|
|
38212
|
+
latestModelTriangles: latest.modelTriangles,
|
|
38213
|
+
latestProgramCount: latest.programCount,
|
|
38214
|
+
latestSdfDistanceBrickCount: ((_a3 = latest.sdfDistanceBricks) == null ? void 0 : _a3.count) ?? 0,
|
|
38215
|
+
latestSdfDistanceBrickVoxels: ((_b2 = latest.sdfDistanceBricks) == null ? void 0 : _b2.voxels) ?? 0,
|
|
38216
|
+
latestSdfDistanceBrickCpuCount: ((_c = latest.sdfDistanceBricks) == null ? void 0 : _c.cpuCount) ?? 0,
|
|
38217
|
+
latestSdfDistanceBrickWebGpuCount: ((_d = latest.sdfDistanceBricks) == null ? void 0 : _d.webGpuCount) ?? 0
|
|
38218
|
+
};
|
|
38219
|
+
}
|
|
38220
|
+
function getViewportPerformanceProbe() {
|
|
38221
|
+
if (typeof window === "undefined") return null;
|
|
38222
|
+
if (!window.__forgeViewportPerformance) {
|
|
38223
|
+
window.__forgeViewportPerformance = {
|
|
38224
|
+
latest: null,
|
|
38225
|
+
samples: [],
|
|
38226
|
+
reset() {
|
|
38227
|
+
this.latest = null;
|
|
38228
|
+
this.samples = [];
|
|
38229
|
+
},
|
|
38230
|
+
summary(sampleLimit) {
|
|
38231
|
+
const selected = typeof sampleLimit === "number" && Number.isFinite(sampleLimit) && sampleLimit > 0 ? this.samples.slice(-Math.round(sampleLimit)) : this.samples;
|
|
38232
|
+
return summarizeViewportPerformanceSamples(selected);
|
|
38233
|
+
}
|
|
38234
|
+
};
|
|
38235
|
+
}
|
|
38236
|
+
return window.__forgeViewportPerformance;
|
|
38237
|
+
}
|
|
38238
|
+
function publishViewportPerformanceSample(stats) {
|
|
38239
|
+
const probe = getViewportPerformanceProbe();
|
|
38240
|
+
if (!probe) return;
|
|
38241
|
+
if (!stats) {
|
|
38242
|
+
probe.latest = null;
|
|
38243
|
+
return;
|
|
38244
|
+
}
|
|
38245
|
+
const sample = {
|
|
38246
|
+
...stats,
|
|
38247
|
+
sampledAtMs: performance.now()
|
|
38248
|
+
};
|
|
38249
|
+
probe.latest = sample;
|
|
38250
|
+
probe.samples.push(sample);
|
|
38251
|
+
if (probe.samples.length > MAX_VIEWPORT_PERFORMANCE_SAMPLES) {
|
|
38252
|
+
probe.samples.splice(0, probe.samples.length - MAX_VIEWPORT_PERFORMANCE_SAMPLES);
|
|
38253
|
+
}
|
|
38254
|
+
}
|
|
38255
|
+
function isViewportPerformanceProbeEnabled() {
|
|
38256
|
+
if (typeof window === "undefined") return false;
|
|
38257
|
+
const params = new URLSearchParams(window.location.search);
|
|
38258
|
+
return params.has("viewport-fps") || params.has("viewportPerf") || window.localStorage.getItem("fc-viewport-performance-probe") === "1";
|
|
38259
|
+
}
|
|
37215
38260
|
function PerformanceInfoSampler({
|
|
37216
38261
|
enabled,
|
|
37217
38262
|
modelTriangles,
|
|
@@ -37236,7 +38281,10 @@ function PerformanceInfoSampler({
|
|
|
37236
38281
|
sinceEmitSec: 0,
|
|
37237
38282
|
reactRenderCountAtLastEmit: reactRenderCountRef.current
|
|
37238
38283
|
};
|
|
37239
|
-
if (!enabled)
|
|
38284
|
+
if (!enabled) {
|
|
38285
|
+
publishViewportPerformanceSample(null);
|
|
38286
|
+
onStatsChange(null);
|
|
38287
|
+
}
|
|
37240
38288
|
}, [enabled, modelTriangles, onStatsChange, reactRenderCountRef, sceneObjects]);
|
|
37241
38289
|
useFrame((_state, delta) => {
|
|
37242
38290
|
var _a3, _b2, _c, _d;
|
|
@@ -37251,7 +38299,7 @@ function PerformanceInfoSampler({
|
|
|
37251
38299
|
const reactRendersDelta = reactRenderCountRef.current - sample.reactRenderCountAtLastEmit;
|
|
37252
38300
|
const mem = performance.memory;
|
|
37253
38301
|
const cacheStats = getRunResultCacheStats();
|
|
37254
|
-
|
|
38302
|
+
const stats = {
|
|
37255
38303
|
fps: frameCount / Math.max(sample.elapsedSec, 1e-6),
|
|
37256
38304
|
frameTimeMs: sample.frameTimeMsTotal / frameCount,
|
|
37257
38305
|
sceneObjects,
|
|
@@ -37274,8 +38322,11 @@ function PerformanceInfoSampler({
|
|
|
37274
38322
|
wasmHeapTruckMB: toMB(((_d = evalWorkerClient.workerWasmHeap) == null ? void 0 : _d.truckBytes) ?? null),
|
|
37275
38323
|
workerFailure: evalWorkerClient.lastWorkerFailure,
|
|
37276
38324
|
reactRendersPerSec: reactRendersDelta / Math.max(sample.sinceEmitSec, 1e-6),
|
|
37277
|
-
scanProxy: collectScanProxyPerformanceInfo(scene)
|
|
37278
|
-
|
|
38325
|
+
scanProxy: collectScanProxyPerformanceInfo(scene),
|
|
38326
|
+
sdfDistanceBricks: collectSdfDistanceBrickPerformanceInfo(scene)
|
|
38327
|
+
};
|
|
38328
|
+
publishViewportPerformanceSample(stats);
|
|
38329
|
+
onStatsChange(stats);
|
|
37279
38330
|
sample.frames = 0;
|
|
37280
38331
|
sample.elapsedSec = 0;
|
|
37281
38332
|
sample.frameTimeMsTotal = 0;
|
|
@@ -37802,6 +38853,13 @@ function computeSceneObjectBounds(obj, objectMatrices) {
|
|
|
37802
38853
|
}
|
|
37803
38854
|
return isFiniteBox3(out) ? out : null;
|
|
37804
38855
|
}
|
|
38856
|
+
if (obj.sdf) {
|
|
38857
|
+
const out = new Box3();
|
|
38858
|
+
if (!expandBoundsByTransformedAabb(out, obj.sdf.bounds.min, obj.sdf.bounds.max, matrix)) {
|
|
38859
|
+
return null;
|
|
38860
|
+
}
|
|
38861
|
+
return isFiniteBox3(out) ? out : null;
|
|
38862
|
+
}
|
|
37805
38863
|
if (obj.curve3d) {
|
|
37806
38864
|
const b2 = obj.curve3d.bounds;
|
|
37807
38865
|
const out = new Box3();
|
|
@@ -37814,12 +38872,6 @@ function computeSceneObjectBounds(obj, objectMatrices) {
|
|
|
37814
38872
|
if (!expandBoundsByTransformedAabb(out, b2.min, b2.max, matrix)) return null;
|
|
37815
38873
|
return isFiniteBox3(out) ? out : null;
|
|
37816
38874
|
}
|
|
37817
|
-
if (obj.sdf) {
|
|
37818
|
-
const b2 = obj.sdf.bounds;
|
|
37819
|
-
const out = new Box3();
|
|
37820
|
-
if (!expandBoundsByTransformedAabb(out, b2.min, b2.max, matrix)) return null;
|
|
37821
|
-
return isFiniteBox3(out) ? out : null;
|
|
37822
|
-
}
|
|
37823
38875
|
return null;
|
|
37824
38876
|
}
|
|
37825
38877
|
function computeSceneBounds(objects, objectMatrices) {
|
|
@@ -38259,290 +39311,6 @@ function SectionCaps({
|
|
|
38259
39311
|
);
|
|
38260
39312
|
}) });
|
|
38261
39313
|
}
|
|
38262
|
-
const DEFAULT_COLOR = "#5b9bd5";
|
|
38263
|
-
const BLACK = [0, 0, 0];
|
|
38264
|
-
const MAX_SDF_CLIP_PLANES = 8;
|
|
38265
|
-
const PICK_MAX_STEPS = 220;
|
|
38266
|
-
const PICK_MIN_STEP = 0.012;
|
|
38267
|
-
const PICK_HIT_EPS = 0.05;
|
|
38268
|
-
function colorToRgb(value, fallback = DEFAULT_COLOR) {
|
|
38269
|
-
const color2 = new Color(value || fallback);
|
|
38270
|
-
return [color2.r, color2.g, color2.b];
|
|
38271
|
-
}
|
|
38272
|
-
function clamp01(value) {
|
|
38273
|
-
return Math.min(1, Math.max(0, value));
|
|
38274
|
-
}
|
|
38275
|
-
function computeBounds(leaves) {
|
|
38276
|
-
if (leaves.length === 0) return null;
|
|
38277
|
-
const min = [Infinity, Infinity, Infinity];
|
|
38278
|
-
const max2 = [-Infinity, -Infinity, -Infinity];
|
|
38279
|
-
for (const leaf of leaves) {
|
|
38280
|
-
for (let i = 0; i < 3; i++) {
|
|
38281
|
-
min[i] = Math.min(min[i], leaf.bounds.min[i]);
|
|
38282
|
-
max2[i] = Math.max(max2[i], leaf.bounds.max[i]);
|
|
38283
|
-
}
|
|
38284
|
-
}
|
|
38285
|
-
if (!min.every(Number.isFinite) || !max2.every(Number.isFinite)) return null;
|
|
38286
|
-
const diagonal = Math.hypot(max2[0] - min[0], max2[1] - min[1], max2[2] - min[2]);
|
|
38287
|
-
const pad = Math.max(1, diagonal * 0.04);
|
|
38288
|
-
return {
|
|
38289
|
-
min: [min[0] - pad, min[1] - pad, min[2] - pad],
|
|
38290
|
-
max: [max2[0] + pad, max2[1] + pad, max2[2] + pad]
|
|
38291
|
-
};
|
|
38292
|
-
}
|
|
38293
|
-
function setClipPlaneUniforms(target, clippingPlanes) {
|
|
38294
|
-
const count = Math.min(clippingPlanes.length, MAX_SDF_CLIP_PLANES);
|
|
38295
|
-
for (let i = 0; i < MAX_SDF_CLIP_PLANES; i++) {
|
|
38296
|
-
const plane = clippingPlanes[i];
|
|
38297
|
-
target[i].set((plane == null ? void 0 : plane.normal.x) ?? 0, (plane == null ? void 0 : plane.normal.y) ?? 0, (plane == null ? void 0 : plane.normal.z) ?? 0, (plane == null ? void 0 : plane.constant) ?? 0);
|
|
38298
|
-
}
|
|
38299
|
-
return count;
|
|
38300
|
-
}
|
|
38301
|
-
function clipPlaneDistance(point, clippingPlanes) {
|
|
38302
|
-
let distance = -Infinity;
|
|
38303
|
-
const count = Math.min(clippingPlanes.length, MAX_SDF_CLIP_PLANES);
|
|
38304
|
-
for (let i = 0; i < count; i++) {
|
|
38305
|
-
const plane = clippingPlanes[i];
|
|
38306
|
-
distance = Math.max(distance, -plane.distanceToPoint(point));
|
|
38307
|
-
}
|
|
38308
|
-
return distance;
|
|
38309
|
-
}
|
|
38310
|
-
function clippedDistance(fn, point, clippingPlanes) {
|
|
38311
|
-
return Math.max(fn(point.x, point.y, point.z), clipPlaneDistance(point, clippingPlanes));
|
|
38312
|
-
}
|
|
38313
|
-
function intersectRayBoxRange(ray, box2) {
|
|
38314
|
-
let tNear = -Infinity;
|
|
38315
|
-
let tFar = Infinity;
|
|
38316
|
-
const origin = ray.origin;
|
|
38317
|
-
const direction = ray.direction;
|
|
38318
|
-
for (const axis of ["x", "y", "z"]) {
|
|
38319
|
-
const o2 = origin[axis];
|
|
38320
|
-
const d = direction[axis];
|
|
38321
|
-
const min = box2.min[axis];
|
|
38322
|
-
const max2 = box2.max[axis];
|
|
38323
|
-
if (Math.abs(d) < 1e-10) {
|
|
38324
|
-
if (o2 < min || o2 > max2) return null;
|
|
38325
|
-
continue;
|
|
38326
|
-
}
|
|
38327
|
-
const inv = 1 / d;
|
|
38328
|
-
let t02 = (min - o2) * inv;
|
|
38329
|
-
let t1 = (max2 - o2) * inv;
|
|
38330
|
-
if (t02 > t1) [t02, t1] = [t1, t02];
|
|
38331
|
-
tNear = Math.max(tNear, t02);
|
|
38332
|
-
tFar = Math.min(tFar, t1);
|
|
38333
|
-
if (tFar < tNear) return null;
|
|
38334
|
-
}
|
|
38335
|
-
if (tFar < 0) return null;
|
|
38336
|
-
return { near: Math.max(0, tNear), far: tFar };
|
|
38337
|
-
}
|
|
38338
|
-
function raymarchHit(ray, box2, diagonal, sdfFn, clippingPlanes) {
|
|
38339
|
-
const range = intersectRayBoxRange(ray, box2);
|
|
38340
|
-
if (!range) return null;
|
|
38341
|
-
const maxStep = Math.max(PICK_MIN_STEP, diagonal / 180);
|
|
38342
|
-
const point = new Vector3();
|
|
38343
|
-
let t2 = range.near;
|
|
38344
|
-
let prevT = t2;
|
|
38345
|
-
let prevDist = Number.POSITIVE_INFINITY;
|
|
38346
|
-
let bestT = t2;
|
|
38347
|
-
let bestAbsDist = Number.POSITIVE_INFINITY;
|
|
38348
|
-
for (let i = 0; i < PICK_MAX_STEPS; i++) {
|
|
38349
|
-
point.copy(ray.origin).addScaledVector(ray.direction, t2);
|
|
38350
|
-
const dist = clippedDistance(sdfFn, point, clippingPlanes);
|
|
38351
|
-
const absDist = Math.abs(dist);
|
|
38352
|
-
if (absDist < bestAbsDist) {
|
|
38353
|
-
bestAbsDist = absDist;
|
|
38354
|
-
bestT = t2;
|
|
38355
|
-
}
|
|
38356
|
-
if (absDist < PICK_HIT_EPS) return point;
|
|
38357
|
-
if (Number.isFinite(prevDist) && (prevDist < 0 && dist > 0 || prevDist > 0 && dist < 0)) {
|
|
38358
|
-
let lo = prevT;
|
|
38359
|
-
let hi = t2;
|
|
38360
|
-
const midPoint = point.clone();
|
|
38361
|
-
let dLo = prevDist;
|
|
38362
|
-
for (let step = 0; step < 8; step++) {
|
|
38363
|
-
const mid = (lo + hi) * 0.5;
|
|
38364
|
-
midPoint.copy(ray.origin).addScaledVector(ray.direction, mid);
|
|
38365
|
-
const dMid = clippedDistance(sdfFn, midPoint, clippingPlanes);
|
|
38366
|
-
if (Math.abs(dMid) < PICK_HIT_EPS) return midPoint;
|
|
38367
|
-
if (dLo < 0 && dMid > 0 || dLo > 0 && dMid < 0) {
|
|
38368
|
-
hi = mid;
|
|
38369
|
-
} else {
|
|
38370
|
-
lo = mid;
|
|
38371
|
-
dLo = dMid;
|
|
38372
|
-
}
|
|
38373
|
-
}
|
|
38374
|
-
return midPoint;
|
|
38375
|
-
}
|
|
38376
|
-
prevT = t2;
|
|
38377
|
-
prevDist = dist;
|
|
38378
|
-
t2 += MathUtils.clamp(absDist * 0.5, PICK_MIN_STEP, maxStep);
|
|
38379
|
-
if (t2 > range.far) break;
|
|
38380
|
-
}
|
|
38381
|
-
return bestAbsDist < PICK_HIT_EPS * 2 ? ray.origin.clone().addScaledVector(ray.direction, bestT) : null;
|
|
38382
|
-
}
|
|
38383
|
-
function SdfRaymarchObject({
|
|
38384
|
-
obj,
|
|
38385
|
-
settings,
|
|
38386
|
-
clippingPlanes,
|
|
38387
|
-
isHovered,
|
|
38388
|
-
onPointerEnter,
|
|
38389
|
-
onPointerMove,
|
|
38390
|
-
onPointerLeave,
|
|
38391
|
-
onClick,
|
|
38392
|
-
onDoubleClick,
|
|
38393
|
-
onContextMenu
|
|
38394
|
-
}) {
|
|
38395
|
-
const meshRef = reactExports.useRef(null);
|
|
38396
|
-
const sdf = obj.sdf;
|
|
38397
|
-
const bounds = reactExports.useMemo(() => sdf ? computeBounds([sdf]) : null, [sdf]);
|
|
38398
|
-
const boundsBox = reactExports.useMemo(
|
|
38399
|
-
() => bounds ? new Box3(new Vector3(...bounds.min), new Vector3(...bounds.max)) : null,
|
|
38400
|
-
[bounds]
|
|
38401
|
-
);
|
|
38402
|
-
const boundsDiagonal = reactExports.useMemo(() => boundsBox ? boundsBox.getSize(new Vector3()).length() : 0, [boundsBox]);
|
|
38403
|
-
const sdfFn = reactExports.useMemo(() => sdf ? compileSdfNode3(sdf.node) : null, [sdf]);
|
|
38404
|
-
const color2 = reactExports.useMemo(() => colorToRgb((settings == null ? void 0 : settings.color) ?? (sdf == null ? void 0 : sdf.colorHex)), [sdf == null ? void 0 : sdf.colorHex, settings == null ? void 0 : settings.color]);
|
|
38405
|
-
const leaf = reactExports.useMemo(() => {
|
|
38406
|
-
var _a3, _b2, _c, _d, _e, _f, _g, _h, _i;
|
|
38407
|
-
if (!sdf) return null;
|
|
38408
|
-
const materialAlpha = ((_a3 = sdf.materialProps) == null ? void 0 : _a3.opacity) ?? 1;
|
|
38409
|
-
return {
|
|
38410
|
-
node: sdf.node,
|
|
38411
|
-
color: color2,
|
|
38412
|
-
alpha: clamp01(Math.min((settings == null ? void 0 : settings.opacity) ?? 1, materialAlpha)),
|
|
38413
|
-
emissive: ((_b2 = sdf.materialProps) == null ? void 0 : _b2.emissive) ? colorToRgb(sdf.materialProps.emissive, "#000000") : BLACK,
|
|
38414
|
-
emissiveIntensity: ((_c = sdf.materialProps) == null ? void 0 : _c.emissiveIntensity) ?? 0,
|
|
38415
|
-
metalness: clamp01(((_d = sdf.materialProps) == null ? void 0 : _d.metalness) ?? 0.05),
|
|
38416
|
-
roughness: clamp01(((_e = sdf.materialProps) == null ? void 0 : _e.roughness) ?? 0.35),
|
|
38417
|
-
clearcoat: clamp01(((_f = sdf.materialProps) == null ? void 0 : _f.clearcoat) ?? 0.1),
|
|
38418
|
-
clearcoatRoughness: clamp01(((_g = sdf.materialProps) == null ? void 0 : _g.clearcoatRoughness) ?? 0.4),
|
|
38419
|
-
transmission: clamp01(((_h = sdf.materialProps) == null ? void 0 : _h.transmission) ?? 0),
|
|
38420
|
-
reflectivity: clamp01(((_i = sdf.materialProps) == null ? void 0 : _i.reflectivity) ?? 0.5)
|
|
38421
|
-
};
|
|
38422
|
-
}, [color2, sdf, settings == null ? void 0 : settings.opacity]);
|
|
38423
|
-
const isTransparent = ((leaf == null ? void 0 : leaf.alpha) ?? 1) < 1 || ((leaf == null ? void 0 : leaf.transmission) ?? 0) > 0;
|
|
38424
|
-
const fragmentShader2 = reactExports.useMemo(() => leaf ? buildSdfRaymarchFragmentShader([leaf]) : null, [leaf]);
|
|
38425
|
-
const clipPlaneUniforms = reactExports.useMemo(() => Array.from({ length: MAX_SDF_CLIP_PLANES }, () => new Vector4()), []);
|
|
38426
|
-
const material = reactExports.useMemo(() => {
|
|
38427
|
-
if (!fragmentShader2) return null;
|
|
38428
|
-
return new ShaderMaterial({
|
|
38429
|
-
vertexShader: SDF_RAYMARCH_PROXY_VERTEX_SHADER,
|
|
38430
|
-
fragmentShader: fragmentShader2,
|
|
38431
|
-
side: BackSide,
|
|
38432
|
-
transparent: isTransparent,
|
|
38433
|
-
depthTest: true,
|
|
38434
|
-
// SDF previews render a proxy box, but the shader writes the actual
|
|
38435
|
-
// raymarched hit depth. Keep depth writes on for transparent SDFs so
|
|
38436
|
-
// overlapping leaves sort by their real surface depth instead of by the
|
|
38437
|
-
// proxy box centers used by Three's transparent object sorter.
|
|
38438
|
-
depthWrite: true,
|
|
38439
|
-
uniforms: {
|
|
38440
|
-
uCameraMatrixWorld: { value: new Matrix4() },
|
|
38441
|
-
uViewProjectionMatrix: { value: new Matrix4() },
|
|
38442
|
-
uSceneMin: { value: new Vector3() },
|
|
38443
|
-
uSceneMax: { value: new Vector3() },
|
|
38444
|
-
uClipPlaneCount: { value: 0 },
|
|
38445
|
-
uClipPlanes: { value: clipPlaneUniforms },
|
|
38446
|
-
uHoverLeafIndex: { value: -1 },
|
|
38447
|
-
uHoverColor: { value: new Vector3() },
|
|
38448
|
-
uHoverIntensity: { value: 0 },
|
|
38449
|
-
uIsOrthographic: { value: 0 }
|
|
38450
|
-
}
|
|
38451
|
-
});
|
|
38452
|
-
}, [clipPlaneUniforms, fragmentShader2, isTransparent]);
|
|
38453
|
-
reactExports.useEffect(() => () => material == null ? void 0 : material.dispose(), [material]);
|
|
38454
|
-
useFrame(({ camera }) => {
|
|
38455
|
-
if (!bounds || !material) return;
|
|
38456
|
-
material.uniforms.uCameraMatrixWorld.value.copy(camera.matrixWorld);
|
|
38457
|
-
material.uniforms.uViewProjectionMatrix.value.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
|
|
38458
|
-
material.uniforms.uSceneMin.value.set(bounds.min[0], bounds.min[1], bounds.min[2]);
|
|
38459
|
-
material.uniforms.uSceneMax.value.set(bounds.max[0], bounds.max[1], bounds.max[2]);
|
|
38460
|
-
material.uniforms.uClipPlaneCount.value = setClipPlaneUniforms(clipPlaneUniforms, clippingPlanes);
|
|
38461
|
-
material.uniforms.uHoverLeafIndex.value = isHovered ? 0 : -1;
|
|
38462
|
-
material.uniforms.uHoverColor.value.set(color2[0], color2[1], color2[2]);
|
|
38463
|
-
material.uniforms.uHoverIntensity.value = isHovered ? 0.3 : 0;
|
|
38464
|
-
material.uniforms.uIsOrthographic.value = camera.isOrthographicCamera ? 1 : 0;
|
|
38465
|
-
});
|
|
38466
|
-
const raycast = reactExports.useCallback(
|
|
38467
|
-
(raycaster, intersections) => {
|
|
38468
|
-
const object = meshRef.current;
|
|
38469
|
-
if (!object || !boundsBox || !sdfFn) return;
|
|
38470
|
-
const point = raymarchHit(raycaster.ray, boundsBox, boundsDiagonal, sdfFn, clippingPlanes);
|
|
38471
|
-
if (!point) return;
|
|
38472
|
-
const distance = raycaster.ray.origin.distanceTo(point);
|
|
38473
|
-
if (distance < raycaster.near || distance > raycaster.far) return;
|
|
38474
|
-
intersections.push({ distance, point, object });
|
|
38475
|
-
},
|
|
38476
|
-
[boundsBox, boundsDiagonal, clippingPlanes, sdfFn]
|
|
38477
|
-
);
|
|
38478
|
-
if (!bounds || !material || !sdfFn) return null;
|
|
38479
|
-
const size = [
|
|
38480
|
-
Math.max(bounds.max[0] - bounds.min[0], 1e-3),
|
|
38481
|
-
Math.max(bounds.max[1] - bounds.min[1], 1e-3),
|
|
38482
|
-
Math.max(bounds.max[2] - bounds.min[2], 1e-3)
|
|
38483
|
-
];
|
|
38484
|
-
const center = [
|
|
38485
|
-
(bounds.min[0] + bounds.max[0]) * 0.5,
|
|
38486
|
-
(bounds.min[1] + bounds.max[1]) * 0.5,
|
|
38487
|
-
(bounds.min[2] + bounds.max[2]) * 0.5
|
|
38488
|
-
];
|
|
38489
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
38490
|
-
"mesh",
|
|
38491
|
-
{
|
|
38492
|
-
ref: meshRef,
|
|
38493
|
-
position: center,
|
|
38494
|
-
frustumCulled: false,
|
|
38495
|
-
raycast,
|
|
38496
|
-
onPointerEnter,
|
|
38497
|
-
onPointerMove,
|
|
38498
|
-
onPointerLeave,
|
|
38499
|
-
onClick,
|
|
38500
|
-
onDoubleClick,
|
|
38501
|
-
onContextMenu,
|
|
38502
|
-
children: [
|
|
38503
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("boxGeometry", { args: size }),
|
|
38504
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("primitive", { object: material, attach: "material" })
|
|
38505
|
-
]
|
|
38506
|
-
}
|
|
38507
|
-
);
|
|
38508
|
-
}
|
|
38509
|
-
function SdfRaymarchLayer({
|
|
38510
|
-
objects,
|
|
38511
|
-
objectSettings,
|
|
38512
|
-
clippingPlanesById,
|
|
38513
|
-
hoveredObjectId,
|
|
38514
|
-
onPointerEnter,
|
|
38515
|
-
onPointerMove,
|
|
38516
|
-
onPointerLeave,
|
|
38517
|
-
onClick,
|
|
38518
|
-
onDoubleClick,
|
|
38519
|
-
onContextMenu
|
|
38520
|
-
}) {
|
|
38521
|
-
const visibleSdfObjects = reactExports.useMemo(
|
|
38522
|
-
() => objects.filter((obj) => {
|
|
38523
|
-
var _a3;
|
|
38524
|
-
return obj.sdf && (((_a3 = objectSettings[obj.id]) == null ? void 0 : _a3.visible) ?? true);
|
|
38525
|
-
}),
|
|
38526
|
-
[objectSettings, objects]
|
|
38527
|
-
);
|
|
38528
|
-
if (visibleSdfObjects.length === 0) return null;
|
|
38529
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx("group", { children: visibleSdfObjects.map((obj) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
38530
|
-
SdfRaymarchObject,
|
|
38531
|
-
{
|
|
38532
|
-
obj,
|
|
38533
|
-
settings: objectSettings[obj.id],
|
|
38534
|
-
clippingPlanes: clippingPlanesById[obj.id] ?? EMPTY_CLIPPING_PLANES,
|
|
38535
|
-
isHovered: hoveredObjectId === obj.id,
|
|
38536
|
-
onPointerEnter: onPointerEnter ? (event) => onPointerEnter(obj, event) : void 0,
|
|
38537
|
-
onPointerMove: onPointerMove ? (event) => onPointerMove(obj, event) : void 0,
|
|
38538
|
-
onPointerLeave: onPointerLeave ? (event) => onPointerLeave(obj, event) : void 0,
|
|
38539
|
-
onClick: onClick ? (event) => onClick(obj, event) : void 0,
|
|
38540
|
-
onDoubleClick: onDoubleClick ? (event) => onDoubleClick(obj, event) : void 0,
|
|
38541
|
-
onContextMenu: onContextMenu ? (event) => onContextMenu(obj, event) : void 0
|
|
38542
|
-
},
|
|
38543
|
-
obj.id
|
|
38544
|
-
)) });
|
|
38545
|
-
}
|
|
38546
39314
|
function findHoveredSurface(x, y, meta) {
|
|
38547
39315
|
for (let i = meta.surfaces.length - 1; i >= 0; i--) {
|
|
38548
39316
|
const s = meta.surfaces[i];
|
|
@@ -42395,6 +43163,10 @@ function useViewportState() {
|
|
|
42395
43163
|
}
|
|
42396
43164
|
return;
|
|
42397
43165
|
}
|
|
43166
|
+
if (obj.sdf) {
|
|
43167
|
+
if (expandBoundsByTransformedAabb(bounds, obj.sdf.bounds.min, obj.sdf.bounds.max, matrix)) hasBounds = true;
|
|
43168
|
+
return;
|
|
43169
|
+
}
|
|
42398
43170
|
if (obj.sketch) {
|
|
42399
43171
|
try {
|
|
42400
43172
|
const bb = obj.sketch.bounds();
|
|
@@ -42403,15 +43175,16 @@ function useViewportState() {
|
|
|
42403
43175
|
}
|
|
42404
43176
|
return;
|
|
42405
43177
|
}
|
|
43178
|
+
if (obj.curve3d) {
|
|
43179
|
+
const cb = obj.curve3d.bounds;
|
|
43180
|
+
if (expandBoundsByTransformedAabb(bounds, cb.min, cb.max, matrix)) hasBounds = true;
|
|
43181
|
+
return;
|
|
43182
|
+
}
|
|
42406
43183
|
if (obj.toolpath) {
|
|
42407
43184
|
const tb = obj.toolpath.bounds;
|
|
42408
43185
|
if (expandBoundsByTransformedAabb(bounds, tb.min, tb.max, matrix)) hasBounds = true;
|
|
42409
43186
|
return;
|
|
42410
43187
|
}
|
|
42411
|
-
if (obj.sdf) {
|
|
42412
|
-
const sb = obj.sdf.bounds;
|
|
42413
|
-
if (expandBoundsByTransformedAabb(bounds, sb.min, sb.max, matrix)) hasBounds = true;
|
|
42414
|
-
}
|
|
42415
43188
|
});
|
|
42416
43189
|
return hasBounds ? bounds.min.z : null;
|
|
42417
43190
|
}, [objects, objectMatrices]);
|
|
@@ -42428,6 +43201,10 @@ function useViewportState() {
|
|
|
42428
43201
|
if (expandBoundsByTransformedAabb(bounds, bb.min, bb.max, matrix)) hasBounds = true;
|
|
42429
43202
|
} catch {
|
|
42430
43203
|
}
|
|
43204
|
+
return;
|
|
43205
|
+
}
|
|
43206
|
+
if (obj.sdf) {
|
|
43207
|
+
if (expandBoundsByTransformedAabb(bounds, obj.sdf.bounds.min, obj.sdf.bounds.max, matrix)) hasBounds = true;
|
|
42431
43208
|
}
|
|
42432
43209
|
});
|
|
42433
43210
|
if (!hasBounds) return { surfaceFieldScale: 1, scanProxyGrid: null };
|
|
@@ -42455,6 +43232,10 @@ function useViewportState() {
|
|
|
42455
43232
|
}
|
|
42456
43233
|
return;
|
|
42457
43234
|
}
|
|
43235
|
+
if (obj.sdf) {
|
|
43236
|
+
if (expandBoundsByTransformedAabb(bounds, obj.sdf.bounds.min, obj.sdf.bounds.max, matrix)) hasBounds = true;
|
|
43237
|
+
return;
|
|
43238
|
+
}
|
|
42458
43239
|
if (obj.sketch) {
|
|
42459
43240
|
try {
|
|
42460
43241
|
const bb = obj.sketch.bounds();
|
|
@@ -42463,15 +43244,16 @@ function useViewportState() {
|
|
|
42463
43244
|
}
|
|
42464
43245
|
return;
|
|
42465
43246
|
}
|
|
43247
|
+
if (obj.curve3d) {
|
|
43248
|
+
const cb = obj.curve3d.bounds;
|
|
43249
|
+
if (expandBoundsByTransformedAabb(bounds, cb.min, cb.max, matrix)) hasBounds = true;
|
|
43250
|
+
return;
|
|
43251
|
+
}
|
|
42466
43252
|
if (obj.toolpath) {
|
|
42467
43253
|
const tb = obj.toolpath.bounds;
|
|
42468
43254
|
if (expandBoundsByTransformedAabb(bounds, tb.min, tb.max, matrix)) hasBounds = true;
|
|
42469
43255
|
return;
|
|
42470
43256
|
}
|
|
42471
|
-
if (obj.sdf) {
|
|
42472
|
-
const sb = obj.sdf.bounds;
|
|
42473
|
-
if (expandBoundsByTransformedAabb(bounds, sb.min, sb.max, matrix)) hasBounds = true;
|
|
42474
|
-
}
|
|
42475
43257
|
});
|
|
42476
43258
|
if (!hasBounds) return Math.max(60, gridSize * 8);
|
|
42477
43259
|
const size = new Vector3();
|
|
@@ -42491,6 +43273,10 @@ function useViewportState() {
|
|
|
42491
43273
|
}
|
|
42492
43274
|
return;
|
|
42493
43275
|
}
|
|
43276
|
+
if (obj.sdf) {
|
|
43277
|
+
if (expandBoundsByTransformedAabb(bounds, obj.sdf.bounds.min, obj.sdf.bounds.max, IDENTITY_MATRIX$2)) hasBounds = true;
|
|
43278
|
+
return;
|
|
43279
|
+
}
|
|
42494
43280
|
if (obj.sketch) {
|
|
42495
43281
|
try {
|
|
42496
43282
|
const bb = obj.sketch.bounds();
|
|
@@ -42506,15 +43292,16 @@ function useViewportState() {
|
|
|
42506
43292
|
}
|
|
42507
43293
|
return;
|
|
42508
43294
|
}
|
|
43295
|
+
if (obj.curve3d) {
|
|
43296
|
+
const cb = obj.curve3d.bounds;
|
|
43297
|
+
if (expandBoundsByTransformedAabb(bounds, cb.min, cb.max, IDENTITY_MATRIX$2)) hasBounds = true;
|
|
43298
|
+
return;
|
|
43299
|
+
}
|
|
42509
43300
|
if (obj.toolpath) {
|
|
42510
43301
|
const tb = obj.toolpath.bounds;
|
|
42511
43302
|
if (expandBoundsByTransformedAabb(bounds, tb.min, tb.max, IDENTITY_MATRIX$2)) hasBounds = true;
|
|
42512
43303
|
return;
|
|
42513
43304
|
}
|
|
42514
|
-
if (obj.sdf) {
|
|
42515
|
-
const sb = obj.sdf.bounds;
|
|
42516
|
-
if (expandBoundsByTransformedAabb(bounds, sb.min, sb.max, IDENTITY_MATRIX$2)) hasBounds = true;
|
|
42517
|
-
}
|
|
42518
43305
|
});
|
|
42519
43306
|
if (!hasBounds) return Math.max(60, gridSize * 8);
|
|
42520
43307
|
const size = new Vector3();
|
|
@@ -42587,8 +43374,7 @@ function useViewportState() {
|
|
|
42587
43374
|
]);
|
|
42588
43375
|
const rigInspectionBounds = rigInspectionOverlay.bounds;
|
|
42589
43376
|
const hasShape = objects.some((obj) => obj.shape);
|
|
42590
|
-
const
|
|
42591
|
-
const isSketchOnly = !hasShape && !hasSdf && objects.some((obj) => obj.sketch);
|
|
43377
|
+
const isSketchOnly = !hasShape && objects.some((obj) => obj.sketch);
|
|
42592
43378
|
const knownFileNames = reactExports.useMemo(() => new Set(Object.keys(files)), [files]);
|
|
42593
43379
|
const focusedObjectIdSet = reactExports.useMemo(() => new Set(focusedObjectIds), [focusedObjectIds]);
|
|
42594
43380
|
const { visibleSceneObjectCount, visibleModelTriangles } = reactExports.useMemo(() => {
|
|
@@ -44273,7 +45059,7 @@ function useGeometryComparison(args) {
|
|
|
44273
45059
|
class InspectWorkerClient {
|
|
44274
45060
|
constructor(workerFactory = () => new Worker(new URL(
|
|
44275
45061
|
/* @vite-ignore */
|
|
44276
|
-
"/assets/inspectWorker-
|
|
45062
|
+
"/assets/inspectWorker-D5T5VbfK.js",
|
|
44277
45063
|
import.meta.url
|
|
44278
45064
|
), { type: "module" })) {
|
|
44279
45065
|
__publicField(this, "worker", null);
|
|
@@ -45014,6 +45800,7 @@ function VoxelIntentOverlay() {
|
|
|
45014
45800
|
))
|
|
45015
45801
|
] });
|
|
45016
45802
|
}
|
|
45803
|
+
const DEFAULT_OBJECT_SETTINGS = { visible: true, opacity: 1, color: "#5b9bd5" };
|
|
45017
45804
|
function buildManualSceneConfig(base, manualScene, renderStylePreset) {
|
|
45018
45805
|
var _a3, _b2, _c;
|
|
45019
45806
|
const lights = [
|
|
@@ -45424,6 +46211,7 @@ function Viewport() {
|
|
|
45424
46211
|
previewFile,
|
|
45425
46212
|
knownFileNames
|
|
45426
46213
|
} = state2;
|
|
46214
|
+
const viewportPerformanceProbeEnabled = reactExports.useMemo(() => isViewportPerformanceProbeEnabled(), []);
|
|
45427
46215
|
const voxelContextFile = previewFile ?? ((activeFile == null ? void 0 : activeFile.toLowerCase().endsWith(".forge.js")) ? activeFile : null);
|
|
45428
46216
|
const historyMode = useForgeStore((s) => s.historyMode);
|
|
45429
46217
|
const historyObjectIds = useForgeStore((s) => s.historyObjectIds);
|
|
@@ -45464,10 +46252,6 @@ function Viewport() {
|
|
|
45464
46252
|
const inspectChannelActive = inspectChannel !== "none";
|
|
45465
46253
|
const comparisonInspectActive = inspectChannel === "comparison";
|
|
45466
46254
|
const rigInspectActive = inspectChannel === "rig";
|
|
45467
|
-
const hasVisibleSdfObjects = objects.some((obj) => {
|
|
45468
|
-
var _a4;
|
|
45469
|
-
return obj.sdf && (((_a4 = objectSettings[obj.id]) == null ? void 0 : _a4.visible) ?? true);
|
|
45470
|
-
});
|
|
45471
46255
|
const viewportDisabledMessage = reactExports.useMemo(() => {
|
|
45472
46256
|
if (activeFile && !isModelFile(activeFile) && !isSvgActive && !meshPreviewFile) {
|
|
45473
46257
|
return {
|
|
@@ -45483,15 +46267,12 @@ function Viewport() {
|
|
|
45483
46267
|
}
|
|
45484
46268
|
return null;
|
|
45485
46269
|
}, [activeFile, isSvgActive, meshPreviewFile, objects.length, result, rigInspectActive]);
|
|
45486
|
-
const canvasDpr =
|
|
45487
|
-
|
|
45488
|
-
return [1, renderStylePreset.canvasDpr.idleMax];
|
|
45489
|
-
}, [hasVisibleSdfObjects, renderStylePreset.canvasDpr.idleMax, renderStylePreset.canvasDpr.live]);
|
|
45490
|
-
const effectiveSdfObjectSettings = reactExports.useMemo(() => {
|
|
46270
|
+
const canvasDpr = isViewportInteracting ? renderStylePreset.canvasDpr.live : [1, renderStylePreset.canvasDpr.idleMax];
|
|
46271
|
+
const sdfObjectSettings = reactExports.useMemo(() => {
|
|
45491
46272
|
const next = {};
|
|
45492
46273
|
for (const obj of objects) {
|
|
45493
46274
|
if (!obj.sdf) continue;
|
|
45494
|
-
const settings = objectSettings[obj.id] ??
|
|
46275
|
+
const settings = objectSettings[obj.id] ?? DEFAULT_OBJECT_SETTINGS;
|
|
45495
46276
|
const isDimmedByFocus = focusedObjectIdSet.size > 0 && !focusedObjectIdSet.has(obj.id);
|
|
45496
46277
|
const isDimmedByGhost = constructionGhost !== null && obj.id !== constructionGhost.objectId;
|
|
45497
46278
|
next[obj.id] = isDimmedByFocus || isDimmedByGhost ? { ...settings, opacity: Math.min(settings.opacity, FOCUS_MODE_DIM_OPACITY) } : settings;
|
|
@@ -45886,7 +46667,7 @@ function Viewport() {
|
|
|
45886
46667
|
}
|
|
45887
46668
|
),
|
|
45888
46669
|
objects.map((obj, objIndex) => {
|
|
45889
|
-
const settings = objectSettings[obj.id] ??
|
|
46670
|
+
const settings = objectSettings[obj.id] ?? DEFAULT_OBJECT_SETTINGS;
|
|
45890
46671
|
const isDimmedByFocus = focusedObjectIdSet.size > 0 && !focusedObjectIdSet.has(obj.id);
|
|
45891
46672
|
const isDimmedByGhost = constructionGhost !== null && obj.id !== constructionGhost.objectId;
|
|
45892
46673
|
const isDimmedByVoxel = voxelIntentMode && !!obj.shape;
|
|
@@ -45936,6 +46717,26 @@ function Viewport() {
|
|
|
45936
46717
|
obj.id
|
|
45937
46718
|
);
|
|
45938
46719
|
}
|
|
46720
|
+
if (canRenderSdfDirectly(obj.sdf)) {
|
|
46721
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
46722
|
+
SdfDirectObject,
|
|
46723
|
+
{
|
|
46724
|
+
sdf: obj.sdf,
|
|
46725
|
+
settings: sdfObjectSettings[obj.id] ?? DEFAULT_OBJECT_SETTINGS,
|
|
46726
|
+
matrix,
|
|
46727
|
+
materialProps: obj.materialProps,
|
|
46728
|
+
isHovered,
|
|
46729
|
+
clippingPlanes: objectClippingPlanes,
|
|
46730
|
+
onPointerEnter: (event) => updateHoverLabel(obj, event),
|
|
46731
|
+
onPointerMove: (event) => updateHoverLabel(obj, event),
|
|
46732
|
+
onPointerLeave: (event) => clearHoverLabel(obj, event),
|
|
46733
|
+
onClick: (event) => handleObjectClick(obj, event),
|
|
46734
|
+
onDoubleClick: (event) => handleObjectDoubleClick(obj, event),
|
|
46735
|
+
onContextMenu: (event) => handleObjectContextMenu(obj, event)
|
|
46736
|
+
},
|
|
46737
|
+
obj.id
|
|
46738
|
+
);
|
|
46739
|
+
}
|
|
45939
46740
|
if (obj.sketch) {
|
|
45940
46741
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
45941
46742
|
SketchObject,
|
|
@@ -46049,7 +46850,7 @@ function Viewport() {
|
|
|
46049
46850
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
46050
46851
|
PerformanceInfoSampler,
|
|
46051
46852
|
{
|
|
46052
|
-
enabled: showPerformanceInfo,
|
|
46853
|
+
enabled: showPerformanceInfo || viewportPerformanceProbeEnabled,
|
|
46053
46854
|
sceneObjects: visibleSceneObjectCount,
|
|
46054
46855
|
modelTriangles: visibleModelTriangles,
|
|
46055
46856
|
reactRenderCountRef,
|
|
@@ -46072,21 +46873,6 @@ function Viewport() {
|
|
|
46072
46873
|
infiniteGrid: true
|
|
46073
46874
|
}
|
|
46074
46875
|
),
|
|
46075
|
-
!isSketchOnly && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
46076
|
-
SdfRaymarchLayer,
|
|
46077
|
-
{
|
|
46078
|
-
objects,
|
|
46079
|
-
objectSettings: effectiveSdfObjectSettings,
|
|
46080
|
-
clippingPlanesById: objectClippingPlanesById,
|
|
46081
|
-
hoveredObjectId,
|
|
46082
|
-
onPointerEnter: (obj, event) => updateHoverLabel(obj, event),
|
|
46083
|
-
onPointerMove: (obj, event) => updateHoverLabel(obj, event),
|
|
46084
|
-
onPointerLeave: (obj, event) => clearHoverLabel(obj, event),
|
|
46085
|
-
onClick: (obj, event) => voxelIntentMode ? handleVoxelObjectSurfaceClick(event, objectMatrices[obj.id] ?? new Matrix4()) : handleObjectClick(obj, event),
|
|
46086
|
-
onDoubleClick: (obj, event) => handleObjectDoubleClick(obj, event),
|
|
46087
|
-
onContextMenu: (obj, event) => handleObjectContextMenu(obj, event)
|
|
46088
|
-
}
|
|
46089
|
-
),
|
|
46090
46876
|
axesVisible && !isSketchOnly && /* @__PURE__ */ jsxRuntimeExports.jsx(LabeledAxes, {}),
|
|
46091
46877
|
axesVisible && isSketchOnly && /* @__PURE__ */ jsxRuntimeExports.jsx(SketchAxes, {}),
|
|
46092
46878
|
isSketchOnly && /* @__PURE__ */ jsxRuntimeExports.jsx(CursorTracker, { onMove: (x, y) => setCursorPos({ x, y }) }),
|
|
@@ -46702,7 +47488,7 @@ function Viewport() {
|
|
|
46702
47488
|
}
|
|
46703
47489
|
);
|
|
46704
47490
|
}
|
|
46705
|
-
const EditorApp$1 = reactExports.lazy(() => __vitePreload(() => import("./EditorApp-
|
|
47491
|
+
const EditorApp$1 = reactExports.lazy(() => __vitePreload(() => import("./EditorApp-Bfd3jbtC.js"), true ? __vite__mapDeps([0]) : void 0).then((m2) => ({ default: m2.EditorApp })));
|
|
46706
47492
|
const PENDING_SHARE_COPY_KEY = "fc-pending-share-copy";
|
|
46707
47493
|
function storePendingShareCopy(shareId) {
|
|
46708
47494
|
sessionStorage.setItem(PENDING_SHARE_COPY_KEY, shareId);
|
|
@@ -46736,7 +47522,7 @@ function PublishedModelPage() {
|
|
|
46736
47522
|
checkSession();
|
|
46737
47523
|
}, [checkSession]);
|
|
46738
47524
|
reactExports.useEffect(() => {
|
|
46739
|
-
|
|
47525
|
+
initBackendForEvaluation(useForgeStore.getState().activeBackend).then(() => {
|
|
46740
47526
|
setKernelReady(true);
|
|
46741
47527
|
});
|
|
46742
47528
|
}, []);
|
|
@@ -46968,17 +47754,17 @@ function SeoMetadata() {
|
|
|
46968
47754
|
}, [location.pathname]);
|
|
46969
47755
|
return null;
|
|
46970
47756
|
}
|
|
46971
|
-
reactExports.lazy(() => __vitePreload(() => import("./LandingPageProofDriven-
|
|
46972
|
-
const DocsPage = reactExports.lazy(() => __vitePreload(() => import("./DocsPage-
|
|
46973
|
-
reactExports.lazy(() => __vitePreload(() => import("./BlogPage-
|
|
46974
|
-
reactExports.lazy(() => __vitePreload(() => import("./BenchmarkPage-
|
|
46975
|
-
reactExports.lazy(() => __vitePreload(() => import("./AdminPage-
|
|
47757
|
+
reactExports.lazy(() => __vitePreload(() => import("./LandingPageProofDriven-DbN7o-Be.js"), true ? __vite__mapDeps([1]) : void 0).then((m2) => ({ default: m2.LandingPageProofDriven })));
|
|
47758
|
+
const DocsPage = reactExports.lazy(() => __vitePreload(() => import("./DocsPage-DsvdiRNK.js"), true ? [] : void 0).then((m2) => ({ default: m2.DocsPage })));
|
|
47759
|
+
reactExports.lazy(() => __vitePreload(() => import("./BlogPage-BssBbnb-.js"), true ? [] : void 0).then((m2) => ({ default: m2.BlogPage })));
|
|
47760
|
+
reactExports.lazy(() => __vitePreload(() => import("./BenchmarkPage-BcRT5iGN.js"), true ? __vite__mapDeps([1,2]) : void 0).then((m2) => ({ default: m2.BenchmarkPage })));
|
|
47761
|
+
reactExports.lazy(() => __vitePreload(() => import("./AdminPage-CHY6ZN-p.js"), true ? [] : void 0).then((m2) => ({ default: m2.AdminPage })));
|
|
46976
47762
|
reactExports.lazy(() => __vitePreload(() => Promise.resolve().then(() => PublishedModelPage$1), true ? void 0 : void 0).then((m2) => ({ default: m2.PublishedModelPage })));
|
|
46977
|
-
reactExports.lazy(() => __vitePreload(() => import("./SettingsPage-
|
|
46978
|
-
reactExports.lazy(() => __vitePreload(() => import("./PricingPage-
|
|
46979
|
-
reactExports.lazy(() => __vitePreload(() => import("./LegalPage-
|
|
46980
|
-
const EditorApp = reactExports.lazy(() => __vitePreload(() => import("./EditorApp-
|
|
46981
|
-
const EmbedViewer = reactExports.lazy(() => __vitePreload(() => import("./EmbedViewer-
|
|
47763
|
+
reactExports.lazy(() => __vitePreload(() => import("./SettingsPage-DZlyu4d4.js"), true ? [] : void 0).then((m2) => ({ default: m2.SettingsPage })));
|
|
47764
|
+
reactExports.lazy(() => __vitePreload(() => import("./PricingPage-Nczr3pRz.js"), true ? __vite__mapDeps([1,3]) : void 0).then((m2) => ({ default: m2.PricingPage })));
|
|
47765
|
+
reactExports.lazy(() => __vitePreload(() => import("./LegalPage-DNGrrY0p.js"), true ? __vite__mapDeps([1,4]) : void 0).then((m2) => ({ default: m2.LegalPage })));
|
|
47766
|
+
const EditorApp = reactExports.lazy(() => __vitePreload(() => import("./EditorApp-Bfd3jbtC.js"), true ? __vite__mapDeps([0]) : void 0).then((m2) => ({ default: m2.EditorApp })));
|
|
47767
|
+
const EmbedViewer = reactExports.lazy(() => __vitePreload(() => import("./EmbedViewer-D5t8WamV.js"), true ? [] : void 0).then((m2) => ({ default: m2.EmbedViewer })));
|
|
46982
47768
|
const embedMode = isEmbedMode() && !window.location.pathname.startsWith("/m/");
|
|
46983
47769
|
const EDITABLE_CRASH_FILE = /\.(?:forge\.js|[cm]?[jt]sx?|json|md|txt|svg|dxf)$/i;
|
|
46984
47770
|
function firstMeaningfulLine(text) {
|