@voluma/vlam 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/README.md +0 -2
  2. package/dist/chunk-loader-DlNwggfG.js.map +1 -1
  3. package/dist/{index.d.ts → core/index.d.ts} +1 -1
  4. package/dist/{splat-budget.d.ts → core/splat-budget.d.ts} +1 -1
  5. package/dist/{splat-data.d.ts → core/splat-data.d.ts} +1 -1
  6. package/dist/{splat-mesh-types.d.ts → core/splat-mesh-types.d.ts} +5 -2
  7. package/dist/{effects.d.ts → effects/index.d.ts} +3 -3
  8. package/dist/effects.js.map +1 -1
  9. package/dist/formats/ksplat/parse-ksplat.d.ts +1 -1
  10. package/dist/formats/ksplat.js.map +1 -1
  11. package/dist/formats/lcc/collision-mesh.d.ts +2 -2
  12. package/dist/formats/lcc/collision-partition.d.ts +1 -1
  13. package/dist/formats/lcc/lcc.d.ts +3 -3
  14. package/dist/formats/lcc/lcc2.d.ts +2 -2
  15. package/dist/formats/lcc/parse-lcc.d.ts +1 -1
  16. package/dist/formats/lcc.js.map +1 -1
  17. package/dist/formats/ply/parse-compressed-ply.d.ts +2 -2
  18. package/dist/formats/ply/parse-splat-ply.d.ts +2 -2
  19. package/dist/formats/ply.js.map +1 -1
  20. package/dist/formats/rad/frontier-worker-protocol.d.ts +8 -1
  21. package/dist/formats/rad/index.d.ts +1 -1
  22. package/dist/formats/rad/parse-rad.d.ts +1 -1
  23. package/dist/formats/rad/rad-foveated-source.d.ts +3 -3
  24. package/dist/formats/rad/rad.d.ts +5 -5
  25. package/dist/formats/rad.js.map +1 -1
  26. package/dist/formats/sog/parse-sog.d.ts +2 -2
  27. package/dist/formats/sog.js.map +1 -1
  28. package/dist/formats/splat/parse-splat.d.ts +1 -1
  29. package/dist/formats/splat.js.map +1 -1
  30. package/dist/formats/spz/parse-spz.d.ts +1 -1
  31. package/dist/formats/spz.js.map +1 -1
  32. package/dist/half-float-Cs4FDq8Q.js.map +1 -1
  33. package/dist/index.js +3 -3
  34. package/dist/index.js.map +1 -1
  35. package/dist/{chunk-loader.d.ts → loaders/chunk-loader.d.ts} +2 -2
  36. package/dist/{load-splat-data.d.ts → loaders/load-splat-data.d.ts} +1 -1
  37. package/dist/{load-worker-protocol.d.ts → loaders/load-worker-protocol.d.ts} +2 -2
  38. package/dist/loaders.js.map +1 -1
  39. package/dist/loading-wLo8vRbA.js.map +1 -1
  40. package/dist/lod-scheduler-B0a_uBlv.js.map +1 -1
  41. package/dist/logging-BfPdd7NJ.js.map +1 -1
  42. package/dist/ply-header-B9WllbPg.js.map +1 -1
  43. package/dist/{radix-sorter-R0FCSqKu.js → radix-sorter-BrbUg_CV.js} +2 -2
  44. package/dist/radix-sorter-BrbUg_CV.js.map +1 -0
  45. package/dist/{relighting-CSQF3UcL.js → relighting-Tiwep8yd.js} +302 -294
  46. package/dist/relighting-Tiwep8yd.js.map +1 -0
  47. package/dist/{selection-volume.d.ts → selection/selection-volume.d.ts} +1 -1
  48. package/dist/{splat-partition.d.ts → selection/splat-partition.d.ts} +1 -1
  49. package/dist/selection.js.map +1 -1
  50. package/dist/sh-pack-D5wAe5gg.js.map +1 -1
  51. package/dist/splat-budget-DuVZspPQ.js.map +1 -1
  52. package/dist/splat-data-BZM5dhhx.js.map +1 -1
  53. package/dist/{splat-mesh-aQdcWA6v.js → splat-mesh-CsLOQb08.js} +3 -3
  54. package/dist/splat-mesh-CsLOQb08.js.map +1 -0
  55. package/dist/splat-mesh-types-BZIko-_9.js.map +1 -1
  56. package/dist/{static-lod-splat-mesh.d.ts → static-lod/static-lod-splat-mesh.d.ts} +2 -2
  57. package/dist/{static-lod-worker-protocol.d.ts → static-lod/static-lod-worker-protocol.d.ts} +1 -1
  58. package/dist/{static-lod.d.ts → static-lod/static-lod.d.ts} +1 -1
  59. package/dist/static-lod.js +1 -1
  60. package/dist/static-lod.js.map +1 -1
  61. package/dist/{dataset-source.d.ts → streaming/dataset-source.d.ts} +1 -1
  62. package/dist/{streaming.d.ts → streaming/index.d.ts} +3 -3
  63. package/dist/{lod-source.d.ts → streaming/lod-source.d.ts} +4 -4
  64. package/dist/{streamed-splat-mesh-utils.d.ts → streaming/streamed-splat-mesh-utils.d.ts} +2 -2
  65. package/dist/{streamed-splat-mesh.d.ts → streaming/streamed-splat-mesh.d.ts} +45 -5
  66. package/dist/streaming.js +844 -810
  67. package/dist/streaming.js.map +1 -1
  68. package/dist/{unified-splat-mesh.d.ts → unified/unified-splat-mesh.d.ts} +13 -6
  69. package/dist/{work-buffer-gather.d.ts → unified/work-buffer-gather.d.ts} +5 -5
  70. package/dist/{work-buffer-material.d.ts → unified/work-buffer-material.d.ts} +1 -1
  71. package/dist/unified.js +280 -272
  72. package/dist/unified.js.map +1 -1
  73. package/dist/webgpu-limits-Y3CI_6_6.js.map +1 -1
  74. package/package.json +9 -9
  75. package/dist/radix-sorter-R0FCSqKu.js.map +0 -1
  76. package/dist/relighting-CSQF3UcL.js.map +0 -1
  77. package/dist/splat-mesh-aQdcWA6v.js.map +0 -1
  78. /package/dist/{compute-sorter.d.ts → core/compute-sorter.d.ts} +0 -0
  79. /package/dist/{create-splat-renderer.d.ts → core/create-splat-renderer.d.ts} +0 -0
  80. /package/dist/{depth-of-field.d.ts → core/depth-of-field.d.ts} +0 -0
  81. /package/dist/{half-float.d.ts → core/half-float.d.ts} +0 -0
  82. /package/dist/{logging.d.ts → core/logging.d.ts} +0 -0
  83. /package/dist/{merged-splat-mesh.d.ts → core/merged-splat-mesh.d.ts} +0 -0
  84. /package/dist/{orientation.d.ts → core/orientation.d.ts} +0 -0
  85. /package/dist/{radix-sort.d.ts → core/radix-sort.d.ts} +0 -0
  86. /package/dist/{radix-sorter.d.ts → core/radix-sorter.d.ts} +0 -0
  87. /package/dist/{relighting-pass.d.ts → core/relighting-pass.d.ts} +0 -0
  88. /package/dist/{relighting.d.ts → core/relighting.d.ts} +0 -0
  89. /package/dist/{sh-pack.d.ts → core/sh-pack.d.ts} +0 -0
  90. /package/dist/{sort-scheduler.d.ts → core/sort-scheduler.d.ts} +0 -0
  91. /package/dist/{sort-worker-protocol.d.ts → core/sort-worker-protocol.d.ts} +0 -0
  92. /package/dist/{sorter.d.ts → core/sorter.d.ts} +0 -0
  93. /package/dist/{source-transform.d.ts → core/source-transform.d.ts} +0 -0
  94. /package/dist/{splat-depth-pack.d.ts → core/splat-depth-pack.d.ts} +0 -0
  95. /package/dist/{splat-mesh-material.d.ts → core/splat-mesh-material.d.ts} +0 -0
  96. /package/dist/{splat-mesh-picking.d.ts → core/splat-mesh-picking.d.ts} +0 -0
  97. /package/dist/{splat-mesh-pool.d.ts → core/splat-mesh-pool.d.ts} +0 -0
  98. /package/dist/{splat-mesh.d.ts → core/splat-mesh.d.ts} +0 -0
  99. /package/dist/{splat-modifier-stack.d.ts → core/splat-modifier-stack.d.ts} +0 -0
  100. /package/dist/{splat-modifier.d.ts → core/splat-modifier.d.ts} +0 -0
  101. /package/dist/{splat-query.d.ts → core/splat-query.d.ts} +0 -0
  102. /package/dist/{splat-sort-bounds.d.ts → core/splat-sort-bounds.d.ts} +0 -0
  103. /package/dist/{storage-attribute-mirror.d.ts → core/storage-attribute-mirror.d.ts} +0 -0
  104. /package/dist/{webgpu-limits.d.ts → core/webgpu-limits.d.ts} +0 -0
  105. /package/dist/{worker-sorter.d.ts → core/worker-sorter.d.ts} +0 -0
  106. /package/dist/{xr-view.d.ts → core/xr-view.d.ts} +0 -0
  107. /package/dist/{loaders.d.ts → loaders/index.d.ts} +0 -0
  108. /package/dist/{loading.d.ts → loaders/loading.d.ts} +0 -0
  109. /package/dist/{ply-header.d.ts → loaders/ply-header.d.ts} +0 -0
  110. /package/dist/{selection.d.ts → selection/index.d.ts} +0 -0
  111. /package/dist/{static-lod-entry.d.ts → static-lod/index.d.ts} +0 -0
  112. /package/dist/{budget-governor.d.ts → streaming/budget-governor.d.ts} +0 -0
  113. /package/dist/{camera-budget-governor.d.ts → streaming/camera-budget-governor.d.ts} +0 -0
  114. /package/dist/{chunk-cache-budget.d.ts → streaming/chunk-cache-budget.d.ts} +0 -0
  115. /package/dist/{chunk-fetch-scheduler.d.ts → streaming/chunk-fetch-scheduler.d.ts} +0 -0
  116. /package/dist/{lod-manifest.d.ts → streaming/lod-manifest.d.ts} +0 -0
  117. /package/dist/{lod-scheduler.d.ts → streaming/lod-scheduler.d.ts} +0 -0
  118. /package/dist/{unified.d.ts → unified/index.d.ts} +0 -0
  119. /package/dist/{unified-work-buffer.d.ts → unified/unified-work-buffer.d.ts} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"ply-header-B9WllbPg.js","sources":["../src/lib/ply-header.ts"],"sourcesContent":["/**\n * Shared PLY header reader.\n *\n * PLY is a container, not a format: the same `.ply` extension carries the\n * uncompressed \"INRIA flavor\" 3DGS export (see `parse-splat-ply.ts`) and\n * SuperSplat/PlayCanvas's compressed flavor (`parse-compressed-ply.ts`).\n * Both need the same thing first - the element list, their property layouts,\n * and where each element's records start - so that lives here.\n */\n\n/** Byte size of each scalar type PLY can declare. */\nconst PROPERTY_SIZES: Record<string, number> = {\n float: 4,\n float32: 4,\n double: 8,\n float64: 8,\n int: 4,\n int32: 4,\n uint: 4,\n uint32: 4,\n short: 2,\n int16: 2,\n ushort: 2,\n uint16: 2,\n char: 1,\n int8: 1,\n uchar: 1,\n uint8: 1,\n};\n\n/** One scalar property of an element. */\nexport interface PlyProperty {\n readonly type: string;\n /** Byte offset within one record of the element. */\n readonly offset: number;\n}\n\n/**\n * One list property (`property list <countType> <itemType> <name>`), such as a\n * mesh's `face` indices. Only the types are recorded - the data is variable-size\n * and must be walked record by record (see `parse-mesh-ply.ts`).\n */\nexport interface PlyListProperty {\n /** Type of the per-record item count, e.g. `uchar`. */\n readonly countType: string;\n /** Type of each item, e.g. `int`. */\n readonly itemType: string;\n}\n\n/** One PLY element (`element <name> <count>`) and its record layout. */\nexport interface PlyElement {\n readonly name: string;\n readonly count: number;\n readonly properties: ReadonlyMap<string, PlyProperty>;\n /** Property names in declaration order. */\n readonly propertyNames: readonly string[];\n /** List properties by name; empty unless {@link hasListProperty}. */\n readonly listProperties: ReadonlyMap<string, PlyListProperty>;\n /**\n * Bytes per record - meaningless when {@link hasListProperty}, since a list\n * makes each record's size depend on its contents.\n */\n readonly stride: number;\n /**\n * Byte offset of this element's first record within the file, or -1 when a\n * preceding element has a variable-size record and no arithmetic can find it.\n */\n readonly offset: number;\n /** A list property makes this element's records variable-size. */\n readonly hasListProperty: boolean;\n}\n\n/** A parsed PLY header. */\nexport interface PlyHeader {\n readonly elements: readonly PlyElement[];\n /** The element of that name, or undefined. */\n element(name: string): PlyElement | undefined;\n}\n\n/**\n * Reads a binary little-endian PLY header and resolves every element's byte\n * offset by walking the elements in declaration order.\n *\n * Whether the declared records actually fit in the buffer is deliberately not\n * checked here - call {@link assertPlyElementFits} once the caller has\n * validated the properties it needs, so a wrong property type is reported as\n * such rather than as the truncation it happens to imply.\n *\n * @throws {Error} if the file is not a binary little-endian PLY, or declares a\n * property type this reader cannot size.\n */\nexport function parsePlyHeader(buffer: ArrayBuffer): PlyHeader {\n const headerBytes = new Uint8Array(buffer, 0, Math.min(buffer.byteLength, 64 * 1024));\n const headerText = new TextDecoder('ascii').decode(headerBytes);\n const endMatch = /end_header\\r?\\n/.exec(headerText);\n if (!/^ply\\r?\\n/.test(headerText)) {\n throw new Error('Not a PLY file (missing \"ply\" magic).');\n }\n if (!endMatch) {\n throw new Error(\n 'Unsupported PLY file: no \"end_header\" within the first 64 KiB - the header exceeds the ' +\n 'supported window, or the file is truncated.',\n );\n }\n if (!headerText.includes('format binary_little_endian 1.0')) {\n throw new Error('Unsupported PLY format; expected binary_little_endian 1.0.');\n }\n\n interface Building {\n name: string;\n count: number;\n properties: Map<string, PlyProperty>;\n propertyNames: string[];\n listProperties: Map<string, PlyListProperty>;\n stride: number;\n hasListProperty: boolean;\n }\n const building: Building[] = [];\n\n for (const line of headerText.slice(0, endMatch.index).split('\\n')) {\n const tokens = line.trim().split(/\\s+/);\n if (tokens[0] === 'element') {\n const name = tokens[1];\n const count = Number(tokens[2]);\n if (name === undefined) throw new Error(`Malformed PLY element: \"${line.trim()}\"`);\n if (!Number.isSafeInteger(count) || count < 0) {\n throw new Error(`Invalid PLY ${name} count: ${tokens[2]}.`);\n }\n building.push({\n name,\n count,\n properties: new Map(),\n propertyNames: [],\n listProperties: new Map(),\n stride: 0,\n hasListProperty: false,\n });\n } else if (tokens[0] === 'property') {\n const element = building[building.length - 1];\n if (!element) throw new Error(`PLY property declared before any element: \"${line.trim()}\"`);\n if (tokens[1] === 'list') {\n // A list makes this element's records variable-size. That is fine for\n // the element itself (a trailing `face` list is common) - it only\n // costs later elements their computable offset. The types are recorded\n // so a reader that does want the data can walk it record by record.\n const countType = tokens[2] ?? '';\n const itemType = tokens[3] ?? '';\n const listName = tokens[4];\n if (\n PROPERTY_SIZES[countType] === undefined ||\n PROPERTY_SIZES[itemType] === undefined ||\n listName === undefined\n ) {\n throw new Error(`Unsupported PLY property: \"${line.trim()}\"`);\n }\n if (element.properties.has(listName) || element.listProperties.has(listName)) {\n throw new Error(`Duplicate PLY property \"${listName}\" in element \"${element.name}\".`);\n }\n element.listProperties.set(listName, { countType, itemType });\n element.hasListProperty = true;\n continue;\n }\n const type = tokens[1] ?? '';\n const size = PROPERTY_SIZES[type];\n const name = tokens[2];\n if (size === undefined || name === undefined) {\n throw new Error(`Unsupported PLY property: \"${line.trim()}\"`);\n }\n if (element.properties.has(name) || element.listProperties.has(name)) {\n // A duplicate name would let the later offset overwrite the earlier\n // one while the stride counts both - every read after it lands on\n // the wrong bytes.\n throw new Error(`Duplicate PLY property \"${name}\" in element \"${element.name}\".`);\n }\n element.properties.set(name, { type, offset: element.stride });\n element.propertyNames.push(name);\n element.stride += size;\n }\n }\n\n // Records are laid out back to back in element order, starting right after\n // the header - so each element begins where the previous one ended, until a\n // variable-size element makes the rest unreachable by arithmetic.\n let offset = endMatch.index + endMatch[0].length;\n let resolved = true;\n const elements: PlyElement[] = [];\n for (const element of building) {\n elements.push({\n name: element.name,\n count: element.count,\n properties: element.properties,\n propertyNames: element.propertyNames,\n listProperties: element.listProperties,\n stride: element.stride,\n offset: resolved ? offset : -1,\n hasListProperty: element.hasListProperty,\n });\n if (element.hasListProperty) resolved = false;\n else offset += element.count * element.stride;\n }\n\n return {\n elements,\n element: (name: string) => elements.find((candidate) => candidate.name === name),\n };\n}\n\n/**\n * Asserts an element's records are actually present in a file of `totalBytes`.\n *\n * Takes a size rather than a buffer so it works for a streamed parse, which\n * only ever holds a window of the file.\n *\n * @throws {Error} if the element sits behind a variable-size one, or its\n * records run past the end of the file.\n */\nexport function assertPlyElementFits(element: PlyElement, totalBytes: number): void {\n if (element.offset < 0) {\n throw new Error(\n `Unsupported PLY layout: element \"${element.name}\" follows a list property, so its ` +\n 'position cannot be determined.',\n );\n }\n const end = element.offset + element.count * element.stride;\n if (end > totalBytes) {\n throw new Error(\n `Truncated PLY file: element \"${element.name}\" needs ${end} bytes but the file is ` +\n `${totalBytes}.`,\n );\n }\n}\n\n/**\n * Byte size of a PLY scalar type.\n *\n * @throws {Error} if the type is not one PLY can declare.\n */\nexport function plyTypeSize(type: string): number {\n const size = PROPERTY_SIZES[type];\n if (size === undefined) throw new Error(`Unsupported PLY property type: \"${type}\".`);\n return size;\n}\n\n/** The byte offset of `property` within `element`'s record. */\nexport function plyPropertyOffset(element: PlyElement, property: string): number {\n const found = element.properties.get(property);\n if (!found) {\n throw new Error(`PLY element \"${element.name}\" is missing property \"${property}\".`);\n }\n return found.offset;\n}\n\n/** Asserts every named property exists on `element` with the given type. */\nexport function assertPlyPropertyTypes(\n element: PlyElement,\n properties: readonly string[],\n types: readonly string[],\n what: string,\n): void {\n for (const name of properties) {\n const property = element.properties.get(name);\n if (!property) {\n throw new Error(`${what}: missing property \"${name}\".`);\n }\n if (!types.includes(property.type)) {\n throw new Error(\n `Unsupported PLY property type for \"${name}\": expected ${types.join(' or ')}, ` +\n `got ${property.type}.`,\n );\n }\n }\n}\n"],"names":["PROPERTY_SIZES","parsePlyHeader","buffer","headerBytes","headerText","endMatch","building","line","tokens","name","count","element","countType","itemType","listName","type","size","offset","resolved","elements","candidate","assertPlyElementFits","totalBytes","end","plyTypeSize","plyPropertyOffset","property","found","assertPlyPropertyTypes","properties","types","what"],"mappings":"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"}
