sdl-mcp 0.12.2 → 0.12.3

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 (276) hide show
  1. package/README.md +10 -0
  2. package/config/sdlmcp.config.example.json +53 -8
  3. package/config/sdlmcp.config.schema.json +530 -106
  4. package/dist/.tsbuildinfo +1 -1
  5. package/dist/benchmark/external-manifest.d.ts +162 -0
  6. package/dist/benchmark/external-manifest.d.ts.map +1 -0
  7. package/dist/benchmark/external-manifest.js +336 -0
  8. package/dist/benchmark/external-manifest.js.map +1 -0
  9. package/dist/benchmark/external-runner.d.ts +100 -0
  10. package/dist/benchmark/external-runner.d.ts.map +1 -0
  11. package/dist/benchmark/external-runner.js +1171 -0
  12. package/dist/benchmark/external-runner.js.map +1 -0
  13. package/dist/benchmark/output-file.d.ts +3 -0
  14. package/dist/benchmark/output-file.d.ts.map +1 -0
  15. package/dist/benchmark/output-file.js +8 -0
  16. package/dist/benchmark/output-file.js.map +1 -0
  17. package/dist/cli/argParsing.d.ts.map +1 -1
  18. package/dist/cli/argParsing.js +6 -0
  19. package/dist/cli/argParsing.js.map +1 -1
  20. package/dist/cli/commands/benchmark.d.ts.map +1 -1
  21. package/dist/cli/commands/benchmark.js +3 -2
  22. package/dist/cli/commands/benchmark.js.map +1 -1
  23. package/dist/cli/commands/index.d.ts +1 -0
  24. package/dist/cli/commands/index.d.ts.map +1 -1
  25. package/dist/cli/commands/index.js +13 -7
  26. package/dist/cli/commands/index.js.map +1 -1
  27. package/dist/cli/commands/init.d.ts +5 -1
  28. package/dist/cli/commands/init.d.ts.map +1 -1
  29. package/dist/cli/commands/init.js +73 -3
  30. package/dist/cli/commands/init.js.map +1 -1
  31. package/dist/cli/commands/serve.d.ts.map +1 -1
  32. package/dist/cli/commands/serve.js +2 -0
  33. package/dist/cli/commands/serve.js.map +1 -1
  34. package/dist/cli/index.js +2 -0
  35. package/dist/cli/index.js.map +1 -1
  36. package/dist/cli/transport/http.d.ts +1 -35
  37. package/dist/cli/transport/http.d.ts.map +1 -1
  38. package/dist/cli/transport/http.js +151 -175
  39. package/dist/cli/transport/http.js.map +1 -1
  40. package/dist/cli/types.d.ts +1 -0
  41. package/dist/cli/types.d.ts.map +1 -1
  42. package/dist/config/constants.d.ts +30 -0
  43. package/dist/config/constants.d.ts.map +1 -1
  44. package/dist/config/constants.js +30 -0
  45. package/dist/config/constants.js.map +1 -1
  46. package/dist/config/types.d.ts +53 -1
  47. package/dist/config/types.d.ts.map +1 -1
  48. package/dist/config/types.js +62 -14
  49. package/dist/config/types.js.map +1 -1
  50. package/dist/db/ladybug-batching.d.ts +1 -0
  51. package/dist/db/ladybug-batching.d.ts.map +1 -1
  52. package/dist/db/ladybug-batching.js +1 -0
  53. package/dist/db/ladybug-batching.js.map +1 -1
  54. package/dist/db/ladybug-core.d.ts +3 -0
  55. package/dist/db/ladybug-core.d.ts.map +1 -1
  56. package/dist/db/ladybug-core.js +72 -2
  57. package/dist/db/ladybug-core.js.map +1 -1
  58. package/dist/db/ladybug-embeddings.d.ts +6 -1
  59. package/dist/db/ladybug-embeddings.d.ts.map +1 -1
  60. package/dist/db/ladybug-embeddings.js +6 -1
  61. package/dist/db/ladybug-embeddings.js.map +1 -1
  62. package/dist/db/ladybug-file-summaries.d.ts.map +1 -1
  63. package/dist/db/ladybug-file-summaries.js +23 -0
  64. package/dist/db/ladybug-file-summaries.js.map +1 -1
  65. package/dist/db/ladybug-queries.js +1 -1
  66. package/dist/db/ladybug-queries.js.map +1 -1
  67. package/dist/db/migrations/index.d.ts.map +1 -1
  68. package/dist/db/migrations/index.js +2 -0
  69. package/dist/db/migrations/index.js.map +1 -1
  70. package/dist/db/migrations/m007-copy-embeddings-to-symbol.d.ts +5 -9
  71. package/dist/db/migrations/m007-copy-embeddings-to-symbol.d.ts.map +1 -1
  72. package/dist/db/migrations/m007-copy-embeddings-to-symbol.js +24 -126
  73. package/dist/db/migrations/m007-copy-embeddings-to-symbol.js.map +1 -1
  74. package/dist/db/migrations/m021-remediate-symbol-embeddings.d.ts +5 -0
  75. package/dist/db/migrations/m021-remediate-symbol-embeddings.d.ts.map +1 -0
  76. package/dist/db/migrations/m021-remediate-symbol-embeddings.js +7 -0
  77. package/dist/db/migrations/m021-remediate-symbol-embeddings.js.map +1 -0
  78. package/dist/db/migrations/symbol-embedding-remediation.d.ts +57 -0
  79. package/dist/db/migrations/symbol-embedding-remediation.d.ts.map +1 -0
  80. package/dist/db/migrations/symbol-embedding-remediation.js +335 -0
  81. package/dist/db/migrations/symbol-embedding-remediation.js.map +1 -0
  82. package/dist/graph/layout/force-layout.d.ts +4 -0
  83. package/dist/graph/layout/force-layout.d.ts.map +1 -0
  84. package/dist/graph/layout/force-layout.js +127 -0
  85. package/dist/graph/layout/force-layout.js.map +1 -0
  86. package/dist/graph/layout/layout-service.d.ts +37 -0
  87. package/dist/graph/layout/layout-service.d.ts.map +1 -0
  88. package/dist/graph/layout/layout-service.js +172 -0
  89. package/dist/graph/layout/layout-service.js.map +1 -0
  90. package/dist/graph/layout/native-engine.d.ts +9 -0
  91. package/dist/graph/layout/native-engine.d.ts.map +1 -0
  92. package/dist/graph/layout/native-engine.js +59 -0
  93. package/dist/graph/layout/native-engine.js.map +1 -0
  94. package/dist/graph/layout/prng.d.ts +3 -0
  95. package/dist/graph/layout/prng.d.ts.map +1 -0
  96. package/dist/graph/layout/prng.js +19 -0
  97. package/dist/graph/layout/prng.js.map +1 -0
  98. package/dist/graph/layout/serializer.d.ts +3 -0
  99. package/dist/graph/layout/serializer.d.ts.map +1 -0
  100. package/dist/graph/layout/serializer.js +20 -0
  101. package/dist/graph/layout/serializer.js.map +1 -0
  102. package/dist/graph/layout/types.d.ts +30 -0
  103. package/dist/graph/layout/types.d.ts.map +1 -0
  104. package/dist/graph/layout/types.js +2 -0
  105. package/dist/graph/layout/types.js.map +1 -0
  106. package/dist/indexer/embeddings.d.ts +7 -0
  107. package/dist/indexer/embeddings.d.ts.map +1 -1
  108. package/dist/indexer/embeddings.js +44 -4
  109. package/dist/indexer/embeddings.js.map +1 -1
  110. package/dist/indexer/file-summary-embeddings.d.ts +12 -0
  111. package/dist/indexer/file-summary-embeddings.d.ts.map +1 -1
  112. package/dist/indexer/file-summary-embeddings.js +83 -21
  113. package/dist/indexer/file-summary-embeddings.js.map +1 -1
  114. package/dist/indexer/fileWalker.d.ts.map +1 -1
  115. package/dist/indexer/fileWalker.js +2 -1
  116. package/dist/indexer/fileWalker.js.map +1 -1
  117. package/dist/indexer/metrics-updater.d.ts.map +1 -1
  118. package/dist/indexer/metrics-updater.js +27 -4
  119. package/dist/indexer/metrics-updater.js.map +1 -1
  120. package/dist/indexer/watcher.d.ts.map +1 -1
  121. package/dist/indexer/watcher.js +2 -1
  122. package/dist/indexer/watcher.js.map +1 -1
  123. package/dist/mcp/context-response-projection.d.ts.map +1 -1
  124. package/dist/mcp/context-response-projection.js +49 -13
  125. package/dist/mcp/context-response-projection.js.map +1 -1
  126. package/dist/mcp/tools/search-edit/planner.d.ts.map +1 -1
  127. package/dist/mcp/tools/search-edit/planner.js +10 -3
  128. package/dist/mcp/tools/search-edit/planner.js.map +1 -1
  129. package/dist/observability/event-tap.d.ts +2 -1
  130. package/dist/observability/event-tap.d.ts.map +1 -1
  131. package/dist/observability/event-tap.js.map +1 -1
  132. package/dist/observability/service.d.ts +11 -4
  133. package/dist/observability/service.d.ts.map +1 -1
  134. package/dist/observability/service.js +83 -13
  135. package/dist/observability/service.js.map +1 -1
  136. package/dist/observability/types.d.ts +48 -2
  137. package/dist/observability/types.d.ts.map +1 -1
  138. package/dist/ui/.tsbuildinfo +1 -0
  139. package/dist/ui/vendor/fflate.js +2692 -0
  140. package/dist/ui/vendor/jsm/controls/ArcballControls.js +3543 -0
  141. package/dist/ui/vendor/jsm/controls/DragControls.js +452 -0
  142. package/dist/ui/vendor/jsm/controls/FirstPersonControls.js +488 -0
  143. package/dist/ui/vendor/jsm/controls/FlyControls.js +384 -0
  144. package/dist/ui/vendor/jsm/controls/MapControls.js +116 -0
  145. package/dist/ui/vendor/jsm/controls/OrbitControls.js +1963 -0
  146. package/dist/ui/vendor/jsm/controls/PointerLockControls.js +264 -0
  147. package/dist/ui/vendor/jsm/controls/TrackballControls.js +1001 -0
  148. package/dist/ui/vendor/jsm/controls/TransformControls.js +2003 -0
  149. package/dist/ui/vendor/jsm/loaders/3DMLoader.js +1836 -0
  150. package/dist/ui/vendor/jsm/loaders/3MFLoader.js +1621 -0
  151. package/dist/ui/vendor/jsm/loaders/AMFLoader.js +541 -0
  152. package/dist/ui/vendor/jsm/loaders/BVHLoader.js +484 -0
  153. package/dist/ui/vendor/jsm/loaders/ColladaLoader.js +153 -0
  154. package/dist/ui/vendor/jsm/loaders/DDSLoader.js +385 -0
  155. package/dist/ui/vendor/jsm/loaders/DRACOLoader.js +772 -0
  156. package/dist/ui/vendor/jsm/loaders/EXRLoader.js +3395 -0
  157. package/dist/ui/vendor/jsm/loaders/FBXLoader.js +4580 -0
  158. package/dist/ui/vendor/jsm/loaders/FontLoader.js +260 -0
  159. package/dist/ui/vendor/jsm/loaders/GCodeLoader.js +318 -0
  160. package/dist/ui/vendor/jsm/loaders/GLTFLoader.js +4860 -0
  161. package/dist/ui/vendor/jsm/loaders/HDRCubeTextureLoader.js +164 -0
  162. package/dist/ui/vendor/jsm/loaders/HDRLoader.js +463 -0
  163. package/dist/ui/vendor/jsm/loaders/IESLoader.js +379 -0
  164. package/dist/ui/vendor/jsm/loaders/KMZLoader.js +163 -0
  165. package/dist/ui/vendor/jsm/loaders/KTX2Loader.js +1276 -0
  166. package/dist/ui/vendor/jsm/loaders/KTXLoader.js +197 -0
  167. package/dist/ui/vendor/jsm/loaders/LDrawLoader.js +2510 -0
  168. package/dist/ui/vendor/jsm/loaders/LUT3dlLoader.js +205 -0
  169. package/dist/ui/vendor/jsm/loaders/LUTCubeLoader.js +190 -0
  170. package/dist/ui/vendor/jsm/loaders/LUTImageLoader.js +190 -0
  171. package/dist/ui/vendor/jsm/loaders/LWOLoader.js +1051 -0
  172. package/dist/ui/vendor/jsm/loaders/LottieLoader.js +130 -0
  173. package/dist/ui/vendor/jsm/loaders/MD2Loader.js +435 -0
  174. package/dist/ui/vendor/jsm/loaders/MDDLoader.js +147 -0
  175. package/dist/ui/vendor/jsm/loaders/MTLLoader.js +593 -0
  176. package/dist/ui/vendor/jsm/loaders/MaterialXLoader.js +1126 -0
  177. package/dist/ui/vendor/jsm/loaders/NRRDLoader.js +718 -0
  178. package/dist/ui/vendor/jsm/loaders/OBJLoader.js +955 -0
  179. package/dist/ui/vendor/jsm/loaders/PCDLoader.js +620 -0
  180. package/dist/ui/vendor/jsm/loaders/PDBLoader.js +272 -0
  181. package/dist/ui/vendor/jsm/loaders/PLYLoader.js +968 -0
  182. package/dist/ui/vendor/jsm/loaders/PVRLoader.js +270 -0
  183. package/dist/ui/vendor/jsm/loaders/RGBELoader.js +18 -0
  184. package/dist/ui/vendor/jsm/loaders/STLLoader.js +421 -0
  185. package/dist/ui/vendor/jsm/loaders/SVGLoader.js +3319 -0
  186. package/dist/ui/vendor/jsm/loaders/TDSLoader.js +1142 -0
  187. package/dist/ui/vendor/jsm/loaders/TGALoader.js +538 -0
  188. package/dist/ui/vendor/jsm/loaders/TIFFLoader.js +59 -0
  189. package/dist/ui/vendor/jsm/loaders/TTFLoader.js +261 -0
  190. package/dist/ui/vendor/jsm/loaders/USDLoader.js +303 -0
  191. package/dist/ui/vendor/jsm/loaders/USDZLoader.js +16 -0
  192. package/dist/ui/vendor/jsm/loaders/UltraHDRLoader.js +755 -0
  193. package/dist/ui/vendor/jsm/loaders/VOXLoader.js +919 -0
  194. package/dist/ui/vendor/jsm/loaders/VRMLLoader.js +3646 -0
  195. package/dist/ui/vendor/jsm/loaders/VTKLoader.js +1293 -0
  196. package/dist/ui/vendor/jsm/loaders/XYZLoader.js +143 -0
  197. package/dist/ui/vendor/jsm/loaders/collada/ColladaComposer.js +3044 -0
  198. package/dist/ui/vendor/jsm/loaders/collada/ColladaParser.js +1977 -0
  199. package/dist/ui/vendor/jsm/loaders/lwo/IFFParser.js +1217 -0
  200. package/dist/ui/vendor/jsm/loaders/lwo/LWO2Parser.js +414 -0
  201. package/dist/ui/vendor/jsm/loaders/lwo/LWO3Parser.js +373 -0
  202. package/dist/ui/vendor/jsm/loaders/usd/USDAParser.js +901 -0
  203. package/dist/ui/vendor/jsm/loaders/usd/USDCParser.js +1878 -0
  204. package/dist/ui/vendor/jsm/loaders/usd/USDComposer.js +4627 -0
  205. package/dist/ui/vendor/jsm/utils/BufferGeometryUtils.js +1501 -0
  206. package/dist/ui/vendor/jsm/utils/CameraUtils.js +82 -0
  207. package/dist/ui/vendor/jsm/utils/ColorUtils.js +76 -0
  208. package/dist/ui/vendor/jsm/utils/GeometryCompressionUtils.js +547 -0
  209. package/dist/ui/vendor/jsm/utils/GeometryUtils.js +226 -0
  210. package/dist/ui/vendor/jsm/utils/LDrawUtils.js +211 -0
  211. package/dist/ui/vendor/jsm/utils/SceneOptimizer.js +458 -0
  212. package/dist/ui/vendor/jsm/utils/SceneUtils.js +363 -0
  213. package/dist/ui/vendor/jsm/utils/ShadowMapViewer.js +244 -0
  214. package/dist/ui/vendor/jsm/utils/ShadowMapViewerGPU.js +233 -0
  215. package/dist/ui/vendor/jsm/utils/SkeletonUtils.js +496 -0
  216. package/dist/ui/vendor/jsm/utils/SortUtils.js +175 -0
  217. package/dist/ui/vendor/jsm/utils/UVsDebug.js +173 -0
  218. package/dist/ui/vendor/jsm/utils/WebGLTextureUtils.js +115 -0
  219. package/dist/ui/vendor/jsm/utils/WebGPUTextureUtils.js +81 -0
  220. package/dist/ui/vendor/jsm/utils/WorkerPool.js +167 -0
  221. package/dist/ui/vendor/three.core.min.js +6 -0
  222. package/dist/ui/vendor/three.module.min.js +6 -0
  223. package/dist/ui/viewer/ambient.js +39 -0
  224. package/dist/ui/viewer/api.js +93 -0
  225. package/dist/ui/viewer/chrome.js +36 -0
  226. package/dist/ui/viewer/edges.js +33 -0
  227. package/dist/ui/viewer/index.html +32 -0
  228. package/dist/ui/viewer/inspector.js +23 -0
  229. package/dist/ui/viewer/lenses/activity.js +24 -0
  230. package/dist/ui/viewer/lenses/community.js +5 -0
  231. package/dist/ui/viewer/lenses/edges.js +4 -0
  232. package/dist/ui/viewer/lenses/impact.js +6 -0
  233. package/dist/ui/viewer/lenses/search.js +69 -0
  234. package/dist/ui/viewer/lod.js +100 -0
  235. package/dist/ui/viewer/main.js +92 -0
  236. package/dist/ui/viewer/picking.js +45 -0
  237. package/dist/ui/viewer/scene.js +85 -0
  238. package/dist/ui/viewer/skins/default-skin.js +15 -0
  239. package/dist/ui/viewer/skins/loader.js +44 -0
  240. package/dist/ui/viewer/skins/manifest-schema.js +30 -0
  241. package/dist/ui/viewer/state.js +44 -0
  242. package/dist/ui/viewer/theme.js +23 -0
  243. package/dist/ui/viewer/universe.js +151 -0
  244. package/dist/ui/viewer/viewer.css +85 -0
  245. package/dist/util/safeRegex.d.ts.map +1 -1
  246. package/dist/util/safeRegex.js +221 -68
  247. package/dist/util/safeRegex.js.map +1 -1
  248. package/dist/viewer/legacy-graph.d.ts +40 -0
  249. package/dist/viewer/legacy-graph.d.ts.map +1 -0
  250. package/dist/viewer/legacy-graph.js +152 -0
  251. package/dist/viewer/legacy-graph.js.map +1 -0
  252. package/dist/viewer/routes.d.ts +10 -0
  253. package/dist/viewer/routes.d.ts.map +1 -0
  254. package/dist/viewer/routes.js +221 -0
  255. package/dist/viewer/routes.js.map +1 -0
  256. package/dist/viewer/service.d.ts +44 -0
  257. package/dist/viewer/service.d.ts.map +1 -0
  258. package/dist/viewer/service.js +160 -0
  259. package/dist/viewer/service.js.map +1 -0
  260. package/dist/viewer/types.d.ts +63 -0
  261. package/dist/viewer/types.d.ts.map +1 -0
  262. package/dist/viewer/types.js +2 -0
  263. package/dist/viewer/types.js.map +1 -0
  264. package/dist/viewer/viewer-config.d.ts +12 -0
  265. package/dist/viewer/viewer-config.d.ts.map +1 -0
  266. package/dist/viewer/viewer-config.js +36 -0
  267. package/dist/viewer/viewer-config.js.map +1 -0
  268. package/package.json +18 -9
  269. package/templates/SDL.md +19 -0
  270. package/templates/claude-code.json +8 -43
  271. package/dist/ui/graph.css +0 -108
  272. package/dist/ui/graph.d.ts +0 -2
  273. package/dist/ui/graph.d.ts.map +0 -1
  274. package/dist/ui/graph.html +0 -52
  275. package/dist/ui/graph.js +0 -259
  276. package/dist/ui/graph.js.map +0 -1
