@loaders.gl/textures 4.4.0-alpha.2 → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. package/README.md +197 -1
  2. package/dist/basis-loader.d.ts +15 -10
  3. package/dist/basis-loader.d.ts.map +1 -1
  4. package/dist/basis-loader.js +1 -1
  5. package/dist/basis-loader.js.map +1 -0
  6. package/dist/basis-worker-node.js +932 -10040
  7. package/dist/basis-worker.d.ts +2 -0
  8. package/dist/basis-worker.d.ts.map +1 -0
  9. package/dist/basis-worker.js +337 -151
  10. package/dist/basis-worker.js.map +1 -0
  11. package/dist/compressed-texture-loader.d.ts +2 -5
  12. package/dist/compressed-texture-loader.d.ts.map +1 -1
  13. package/dist/compressed-texture-loader.js +2 -3
  14. package/dist/compressed-texture-loader.js.map +1 -0
  15. package/dist/compressed-texture-worker.d.ts +2 -0
  16. package/dist/compressed-texture-worker.d.ts.map +1 -0
  17. package/dist/compressed-texture-worker.js +1148 -365
  18. package/dist/compressed-texture-worker.js.map +1 -0
  19. package/dist/compressed-texture-writer.js +1 -0
  20. package/dist/compressed-texture-writer.js.map +1 -0
  21. package/dist/crunch-loader.d.ts +1 -5
  22. package/dist/crunch-loader.d.ts.map +1 -1
  23. package/dist/crunch-loader.js +2 -3
  24. package/dist/crunch-loader.js.map +1 -0
  25. package/dist/crunch-worker.d.ts +2 -0
  26. package/dist/crunch-worker.d.ts.map +1 -0
  27. package/dist/crunch-worker.js +204 -92
  28. package/dist/crunch-worker.js.map +1 -0
  29. package/dist/dist.dev.js +2687 -677
  30. package/dist/dist.min.js +1 -2
  31. package/dist/index.cjs +1644 -428
  32. package/dist/index.cjs.map +4 -4
  33. package/dist/index.d.ts +13 -4
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +7 -3
  36. package/dist/index.js.map +1 -0
  37. package/dist/ktx2-basis-writer-worker-node.js +574 -9832
  38. package/dist/ktx2-basis-writer-worker.d.ts +2 -0
  39. package/dist/ktx2-basis-writer-worker.d.ts.map +1 -0
  40. package/dist/ktx2-basis-writer-worker.js +45 -7
  41. package/dist/ktx2-basis-writer-worker.js.map +1 -0
  42. package/dist/ktx2-basis-writer.js +1 -0
  43. package/dist/ktx2-basis-writer.js.map +1 -0
  44. package/dist/lib/composite-image/image-texture-cube.d.ts +47 -0
  45. package/dist/lib/composite-image/image-texture-cube.d.ts.map +1 -0
  46. package/dist/lib/composite-image/image-texture-cube.js +42 -0
  47. package/dist/lib/composite-image/image-texture-cube.js.map +1 -0
  48. package/dist/lib/composite-image/parse-composite-image.d.ts +43 -0
  49. package/dist/lib/composite-image/parse-composite-image.d.ts.map +1 -0
  50. package/dist/lib/composite-image/parse-composite-image.js +437 -0
  51. package/dist/lib/composite-image/parse-composite-image.js.map +1 -0
  52. package/dist/lib/encoders/encode-ktx.d.ts +1 -1
  53. package/dist/lib/encoders/encode-ktx.d.ts.map +1 -1
  54. package/dist/lib/encoders/encode-ktx.js +1 -0
  55. package/dist/lib/encoders/encode-ktx.js.map +1 -0
  56. package/dist/lib/encoders/encode-ktx2-basis-texture.d.ts +2 -1
  57. package/dist/lib/encoders/encode-ktx2-basis-texture.d.ts.map +1 -1
  58. package/dist/lib/encoders/encode-ktx2-basis-texture.js +3 -1
  59. package/dist/lib/encoders/encode-ktx2-basis-texture.js.map +1 -0
  60. package/dist/lib/encoders/encode-texture.js +1 -0
  61. package/dist/lib/encoders/encode-texture.js.map +1 -0
  62. package/dist/lib/gl-extensions.d.ts +166 -58
  63. package/dist/lib/gl-extensions.d.ts.map +1 -1
  64. package/dist/lib/gl-extensions.js +178 -66
  65. package/dist/lib/gl-extensions.js.map +1 -0
  66. package/dist/lib/gl-types.d.ts +4 -0
  67. package/dist/lib/gl-types.d.ts.map +1 -0
  68. package/dist/lib/gl-types.js +5 -0
  69. package/dist/lib/gl-types.js.map +1 -0
  70. package/dist/lib/parsers/basis-module-loader.d.ts +3 -2
  71. package/dist/lib/parsers/basis-module-loader.d.ts.map +1 -1
  72. package/dist/lib/parsers/basis-module-loader.js +1 -0
  73. package/dist/lib/parsers/basis-module-loader.js.map +1 -0
  74. package/dist/lib/parsers/crunch-module-loader.d.ts +2 -2
  75. package/dist/lib/parsers/crunch-module-loader.d.ts.map +1 -1
  76. package/dist/lib/parsers/crunch-module-loader.js +1 -0
  77. package/dist/lib/parsers/crunch-module-loader.js.map +1 -0
  78. package/dist/lib/parsers/parse-basis.d.ts +34 -2
  79. package/dist/lib/parsers/parse-basis.d.ts.map +1 -1
  80. package/dist/lib/parsers/parse-basis.js +265 -64
  81. package/dist/lib/parsers/parse-basis.js.map +1 -0
  82. package/dist/lib/parsers/parse-compressed-texture.js +1 -0
  83. package/dist/lib/parsers/parse-compressed-texture.js.map +1 -0
  84. package/dist/lib/parsers/parse-crunch.d.ts.map +1 -1
  85. package/dist/lib/parsers/parse-crunch.js +7 -6
  86. package/dist/lib/parsers/parse-crunch.js.map +1 -0
  87. package/dist/lib/parsers/parse-dds.d.ts.map +1 -1
  88. package/dist/lib/parsers/parse-dds.js +11 -11
  89. package/dist/lib/parsers/parse-dds.js.map +1 -0
  90. package/dist/lib/parsers/parse-hdr.d.ts +21 -0
  91. package/dist/lib/parsers/parse-hdr.d.ts.map +1 -0
  92. package/dist/lib/parsers/parse-hdr.js +305 -0
  93. package/dist/lib/parsers/parse-hdr.js.map +1 -0
  94. package/dist/lib/parsers/parse-ktx.d.ts.map +1 -1
  95. package/dist/lib/parsers/parse-ktx.js +11 -3
  96. package/dist/lib/parsers/parse-ktx.js.map +1 -0
  97. package/dist/lib/parsers/parse-npy.js +1 -0
  98. package/dist/lib/parsers/parse-npy.js.map +1 -0
  99. package/dist/lib/parsers/parse-pvr.d.ts.map +1 -1
  100. package/dist/lib/parsers/parse-pvr.js +32 -74
  101. package/dist/lib/parsers/parse-pvr.js.map +1 -0
  102. package/dist/lib/texture-api/async-deep-map.js +1 -0
  103. package/dist/lib/texture-api/async-deep-map.js.map +1 -0
  104. package/dist/lib/texture-api/deep-load.js +1 -0
  105. package/dist/lib/texture-api/deep-load.js.map +1 -0
  106. package/dist/lib/texture-api/generate-url.d.ts.map +1 -1
  107. package/dist/lib/texture-api/generate-url.js +3 -10
  108. package/dist/lib/texture-api/generate-url.js.map +1 -0
  109. package/dist/lib/texture-api/load-image-array.d.ts +6 -3
  110. package/dist/lib/texture-api/load-image-array.d.ts.map +1 -1
  111. package/dist/lib/texture-api/load-image-array.js +6 -3
  112. package/dist/lib/texture-api/load-image-array.js.map +1 -0
  113. package/dist/lib/texture-api/load-image-cube.d.ts +7 -11
  114. package/dist/lib/texture-api/load-image-cube.d.ts.map +1 -1
  115. package/dist/lib/texture-api/load-image-cube.js +9 -20
  116. package/dist/lib/texture-api/load-image-cube.js.map +1 -0
  117. package/dist/lib/texture-api/load-image.d.ts +6 -3
  118. package/dist/lib/texture-api/load-image.d.ts.map +1 -1
  119. package/dist/lib/texture-api/load-image.js +9 -4
  120. package/dist/lib/texture-api/load-image.js.map +1 -0
  121. package/dist/lib/texture-api/texture-api-types.d.ts +13 -0
  122. package/dist/lib/texture-api/texture-api-types.d.ts.map +1 -1
  123. package/dist/lib/texture-api/texture-api-types.js +1 -0
  124. package/dist/lib/texture-api/texture-api-types.js.map +1 -0
  125. package/dist/lib/utils/detect-supported-texture-formats.d.ts +14 -0
  126. package/dist/lib/utils/detect-supported-texture-formats.d.ts.map +1 -0
  127. package/dist/lib/utils/detect-supported-texture-formats.js +197 -0
  128. package/dist/lib/utils/detect-supported-texture-formats.js.map +1 -0
  129. package/dist/lib/utils/extract-mipmap-images.d.ts +6 -2
  130. package/dist/lib/utils/extract-mipmap-images.d.ts.map +1 -1
  131. package/dist/lib/utils/extract-mipmap-images.js +14 -2
  132. package/dist/lib/utils/extract-mipmap-images.js.map +1 -0
  133. package/dist/lib/utils/ktx-format-helper.d.ts +9 -1
  134. package/dist/lib/utils/ktx-format-helper.d.ts.map +1 -1
  135. package/dist/lib/utils/ktx-format-helper.js +77 -109
  136. package/dist/lib/utils/ktx-format-helper.js.map +1 -0
  137. package/dist/lib/utils/texture-format-map.d.ts +10 -0
  138. package/dist/lib/utils/texture-format-map.d.ts.map +1 -0
  139. package/dist/lib/utils/texture-format-map.js +87 -0
  140. package/dist/lib/utils/texture-format-map.js.map +1 -0
  141. package/dist/lib/utils/version.js +2 -1
  142. package/dist/lib/utils/version.js.map +1 -0
  143. package/dist/libs/libs/README.md +9 -0
  144. package/dist/libs/libs/basis_encoder.js +21 -0
  145. package/dist/libs/libs/basis_encoder.wasm +0 -0
  146. package/dist/libs/libs/basis_transcoder.js +22 -0
  147. package/dist/libs/libs/basis_transcoder.wasm +0 -0
  148. package/dist/libs/libs/crunch.js +136 -0
  149. package/dist/npy-loader.d.ts +2 -2
  150. package/dist/npy-loader.js +1 -0
  151. package/dist/npy-loader.js.map +1 -0
  152. package/dist/npy-worker.d.ts +2 -0
  153. package/dist/npy-worker.d.ts.map +1 -0
  154. package/dist/npy-worker.js +5 -2
  155. package/dist/npy-worker.js.map +1 -0
  156. package/dist/radiance-hdr-loader.d.ts +25 -0
  157. package/dist/radiance-hdr-loader.d.ts.map +1 -0
  158. package/dist/radiance-hdr-loader.js +23 -0
  159. package/dist/radiance-hdr-loader.js.map +1 -0
  160. package/dist/texture-array-loader.d.ts +25 -0
  161. package/dist/texture-array-loader.d.ts.map +1 -0
  162. package/dist/texture-array-loader.js +24 -0
  163. package/dist/texture-array-loader.js.map +1 -0
  164. package/dist/texture-cube-array-loader.d.ts +25 -0
  165. package/dist/texture-cube-array-loader.d.ts.map +1 -0
  166. package/dist/texture-cube-array-loader.js +24 -0
  167. package/dist/texture-cube-array-loader.js.map +1 -0
  168. package/dist/texture-cube-loader.d.ts +25 -0
  169. package/dist/texture-cube-loader.d.ts.map +1 -0
  170. package/dist/texture-cube-loader.js +24 -0
  171. package/dist/texture-cube-loader.js.map +1 -0
  172. package/dist/texture-loader.d.ts +25 -0
  173. package/dist/texture-loader.d.ts.map +1 -0
  174. package/dist/texture-loader.js +24 -0
  175. package/dist/texture-loader.js.map +1 -0
  176. package/dist/workers/basis-worker-node.js +1 -0
  177. package/dist/workers/basis-worker-node.js.map +1 -0
  178. package/dist/workers/basis-worker.js +1 -0
  179. package/dist/workers/basis-worker.js.map +1 -0
  180. package/dist/workers/compressed-texture-worker.js +1 -1
  181. package/dist/workers/compressed-texture-worker.js.map +1 -0
  182. package/dist/workers/crunch-worker.d.ts +1 -3
  183. package/dist/workers/crunch-worker.d.ts.map +1 -1
  184. package/dist/workers/crunch-worker.js +1 -0
  185. package/dist/workers/crunch-worker.js.map +1 -0
  186. package/dist/workers/ktx2-basis-writer-worker-node.js +1 -0
  187. package/dist/workers/ktx2-basis-writer-worker-node.js.map +1 -0
  188. package/dist/workers/ktx2-basis-writer-worker.js +1 -0
  189. package/dist/workers/ktx2-basis-writer-worker.js.map +1 -0
  190. package/dist/workers/npy-worker.js +1 -0
  191. package/dist/workers/npy-worker.js.map +1 -0
  192. package/package.json +27 -6
  193. package/src/basis-loader.ts +19 -9
  194. package/src/basis-worker.ts +7 -0
  195. package/src/compressed-texture-loader.ts +3 -7
  196. package/src/compressed-texture-worker.ts +6 -0
  197. package/src/crunch-loader.ts +1 -5
  198. package/src/crunch-worker.ts +6 -0
  199. package/src/index.ts +21 -4
  200. package/src/ktx2-basis-writer-worker.ts +6 -0
  201. package/src/lib/composite-image/image-texture-cube.ts +49 -0
  202. package/src/lib/composite-image/parse-composite-image.ts +699 -0
  203. package/src/lib/encoders/encode-ktx.ts +1 -1
  204. package/src/lib/encoders/encode-ktx2-basis-texture.ts +4 -2
  205. package/src/lib/gl-extensions.ts +188 -81
  206. package/src/lib/gl-types.ts +136 -0
  207. package/src/lib/parsers/basis-module-loader.ts +5 -5
  208. package/src/lib/parsers/crunch-module-loader.ts +4 -4
  209. package/src/lib/parsers/parse-basis.ts +358 -66
  210. package/src/lib/parsers/parse-crunch.ts +11 -8
  211. package/src/lib/parsers/parse-dds.ts +11 -12
  212. package/src/lib/parsers/parse-hdr.ts +426 -0
  213. package/src/lib/parsers/parse-ktx.ts +13 -3
  214. package/src/lib/parsers/parse-pvr.ts +33 -75
  215. package/src/lib/texture-api/generate-url.ts +2 -12
  216. package/src/lib/texture-api/load-image-array.ts +15 -6
  217. package/src/lib/texture-api/load-image-cube.ts +20 -34
  218. package/src/lib/texture-api/load-image.ts +19 -8
  219. package/src/lib/texture-api/texture-api-types.ts +15 -0
  220. package/src/lib/utils/detect-supported-texture-formats.ts +210 -0
  221. package/src/lib/utils/extract-mipmap-images.ts +23 -4
  222. package/src/lib/utils/ktx-format-helper.ts +135 -111
  223. package/src/lib/utils/texture-format-map.ts +162 -0
  224. package/src/npy-worker.ts +6 -0
  225. package/src/radiance-hdr-loader.ts +36 -0
  226. package/src/texture-array-loader.ts +46 -0
  227. package/src/texture-cube-array-loader.ts +49 -0
  228. package/src/texture-cube-loader.ts +46 -0
  229. package/src/texture-loader.ts +49 -0
  230. package/src/workers/compressed-texture-worker.ts +0 -1
  231. package/dist/lib/utils/texture-formats.d.ts +0 -8
  232. package/dist/lib/utils/texture-formats.d.ts.map +0 -1
  233. package/dist/lib/utils/texture-formats.js +0 -50
  234. package/src/lib/utils/texture-formats.ts +0 -59