1
+ {"version":3,"file":"ply-header-B9WllbPg.js","sources":["../src/lib/loaders/ply-header.ts"],"sourcesContent":["/**\n * Shared PLY header reader.\n *\n * PLY is a container, not a format: the same `.ply` extension carries the\n * uncompressed \"INRIA flavor\" 3DGS export (see `parse-splat-ply.ts`) and\n * SuperSplat/PlayCanvas's compressed flavor (`parse-compressed-ply.ts`).\n * Both need the same thing first - the element list, their property layouts,\n * and where each element's records start - so that lives here.\n */\n\n/** Byte size of each scalar type PLY can declare. */\nconst PROPERTY_SIZES: Record<string, number> = {\n float: 4,\n float32: 4,\n double: 8,\n float64: 8,\n int: 4,\n int32: 4,\n uint: 4,\n uint32: 4,\n short: 2,\n int16: 2,\n ushort: 2,\n uint16: 2,\n char: 1,\n int8: 1,\n uchar: 1,\n uint8: 1,\n};\n\n/** One scalar property of an element. */\nexport interface PlyProperty {\n readonly type: string;\n /** Byte offset within one record of the element. */\n readonly offset: number;\n}\n\n/**\n * One list property (`property list <countType> <itemType> <name>`), such as a\n * mesh's `face` indices. Only the types are recorded - the data is variable-size\n * and must be walked record by record (see `parse-mesh-ply.ts`).\n */\nexport interface PlyListProperty {\n /** Type of the per-record item count, e.g. `uchar`. */\n readonly countType: string;\n /** Type of each item, e.g. `int`. */\n readonly itemType: string;\n}\n\n/** One PLY element (`element <name> <count>`) and its record layout. */\nexport interface PlyElement {\n readonly name: string;\n readonly count: number;\n readonly properties: ReadonlyMap<string, PlyProperty>;\n /** Property names in declaration order. */\n readonly propertyNames: readonly string[];\n /** List properties by name; empty unless {@link hasListProperty}. */\n readonly listProperties: ReadonlyMap<string, PlyListProperty>;\n /**\n * Bytes per record - meaningless when {@link hasListProperty}, since a list\n * makes each record's size depend on its contents.\n */\n readonly stride: number;\n /**\n * Byte offset of this element's first record within the file, or -1 when a\n * preceding element has a variable-size record and no arithmetic can find it.\n */\n readonly offset: number;\n /** A list property makes this element's records variable-size. */\n readonly hasListProperty: boolean;\n}\n\n/** A parsed PLY header. */\nexport interface PlyHeader {\n readonly elements: readonly PlyElement[];\n /** The element of that name, or undefined. */\n element(name: string): PlyElement | undefined;\n}\n\n/**\n * Reads a binary little-endian PLY header and resolves every element's byte\n * offset by walking the elements in declaration order.\n *\n * Whether the declared records actually fit in the buffer is deliberately not\n * checked here - call {@link assertPlyElementFits} once the caller has\n * validated the properties it needs, so a wrong property type is reported as\n * such rather than as the truncation it happens to imply.\n *\n * @throws {Error} if the file is not a binary little-endian PLY, or declares a\n * property type this reader cannot size.\n */\nexport function parsePlyHeader(buffer: ArrayBuffer): PlyHeader {\n const headerBytes = new Uint8Array(buffer, 0, Math.min(buffer.byteLength, 64 * 1024));\n const headerText = new TextDecoder('ascii').decode(headerBytes);\n const endMatch = /end_header\\r?\\n/.exec(headerText);\n if (!/^ply\\r?\\n/.test(headerText)) {\n throw new Error('Not a PLY file (missing \"ply\" magic).');\n }\n if (!endMatch) {\n throw new Error(\n 'Unsupported PLY file: no \"end_header\" within the first 64 KiB - the header exceeds the ' +\n 'supported window, or the file is truncated.',\n );\n }\n if (!headerText.includes('format binary_little_endian 1.0')) {\n throw new Error('Unsupported PLY format; expected binary_little_endian 1.0.');\n }\n\n interface Building {\n name: string;\n count: number;\n properties: Map<string, PlyProperty>;\n propertyNames: string[];\n listProperties: Map<string, PlyListProperty>;\n stride: number;\n hasListProperty: boolean;\n }\n const building: Building[] = [];\n\n for (const line of headerText.slice(0, endMatch.index).split('\\n')) {\n const tokens = line.trim().split(/\\s+/);\n if (tokens[0] === 'element') {\n const name = tokens[1];\n const count = Number(tokens[2]);\n if (name === undefined) throw new Error(`Malformed PLY element: \"${line.trim()}\"`);\n if (!Number.isSafeInteger(count) || count < 0) {\n throw new Error(`Invalid PLY ${name} count: ${tokens[2]}.`);\n }\n building.push({\n name,\n count,\n properties: new Map(),\n propertyNames: [],\n listProperties: new Map(),\n stride: 0,\n hasListProperty: false,\n });\n } else if (tokens[0] === 'property') {\n const element = building[building.length - 1];\n if (!element) throw new Error(`PLY property declared before any element: \"${line.trim()}\"`);\n if (tokens[1] === 'list') {\n // A list makes this element's records variable-size. That is fine for\n // the element itself (a trailing `face` list is common) - it only\n // costs later elements their computable offset. The types are recorded\n // so a reader that does want the data can walk it record by record.\n const countType = tokens[2] ?? '';\n const itemType = tokens[3] ?? '';\n const listName = tokens[4];\n if (\n PROPERTY_SIZES[countType] === undefined ||\n PROPERTY_SIZES[itemType] === undefined ||\n listName === undefined\n ) {\n throw new Error(`Unsupported PLY property: \"${line.trim()}\"`);\n }\n if (element.properties.has(listName) || element.listProperties.has(listName)) {\n throw new Error(`Duplicate PLY property \"${listName}\" in element \"${element.name}\".`);\n }\n element.listProperties.set(listName, { countType, itemType });\n element.hasListProperty = true;\n continue;\n }\n const type = tokens[1] ?? '';\n const size = PROPERTY_SIZES[type];\n const name = tokens[2];\n if (size === undefined || name === undefined) {\n throw new Error(`Unsupported PLY property: \"${line.trim()}\"`);\n }\n if (element.properties.has(name) || element.listProperties.has(name)) {\n // A duplicate name would let the later offset overwrite the earlier\n // one while the stride counts both - every read after it lands on\n // the wrong bytes.\n throw new Error(`Duplicate PLY property \"${name}\" in element \"${element.name}\".`);\n }\n element.properties.set(name, { type, offset: element.stride });\n element.propertyNames.push(name);\n element.stride += size;\n }\n }\n\n // Records are laid out back to back in element order, starting right after\n // the header - so each element begins where the previous one ended, until a\n // variable-size element makes the rest unreachable by arithmetic.\n let offset = endMatch.index + endMatch[0].length;\n let resolved = true;\n const elements: PlyElement[] = [];\n for (const element of building) {\n elements.push({\n name: element.name,\n count: element.count,\n properties: element.properties,\n propertyNames: element.propertyNames,\n listProperties: element.listProperties,\n stride: element.stride,\n offset: resolved ? offset : -1,\n hasListProperty: element.hasListProperty,\n });\n if (element.hasListProperty) resolved = false;\n else offset += element.count * element.stride;\n }\n\n return {\n elements,\n element: (name: string) => elements.find((candidate) => candidate.name === name),\n };\n}\n\n/**\n * Asserts an element's records are actually present in a file of `totalBytes`.\n *\n * Takes a size rather than a buffer so it works for a streamed parse, which\n * only ever holds a window of the file.\n *\n * @throws {Error} if the element sits behind a variable-size one, or its\n * records run past the end of the file.\n */\nexport function assertPlyElementFits(element: PlyElement, totalBytes: number): void {\n if (element.offset < 0) {\n throw new Error(\n `Unsupported PLY layout: element \"${element.name}\" follows a list property, so its ` +\n 'position cannot be determined.',\n );\n }\n const end = element.offset + element.count * element.stride;\n if (end > totalBytes) {\n throw new Error(\n `Truncated PLY file: element \"${element.name}\" needs ${end} bytes but the file is ` +\n `${totalBytes}.`,\n );\n }\n}\n\n/**\n * Byte size of a PLY scalar type.\n *\n * @throws {Error} if the type is not one PLY can declare.\n */\nexport function plyTypeSize(type: string): number {\n const size = PROPERTY_SIZES[type];\n if (size === undefined) throw new Error(`Unsupported PLY property type: \"${type}\".`);\n return size;\n}\n\n/** The byte offset of `property` within `element`'s record. */\nexport function plyPropertyOffset(element: PlyElement, property: string): number {\n const found = element.properties.get(property);\n if (!found) {\n throw new Error(`PLY element \"${element.name}\" is missing property \"${property}\".`);\n }\n return found.offset;\n}\n\n/** Asserts every named property exists on `element` with the given type. */\nexport function assertPlyPropertyTypes(\n element: PlyElement,\n properties: readonly string[],\n types: readonly string[],\n what: string,\n): void {\n for (const name of properties) {\n const property = element.properties.get(name);\n if (!property) {\n throw new Error(`${what}: missing property \"${name}\".`);\n }\n if (!types.includes(property.type)) {\n throw new Error(\n `Unsupported PLY property type for \"${name}\": expected ${types.join(' or ')}, ` +\n `got ${property.type}.`,\n );\n }\n }\n}\n"],"names":["PROPERTY_SIZES","parsePlyHeader","buffer","headerBytes","headerText","endMatch","building","line","tokens","name","count","element","countType","itemType","listName","type","size","offset","resolved","elements","candidate","assertPlyElementFits","totalBytes","end","plyTypeSize","plyPropertyOffset","property","found","assertPlyPropertyTypes","properties","types","what"],"mappings":"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"}
@@ -3,7 +3,7 @@ var Ot = (u, n, e) => n in u ? Dt(u, n, { enumerable: !0, configurable: !0, writ
3
3
  var r = (u, n, e) => Ot(u, typeof n != "symbol" ? n + "" : n, e);
4
4
  import * as h from "three/webgpu";
5
5
  import { uniform as z, storage as m, Fn as A, If as l, float as C, instanceIndex as i, ivec2 as Mt, int as G, textureLoad as Kt, floatBitsToUint as Vt, uint as t, atomicStore as D, workgroupId as tt, Loop as B, invocationLocalIndex as bt, atomicAdd as Lt, atomicLoad as I, workgroupArray as Pt, storageBarrier as H, workgroupBarrier as q, atomicOr as Wt, countOneBits as et } from "three/tsl";
6
- import { S as Xt, v as Nt, r as zt } from "./relighting-CSQF3UcL.js";
6
+ import { S as Xt, v as Nt, r as zt } from "./relighting-Tiwep8yd.js";
7
7
  const Rt = 24, Gt = 32, nt = 4, xt = (1 << Rt) - 1;
8
8
  function Ht(u) {
9
9
  if (!Number.isInteger(u) || u <= 0 || u % nt !== 0)
@@ -175,4 +175,4 @@ class jt {
175
175
  export {
176
176
  jt as RadixSorter
177
177
  };
178
- //# sourceMappingURL=radix-sorter-R0FCSqKu.js.map
178
+ //# sourceMappingURL=radix-sorter-BrbUg_CV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"radix-sorter-BrbUg_CV.js","sources":["../src/lib/core/radix-sort.ts","../src/lib/core/radix-sorter.ts"],"sourcesContent":["/**\n * @role Utility\n * Shared constants and deterministic reference logic for GPU radix sorting.\n */\n\n/** Depth precision retained by both the GPU radix path and WebGL worker path. */\nexport const RADIX_KEY_BITS = 24;\n/** Exact Float32 depth keys use every sortable IEEE-754 bit. */\nexport const RADIX_EXACT_KEY_BITS = 32;\n/** Four-bit digits keep the portable shader's workgroup memory requirements small. */\nexport const RADIX_BITS_PER_PASS = 4;\nexport const RADIX_BUCKETS = 1 << RADIX_BITS_PER_PASS;\nexport const RADIX_PASS_COUNT = RADIX_KEY_BITS / RADIX_BITS_PER_PASS;\nexport const RADIX_KEY_MAX = (1 << RADIX_KEY_BITS) - 1;\n\n/** Number of four-bit passes required for one unsigned radix key width. */\nexport function radixPassCount(keyBits: number): number {\n if (!Number.isInteger(keyBits) || keyBits <= 0 || keyBits % RADIX_BITS_PER_PASS !== 0) {\n throw new RangeError('Radix key width must be a positive multiple of four bits.');\n }\n return keyBits / RADIX_BITS_PER_PASS;\n}\n\n/**\n * Maps a Float32 bit pattern onto unsigned integer order without losing depth\n * precision. Ascending mapped keys are ascending numeric floats, including\n * negative view-space Z values (farther splats first in VLAM's convention).\n */\nexport function sortableFloat32Bits(bits: number): number {\n const value = bits >>> 0;\n return (value ^ ((value & 0x80000000) === 0 ? 0x80000000 : 0xffffffff)) >>> 0;\n}\n\n/** Quantizes a depth into the unsigned 24-bit key used by the GPU sorter. */\nexport function quantizeDepthKey(depth: number, minimum: number, maximum: number): number {\n const span = maximum - minimum;\n if (!Number.isFinite(depth) || !Number.isFinite(span) || span <= 0) return 0;\n return Math.min(\n RADIX_KEY_MAX,\n Math.max(0, Math.round(((depth - minimum) / span) * RADIX_KEY_MAX)),\n );\n}\n\n/**\n * Stable CPU reference for validating the GPU's six four-bit radix passes.\n * This is deliberately test/debug-only logic, not the WebGL production sorter.\n */\nexport function stableRadixSortReference(\n keys: Uint32Array,\n values?: Uint32Array,\n keyBits = RADIX_KEY_BITS,\n): Uint32Array {\n const count = keys.length;\n let inputKeys = Uint32Array.from(keys);\n let outputKeys = new Uint32Array(count);\n let inputValues = values ? Uint32Array.from(values) : Uint32Array.from(keys.keys());\n let outputValues = new Uint32Array(count);\n const counts = new Uint32Array(RADIX_BUCKETS);\n const offsets = new Uint32Array(RADIX_BUCKETS);\n\n for (let pass = 0; pass < radixPassCount(keyBits); pass++) {\n counts.fill(0);\n const shift = pass * RADIX_BITS_PER_PASS;\n for (let i = 0; i < count; i++) {\n const digit = ((inputKeys[i] as number) >>> shift) & 0xf;\n counts[digit] = (counts[digit] as number) + 1;\n }\n let total = 0;\n for (let digit = 0; digit < RADIX_BUCKETS; digit++) {\n offsets[digit] = total;\n total += counts[digit] as number;\n }\n for (let i = 0; i < count; i++) {\n const key = inputKeys[i] as number;\n const digit = (key >>> shift) & 0xf;\n const target = offsets[digit] as number;\n offsets[digit] = target + 1;\n outputKeys[target] = key;\n outputValues[target] = inputValues[i] as number;\n }\n [inputKeys, outputKeys] = [outputKeys, inputKeys];\n [inputValues, outputValues] = [outputValues, inputValues];\n }\n return inputValues;\n}\n","/**\n * @role Bridge\n * Portable stable WebGPU radix sorting adapted to Three.js TSL compute nodes.\n */\nimport * as THREE from 'three/webgpu';\nimport {\n Fn,\n If,\n Loop,\n atomicAdd,\n atomicLoad,\n atomicOr,\n atomicStore,\n countOneBits,\n float,\n floatBitsToUint,\n instanceIndex,\n int,\n invocationLocalIndex,\n ivec2,\n storage,\n storageBarrier,\n textureLoad,\n uint,\n uniform,\n workgroupArray,\n workgroupBarrier,\n workgroupId,\n} from 'three/tsl';\nimport type { SplatSorter } from './sorter';\nimport { releaseRendererAttributes } from './compute-sorter';\nimport {\n RADIX_BITS_PER_PASS,\n RADIX_EXACT_KEY_BITS,\n RADIX_KEY_BITS,\n RADIX_KEY_MAX,\n radixPassCount,\n} from './radix-sort';\nimport { viewDepthRadius } from './splat-sort-bounds';\nimport { StorageMirrorReleaser } from './storage-attribute-mirror';\n\nconst WORKGROUP_SIZE = 256;\nconst ELEMENTS_PER_THREAD = 8;\nconst ELEMENTS_PER_WORKGROUP = WORKGROUP_SIZE * ELEMENTS_PER_THREAD;\nconst DIGIT_COUNT = 16;\nconst MASK_WORDS_PER_DIGIT = WORKGROUP_SIZE / 32;\nconst MASK_WORDS_PER_GROUP = DIGIT_COUNT * MASK_WORDS_PER_DIGIT;\nconst SCAN_BLOCK_SIZE = 256;\n\ntype UintWorkgroupArray = {\n element(index: THREE.Node<'uint'>): THREE.Node<'uint'>;\n};\n\n/** Isolates gaps in Three's current WorkgroupInfo/Bitcount TypeScript declarations. */\nfunction asUintNode(node: unknown): THREE.Node<'uint'> {\n return node as THREE.Node<'uint'>;\n}\n\n/**\n * Stable four-bit-per-pass WebGPU radix sorter.\n *\n * The ranked scatter follows PlayCanvas/WebGPU-Radix-Sort's per-digit bitmask\n * design. Three.js does not currently expose atomic workgroup arrays in TSL,\n * so masks use disjoint global-storage slices per workgroup. Workgroup and\n * storage barriers retain the same stable ranking semantics without relying\n * on cross-workgroup execution order.\n */\nexport class RadixSorter implements SplatSorter {\n readonly kind = 'radix' as const;\n private readonly renderer: THREE.WebGPURenderer;\n private readonly stages: THREE.ComputeNode[] = [];\n private readonly workingAttributes: THREE.StorageBufferAttribute[];\n /** Frees the JS mirrors three keeps behind the GPU-only ping-pong buffers. */\n private readonly mirrors: StorageMirrorReleaser;\n /** Set by {@link dispose}; makes a second dispose a no-op. */\n private disposed = false;\n private readonly viewRow2 = uniform(new THREE.Vector4());\n private readonly depthMin = uniform(0);\n private readonly depthScale = uniform(0);\n private readonly activeCount = uniform(0);\n private readonly viewCenter = new THREE.Vector3();\n /** Exact mode avoids scene-bounds quantization entirely. */\n private readonly exactDepth: boolean;\n\n constructor(options: {\n renderer: THREE.WebGPURenderer;\n capacity: number;\n centersTexture?: THREE.DataTexture;\n dataTextureWidth?: number;\n /** Gathered world-space centers for a unified renderer. */\n centersBuffer?: THREE.StorageBufferAttribute;\n splatIndexAttribute: THREE.StorageInstancedBufferAttribute;\n sourceIndexAttribute: THREE.StorageBufferAttribute;\n /** Keep every Float32 depth bit instead of quantizing to 24 bits. */\n exactDepth?: boolean;\n }) {\n const { capacity, centersTexture, dataTextureWidth, centersBuffer } = options;\n if (!centersTexture && !centersBuffer) {\n throw new Error('RadixSorter: provide centersTexture or centersBuffer.');\n }\n if (centersTexture && dataTextureWidth === undefined) {\n throw new Error('RadixSorter: dataTextureWidth is required with centersTexture.');\n }\n this.renderer = options.renderer;\n const exactDepth = options.exactDepth === true;\n this.exactDepth = exactDepth;\n const passCount = radixPassCount(exactDepth ? RADIX_EXACT_KEY_BITS : RADIX_KEY_BITS);\n const groupCount = Math.ceil(capacity / ELEMENTS_PER_WORKGROUP);\n const histogramLength = DIGIT_COUNT * groupCount;\n const scanBlockCount = Math.ceil(histogramLength / SCAN_BLOCK_SIZE);\n\n const keysAAttribute = new THREE.StorageBufferAttribute(new Uint32Array(capacity), 1);\n const keysBAttribute = new THREE.StorageBufferAttribute(new Uint32Array(capacity), 1);\n const valuesAAttribute = new THREE.StorageBufferAttribute(new Uint32Array(capacity), 1);\n const valuesBAttribute = new THREE.StorageBufferAttribute(new Uint32Array(capacity), 1);\n const histogramAttribute = new THREE.StorageBufferAttribute(\n new Uint32Array(histogramLength),\n 1,\n );\n const scanSumsAttribute = new THREE.StorageBufferAttribute(new Uint32Array(scanBlockCount), 1);\n const masksAttribute = new THREE.StorageBufferAttribute(\n new Uint32Array(groupCount * MASK_WORDS_PER_GROUP),\n 1,\n );\n this.workingAttributes = [\n keysAAttribute,\n keysBAttribute,\n valuesAAttribute,\n valuesBAttribute,\n histogramAttribute,\n scanSumsAttribute,\n masksAttribute,\n ];\n this.mirrors = new StorageMirrorReleaser(this.workingAttributes);\n\n const keysA = storage(keysAAttribute, 'uint', capacity);\n const keysB = storage(keysBAttribute, 'uint', capacity);\n const valuesA = storage(valuesAAttribute, 'uint', capacity);\n const valuesB = storage(valuesBAttribute, 'uint', capacity);\n const source = storage(options.sourceIndexAttribute, 'uint', capacity);\n const order = storage(options.splatIndexAttribute, 'float', capacity);\n const workCenters = centersBuffer ? storage(centersBuffer, 'vec4', capacity) : null;\n const histogram = storage(histogramAttribute, 'uint', histogramLength).toAtomic();\n const scanSums = storage(scanSumsAttribute, 'uint', scanBlockCount);\n const masks = storage(masksAttribute, 'uint', groupCount * MASK_WORDS_PER_GROUP).toAtomic();\n\n const buildKeys = Fn(() => {\n If(float(instanceIndex).lessThan(this.activeCount), () => {\n const poolIndex = source.element(instanceIndex);\n const texel = centersTexture\n ? ivec2(\n int(poolIndex).mod(int(dataTextureWidth as number)),\n int(poolIndex).div(int(dataTextureWidth as number)),\n )\n : null;\n const center = workCenters\n ? workCenters.element(poolIndex).xyz\n : textureLoad(centersTexture, texel as THREE.Node<'ivec2'>).xyz;\n const depth = this.viewRow2.xyz.dot(center).add(this.viewRow2.w);\n if (exactDepth) {\n // IEEE-754 bits are monotonic only for positive values. Flip the\n // sign partition so ascending unsigned keys remain ascending numeric\n // depth, including VLAM's negative view-space Z convention.\n // Three's BitcastNode typings omit shift/xor; runtime nodes support them.\n const bits = asUintNode(floatBitsToUint(depth));\n const mask = bits\n .shiftRight(uint(31))\n .equal(uint(0))\n .select(uint(0x80000000), uint(0xffffffff));\n keysA.element(instanceIndex).assign(bits.bitXor(mask));\n } else {\n keysA\n .element(instanceIndex)\n .assign(depth.sub(this.depthMin).mul(this.depthScale).clamp(0, RADIX_KEY_MAX).toUint());\n }\n valuesA.element(instanceIndex).assign(poolIndex);\n });\n })().compute(capacity, [WORKGROUP_SIZE]);\n this.stages.push(buildKeys);\n\n for (let pass = 0; pass < passCount; pass++) {\n const inputKeys = pass % 2 === 0 ? keysA : keysB;\n const outputKeys = pass % 2 === 0 ? keysB : keysA;\n const inputValues = pass % 2 === 0 ? valuesA : valuesB;\n const outputValues = pass % 2 === 0 ? valuesB : valuesA;\n const bit = uint(pass * RADIX_BITS_PER_PASS);\n\n const clearHistogram = Fn(() => {\n atomicStore(histogram.element(instanceIndex), uint(0));\n })().compute(histogramLength, [WORKGROUP_SIZE]);\n\n const buildHistogram = Fn(() => {\n const base = workgroupId.x.mul(uint(ELEMENTS_PER_WORKGROUP));\n Loop(ELEMENTS_PER_THREAD, ({ i }) => {\n const index = base.add(uint(i).mul(uint(WORKGROUP_SIZE))).add(invocationLocalIndex);\n If(float(index).lessThan(this.activeCount), () => {\n const digit = inputKeys.element(index).shiftRight(bit).bitAnd(uint(0xf));\n atomicAdd(histogram.element(digit.mul(uint(groupCount)).add(workgroupId.x)), uint(1));\n });\n });\n })().compute(groupCount * WORKGROUP_SIZE, [WORKGROUP_SIZE]);\n\n const scanBlocks = Fn(() => {\n const start = instanceIndex.mul(uint(SCAN_BLOCK_SIZE));\n const running = uint(0).toVar();\n Loop(SCAN_BLOCK_SIZE, ({ i }) => {\n const index = start.add(uint(i));\n If(index.lessThan(uint(histogramLength)), () => {\n const value = atomicLoad(histogram.element(index)).toVar();\n atomicStore(histogram.element(index), running);\n running.addAssign(value);\n });\n });\n scanSums.element(instanceIndex).assign(running);\n })().compute(scanBlockCount, [64]);\n\n const scanBlockSums = Fn(() => {\n If(instanceIndex.equal(uint(0)), () => {\n const running = uint(0).toVar();\n Loop(scanBlockCount, ({ i }) => {\n const value = scanSums.element(i).toVar();\n scanSums.element(i).assign(running);\n running.addAssign(value);\n });\n });\n })().compute(1, [64]);\n\n const addBlockOffsets = Fn(() => {\n const block = instanceIndex.div(uint(SCAN_BLOCK_SIZE));\n atomicStore(\n histogram.element(instanceIndex),\n atomicLoad(histogram.element(instanceIndex)).add(scanSums.element(block)),\n );\n })().compute(histogramLength, [WORKGROUP_SIZE]);\n\n const digitOffsets = workgroupArray('uint', DIGIT_COUNT) as unknown as UintWorkgroupArray;\n const rankedScatter = Fn(() => {\n const thread = invocationLocalIndex;\n const group = workgroupId.x;\n const maskBase = group.mul(uint(MASK_WORDS_PER_GROUP));\n If(thread.lessThan(uint(DIGIT_COUNT)), () => {\n digitOffsets.element(thread).assign(uint(0));\n });\n If(thread.lessThan(uint(MASK_WORDS_PER_GROUP)), () => {\n atomicStore(masks.element(maskBase.add(thread)), uint(0));\n });\n storageBarrier();\n workgroupBarrier();\n\n Loop(ELEMENTS_PER_THREAD, ({ i }) => {\n const index = group\n .mul(uint(ELEMENTS_PER_WORKGROUP))\n .add(i.toUint().mul(uint(WORKGROUP_SIZE)))\n .add(thread);\n const valid = float(index).lessThan(this.activeCount);\n const key = uint(0).toVar();\n const value = uint(0).toVar();\n const digit = uint(0).toVar();\n If(valid, () => {\n key.assign(inputKeys.element(index));\n value.assign(inputValues.element(index));\n digit.assign(key.shiftRight(bit).bitAnd(uint(0xf)));\n const word = thread.shiftRight(uint(5));\n const bitInWord = thread.bitAnd(uint(31));\n const maskIndex = maskBase.add(digit.mul(uint(MASK_WORDS_PER_DIGIT))).add(word);\n atomicOr(masks.element(maskIndex), uint(1).shiftLeft(bitInWord));\n });\n storageBarrier();\n workgroupBarrier();\n\n If(valid, () => {\n const word = thread.shiftRight(uint(5));\n const bitInWord = thread.bitAnd(uint(31));\n const digitBase = maskBase.add(digit.mul(uint(MASK_WORDS_PER_DIGIT)));\n const localRank = digitOffsets.element(digit).toVar();\n Loop(MASK_WORDS_PER_DIGIT, ({ i: wordIndex }) => {\n If(uint(wordIndex).lessThan(word), () => {\n localRank.addAssign(\n asUintNode(\n countOneBits(atomicLoad(masks.element(digitBase.add(wordIndex.toUint())))),\n ),\n );\n });\n });\n const precedingMask = uint(1).shiftLeft(bitInWord).sub(uint(1));\n localRank.addAssign(\n asUintNode(\n countOneBits(atomicLoad(masks.element(digitBase.add(word))).bitAnd(precedingMask)),\n ),\n );\n const prefix = atomicLoad(histogram.element(digit.mul(uint(groupCount)).add(group)));\n const target = prefix.add(localRank);\n outputKeys.element(target).assign(key);\n outputValues.element(target).assign(value);\n });\n\n storageBarrier();\n workgroupBarrier();\n If(thread.lessThan(uint(DIGIT_COUNT)), () => {\n const total = uint(0).toVar();\n Loop(MASK_WORDS_PER_DIGIT, ({ i: wordIndex }) => {\n const maskIndex = maskBase\n .add(thread.mul(uint(MASK_WORDS_PER_DIGIT)))\n .add(wordIndex.toUint());\n total.addAssign(asUintNode(countOneBits(atomicLoad(masks.element(maskIndex)))));\n atomicStore(masks.element(maskIndex), uint(0));\n });\n digitOffsets.element(thread).addAssign(total);\n });\n storageBarrier();\n workgroupBarrier();\n });\n })().compute(groupCount * WORKGROUP_SIZE, [WORKGROUP_SIZE]);\n\n this.stages.push(\n clearHistogram,\n buildHistogram,\n scanBlocks,\n scanBlockSums,\n addBlockOffsets,\n rankedScatter,\n );\n }\n\n const writeOrder = Fn(() => {\n If(float(instanceIndex).lessThan(this.activeCount), () => {\n order.element(instanceIndex).assign(float(valuesA.element(instanceIndex)));\n });\n })().compute(capacity, [WORKGROUP_SIZE]);\n this.stages.push(writeOrder);\n }\n\n sort(modelView: THREE.Matrix4, activeCount: number, bounds: THREE.Sphere): boolean {\n if (activeCount === 0) return true;\n const m = modelView.elements;\n this.viewRow2.value.set(m[2], m[6], m[10], m[14]);\n this.activeCount.value = activeCount;\n if (!this.exactDepth) {\n this.viewCenter.copy(bounds.center).applyMatrix4(modelView);\n const viewRadius = viewDepthRadius(modelView, bounds.radius);\n const minimum = this.viewCenter.z - viewRadius;\n const maximum = this.viewCenter.z + viewRadius;\n this.depthMin.value = minimum;\n this.depthScale.value = RADIX_KEY_MAX / (maximum - minimum || 1);\n }\n this.stages[0]!.count = activeCount;\n this.stages[this.stages.length - 1]!.count = activeCount;\n this.renderer.compute(this.stages);\n // Key/value ping-pong, histogram, scan sums and masks are all written and\n // read entirely on the GPU - at 4 B per splat of capacity each, their JS\n // mirrors are ~16 B/splat of pure waste. Deliberately *not*\n // `sourceIndex`/`splatIndex`: those belong to the mesh and are rewritten\n // from the CPU every frame. Same ownership line as `releaseRendererAttributes`.\n if (!this.mirrors.settled) this.mirrors.release(this.renderer);\n return true;\n }\n\n dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n for (const stage of this.stages) stage.dispose();\n releaseRendererAttributes(this.renderer, this.workingAttributes);\n }\n}\n"],"names":["RADIX_KEY_BITS","RADIX_EXACT_KEY_BITS","RADIX_BITS_PER_PASS","RADIX_KEY_MAX","radixPassCount","keyBits","WORKGROUP_SIZE","ELEMENTS_PER_THREAD","ELEMENTS_PER_WORKGROUP","DIGIT_COUNT","MASK_WORDS_PER_DIGIT","MASK_WORDS_PER_GROUP","SCAN_BLOCK_SIZE","RadixSorter","options","__publicField","uniform","THREE","capacity","centersTexture","dataTextureWidth","centersBuffer","exactDepth","passCount","groupCount","histogramLength","scanBlockCount","keysAAttribute","keysBAttribute","valuesAAttribute","valuesBAttribute","histogramAttribute","scanSumsAttribute","masksAttribute","StorageMirrorReleaser","keysA","storage","keysB","valuesA","valuesB","source","order","workCenters","histogram","scanSums","masks","buildKeys","Fn","If","float","instanceIndex","poolIndex","texel","ivec2","int","center","textureLoad","depth","bits","floatBitsToUint","mask","uint","pass","inputKeys","outputKeys","inputValues","outputValues","bit","clearHistogram","atomicStore","buildHistogram","base","workgroupId","Loop","i","index","invocationLocalIndex","digit","atomicAdd","scanBlocks","start","running","value","atomicLoad","scanBlockSums","addBlockOffsets","block","digitOffsets","workgroupArray","rankedScatter","thread","group","maskBase","storageBarrier","workgroupBarrier","valid","key","word","bitInWord","maskIndex","atomicOr","digitBase","localRank","wordIndex","countOneBits","precedingMask","target","total","writeOrder","modelView","activeCount","bounds","m","viewRadius","viewDepthRadius","minimum","maximum","stage","releaseRendererAttributes"],"mappings":";;;;;;AAMO,MAAMA,KAAiB,IAEjBC,KAAuB,IAEvBC,KAAsB,GAGtBC,MAAiB,KAAKH,MAAkB;AAG9C,SAASI,GAAeC,GAAyB;AACtD,MAAI,CAAC,OAAO,UAAUA,CAAO,KAAKA,KAAW,KAAKA,IAAUH,OAAwB;AAClF,UAAM,IAAI,WAAW,2DAA2D;AAElF,SAAOG,IAAUH;AACnB;ACoBA,MAAMI,IAAiB,KACjBC,KAAsB,GACtBC,KAAyBF,IAAiBC,IAC1CE,IAAc,IACdC,IAAuBJ,IAAiB,IACxCK,IAAuBF,IAAcC,GACrCE,IAAkB;AAoBjB,MAAMC,GAAmC;AAAA,EAiB9C,YAAYC,GAWT;AA3BM,IAAAC,EAAA,cAAO;AACC,IAAAA,EAAA;AACA,IAAAA,EAAA,gBAA8B,CAAA;AAC9B,IAAAA,EAAA;AAEA;AAAA,IAAAA,EAAA;AAET;AAAA,IAAAA,EAAA,kBAAW;AACF,IAAAA,EAAA,kBAAWC,EAAQ,IAAIC,EAAM,SAAS;AACtC,IAAAF,EAAA,kBAAWC,EAAQ,CAAC;AACpB,IAAAD,EAAA,oBAAaC,EAAQ,CAAC;AACtB,IAAAD,EAAA,qBAAcC,EAAQ,CAAC;AACvB,IAAAD,EAAA,oBAAa,IAAIE,EAAM,QAAA;AAEvB;AAAA,IAAAF,EAAA;AAcf,UAAM,EAAE,UAAAG,GAAU,gBAAAC,GAAgB,kBAAAC,GAAkB,eAAAC,MAAkBP;AACtE,QAAI,CAACK,KAAkB,CAACE;AACtB,YAAM,IAAI,MAAM,uDAAuD;AAEzE,QAAIF,KAAkBC,MAAqB;AACzC,YAAM,IAAI,MAAM,gEAAgE;AAElF,SAAK,WAAWN,EAAQ;AACxB,UAAMQ,IAAaR,EAAQ,eAAe;AAC1C,SAAK,aAAaQ;AAClB,UAAMC,IAAYnB,GAAekB,IAAarB,KAAuBD,EAAc,GAC7EwB,IAAa,KAAK,KAAKN,IAAWV,EAAsB,GACxDiB,IAAkBhB,IAAce,GAChCE,IAAiB,KAAK,KAAKD,IAAkBb,CAAe,GAE5De,KAAiB,IAAIV,EAAM,uBAAuB,IAAI,YAAYC,CAAQ,GAAG,CAAC,GAC9EU,KAAiB,IAAIX,EAAM,uBAAuB,IAAI,YAAYC,CAAQ,GAAG,CAAC,GAC9EW,KAAmB,IAAIZ,EAAM,uBAAuB,IAAI,YAAYC,CAAQ,GAAG,CAAC,GAChFY,KAAmB,IAAIb,EAAM,uBAAuB,IAAI,YAAYC,CAAQ,GAAG,CAAC,GAChFa,KAAqB,IAAId,EAAM;AAAA,MACnC,IAAI,YAAYQ,CAAe;AAAA,MAC/B;AAAA,IAAA,GAEIO,KAAoB,IAAIf,EAAM,uBAAuB,IAAI,YAAYS,CAAc,GAAG,CAAC,GACvFO,KAAiB,IAAIhB,EAAM;AAAA,MAC/B,IAAI,YAAYO,IAAab,CAAoB;AAAA,MACjD;AAAA,IAAA;AAEF,SAAK,oBAAoB;AAAA,MACvBgB;AAAA,MACAC;AAAA,MACAC;AAAA,MACAC;AAAA,MACAC;AAAA,MACAC;AAAA,MACAC;AAAA,IAAA,GAEF,KAAK,UAAU,IAAIC,GAAsB,KAAK,iBAAiB;AAE/D,UAAMC,IAAQC,EAAQT,IAAgB,QAAQT,CAAQ,GAChDmB,KAAQD,EAAQR,IAAgB,QAAQV,CAAQ,GAChDoB,IAAUF,EAAQP,IAAkB,QAAQX,CAAQ,GACpDqB,KAAUH,EAAQN,IAAkB,QAAQZ,CAAQ,GACpDsB,KAASJ,EAAQtB,EAAQ,sBAAsB,QAAQI,CAAQ,GAC/DuB,KAAQL,EAAQtB,EAAQ,qBAAqB,SAASI,CAAQ,GAC9DwB,KAAcrB,IAAgBe,EAAQf,GAAe,QAAQH,CAAQ,IAAI,MACzEyB,IAAYP,EAAQL,IAAoB,QAAQN,CAAe,EAAE,SAAA,GACjEmB,IAAWR,EAAQJ,IAAmB,QAAQN,CAAc,GAC5DmB,IAAQT,EAAQH,IAAgB,QAAQT,IAAab,CAAoB,EAAE,SAAA,GAE3EmC,KAAYC,EAAG,MAAM;AACzB,MAAAC,EAAGC,EAAMC,CAAa,EAAE,SAAS,KAAK,WAAW,GAAG,MAAM;AACxD,cAAMC,IAAYX,GAAO,QAAQU,CAAa,GACxCE,IAAQjC,IACVkC;AAAA,UACEC,EAAIH,CAAS,EAAE,IAAIG,EAAIlC,CAA0B,CAAC;AAAA,UAClDkC,EAAIH,CAAS,EAAE,IAAIG,EAAIlC,CAA0B,CAAC;AAAA,QAAA,IAEpD,MACEmC,IAASb,KACXA,GAAY,QAAQS,CAAS,EAAE,MAC/BK,GAAYrC,GAAgBiC,CAA4B,EAAE,KACxDK,IAAQ,KAAK,SAAS,IAAI,IAAIF,CAAM,EAAE,IAAI,KAAK,SAAS,CAAC;AAC/D,YAAIjC,GAAY;AAKd,gBAAMoC,IAAkBC,GAAgBF,CAAK,GACvCG,IAAOF,EACV,WAAWG,EAAK,EAAE,CAAC,EACnB,MAAMA,EAAK,CAAC,CAAC,EACb,OAAOA,EAAK,UAAU,GAAGA,EAAK,UAAU,CAAC;AAC5C,UAAA1B,EAAM,QAAQe,CAAa,EAAE,OAAOQ,EAAK,OAAOE,CAAI,CAAC;AAAA,QACvD;AACE,UAAAzB,EACG,QAAQe,CAAa,EACrB,OAAOO,EAAM,IAAI,KAAK,QAAQ,EAAE,IAAI,KAAK,UAAU,EAAE,MAAM,GAAGtD,EAAa,EAAE,QAAQ;AAE1F,QAAAmC,EAAQ,QAAQY,CAAa,EAAE,OAAOC,CAAS;AAAA,MACjD,CAAC;AAAA,IACH,CAAC,EAAA,EAAI,QAAQjC,GAAU,CAACZ,CAAc,CAAC;AACvC,SAAK,OAAO,KAAKwC,EAAS;AAE1B,aAASgB,IAAO,GAAGA,IAAOvC,GAAWuC,KAAQ;AAC3C,YAAMC,IAAYD,IAAO,MAAM,IAAI3B,IAAQE,IACrC2B,IAAaF,IAAO,MAAM,IAAIzB,KAAQF,GACtC8B,IAAcH,IAAO,MAAM,IAAIxB,IAAUC,IACzC2B,IAAeJ,IAAO,MAAM,IAAIvB,KAAUD,GAC1C6B,IAAMN,EAAKC,IAAO5D,EAAmB,GAErCkE,KAAiBrB,EAAG,MAAM;AAC9B,QAAAsB,EAAY1B,EAAU,QAAQO,CAAa,GAAGW,EAAK,CAAC,CAAC;AAAA,MACvD,CAAC,EAAA,EAAI,QAAQpC,GAAiB,CAACnB,CAAc,CAAC,GAExCgE,KAAiBvB,EAAG,MAAM;AAC9B,cAAMwB,IAAOC,GAAY,EAAE,IAAIX,EAAKrD,EAAsB,CAAC;AAC3D,QAAAiE,EAAKlE,IAAqB,CAAC,EAAE,GAAAmE,QAAQ;AACnC,gBAAMC,IAAQJ,EAAK,IAAIV,EAAKa,CAAC,EAAE,IAAIb,EAAKvD,CAAc,CAAC,CAAC,EAAE,IAAIsE,EAAoB;AAClF,UAAA5B,EAAGC,EAAM0B,CAAK,EAAE,SAAS,KAAK,WAAW,GAAG,MAAM;AAChD,kBAAME,IAAQd,EAAU,QAAQY,CAAK,EAAE,WAAWR,CAAG,EAAE,OAAON,EAAK,EAAG,CAAC;AACvE,YAAAiB,GAAUnC,EAAU,QAAQkC,EAAM,IAAIhB,EAAKrC,CAAU,CAAC,EAAE,IAAIgD,GAAY,CAAC,CAAC,GAAGX,EAAK,CAAC,CAAC;AAAA,UACtF,CAAC;AAAA,QACH,CAAC;AAAA,MACH,CAAC,IAAI,QAAQrC,IAAalB,GAAgB,CAACA,CAAc,CAAC,GAEpDyE,KAAahC,EAAG,MAAM;AAC1B,cAAMiC,IAAQ9B,EAAc,IAAIW,EAAKjD,CAAe,CAAC,GAC/CqE,IAAUpB,EAAK,CAAC,EAAE,MAAA;AACxB,QAAAY,EAAK7D,GAAiB,CAAC,EAAE,GAAA8D,QAAQ;AAC/B,gBAAMC,IAAQK,EAAM,IAAInB,EAAKa,CAAC,CAAC;AAC/B,UAAA1B,EAAG2B,EAAM,SAASd,EAAKpC,CAAe,CAAC,GAAG,MAAM;AAC9C,kBAAMyD,IAAQC,EAAWxC,EAAU,QAAQgC,CAAK,CAAC,EAAE,MAAA;AACnD,YAAAN,EAAY1B,EAAU,QAAQgC,CAAK,GAAGM,CAAO,GAC7CA,EAAQ,UAAUC,CAAK;AAAA,UACzB,CAAC;AAAA,QACH,CAAC,GACDtC,EAAS,QAAQM,CAAa,EAAE,OAAO+B,CAAO;AAAA,MAChD,CAAC,EAAA,EAAI,QAAQvD,GAAgB,CAAC,EAAE,CAAC,GAE3B0D,KAAgBrC,EAAG,MAAM;AAC7B,QAAAC,EAAGE,EAAc,MAAMW,EAAK,CAAC,CAAC,GAAG,MAAM;AACrC,gBAAMoB,IAAUpB,EAAK,CAAC,EAAE,MAAA;AACxB,UAAAY,EAAK/C,GAAgB,CAAC,EAAE,GAAAgD,QAAQ;AAC9B,kBAAMQ,IAAQtC,EAAS,QAAQ8B,CAAC,EAAE,MAAA;AAClC,YAAA9B,EAAS,QAAQ8B,CAAC,EAAE,OAAOO,CAAO,GAClCA,EAAQ,UAAUC,CAAK;AAAA,UACzB,CAAC;AAAA,QACH,CAAC;AAAA,MACH,CAAC,EAAA,EAAI,QAAQ,GAAG,CAAC,EAAE,CAAC,GAEdG,KAAkBtC,EAAG,MAAM;AAC/B,cAAMuC,IAAQpC,EAAc,IAAIW,EAAKjD,CAAe,CAAC;AACrD,QAAAyD;AAAA,UACE1B,EAAU,QAAQO,CAAa;AAAA,UAC/BiC,EAAWxC,EAAU,QAAQO,CAAa,CAAC,EAAE,IAAIN,EAAS,QAAQ0C,CAAK,CAAC;AAAA,QAAA;AAAA,MAE5E,CAAC,EAAA,EAAI,QAAQ7D,GAAiB,CAACnB,CAAc,CAAC,GAExCiF,IAAeC,GAAe,QAAQ/E,CAAW,GACjDgF,KAAgB1C,EAAG,MAAM;AAC7B,cAAM2C,IAASd,IACTe,IAAQnB,GAAY,GACpBoB,IAAWD,EAAM,IAAI9B,EAAKlD,CAAoB,CAAC;AACrD,QAAAqC,EAAG0C,EAAO,SAAS7B,EAAKpD,CAAW,CAAC,GAAG,MAAM;AAC3C,UAAA8E,EAAa,QAAQG,CAAM,EAAE,OAAO7B,EAAK,CAAC,CAAC;AAAA,QAC7C,CAAC,GACDb,EAAG0C,EAAO,SAAS7B,EAAKlD,CAAoB,CAAC,GAAG,MAAM;AACpD,UAAA0D,EAAYxB,EAAM,QAAQ+C,EAAS,IAAIF,CAAM,CAAC,GAAG7B,EAAK,CAAC,CAAC;AAAA,QAC1D,CAAC,GACDgC,EAAA,GACAC,EAAA,GAEArB,EAAKlE,IAAqB,CAAC,EAAE,GAAAmE,QAAQ;AACnC,gBAAMC,IAAQgB,EACX,IAAI9B,EAAKrD,EAAsB,CAAC,EAChC,IAAIkE,EAAE,OAAA,EAAS,IAAIb,EAAKvD,CAAc,CAAC,CAAC,EACxC,IAAIoF,CAAM,GACPK,KAAQ9C,EAAM0B,CAAK,EAAE,SAAS,KAAK,WAAW,GAC9CqB,IAAMnC,EAAK,CAAC,EAAE,MAAA,GACdqB,KAAQrB,EAAK,CAAC,EAAE,MAAA,GAChBgB,IAAQhB,EAAK,CAAC,EAAE,MAAA;AACtB,UAAAb,EAAG+C,IAAO,MAAM;AACd,YAAAC,EAAI,OAAOjC,EAAU,QAAQY,CAAK,CAAC,GACnCO,GAAM,OAAOjB,EAAY,QAAQU,CAAK,CAAC,GACvCE,EAAM,OAAOmB,EAAI,WAAW7B,CAAG,EAAE,OAAON,EAAK,EAAG,CAAC,CAAC;AAClD,kBAAMoC,IAAOP,EAAO,WAAW7B,EAAK,CAAC,CAAC,GAChCqC,IAAYR,EAAO,OAAO7B,EAAK,EAAE,CAAC,GAClCsC,IAAYP,EAAS,IAAIf,EAAM,IAAIhB,EAAKnD,CAAoB,CAAC,CAAC,EAAE,IAAIuF,CAAI;AAC9E,YAAAG,GAASvD,EAAM,QAAQsD,CAAS,GAAGtC,EAAK,CAAC,EAAE,UAAUqC,CAAS,CAAC;AAAA,UACjE,CAAC,GACDL,EAAA,GACAC,EAAA,GAEA9C,EAAG+C,IAAO,MAAM;AACd,kBAAME,IAAOP,EAAO,WAAW7B,EAAK,CAAC,CAAC,GAChCqC,IAAYR,EAAO,OAAO7B,EAAK,EAAE,CAAC,GAClCwC,IAAYT,EAAS,IAAIf,EAAM,IAAIhB,EAAKnD,CAAoB,CAAC,CAAC,GAC9D4F,IAAYf,EAAa,QAAQV,CAAK,EAAE,MAAA;AAC9C,YAAAJ,EAAK/D,GAAsB,CAAC,EAAE,GAAG6F,SAAgB;AAC/C,cAAAvD,EAAGa,EAAK0C,EAAS,EAAE,SAASN,CAAI,GAAG,MAAM;AACvC,gBAAAK,EAAU;AAAA,kBAENE,GAAarB,EAAWtC,EAAM,QAAQwD,EAAU,IAAIE,GAAU,OAAA,CAAQ,CAAC,CAAC,CAAC;AAAA,gBAC3E;AAAA,cAEJ,CAAC;AAAA,YACH,CAAC;AACD,kBAAME,KAAgB5C,EAAK,CAAC,EAAE,UAAUqC,CAAS,EAAE,IAAIrC,EAAK,CAAC,CAAC;AAC9D,YAAAyC,EAAU;AAAA,cAENE,GAAarB,EAAWtC,EAAM,QAAQwD,EAAU,IAAIJ,CAAI,CAAC,CAAC,EAAE,OAAOQ,EAAa,CAAC;AAAA,YACnF;AAGF,kBAAMC,KADSvB,EAAWxC,EAAU,QAAQkC,EAAM,IAAIhB,EAAKrC,CAAU,CAAC,EAAE,IAAImE,CAAK,CAAC,CAAC,EAC7D,IAAIW,CAAS;AACnC,YAAAtC,EAAW,QAAQ0C,EAAM,EAAE,OAAOV,CAAG,GACrC9B,EAAa,QAAQwC,EAAM,EAAE,OAAOxB,EAAK;AAAA,UAC3C,CAAC,GAEDW,EAAA,GACAC,EAAA,GACA9C,EAAG0C,EAAO,SAAS7B,EAAKpD,CAAW,CAAC,GAAG,MAAM;AAC3C,kBAAMkG,IAAQ9C,EAAK,CAAC,EAAE,MAAA;AACtB,YAAAY,EAAK/D,GAAsB,CAAC,EAAE,GAAG6F,QAAgB;AAC/C,oBAAMJ,IAAYP,EACf,IAAIF,EAAO,IAAI7B,EAAKnD,CAAoB,CAAC,CAAC,EAC1C,IAAI6F,EAAU,QAAQ;AACzB,cAAAI,EAAM,UAAqBH,GAAarB,EAAWtC,EAAM,QAAQsD,CAAS,CAAC,CAAC,CAAE,GAC9E9B,EAAYxB,EAAM,QAAQsD,CAAS,GAAGtC,EAAK,CAAC,CAAC;AAAA,YAC/C,CAAC,GACD0B,EAAa,QAAQG,CAAM,EAAE,UAAUiB,CAAK;AAAA,UAC9C,CAAC,GACDd,EAAA,GACAC,EAAA;AAAA,QACF,CAAC;AAAA,MACH,CAAC,IAAI,QAAQtE,IAAalB,GAAgB,CAACA,CAAc,CAAC;AAE1D,WAAK,OAAO;AAAA,QACV8D;AAAA,QACAE;AAAA,QACAS;AAAA,QACAK;AAAA,QACAC;AAAA,QACAI;AAAA,MAAA;AAAA,IAEJ;AAEA,UAAMmB,KAAa7D,EAAG,MAAM;AAC1B,MAAAC,EAAGC,EAAMC,CAAa,EAAE,SAAS,KAAK,WAAW,GAAG,MAAM;AACxD,QAAAT,GAAM,QAAQS,CAAa,EAAE,OAAOD,EAAMX,EAAQ,QAAQY,CAAa,CAAC,CAAC;AAAA,MAC3E,CAAC;AAAA,IACH,CAAC,EAAA,EAAI,QAAQhC,GAAU,CAACZ,CAAc,CAAC;AACvC,SAAK,OAAO,KAAKsG,EAAU;AAAA,EAC7B;AAAA,EAEA,KAAKC,GAA0BC,GAAqBC,GAA+B;AACjF,QAAID,MAAgB,EAAG,QAAO;AAC9B,UAAME,IAAIH,EAAU;AAGpB,QAFA,KAAK,SAAS,MAAM,IAAIG,EAAE,CAAC,GAAGA,EAAE,CAAC,GAAGA,EAAE,EAAE,GAAGA,EAAE,EAAE,CAAC,GAChD,KAAK,YAAY,QAAQF,GACrB,CAAC,KAAK,YAAY;AACpB,WAAK,WAAW,KAAKC,EAAO,MAAM,EAAE,aAAaF,CAAS;AAC1D,YAAMI,IAAaC,GAAgBL,GAAWE,EAAO,MAAM,GACrDI,IAAU,KAAK,WAAW,IAAIF,GAC9BG,IAAU,KAAK,WAAW,IAAIH;AACpC,WAAK,SAAS,QAAQE,GACtB,KAAK,WAAW,QAAQhH,MAAiBiH,IAAUD,KAAW;AAAA,IAChE;AACA,gBAAK,OAAO,CAAC,EAAG,QAAQL,GACxB,KAAK,OAAO,KAAK,OAAO,SAAS,CAAC,EAAG,QAAQA,GAC7C,KAAK,SAAS,QAAQ,KAAK,MAAM,GAM5B,KAAK,QAAQ,gBAAc,QAAQ,QAAQ,KAAK,QAAQ,GACtD;AAAA,EACT;AAAA,EAEA,UAAgB;AACd,QAAI,MAAK,UACT;AAAA,WAAK,WAAW;AAChB,iBAAWO,KAAS,KAAK,OAAQ,CAAAA,EAAM,QAAA;AACvC,MAAAC,GAA0B,KAAK,UAAU,KAAK,iBAAiB;AAAA;AAAA,EACjE;AACF;"}