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.
- package/README.md +10 -0
- package/config/sdlmcp.config.example.json +53 -8
- package/config/sdlmcp.config.schema.json +530 -106
- package/dist/.tsbuildinfo +1 -1
- package/dist/benchmark/external-manifest.d.ts +162 -0
- package/dist/benchmark/external-manifest.d.ts.map +1 -0
- package/dist/benchmark/external-manifest.js +336 -0
- package/dist/benchmark/external-manifest.js.map +1 -0
- package/dist/benchmark/external-runner.d.ts +100 -0
- package/dist/benchmark/external-runner.d.ts.map +1 -0
- package/dist/benchmark/external-runner.js +1171 -0
- package/dist/benchmark/external-runner.js.map +1 -0
- package/dist/benchmark/output-file.d.ts +3 -0
- package/dist/benchmark/output-file.d.ts.map +1 -0
- package/dist/benchmark/output-file.js +8 -0
- package/dist/benchmark/output-file.js.map +1 -0
- package/dist/cli/argParsing.d.ts.map +1 -1
- package/dist/cli/argParsing.js +6 -0
- package/dist/cli/argParsing.js.map +1 -1
- package/dist/cli/commands/benchmark.d.ts.map +1 -1
- package/dist/cli/commands/benchmark.js +3 -2
- package/dist/cli/commands/benchmark.js.map +1 -1
- package/dist/cli/commands/index.d.ts +1 -0
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/index.js +13 -7
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/init.d.ts +5 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +73 -3
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/serve.d.ts.map +1 -1
- package/dist/cli/commands/serve.js +2 -0
- package/dist/cli/commands/serve.js.map +1 -1
- package/dist/cli/index.js +2 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/transport/http.d.ts +1 -35
- package/dist/cli/transport/http.d.ts.map +1 -1
- package/dist/cli/transport/http.js +151 -175
- package/dist/cli/transport/http.js.map +1 -1
- package/dist/cli/types.d.ts +1 -0
- package/dist/cli/types.d.ts.map +1 -1
- package/dist/config/constants.d.ts +30 -0
- package/dist/config/constants.d.ts.map +1 -1
- package/dist/config/constants.js +30 -0
- package/dist/config/constants.js.map +1 -1
- package/dist/config/types.d.ts +53 -1
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/types.js +62 -14
- package/dist/config/types.js.map +1 -1
- package/dist/db/ladybug-batching.d.ts +1 -0
- package/dist/db/ladybug-batching.d.ts.map +1 -1
- package/dist/db/ladybug-batching.js +1 -0
- package/dist/db/ladybug-batching.js.map +1 -1
- package/dist/db/ladybug-core.d.ts +3 -0
- package/dist/db/ladybug-core.d.ts.map +1 -1
- package/dist/db/ladybug-core.js +72 -2
- package/dist/db/ladybug-core.js.map +1 -1
- package/dist/db/ladybug-embeddings.d.ts +6 -1
- package/dist/db/ladybug-embeddings.d.ts.map +1 -1
- package/dist/db/ladybug-embeddings.js +6 -1
- package/dist/db/ladybug-embeddings.js.map +1 -1
- package/dist/db/ladybug-file-summaries.d.ts.map +1 -1
- package/dist/db/ladybug-file-summaries.js +23 -0
- package/dist/db/ladybug-file-summaries.js.map +1 -1
- package/dist/db/ladybug-queries.js +1 -1
- package/dist/db/ladybug-queries.js.map +1 -1
- package/dist/db/migrations/index.d.ts.map +1 -1
- package/dist/db/migrations/index.js +2 -0
- package/dist/db/migrations/index.js.map +1 -1
- package/dist/db/migrations/m007-copy-embeddings-to-symbol.d.ts +5 -9
- package/dist/db/migrations/m007-copy-embeddings-to-symbol.d.ts.map +1 -1
- package/dist/db/migrations/m007-copy-embeddings-to-symbol.js +24 -126
- package/dist/db/migrations/m007-copy-embeddings-to-symbol.js.map +1 -1
- package/dist/db/migrations/m021-remediate-symbol-embeddings.d.ts +5 -0
- package/dist/db/migrations/m021-remediate-symbol-embeddings.d.ts.map +1 -0
- package/dist/db/migrations/m021-remediate-symbol-embeddings.js +7 -0
- package/dist/db/migrations/m021-remediate-symbol-embeddings.js.map +1 -0
- package/dist/db/migrations/symbol-embedding-remediation.d.ts +57 -0
- package/dist/db/migrations/symbol-embedding-remediation.d.ts.map +1 -0
- package/dist/db/migrations/symbol-embedding-remediation.js +335 -0
- package/dist/db/migrations/symbol-embedding-remediation.js.map +1 -0
- package/dist/graph/layout/force-layout.d.ts +4 -0
- package/dist/graph/layout/force-layout.d.ts.map +1 -0
- package/dist/graph/layout/force-layout.js +127 -0
- package/dist/graph/layout/force-layout.js.map +1 -0
- package/dist/graph/layout/layout-service.d.ts +37 -0
- package/dist/graph/layout/layout-service.d.ts.map +1 -0
- package/dist/graph/layout/layout-service.js +172 -0
- package/dist/graph/layout/layout-service.js.map +1 -0
- package/dist/graph/layout/native-engine.d.ts +9 -0
- package/dist/graph/layout/native-engine.d.ts.map +1 -0
- package/dist/graph/layout/native-engine.js +59 -0
- package/dist/graph/layout/native-engine.js.map +1 -0
- package/dist/graph/layout/prng.d.ts +3 -0
- package/dist/graph/layout/prng.d.ts.map +1 -0
- package/dist/graph/layout/prng.js +19 -0
- package/dist/graph/layout/prng.js.map +1 -0
- package/dist/graph/layout/serializer.d.ts +3 -0
- package/dist/graph/layout/serializer.d.ts.map +1 -0
- package/dist/graph/layout/serializer.js +20 -0
- package/dist/graph/layout/serializer.js.map +1 -0
- package/dist/graph/layout/types.d.ts +30 -0
- package/dist/graph/layout/types.d.ts.map +1 -0
- package/dist/graph/layout/types.js +2 -0
- package/dist/graph/layout/types.js.map +1 -0
- package/dist/indexer/embeddings.d.ts +7 -0
- package/dist/indexer/embeddings.d.ts.map +1 -1
- package/dist/indexer/embeddings.js +44 -4
- package/dist/indexer/embeddings.js.map +1 -1
- package/dist/indexer/file-summary-embeddings.d.ts +12 -0
- package/dist/indexer/file-summary-embeddings.d.ts.map +1 -1
- package/dist/indexer/file-summary-embeddings.js +83 -21
- package/dist/indexer/file-summary-embeddings.js.map +1 -1
- package/dist/indexer/fileWalker.d.ts.map +1 -1
- package/dist/indexer/fileWalker.js +2 -1
- package/dist/indexer/fileWalker.js.map +1 -1
- package/dist/indexer/metrics-updater.d.ts.map +1 -1
- package/dist/indexer/metrics-updater.js +27 -4
- package/dist/indexer/metrics-updater.js.map +1 -1
- package/dist/indexer/watcher.d.ts.map +1 -1
- package/dist/indexer/watcher.js +2 -1
- package/dist/indexer/watcher.js.map +1 -1
- package/dist/mcp/context-response-projection.d.ts.map +1 -1
- package/dist/mcp/context-response-projection.js +49 -13
- package/dist/mcp/context-response-projection.js.map +1 -1
- package/dist/mcp/tools/search-edit/planner.d.ts.map +1 -1
- package/dist/mcp/tools/search-edit/planner.js +10 -3
- package/dist/mcp/tools/search-edit/planner.js.map +1 -1
- package/dist/observability/event-tap.d.ts +2 -1
- package/dist/observability/event-tap.d.ts.map +1 -1
- package/dist/observability/event-tap.js.map +1 -1
- package/dist/observability/service.d.ts +11 -4
- package/dist/observability/service.d.ts.map +1 -1
- package/dist/observability/service.js +83 -13
- package/dist/observability/service.js.map +1 -1
- package/dist/observability/types.d.ts +48 -2
- package/dist/observability/types.d.ts.map +1 -1
- package/dist/ui/.tsbuildinfo +1 -0
- package/dist/ui/vendor/fflate.js +2692 -0
- package/dist/ui/vendor/jsm/controls/ArcballControls.js +3543 -0
- package/dist/ui/vendor/jsm/controls/DragControls.js +452 -0
- package/dist/ui/vendor/jsm/controls/FirstPersonControls.js +488 -0
- package/dist/ui/vendor/jsm/controls/FlyControls.js +384 -0
- package/dist/ui/vendor/jsm/controls/MapControls.js +116 -0
- package/dist/ui/vendor/jsm/controls/OrbitControls.js +1963 -0
- package/dist/ui/vendor/jsm/controls/PointerLockControls.js +264 -0
- package/dist/ui/vendor/jsm/controls/TrackballControls.js +1001 -0
- package/dist/ui/vendor/jsm/controls/TransformControls.js +2003 -0
- package/dist/ui/vendor/jsm/loaders/3DMLoader.js +1836 -0
- package/dist/ui/vendor/jsm/loaders/3MFLoader.js +1621 -0
- package/dist/ui/vendor/jsm/loaders/AMFLoader.js +541 -0
- package/dist/ui/vendor/jsm/loaders/BVHLoader.js +484 -0
- package/dist/ui/vendor/jsm/loaders/ColladaLoader.js +153 -0
- package/dist/ui/vendor/jsm/loaders/DDSLoader.js +385 -0
- package/dist/ui/vendor/jsm/loaders/DRACOLoader.js +772 -0
- package/dist/ui/vendor/jsm/loaders/EXRLoader.js +3395 -0
- package/dist/ui/vendor/jsm/loaders/FBXLoader.js +4580 -0
- package/dist/ui/vendor/jsm/loaders/FontLoader.js +260 -0
- package/dist/ui/vendor/jsm/loaders/GCodeLoader.js +318 -0
- package/dist/ui/vendor/jsm/loaders/GLTFLoader.js +4860 -0
- package/dist/ui/vendor/jsm/loaders/HDRCubeTextureLoader.js +164 -0
- package/dist/ui/vendor/jsm/loaders/HDRLoader.js +463 -0
- package/dist/ui/vendor/jsm/loaders/IESLoader.js +379 -0
- package/dist/ui/vendor/jsm/loaders/KMZLoader.js +163 -0
- package/dist/ui/vendor/jsm/loaders/KTX2Loader.js +1276 -0
- package/dist/ui/vendor/jsm/loaders/KTXLoader.js +197 -0
- package/dist/ui/vendor/jsm/loaders/LDrawLoader.js +2510 -0
- package/dist/ui/vendor/jsm/loaders/LUT3dlLoader.js +205 -0
- package/dist/ui/vendor/jsm/loaders/LUTCubeLoader.js +190 -0
- package/dist/ui/vendor/jsm/loaders/LUTImageLoader.js +190 -0
- package/dist/ui/vendor/jsm/loaders/LWOLoader.js +1051 -0
- package/dist/ui/vendor/jsm/loaders/LottieLoader.js +130 -0
- package/dist/ui/vendor/jsm/loaders/MD2Loader.js +435 -0
- package/dist/ui/vendor/jsm/loaders/MDDLoader.js +147 -0
- package/dist/ui/vendor/jsm/loaders/MTLLoader.js +593 -0
- package/dist/ui/vendor/jsm/loaders/MaterialXLoader.js +1126 -0
- package/dist/ui/vendor/jsm/loaders/NRRDLoader.js +718 -0
- package/dist/ui/vendor/jsm/loaders/OBJLoader.js +955 -0
- package/dist/ui/vendor/jsm/loaders/PCDLoader.js +620 -0
- package/dist/ui/vendor/jsm/loaders/PDBLoader.js +272 -0
- package/dist/ui/vendor/jsm/loaders/PLYLoader.js +968 -0
- package/dist/ui/vendor/jsm/loaders/PVRLoader.js +270 -0
- package/dist/ui/vendor/jsm/loaders/RGBELoader.js +18 -0
- package/dist/ui/vendor/jsm/loaders/STLLoader.js +421 -0
- package/dist/ui/vendor/jsm/loaders/SVGLoader.js +3319 -0
- package/dist/ui/vendor/jsm/loaders/TDSLoader.js +1142 -0
- package/dist/ui/vendor/jsm/loaders/TGALoader.js +538 -0
- package/dist/ui/vendor/jsm/loaders/TIFFLoader.js +59 -0
- package/dist/ui/vendor/jsm/loaders/TTFLoader.js +261 -0
- package/dist/ui/vendor/jsm/loaders/USDLoader.js +303 -0
- package/dist/ui/vendor/jsm/loaders/USDZLoader.js +16 -0
- package/dist/ui/vendor/jsm/loaders/UltraHDRLoader.js +755 -0
- package/dist/ui/vendor/jsm/loaders/VOXLoader.js +919 -0
- package/dist/ui/vendor/jsm/loaders/VRMLLoader.js +3646 -0
- package/dist/ui/vendor/jsm/loaders/VTKLoader.js +1293 -0
- package/dist/ui/vendor/jsm/loaders/XYZLoader.js +143 -0
- package/dist/ui/vendor/jsm/loaders/collada/ColladaComposer.js +3044 -0
- package/dist/ui/vendor/jsm/loaders/collada/ColladaParser.js +1977 -0
- package/dist/ui/vendor/jsm/loaders/lwo/IFFParser.js +1217 -0
- package/dist/ui/vendor/jsm/loaders/lwo/LWO2Parser.js +414 -0
- package/dist/ui/vendor/jsm/loaders/lwo/LWO3Parser.js +373 -0
- package/dist/ui/vendor/jsm/loaders/usd/USDAParser.js +901 -0
- package/dist/ui/vendor/jsm/loaders/usd/USDCParser.js +1878 -0
- package/dist/ui/vendor/jsm/loaders/usd/USDComposer.js +4627 -0
- package/dist/ui/vendor/jsm/utils/BufferGeometryUtils.js +1501 -0
- package/dist/ui/vendor/jsm/utils/CameraUtils.js +82 -0
- package/dist/ui/vendor/jsm/utils/ColorUtils.js +76 -0
- package/dist/ui/vendor/jsm/utils/GeometryCompressionUtils.js +547 -0
- package/dist/ui/vendor/jsm/utils/GeometryUtils.js +226 -0
- package/dist/ui/vendor/jsm/utils/LDrawUtils.js +211 -0
- package/dist/ui/vendor/jsm/utils/SceneOptimizer.js +458 -0
- package/dist/ui/vendor/jsm/utils/SceneUtils.js +363 -0
- package/dist/ui/vendor/jsm/utils/ShadowMapViewer.js +244 -0
- package/dist/ui/vendor/jsm/utils/ShadowMapViewerGPU.js +233 -0
- package/dist/ui/vendor/jsm/utils/SkeletonUtils.js +496 -0
- package/dist/ui/vendor/jsm/utils/SortUtils.js +175 -0
- package/dist/ui/vendor/jsm/utils/UVsDebug.js +173 -0
- package/dist/ui/vendor/jsm/utils/WebGLTextureUtils.js +115 -0
- package/dist/ui/vendor/jsm/utils/WebGPUTextureUtils.js +81 -0
- package/dist/ui/vendor/jsm/utils/WorkerPool.js +167 -0
- package/dist/ui/vendor/three.core.min.js +6 -0
- package/dist/ui/vendor/three.module.min.js +6 -0
- package/dist/ui/viewer/ambient.js +39 -0
- package/dist/ui/viewer/api.js +93 -0
- package/dist/ui/viewer/chrome.js +36 -0
- package/dist/ui/viewer/edges.js +33 -0
- package/dist/ui/viewer/index.html +32 -0
- package/dist/ui/viewer/inspector.js +23 -0
- package/dist/ui/viewer/lenses/activity.js +24 -0
- package/dist/ui/viewer/lenses/community.js +5 -0
- package/dist/ui/viewer/lenses/edges.js +4 -0
- package/dist/ui/viewer/lenses/impact.js +6 -0
- package/dist/ui/viewer/lenses/search.js +69 -0
- package/dist/ui/viewer/lod.js +100 -0
- package/dist/ui/viewer/main.js +92 -0
- package/dist/ui/viewer/picking.js +45 -0
- package/dist/ui/viewer/scene.js +85 -0
- package/dist/ui/viewer/skins/default-skin.js +15 -0
- package/dist/ui/viewer/skins/loader.js +44 -0
- package/dist/ui/viewer/skins/manifest-schema.js +30 -0
- package/dist/ui/viewer/state.js +44 -0
- package/dist/ui/viewer/theme.js +23 -0
- package/dist/ui/viewer/universe.js +151 -0
- package/dist/ui/viewer/viewer.css +85 -0
- package/dist/util/safeRegex.d.ts.map +1 -1
- package/dist/util/safeRegex.js +221 -68
- package/dist/util/safeRegex.js.map +1 -1
- package/dist/viewer/legacy-graph.d.ts +40 -0
- package/dist/viewer/legacy-graph.d.ts.map +1 -0
- package/dist/viewer/legacy-graph.js +152 -0
- package/dist/viewer/legacy-graph.js.map +1 -0
- package/dist/viewer/routes.d.ts +10 -0
- package/dist/viewer/routes.d.ts.map +1 -0
- package/dist/viewer/routes.js +221 -0
- package/dist/viewer/routes.js.map +1 -0
- package/dist/viewer/service.d.ts +44 -0
- package/dist/viewer/service.d.ts.map +1 -0
- package/dist/viewer/service.js +160 -0
- package/dist/viewer/service.js.map +1 -0
- package/dist/viewer/types.d.ts +63 -0
- package/dist/viewer/types.d.ts.map +1 -0
- package/dist/viewer/types.js +2 -0
- package/dist/viewer/types.js.map +1 -0
- package/dist/viewer/viewer-config.d.ts +12 -0
- package/dist/viewer/viewer-config.d.ts.map +1 -0
- package/dist/viewer/viewer-config.js +36 -0
- package/dist/viewer/viewer-config.js.map +1 -0
- package/package.json +18 -9
- package/templates/SDL.md +19 -0
- package/templates/claude-code.json +8 -43
- package/dist/ui/graph.css +0 -108
- package/dist/ui/graph.d.ts +0 -2
- package/dist/ui/graph.d.ts.map +0 -1
- package/dist/ui/graph.html +0 -52
- package/dist/ui/graph.js +0 -259
- 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 };
|