@@ -0,0 +1,755 @@
1
+ import {
2
+ ClampToEdgeWrapping,
3
+ DataTexture,
4
+ DataUtils,
5
+ FileLoader,
6
+ HalfFloatType,
7
+ LinearFilter,
8
+ LinearMipMapLinearFilter,
9
+ LinearSRGBColorSpace,
10
+ Loader,
11
+ RGBAFormat,
12
+ UVMapping,
13
+ } from 'three';
14
+
15
+ /**
16
+ * UltraHDR Image Format - https://developer.android.com/media/platform/hdr-image-format
17
+ *
18
+ * Short format brief:
19
+ *
20
+ * [JPEG headers]
21
+ * [Metadata describing the MPF container and both SDR and gainmap images]
22
+ * - XMP metadata (legacy format)
23
+ * - ISO 21496-1 metadata (current standard)
24
+ * [Optional metadata] [EXIF] [ICC Profile]
25
+ * [SDR image]
26
+ * [Gainmap image with metadata]
27
+ *
28
+ * Each section is separated by a 0xFFXX byte followed by a descriptor byte (0xFFE0, 0xFFE1, 0xFFE2.)
29
+ * Binary image storages are prefixed with a unique 0xFFD8 16-bit descriptor.
30
+ */
31
+
32
+
33
+ // Pre-calculated sRGB to linear lookup table for values 0-1023
34
+ const SRGB_TO_LINEAR = new Float64Array( 1024 );
35
+ for ( let i = 0; i < 1024; i ++ ) {
36
+
37
+ // (1/255) * 0.9478672986 = 0.003717127
38
+ SRGB_TO_LINEAR[ i ] = Math.pow( i * 0.003717127 + 0.0521327014, 2.4 );
39
+
40
+ }
41
+
42
+ /**
43
+ * A loader for the Ultra HDR Image Format.
44
+ *
45
+ * Existing HDR or EXR textures can be converted to Ultra HDR with this [tool](https://gainmap-creator.monogrid.com/).
46
+ *
47
+ * Current feature set:
48
+ * - JPEG headers (required)
49
+ * - XMP metadata (legacy format, supported)
50
+ * - ISO 21496-1 metadata (current standard, supported)
51
+ * - XMP validation (not implemented)
52
+ * - EXIF profile (not implemented)
53
+ * - ICC profile (not implemented)
54
+ * - Binary storage for SDR & HDR images (required)
55
+ * - Gainmap metadata (required)
56
+ * - Non-JPEG image formats (not implemented)
57
+ * - Primary image as an HDR image (not implemented)
58
+ *
59
+ * ```js
60
+ * const loader = new UltraHDRLoader();
61
+ * const texture = await loader.loadAsync( 'textures/equirectangular/ice_planet_close.jpg' );
62
+ * texture.mapping = THREE.EquirectangularReflectionMapping;
63
+ *
64
+ * scene.background = texture;
65
+ * scene.environment = texture;
66
+ * ```
67
+ *
68
+ * @augments Loader
69
+ * @three_import import { UltraHDRLoader } from 'three/addons/loaders/UltraHDRLoader.js';
70
+ */
71
+ class UltraHDRLoader extends Loader {
72
+
73
+ /**
74
+ * Constructs a new Ultra HDR loader.
75
+ *
76
+ * @param {LoadingManager} [manager] - The loading manager.
77
+ */
78
+ constructor( manager ) {
79
+
80
+ super( manager );
81
+
82
+ /**
83
+ * The texture type.
84
+ *
85
+ * @type {(HalfFloatType|FloatType)}
86
+ * @default HalfFloatType
87
+ */
88
+ this.type = HalfFloatType;
89
+
90
+ }
91
+
92
+ /**
93
+ * Sets the texture type.
94
+ *
95
+ * @param {(HalfFloatType|FloatType)} value - The texture type to set.
96
+ * @return {UltraHDRLoader} A reference to this loader.
97
+ */
98
+ setDataType( value ) {
99
+
100
+ this.type = value;
101
+
102
+ return this;
103
+
104
+ }
105
+
106
+ /**
107
+ * Parses the given Ultra HDR texture data.
108
+ *
109
+ * @param {ArrayBuffer} buffer - The raw texture data.
110
+ * @param {Function} onLoad - The `onLoad` callback.
111
+ */
112
+ parse( buffer, onLoad ) {
113
+
114
+ const metadata = {
115
+ version: null,
116
+ baseRenditionIsHDR: null,
117
+ gainMapMin: null,
118
+ gainMapMax: null,
119
+ gamma: null,
120
+ offsetSDR: null,
121
+ offsetHDR: null,
122
+ hdrCapacityMin: null,
123
+ hdrCapacityMax: null,
124
+ };
125
+ const textDecoder = new TextDecoder();
126
+
127
+ const bytes = new Uint8Array( buffer );
128
+
129
+ const sections = [];
130
+
131
+ // JPEG segment-aware scanner using length headers
132
+ let offset = 0;
133
+
134
+ while ( offset < bytes.length - 1 ) {
135
+
136
+ // Find marker prefix
137
+ if ( bytes[ offset ] !== 0xff ) {
138
+
139
+ offset ++;
140
+ continue;
141
+
142
+ }
143
+
144
+ const markerType = bytes[ offset + 1 ];
145
+
146
+ // SOI (0xD8) - Start of Image, no length field
147
+ if ( markerType === 0xd8 ) {
148
+
149
+ sections.push( {
150
+ sectionType: markerType,
151
+ section: bytes.subarray( offset, offset + 2 ),
152
+ sectionOffset: offset + 2,
153
+ } );
154
+
155
+ offset += 2;
156
+ continue;
157
+
158
+ }
159
+
160
+ // APP0-APP2 segments have length headers
161
+ if ( markerType === 0xe0 || markerType === 0xe1 || markerType === 0xe2 ) {
162
+
163
+ // Length is stored as big-endian 16-bit value (includes length bytes, excludes marker)
164
+ const segmentLength = ( bytes[ offset + 2 ] << 8 ) | bytes[ offset + 3 ];
165
+ const segmentEnd = offset + 2 + segmentLength;
166
+
167
+ sections.push( {
168
+ sectionType: markerType,
169
+ section: bytes.subarray( offset, segmentEnd ),
170
+ sectionOffset: offset + 2,
171
+ } );
172
+
173
+ offset = segmentEnd;
174
+ continue;
175
+
176
+ }
177
+
178
+ // Skip other markers with length fields (0xC0-0xFE range, except RST and EOI)
179
+ if ( markerType >= 0xc0 && markerType <= 0xfe && markerType !== 0xd9 && ( markerType < 0xd0 || markerType > 0xd7 ) ) {
180
+
181
+ const segmentLength = ( bytes[ offset + 2 ] << 8 ) | bytes[ offset + 3 ];
182
+ offset += 2 + segmentLength;
183
+ continue;
184
+
185
+ }
186
+
187
+ // EOI (0xD9) or RST markers (0xD0-0xD7) - no length field
188
+ offset += 2;
189
+
190
+ }
191
+
192
+ let primaryImage, gainmapImage;
193
+
194
+ for ( let i = 0; i < sections.length; i ++ ) {
195
+
196
+ const { sectionType, section, sectionOffset } = sections[ i ];
197
+
198
+ if ( sectionType === 0xe0 ) {
199
+ /* JPEG Header - no useful information */
200
+ } else if ( sectionType === 0xe1 ) {
201
+
202
+ /* APP1: XMP Metadata */
203
+
204
+ this._parseXMPMetadata(
205
+ textDecoder.decode( new Uint8Array( section ) ),
206
+ metadata
207
+ );
208
+
209
+ } else if ( sectionType === 0xe2 ) {
210
+
211
+ /* APP2: Data Sections - MPF / ICC Profile / ISO 21496-1 Metadata */
212
+
213
+ const sectionData = new DataView( section.buffer, section.byteOffset + 2, section.byteLength - 2 );
214
+
215
+ // Check for ISO 21496-1 namespace: "urn:iso:std:iso:ts:21496:-1\0"
216
+ const isoNameSpace = 'urn:iso:std:iso:ts:21496:-1\0';
217
+ if ( section.byteLength >= isoNameSpace.length + 2 ) {
218
+
219
+ let isISO = true;
220
+ for ( let j = 0; j < isoNameSpace.length; j ++ ) {
221
+
222
+ if ( section[ 2 + j ] !== isoNameSpace.charCodeAt( j ) ) {
223
+
224
+ isISO = false;
225
+ break;
226
+
227
+ }
228
+
229
+ }
230
+
231
+ if ( isISO ) {
232
+
233
+ // Parse ISO 21496-1 metadata
234
+ const isoData = section.subarray( 2 + isoNameSpace.length );
235
+ this._parseISOMetadata( isoData, metadata );
236
+ continue;
237
+
238
+ }
239
+
240
+ }
241
+
242
+ // Check for MPF
243
+ const sectionHeader = sectionData.getUint32( 2, false );
244
+
245
+ if ( sectionHeader === 0x4d504600 ) {
246
+
247
+ /* MPF Section */
248
+
249
+ /* Section contains a list of static bytes and ends with offsets indicating location of SDR and gainmap images */
250
+ /* First bytes after header indicate little / big endian ordering (0x49492A00 - LE / 0x4D4D002A - BE) */
251
+ /*
252
+ ... 60 bytes indicating tags, versions, etc. ...
253
+
254
+ bytes | bits | description
255
+
256
+ 4 32 primary image size
257
+ 4 32 primary image offset
258
+ 2 16 0x0000
259
+ 2 16 0x0000
260
+
261
+ 4 32 0x00000000
262
+ 4 32 gainmap image size
263
+ 4 32 gainmap image offset
264
+ 2 16 0x0000
265
+ 2 16 0x0000
266
+ */
267
+
268
+ const mpfLittleEndian = sectionData.getUint32( 6 ) === 0x49492a00;
269
+ const mpfBytesOffset = 60;
270
+
271
+ /* SDR size includes the metadata length, SDR offset is always 0 */
272
+
273
+ const primaryImageSize = sectionData.getUint32(
274
+ mpfBytesOffset,
275
+ mpfLittleEndian
276
+ );
277
+ const primaryImageOffset = sectionData.getUint32(
278
+ mpfBytesOffset + 4,
279
+ mpfLittleEndian
280
+ );
281
+
282
+ /* Gainmap size is an absolute value starting from its offset, gainmap offset needs 6 bytes padding to take into account 0x00 bytes at the end of XMP */
283
+ const gainmapImageSize = sectionData.getUint32(
284
+ mpfBytesOffset + 16,
285
+ mpfLittleEndian
286
+ );
287
+ const gainmapImageOffset =
288
+ sectionData.getUint32( mpfBytesOffset + 20, mpfLittleEndian ) +
289
+ sectionOffset +
290
+ 6;
291
+
292
+ primaryImage = new Uint8Array(
293
+ buffer,
294
+ primaryImageOffset,
295
+ primaryImageSize
296
+ );
297
+
298
+ gainmapImage = new Uint8Array(
299
+ buffer,
300
+ gainmapImageOffset,
301
+ gainmapImageSize
302
+ );
303
+
304
+ }
305
+
306
+ }
307
+
308
+ }
309
+
310
+ /* Minimal sufficient validation - https://developer.android.com/media/platform/hdr-image-format#signal_of_the_format */
311
+ // Version can come from either XMP or ISO metadata
312
+ if ( ! metadata.version ) {
313
+
314
+ throw new Error( 'THREE.UltraHDRLoader: Not a valid UltraHDR image' );
315
+
316
+ }
317
+
318
+ if ( primaryImage && gainmapImage ) {
319
+
320
+ this._applyGainmapToSDR(
321
+ metadata,
322
+ primaryImage,
323
+ gainmapImage,
324
+ ( hdrBuffer, width, height ) => {
325
+
326
+ onLoad( {
327
+ width,
328
+ height,
329
+ data: hdrBuffer,
330
+ format: RGBAFormat,
331
+ type: this.type,
332
+ } );
333
+
334
+ },
335
+ ( error ) => {
336
+
337
+ throw new Error( error );
338
+
339
+ }
340
+ );
341
+
342
+ } else {
343
+
344
+ throw new Error( 'THREE.UltraHDRLoader: Could not parse UltraHDR images' );
345
+
346
+ }
347
+
348
+ }
349
+
350
+ /**
351
+ * Parses ISO 21496-1 gainmap metadata from binary data.
352
+ *
353
+ * @private
354
+ * @param {Uint8Array} data - The binary ISO metadata.
355
+ * @param {Object} metadata - The metadata object to populate.
356
+ */
357
+ _parseISOMetadata( data, metadata ) {
358
+
359
+ const view = new DataView( data.buffer, data.byteOffset, data.byteLength );
360
+
361
+ // Skip minimum version (2 bytes) and writer version (2 bytes)
362
+ let offset = 4;
363
+
364
+ // Read flags (1 byte)
365
+ const flags = view.getUint8( offset );
366
+ offset += 1;
367
+
368
+ const backwardDirection = ( flags & 0x4 ) !== 0;
369
+ const useCommonDenominator = ( flags & 0x8 ) !== 0;
370
+
371
+ let gainMapMin, gainMapMax, gamma, offsetSDR, offsetHDR, hdrCapacityMin, hdrCapacityMax;
372
+
373
+ if ( useCommonDenominator ) {
374
+
375
+ // Read common denominator (4 bytes, unsigned)
376
+ const commonDenominator = view.getUint32( offset, false );
377
+ offset += 4;
378
+
379
+ // Read baseHdrHeadroom (4 bytes, unsigned)
380
+ const baseHdrHeadroomN = view.getUint32( offset, false );
381
+ offset += 4;
382
+ hdrCapacityMin = Math.log2( baseHdrHeadroomN / commonDenominator );
383
+
384
+ // Read alternateHdrHeadroom (4 bytes, unsigned)
385
+ const alternateHdrHeadroomN = view.getUint32( offset, false );
386
+ offset += 4;
387
+ hdrCapacityMax = Math.log2( alternateHdrHeadroomN / commonDenominator );
388
+
389
+ // Read first channel (or only channel) parameters
390
+ const gainMapMinN = view.getInt32( offset, false );
391
+ offset += 4;
392
+ gainMapMin = gainMapMinN / commonDenominator;
393
+
394
+ const gainMapMaxN = view.getInt32( offset, false );
395
+ offset += 4;
396
+ gainMapMax = gainMapMaxN / commonDenominator;
397
+
398
+ const gammaN = view.getUint32( offset, false );
399
+ offset += 4;
400
+ gamma = gammaN / commonDenominator;
401
+
402
+ const offsetSDRN = view.getInt32( offset, false );
403
+ offset += 4;
404
+ offsetSDR = ( offsetSDRN / commonDenominator ) * 255.0;
405
+
406
+ const offsetHDRN = view.getInt32( offset, false );
407
+ offsetHDR = ( offsetHDRN / commonDenominator ) * 255.0;
408
+
409
+ } else {
410
+
411
+ // Read baseHdrHeadroom numerator and denominator
412
+ const baseHdrHeadroomN = view.getUint32( offset, false );
413
+ offset += 4;
414
+ const baseHdrHeadroomD = view.getUint32( offset, false );
415
+ offset += 4;
416
+ hdrCapacityMin = Math.log2( baseHdrHeadroomN / baseHdrHeadroomD );
417
+
418
+ // Read alternateHdrHeadroom numerator and denominator
419
+ const alternateHdrHeadroomN = view.getUint32( offset, false );
420
+ offset += 4;
421
+ const alternateHdrHeadroomD = view.getUint32( offset, false );
422
+ offset += 4;
423
+ hdrCapacityMax = Math.log2( alternateHdrHeadroomN / alternateHdrHeadroomD );
424
+
425
+ // Read first channel parameters
426
+ const gainMapMinN = view.getInt32( offset, false );
427
+ offset += 4;
428
+ const gainMapMinD = view.getUint32( offset, false );
429
+ offset += 4;
430
+ gainMapMin = gainMapMinN / gainMapMinD;
431
+
432
+ const gainMapMaxN = view.getInt32( offset, false );
433
+ offset += 4;
434
+ const gainMapMaxD = view.getUint32( offset, false );
435
+ offset += 4;
436
+ gainMapMax = gainMapMaxN / gainMapMaxD;
437
+
438
+ const gammaN = view.getUint32( offset, false );
439
+ offset += 4;
440
+ const gammaD = view.getUint32( offset, false );
441
+ offset += 4;
442
+ gamma = gammaN / gammaD;
443
+
444
+ const offsetSDRN = view.getInt32( offset, false );
445
+ offset += 4;
446
+ const offsetSDRD = view.getUint32( offset, false );
447
+ offset += 4;
448
+ offsetSDR = ( offsetSDRN / offsetSDRD ) * 255.0;
449
+
450
+ const offsetHDRN = view.getInt32( offset, false );
451
+ offset += 4;
452
+ const offsetHDRD = view.getUint32( offset, false );
453
+ offsetHDR = ( offsetHDRN / offsetHDRD ) * 255.0;
454
+
455
+ }
456
+
457
+ // Convert log2 values to linear
458
+ metadata.version = '1.0'; // ISO standard doesn't encode version string, use default
459
+ metadata.baseRenditionIsHDR = backwardDirection;
460
+ metadata.gainMapMin = gainMapMin;
461
+ metadata.gainMapMax = gainMapMax;
462
+ metadata.gamma = gamma;
463
+ metadata.offsetSDR = offsetSDR;
464
+ metadata.offsetHDR = offsetHDR;
465
+ metadata.hdrCapacityMin = hdrCapacityMin;
466
+ metadata.hdrCapacityMax = hdrCapacityMax;
467
+
468
+ }
469
+
470
+ /**
471
+ * Starts loading from the given URL and passes the loaded Ultra HDR texture
472
+ * to the `onLoad()` callback.
473
+ *
474
+ * @param {string} url - The path/URL of the files to be loaded. This can also be a data URI.
475
+ * @param {function(DataTexture, Object)} onLoad - Executed when the loading process has been finished.
476
+ * @param {onProgressCallback} onProgress - Executed while the loading is in progress.
477
+ * @param {onErrorCallback} onError - Executed when errors occur.
478
+ * @return {DataTexture} The Ultra HDR texture.
479
+ */
480
+ load( url, onLoad, onProgress, onError ) {
481
+
482
+ const texture = new DataTexture(
483
+ this.type === HalfFloatType ? new Uint16Array() : new Float32Array(),
484
+ 0,
485
+ 0,
486
+ RGBAFormat,
487
+ this.type,
488
+ UVMapping,
489
+ ClampToEdgeWrapping,
490
+ ClampToEdgeWrapping,
491
+ LinearFilter,
492
+ LinearMipMapLinearFilter,
493
+ 1,
494
+ LinearSRGBColorSpace
495
+ );
496
+ texture.generateMipmaps = true;
497
+ texture.flipY = true;
498
+
499
+ const loader = new FileLoader( this.manager );
500
+ loader.setResponseType( 'arraybuffer' );
501
+ loader.setRequestHeader( this.requestHeader );
502
+ loader.setPath( this.path );
503
+ loader.setWithCredentials( this.withCredentials );
504
+ loader.load( url, ( buffer ) => {
505
+
506
+ try {
507
+
508
+ this.parse(
509
+ buffer,
510
+ ( texData ) => {
511
+
512
+ texture.image = {
513
+ data: texData.data,
514
+ width: texData.width,
515
+ height: texData.height,
516
+ };
517
+ texture.needsUpdate = true;
518
+
519
+ if ( onLoad ) onLoad( texture, texData );
520
+
521
+ }
522
+ );
523
+
524
+ } catch ( error ) {
525
+
526
+ if ( onError ) onError( error );
527
+
528
+ console.error( error );
529
+
530
+ }
531
+
532
+ }, onProgress, onError );
533
+
534
+ return texture;
535
+
536
+ }
537
+
538
+ _parseXMPMetadata( xmpDataString, metadata ) {
539
+
540
+ const domParser = new DOMParser();
541
+
542
+ const xmpXml = domParser.parseFromString(
543
+ xmpDataString.substring(
544
+ xmpDataString.indexOf( '<' ),
545
+ xmpDataString.lastIndexOf( '>' ) + 1
546
+ ),
547
+ 'text/xml'
548
+ );
549
+
550
+ /* Determine if given XMP metadata is the primary GContainer descriptor or a gainmap descriptor */
551
+ const [ hasHDRContainerDescriptor ] = xmpXml.getElementsByTagName(
552
+ 'Container:Directory'
553
+ );
554
+
555
+ if ( hasHDRContainerDescriptor ) {
556
+ /* There's not much useful information in the container descriptor besides memory-validation */
557
+ } else {
558
+
559
+ /* Gainmap descriptor - defaults from https://developer.android.com/media/platform/hdr-image-format#HDR_gain_map_metadata */
560
+
561
+ const [ gainmapNode ] = xmpXml.getElementsByTagName( 'rdf:Description' );
562
+
563
+ metadata.version = gainmapNode.getAttribute( 'hdrgm:Version' );
564
+ metadata.baseRenditionIsHDR =
565
+ gainmapNode.getAttribute( 'hdrgm:BaseRenditionIsHDR' ) === 'True';
566
+ metadata.gainMapMin = parseFloat(
567
+ gainmapNode.getAttribute( 'hdrgm:GainMapMin' ) || 0.0
568
+ );
569
+ metadata.gainMapMax = parseFloat(
570
+ gainmapNode.getAttribute( 'hdrgm:GainMapMax' ) || 1.0
571
+ );
572
+ metadata.gamma = parseFloat(
573
+ gainmapNode.getAttribute( 'hdrgm:Gamma' ) || 1.0
574
+ );
575
+ metadata.offsetSDR = parseFloat(
576
+ gainmapNode.getAttribute( 'hdrgm:OffsetSDR' ) / ( 1 / 64 )
577
+ );
578
+ metadata.offsetHDR = parseFloat(
579
+ gainmapNode.getAttribute( 'hdrgm:OffsetHDR' ) / ( 1 / 64 )
580
+ );
581
+ metadata.hdrCapacityMin = parseFloat(
582
+ gainmapNode.getAttribute( 'hdrgm:HDRCapacityMin' ) || 0.0
583
+ );
584
+ metadata.hdrCapacityMax = parseFloat(
585
+ gainmapNode.getAttribute( 'hdrgm:HDRCapacityMax' ) || 1.0
586
+ );
587
+
588
+ }
589
+
590
+ }
591
+
592
+ _srgbToLinear( value ) {
593
+
594
+ // 0.04045 * 255 = 10.31475
595
+ if ( value < 10.31475 ) {
596
+
597
+ // (1/255) * 0.0773993808
598
+ return value * 0.000303527;
599
+
600
+ }
601
+
602
+ if ( value < 1024 ) {
603
+
604
+ return SRGB_TO_LINEAR[ value | 0 ];
605
+
606
+ }
607
+
608
+ // (1/255) * 0.9478672986 = 0.003717127
609
+ return Math.pow( value * 0.003717127 + 0.0521327014, 2.4 );
610
+
611
+ }
612
+
613
+ _applyGainmapToSDR(
614
+ metadata,
615
+ sdrBuffer,
616
+ gainmapBuffer,
617
+ onSuccess,
618
+ onError
619
+ ) {
620
+
621
+ const decodeImage = ( data ) => createImageBitmap( new Blob( [ data ], { type: 'image/jpeg' } ) );
622
+
623
+ Promise.all( [ decodeImage( sdrBuffer ), decodeImage( gainmapBuffer ) ] )
624
+ .then( ( [ sdrImage, gainmapImage ] ) => {
625
+
626
+ const sdrWidth = sdrImage.width;
627
+ const sdrHeight = sdrImage.height;
628
+ const sdrImageAspect = sdrWidth / sdrHeight;
629
+ const gainmapImageAspect = gainmapImage.width / gainmapImage.height;
630
+
631
+ if ( sdrImageAspect !== gainmapImageAspect ) {
632
+
633
+ onError(
634
+ 'THREE.UltraHDRLoader Error: Aspect ratio mismatch between SDR and Gainmap images'
635
+ );
636
+
637
+ return;
638
+
639
+ }
640
+
641
+ const canvas = document.createElement( 'canvas' );
642
+ const ctx = canvas.getContext( '2d', {
643
+ willReadFrequently: true,
644
+ colorSpace: 'srgb',
645
+ } );
646
+
647
+ canvas.width = sdrWidth;
648
+ canvas.height = sdrHeight;
649
+
650
+ /* Use out-of-the-box interpolation of Canvas API to scale gainmap to fit the SDR resolution */
651
+ ctx.drawImage(
652
+ gainmapImage,
653
+ 0,
654
+ 0,
655
+ gainmapImage.width,
656
+ gainmapImage.height,
657
+ 0,
658
+ 0,
659
+ sdrWidth,
660
+ sdrHeight
661
+ );
662
+ const gainmapImageData = ctx.getImageData(
663
+ 0,
664
+ 0,
665
+ sdrWidth,
666
+ sdrHeight,
667
+ { colorSpace: 'srgb' }
668
+ );
669
+
670
+ ctx.drawImage( sdrImage, 0, 0 );
671
+ const sdrImageData = ctx.getImageData(
672
+ 0,
673
+ 0,
674
+ sdrWidth,
675
+ sdrHeight,
676
+ { colorSpace: 'srgb' }
677
+ );
678
+
679
+ /* HDR Recovery formula - https://developer.android.com/media/platform/hdr-image-format#use_the_gain_map_to_create_adapted_HDR_rendition */
680
+
681
+ /* 1.8 instead of 2 near-perfectly rectifies approximations introduced by precalculated SRGB_TO_LINEAR values */
682
+ const maxDisplayBoost = 1.8 ** ( metadata.hdrCapacityMax * 0.5 );
683
+ const unclampedWeightFactor =
684
+ ( Math.log2( maxDisplayBoost ) - metadata.hdrCapacityMin ) /
685
+ ( metadata.hdrCapacityMax - metadata.hdrCapacityMin );
686
+ const weightFactor = Math.min(
687
+ Math.max( unclampedWeightFactor, 0.0 ),
688
+ 1.0
689
+ );
690
+
691
+ const sdrData = sdrImageData.data;
692
+ const gainmapData = gainmapImageData.data;
693
+ const dataLength = sdrData.length;
694
+ const gainMapMin = metadata.gainMapMin;
695
+ const gainMapMax = metadata.gainMapMax;
696
+ const offsetSDR = metadata.offsetSDR;
697
+ const offsetHDR = metadata.offsetHDR;
698
+ const invGamma = 1.0 / metadata.gamma;
699
+ const useGammaOne = metadata.gamma === 1.0;
700
+ const isHalfFloat = this.type === HalfFloatType;
701
+ const toHalfFloat = DataUtils.toHalfFloat;
702
+ const srgbToLinear = this._srgbToLinear;
703
+
704
+ const hdrBuffer = isHalfFloat
705
+ ? new Uint16Array( dataLength ).fill( 15360 )
706
+ : new Float32Array( dataLength ).fill( 1.0 );
707
+
708
+ for ( let i = 0; i < dataLength; i += 4 ) {
709
+
710
+ for ( let c = 0; c < 3; c ++ ) {
711
+
712
+ const idx = i + c;
713
+ const sdrValue = sdrData[ idx ];
714
+ const gainmapValue = gainmapData[ idx ] * 0.00392156862745098; // 1/255
715
+
716
+ const logRecovery = useGammaOne
717
+ ? gainmapValue
718
+ : Math.pow( gainmapValue, invGamma );
719
+
720
+ const logBoost = gainMapMin + ( gainMapMax - gainMapMin ) * logRecovery;
721
+
722
+ const hdrValue =
723
+ ( sdrValue + offsetSDR ) *
724
+ ( logBoost * weightFactor === 0.0
725
+ ? 1.0
726
+ : Math.pow( 2, logBoost * weightFactor ) ) -
727
+ offsetHDR;
728
+
729
+ const linearHDRValue = Math.min(
730
+ Math.max( srgbToLinear( hdrValue ), 0 ),
731
+ 65504
732
+ );
733
+
734
+ hdrBuffer[ idx ] = isHalfFloat
735
+ ? toHalfFloat( linearHDRValue )
736
+ : linearHDRValue;
737
+
738
+ }
739
+
740
+ }
741
+
742
+ onSuccess( hdrBuffer, sdrWidth, sdrHeight );
743
+
744
+ } )
745
+ .catch( ( e ) => {
746
+
747
+ onError( e );
748
+
749
+ } );
750
+
751
+ }
752
+
753
+ }
754
+
755
+ export { UltraHDRLoader };