@@ -0,0 +1,426 @@
1
+ // loaders.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import type {Texture, TextureLevel} from '@loaders.gl/schema';
6
+ import {GL_RGBA32F} from '../gl-extensions';
7
+
8
+ const HDR_MAGIC_HEADERS = ['#?RADIANCE', '#?RGBE'];
9
+ const HDR_FORMAT = '32-bit_rle_rgbe';
10
+
11
+ /** Application-facing metadata extracted from Radiance HDR header fields. */
12
+ export type RadianceHDRMetadata = {
13
+ /** Per-channel color correction factors from the `COLORCORR` header field. */
14
+ colorCorrection?: [number, number, number];
15
+ /** Scene exposure multiplier from the `EXPOSURE` header field. */
16
+ exposure?: number;
17
+ /** Display gamma hint from the `GAMMA` header field. */
18
+ gamma?: number;
19
+ /** Pixel aspect ratio from the `PIXASPECT` header field. */
20
+ pixelAspectRatio?: number;
21
+ /** Chromaticity primaries and white point from the `PRIMARIES` header field. */
22
+ primaries?: [number, number, number, number, number, number, number, number];
23
+ /** Producer software identifier from the `SOFTWARE` header field. */
24
+ software?: string;
25
+ /** View specification string from the `VIEW` header field. */
26
+ view?: string;
27
+ };
28
+
29
+ type HeaderState = {
30
+ data: Uint8Array;
31
+ offset: number;
32
+ };
33
+
34
+ type HDRHeader = {
35
+ width: number;
36
+ height: number;
37
+ majorAxis: 'X' | 'Y';
38
+ majorSign: 1 | -1;
39
+ minorAxis: 'X' | 'Y';
40
+ minorSign: 1 | -1;
41
+ metadata?: RadianceHDRMetadata;
42
+ };
43
+
44
+ export function isHDR(arrayBuffer: ArrayBuffer): boolean {
45
+ const state: HeaderState = {
46
+ data: new Uint8Array(arrayBuffer),
47
+ offset: 0
48
+ };
49
+
50
+ const firstLine = readLine(state);
51
+ return firstLine ? HDR_MAGIC_HEADERS.includes(firstLine) : false;
52
+ }
53
+
54
+ export function parseHDR(arrayBuffer: ArrayBuffer): Texture<RadianceHDRMetadata> {
55
+ const state: HeaderState = {
56
+ data: new Uint8Array(arrayBuffer),
57
+ offset: 0
58
+ };
59
+ const header = readHeader(state);
60
+ const {width, height} = header;
61
+ const rgbeData = readPixels(state, header);
62
+ const data = convertRGBEToFloat(rgbeData);
63
+ const level: TextureLevel = {
64
+ shape: 'texture-level',
65
+ compressed: false,
66
+ width,
67
+ height,
68
+ data,
69
+ levelSize: data.byteLength,
70
+ format: GL_RGBA32F,
71
+ textureFormat: 'rgba32float'
72
+ };
73
+
74
+ return {
75
+ shape: 'texture',
76
+ type: '2d',
77
+ format: 'rgba32float',
78
+ ...(header.metadata ? {metadata: header.metadata} : {}),
79
+ data: [level]
80
+ };
81
+ }
82
+
83
+ function readHeader(state: HeaderState): HDRHeader {
84
+ const magicHeader = readLine(state);
85
+ if (!magicHeader || !HDR_MAGIC_HEADERS.includes(magicHeader)) {
86
+ throw new Error('RadianceHDRLoader: bad initial token');
87
+ }
88
+
89
+ let hasFormat = false;
90
+ const metadata: RadianceHDRMetadata = {};
91
+
92
+ while (state.offset < state.data.length) {
93
+ const line = readLine(state);
94
+
95
+ if (line === null) {
96
+ break;
97
+ }
98
+
99
+ if (!line || line.startsWith('#')) {
100
+ continue;
101
+ }
102
+
103
+ if (line.startsWith('FORMAT=')) {
104
+ hasFormat = line.slice('FORMAT='.length) === HDR_FORMAT;
105
+ if (!hasFormat) {
106
+ throw new Error('RadianceHDRLoader: unsupported format specifier');
107
+ }
108
+ continue;
109
+ }
110
+
111
+ parseMetadataLine(metadata, line);
112
+
113
+ const dimensions = parseDimensions(line);
114
+ if (dimensions) {
115
+ if (!hasFormat) {
116
+ throw new Error('RadianceHDRLoader: missing format specifier');
117
+ }
118
+ return {
119
+ ...dimensions,
120
+ ...(hasMetadata(metadata) ? {metadata} : {})
121
+ };
122
+ }
123
+ }
124
+
125
+ if (!hasFormat) {
126
+ throw new Error('RadianceHDRLoader: missing format specifier');
127
+ }
128
+
129
+ throw new Error('RadianceHDRLoader: missing image size specifier');
130
+ }
131
+
132
+ function parseDimensions(line: string): HDRHeader | null {
133
+ const match = line.match(/^([+-])([YX])\s+(\d+)\s+([+-])([YX])\s+(\d+)$/);
134
+ if (!match) {
135
+ return null;
136
+ }
137
+
138
+ const majorSign = match[1] === '+' ? 1 : -1;
139
+ const majorAxis = match[2] as 'X' | 'Y';
140
+ const majorLength = Number(match[3]);
141
+ const minorSign = match[4] === '+' ? 1 : -1;
142
+ const minorAxis = match[5] as 'X' | 'Y';
143
+ const minorLength = Number(match[6]);
144
+
145
+ if (majorAxis === minorAxis) {
146
+ throw new Error('RadianceHDRLoader: invalid image dimensions');
147
+ }
148
+
149
+ const width = majorAxis === 'X' ? majorLength : minorLength;
150
+ const height = majorAxis === 'Y' ? majorLength : minorLength;
151
+ if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {
152
+ throw new Error('RadianceHDRLoader: invalid image dimensions');
153
+ }
154
+
155
+ return {width, height, majorAxis, majorSign, minorAxis, minorSign};
156
+ }
157
+
158
+ function readPixels(state: HeaderState, header: HDRHeader): Uint8Array {
159
+ const {width, height} = header;
160
+ const pixelCount = width * height;
161
+ const flatByteLength = pixelCount * 4;
162
+ const scanlineLength = header.minorAxis === 'X' ? width : height;
163
+ const scanlineCount = header.majorAxis === 'Y' ? height : width;
164
+
165
+ if (scanlineLength < 8 || scanlineLength > 0x7fff) {
166
+ return reorderPixels(readFlatPixels(state, flatByteLength), header);
167
+ }
168
+
169
+ if (state.offset + 4 > state.data.length) {
170
+ throw new Error('RadianceHDRLoader: unexpected end of file');
171
+ }
172
+
173
+ const data = state.data;
174
+ const isRunLengthEncoded =
175
+ data[state.offset] === 2 && data[state.offset + 1] === 2 && !(data[state.offset + 2] & 0x80);
176
+
177
+ if (!isRunLengthEncoded) {
178
+ return reorderPixels(readFlatPixels(state, flatByteLength), header);
179
+ }
180
+
181
+ const scanlineWidth = (data[state.offset + 2] << 8) | data[state.offset + 3];
182
+ if (scanlineWidth !== scanlineLength) {
183
+ return reorderPixels(readFlatPixels(state, flatByteLength), header);
184
+ }
185
+
186
+ const pixels = new Uint8Array(flatByteLength);
187
+ const scanlineBuffer = new Uint8Array(scanlineLength * 4);
188
+
189
+ for (let scanlineIndex = 0; scanlineIndex < scanlineCount; scanlineIndex++) {
190
+ if (state.offset + 4 > data.length) {
191
+ throw new Error('RadianceHDRLoader: unexpected end of file');
192
+ }
193
+
194
+ const red = data[state.offset++];
195
+ const green = data[state.offset++];
196
+ const blue = data[state.offset++];
197
+ const exponent = data[state.offset++];
198
+
199
+ if (red !== 2 || green !== 2 || ((blue << 8) | exponent) !== scanlineLength) {
200
+ throw new Error('RadianceHDRLoader: bad rgbe scanline format');
201
+ }
202
+
203
+ for (let channelIndex = 0; channelIndex < 4; channelIndex++) {
204
+ const channelOffset = channelIndex * scanlineLength;
205
+ const channelEnd = channelOffset + scanlineLength;
206
+ let pixelOffset = channelOffset;
207
+
208
+ while (pixelOffset < channelEnd) {
209
+ if (state.offset >= data.length) {
210
+ throw new Error('RadianceHDRLoader: unexpected end of file');
211
+ }
212
+
213
+ let count = data[state.offset++];
214
+
215
+ if (count > 128) {
216
+ count -= 128;
217
+ if (count === 0 || pixelOffset + count > channelEnd || state.offset >= data.length) {
218
+ throw new Error('RadianceHDRLoader: bad scanline data');
219
+ }
220
+
221
+ const value = data[state.offset++];
222
+ scanlineBuffer.fill(value, pixelOffset, pixelOffset + count);
223
+ pixelOffset += count;
224
+ continue;
225
+ }
226
+
227
+ if (count === 0 || pixelOffset + count > channelEnd || state.offset + count > data.length) {
228
+ throw new Error('RadianceHDRLoader: bad scanline data');
229
+ }
230
+
231
+ scanlineBuffer.set(data.subarray(state.offset, state.offset + count), pixelOffset);
232
+ pixelOffset += count;
233
+ state.offset += count;
234
+ }
235
+ }
236
+
237
+ for (let pixelIndex = 0; pixelIndex < scanlineLength; pixelIndex++) {
238
+ const outputOffset = getOutputOffset(header, scanlineIndex, pixelIndex);
239
+ pixels[outputOffset] = scanlineBuffer[pixelIndex];
240
+ pixels[outputOffset + 1] = scanlineBuffer[pixelIndex + scanlineLength];
241
+ pixels[outputOffset + 2] = scanlineBuffer[pixelIndex + scanlineLength * 2];
242
+ pixels[outputOffset + 3] = scanlineBuffer[pixelIndex + scanlineLength * 3];
243
+ }
244
+ }
245
+
246
+ return pixels;
247
+ }
248
+
249
+ function reorderPixels(data: Uint8Array, header: HDRHeader): Uint8Array {
250
+ const pixels = new Uint8Array(data.length);
251
+ const scanlineLength = header.minorAxis === 'X' ? header.width : header.height;
252
+ const scanlineCount = header.majorAxis === 'Y' ? header.height : header.width;
253
+
254
+ for (let scanlineIndex = 0; scanlineIndex < scanlineCount; scanlineIndex++) {
255
+ for (let pixelIndex = 0; pixelIndex < scanlineLength; pixelIndex++) {
256
+ const sourceOffset = (scanlineIndex * scanlineLength + pixelIndex) * 4;
257
+ const outputOffset = getOutputOffset(header, scanlineIndex, pixelIndex);
258
+ pixels[outputOffset] = data[sourceOffset];
259
+ pixels[outputOffset + 1] = data[sourceOffset + 1];
260
+ pixels[outputOffset + 2] = data[sourceOffset + 2];
261
+ pixels[outputOffset + 3] = data[sourceOffset + 3];
262
+ }
263
+ }
264
+
265
+ return pixels;
266
+ }
267
+
268
+ function getOutputOffset(header: HDRHeader, scanlineIndex: number, pixelIndex: number): number {
269
+ const majorCoordinate = getCoordinate(
270
+ header.majorAxis === 'X' ? header.width : header.height,
271
+ header.majorSign,
272
+ scanlineIndex
273
+ );
274
+ const minorCoordinate = getCoordinate(
275
+ header.minorAxis === 'X' ? header.width : header.height,
276
+ header.minorSign,
277
+ pixelIndex
278
+ );
279
+ const x = header.majorAxis === 'X' ? majorCoordinate : minorCoordinate;
280
+ const y = header.majorAxis === 'Y' ? majorCoordinate : minorCoordinate;
281
+
282
+ return ((header.height - 1 - y) * header.width + x) * 4;
283
+ }
284
+
285
+ function getCoordinate(length: number, sign: 1 | -1, index: number): number {
286
+ return sign === 1 ? index : length - 1 - index;
287
+ }
288
+
289
+ function readFlatPixels(state: HeaderState, byteLength: number): Uint8Array {
290
+ if (state.offset + byteLength > state.data.length) {
291
+ throw new Error('RadianceHDRLoader: unexpected end of file');
292
+ }
293
+
294
+ const pixels = state.data.slice(state.offset, state.offset + byteLength);
295
+ state.offset += byteLength;
296
+ return pixels;
297
+ }
298
+
299
+ function convertRGBEToFloat(data: Uint8Array): Float32Array {
300
+ const floatData = new Float32Array(data.length);
301
+
302
+ for (let sourceOffset = 0; sourceOffset < data.length; sourceOffset += 4) {
303
+ const exponent = data[sourceOffset + 3];
304
+ const destinationOffset = sourceOffset;
305
+
306
+ if (exponent > 0) {
307
+ const scale = Math.pow(2, exponent - 128) / 255;
308
+ floatData[destinationOffset] = data[sourceOffset] * scale;
309
+ floatData[destinationOffset + 1] = data[sourceOffset + 1] * scale;
310
+ floatData[destinationOffset + 2] = data[sourceOffset + 2] * scale;
311
+ }
312
+
313
+ floatData[destinationOffset + 3] = 1;
314
+ }
315
+
316
+ return floatData;
317
+ }
318
+
319
+ function readLine(state: HeaderState): string | null {
320
+ if (state.offset >= state.data.length) {
321
+ return null;
322
+ }
323
+
324
+ const lineStart = state.offset;
325
+
326
+ while (state.offset < state.data.length) {
327
+ const byte = state.data[state.offset++];
328
+ if (byte === 0x0a) {
329
+ const line = decodeASCII(state.data.subarray(lineStart, state.offset - 1));
330
+ return line.endsWith('\r') ? line.slice(0, -1) : line;
331
+ }
332
+ }
333
+
334
+ const line = decodeASCII(state.data.subarray(lineStart, state.offset));
335
+ return line.endsWith('\r') ? line.slice(0, -1) : line;
336
+ }
337
+
338
+ function decodeASCII(data: Uint8Array): string {
339
+ let line = '';
340
+ for (const byte of data) {
341
+ line += String.fromCharCode(byte);
342
+ }
343
+ return line;
344
+ }
345
+
346
+ function parseMetadataLine(metadata: RadianceHDRMetadata, line: string): void {
347
+ if (line.startsWith('COLORCORR=')) {
348
+ const values = parseNumberList(line.slice('COLORCORR='.length), 3);
349
+ if (values) {
350
+ metadata.colorCorrection = values as [number, number, number];
351
+ }
352
+ return;
353
+ }
354
+
355
+ if (line.startsWith('EXPOSURE=')) {
356
+ const value = parseNumber(line.slice('EXPOSURE='.length));
357
+ if (value !== null) {
358
+ metadata.exposure = value;
359
+ }
360
+ return;
361
+ }
362
+
363
+ if (line.startsWith('GAMMA=')) {
364
+ const value = parseNumber(line.slice('GAMMA='.length));
365
+ if (value !== null) {
366
+ metadata.gamma = value;
367
+ }
368
+ return;
369
+ }
370
+
371
+ if (line.startsWith('PIXASPECT=')) {
372
+ const value = parseNumber(line.slice('PIXASPECT='.length));
373
+ if (value !== null) {
374
+ metadata.pixelAspectRatio = value;
375
+ }
376
+ return;
377
+ }
378
+
379
+ if (line.startsWith('PRIMARIES=')) {
380
+ const values = parseNumberList(line.slice('PRIMARIES='.length), 8);
381
+ if (values) {
382
+ metadata.primaries = values as [
383
+ number,
384
+ number,
385
+ number,
386
+ number,
387
+ number,
388
+ number,
389
+ number,
390
+ number
391
+ ];
392
+ }
393
+ return;
394
+ }
395
+
396
+ if (line.startsWith('SOFTWARE=')) {
397
+ metadata.software = line.slice('SOFTWARE='.length).trim();
398
+ return;
399
+ }
400
+
401
+ if (line.startsWith('VIEW=')) {
402
+ metadata.view = line.slice('VIEW='.length).trim();
403
+ }
404
+ }
405
+
406
+ function parseNumber(text: string): number | null {
407
+ const value = Number(text.trim());
408
+ return Number.isFinite(value) ? value : null;
409
+ }
410
+
411
+ function parseNumberList(text: string, count: number): number[] | null {
412
+ const values = text
413
+ .trim()
414
+ .split(/\s+/)
415
+ .map((value) => Number(value));
416
+
417
+ if (values.length !== count || values.some((value) => !Number.isFinite(value))) {
418
+ return null;
419
+ }
420
+
421
+ return values;
422
+ }
423
+
424
+ function hasMetadata(metadata: RadianceHDRMetadata): boolean {
425
+ return Object.keys(metadata).length > 0;
426
+ }
@@ -3,9 +3,10 @@
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
5
  import type {TextureLevel} from '@loaders.gl/schema';
