@selvajs/visualization 1.4.1 → 1.6.0-beta.0
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/gpu-dispose-Dich0oW7.js +2 -0
- package/dist/gpu-dispose-Dich0oW7.js.map +1 -0
- package/dist/gpu-dispose-GZmNW-gK.cjs +2 -0
- package/dist/gpu-dispose-GZmNW-gK.cjs.map +1 -0
- package/dist/parse.cjs +61 -3
- package/dist/parse.cjs.map +1 -1
- package/dist/parse.d.cts +15 -3
- package/dist/parse.d.ts +15 -3
- package/dist/parse.js +61 -3
- package/dist/parse.js.map +1 -1
- package/dist/render.cjs +4 -4
- package/dist/render.cjs.map +1 -1
- package/dist/render.d.cts +4 -4
- package/dist/render.d.ts +4 -4
- package/dist/render.js +4 -4
- package/dist/render.js.map +1 -1
- package/dist/{types-C0V-dIU-.d.ts → types-DjPelPRM.d.cts} +8 -4
- package/dist/{types-C0V-dIU-.d.cts → types-DjPelPRM.d.ts} +8 -4
- package/package.json +1 -1
- package/dist/gpu-dispose-CCO5Grel.cjs +0 -2
- package/dist/gpu-dispose-CCO5Grel.cjs.map +0 -1
- package/dist/gpu-dispose-Cl2f9lUC.js +0 -2
- package/dist/gpu-dispose-Cl2f9lUC.js.map +0 -1
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import*as e from"three";const t={VALIDATION_ERROR:`VALIDATION_ERROR`,INVALID_STATE:`INVALID_STATE`,ENVIRONMENT_ERROR:`ENVIRONMENT_ERROR`,INVALID_CONFIG:`INVALID_CONFIG`,ENCODING_ERROR:`ENCODING_ERROR`,UNKNOWN_ERROR:`UNKNOWN_ERROR`};var n=class extends Error{code;context;originalError;constructor(e,n=t.UNKNOWN_ERROR,r){super(e),this.name=`VisualizationError`,this.code=n,this.context=r?.context,this.originalError=r?.originalError,r?.originalError&&(this.cause=r.originalError)}},r=class{debug(){}info(){}warn(){}error(){}},i=class{debug(e,...t){console.debug(e,...t)}info(e,...t){console.info(e,...t)}warn(e,...t){console.warn(e,...t)}error(e,...t){console.error(e,...t)}};let a=new r;function o(){return a}function s(e){if(e===null){a=new r;return}let i=[`debug`,`info`,`warn`,`error`].filter(t=>typeof e[t]!=`function`);if(i.length>0)throw new n(`Logger is missing required method(s): ${i.join(`, `)}. A logger must implement debug, info, warn and error.`,t.INVALID_CONFIG,{context:{missingMethods:i}});a=e}function c(){s(new i)}const l=`technical`,u={studio:{toneMapping:e.ACESFilmicToneMapping,toneMappingExposure:1,envMapIntensity:1,environmentIntensity:.85,hemisphereIntensity:.5,ambientIntensity:.25,cullBackfaces:!1,ambientOcclusion:!0,sunlightIntensity:1.6},technical:{toneMapping:e.NeutralToneMapping,toneMappingExposure:1,envMapIntensity:.55,environmentIntensity:.6,hemisphereIntensity:.25,ambientIntensity:.15,cullBackfaces:!1,ambientOcclusion:!0,sunlightIntensity:2.2},showcase:{toneMapping:e.ACESFilmicToneMapping,toneMappingExposure:1.15,envMapIntensity:1.4,environmentIntensity:1,hemisphereIntensity:.2,ambientIntensity:.1,cullBackfaces:!1,ambientOcclusion:!0,sunlightIntensity:2.6},arctic:{toneMapping:e.NeutralToneMapping,toneMappingExposure:1.05,envMapIntensity:.85,environmentIntensity:1.1,hemisphereIntensity:.3,ambientIntensity:.15,cullBackfaces:!1,ambientOcclusion:!0,sunlightIntensity:2,materialOverride:{color:15659509,metalness:0,roughness:.75}},xray:{toneMapping:e.NeutralToneMapping,toneMappingExposure:1.3,envMapIntensity:.4,environmentIntensity:.8,hemisphereIntensity:.6,ambientIntensity:.6,cullBackfaces:!1,ambientOcclusion:!1,sunlightIntensity:.6,materialOverride:{color:10470632,metalness:0,roughness:.9,opacity:.28,depthWrite:!1,side:e.DoubleSide}},lineart:{toneMapping:e.NeutralToneMapping,toneMappingExposure:1,envMapIntensity:1,environmentIntensity:1,hemisphereIntensity:.6,ambientIntensity:3.2,cullBackfaces:!1,ambientOcclusion:!1,sunlightIntensity:0,requiresEdges:!0,materialOverride:{color:16251130,metalness:0,roughness:1}},wireframe:{toneMapping:e.NeutralToneMapping,toneMappingExposure:1,envMapIntensity:1,environmentIntensity:1,hemisphereIntensity:.4,ambientIntensity:2,cullBackfaces:!1,ambientOcclusion:!1,sunlightIntensity:0,materialOverride:{color:2830648,metalness:0,roughness:1,wireframe:!0,side:e.DoubleSide}}},d=`selvaEnvMapIntensity`;function f(e,t){return e+(1-e)*Math.min(1,Math.max(0,t))}function p(e){let t=u[e];return{envMapIntensity:t.envMapIntensity,cullBackfaces:t.cullBackfaces}}function m(t){if(!t||typeof t!=`string`)return o().warn(`Invalid color input: ${t}, using white`),new e.Color(16777215);let n=t.trim();if(/^#?[0-9A-Fa-f]{6}$/.test(n))try{let t=n.startsWith(`#`)?n:`#${n}`;return new e.Color(t)}catch{return o().warn(`Invalid hex color: ${t}, using white`),new e.Color(16777215)}if(n.includes(`,`)){let t=n.split(`,`).map(e=>parseInt(e.trim(),10));if(t.length===3&&t.every(e=>!isNaN(e)&&e>=0&&e<=255))return new e.Color(t[0]/255,t[1]/255,t[2]/255)}let r=n.toLowerCase();return r in e.Color.NAMES?new e.Color(e.Color.NAMES[r]):(o().warn(`Invalid color string: ${t}, using white`),new e.Color(16777215))}function h(e,t,n=`z`){e.forEach(e=>{e.position[n]-=t})}function g(t){let n=new e.Box3;return t.length===0||t.forEach(t=>{t.updateMatrixWorld(!0);let r=new e.Box3().setFromObject(t);n.union(r)}),n}const _=new Set;function v(e){return e?!_.has(e):!1}const y=new Set;let b=1;function x(e){let t=Math.max(1,e);if(t!==b){b=t;for(let e of y)e(t)}}function S(e){return y.add(e),e(b),()=>y.delete(e)}function C(t){if(v(t)){for(let[n,r]of Object.entries(t))n!==`envMap`&&r instanceof e.Texture&&r.dispose();t.dispose()}}function w(e){e&&(Array.isArray(e)?e.forEach(C):C(e))}function T(e,t={}){let{materials:n=!0}=t;e.traverse(e=>{let t=e;(t.geometry||t.material)&&(t.geometry&&t.geometry?.dispose(),n&&w(t.material))})}export{g as a,u as c,p as d,c as f,n as g,t as h,h as i,d as l,s as m,S as n,m as o,o as p,x as r,l as s,T as t,f as u};
|
|
2
|
+
//# sourceMappingURL=gpu-dispose-Dich0oW7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gpu-dispose-Dich0oW7.js","names":[],"sources":["../src/shared/errors.ts","../src/shared/logger.ts","../src/shared/looks.ts","../src/shared/geometry.ts","../src/shared/gpu-ownership.ts","../src/shared/gpu-capabilities.ts","../src/shared/gpu-dispose.ts"],"sourcesContent":["/**\n * Errors for the visualization package. Replaces `@selvajs/compute`'s `RhinoComputeError`, which\n * mis-named failures on paths (e.g. the plugin WebSocket) that never touch Rhino.Compute. `code`\n * values match compute's so existing catch-sites keep working.\n */\n\nexport const ErrorCodes = {\n\t/** Structural check failed: bad magic bytes, out-of-window index, malformed metadata. */\n\tVALIDATION_ERROR: 'VALIDATION_ERROR',\n\tINVALID_STATE: 'INVALID_STATE',\n\t/** No `DecompressionStream`, no WebGL context, etc. */\n\tENVIRONMENT_ERROR: 'ENVIRONMENT_ERROR',\n\tINVALID_CONFIG: 'INVALID_CONFIG',\n\t/** Base64 input could not be decoded. */\n\tENCODING_ERROR: 'ENCODING_ERROR',\n\tUNKNOWN_ERROR: 'UNKNOWN_ERROR'\n} as const;\n\nexport type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];\n\nexport class VisualizationError extends Error {\n\tpublic readonly code: ErrorCode;\n\tpublic readonly context?: Record<string, unknown>;\n\tpublic readonly originalError?: Error;\n\n\tconstructor(\n\t\tmessage: string,\n\t\tcode: ErrorCode = ErrorCodes.UNKNOWN_ERROR,\n\t\toptions?: { context?: Record<string, unknown>; originalError?: Error }\n\t) {\n\t\tsuper(message);\n\t\tthis.name = 'VisualizationError';\n\t\tthis.code = code;\n\t\tthis.context = options?.context;\n\t\tthis.originalError = options?.originalError;\n\t\tif (options?.originalError) {\n\t\t\t(this as { cause?: unknown }).cause = options.originalError;\n\t\t}\n\t}\n}\n","/**\n * Logging facility for the visualization package. Deliberately local rather than imported from\n * `@selvajs/compute` (logging isn't a compute concern). Mirrors compute's logger shape so a host\n * wanting one sink for both can call `setLogger(computeLogger.getLogger())`.\n */\n\nimport { VisualizationError, ErrorCodes } from './errors.js';\n\nexport interface Logger {\n\tdebug(message: string, ...args: unknown[]): void;\n\tinfo(message: string, ...args: unknown[]): void;\n\twarn(message: string, ...args: unknown[]): void;\n\terror(message: string, ...args: unknown[]): void;\n}\n\nclass NoOpLogger implements Logger {\n\tdebug(): void {}\n\tinfo(): void {}\n\twarn(): void {}\n\terror(): void {}\n}\n\nclass ConsoleLogger implements Logger {\n\tdebug(message: string, ...args: unknown[]): void {\n\t\t// eslint-disable-next-line no-console -- this class exists to be the console sink\n\t\tconsole.debug(message, ...args);\n\t}\n\n\tinfo(message: string, ...args: unknown[]): void {\n\t\tconsole.info(message, ...args);\n\t}\n\n\twarn(message: string, ...args: unknown[]): void {\n\t\tconsole.warn(message, ...args);\n\t}\n\n\terror(message: string, ...args: unknown[]): void {\n\t\tconsole.error(message, ...args);\n\t}\n}\n\n// Defaults to no-op: a library that writes to the console uninvited is a nuisance in a host with\n// its own logging. Opt in with setLogger or enableDebugLogging.\nlet internalLogger: Logger = new NoOpLogger();\n\n// Call per-use rather than caching — the sink is settable at any time.\nexport function getLogger(): Logger {\n\treturn internalLogger;\n}\n\n// Validates logger shape up front: failing here beats a confusing \"getLogger().debug is not a\n// function\" at some later, unrelated call site.\nexport function setLogger(logger: Logger | Console | null): void {\n\tif (logger === null) {\n\t\tinternalLogger = new NoOpLogger();\n\t\treturn;\n\t}\n\n\tconst missing = (['debug', 'info', 'warn', 'error'] as const).filter(\n\t\t(method) => typeof (logger as unknown as Record<string, unknown>)[method] !== 'function'\n\t);\n\tif (missing.length > 0) {\n\t\tthrow new VisualizationError(\n\t\t\t`Logger is missing required method(s): ${missing.join(', ')}. A logger must implement debug, info, warn and error.`,\n\t\t\tErrorCodes.INVALID_CONFIG,\n\t\t\t{ context: { missingMethods: missing } }\n\t\t);\n\t}\n\n\tinternalLogger = logger as Logger;\n}\n\nexport function enableDebugLogging(): void {\n\tsetLogger(new ConsoleLogger());\n}\n","import * as THREE from 'three';\n\nimport type { Look, LookPreset, MaterialAppearanceOptions } from './types.js';\n\n/** The look applied when the caller passes no `look` option. */\nexport const DEFAULT_LOOK: Look = 'technical';\n\n/**\n * Single source of truth for both `applyDefaults` (construction) and `setLook` (runtime), so the two\n * can't drift.\n *\n * Every shaded look pairs a key light with contact shading (GTAO), because image-based lighting on\n * its own lights all faces of a box nearly equally — the result is a white silhouette with no\n * readable form. GTAO is a full-screen pass and does cost frames; `xray` skips it since there are no\n * opaque contacts left to shade.\n */\nexport const LOOK_PRESETS: Record<Look, LookPreset> = {\n\t// Fills shadows in (vs. showcase, which lets them fall off), but still key-lit: ACES plus a\n\t// moderate sun, with fill high enough that shadowed faces keep detail.\n\tstudio: {\n\t\ttoneMapping: THREE.ACESFilmicToneMapping,\n\t\ttoneMappingExposure: 1,\n\t\tenvMapIntensity: 1.0,\n\t\tenvironmentIntensity: 0.85,\n\t\themisphereIntensity: 0.5,\n\t\tambientIntensity: 0.25,\n\t\tcullBackfaces: false,\n\t\tambientOcclusion: true,\n\t\tsunlightIntensity: 1.6\n\t},\n\t// The sun carries this look and the ambient/IBL only lift shadows off black. Fill was the thing\n\t// making it read as flat white paper: every source except the sun is orientation-independent, so\n\t// the more of them you stack the less the three faces of a corner differ.\n\ttechnical: {\n\t\ttoneMapping: THREE.NeutralToneMapping,\n\t\ttoneMappingExposure: 1,\n\t\tenvMapIntensity: 0.55,\n\t\tenvironmentIntensity: 0.6,\n\t\themisphereIntensity: 0.25,\n\t\tambientIntensity: 0.15,\n\t\tcullBackfaces: false,\n\t\tambientOcclusion: true,\n\t\tsunlightIntensity: 2.2\n\t},\n\t// Fill pulled furthest DOWN and the sun pushed hardest, so light-to-shadow falloff is steepest —\n\t// a dramatic hero shot, unlike `studio` which fills shadows back in.\n\tshowcase: {\n\t\ttoneMapping: THREE.ACESFilmicToneMapping,\n\t\ttoneMappingExposure: 1.15,\n\t\tenvMapIntensity: 1.4,\n\t\tenvironmentIntensity: 1.0,\n\t\themisphereIntensity: 0.2,\n\t\tambientIntensity: 0.1,\n\t\tcullBackfaces: false,\n\t\tambientOcclusion: true,\n\t\tsunlightIntensity: 2.6\n\t},\n\t// Every mesh forced to one near-white clay, so form and shadow carry the image instead of the\n\t// model's own colours. AO on: with all albedo differences gone, contact shading is the only thing\n\t// left separating touching parts — without it the model reads as one white blob.\n\tarctic: {\n\t\ttoneMapping: THREE.NeutralToneMapping,\n\t\ttoneMappingExposure: 1.05,\n\t\tenvMapIntensity: 0.85,\n\t\tenvironmentIntensity: 1.1,\n\t\themisphereIntensity: 0.3,\n\t\tambientIntensity: 0.15,\n\t\tcullBackfaces: false,\n\t\tambientOcclusion: true,\n\t\tsunlightIntensity: 2.0,\n\t\tmaterialOverride: {\n\t\t\tcolor: 0xeef1f5,\n\t\t\tmetalness: 0,\n\t\t\troughness: 0.75\n\t\t}\n\t},\n\t// See-through blue-white with depth writes off, so interior geometry shows through the shell.\n\t// Exposure pushed up because stacked transparent layers darken fast; the sun is dialled back\n\t// because a hard highlight on a transparent shell hides what is behind it.\n\txray: {\n\t\ttoneMapping: THREE.NeutralToneMapping,\n\t\ttoneMappingExposure: 1.3,\n\t\tenvMapIntensity: 0.4,\n\t\tenvironmentIntensity: 0.8,\n\t\themisphereIntensity: 0.6,\n\t\tambientIntensity: 0.6,\n\t\tcullBackfaces: false,\n\t\tambientOcclusion: false,\n\t\tsunlightIntensity: 0.6,\n\t\tmaterialOverride: {\n\t\t\tcolor: 0x9fc4e8,\n\t\t\tmetalness: 0,\n\t\t\troughness: 0.9,\n\t\t\topacity: 0.28,\n\t\t\tdepthWrite: false,\n\t\t\tside: THREE.DoubleSide\n\t\t}\n\t},\n\t// The architectural line drawing: feature edges over flat white faces. The faces are the whole\n\t// point even though you never really see them — they still write depth, so a near member hides\n\t// the ones behind it. True wireframe can't do that, and on a dense frame (thousands of members,\n\t// every edge of every one drawn at once) it collapses into a black mass.\n\t//\n\t// Unlit on purpose: any directional shading would compete with the lines for the eye. Ambient\n\t// alone lands every face on the same flat white, so the only contrast in the image is the edges.\n\t// AO is off for the same reason — a grey contact smear under a line drawing just muddies it.\n\tlineart: {\n\t\ttoneMapping: THREE.NeutralToneMapping,\n\t\ttoneMappingExposure: 1,\n\t\t// The faces are MeshPhysicalMaterial, so they take their brightness from lighting, not from\n\t\t// `color`: zero out the lights and they render black however white the override is. Hemisphere\n\t\t// and ambient carry it rather than IBL, because `scene.environment` only exists if the host\n\t\t// loaded an HDR — leaning on IBL would render this look black in any viewer without one. Both\n\t\t// are orientation-independent, so every face lands on the same flat white and the edges stay\n\t\t// the only contrast in the image. Ambient is weighted over hemisphere because hemisphere's\n\t\t// ground colour is a warm brown by default: leaning on it tints every downward face grey and\n\t\t// the drawing stops reading as one flat white.\n\t\tenvMapIntensity: 1.0,\n\t\tenvironmentIntensity: 1.0,\n\t\themisphereIntensity: 0.6,\n\t\tambientIntensity: 3.2,\n\t\tcullBackfaces: false,\n\t\tambientOcclusion: false,\n\t\tsunlightIntensity: 0,\n\t\trequiresEdges: true,\n\t\tmaterialOverride: {\n\t\t\tcolor: 0xf7f8fa,\n\t\t\tmetalness: 0,\n\t\t\troughness: 1\n\t\t}\n\t},\n\t// Triangle edges only — the tessellation itself, diagonals and all. That makes it a mesh-\n\t// inspection tool, not a drawing: for a readable line drawing use `lineart`, which draws\n\t// feature edges and lets near faces occlude far ones. Nothing here is a lit surface:\n\t// the sun is off and fill carries the image, because a directional light on a line renders it\n\t// black wherever the line runs away from the key. AO is off for the same reason — a full-screen\n\t// contact pass has no contacts to find between wires, and it only costs frames.\n\twireframe: {\n\t\ttoneMapping: THREE.NeutralToneMapping,\n\t\ttoneMappingExposure: 1,\n\t\t// Lit for the same reason as lineart (see there): PBR lines are black unlit, and hemisphere\n\t\t// plus ambient work with no HDR loaded. Dimmer than lineart because these lines are dark\n\t\t// on white, not white on dark.\n\t\tenvMapIntensity: 1.0,\n\t\tenvironmentIntensity: 1.0,\n\t\themisphereIntensity: 0.4,\n\t\tambientIntensity: 2.0,\n\t\tcullBackfaces: false,\n\t\tambientOcclusion: false,\n\t\tsunlightIntensity: 0,\n\t\tmaterialOverride: {\n\t\t\tcolor: 0x2b3138,\n\t\t\tmetalness: 0,\n\t\t\troughness: 1,\n\t\t\twireframe: true,\n\t\t\tside: THREE.DoubleSide\n\t\t}\n\t}\n};\n\n/**\n * `userData` key holding a material's own `envMapIntensity`, set by the parser when the wire\n * material carries one. `setLook` keeps it instead of the look's value, except in looks with a\n * `materialOverride`: those restyle every mesh alike, so the look's value wins there.\n */\nexport const OWN_ENV_MAP_INTENSITY = 'selvaEnvMapIntensity';\n\n/**\n * A look dims `envMapIntensity` to turn down fill, but three scales a material's diffuse and\n * specular IBL together. A metal has no diffuse, so the same dimming would only take away its\n * reflection, which is all a metal shows. Blending toward 1 by metalness keeps a dielectric's fill\n * on the look and a metal's reflection the same in every look.\n */\nexport function lookEnvMapIntensity(lookValue: number, metalness: number): number {\n\treturn lookValue + (1 - lookValue) * Math.min(1, Math.max(0, metalness));\n}\n\n/** Baked at parse time (not toggleable at runtime). */\nexport function materialAppearanceForLook(look: Look): MaterialAppearanceOptions {\n\tconst preset = LOOK_PRESETS[look];\n\treturn {\n\t\tenvMapIntensity: preset.envMapIntensity,\n\t\tcullBackfaces: preset.cullBackfaces\n\t};\n}\n","import * as THREE from 'three';\n\nimport { getLogger } from './logger.js';\n\n// parse/ needs these and must never import upward from render/, so they live in shared/ instead\n// of render's three-helpers.\n\nexport function parseColor(colorString: string): THREE.Color {\n\tif (!colorString || typeof colorString !== 'string') {\n\t\tgetLogger().warn(`Invalid color input: ${colorString}, using white`);\n\t\treturn new THREE.Color(0xffffff);\n\t}\n\n\tconst trimmed = colorString.trim();\n\n\tif (/^#?[0-9A-Fa-f]{6}$/.test(trimmed)) {\n\t\ttry {\n\t\t\tconst hex = trimmed.startsWith('#') ? trimmed : `#${trimmed}`;\n\t\t\treturn new THREE.Color(hex);\n\t\t} catch {\n\t\t\tgetLogger().warn(`Invalid hex color: ${colorString}, using white`);\n\t\t\treturn new THREE.Color(0xffffff);\n\t\t}\n\t}\n\n\tif (trimmed.includes(',')) {\n\t\tconst rgb = trimmed.split(',').map((c) => parseInt(c.trim(), 10));\n\t\tif (rgb.length === 3 && rgb.every((n) => !isNaN(n) && n >= 0 && n <= 255)) {\n\t\t\treturn new THREE.Color(rgb[0] / 255, rgb[1] / 255, rgb[2] / 255);\n\t\t}\n\t}\n\n\t// `new THREE.Color(name)` never throws on unknown names (it logs its own warning and leaves the\n\t// color white), so validate against three's CSS name table instead.\n\tconst named = trimmed.toLowerCase();\n\tif (named in THREE.Color.NAMES) {\n\t\treturn new THREE.Color(THREE.Color.NAMES[named as keyof typeof THREE.Color.NAMES]);\n\t}\n\n\tgetLogger().warn(`Invalid color string: ${colorString}, using white`);\n\treturn new THREE.Color(0xffffff);\n}\n\n/** Defaults to `z` (Rhino's up axis); pass an explicit axis when the scene uses a different `sceneUp`. */\nexport function applyOffset(\n\tmeshes: THREE.Object3D[],\n\toffset: number,\n\taxis: 'x' | 'y' | 'z' = 'z'\n): void {\n\tmeshes.forEach((mesh) => {\n\t\tmesh.position[axis] -= offset;\n\t});\n}\n\nexport function computeCombinedBoundingBox(meshes: THREE.Object3D[]): THREE.Box3 {\n\tconst combinedBoundingBox = new THREE.Box3();\n\tif (meshes.length === 0) return combinedBoundingBox;\n\tmeshes.forEach((mesh) => {\n\t\tmesh.updateMatrixWorld(true);\n\t\tconst bbox = new THREE.Box3().setFromObject(mesh);\n\t\tcombinedBoundingBox.union(bbox);\n\t});\n\treturn combinedBoundingBox;\n}\n","import type * as THREE from 'three';\n\n// ============================================================================\n// GPU resource ownership — the single rule every disposal path obeys\n// ============================================================================\n\n/**\n * A GPU resource has exactly one owner: a **module singleton** (nobody ever frees it) or the\n * **scene** (freed on teardown). Every disposal path asks {@link canDisposeMaterial} and disposes\n * only if true. Geometries and textures are always scene-owned, so they have no claim to check.\n */\n\n// Module-scope singletons from `render/three-materials.ts`, shared across meshes and solves —\n// disposing one would free textures still in use and force a recompile. Held here (not imported\n// there) to avoid an import cycle.\nconst protectedMaterials = new Set<THREE.Material>();\n\n/** Register materials as never-disposable. Called once by `render/three-materials.ts`. */\nexport function protectMaterials(materials: Iterable<THREE.Material>): void {\n\tfor (const material of materials) protectedMaterials.add(material);\n}\n\n/** True when `material` is scene-owned (not one of the protected singletons). */\nexport function canDisposeMaterial(material: THREE.Material | undefined): boolean {\n\tif (!material) return false;\n\treturn !protectedMaterials.has(material);\n}\n","// ============================================================================\n// GPU capabilities — published by the renderer, read by whoever needs them\n// ============================================================================\n\n// Lets a renderer publish GPU capabilities (max anisotropy) without `render/` and `parse/` importing\n// each other: the renderer publishes on init, interested parties subscribe.\n\ntype AnisotropyObserver = (value: number) => void;\n\nconst observers = new Set<AnisotropyObserver>();\n\n// Module load order between layers isn't guaranteed, so a subscriber arriving after init still\n// needs the current value rather than waiting for a second renderer to publish.\nlet maxAnisotropy = 1;\n\nexport function publishMaxAnisotropy(value: number): void {\n\tconst next = Math.max(1, value);\n\tif (next === maxAnisotropy) return;\n\tmaxAnisotropy = next;\n\tfor (const observe of observers) observe(next);\n}\n\n/** Fires immediately with the current value (1 until a renderer has reported), then on every change. */\nexport function observeMaxAnisotropy(observe: AnisotropyObserver): () => void {\n\tobservers.add(observe);\n\tobserve(maxAnisotropy);\n\treturn () => observers.delete(observe);\n}\n","import * as THREE from 'three';\n\nimport { canDisposeMaterial } from './gpu-ownership.js';\n\n// ============================================================================\n// The disposal walkers — every teardown path in the package goes through these\n// ============================================================================\n\n/** Frees a material and its textures, respecting ownership (`./gpu-ownership.ts`). */\nexport function disposeMaterial(material: THREE.Material): void {\n\tif (!canDisposeMaterial(material)) return;\n\n\tfor (const [key, value] of Object.entries(material)) {\n\t\t// An envMap is the scene's, shared by every metal: freeing it here would blank them all.\n\t\tif (key === 'envMap') continue;\n\t\tif (value instanceof THREE.Texture) {\n\t\t\tvalue.dispose();\n\t\t}\n\t}\n\tmaterial.dispose();\n}\n\nfunction disposeMaterials(material: THREE.Material | THREE.Material[] | undefined): void {\n\tif (!material) return;\n\tif (Array.isArray(material)) material.forEach(disposeMaterial);\n\telse disposeMaterial(material);\n}\n\nexport interface DisposeOptions {\n\t/** Free materials and their textures too. Default true; the solve memo passes false. */\n\tmaterials?: boolean;\n\t/** Called for each geometry before disposal, so a subsystem can free derived resources keyed on it (e.g. edge caches). */\n\tonGeometry?: (geometry: THREE.BufferGeometry) => void;\n}\n\n/**\n * Frees the GPU resources of an object subtree, respecting ownership. **The only traversal that\n * should dispose scene content** — a second disposing `traverse` risks missing an ownership guard.\n */\nexport function disposeObjectTree(root: THREE.Object3D, options: DisposeOptions = {}): void {\n\tconst { materials = true } = options;\n\n\troot.traverse((object) => {\n\t\tconst renderable = object as Partial<THREE.Mesh> & THREE.Object3D;\n\t\tif (!renderable.geometry && !renderable.material) return;\n\n\t\tif (renderable.geometry) {\n\t\t\trenderable.geometry?.dispose();\n\t\t}\n\n\t\tif (materials) disposeMaterials(renderable.material);\n\t});\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("./rolldown-runtime-BocRIvOZ.cjs");let t=require("three");t=e.t(t,1);const n={VALIDATION_ERROR:`VALIDATION_ERROR`,INVALID_STATE:`INVALID_STATE`,ENVIRONMENT_ERROR:`ENVIRONMENT_ERROR`,INVALID_CONFIG:`INVALID_CONFIG`,ENCODING_ERROR:`ENCODING_ERROR`,UNKNOWN_ERROR:`UNKNOWN_ERROR`};var r=class extends Error{code;context;originalError;constructor(e,t=n.UNKNOWN_ERROR,r){super(e),this.name=`VisualizationError`,this.code=t,this.context=r?.context,this.originalError=r?.originalError,r?.originalError&&(this.cause=r.originalError)}},i=class{debug(){}info(){}warn(){}error(){}},a=class{debug(e,...t){console.debug(e,...t)}info(e,...t){console.info(e,...t)}warn(e,...t){console.warn(e,...t)}error(e,...t){console.error(e,...t)}};let o=new i;function s(){return o}function c(e){if(e===null){o=new i;return}let t=[`debug`,`info`,`warn`,`error`].filter(t=>typeof e[t]!=`function`);if(t.length>0)throw new r(`Logger is missing required method(s): ${t.join(`, `)}. A logger must implement debug, info, warn and error.`,n.INVALID_CONFIG,{context:{missingMethods:t}});o=e}function l(){c(new a)}const u={studio:{toneMapping:t.ACESFilmicToneMapping,toneMappingExposure:1,envMapIntensity:1,environmentIntensity:.85,hemisphereIntensity:.5,ambientIntensity:.25,cullBackfaces:!1,ambientOcclusion:!0,sunlightIntensity:1.6},technical:{toneMapping:t.NeutralToneMapping,toneMappingExposure:1,envMapIntensity:.55,environmentIntensity:.6,hemisphereIntensity:.25,ambientIntensity:.15,cullBackfaces:!1,ambientOcclusion:!0,sunlightIntensity:2.2},showcase:{toneMapping:t.ACESFilmicToneMapping,toneMappingExposure:1.15,envMapIntensity:1.4,environmentIntensity:1,hemisphereIntensity:.2,ambientIntensity:.1,cullBackfaces:!1,ambientOcclusion:!0,sunlightIntensity:2.6},arctic:{toneMapping:t.NeutralToneMapping,toneMappingExposure:1.05,envMapIntensity:.85,environmentIntensity:1.1,hemisphereIntensity:.3,ambientIntensity:.15,cullBackfaces:!1,ambientOcclusion:!0,sunlightIntensity:2,materialOverride:{color:15659509,metalness:0,roughness:.75}},xray:{toneMapping:t.NeutralToneMapping,toneMappingExposure:1.3,envMapIntensity:.4,environmentIntensity:.8,hemisphereIntensity:.6,ambientIntensity:.6,cullBackfaces:!1,ambientOcclusion:!1,sunlightIntensity:.6,materialOverride:{color:10470632,metalness:0,roughness:.9,opacity:.28,depthWrite:!1,side:t.DoubleSide}},lineart:{toneMapping:t.NeutralToneMapping,toneMappingExposure:1,envMapIntensity:1,environmentIntensity:1,hemisphereIntensity:.6,ambientIntensity:3.2,cullBackfaces:!1,ambientOcclusion:!1,sunlightIntensity:0,requiresEdges:!0,materialOverride:{color:16251130,metalness:0,roughness:1}},wireframe:{toneMapping:t.NeutralToneMapping,toneMappingExposure:1,envMapIntensity:1,environmentIntensity:1,hemisphereIntensity:.4,ambientIntensity:2,cullBackfaces:!1,ambientOcclusion:!1,sunlightIntensity:0,materialOverride:{color:2830648,metalness:0,roughness:1,wireframe:!0,side:t.DoubleSide}}};function d(e,t){return e+(1-e)*Math.min(1,Math.max(0,t))}function f(e){let t=u[e];return{envMapIntensity:t.envMapIntensity,cullBackfaces:t.cullBackfaces}}function p(e){if(!e||typeof e!=`string`)return s().warn(`Invalid color input: ${e}, using white`),new t.Color(16777215);let n=e.trim();if(/^#?[0-9A-Fa-f]{6}$/.test(n))try{let e=n.startsWith(`#`)?n:`#${n}`;return new t.Color(e)}catch{return s().warn(`Invalid hex color: ${e}, using white`),new t.Color(16777215)}if(n.includes(`,`)){let e=n.split(`,`).map(e=>parseInt(e.trim(),10));if(e.length===3&&e.every(e=>!isNaN(e)&&e>=0&&e<=255))return new t.Color(e[0]/255,e[1]/255,e[2]/255)}let r=n.toLowerCase();return r in t.Color.NAMES?new t.Color(t.Color.NAMES[r]):(s().warn(`Invalid color string: ${e}, using white`),new t.Color(16777215))}function m(e,t,n=`z`){e.forEach(e=>{e.position[n]-=t})}function h(e){let n=new t.Box3;return e.length===0||e.forEach(e=>{e.updateMatrixWorld(!0);let r=new t.Box3().setFromObject(e);n.union(r)}),n}const g=new Set;function _(e){return e?!g.has(e):!1}const v=new Set;let y=1;function b(e){let t=Math.max(1,e);if(t!==y){y=t;for(let e of v)e(t)}}function x(e){return v.add(e),e(y),()=>v.delete(e)}function S(e){if(_(e)){for(let[n,r]of Object.entries(e))n!==`envMap`&&r instanceof t.Texture&&r.dispose();e.dispose()}}function C(e){e&&(Array.isArray(e)?e.forEach(S):S(e))}function w(e,t={}){let{materials:n=!0}=t;e.traverse(e=>{let t=e;(t.geometry||t.material)&&(t.geometry&&t.geometry?.dispose(),n&&C(t.material))})}Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return h}}),Object.defineProperty(exports,"c",{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,"d",{enumerable:!0,get:function(){return f}}),Object.defineProperty(exports,"f",{enumerable:!0,get:function(){return l}}),Object.defineProperty(exports,"g",{enumerable:!0,get:function(){return r}}),Object.defineProperty(exports,"h",{enumerable:!0,get:function(){return n}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return m}}),Object.defineProperty(exports,"l",{enumerable:!0,get:function(){return`selvaEnvMapIntensity`}}),Object.defineProperty(exports,"m",{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return x}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return p}}),Object.defineProperty(exports,"p",{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return b}}),Object.defineProperty(exports,"s",{enumerable:!0,get:function(){return`technical`}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return w}}),Object.defineProperty(exports,"u",{enumerable:!0,get:function(){return d}});
|
|
2
|
+
//# sourceMappingURL=gpu-dispose-GZmNW-gK.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gpu-dispose-GZmNW-gK.cjs","names":["THREE","THREE","THREE"],"sources":["../src/shared/errors.ts","../src/shared/logger.ts","../src/shared/looks.ts","../src/shared/geometry.ts","../src/shared/gpu-ownership.ts","../src/shared/gpu-capabilities.ts","../src/shared/gpu-dispose.ts"],"sourcesContent":["/**\n * Errors for the visualization package. Replaces `@selvajs/compute`'s `RhinoComputeError`, which\n * mis-named failures on paths (e.g. the plugin WebSocket) that never touch Rhino.Compute. `code`\n * values match compute's so existing catch-sites keep working.\n */\n\nexport const ErrorCodes = {\n\t/** Structural check failed: bad magic bytes, out-of-window index, malformed metadata. */\n\tVALIDATION_ERROR: 'VALIDATION_ERROR',\n\tINVALID_STATE: 'INVALID_STATE',\n\t/** No `DecompressionStream`, no WebGL context, etc. */\n\tENVIRONMENT_ERROR: 'ENVIRONMENT_ERROR',\n\tINVALID_CONFIG: 'INVALID_CONFIG',\n\t/** Base64 input could not be decoded. */\n\tENCODING_ERROR: 'ENCODING_ERROR',\n\tUNKNOWN_ERROR: 'UNKNOWN_ERROR'\n} as const;\n\nexport type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];\n\nexport class VisualizationError extends Error {\n\tpublic readonly code: ErrorCode;\n\tpublic readonly context?: Record<string, unknown>;\n\tpublic readonly originalError?: Error;\n\n\tconstructor(\n\t\tmessage: string,\n\t\tcode: ErrorCode = ErrorCodes.UNKNOWN_ERROR,\n\t\toptions?: { context?: Record<string, unknown>; originalError?: Error }\n\t) {\n\t\tsuper(message);\n\t\tthis.name = 'VisualizationError';\n\t\tthis.code = code;\n\t\tthis.context = options?.context;\n\t\tthis.originalError = options?.originalError;\n\t\tif (options?.originalError) {\n\t\t\t(this as { cause?: unknown }).cause = options.originalError;\n\t\t}\n\t}\n}\n","/**\n * Logging facility for the visualization package. Deliberately local rather than imported from\n * `@selvajs/compute` (logging isn't a compute concern). Mirrors compute's logger shape so a host\n * wanting one sink for both can call `setLogger(computeLogger.getLogger())`.\n */\n\nimport { VisualizationError, ErrorCodes } from './errors.js';\n\nexport interface Logger {\n\tdebug(message: string, ...args: unknown[]): void;\n\tinfo(message: string, ...args: unknown[]): void;\n\twarn(message: string, ...args: unknown[]): void;\n\terror(message: string, ...args: unknown[]): void;\n}\n\nclass NoOpLogger implements Logger {\n\tdebug(): void {}\n\tinfo(): void {}\n\twarn(): void {}\n\terror(): void {}\n}\n\nclass ConsoleLogger implements Logger {\n\tdebug(message: string, ...args: unknown[]): void {\n\t\t// eslint-disable-next-line no-console -- this class exists to be the console sink\n\t\tconsole.debug(message, ...args);\n\t}\n\n\tinfo(message: string, ...args: unknown[]): void {\n\t\tconsole.info(message, ...args);\n\t}\n\n\twarn(message: string, ...args: unknown[]): void {\n\t\tconsole.warn(message, ...args);\n\t}\n\n\terror(message: string, ...args: unknown[]): void {\n\t\tconsole.error(message, ...args);\n\t}\n}\n\n// Defaults to no-op: a library that writes to the console uninvited is a nuisance in a host with\n// its own logging. Opt in with setLogger or enableDebugLogging.\nlet internalLogger: Logger = new NoOpLogger();\n\n// Call per-use rather than caching — the sink is settable at any time.\nexport function getLogger(): Logger {\n\treturn internalLogger;\n}\n\n// Validates logger shape up front: failing here beats a confusing \"getLogger().debug is not a\n// function\" at some later, unrelated call site.\nexport function setLogger(logger: Logger | Console | null): void {\n\tif (logger === null) {\n\t\tinternalLogger = new NoOpLogger();\n\t\treturn;\n\t}\n\n\tconst missing = (['debug', 'info', 'warn', 'error'] as const).filter(\n\t\t(method) => typeof (logger as unknown as Record<string, unknown>)[method] !== 'function'\n\t);\n\tif (missing.length > 0) {\n\t\tthrow new VisualizationError(\n\t\t\t`Logger is missing required method(s): ${missing.join(', ')}. A logger must implement debug, info, warn and error.`,\n\t\t\tErrorCodes.INVALID_CONFIG,\n\t\t\t{ context: { missingMethods: missing } }\n\t\t);\n\t}\n\n\tinternalLogger = logger as Logger;\n}\n\nexport function enableDebugLogging(): void {\n\tsetLogger(new ConsoleLogger());\n}\n","import * as THREE from 'three';\n\nimport type { Look, LookPreset, MaterialAppearanceOptions } from './types.js';\n\n/** The look applied when the caller passes no `look` option. */\nexport const DEFAULT_LOOK: Look = 'technical';\n\n/**\n * Single source of truth for both `applyDefaults` (construction) and `setLook` (runtime), so the two\n * can't drift.\n *\n * Every shaded look pairs a key light with contact shading (GTAO), because image-based lighting on\n * its own lights all faces of a box nearly equally — the result is a white silhouette with no\n * readable form. GTAO is a full-screen pass and does cost frames; `xray` skips it since there are no\n * opaque contacts left to shade.\n */\nexport const LOOK_PRESETS: Record<Look, LookPreset> = {\n\t// Fills shadows in (vs. showcase, which lets them fall off), but still key-lit: ACES plus a\n\t// moderate sun, with fill high enough that shadowed faces keep detail.\n\tstudio: {\n\t\ttoneMapping: THREE.ACESFilmicToneMapping,\n\t\ttoneMappingExposure: 1,\n\t\tenvMapIntensity: 1.0,\n\t\tenvironmentIntensity: 0.85,\n\t\themisphereIntensity: 0.5,\n\t\tambientIntensity: 0.25,\n\t\tcullBackfaces: false,\n\t\tambientOcclusion: true,\n\t\tsunlightIntensity: 1.6\n\t},\n\t// The sun carries this look and the ambient/IBL only lift shadows off black. Fill was the thing\n\t// making it read as flat white paper: every source except the sun is orientation-independent, so\n\t// the more of them you stack the less the three faces of a corner differ.\n\ttechnical: {\n\t\ttoneMapping: THREE.NeutralToneMapping,\n\t\ttoneMappingExposure: 1,\n\t\tenvMapIntensity: 0.55,\n\t\tenvironmentIntensity: 0.6,\n\t\themisphereIntensity: 0.25,\n\t\tambientIntensity: 0.15,\n\t\tcullBackfaces: false,\n\t\tambientOcclusion: true,\n\t\tsunlightIntensity: 2.2\n\t},\n\t// Fill pulled furthest DOWN and the sun pushed hardest, so light-to-shadow falloff is steepest —\n\t// a dramatic hero shot, unlike `studio` which fills shadows back in.\n\tshowcase: {\n\t\ttoneMapping: THREE.ACESFilmicToneMapping,\n\t\ttoneMappingExposure: 1.15,\n\t\tenvMapIntensity: 1.4,\n\t\tenvironmentIntensity: 1.0,\n\t\themisphereIntensity: 0.2,\n\t\tambientIntensity: 0.1,\n\t\tcullBackfaces: false,\n\t\tambientOcclusion: true,\n\t\tsunlightIntensity: 2.6\n\t},\n\t// Every mesh forced to one near-white clay, so form and shadow carry the image instead of the\n\t// model's own colours. AO on: with all albedo differences gone, contact shading is the only thing\n\t// left separating touching parts — without it the model reads as one white blob.\n\tarctic: {\n\t\ttoneMapping: THREE.NeutralToneMapping,\n\t\ttoneMappingExposure: 1.05,\n\t\tenvMapIntensity: 0.85,\n\t\tenvironmentIntensity: 1.1,\n\t\themisphereIntensity: 0.3,\n\t\tambientIntensity: 0.15,\n\t\tcullBackfaces: false,\n\t\tambientOcclusion: true,\n\t\tsunlightIntensity: 2.0,\n\t\tmaterialOverride: {\n\t\t\tcolor: 0xeef1f5,\n\t\t\tmetalness: 0,\n\t\t\troughness: 0.75\n\t\t}\n\t},\n\t// See-through blue-white with depth writes off, so interior geometry shows through the shell.\n\t// Exposure pushed up because stacked transparent layers darken fast; the sun is dialled back\n\t// because a hard highlight on a transparent shell hides what is behind it.\n\txray: {\n\t\ttoneMapping: THREE.NeutralToneMapping,\n\t\ttoneMappingExposure: 1.3,\n\t\tenvMapIntensity: 0.4,\n\t\tenvironmentIntensity: 0.8,\n\t\themisphereIntensity: 0.6,\n\t\tambientIntensity: 0.6,\n\t\tcullBackfaces: false,\n\t\tambientOcclusion: false,\n\t\tsunlightIntensity: 0.6,\n\t\tmaterialOverride: {\n\t\t\tcolor: 0x9fc4e8,\n\t\t\tmetalness: 0,\n\t\t\troughness: 0.9,\n\t\t\topacity: 0.28,\n\t\t\tdepthWrite: false,\n\t\t\tside: THREE.DoubleSide\n\t\t}\n\t},\n\t// The architectural line drawing: feature edges over flat white faces. The faces are the whole\n\t// point even though you never really see them — they still write depth, so a near member hides\n\t// the ones behind it. True wireframe can't do that, and on a dense frame (thousands of members,\n\t// every edge of every one drawn at once) it collapses into a black mass.\n\t//\n\t// Unlit on purpose: any directional shading would compete with the lines for the eye. Ambient\n\t// alone lands every face on the same flat white, so the only contrast in the image is the edges.\n\t// AO is off for the same reason — a grey contact smear under a line drawing just muddies it.\n\tlineart: {\n\t\ttoneMapping: THREE.NeutralToneMapping,\n\t\ttoneMappingExposure: 1,\n\t\t// The faces are MeshPhysicalMaterial, so they take their brightness from lighting, not from\n\t\t// `color`: zero out the lights and they render black however white the override is. Hemisphere\n\t\t// and ambient carry it rather than IBL, because `scene.environment` only exists if the host\n\t\t// loaded an HDR — leaning on IBL would render this look black in any viewer without one. Both\n\t\t// are orientation-independent, so every face lands on the same flat white and the edges stay\n\t\t// the only contrast in the image. Ambient is weighted over hemisphere because hemisphere's\n\t\t// ground colour is a warm brown by default: leaning on it tints every downward face grey and\n\t\t// the drawing stops reading as one flat white.\n\t\tenvMapIntensity: 1.0,\n\t\tenvironmentIntensity: 1.0,\n\t\themisphereIntensity: 0.6,\n\t\tambientIntensity: 3.2,\n\t\tcullBackfaces: false,\n\t\tambientOcclusion: false,\n\t\tsunlightIntensity: 0,\n\t\trequiresEdges: true,\n\t\tmaterialOverride: {\n\t\t\tcolor: 0xf7f8fa,\n\t\t\tmetalness: 0,\n\t\t\troughness: 1\n\t\t}\n\t},\n\t// Triangle edges only — the tessellation itself, diagonals and all. That makes it a mesh-\n\t// inspection tool, not a drawing: for a readable line drawing use `lineart`, which draws\n\t// feature edges and lets near faces occlude far ones. Nothing here is a lit surface:\n\t// the sun is off and fill carries the image, because a directional light on a line renders it\n\t// black wherever the line runs away from the key. AO is off for the same reason — a full-screen\n\t// contact pass has no contacts to find between wires, and it only costs frames.\n\twireframe: {\n\t\ttoneMapping: THREE.NeutralToneMapping,\n\t\ttoneMappingExposure: 1,\n\t\t// Lit for the same reason as lineart (see there): PBR lines are black unlit, and hemisphere\n\t\t// plus ambient work with no HDR loaded. Dimmer than lineart because these lines are dark\n\t\t// on white, not white on dark.\n\t\tenvMapIntensity: 1.0,\n\t\tenvironmentIntensity: 1.0,\n\t\themisphereIntensity: 0.4,\n\t\tambientIntensity: 2.0,\n\t\tcullBackfaces: false,\n\t\tambientOcclusion: false,\n\t\tsunlightIntensity: 0,\n\t\tmaterialOverride: {\n\t\t\tcolor: 0x2b3138,\n\t\t\tmetalness: 0,\n\t\t\troughness: 1,\n\t\t\twireframe: true,\n\t\t\tside: THREE.DoubleSide\n\t\t}\n\t}\n};\n\n/**\n * `userData` key holding a material's own `envMapIntensity`, set by the parser when the wire\n * material carries one. `setLook` keeps it instead of the look's value, except in looks with a\n * `materialOverride`: those restyle every mesh alike, so the look's value wins there.\n */\nexport const OWN_ENV_MAP_INTENSITY = 'selvaEnvMapIntensity';\n\n/**\n * A look dims `envMapIntensity` to turn down fill, but three scales a material's diffuse and\n * specular IBL together. A metal has no diffuse, so the same dimming would only take away its\n * reflection, which is all a metal shows. Blending toward 1 by metalness keeps a dielectric's fill\n * on the look and a metal's reflection the same in every look.\n */\nexport function lookEnvMapIntensity(lookValue: number, metalness: number): number {\n\treturn lookValue + (1 - lookValue) * Math.min(1, Math.max(0, metalness));\n}\n\n/** Baked at parse time (not toggleable at runtime). */\nexport function materialAppearanceForLook(look: Look): MaterialAppearanceOptions {\n\tconst preset = LOOK_PRESETS[look];\n\treturn {\n\t\tenvMapIntensity: preset.envMapIntensity,\n\t\tcullBackfaces: preset.cullBackfaces\n\t};\n}\n","import * as THREE from 'three';\n\nimport { getLogger } from './logger.js';\n\n// parse/ needs these and must never import upward from render/, so they live in shared/ instead\n// of render's three-helpers.\n\nexport function parseColor(colorString: string): THREE.Color {\n\tif (!colorString || typeof colorString !== 'string') {\n\t\tgetLogger().warn(`Invalid color input: ${colorString}, using white`);\n\t\treturn new THREE.Color(0xffffff);\n\t}\n\n\tconst trimmed = colorString.trim();\n\n\tif (/^#?[0-9A-Fa-f]{6}$/.test(trimmed)) {\n\t\ttry {\n\t\t\tconst hex = trimmed.startsWith('#') ? trimmed : `#${trimmed}`;\n\t\t\treturn new THREE.Color(hex);\n\t\t} catch {\n\t\t\tgetLogger().warn(`Invalid hex color: ${colorString}, using white`);\n\t\t\treturn new THREE.Color(0xffffff);\n\t\t}\n\t}\n\n\tif (trimmed.includes(',')) {\n\t\tconst rgb = trimmed.split(',').map((c) => parseInt(c.trim(), 10));\n\t\tif (rgb.length === 3 && rgb.every((n) => !isNaN(n) && n >= 0 && n <= 255)) {\n\t\t\treturn new THREE.Color(rgb[0] / 255, rgb[1] / 255, rgb[2] / 255);\n\t\t}\n\t}\n\n\t// `new THREE.Color(name)` never throws on unknown names (it logs its own warning and leaves the\n\t// color white), so validate against three's CSS name table instead.\n\tconst named = trimmed.toLowerCase();\n\tif (named in THREE.Color.NAMES) {\n\t\treturn new THREE.Color(THREE.Color.NAMES[named as keyof typeof THREE.Color.NAMES]);\n\t}\n\n\tgetLogger().warn(`Invalid color string: ${colorString}, using white`);\n\treturn new THREE.Color(0xffffff);\n}\n\n/** Defaults to `z` (Rhino's up axis); pass an explicit axis when the scene uses a different `sceneUp`. */\nexport function applyOffset(\n\tmeshes: THREE.Object3D[],\n\toffset: number,\n\taxis: 'x' | 'y' | 'z' = 'z'\n): void {\n\tmeshes.forEach((mesh) => {\n\t\tmesh.position[axis] -= offset;\n\t});\n}\n\nexport function computeCombinedBoundingBox(meshes: THREE.Object3D[]): THREE.Box3 {\n\tconst combinedBoundingBox = new THREE.Box3();\n\tif (meshes.length === 0) return combinedBoundingBox;\n\tmeshes.forEach((mesh) => {\n\t\tmesh.updateMatrixWorld(true);\n\t\tconst bbox = new THREE.Box3().setFromObject(mesh);\n\t\tcombinedBoundingBox.union(bbox);\n\t});\n\treturn combinedBoundingBox;\n}\n","import type * as THREE from 'three';\n\n// ============================================================================\n// GPU resource ownership — the single rule every disposal path obeys\n// ============================================================================\n\n/**\n * A GPU resource has exactly one owner: a **module singleton** (nobody ever frees it) or the\n * **scene** (freed on teardown). Every disposal path asks {@link canDisposeMaterial} and disposes\n * only if true. Geometries and textures are always scene-owned, so they have no claim to check.\n */\n\n// Module-scope singletons from `render/three-materials.ts`, shared across meshes and solves —\n// disposing one would free textures still in use and force a recompile. Held here (not imported\n// there) to avoid an import cycle.\nconst protectedMaterials = new Set<THREE.Material>();\n\n/** Register materials as never-disposable. Called once by `render/three-materials.ts`. */\nexport function protectMaterials(materials: Iterable<THREE.Material>): void {\n\tfor (const material of materials) protectedMaterials.add(material);\n}\n\n/** True when `material` is scene-owned (not one of the protected singletons). */\nexport function canDisposeMaterial(material: THREE.Material | undefined): boolean {\n\tif (!material) return false;\n\treturn !protectedMaterials.has(material);\n}\n","// ============================================================================\n// GPU capabilities — published by the renderer, read by whoever needs them\n// ============================================================================\n\n// Lets a renderer publish GPU capabilities (max anisotropy) without `render/` and `parse/` importing\n// each other: the renderer publishes on init, interested parties subscribe.\n\ntype AnisotropyObserver = (value: number) => void;\n\nconst observers = new Set<AnisotropyObserver>();\n\n// Module load order between layers isn't guaranteed, so a subscriber arriving after init still\n// needs the current value rather than waiting for a second renderer to publish.\nlet maxAnisotropy = 1;\n\nexport function publishMaxAnisotropy(value: number): void {\n\tconst next = Math.max(1, value);\n\tif (next === maxAnisotropy) return;\n\tmaxAnisotropy = next;\n\tfor (const observe of observers) observe(next);\n}\n\n/** Fires immediately with the current value (1 until a renderer has reported), then on every change. */\nexport function observeMaxAnisotropy(observe: AnisotropyObserver): () => void {\n\tobservers.add(observe);\n\tobserve(maxAnisotropy);\n\treturn () => observers.delete(observe);\n}\n","import * as THREE from 'three';\n\nimport { canDisposeMaterial } from './gpu-ownership.js';\n\n// ============================================================================\n// The disposal walkers — every teardown path in the package goes through these\n// ============================================================================\n\n/** Frees a material and its textures, respecting ownership (`./gpu-ownership.ts`). */\nexport function disposeMaterial(material: THREE.Material): void {\n\tif (!canDisposeMaterial(material)) return;\n\n\tfor (const [key, value] of Object.entries(material)) {\n\t\t// An envMap is the scene's, shared by every metal: freeing it here would blank them all.\n\t\tif (key === 'envMap') continue;\n\t\tif (value instanceof THREE.Texture) {\n\t\t\tvalue.dispose();\n\t\t}\n\t}\n\tmaterial.dispose();\n}\n\nfunction disposeMaterials(material: THREE.Material | THREE.Material[] | undefined): void {\n\tif (!material) return;\n\tif (Array.isArray(material)) material.forEach(disposeMaterial);\n\telse disposeMaterial(material);\n}\n\nexport interface DisposeOptions {\n\t/** Free materials and their textures too. Default true; the solve memo passes false. */\n\tmaterials?: boolean;\n\t/** Called for each geometry before disposal, so a subsystem can free derived resources keyed on it (e.g. edge caches). */\n\tonGeometry?: (geometry: THREE.BufferGeometry) => void;\n}\n\n/**\n * Frees the GPU resources of an object subtree, respecting ownership. **The only traversal that\n * should dispose scene content** — a second disposing `traverse` risks missing an ownership guard.\n */\nexport function disposeObjectTree(root: THREE.Object3D, options: DisposeOptions = {}): void {\n\tconst { materials = true } = options;\n\n\troot.traverse((object) => {\n\t\tconst renderable = object as Partial<THREE.Mesh> & THREE.Object3D;\n\t\tif (!renderable.geometry && !renderable.material) return;\n\n\t\tif (renderable.geometry) {\n\t\t\trenderable.geometry?.dispose();\n\t\t}\n\n\t\tif (materials) disposeMaterials(renderable.material);\n\t});\n}\n"],"mappings":"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"}
|
package/dist/parse.cjs
CHANGED
|
@@ -1,10 +1,68 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./rolldown-runtime-BocRIvOZ.cjs"),t=require("./gpu-dispose-CCO5Grel.cjs");let n=require("three");n=e.t(n,1);let r=require("three/addons/lines/Line2.js"),i=require("three/addons/lines/LineGeometry.js"),a=require("three/addons/lines/LineMaterial.js"),o=require("fflate");function s(){let e=globalThis.Buffer;return typeof e==`function`?e:void 0}function c(e){let n=e.replace(/[\t\n\f\r ]/g,``);if(n.length%4==0&&(n=n.replace(/={1,2}$/,``)),n.length%4==1||!/^[A-Za-z0-9+/]*$/.test(n))throw new t.h(`Invalid base64 input.`,t.m.ENCODING_ERROR,{context:{inputLength:e.length}});let r=s();if(r)return new Uint8Array(r.from(n,`base64`));if(typeof globalThis.atob==`function`){let e=globalThis.atob(n),t=new Uint8Array(e.length);for(let n=0;n<e.length;n++)t[n]=e.charCodeAt(n)&255;return t}throw new t.h(`Base64 decoding not supported in this environment.`,t.m.INVALID_STATE,{context:{environmentInfo:`atob or Buffer not available`}})}function l(e){return e.map(e=>{let t=e.clone(!0),n=[];e.traverse(e=>n.push(e));let r=0;return t.traverse(e=>{let t=n[r++],i=e;t.geometry&&(i.geometry=t.geometry.clone())}),t})}function u(e){e.forEach(e=>t.t(e,{materials:!1}))}const d={clone:l,release:u};function f(e,t){let r=t??1;return{color:new n.Color(e??`#ffffff`),transparent:r<1,opacity:r}}function p(e){let t=m(e);if(!t)return null;let n=new i.LineGeometry;n.setPositions(t);let o=f(e.color,e.opacity),s=new a.LineMaterial({color:o.color}),c=s;c.linewidth=e.width??2,c.transparent=o.transparent,c.opacity=o.opacity;let l=new r.Line2(n,s);return l.computeLineDistances(),l.name=e.name,l.userData={source:`compute`,id:e.id,layer:e.layer,kind:`curve`,metadata:e.metadata},l}function m(e){if(!e.points)throw new t.h(`Curve display item '${e.id}' has no tessellated points. It was produced by an outdated Display component — upgrade it in Grasshopper (Solution → Upgrade obsolete components) and re-save the definition.`,t.m.INVALID_CONFIG,{context:{itemId:e.id,kind:e.kind}});return e.points.length>=6?e.points:null}function h(e){let{position:r}=e;if(!r||typeof r.X!=`number`||!Number.isFinite(r.X)||typeof r.Y!=`number`||!Number.isFinite(r.Y)||typeof r.Z!=`number`||!Number.isFinite(r.Z))return t.f().warn(`Skipping point display item with missing or non-finite position (id: ${String(e.id)}).`),null;let i=new n.BufferGeometry;i.setAttribute(`position`,new n.Float32BufferAttribute([r.X,r.Y,r.Z],3));let a=new n.PointsMaterial({...f(e.color,e.opacity),size:6,sizeAttenuation:!1}),o=new n.Points(i,a);return o.name=e.name,o.userData={source:`compute`,id:e.id,layer:e.layer,kind:`point`,metadata:e.metadata},o}function g(e){if(!e||e.length===0)return[];let n=[];for(let r of e)switch(r.kind){case`curve`:{let e=p(r);e&&n.push(e);break}case`point`:{let e=h(r);e&&n.push(e);break}default:{let e=r;t.f().warn(`Skipping unknown display item kind: ${String(e.kind)}`);break}}return n}const _=new Uint16Array(new Uint8Array([1,0]).buffer)[0]===1;function v(e){return typeof e==`string`?c(e):e instanceof Uint8Array?e:new Uint8Array(e)}function y(e){if(e.byteLength<8)return e;let t=new DataView(e.buffer,e.byteOffset,e.byteLength);if(t.getUint32(0,!0)!==1515605075)return e;let n=t.getUint32(4,!0),r=e.subarray(8),i=Math.max(r.byteLength*1032+1024,1<<20);if(n>i)throw M(`SLVZ header declares an implausible uncompressed length`,{uncompressedLen:n,deflatedBytes:r.byteLength,maxPlausibleLen:i});let a;try{a=(0,o.inflateSync)(r,{out:new Uint8Array(n+1)})}catch(e){throw M(`Failed to inflate SLVZ blob: ${e instanceof Error?e.message:String(e)}`,{uncompressedLen:n,deflatedBytes:r.byteLength})}if(a.byteLength!==n)throw M(`SLVZ payload inflated to a different size than the header declares.`,{declaredLen:n,actualLen:a.byteLength,deflatedBytes:r.byteLength});return a}function b(e){if(typeof TextDecoder<`u`)return new TextDecoder(`utf-8`).decode(e);if(globalThis.Buffer!==void 0)return globalThis.Buffer.from(e).toString(`utf-8`);throw new t.h(`No UTF-8 decoder available in this environment.`,t.m.INVALID_STATE)}function x(e,t,n){if(n===0)return new Int16Array;if(t%2==0)return new Int16Array(e,t,n);let r=new Uint8Array(n*2);return r.set(new Uint8Array(e,t,n*2)),new Int16Array(r.buffer)}function S(e,t,n){if(n===0)return new Float32Array;if(t%4==0)return new Float32Array(e,t,n);let r=new Uint8Array(n*4);return r.set(new Uint8Array(e,t,n*4)),new Float32Array(r.buffer)}function C(e,t,n){if(n===0)return new Uint16Array;if(t%2==0)return new Uint16Array(e,t,n);let r=new Uint8Array(n*2);return r.set(new Uint8Array(e,t,n*2)),new Uint16Array(r.buffer)}function ee(e,t,n){if(n===0)return new Uint32Array;if(t%4==0)return new Uint32Array(e,t,n);let r=new Uint8Array(n*4);return r.set(new Uint8Array(e,t,n*4)),new Uint32Array(r.buffer)}function w(e,t){if(e.length!==0&&!(e instanceof Uint16Array&&t>65535)){for(let n=0;n<e.length;n++)if(e[n]>=t)throw M(`Index out of range of vertexCount.`,{indexPosition:n,indexValue:e[n],vertexCount:t})}}function T(e){return e>>>1^-(e&1)}function E(e){let t=new Int16Array(e.length),n=0,r=0,i=0;for(let a=0;a<e.length;a+=3)n=n+T(e[a])<<16>>16,r=r+T(e[a+1])<<16>>16,i=i+T(e[a+2])<<16>>16,t[a]=n,t[a+1]=r,t[a+2]=i;return t}function D(e,t){let n=new Int16Array(t*3),r=t,i=0,a=0,o=0;for(let t=0;t<r;t++)i=i+T(e[t]|e[r*3+t]<<8)<<16>>16,a=a+T(e[r+t]|e[r*4+t]<<8)<<16>>16,o=o+T(e[r*2+t]|e[r*5+t]<<8)<<16>>16,n[t*3]=i,n[t*3+1]=a,n[t*3+2]=o;return n}function O(e,t){let n=new Uint16Array(t),r=0;for(let i=0;i<t;i++)r=r+T(e[i]|e[t+i]<<8)&65535,n[i]=r;return n}function k(e,t){let n=new Uint32Array(t),r=0;for(let i=0;i<t;i++){let a=(e[i]|e[t+i]<<8|e[t*2+i]<<16|e[t*3+i]<<24)>>>0;r=r+T(a)>>>0,n[i]=r}return n}function A(e){let t=new Uint16Array(e.length),n=0;for(let r=0;r<e.length;r++)n=n+T(e[r])&65535,t[r]=n;return t}function j(e){let t=new Uint32Array(e.length),n=0;for(let r=0;r<e.length;r++)n=n+T(e[r])>>>0,t[r]=n;return t}function M(e,n){return new t.h(e,t.m.VALIDATION_ERROR,{context:n})}function te(e,t,n,r,i,a=!1){if(n+36>e.byteLength)throw M(`Insufficient data to read UV chunk header.`,{expectedBytes:36,availableBytes:e.byteLength-n,offset:n});let o=t.getUint32(n,!0);n+=4;let s=t.getFloat64(n,!0);n+=8;let c=t.getFloat64(n,!0);n+=8;let l=t.getFloat64(n,!0);n+=8;let u=t.getFloat64(n,!0);n+=8;let d=r*2,f=o===1,p=d*(f?4:2);if(n+p>e.byteLength)throw M(`Insufficient data to read UV chunk.`,{expectedBytes:p,availableBytes:e.byteLength-n,offset:n,uvFormat:o,vertexCount:r});let m=e.byteOffset+n,h;if(f)h=S(e.buffer,m,d).slice();else if(a){let t=e.subarray(n,n+p),i=r;h=new Float32Array(d);let a=0,o=0;for(let e=0;e<i;e++)a=a+T(t[e]|t[i*2+e]<<8)&65535,o=o+T(t[i+e]|t[i*3+e]<<8)&65535,h[e*2]=s+a*l,h[e*2+1]=c+o*u}else{let t=C(e.buffer,m,d);h=new Float32Array(d);let n=0,r=0;for(let e=0;e<d;e+=2)i?(n=n+T(t[e])&65535,r=r+T(t[e+1])&65535):(n=t[e],r=t[e+1]),h[e]=s+n*l,h[e+1]=c+r*u}return{uvs:h,offset:n+p}}function ne(e,t,n,r){let i=n*3;if(t+i>e.byteLength)throw M(`Insufficient data to read vertex-color chunk.`,{expectedBytes:i,availableBytes:e.byteLength-t,offset:t,vertexCount:n});let a=e.subarray(t,t+i);if(!r)return a.slice();let o=new Uint8Array(i),s=0,c=0,l=0;for(let e=0;e<i;e+=3)s=s+T(a[e])&255,c=c+T(a[e+1])&255,l=l+T(a[e+2])&255,o[e]=s,o[e+1]=c,o[e+2]=l;return o}function re(e){return e.byteLength>=4&&new DataView(e.buffer,e.byteOffset,4).getUint32(0,!0)===1297501267}function ie(e){let t=N(e),n=null,r=null,i=null,a=[];for(let{type:e,payload:o}of t)switch(e){case 1297040711:n=o;break;case 1279410516:r=y(o);break;case 1280590157:i=b(o);break;case 1381516628:a.push(o)}if(n===null)throw M(`SLVM container has no GEOM chunk.`,{chunkCount:t.length});if(r===null)throw M(`SLVM container has no TABL chunk.`,{chunkCount:t.length});let{groups:o}=I(r),s=ae(i,a);return{geometryBlob:n,metadata:{materials:s,groups:o}}}function N(e){let t=new DataView(e.buffer,e.byteOffset,e.byteLength);if(e.byteLength<12||t.getUint32(0,!0)!==1297501267)throw M(`Not an SLVM container (bad magic).`,{byteLength:e.byteLength});let n=t.getUint32(4,!0);if(n!==3)throw M(`Unsupported SLVM version: ${n}`,{expectedVersion:3});let r=t.getUint32(8,!0),i=[],a=12;for(let n=0;n<r;n++){if(a+8>e.byteLength)throw M(`Truncated SLVM chunk header.`,{offset:a,chunkIndex:n});let r=t.getUint32(a,!0),o=t.getUint32(a+4,!0);if(a+=8,a+o>e.byteLength)throw M(`Truncated SLVM chunk payload.`,{offset:a,chunkIndex:n,byteLen:o});i.push({type:r,payload:e.subarray(a,a+o)}),a+=o+(4-o%4)%4}return i}function P(e){let t=0,n=0;for(;;){if(e.pos>=e.bytes.byteLength||n>28)throw M(`Malformed varint in SLVM table.`,{pos:e.pos});let r=e.bytes[e.pos++];if(t|=(r&127)<<n,!(r&128))return t>>>0;n+=7}}function F(e,t,n){let r=e.bytes[e.pos++],i=Array(t);switch(r){case 0:i.fill(``);break;case 1:for(let e=0;e<t;e++)i[e]=String(e+1);break;case 2:for(let r=0;r<t;r++)i[r]=n[P(e)]??``;break;default:throw M(`Unknown SLVM string column mode: ${r}`,{pos:e.pos})}return i}function I(e){let t={bytes:e,pos:0},n=P(t),r=P(t),i=P(t),a=n+r+i,o=P(t),s=Array(o);for(let n=0;n<o;n++){let r=P(t);s[n]=b(e.subarray(t.pos,t.pos+r)),t.pos+=r}let c=Array(n),l=Array(n);for(let e=0;e<n;e++)c[e]=P(t),l[e]=P(t);for(let e=0;e<r;e++)P(t);let u=P(t),d=[];for(let e=0;e<u;e++)d.push({materialId:P(t),meshCount:P(t)});let f=F(t,a,s),p=F(t,a,s),m=Array(a),h=P(t);for(let e=0;e<h;e++){let e=s[P(t)]??``,n=P(t),r=Array(n),i=0;for(let e=0;e<n;e++)i+=P(t),r[e]=i;for(let i=0;i<n;i++){let n=s[P(t)]??``,a=r[i];(m[a]??={})[e]=n}}let g=d.length>0||n===0?d:[{materialId:0,meshCount:n}],_=[],v=0,y=0,x=0;for(let e of g){let t=[];for(let r=0;r<e.meshCount&&v<n;r++,v++){let e=m[v],n=e?.id;e!==void 0&&delete e.id,t.push({id:n,name:f[v],layer:p[v],vertexCount:c[v],indexCount:l[v]*3,vertexStart:y,indexStart:x,metadata:e??{}}),y+=c[v],x+=l[v]*3}_.push({materialId:e.materialId,meshes:t})}return{groups:_}}function ae(e,t){if(e===null)return[];let n;try{n=JSON.parse(e).materials??[]}catch(t){throw M(`Failed to parse SLVM materials JSON: ${t instanceof Error?t.message:String(t)}`,{byteLength:e.length})}for(let e of n)for(let n of L){let r=e[n];if(r?.startsWith(`slvm:tex:`)){let i=t[Number(r.slice(9))];i!==void 0&&(e[n]=R(i))}}return n}const L=[`map`,`roughnessMap`,`normalMap`];function R(e){let t={bytes:e,pos:0},n=P(t),r=b(e.subarray(t.pos,t.pos+n)),i=e.subarray(t.pos+n),a=``,o=32768;for(let e=0;e<i.byteLength;e+=o)a+=String.fromCharCode(...i.subarray(e,e+o));return`data:${r};base64,${btoa(a)}`}function z(e){let t=B(e),n;n=t.isFloat32?t.vertexData:t.planarByteSplit?D(t.vertexData,t.vertexCount):t.deltaEncoded?E(t.vertexData):t.vertexData;let r;if(t.planarByteSplit){let e=t.indexData;r=t.uint16Indices?O(e,e.length/2):k(e,e.length/4)}else r=t.deltaEncoded?t.indexData instanceof Uint16Array?A(t.indexData):j(t.indexData):t.indexData;return w(r,t.vertexCount),{metadata:t.metadata,flags:t.flags,vertices:n,indices:r,origin:t.origin,scale:t.scale,uvs:t.uvs,colors:t.colors}}function B(e){if(!_)throw new t.h(`SLVA parsing requires a little-endian host: the zero-copy geometry readers view the wire bytes in host byte order.`,t.m.ENVIRONMENT_ERROR);let n=v(e);if(re(n)){let e=ie(n),t=B(e.geometryBlob);return t.metadata=e.metadata,t}let r=y(n),i=new DataView(r.buffer,r.byteOffset,r.byteLength);if(r.byteLength<12)throw M(`Blob too small to contain SLVA header.`,{expectedBytes:12,availableBytes:r.byteLength});let a=0,o=i.getUint32(a,!0);if(a+=4,o!==1096174675)throw M(`Invalid SLVA magic: 0x${o.toString(16)}`,{expectedMagic:`0x41564c53`,actualMagic:`0x${o.toString(16)}`});let s=i.getUint32(a,!0);if(a+=4,s<1||s>4)throw M(`Unsupported SLVA version: ${s}`,{minSupportedVersion:1,maxSupportedVersion:4,actualVersion:s});let c=i.getUint32(a,!0);if(a+=4,a+c>r.byteLength)throw M(`Insufficient data to read metadata JSON.`,{expectedBytes:c,availableBytes:r.byteLength-a,offset:a});let l=r.subarray(a,a+c);a+=c;let u;try{u=c===0?{}:JSON.parse(b(l))}catch(e){throw M(`Failed to parse metadata JSON: ${e instanceof Error?e.message:String(e)}`,{metadataLen:c})}if(a+56>r.byteLength)throw M(`Insufficient data to read geometry header.`,{expectedBytes:56,availableBytes:r.byteLength-a,offset:a});let d=i.getUint32(a,!0);a+=4;let f=i.getFloat64(a,!0);a+=8;let p=i.getFloat64(a,!0);a+=8;let m=i.getFloat64(a,!0);a+=8;let h=i.getFloat64(a,!0);a+=8;let g=i.getFloat64(a,!0);a+=8;let w=i.getFloat64(a,!0);a+=8;let T=i.getUint32(a,!0);a+=4;let E=!!(d&1),D=!!(d&4),O=!!(d&32),k=T*3,A=k*(E?4:2);if(a+A>r.byteLength)throw M(`Insufficient data to read vertices.`,{expectedBytes:A,availableBytes:r.byteLength-a,offset:a,useFloat32:E,vertexCount:T});let j=r.byteOffset+a,N;if(N=E?S(r.buffer,j,k):O?r.subarray(a,a+A):D?C(r.buffer,j,k):x(r.buffer,j,k),a+=A,a+4>r.byteLength)throw M(`Insufficient data to read index count.`,{expectedBytes:4,availableBytes:r.byteLength-a,offset:a});let P=i.getUint32(a,!0);a+=4;let F=!!(d&2),I=P*(F?2:4);if(a+I>r.byteLength)throw M(`Insufficient data to read indices.`,{expectedBytes:I,availableBytes:r.byteLength-a,offset:a,indexCount:P,useUint16Indices:F});let ae=O?r.subarray(a,a+I):F?C(r.buffer,r.byteOffset+a,P):ee(r.buffer,r.byteOffset+a,P);a+=I;let L=null;if(d&8){let e=te(r,i,a,T,D,O);L=e.uvs,a=e.offset}let R=null;return d&16&&(R=ne(r,a,T,D)),{metadata:u,flags:d,vertexData:N,indexData:ae,isFloat32:E,deltaEncoded:D,planarByteSplit:O,uint16Indices:F,vertexCount:T,origin:[f,p,m],scale:[h,g,w],uvs:L,colors:R}}function oe(e){let{isFloat32:t,deltaEncoded:n,planarByteSplit:r,uint16Indices:i,origin:a,scale:o,uvs:s,colors:c,jobs:l}=e,u=e=>e>>>1^-(e&1),d;if(t)d=e.vertexData;else{let t;if(r){let n=e.vertexData,r=n.length/6;t=new Int16Array(r*3);let i=0,a=0,o=0;for(let e=0;e<r;e++)i=i+u(n[e]|n[r*3+e]<<8)<<16>>16,a=a+u(n[r+e]|n[r*4+e]<<8)<<16>>16,o=o+u(n[r*2+e]|n[r*5+e]<<8)<<16>>16,t[e*3]=i,t[e*3+1]=a,t[e*3+2]=o}else if(n){let n=e.vertexData;t=new Int16Array(n.length);let r=0,i=0,a=0;for(let e=0;e<n.length;e+=3)r=r+u(n[e])<<16>>16,i=i+u(n[e+1])<<16>>16,a=a+u(n[e+2])<<16>>16,t[e]=r,t[e+1]=i,t[e+2]=a}else t=e.vertexData;d=new Float32Array(t.length);let i=a[0],s=a[1],c=a[2],l=o[0],f=o[1],p=o[2];for(let e=0;e<t.length;e+=3)d[e]=i+(t[e]+32767)*l,d[e+1]=s+(t[e+1]+32767)*f,d[e+2]=c+(t[e+2]+32767)*p}let f;if(r){let t=e.indexData;if(i){let e=t.length/2,n=new Uint16Array(e),r=0;for(let i=0;i<e;i++)r=r+u(t[i]|t[e+i]<<8)&65535,n[i]=r;f=n}else{let e=t.length/4,n=new Uint32Array(e),r=0;for(let i=0;i<e;i++){let a=(t[i]|t[e+i]<<8|t[e*2+i]<<16|t[e*3+i]<<24)>>>0;r=r+u(a)>>>0,n[i]=r}f=n}}else if(n){let t=e.indexData;if(t instanceof Uint16Array){let e=new Uint16Array(t.length),n=0;for(let r=0;r<t.length;r++)n=n+u(t[r])&65535,e[r]=n;f=e}else{let e=new Uint32Array(t.length),n=0;for(let r=0;r<t.length;r++)n=n+u(t[r])>>>0,e[r]=n;f=e}}else f=e.indexData;let p=d.length/3;for(let e=0;e<f.length;e++)if(f[e]>=p)throw Error(`Index ${f[e]} out of range of vertexCount ${p}`);let m=[];for(let e of l){let t=0,n=0;for(let r of e.windows)t+=r.vertexCount,n+=r.indexCount;let r=new Float32Array(t*3),i=new Uint32Array(n),a=s?new Float32Array(t*2):null,o=c?new Uint8Array(t*3):null,l=0,u=0;for(let t of e.windows){let e=t.vertexStart*3;r.set(d.subarray(e,e+t.vertexCount*3),l*3),a&&s&&a.set(s.subarray(t.vertexStart*2,(t.vertexStart+t.vertexCount)*2),l*2),o&&c&&o.set(c.subarray(e,e+t.vertexCount*3),l*3);let n=t.vertexStart,p=t.vertexStart+t.vertexCount,m=l-t.vertexStart;for(let e=0;e<t.indexCount;e++){let r=f[t.indexStart+e];if(r<n||r>=p)throw Error(`Index ${r} outside vertex window [${n}, ${p})`);i[u+e]=r+m}l+=t.vertexCount,u+=t.indexCount}let p=new Float32Array(t*3);for(let e=0;e<i.length;e+=3){let t=i[e]*3,n=i[e+1]*3,a=i[e+2]*3,o=r[a]-r[n],s=r[a+1]-r[n+1],c=r[a+2]-r[n+2],l=r[t]-r[n],u=r[t+1]-r[n+1],d=r[t+2]-r[n+2],f=s*d-c*u,m=c*l-o*d,h=o*u-s*l;p[t]+=f,p[t+1]+=m,p[t+2]+=h,p[n]+=f,p[n+1]+=m,p[n+2]+=h,p[a]+=f,p[a+1]+=m,p[a+2]+=h}for(let e=0;e<p.length;e+=3){let t=p[e],n=p[e+1],r=p[e+2],i=Math.sqrt(t*t+n*n+r*r)||1;p[e]=t/i,p[e+1]=n/i,p[e+2]=r/i}m.push({positions:r,normals:p,indices:i,uvs:a,colors:o})}return m}function se(){return[`const assemble = ${oe.toString()};`,`self.onmessage = (event) => {`,` const { id, input } = event.data;`,` try {`,` const geometries = assemble(input);`,` const transfer = [];`,` for (const g of geometries) {`,` transfer.push(g.positions.buffer, g.normals.buffer, g.indices.buffer);`,` if (g.uvs) transfer.push(g.uvs.buffer);`,` if (g.colors) transfer.push(g.colors.buffer);`,` }`,` self.postMessage({ id, geometries }, transfer);`,` } catch (error) {`,` self.postMessage({ id, error: String((error && error.message) || error) });`,` }`,`};`].join(`
|
|
2
|
-
`)}let
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./rolldown-runtime-BocRIvOZ.cjs"),t=require("./gpu-dispose-GZmNW-gK.cjs");let n=require("three");n=e.t(n,1);let r=require("three/addons/lines/Line2.js"),i=require("three/addons/lines/LineGeometry.js"),a=require("three/addons/lines/LineMaterial.js"),o=require("fflate");function s(){let e=globalThis.Buffer;return typeof e==`function`?e:void 0}function c(e){let n=e.replace(/[\t\n\f\r ]/g,``);if(n.length%4==0&&(n=n.replace(/={1,2}$/,``)),n.length%4==1||!/^[A-Za-z0-9+/]*$/.test(n))throw new t.g(`Invalid base64 input.`,t.h.ENCODING_ERROR,{context:{inputLength:e.length}});let r=s();if(r)return new Uint8Array(r.from(n,`base64`));if(typeof globalThis.atob==`function`){let e=globalThis.atob(n),t=new Uint8Array(e.length);for(let n=0;n<e.length;n++)t[n]=e.charCodeAt(n)&255;return t}throw new t.g(`Base64 decoding not supported in this environment.`,t.h.INVALID_STATE,{context:{environmentInfo:`atob or Buffer not available`}})}function l(e){return e.map(e=>{let t=e.clone(!0),n=[];e.traverse(e=>n.push(e));let r=0;return t.traverse(e=>{let t=n[r++],i=e;t.geometry&&(i.geometry=t.geometry.clone())}),t})}function u(e){e.forEach(e=>t.t(e,{materials:!1}))}const d={clone:l,release:u};function f(e,t){let r=t??1;return{color:new n.Color(e??`#ffffff`),transparent:r<1,opacity:r}}function p(e){let t=m(e);if(!t)return null;let n=new i.LineGeometry;n.setPositions(t);let o=f(e.color,e.opacity),s=new a.LineMaterial({color:o.color}),c=s;c.linewidth=e.width??2,c.transparent=o.transparent,c.opacity=o.opacity;let l=new r.Line2(n,s);return l.computeLineDistances(),l.name=e.name,l.userData={source:`compute`,id:e.id,layer:e.layer,kind:`curve`,metadata:e.metadata},l}function m(e){if(!e.points)throw new t.g(`Curve display item '${e.id}' has no tessellated points. It was produced by an outdated Display component — upgrade it in Grasshopper (Solution → Upgrade obsolete components) and re-save the definition.`,t.h.INVALID_CONFIG,{context:{itemId:e.id,kind:e.kind}});return e.points.length>=6?e.points:null}function h(e){let{position:r}=e;if(!r||typeof r.X!=`number`||!Number.isFinite(r.X)||typeof r.Y!=`number`||!Number.isFinite(r.Y)||typeof r.Z!=`number`||!Number.isFinite(r.Z))return t.p().warn(`Skipping point display item with missing or non-finite position (id: ${String(e.id)}).`),null;let i=new n.BufferGeometry;i.setAttribute(`position`,new n.Float32BufferAttribute([r.X,r.Y,r.Z],3));let a=new n.PointsMaterial({...f(e.color,e.opacity),size:6,sizeAttenuation:!1}),o=new n.Points(i,a);return o.name=e.name,o.userData={source:`compute`,id:e.id,layer:e.layer,kind:`point`,metadata:e.metadata},o}function g(e){if(!e||e.length===0)return[];let n=[];for(let r of e)switch(r.kind){case`curve`:{let e=p(r);e&&n.push(e);break}case`point`:{let e=h(r);e&&n.push(e);break}default:{let e=r;t.p().warn(`Skipping unknown display item kind: ${String(e.kind)}`);break}}return n}const _=new Uint16Array(new Uint8Array([1,0]).buffer)[0]===1;function v(e){return typeof e==`string`?c(e):e instanceof Uint8Array?e:new Uint8Array(e)}function y(e){if(e.byteLength<8)return e;let t=new DataView(e.buffer,e.byteOffset,e.byteLength);if(t.getUint32(0,!0)!==1515605075)return e;let n=t.getUint32(4,!0),r=e.subarray(8),i=Math.max(r.byteLength*1032+1024,1<<20);if(n>i)throw N(`SLVZ header declares an implausible uncompressed length`,{uncompressedLen:n,deflatedBytes:r.byteLength,maxPlausibleLen:i});let a;try{a=(0,o.inflateSync)(r,{out:new Uint8Array(n+1)})}catch(e){throw N(`Failed to inflate SLVZ blob: ${e instanceof Error?e.message:String(e)}`,{uncompressedLen:n,deflatedBytes:r.byteLength})}if(a.byteLength!==n)throw N(`SLVZ payload inflated to a different size than the header declares.`,{declaredLen:n,actualLen:a.byteLength,deflatedBytes:r.byteLength});return a}function b(e){if(typeof TextDecoder<`u`)return new TextDecoder(`utf-8`).decode(e);if(globalThis.Buffer!==void 0)return globalThis.Buffer.from(e).toString(`utf-8`);throw new t.g(`No UTF-8 decoder available in this environment.`,t.h.INVALID_STATE)}function x(e,t,n){if(n===0)return new Int16Array;if(t%2==0)return new Int16Array(e,t,n);let r=new Uint8Array(n*2);return r.set(new Uint8Array(e,t,n*2)),new Int16Array(r.buffer)}function S(e,t,n){if(n===0)return new Float32Array;if(t%4==0)return new Float32Array(e,t,n);let r=new Uint8Array(n*4);return r.set(new Uint8Array(e,t,n*4)),new Float32Array(r.buffer)}function C(e,t,n){if(n===0)return new Uint16Array;if(t%2==0)return new Uint16Array(e,t,n);let r=new Uint8Array(n*2);return r.set(new Uint8Array(e,t,n*2)),new Uint16Array(r.buffer)}function w(e,t,n){if(n===0)return new Uint32Array;if(t%4==0)return new Uint32Array(e,t,n);let r=new Uint8Array(n*4);return r.set(new Uint8Array(e,t,n*4)),new Uint32Array(r.buffer)}function T(e,t){if(e.length!==0&&!(e instanceof Uint16Array&&t>65535)){for(let n=0;n<e.length;n++)if(e[n]>=t)throw N(`Index out of range of vertexCount.`,{indexPosition:n,indexValue:e[n],vertexCount:t})}}function E(e){return e>>>1^-(e&1)}function D(e){let t=new Int16Array(e.length),n=0,r=0,i=0;for(let a=0;a<e.length;a+=3)n=n+E(e[a])<<16>>16,r=r+E(e[a+1])<<16>>16,i=i+E(e[a+2])<<16>>16,t[a]=n,t[a+1]=r,t[a+2]=i;return t}function O(e,t){let n=new Int16Array(t*3),r=t,i=0,a=0,o=0;for(let t=0;t<r;t++)i=i+E(e[t]|e[r*3+t]<<8)<<16>>16,a=a+E(e[r+t]|e[r*4+t]<<8)<<16>>16,o=o+E(e[r*2+t]|e[r*5+t]<<8)<<16>>16,n[t*3]=i,n[t*3+1]=a,n[t*3+2]=o;return n}function k(e,t){let n=new Uint16Array(t),r=0;for(let i=0;i<t;i++)r=r+E(e[i]|e[t+i]<<8)&65535,n[i]=r;return n}function A(e,t){let n=new Uint32Array(t),r=0;for(let i=0;i<t;i++){let a=(e[i]|e[t+i]<<8|e[t*2+i]<<16|e[t*3+i]<<24)>>>0;r=r+E(a)>>>0,n[i]=r}return n}function j(e){let t=new Uint16Array(e.length),n=0;for(let r=0;r<e.length;r++)n=n+E(e[r])&65535,t[r]=n;return t}function M(e){let t=new Uint32Array(e.length),n=0;for(let r=0;r<e.length;r++)n=n+E(e[r])>>>0,t[r]=n;return t}function N(e,n){return new t.g(e,t.h.VALIDATION_ERROR,{context:n})}function P(e,t,n,r,i,a=!1){if(n+36>e.byteLength)throw N(`Insufficient data to read UV chunk header.`,{expectedBytes:36,availableBytes:e.byteLength-n,offset:n});let o=t.getUint32(n,!0);n+=4;let s=t.getFloat64(n,!0);n+=8;let c=t.getFloat64(n,!0);n+=8;let l=t.getFloat64(n,!0);n+=8;let u=t.getFloat64(n,!0);n+=8;let d=r*2,f=o===1,p=d*(f?4:2);if(n+p>e.byteLength)throw N(`Insufficient data to read UV chunk.`,{expectedBytes:p,availableBytes:e.byteLength-n,offset:n,uvFormat:o,vertexCount:r});let m=e.byteOffset+n,h;if(f)h=S(e.buffer,m,d).slice();else if(a){let t=e.subarray(n,n+p),i=r;h=new Float32Array(d);let a=0,o=0;for(let e=0;e<i;e++)a=a+E(t[e]|t[i*2+e]<<8)&65535,o=o+E(t[i+e]|t[i*3+e]<<8)&65535,h[e*2]=s+a*l,h[e*2+1]=c+o*u}else{let t=C(e.buffer,m,d);h=new Float32Array(d);let n=0,r=0;for(let e=0;e<d;e+=2)i?(n=n+E(t[e])&65535,r=r+E(t[e+1])&65535):(n=t[e],r=t[e+1]),h[e]=s+n*l,h[e+1]=c+r*u}return{uvs:h,offset:n+p}}function ee(e,t,n,r){let i=n*3;if(t+i>e.byteLength)throw N(`Insufficient data to read vertex-color chunk.`,{expectedBytes:i,availableBytes:e.byteLength-t,offset:t,vertexCount:n});let a=e.subarray(t,t+i);if(!r)return a.slice();let o=new Uint8Array(i),s=0,c=0,l=0;for(let e=0;e<i;e+=3)s=s+E(a[e])&255,c=c+E(a[e+1])&255,l=l+E(a[e+2])&255,o[e]=s,o[e+1]=c,o[e+2]=l;return o}function te(e){return e.byteLength>=4&&new DataView(e.buffer,e.byteOffset,4).getUint32(0,!0)===1297501267}function ne(e){let t=F(e),n=null,r=null,i=null,a=[];for(let{type:e,payload:o}of t)switch(e){case 1297040711:n=o;break;case 1279410516:r=y(o);break;case 1280590157:i=b(o);break;case 1381516628:a.push(o)}if(n===null)throw N(`SLVM container has no GEOM chunk.`,{chunkCount:t.length});if(r===null)throw N(`SLVM container has no TABL chunk.`,{chunkCount:t.length});let{groups:o}=R(r),s=re(i,a);return{geometryBlob:n,metadata:{materials:s,groups:o}}}function F(e){let t=new DataView(e.buffer,e.byteOffset,e.byteLength);if(e.byteLength<12||t.getUint32(0,!0)!==1297501267)throw N(`Not an SLVM container (bad magic).`,{byteLength:e.byteLength});let n=t.getUint32(4,!0);if(n!==3)throw N(`Unsupported SLVM version: ${n}`,{expectedVersion:3});let r=t.getUint32(8,!0),i=[],a=12;for(let n=0;n<r;n++){if(a+8>e.byteLength)throw N(`Truncated SLVM chunk header.`,{offset:a,chunkIndex:n});let r=t.getUint32(a,!0),o=t.getUint32(a+4,!0);if(a+=8,a+o>e.byteLength)throw N(`Truncated SLVM chunk payload.`,{offset:a,chunkIndex:n,byteLen:o});i.push({type:r,payload:e.subarray(a,a+o)}),a+=o+(4-o%4)%4}return i}function I(e){let t=0,n=0;for(;;){if(e.pos>=e.bytes.byteLength||n>28)throw N(`Malformed varint in SLVM table.`,{pos:e.pos});let r=e.bytes[e.pos++];if(t|=(r&127)<<n,!(r&128))return t>>>0;n+=7}}function L(e,t,n){let r=e.bytes[e.pos++],i=Array(t);switch(r){case 0:i.fill(``);break;case 1:for(let e=0;e<t;e++)i[e]=String(e+1);break;case 2:for(let r=0;r<t;r++)i[r]=n[I(e)]??``;break;default:throw N(`Unknown SLVM string column mode: ${r}`,{pos:e.pos})}return i}function R(e){let t={bytes:e,pos:0},n=I(t),r=I(t),i=I(t),a=n+r+i,o=I(t),s=Array(o);for(let n=0;n<o;n++){let r=I(t);s[n]=b(e.subarray(t.pos,t.pos+r)),t.pos+=r}let c=Array(n),l=Array(n);for(let e=0;e<n;e++)c[e]=I(t),l[e]=I(t);for(let e=0;e<r;e++)I(t);let u=I(t),d=[];for(let e=0;e<u;e++)d.push({materialId:I(t),meshCount:I(t)});let f=L(t,a,s),p=L(t,a,s),m=Array(a),h=I(t);for(let e=0;e<h;e++){let e=s[I(t)]??``,n=I(t),r=Array(n),i=0;for(let e=0;e<n;e++)i+=I(t),r[e]=i;for(let i=0;i<n;i++){let n=s[I(t)]??``,a=r[i];(m[a]??={})[e]=n}}let g=d.length>0||n===0?d:[{materialId:0,meshCount:n}],_=[],v=0,y=0,x=0;for(let e of g){let t=[];for(let r=0;r<e.meshCount&&v<n;r++,v++){let e=m[v],n=e?.id;e!==void 0&&delete e.id,t.push({id:n,name:f[v],layer:p[v],vertexCount:c[v],indexCount:l[v]*3,vertexStart:y,indexStart:x,metadata:e??{}}),y+=c[v],x+=l[v]*3}_.push({materialId:e.materialId,meshes:t})}return{groups:_}}function re(e,t){if(e===null)return[];let n;try{n=JSON.parse(e).materials??[]}catch(t){throw N(`Failed to parse SLVM materials JSON: ${t instanceof Error?t.message:String(t)}`,{byteLength:e.length})}for(let e of n)for(let n of z){let r=e[n];if(r?.startsWith(`slvm:tex:`)){let i=t[Number(r.slice(9))];i!==void 0&&(e[n]=B(i))}}return n}const z=[`map`,`roughnessMap`,`normalMap`];function B(e){let t={bytes:e,pos:0},n=I(t),r=b(e.subarray(t.pos,t.pos+n)),i=e.subarray(t.pos+n),a=``,o=32768;for(let e=0;e<i.byteLength;e+=o)a+=String.fromCharCode(...i.subarray(e,e+o));return`data:${r};base64,${btoa(a)}`}function ie(e){let t=V(e),n;n=t.isFloat32?t.vertexData:t.planarByteSplit?O(t.vertexData,t.vertexCount):t.deltaEncoded?D(t.vertexData):t.vertexData;let r;if(t.planarByteSplit){let e=t.indexData;r=t.uint16Indices?k(e,e.length/2):A(e,e.length/4)}else r=t.deltaEncoded?t.indexData instanceof Uint16Array?j(t.indexData):M(t.indexData):t.indexData;return T(r,t.vertexCount),{metadata:t.metadata,flags:t.flags,vertices:n,indices:r,origin:t.origin,scale:t.scale,uvs:t.uvs,colors:t.colors}}function V(e){if(!_)throw new t.g(`SLVA parsing requires a little-endian host: the zero-copy geometry readers view the wire bytes in host byte order.`,t.h.ENVIRONMENT_ERROR);let n=v(e);if(te(n)){let e=ne(n),t=V(e.geometryBlob);return t.metadata=e.metadata,t}let r=y(n),i=new DataView(r.buffer,r.byteOffset,r.byteLength);if(r.byteLength<12)throw N(`Blob too small to contain SLVA header.`,{expectedBytes:12,availableBytes:r.byteLength});let a=0,o=i.getUint32(a,!0);if(a+=4,o!==1096174675)throw N(`Invalid SLVA magic: 0x${o.toString(16)}`,{expectedMagic:`0x41564c53`,actualMagic:`0x${o.toString(16)}`});let s=i.getUint32(a,!0);if(a+=4,s<1||s>4)throw N(`Unsupported SLVA version: ${s}`,{minSupportedVersion:1,maxSupportedVersion:4,actualVersion:s});let c=i.getUint32(a,!0);if(a+=4,a+c>r.byteLength)throw N(`Insufficient data to read metadata JSON.`,{expectedBytes:c,availableBytes:r.byteLength-a,offset:a});let l=r.subarray(a,a+c);a+=c;let u;try{u=c===0?{}:JSON.parse(b(l))}catch(e){throw N(`Failed to parse metadata JSON: ${e instanceof Error?e.message:String(e)}`,{metadataLen:c})}if(a+56>r.byteLength)throw N(`Insufficient data to read geometry header.`,{expectedBytes:56,availableBytes:r.byteLength-a,offset:a});let d=i.getUint32(a,!0);a+=4;let f=i.getFloat64(a,!0);a+=8;let p=i.getFloat64(a,!0);a+=8;let m=i.getFloat64(a,!0);a+=8;let h=i.getFloat64(a,!0);a+=8;let g=i.getFloat64(a,!0);a+=8;let T=i.getFloat64(a,!0);a+=8;let E=i.getUint32(a,!0);a+=4;let D=!!(d&1),O=!!(d&4),k=!!(d&32),A=E*3,j=A*(D?4:2);if(a+j>r.byteLength)throw N(`Insufficient data to read vertices.`,{expectedBytes:j,availableBytes:r.byteLength-a,offset:a,useFloat32:D,vertexCount:E});let M=r.byteOffset+a,F;if(F=D?S(r.buffer,M,A):k?r.subarray(a,a+j):O?C(r.buffer,M,A):x(r.buffer,M,A),a+=j,a+4>r.byteLength)throw N(`Insufficient data to read index count.`,{expectedBytes:4,availableBytes:r.byteLength-a,offset:a});let I=i.getUint32(a,!0);a+=4;let L=!!(d&2),R=I*(L?2:4);if(a+R>r.byteLength)throw N(`Insufficient data to read indices.`,{expectedBytes:R,availableBytes:r.byteLength-a,offset:a,indexCount:I,useUint16Indices:L});let re=k?r.subarray(a,a+R):L?C(r.buffer,r.byteOffset+a,I):w(r.buffer,r.byteOffset+a,I);a+=R;let z=null;if(d&8){let e=P(r,i,a,E,O,k);z=e.uvs,a=e.offset}let B=null;return d&16&&(B=ee(r,a,E,O)),{metadata:u,flags:d,vertexData:F,indexData:re,isFloat32:D,deltaEncoded:O,planarByteSplit:k,uint16Indices:L,vertexCount:E,origin:[f,p,m],scale:[h,g,T],uvs:z,colors:B}}function H(e,t,n){if(n.length===0)return!1;let r=e=>{let t=16;for(;t<e*2;)t*=2;return t},i=(n,i)=>{if(i<12||i%3!=0)return!1;let a=0;for(let r=0;r<i;r++){let i=t[n+r]*3;a=Math.max(a,Math.abs(e[i]),Math.abs(e[i+1]),Math.abs(e[i+2]))}if(!(a>0)||!Number.isFinite(a))return!1;let o=1/(2*2**(Math.floor(Math.log2(a))-23)),s=r(i),c=s-1,l=new Int32Array(s).fill(-1),u=new Int32Array(s),d=new Int32Array(s),f=new Int32Array(s),p=(e,t,n)=>{let r=Math.imul(e,2654435761)^Math.imul(t,2246822519)^Math.imul(n,3266489917);for(r=(r^r>>>15)&c;l[r]!==-1&&(u[r]!==e||d[r]!==t||f[r]!==n);)r=r+1&c;return r},m=(e,t)=>{let n=e-t;return n>.25?t+1:n<-.25?t-1:t},h=new Int32Array(i);for(let r=0;r<i;r++){let i=t[n+r],a=e[i*3]*o,s=e[i*3+1]*o,c=e[i*3+2]*o,g=Math.round(a),_=Math.round(s),v=Math.round(c),y=m(a,g),b=m(s,_),x=m(c,v),S=-1;for(let e=0;e<8&&S===-1;e++){if(e&1&&y===g||e&2&&b===_||e&4&&x===v)continue;let t=p(e&1?y:g,e&2?b:_,e&4?x:v);l[t]!==-1&&(S=l[t])}if(S===-1){let e=p(g,_,v);l[e]=i,u[e]=g,d[e]=_,f[e]=v,S=i}h[r]=S}let g=r(i),_=g-1,v=new Int32Array(g).fill(-1),y=new Int32Array(g),b=(e,t)=>{let n=(Math.imul(e,2654435761)^Math.imul(t,2246822519))&_;for(;v[n]!==-1&&(v[n]!==e||y[n]!==t);)n=n+1&_;return n},x=(e,t)=>{let n=b(e,t);return v[n]===-1&&(v[n]=e,y[n]=t,!0)},S=(e,t)=>v[b(e,t)]!==-1,C=0;for(let e=0;e<i;e+=3){let t=h[e],n=h[e+1],r=h[e+2];if(t!==n&&n!==r&&r!==t){if(!x(t,n)||!x(n,r)||!x(r,t))return!1;C++}}if(C<4)return!1;for(let e=0;e<i;e+=3){let t=h[e],n=h[e+1],r=h[e+2];if(t!==n&&n!==r&&r!==t&&(!S(n,t)||!S(r,n)||!S(t,r)))return!1}let w=h[0]*3,T=e[w],E=e[w+1],D=e[w+2],O=0;for(let t=0;t<i;t+=3){let n=h[t]*3,r=h[t+1]*3,i=h[t+2]*3,a=e[n]-T,o=e[n+1]-E,s=e[n+2]-D,c=e[r]-T,l=e[r+1]-E,u=e[r+2]-D,d=e[i]-T,f=e[i+1]-E,p=e[i+2]-D;O+=a*(l*p-u*f)+o*(u*d-c*p)+s*(c*f-l*d)}return O>0},a=0;for(let e of n){if(!i(a,e))return!1;a+=e}return!0}function U(e,t,n,r){let i=Math.cos(30*Math.PI/180),a=e.length/3,o=t.length,s=o/3;{let i=new Uint32Array(e.buffer,e.byteOffset,e.length),s=n?new Uint32Array(n.buffer,n.byteOffset,n.length):null,c=(e,t)=>e[t]===2147483648?0:e[t],l=(e,t)=>{for(let n=0;n<3;n++)if(c(i,e*3+n)!==c(i,t*3+n)||r&&r[e*3+n]!==r[t*3+n])return!1;return!s||s[e*2]===s[t*2]&&s[e*2+1]===s[t*2+1]},u=16;for(;u<a*2;)u*=2;let d=u-1,f=new Int32Array(u).fill(-1),p=new Uint32Array(a);for(let e=0;e<a;e++){let t=Math.imul(c(i,e*3),2654435761)^Math.imul(c(i,e*3+1),2246822519)^Math.imul(c(i,e*3+2),3266489917);for(t=(t^t>>>15)&d;f[t]!==-1&&!l(f[t],e);)t=t+1&d;f[t]===-1&&(f[t]=e),p[e]=f[t]}for(let e=0;e<o;e++)t[e]=p[t[e]]}let c=new Float32Array(s*3),l=new Float32Array(s);for(let n=0;n<s;n++){let r=t[n*3]*3,i=t[n*3+1]*3,a=t[n*3+2]*3,o=e[i]-e[r],s=e[i+1]-e[r+1],u=e[i+2]-e[r+2],d=e[a]-e[r],f=e[a+1]-e[r+1],p=e[a+2]-e[r+2],m=s*p-u*f,h=u*d-o*p,g=o*f-s*d,_=Math.sqrt(m*m+h*h+g*g);_!==0&&(c[n*3]=m/_,c[n*3+1]=h/_,c[n*3+2]=g/_,l[n]=_)}let u=new Uint32Array(a+1);for(let e=0;e<o;e++)u[t[e]+1]+=1;for(let e=0;e<a;e++)u[e+1]+=u[e];let d=new Uint32Array(o),f=u.slice(0,a);for(let e=0;e<o;e++){let n=t[e];d[f[n]]=e,f[n]+=1}let p=0;for(let e=0;e<a;e++)p=Math.max(p,u[e+1]-u[e]);let m=new Uint32Array(o),h=new Uint32Array(a),g=new Float32Array(Math.max(1,p)*3);for(let e=0;e<a;e++){let t=0;for(let n=u[e];n<u[e+1];n++){let e=d[n],r=Math.floor(e/3)*3,a=c[r],o=c[r+1],s=c[r+2],l=-1;if(a===0&&o===0&&s===0)l=0;else for(let e=0;e<t;e++)if(g[e*3]*a+g[e*3+1]*o+g[e*3+2]*s>=i){l=e;break}l===-1&&(l=t,g[t*3]=a,g[t*3+1]=o,g[t*3+2]=s,t++),m[e]=l}h[e]=Math.max(1,t)}let _=new Uint32Array(a+1);for(let e=0;e<a;e++)_[e+1]=_[e]+h[e]-1;let v=_[a],y=a+v,b=e,x=n,S=r;if(v>0){b=new Float32Array(y*3),b.set(e),x=n?new Float32Array(y*2):null,x&&n&&x.set(n),S=r?new Uint8Array(y*3):null,S&&r&&S.set(r);for(let t=0;t<a;t++)for(let i=1;i<h[t];i++){let o=a+_[t]+i-1;b[o*3]=e[t*3],b[o*3+1]=e[t*3+1],b[o*3+2]=e[t*3+2],x&&n&&(x[o*2]=n[t*2],x[o*2+1]=n[t*2+1]),S&&r&&(S[o*3]=r[t*3],S[o*3+1]=r[t*3+1],S[o*3+2]=r[t*3+2])}}let C=new Float32Array(y*3);for(let e=0;e<o;e++){let n=t[e],r=m[e],i=r===0?n:a+_[n]+r-1;t[e]=i;let o=Math.floor(e/3)*3,s=l[o/3];C[i*3]+=c[o]*s,C[i*3+1]+=c[o+1]*s,C[i*3+2]+=c[o+2]*s}for(let e=0;e<C.length;e+=3){let t=C[e],n=C[e+1],r=C[e+2],i=Math.sqrt(t*t+n*n+r*r)||1;C[e]=t/i,C[e+1]=n/i,C[e+2]=r/i}return{positions:b,normals:C,indices:t,uvs:x,colors:S}}function ae(e,t,n,r){let i=e.length/3,a=new Float32Array(i*3),o=new Float32Array(i*3);for(let t=0;t<n.length;t+=3){let i=n[t],s=n[t+1],c=n[t+2],l=e[s*3]-e[i*3],u=e[s*3+1]-e[i*3+1],d=e[s*3+2]-e[i*3+2],f=e[c*3]-e[i*3],p=e[c*3+1]-e[i*3+1],m=e[c*3+2]-e[i*3+2],h=u*m-d*p,g=d*f-l*m,_=l*p-u*f,v=Math.sqrt(h*h+g*g+_*_);if(v===0)continue;let y=(p*_-m*g)/v,b=(m*h-f*_)/v,x=(f*g-p*h)/v,S=(g*d-_*u)/v,C=(_*l-h*d)/v,w=(h*u-g*l)/v,T=r[s*2]-r[i*2],E=r[c*2]-r[i*2],D=r[s*2+1]-r[i*2+1],O=r[c*2+1]-r[i*2+1],k=T*y+E*S,A=T*b+E*C,j=T*x+E*w,M=D*y+O*S,N=D*b+O*C,P=D*x+O*w;for(let e=0;e<3;e++){let r=n[t+e];a[r*3]+=k,a[r*3+1]+=A,a[r*3+2]+=j,o[r*3]+=M,o[r*3+1]+=N,o[r*3+2]+=P}}let s=new Float32Array(i*4);for(let e=0;e<i;e++){let n=t[e*3],r=t[e*3+1],i=t[e*3+2],c=a[e*3]*n+a[e*3+1]*r+a[e*3+2]*i,l=a[e*3]-c*n,u=a[e*3+1]-c*r,d=a[e*3+2]-c*i,f=Math.sqrt(l*l+u*u+d*d);if(!(f>1e-12)){let e=+(Math.abs(n)<.9),t=1-e;l=t*i,u=-e*i,d=e*r-t*n,f=Math.sqrt(l*l+u*u+d*d)||1}l/=f,u/=f,d/=f;let p=r*d-i*u,m=i*l-n*d,h=n*u-r*l,g=p*o[e*3]+m*o[e*3+1]+h*o[e*3+2];s[e*4]=l,s[e*4+1]=u,s[e*4+2]=d,s[e*4+3]=g<0?-1:1}return s}function oe(e,t){let n=H(e.positions,e.indices,t),r=U(e.positions,e.indices,e.uvs,e.colors),i=r.uvs?ae(r.positions,r.normals,r.indices,r.uvs):null;return{...r,closed:n,tangents:i}}function se(e){let{isFloat32:t,deltaEncoded:n,planarByteSplit:r,uint16Indices:i,origin:a,scale:o,uvs:s,colors:c,jobs:l}=e,u=e=>e>>>1^-(e&1),d;if(t)d=e.vertexData;else{let t;if(r){let n=e.vertexData,r=n.length/6;t=new Int16Array(r*3);let i=0,a=0,o=0;for(let e=0;e<r;e++)i=i+u(n[e]|n[r*3+e]<<8)<<16>>16,a=a+u(n[r+e]|n[r*4+e]<<8)<<16>>16,o=o+u(n[r*2+e]|n[r*5+e]<<8)<<16>>16,t[e*3]=i,t[e*3+1]=a,t[e*3+2]=o}else if(n){let n=e.vertexData;t=new Int16Array(n.length);let r=0,i=0,a=0;for(let e=0;e<n.length;e+=3)r=r+u(n[e])<<16>>16,i=i+u(n[e+1])<<16>>16,a=a+u(n[e+2])<<16>>16,t[e]=r,t[e+1]=i,t[e+2]=a}else t=e.vertexData;d=new Float32Array(t.length);let i=a[0],s=a[1],c=a[2],l=o[0],f=o[1],p=o[2];for(let e=0;e<t.length;e+=3)d[e]=i+(t[e]+32767)*l,d[e+1]=s+(t[e+1]+32767)*f,d[e+2]=c+(t[e+2]+32767)*p}let f;if(r){let t=e.indexData;if(i){let e=t.length/2,n=new Uint16Array(e),r=0;for(let i=0;i<e;i++)r=r+u(t[i]|t[e+i]<<8)&65535,n[i]=r;f=n}else{let e=t.length/4,n=new Uint32Array(e),r=0;for(let i=0;i<e;i++){let a=(t[i]|t[e+i]<<8|t[e*2+i]<<16|t[e*3+i]<<24)>>>0;r=r+u(a)>>>0,n[i]=r}f=n}}else if(n){let t=e.indexData;if(t instanceof Uint16Array){let e=new Uint16Array(t.length),n=0;for(let r=0;r<t.length;r++)n=n+u(t[r])&65535,e[r]=n;f=e}else{let e=new Uint32Array(t.length),n=0;for(let r=0;r<t.length;r++)n=n+u(t[r])>>>0,e[r]=n;f=e}}else f=e.indexData;let p=d.length/3;for(let e=0;e<f.length;e++)if(f[e]>=p)throw Error(`Index ${f[e]} out of range of vertexCount ${p}`);let m=[];for(let e of l){let t=0,n=0;for(let r of e.windows)t+=r.vertexCount,n+=r.indexCount;let r=new Float32Array(t*3),i=new Uint32Array(n),a=s?new Float32Array(t*2):null,o=c?new Uint8Array(t*3):null,l=0,u=0;for(let t of e.windows){let e=t.vertexStart*3;r.set(d.subarray(e,e+t.vertexCount*3),l*3),a&&s&&a.set(s.subarray(t.vertexStart*2,(t.vertexStart+t.vertexCount)*2),l*2),o&&c&&o.set(c.subarray(e,e+t.vertexCount*3),l*3);let n=t.vertexStart,p=t.vertexStart+t.vertexCount,m=l-t.vertexStart;for(let e=0;e<t.indexCount;e++){let r=f[t.indexStart+e];if(r<n||r>=p)throw Error(`Index ${r} outside vertex window [${n}, ${p})`);i[u+e]=r+m}l+=t.vertexCount,u+=t.indexCount}m.push({positions:r,indices:i,uvs:a,colors:o})}return m}function ce(){return[`const assemble = ${se.toString()};`,`const isClosedSolid = ${H.toString()};`,`const splitCreases = ${U.toString()};`,`const grainTangents = ${ae.toString()};`,`self.onmessage = (event) => {`,` const { id, input } = event.data;`,` try {`,` const geometries = assemble(input).map((g, i) => {`,` const counts = input.jobs[i].windows.map((w) => w.indexCount);`,` const closed = isClosedSolid(g.positions, g.indices, counts);`,` const c = splitCreases(g.positions, g.indices, g.uvs, g.colors);`,` const tangents = c.uvs ? grainTangents(c.positions, c.normals, c.indices, c.uvs) : null;`,` return { ...c, closed, tangents };`,` });`,` const transfer = [];`,` for (const g of geometries) {`,` transfer.push(g.positions.buffer, g.normals.buffer, g.indices.buffer);`,` if (g.uvs) transfer.push(g.uvs.buffer);`,` if (g.tangents) transfer.push(g.tangents.buffer);`,` if (g.colors) transfer.push(g.colors.buffer);`,` }`,` self.postMessage({ id, geometries }, transfer);`,` } catch (error) {`,` self.postMessage({ id, error: String((error && error.message) || error) });`,` }`,`};`].join(`
|
|
2
|
+
`)}let W;const G=new Map;let le=1;function ue(){if(W!==void 0)return W;if(typeof Worker>`u`||typeof Blob>`u`||typeof URL>`u`||typeof URL.createObjectURL!=`function`)return W=null,null;try{let e=URL.createObjectURL(new Blob([ce()],{type:`text/javascript`})),t=new Worker(e);t.onmessage=e=>{let{id:t,geometries:n,error:r}=e.data,i=G.get(t);i&&(G.delete(t),n?i.resolve(n):i.reject(Error(r??`mesh assembly failed in worker`)))},t.onerror=()=>{for(let e of G.values())e.reject(Error(`mesh assembly worker crashed`));G.clear(),t.terminate(),W=null},W=t}catch{W=null}return W}function de(e,t,n){return new Promise((r,i)=>{let a=le++;G.set(a,{resolve:r,reject:i}),e.postMessage({id:a,input:t},n)})}let K=1;function q(e){K=Math.max(1,e)}t.n(q);function J(e,r,i,a){typeof document>`u`||new n.TextureLoader().load(r,t=>{if(t.colorSpace=i===`map`?n.SRGBColorSpace:n.NoColorSpace,t.anisotropy=K,a){let e=t.image,r=e?.width&&e.height?e.height/e.width:1;t.wrapS=n.RepeatWrapping,t.wrapT=n.RepeatWrapping,t.repeat.set(1/a,1/(a*r))}e[i]=t,e.needsUpdate=!0},void 0,e=>{t.p().warn(`Failed to load material ${i} ${r}:`,e)})}const fe={brushed:{fibres:[{pitch:.04,length:[2,12],depth:.3},{pitch:.25,length:[5,40],depth:.18}],bands:[]},rolled:{fibres:[{pitch:.3,length:[80,600],depth:.07}],bands:[{width:20,length:1500,depth:.05}]}},Y=.35,X=e=>e.toFixed(4);function pe(e,t){let n=fe[e];if(!n||!(t>0))return null;let r=n.fibres.map((e,t)=>`selvaFibres( vUv, footprint, ${X(e.pitch)}, vec2( ${X(e.length[0])}, ${X(e.length[1])} ), ${X(e.depth)}, ${X(t*31+3)} )`).join(` + `)||`0.0`,i=n.bands.map(e=>`selvaBand( vUv, footprint, vec2( ${X(e.length)}, ${X(e.width)} ), ${X(e.depth)} )`).join(` + `)||`0.0`;return{key:`finish:${e}:${X(t)}`,patch:e=>{e.fragmentShader=e.fragmentShader.replace(`#include <common>`,`#include <common>
|
|
3
|
+
// Hash without sine: sin() loses precision on the large arguments mm UVs produce.
|
|
4
|
+
float selvaHash( vec2 p ) {
|
|
5
|
+
vec3 p3 = fract( vec3( p.xyx ) * 0.1031 );
|
|
6
|
+
p3 += dot( p3, p3.yzx + 33.33 );
|
|
7
|
+
return fract( ( p3.x + p3.y ) * p3.z );
|
|
8
|
+
}
|
|
9
|
+
float selvaNoise( vec2 p ) {
|
|
10
|
+
vec2 i = floor( p );
|
|
11
|
+
vec2 f = fract( p );
|
|
12
|
+
vec2 s = f * f * ( 3.0 - 2.0 * f );
|
|
13
|
+
return mix(
|
|
14
|
+
mix( selvaHash( i ), selvaHash( i + vec2( 1.0, 0.0 ) ), s.x ),
|
|
15
|
+
mix( selvaHash( i + vec2( 0.0, 1.0 ) ), selvaHash( i + vec2( 1.0, 1.0 ) ), s.x ),
|
|
16
|
+
s.y
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
// One row of fibres per pitch, hard-edged across the grain, each fibre its own depth and
|
|
20
|
+
// tapered at both ends. A depth per row instead drew every row as one streak the height
|
|
21
|
+
// of the part. depth * |depth| keeps most fibres faint and a few deep.
|
|
22
|
+
float selvaFibreRow( vec2 uv, float pitch, vec2 len, float seed ) {
|
|
23
|
+
float row = floor( uv.y / pitch );
|
|
24
|
+
float l = mix( len.x, len.y, selvaHash( vec2( row, seed + 1.0 ) ) );
|
|
25
|
+
float along = uv.x / l + selvaHash( vec2( row, seed + 2.0 ) );
|
|
26
|
+
float seg = floor( along );
|
|
27
|
+
float depth = selvaHash( vec2( row, seed + 3.0 + 1.618 * seg ) ) * 2.0 - 1.0;
|
|
28
|
+
float t = along - seg;
|
|
29
|
+
return depth * abs( depth ) * smoothstep( 0.0, 0.2, t ) * smoothstep( 1.0, 0.8, t );
|
|
30
|
+
}
|
|
31
|
+
// Below pixel size a cell 2^n rows wide stands for the rows it covers, at a reduced
|
|
32
|
+
// spread: distance keeps the grain's texture without the shimmer of sampling single
|
|
33
|
+
// fibres. Two levels blend so nothing pops while zooming.
|
|
34
|
+
float selvaFibres( vec2 uv, float footprint, float pitch, vec2 len, float depth, float seed ) {
|
|
35
|
+
float level = clamp( log2( footprint / pitch ) + 0.5, 0.0, 14.0 );
|
|
36
|
+
float l0 = floor( level );
|
|
37
|
+
float a = selvaFibreRow( uv, pitch * exp2( l0 ), len, seed + 7.0 * l0 ) * exp2( -${X(Y)} * l0 );
|
|
38
|
+
float b = selvaFibreRow( uv, pitch * exp2( l0 + 1.0 ), len, seed + 7.0 * l0 + 7.0 )
|
|
39
|
+
* exp2( -${X(Y)} * ( l0 + 1.0 ) );
|
|
40
|
+
return depth * mix( a, b, level - l0 );
|
|
41
|
+
}
|
|
42
|
+
float selvaBand( vec2 uv, float footprint, vec2 size, float depth ) {
|
|
43
|
+
float fade = 1.0 - smoothstep( 0.5, 1.0, footprint / size.y );
|
|
44
|
+
return depth * fade * ( selvaNoise( uv / size ) * 2.0 - 1.0 );
|
|
45
|
+
}`).replace(`#include <color_fragment>`,`#include <color_fragment>
|
|
46
|
+
float footprint = max( fwidth( vUv.y ), 1e-6 );
|
|
47
|
+
float selvaFibre = ( ${r} ) * ${X(t)};
|
|
48
|
+
float selvaStreak = selvaFibre + ( ${i} ) * ${X(t)};
|
|
49
|
+
diffuseColor.rgb *= 1.0 + 0.5 * selvaStreak;`).replace(`#include <roughnessmap_fragment>`,`#include <roughnessmap_fragment>
|
|
50
|
+
roughnessFactor = clamp( roughnessFactor * ( 1.0 + selvaStreak ), 0.0, 1.0 );`).replace(`#include <normal_fragment_maps>`,`#include <normal_fragment_maps>
|
|
51
|
+
#ifdef USE_ANISOTROPY
|
|
52
|
+
vec3 selvaAcross = tbn[ 1 ];
|
|
53
|
+
#else
|
|
54
|
+
// V's direction from screen derivatives, as three's getTangentFrame.
|
|
55
|
+
vec3 selvaQ0 = dFdx( - vViewPosition );
|
|
56
|
+
vec3 selvaQ1 = dFdy( - vViewPosition );
|
|
57
|
+
vec3 selvaAcross = cross( selvaQ1, normal ) * dFdx( vUv ).y + cross( normal, selvaQ0 ) * dFdy( vUv ).y;
|
|
58
|
+
selvaAcross *= inversesqrt( max( dot( selvaAcross, selvaAcross ), 1e-12 ) );
|
|
59
|
+
#endif
|
|
60
|
+
normal = normalize( normal + ${X(.6)} * selvaFibre * selvaAcross );`)}}}function me(e,t){return t?.appearance?.cullBackfaces?!0:(t?.closed??!1)&&!e.transparent&&e.opacity>=1}function he(e,t){let n=new Map;return(r,i)=>{let a=e[r],o=me(a,{...t,closed:i}),s=`${r}:${o}`,c=n.get(s);return c||(c=ge(a,{...t,closed:o}),n.set(s,c)),c}}function ge(e,r){let i=t.o(e.color),a=r?.vertexColors??!1,o=r?.appearance,s=new n.MeshPhysicalMaterial({color:i,metalness:e.metalness,roughness:e.roughness,opacity:e.opacity,transparent:e.transparent,vertexColors:a,side:me(e,r)?n.FrontSide:n.DoubleSide,polygonOffset:!0,polygonOffsetFactor:.25,polygonOffsetUnits:0,depthWrite:!0,depthTest:!0});e.envMapIntensity==null?o?.envMapIntensity!=null&&(s.envMapIntensity=t.u(o.envMapIntensity,e.metalness)):(s.envMapIntensity=e.envMapIntensity,s.userData[t.l]=e.envMapIntensity),e.clearcoat!=null&&(s.clearcoat=e.clearcoat,s.clearcoatRoughness=e.clearcoatRoughness??0),e.anisotropy!=null&&e.anisotropy>0&&r?.hasUvs&&(s.anisotropy=e.anisotropy,s.anisotropyRotation=e.anisotropyRotation??0),e.transmission!=null&&(s.transmission=e.transmission,s.thickness=0),e.ior!=null&&(s.ior=e.ior),a&&ve(s);let c=e.finish&&r?.hasUvs?pe(e.finish,e.finishStrength??1):null;c&&(s.defines={...s.defines,USE_UV:``},_e(s,c.key,c.patch));let{mapSize:l}=e;return e.map&&J(s,e.map,`map`,l),e.roughnessMap&&J(s,e.roughnessMap,`roughnessMap`,l),e.normalMap&&J(s,e.normalMap,`normalMap`,l),s}function _e(e,t,n){let r=e.onBeforeCompile,i=e.customProgramCacheKey.bind(e);e.onBeforeCompile=(t,i)=>{r.call(e,t,i),n(t)},e.customProgramCacheKey=()=>`${i()}|${t}`}function ve(e){_e(e,`srgb-vertex-colors`,e=>{e.vertexShader=e.vertexShader.replace(`#include <color_vertex>`,`#include <color_vertex>
|
|
3
61
|
#if defined( USE_COLOR ) || defined( USE_COLOR_ALPHA )
|
|
4
62
|
vColor.rgb = mix(
|
|
5
63
|
vColor.rgb / 12.92,
|
|
6
64
|
pow( ( vColor.rgb + 0.055 ) / 1.055, vec3( 2.4 ) ),
|
|
7
65
|
step( vec3( 0.04045 ), vColor.rgb )
|
|
8
66
|
);
|
|
9
|
-
#endif`)}}function K(e,n){return new t.h(e,t.m.VALIDATION_ERROR,{context:n})}function q(e,t,n,r){for(let i of e){if(!Number.isInteger(i.materialId)||i.materialId<0||i.materialId>=t)throw K(`Group materialId out of range of the materials array.`,{materialId:i.materialId,materialCount:t});for(let e of i.meshes){let t={vertexStart:e.vertexStart,vertexCount:e.vertexCount,indexStart:e.indexStart,indexCount:e.indexCount};for(let[n,r]of Object.entries(t))if(!Number.isInteger(r)||r<0)throw K(`Mesh metadata field "${n}" must be a non-negative integer.`,{meshName:e.name,field:n,value:r});if(e.vertexStart+e.vertexCount>n)throw K(`Mesh vertex window exceeds the batch vertex buffer.`,{meshName:e.name,vertexStart:e.vertexStart,vertexCount:e.vertexCount,totalVertexCount:n});if(e.indexStart+e.indexCount>r)throw K(`Mesh index window exceeds the batch index buffer.`,{meshName:e.name,indexStart:e.indexStart,indexCount:e.indexCount,totalIndexCount:r})}}}function J(e,t){return K(`Index references a vertex outside its mesh's vertex window.`,{meshName:t.name,indexValue:e,vertexStart:t.vertexStart,vertexCount:t.vertexCount})}function pe(e,t,n){let r=new Float32Array(e.length),i=t[0],a=t[1],o=t[2],s=n[0],c=n[1],l=n[2];for(let t=0;t<e.length;t+=3)r[t]=i+(e[t]+32767)*s,r[t+1]=a+(e[t+1]+32767)*c,r[t+2]=o+(e[t+2]+32767)*l;return r}function Y(e){let t=new Map;for(let n of e.meshes){let e=n.layer??``,r=t.get(e);r||(r=[],t.set(e,r)),r.push(n)}return[...t.values()].map(t=>({materialId:e.materialId,meshes:t}))}function me(e,t,r,i,a=null,o=null){let s=0,c=0;for(let t of e.meshes)s+=t.vertexCount,c+=t.indexCount;let l=new Float32Array(s*3),u=new Uint32Array(c),d=a?new Float32Array(s*2):null,f=o?new Uint8Array(s*3):null,p=0,m=0;for(let n of e.meshes){let e=n.vertexStart*3,i=n.vertexCount*3;if(l.set(t.subarray(e,e+i),p*3),d&&a){let e=n.vertexStart*2;d.set(a.subarray(e,e+n.vertexCount*2),p*2)}f&&o&&f.set(o.subarray(e,e+i),p*3);let s=r.subarray(n.indexStart,n.indexStart+n.indexCount),c=p-n.vertexStart,h=n.vertexStart,g=n.vertexStart+n.vertexCount;for(let e=0;e<s.length;e++){let t=s[e];if(t<h||t>=g)throw J(t,n);u[m+e]=t+c}p+=n.vertexCount,m+=n.indexCount}let h=new n.BufferGeometry;return h.setAttribute(`position`,new n.BufferAttribute(l,3)),h.setIndex(new n.BufferAttribute(u,1)),d&&h.setAttribute(`uv`,new n.BufferAttribute(d,2)),f&&h.setAttribute(`color`,new n.BufferAttribute(f,3,!0)),h.computeVertexNormals(),X(h,e,i)}function he(e){let t=[],n=0;for(let r of e.meshes)t.push({trackingKey:r.id,name:r.name,layer:r.layer,metadata:r.metadata??{},indexStart:n,indexCount:r.indexCount}),n+=r.indexCount;return t}function X(e,t,r){let i=new n.Mesh(e,r[t.materialId]),a=t.meshes[0],o=t.meshes.map(e=>e.name).filter(e=>e&&e.length>0);return i.name=o.length>0?o[0]:`merged_material_${t.materialId}`,i.castShadow=!0,i.receiveShadow=!0,i.userData={source:`compute`,name:i.name,layer:a?.layer??``,metadata:a?.metadata??{},members:he(t)},i}function ge(e,t,r,i,a=null,o=null){let s=[];for(let c of e.meshes){let l=c.vertexStart*3,u=c.vertexCount*3,d=t.slice(l,l+u),f=r.subarray(c.indexStart,c.indexStart+c.indexCount),p=new Uint32Array(f.length),m=c.vertexStart,h=c.vertexStart+c.vertexCount;for(let e=0;e<f.length;e++){let t=f[e];if(t<m||t>=h)throw J(t,c);p[e]=t-m}let g=new n.BufferGeometry;if(g.setAttribute(`position`,new n.BufferAttribute(d,3)),g.setIndex(new n.BufferAttribute(p,1)),a){let e=c.vertexStart*2,t=a.slice(e,e+c.vertexCount*2);g.setAttribute(`uv`,new n.BufferAttribute(t,2))}if(o){let e=o.slice(l,l+u);g.setAttribute(`color`,new n.BufferAttribute(e,3,!0))}g.computeVertexNormals(),s.push(Z(g,c,e,i))}return s}function Z(e,t,r,i){let a=new n.Mesh(e,i[r.materialId]);return a.name=t.name,a.userData={source:`compute`,name:t.name,layer:t.layer??``,trackingKey:t.id,metadata:t.metadata??{}},a.castShadow=!0,a.receiveShadow=!0,a}async function Q(e,t,n){let{mergeByMaterial:r=!0,debug:i=!1,material:a}=t??{},{parseTime:o=0,perfStart:s=i?performance.now():0}=n??{};if(!e.compressedData)return[];let c=await xe(e.compressedData,{mergeByMaterial:r,debug:i,material:a,fallback:{materials:e.materials,groups:e.groups}});if(c)return c;let l=performance.now();return be(z(e.compressedData),{mergeByMaterial:r,debug:i,material:a,parseTime:o,decodeTime:performance.now()-l,perfStart:s,blobBytes:i?Se(e.compressedData):0,fallback:{materials:e.materials,groups:e.groups}})}async function _e(e,t){let{mergeByMaterial:n=!0,debug:r=!1,material:i}=t??{},a=r?performance.now():0,o=await xe(e,{mergeByMaterial:n,debug:r,material:i});if(o)return o;let s=performance.now(),c=z(e),l=performance.now()-s,u=e.byteLength;return be(c,{mergeByMaterial:n,debug:r,material:i,parseTime:0,decodeTime:l,perfStart:a,blobBytes:u})}let ve=!1;function ye(e,n){if(e||ve)return;let r=0;for(let e of n)r+=e.meshes.length;r<1e3||(ve=!0,t.f().warn(`Parsing ${r} meshes with mergeByMaterial: false — each becomes its own THREE object, and render cost scales with object count. Drop the option to merge by material (the default); per-object identity survives it via userData.members.`))}function be(e,n){let{mergeByMaterial:r,debug:i,material:a,parseTime:o,decodeTime:s,perfStart:c,blobBytes:l,fallback:u}=n,d=e.metadata.materials??u?.materials??[],f=e.metadata.groups??u?.groups??[],p=!!(e.flags&1);q(f,d.length,e.vertices.length/3,e.indices.length);let m=p?e.vertices:pe(e.vertices,e.origin,e.scale);if(i){let n=e.vertices.byteLength+e.indices.byteLength;t.f().debug(`Mesh Batch Stats:`),t.f().debug(` Materials: ${d.length} | Groups: ${f.length}`),t.f().debug(` Vertices: ${e.vertices.length/3} | Indices: ${e.indices.length}`),t.f().debug(` Format: ${p?`float32`:`int16 quantized`}`),t.f().debug(` Blob: ${(l/1024/1024).toFixed(2)} MB | Geometry on wire: ${(n/1024/1024).toFixed(2)} MB`)}ye(r,f);let h=performance.now(),g=d.map(t=>G(t,{vertexColors:e.colors!=null,hasUvs:e.uvs!=null,appearance:a})),_=[],v=r?f.flatMap(Y):f;for(let t of v)if(r&&t.meshes.length>1){let n=me(t,m,e.indices,g,e.uvs,e.colors);_.push(n)}else{let n=ge(t,m,e.indices,g,e.uvs,e.colors);_.push(...n)}let y=performance.now()-h;if(i){let e=performance.now()-c;t.f().debug(`Performance:`),o>0&&t.f().debug(` Parse JSON: ${o.toFixed(2)}ms`),t.f().debug(` Decode binary: ${s.toFixed(2)}ms`),t.f().debug(` Create Meshes: ${y.toFixed(2)}ms`),t.f().debug(` Total: ${e.toFixed(2)}ms`)}return Promise.resolve(_)}async function xe(e,r){if(typeof Worker>`u`)return null;let i=B(e),a=i.planarByteSplit?i.indexData.length/(i.uint16Indices?2:4):i.indexData.length;if(a/3<5e4)return null;let o=le();if(!o)return null;let s=i.metadata.materials??r.fallback?.materials??[],c=i.metadata.groups??r.fallback?.groups??[];q(c,s.length,i.vertexCount,a);let l=e=>({vertexStart:e.vertexStart,vertexCount:e.vertexCount,indexStart:e.indexStart,indexCount:e.indexCount}),u=[],d=[],f=r.mergeByMaterial?c.flatMap(Y):c;for(let e of f)if(r.mergeByMaterial&&e.meshes.length>1)u.push({kind:`merged`,windows:e.meshes.map(l)}),d.push({kind:`merged`,group:e});else for(let t of e.meshes)u.push({kind:`single`,windows:[l(t)]}),d.push({kind:`single`,group:e,meshMeta:t});let p=i.vertexData.slice(),m=i.indexData.slice(),h=[p.buffer,m.buffer];i.uvs&&h.push(i.uvs.buffer),i.colors&&h.push(i.colors.buffer);let g;try{g=await ue(o,{vertexData:p,isFloat32:i.isFloat32,deltaEncoded:i.deltaEncoded,planarByteSplit:i.planarByteSplit,uint16Indices:i.uint16Indices,origin:i.origin,scale:i.scale,indexData:m,uvs:i.uvs,colors:i.colors,jobs:u},h)}catch(e){return t.f().warn(`Mesh assembly worker failed; falling back to main-thread parse.`,e),null}if(g.length!==u.length)return null;let _=s.map(e=>G(e,{vertexColors:i.colors!=null,hasUvs:i.uvs!=null,appearance:r.material})),v=[];for(let e=0;e<g.length;e++){let t=g[e],r=d[e],i=new n.BufferGeometry;i.setAttribute(`position`,new n.BufferAttribute(t.positions,3)),i.setAttribute(`normal`,new n.BufferAttribute(t.normals,3)),i.setIndex(new n.BufferAttribute(t.indices,1)),t.uvs&&i.setAttribute(`uv`,new n.BufferAttribute(t.uvs,2)),t.colors&&i.setAttribute(`color`,new n.BufferAttribute(t.colors,3,!0));let a=r.kind===`merged`?X(i,r.group,_):Z(i,r.meshMeta,r.group,_);v.push(a)}return r.debug&&t.f().debug(`Mesh batch assembled off-thread: ${v.length} meshes, ${a/3} triangles`),v}function Se(e){return Math.floor(e.length*3/4)}const $={Angstroms:1e-10,Nanometers:1e-9,Microns:1e-6,Millimeters:.001,Centimeters:.01,Decimeters:.1,Meters:1,Dekameters:10,Hectometers:100,Kilometers:1e3,Megameters:1e6,Gigameters:1e9,Microinches:2.54e-8,Mils:254e-7,Inches:.0254,Feet:.3048,Yards:.9144,Miles:1609.344,NauticalMiles:1852};function Ce(e){let t=e.split(`.`);return t.includes(`Display`)||t.includes(`DisplayBatch`)}const we=new Set;async function Te(e,t){let n=performance.now(),r=[],{allowScaling:i=!0,allowAutoPosition:a=!1,groundAxis:o=`z`,debug:s=!1,parsing:c={}}=t??{};try{return await De(e,r,i?Ee(e.modelunits):1,c,s),a&&je(r,o),r}catch(e){throw Me(e,r),e}finally{s&&Pe(n)}}function Ee(e){let n=$[e];return n===void 0?(we.has(e)||(we.add(e),t.f().warn(`Unknown Rhino model unit "${e}" — geometry will not be scaled (factor 1). Known units: ${Object.keys($).join(`, `)}.`)),1):n}async function De(e,t,n,r,i){for(let a of e.values){let e=a.InnerTree;for(let a in e){let o=e[a];o&&await Oe(o,t,n,r,i)}}}async function Oe(e,n,r,i,a){for(let o of e){if(!Ce(o.type))continue;let e={debug:!1,...i,mergeByMaterial:i.mergeByMaterial??!0},s=ke(o.data);if(!s){t.f().error(`Error parsing display batch envelope: invalid JSON`);continue}let c=await Q(s,e),l=g(s.items),u=[...c,...l];if(r!==1)for(let e of u)e.scale.set(r,r,r);n.push(...u),a&&t.f().debug(`Extracted ${c.length} meshes and ${l.length} items from batch`)}}function ke(e){return typeof e==`string`?Ae(e):e}function Ae(e){try{return JSON.parse(e)}catch{return}}function je(e,n){if(e.length===0)return;let r=t.a(e);t.i(e,r.min[n],n)}function Me(e,n){t.f().error(`An unexpected error occurred:`,e),Ne(n)}function Ne(e){for(let t of e){let e=t;e.geometry&&e.geometry.dispose(),e.material&&(Array.isArray(e.material)?e.material.forEach(e=>e.dispose()):e.material.dispose())}}function Pe(e){let n=performance.now()-e;t.f().info(`Time to process meshes:`,`${n.toFixed(2)}ms`)}exports.SCALE_FACTORS=$,exports.getThreeObjectsFromComputeResponse=Te,exports.meshPolicy=d,exports.parseDisplayItems=g,exports.parseMeshBatchBlob=_e,exports.parseMeshBatchObject=Q,exports.setTextureAnisotropy=U;
|
|
67
|
+
#endif`)})}function Z(e,n){return new t.g(e,t.h.VALIDATION_ERROR,{context:n})}function ye(e,t,n,r){for(let i of e){if(!Number.isInteger(i.materialId)||i.materialId<0||i.materialId>=t)throw Z(`Group materialId out of range of the materials array.`,{materialId:i.materialId,materialCount:t});for(let e of i.meshes){let t={vertexStart:e.vertexStart,vertexCount:e.vertexCount,indexStart:e.indexStart,indexCount:e.indexCount};for(let[n,r]of Object.entries(t))if(!Number.isInteger(r)||r<0)throw Z(`Mesh metadata field "${n}" must be a non-negative integer.`,{meshName:e.name,field:n,value:r});if(e.vertexStart+e.vertexCount>n)throw Z(`Mesh vertex window exceeds the batch vertex buffer.`,{meshName:e.name,vertexStart:e.vertexStart,vertexCount:e.vertexCount,totalVertexCount:n});if(e.indexStart+e.indexCount>r)throw Z(`Mesh index window exceeds the batch index buffer.`,{meshName:e.name,indexStart:e.indexStart,indexCount:e.indexCount,totalIndexCount:r})}}}function be(e,t){return Z(`Index references a vertex outside its mesh's vertex window.`,{meshName:t.name,indexValue:e,vertexStart:t.vertexStart,vertexCount:t.vertexCount})}function xe(e,t,n){let r=new Float32Array(e.length),i=t[0],a=t[1],o=t[2],s=n[0],c=n[1],l=n[2];for(let t=0;t<e.length;t+=3)r[t]=i+(e[t]+32767)*s,r[t+1]=a+(e[t+1]+32767)*c,r[t+2]=o+(e[t+2]+32767)*l;return r}function Se(e){let t=new Map;for(let n of e.meshes){let e=n.layer??``,r=t.get(e);r||(r=[],t.set(e,r)),r.push(n)}return[...t.values()].map(t=>({materialId:e.materialId,meshes:t}))}function Ce(e,t,n,r,i=null,a=null){let o=0,s=0;for(let t of e.meshes)o+=t.vertexCount,s+=t.indexCount;let c=new Float32Array(o*3),l=new Uint32Array(s),u=i?new Float32Array(o*2):null,d=a?new Uint8Array(o*3):null,f=0,p=0;for(let r of e.meshes){let e=r.vertexStart*3,o=r.vertexCount*3;if(c.set(t.subarray(e,e+o),f*3),u&&i){let e=r.vertexStart*2;u.set(i.subarray(e,e+r.vertexCount*2),f*2)}d&&a&&d.set(a.subarray(e,e+o),f*3);let s=n.subarray(r.indexStart,r.indexStart+r.indexCount),m=f-r.vertexStart,h=r.vertexStart,g=r.vertexStart+r.vertexCount;for(let e=0;e<s.length;e++){let t=s[e];if(t<h||t>=g)throw be(t,r);l[p+e]=t+m}f+=r.vertexCount,p+=r.indexCount}let m=oe({positions:c,indices:l,uvs:u,colors:d},e.meshes.map(e=>e.indexCount));return Te(Q(m),e,r(e.materialId,m.closed))}function Q(e){let t=new n.BufferGeometry;return t.setAttribute(`position`,new n.BufferAttribute(e.positions,3)),t.setAttribute(`normal`,new n.BufferAttribute(e.normals,3)),t.setIndex(new n.BufferAttribute(e.indices,1)),e.uvs&&t.setAttribute(`uv`,new n.BufferAttribute(e.uvs,2)),e.tangents&&t.setAttribute(`tangent`,new n.BufferAttribute(e.tangents,4)),e.colors&&t.setAttribute(`color`,new n.BufferAttribute(e.colors,3,!0)),t}function we(e){let t=[],n=0;for(let r of e.meshes)t.push({trackingKey:r.id,name:r.name,layer:r.layer,metadata:r.metadata??{},indexStart:n,indexCount:r.indexCount}),n+=r.indexCount;return t}function Te(e,t,r){let i=new n.Mesh(e,r),a=t.meshes[0],o=t.meshes.map(e=>e.name).filter(e=>e&&e.length>0);return i.name=o.length>0?o[0]:`merged_material_${t.materialId}`,i.castShadow=!0,i.receiveShadow=!0,i.userData={source:`compute`,name:i.name,layer:a?.layer??``,metadata:a?.metadata??{},members:we(t)},i}function Ee(e,t,n,r,i=null,a=null){let o=[];for(let s of e.meshes){let c=s.vertexStart*3,l=s.vertexCount*3,u=t.slice(c,c+l),d=n.subarray(s.indexStart,s.indexStart+s.indexCount),f=new Uint32Array(d.length),p=s.vertexStart,m=s.vertexStart+s.vertexCount;for(let e=0;e<d.length;e++){let t=d[e];if(t<p||t>=m)throw be(t,s);f[e]=t-p}let h=s.vertexStart*2,g=oe({positions:u,indices:f,uvs:i?i.slice(h,h+s.vertexCount*2):null,colors:a?a.slice(c,c+l):null},[f.length]);o.push(De(Q(g),s,r(e.materialId,g.closed)))}return o}function De(e,t,r){let i=new n.Mesh(e,r);return i.name=t.name,i.userData={source:`compute`,name:t.name,layer:t.layer??``,trackingKey:t.id,metadata:t.metadata??{}},i.castShadow=!0,i.receiveShadow=!0,i}async function Oe(e,t,n){let{mergeByMaterial:r=!0,debug:i=!1,material:a}=t??{},{parseTime:o=0,perfStart:s=i?performance.now():0}=n??{};if(!e.compressedData)return[];let c=await Ne(e.compressedData,{mergeByMaterial:r,debug:i,material:a,fallback:{materials:e.materials,groups:e.groups}});if(c)return c;let l=performance.now();return Me(ie(e.compressedData),{mergeByMaterial:r,debug:i,material:a,parseTime:o,decodeTime:performance.now()-l,perfStart:s,blobBytes:i?Pe(e.compressedData):0,fallback:{materials:e.materials,groups:e.groups}})}async function ke(e,t){let{mergeByMaterial:n=!0,debug:r=!1,material:i}=t??{},a=r?performance.now():0,o=await Ne(e,{mergeByMaterial:n,debug:r,material:i});if(o)return o;let s=performance.now(),c=ie(e),l=performance.now()-s,u=e.byteLength;return Me(c,{mergeByMaterial:n,debug:r,material:i,parseTime:0,decodeTime:l,perfStart:a,blobBytes:u})}let Ae=!1;function je(e,n){if(e||Ae)return;let r=0;for(let e of n)r+=e.meshes.length;r<1e3||(Ae=!0,t.p().warn(`Parsing ${r} meshes with mergeByMaterial: false — each becomes its own THREE object, and render cost scales with object count. Drop the option to merge by material (the default); per-object identity survives it via userData.members.`))}function Me(e,n){let{mergeByMaterial:r,debug:i,material:a,parseTime:o,decodeTime:s,perfStart:c,blobBytes:l,fallback:u}=n,d=e.metadata.materials??u?.materials??[],f=e.metadata.groups??u?.groups??[],p=!!(e.flags&1);ye(f,d.length,e.vertices.length/3,e.indices.length);let m=p?e.vertices:xe(e.vertices,e.origin,e.scale);if(i){let n=e.vertices.byteLength+e.indices.byteLength;t.p().debug(`Mesh Batch Stats:`),t.p().debug(` Materials: ${d.length} | Groups: ${f.length}`),t.p().debug(` Vertices: ${e.vertices.length/3} | Indices: ${e.indices.length}`),t.p().debug(` Format: ${p?`float32`:`int16 quantized`}`),t.p().debug(` Blob: ${(l/1024/1024).toFixed(2)} MB | Geometry on wire: ${(n/1024/1024).toFixed(2)} MB`)}je(r,f);let h=performance.now(),g=he(d,{vertexColors:e.colors!=null,hasUvs:e.uvs!=null,appearance:a}),_=[],v=r?f.flatMap(Se):f;for(let t of v)if(r&&t.meshes.length>1){let n=Ce(t,m,e.indices,g,e.uvs,e.colors);_.push(n)}else{let n=Ee(t,m,e.indices,g,e.uvs,e.colors);_.push(...n)}let y=performance.now()-h;if(i){let e=performance.now()-c;t.p().debug(`Performance:`),o>0&&t.p().debug(` Parse JSON: ${o.toFixed(2)}ms`),t.p().debug(` Decode binary: ${s.toFixed(2)}ms`),t.p().debug(` Create Meshes: ${y.toFixed(2)}ms`),t.p().debug(` Total: ${e.toFixed(2)}ms`)}return Promise.resolve(_)}async function Ne(e,n){if(typeof Worker>`u`)return null;let r=V(e),i=r.planarByteSplit?r.indexData.length/(r.uint16Indices?2:4):r.indexData.length;if(i/3<5e4)return null;let a=ue();if(!a)return null;let o=r.metadata.materials??n.fallback?.materials??[],s=r.metadata.groups??n.fallback?.groups??[];ye(s,o.length,r.vertexCount,i);let c=e=>({vertexStart:e.vertexStart,vertexCount:e.vertexCount,indexStart:e.indexStart,indexCount:e.indexCount}),l=[],u=[],d=n.mergeByMaterial?s.flatMap(Se):s;for(let e of d)if(n.mergeByMaterial&&e.meshes.length>1)l.push({kind:`merged`,windows:e.meshes.map(c)}),u.push({kind:`merged`,group:e});else for(let t of e.meshes)l.push({kind:`single`,windows:[c(t)]}),u.push({kind:`single`,group:e,meshMeta:t});let f=r.vertexData.slice(),p=r.indexData.slice(),m=[f.buffer,p.buffer];r.uvs&&m.push(r.uvs.buffer),r.colors&&m.push(r.colors.buffer);let h;try{h=await de(a,{vertexData:f,isFloat32:r.isFloat32,deltaEncoded:r.deltaEncoded,planarByteSplit:r.planarByteSplit,uint16Indices:r.uint16Indices,origin:r.origin,scale:r.scale,indexData:p,uvs:r.uvs,colors:r.colors,jobs:l},m)}catch(e){return t.p().warn(`Mesh assembly worker failed; falling back to main-thread parse.`,e),null}if(h.length!==l.length)return null;let g=he(o,{vertexColors:r.colors!=null,hasUvs:r.uvs!=null,appearance:n.material}),_=[];for(let e=0;e<h.length;e++){let t=h[e],n=u[e],r=Q(t),i=g(n.group.materialId,t.closed),a=n.kind===`merged`?Te(r,n.group,i):De(r,n.meshMeta,i);_.push(a)}return n.debug&&t.p().debug(`Mesh batch assembled off-thread: ${_.length} meshes, ${i/3} triangles`),_}function Pe(e){return Math.floor(e.length*3/4)}const $={Angstroms:1e-10,Nanometers:1e-9,Microns:1e-6,Millimeters:.001,Centimeters:.01,Decimeters:.1,Meters:1,Dekameters:10,Hectometers:100,Kilometers:1e3,Megameters:1e6,Gigameters:1e9,Microinches:2.54e-8,Mils:254e-7,Inches:.0254,Feet:.3048,Yards:.9144,Miles:1609.344,NauticalMiles:1852};function Fe(e){let t=e.split(`.`);return t.includes(`Display`)||t.includes(`DisplayBatch`)}const Ie=new Set;async function Le(e,t){let n=performance.now(),r=[],{allowScaling:i=!0,allowAutoPosition:a=!1,groundAxis:o=`z`,debug:s=!1,parsing:c={}}=t??{};try{return await ze(e,r,i?Re(e.modelunits):1,c,s),a&&Ue(r,o),r}catch(e){throw We(e,r),e}finally{s&&Ke(n)}}function Re(e){let n=$[e];return n===void 0?(Ie.has(e)||(Ie.add(e),t.p().warn(`Unknown Rhino model unit "${e}" — geometry will not be scaled (factor 1). Known units: ${Object.keys($).join(`, `)}.`)),1):n}async function ze(e,t,n,r,i){for(let a of e.values){let e=a.InnerTree;for(let a in e){let o=e[a];o&&await Be(o,t,n,r,i)}}}async function Be(e,n,r,i,a){for(let o of e){if(!Fe(o.type))continue;let e={debug:!1,...i,mergeByMaterial:i.mergeByMaterial??!0},s=Ve(o.data);if(!s){t.p().error(`Error parsing display batch envelope: invalid JSON`);continue}let c=await Oe(s,e),l=g(s.items),u=[...c,...l];if(r!==1)for(let e of u)e.scale.set(r,r,r);n.push(...u),a&&t.p().debug(`Extracted ${c.length} meshes and ${l.length} items from batch`)}}function Ve(e){return typeof e==`string`?He(e):e}function He(e){try{return JSON.parse(e)}catch{return}}function Ue(e,n){if(e.length===0)return;let r=t.a(e);t.i(e,r.min[n],n)}function We(e,n){t.p().error(`An unexpected error occurred:`,e),Ge(n)}function Ge(e){for(let t of e){let e=t;e.geometry&&e.geometry.dispose(),e.material&&(Array.isArray(e.material)?e.material.forEach(e=>e.dispose()):e.material.dispose())}}function Ke(e){let n=performance.now()-e;t.p().info(`Time to process meshes:`,`${n.toFixed(2)}ms`)}exports.SCALE_FACTORS=$,exports.getThreeObjectsFromComputeResponse=Le,exports.meshPolicy=d,exports.parseDisplayItems=g,exports.parseMeshBatchBlob=ke,exports.parseMeshBatchObject=Oe,exports.setTextureAnisotropy=q;
|
|
10
68
|
//# sourceMappingURL=parse.cjs.map
|