6
+ import {log} from '@loaders.gl/loader-utils';
6
7
  import {read} from 'ktx-parse';
7
8
  import {extractMipmapImages} from '../utils/extract-mipmap-images';
8
- import {mapVkFormatToWebGL} from '../utils/ktx-format-helper';
9
+ import {mapVkFormatToTextureFormat} from '../utils/ktx-format-helper';
9
10
 
10
11
  const KTX2_ID = [
11
12
  // '´', 'K', 'T', 'X', '2', '0', 'ª', '\r', '\n', '\x1A', '\n'
@@ -40,13 +41,22 @@ export function parseKTX(arrayBuffer: ArrayBuffer): TextureLevel[] {
40
41
  const mipMapLevels = Math.max(1, ktx.levels.length);
41
42
  const width = ktx.pixelWidth;
42
43
  const height = ktx.pixelHeight;
43
- const internalFormat = mapVkFormatToWebGL(ktx.vkFormat);
44
+ const textureFormat = mapVkFormatToTextureFormat(ktx.vkFormat);
45
+
46
+ if (textureFormat === undefined) {
47
+ // TODO: Basis-backed and otherwise unknown-format KTX2 files should preserve the
48
+ // legacy CompressedTextureLoader behavior for now. Do not fail here or add implicit
49
+ // transcoding in this parser path; just return levels without `format` metadata.
50
+ log.warn(
51
+ `KTX2 container vkFormat ${ktx.vkFormat} does not map to a known texture format; returning texture levels without format metadata.`
52
+ )();
53
+ }
44
54
 
45
55
  return extractMipmapImages(ktx.levels, {
46
56
  mipMapLevels,
47
57
  width,
48
58
  height,
49
59
  sizeFunction: (level: any): number => level.uncompressedByteLength,
50
- internalFormat
60
+ textureFormat
51
61
  });
52
62
  }
@@ -6,8 +6,7 @@
6
6
  // Forked from PicoGL: https://github.com/tsherif/picogl.js/blob/master/examples/utils/utils.js
7
7
  // Copyright (c) 2017 Tarek Sherif, The MIT License (MIT)
8
8
 
9
- import type {TextureLevel} from '@loaders.gl/schema';
10
- import {GL_EXTENSIONS_CONSTANTS} from '../gl-extensions';
9
+ import type {TextureFormat, TextureLevel} from '@loaders.gl/schema';
11
10
  import {extractMipmapImages} from '../utils/extract-mipmap-images';
12
11
 
13
12
  const PVR_CONSTANTS: Record<string, number> = {
@@ -24,76 +23,34 @@ const PVR_CONSTANTS: Record<string, number> = {
24
23
  METADATA_SIZE_INDEX: 12
25
24
  };
26
25
 
27
- const PVR_PIXEL_FORMATS: Record<number, number[]> = {
28
- 0: [GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGB_PVRTC_2BPPV1_IMG],
29
- 1: [GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG],
30
- 2: [GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGB_PVRTC_4BPPV1_IMG],
31
- 3: [GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG],
32
- 6: [GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGB_ETC1_WEBGL],
33
- 7: [GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGB_S3TC_DXT1_EXT],
34
- 9: [GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_S3TC_DXT3_EXT],
35
- 11: [GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_S3TC_DXT5_EXT],
36
- 22: [GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGB8_ETC2],
37
- 23: [GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA8_ETC2_EAC],
38
- 24: [GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2],
39
- 25: [GL_EXTENSIONS_CONSTANTS.COMPRESSED_R11_EAC],
40
- 26: [GL_EXTENSIONS_CONSTANTS.COMPRESSED_RG11_EAC],
41
- 27: [
42
- GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_ASTC_4X4_KHR,
43
- GL_EXTENSIONS_CONSTANTS.COMPRESSED_SRGB8_ALPHA8_ASTC_4X4_KHR
44
- ],
45
- 28: [
46
- GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_ASTC_5X4_KHR,
47
- GL_EXTENSIONS_CONSTANTS.COMPRESSED_SRGB8_ALPHA8_ASTC_5X4_KHR
48
- ],
49
- 29: [
50
- GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_ASTC_5X5_KHR,
51
- GL_EXTENSIONS_CONSTANTS.COMPRESSED_SRGB8_ALPHA8_ASTC_5X5_KHR
52
- ],
53
- 30: [
54
- GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_ASTC_6X5_KHR,
55
- GL_EXTENSIONS_CONSTANTS.COMPRESSED_SRGB8_ALPHA8_ASTC_6X5_KHR
56
- ],
57
- 31: [
58
- GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_ASTC_6X6_KHR,
59
- GL_EXTENSIONS_CONSTANTS.COMPRESSED_SRGB8_ALPHA8_ASTC_6X6_KHR
60
- ],
61
- 32: [
62
- GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_ASTC_8X5_KHR,
63
- GL_EXTENSIONS_CONSTANTS.COMPRESSED_SRGB8_ALPHA8_ASTC_8X5_KHR
64
- ],
65
- 33: [
66
- GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_ASTC_8X6_KHR,
67
- GL_EXTENSIONS_CONSTANTS.COMPRESSED_SRGB8_ALPHA8_ASTC_8X6_KHR
68
- ],
69
- 34: [
70
- GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_ASTC_8X8_KHR,
71
- GL_EXTENSIONS_CONSTANTS.COMPRESSED_SRGB8_ALPHA8_ASTC_8X8_KHR
72
- ],
73
- 35: [
74
- GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_ASTC_10X5_KHR,
75
- GL_EXTENSIONS_CONSTANTS.COMPRESSED_SRGB8_ALPHA8_ASTC_10X5_KHR
76
- ],
77
- 36: [
78
- GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_ASTC_10X6_KHR,
79
- GL_EXTENSIONS_CONSTANTS.COMPRESSED_SRGB8_ALPHA8_ASTC_10X6_KHR
80
- ],
81
- 37: [
82
- GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_ASTC_10X8_KHR,
83
- GL_EXTENSIONS_CONSTANTS.COMPRESSED_SRGB8_ALPHA8_ASTC_10X8_KHR
84
- ],
85
- 38: [
86
- GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_ASTC_10X10_KHR,
87
- GL_EXTENSIONS_CONSTANTS.COMPRESSED_SRGB8_ALPHA8_ASTC_10X10_KHR
88
- ],
89
- 39: [
90
- GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_ASTC_12X10_KHR,
91
- GL_EXTENSIONS_CONSTANTS.COMPRESSED_SRGB8_ALPHA8_ASTC_12X10_KHR
92
- ],
93
- 40: [
94
- GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_ASTC_12X12_KHR,
95
- GL_EXTENSIONS_CONSTANTS.COMPRESSED_SRGB8_ALPHA8_ASTC_12X12_KHR
96
- ]
26
+ const PVR_TEXTURE_FORMATS: Record<number, TextureFormat[]> = {
27
+ 0: ['pvrtc-rgb2unorm-webgl'],
28
+ 1: ['pvrtc-rgba2unorm-webgl'],
29
+ 2: ['pvrtc-rgb4unorm-webgl'],
30
+ 3: ['pvrtc-rgba4unorm-webgl'],
31
+ 6: ['etc1-rgb-unorm-webgl'],
32
+ 7: ['bc1-rgb-unorm-webgl'],
33
+ 9: ['bc2-rgba-unorm'],
34
+ 11: ['bc3-rgba-unorm'],
35
+ 22: ['etc2-rgb8unorm'],
36
+ 23: ['etc2-rgba8unorm'],
37
+ 24: ['etc2-rgb8a1unorm'],
38
+ 25: ['eac-r11unorm'],
39
+ 26: ['eac-rg11unorm'],
40
+ 27: ['astc-4x4-unorm', 'astc-4x4-unorm-srgb'],
41
+ 28: ['astc-5x4-unorm', 'astc-5x4-unorm-srgb'],
42
+ 29: ['astc-5x5-unorm', 'astc-5x5-unorm-srgb'],
43
+ 30: ['astc-6x5-unorm', 'astc-6x5-unorm-srgb'],
44
+ 31: ['astc-6x6-unorm', 'astc-6x6-unorm-srgb'],
45
+ 32: ['astc-8x5-unorm', 'astc-8x5-unorm-srgb'],
46
+ 33: ['astc-8x6-unorm', 'astc-8x6-unorm-srgb'],
47
+ 34: ['astc-8x8-unorm', 'astc-8x8-unorm-srgb'],
48
+ 35: ['astc-10x5-unorm', 'astc-10x5-unorm-srgb'],
49
+ 36: ['astc-10x6-unorm', 'astc-10x6-unorm-srgb'],
50
+ 37: ['astc-10x8-unorm', 'astc-10x8-unorm-srgb'],
51
+ 38: ['astc-10x10-unorm', 'astc-10x10-unorm-srgb'],
52
+ 39: ['astc-12x10-unorm', 'astc-12x10-unorm-srgb'],
53
+ 40: ['astc-12x12-unorm', 'astc-12x12-unorm-srgb']
97
54
  };
98
55
 
99
56
  const PVR_SIZE_FUNCTIONS: Record<number, (width: number, height: number) => number> = {
@@ -149,8 +106,9 @@ export function parsePVR(data: ArrayBuffer): TextureLevel[] {
149
106
 
150
107
  const pvrFormat = header[PVR_CONSTANTS.PIXEL_FORMAT_INDEX];
151
108
  const colourSpace = header[PVR_CONSTANTS.COLOUR_SPACE_INDEX];
152
- const pixelFormats = PVR_PIXEL_FORMATS[pvrFormat] || [];
153
- const internalFormat = pixelFormats.length > 1 && colourSpace ? pixelFormats[1] : pixelFormats[0];
109
+ const textureFormats = PVR_TEXTURE_FORMATS[pvrFormat] || [];
110
+ const textureFormat =
111
+ textureFormats.length > 1 && colourSpace ? textureFormats[1] : textureFormats[0];
154
112
 
155
113
  const sizeFunction = PVR_SIZE_FUNCTIONS[pvrFormat];
156
114
 
@@ -168,7 +126,7 @@ export function parsePVR(data: ArrayBuffer): TextureLevel[] {
168
126
  width,
169
127
  height,
170
128
  sizeFunction,
171
- internalFormat
129
+ textureFormat
172
130
  });
173
131
  }
174
132
 
@@ -2,23 +2,13 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
- import {resolvePath} from '@loaders.gl/loader-utils';
6
5
  import type {GetUrl, UrlOptions} from './texture-api-types';
7
6
 
8
- // Generate a url by calling getUrl with mix of options, applying options.baseUrl
7
+ // Generate a member url by calling getUrl with merged options.
9
8
  export function generateUrl(
10
9
  getUrl: string | GetUrl,
11
10
  options: UrlOptions,
12
11
  urlOptions: Record<string, any>
13
12
  ): string {
14
- // Get url
15
- let url = typeof getUrl === 'function' ? getUrl({...options, ...urlOptions}) : getUrl;
16
-
17
- // Apply options.baseUrl
18
- const baseUrl = options.baseUrl;
19
- if (baseUrl) {
20
- url = baseUrl[baseUrl.length - 1] === '/' ? `${baseUrl}${url}` : `${baseUrl}/${url}`;
21
- }
22
-
23
- return resolvePath(url);
13
+ return typeof getUrl === 'function' ? getUrl({...options, ...urlOptions}) : getUrl;
24
14
  }
@@ -2,21 +2,30 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
- import {ImageLoader} from '@loaders.gl/images';
6
- import type {GetUrl} from './texture-api-types';
5
+ import {
6
+ loadCompositeImageUrlTree,
7
+ normalizeCompositeImageOptions
8
+ } from '../composite-image/parse-composite-image';
9
+ import type {GetUrl, TextureLoaderOptions} from './texture-api-types';
7
10
  import {getImageUrls} from './load-image';
8
- import {deepLoad} from './deep-load';
9
11
 
12
+ /**
13
+ * @deprecated Use `load(url, TextureArrayLoader)` for manifest-driven loading.
14
+ */
10
15
  export async function loadImageTextureArray(
11
16
  count: number,
12
17
  getUrl: GetUrl,
13
- options = {}
18
+ options: TextureLoaderOptions = {}
14
19
  ): Promise<any> {
15
20
  const imageUrls = await getImageArrayUrls(count, getUrl, options);
16
- return await deepLoad(imageUrls, ImageLoader.parse, options);
21
+ return await loadCompositeImageUrlTree(imageUrls, normalizeCompositeImageOptions(options));
17
22
  }
18
23
 
19
- export async function getImageArrayUrls(count: number, getUrl: GetUrl, options = {}): Promise<any> {
24
+ export async function getImageArrayUrls(
25
+ count: number,
26
+ getUrl: GetUrl,
27
+ options: TextureLoaderOptions = {}
28
+ ): Promise<any> {
20
29
  const promises: Promise<any>[] = [];
21
30
  for (let index = 0; index < count; index++) {
22
31
  const promise = getImageUrls(getUrl, options, {index});