@driftengine/assets 3.61.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 (100) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +9 -0
  3. package/README.md +9 -0
  4. package/dist/assetPath.d.ts +51 -0
  5. package/dist/assetPath.js +59 -0
  6. package/dist/coarseLevel.d.ts +94 -0
  7. package/dist/coarseLevel.js +606 -0
  8. package/dist/dds.d.ts +41 -0
  9. package/dist/dds.js +425 -0
  10. package/dist/drawKey.d.ts +64 -0
  11. package/dist/drawKey.js +42 -0
  12. package/dist/drftLoader.d.ts +420 -0
  13. package/dist/drftLoader.js +996 -0
  14. package/dist/drftTextures.d.ts +87 -0
  15. package/dist/drftTextures.js +138 -0
  16. package/dist/fbx.d.ts +86 -0
  17. package/dist/fbx.js +792 -0
  18. package/dist/fbxHarness.d.ts +68 -0
  19. package/dist/fbxHarness.js +185 -0
  20. package/dist/fbxInflate.d.ts +60 -0
  21. package/dist/fbxInflate.js +204 -0
  22. package/dist/fbxMaterial.d.ts +87 -0
  23. package/dist/fbxMaterial.js +345 -0
  24. package/dist/fbxRig.d.ts +130 -0
  25. package/dist/fbxRig.js +601 -0
  26. package/dist/gltf.d.ts +242 -0
  27. package/dist/gltf.js +904 -0
  28. package/dist/gltfAccessor.d.ts +2 -0
  29. package/dist/gltfAccessor.js +106 -0
  30. package/dist/gltfSkin.d.ts +32 -0
  31. package/dist/gltfSkin.js +144 -0
  32. package/dist/iesPhotometry.d.ts +44 -0
  33. package/dist/iesPhotometry.js +94 -0
  34. package/dist/imageInfo.d.ts +31 -0
  35. package/dist/imageInfo.js +119 -0
  36. package/dist/index.d.ts +58 -0
  37. package/dist/index.js +132 -0
  38. package/dist/kn5.d.ts +158 -0
  39. package/dist/kn5.js +557 -0
  40. package/dist/loadProgress.d.ts +118 -0
  41. package/dist/loadProgress.js +1 -0
  42. package/dist/localise.d.ts +35 -0
  43. package/dist/localise.js +253 -0
  44. package/dist/obj.d.ts +54 -0
  45. package/dist/obj.js +335 -0
  46. package/dist/orient.d.ts +104 -0
  47. package/dist/orient.js +241 -0
  48. package/dist/radianceHdr.d.ts +36 -0
  49. package/dist/radianceHdr.js +172 -0
  50. package/dist/readModel.d.ts +153 -0
  51. package/dist/readModel.js +386 -0
  52. package/dist/recognise.d.ts +38 -0
  53. package/dist/recognise.js +97 -0
  54. package/dist/stl.d.ts +22 -0
  55. package/dist/stl.js +131 -0
  56. package/dist/tangentOrder.d.ts +24 -0
  57. package/dist/tangentOrder.js +31 -0
  58. package/dist/threemf.d.ts +46 -0
  59. package/dist/threemf.js +254 -0
  60. package/dist/uploadBudget.d.ts +82 -0
  61. package/dist/uploadBudget.js +86 -0
  62. package/dist/usd.d.ts +49 -0
  63. package/dist/usd.js +542 -0
  64. package/dist/weld.d.ts +44 -0
  65. package/dist/weld.js +237 -0
  66. package/dist/zip.d.ts +35 -0
  67. package/dist/zip.js +110 -0
  68. package/package.json +61 -0
  69. package/src/assetPath.ts +79 -0
  70. package/src/coarseLevel.ts +720 -0
  71. package/src/dds.ts +507 -0
  72. package/src/drawKey.ts +91 -0
  73. package/src/drftLoader.ts +1197 -0
  74. package/src/drftTextures.ts +153 -0
  75. package/src/fbx.ts +934 -0
  76. package/src/fbxHarness.ts +215 -0
  77. package/src/fbxInflate.ts +258 -0
  78. package/src/fbxMaterial.ts +410 -0
  79. package/src/fbxRig.ts +652 -0
  80. package/src/gltf.ts +1161 -0
  81. package/src/gltfAccessor.ts +127 -0
  82. package/src/gltfSkin.ts +210 -0
  83. package/src/iesPhotometry.ts +136 -0
  84. package/src/imageInfo.ts +130 -0
  85. package/src/index.ts +162 -0
  86. package/src/kn5.ts +705 -0
  87. package/src/loadProgress.ts +131 -0
  88. package/src/localise.ts +275 -0
  89. package/src/obj.ts +386 -0
  90. package/src/orient.ts +262 -0
  91. package/src/radianceHdr.ts +195 -0
  92. package/src/readModel.ts +515 -0
  93. package/src/recognise.ts +124 -0
  94. package/src/stl.ts +147 -0
  95. package/src/tangentOrder.ts +32 -0
  96. package/src/threemf.ts +303 -0
  97. package/src/uploadBudget.ts +90 -0
  98. package/src/usd.ts +642 -0
  99. package/src/weld.ts +264 -0
  100. package/src/zip.ts +130 -0
@@ -0,0 +1,195 @@
1
+ /** The Radiance `.hdr` container (RGBE), decoded to linear floats. */
2
+
3
+ /**
4
+ * An equirectangular image, linear, three floats a texel, row 0 at the top.
5
+ *
6
+ * Three rather than four because an environment has no alpha and never will: the fourth channel
7
+ * would be a byte a texel of ones, and at 2048x1024 that is eight megabytes of nothing.
8
+ */
9
+ export interface RadianceImage {
10
+ readonly width: number;
11
+ readonly height: number;
12
+ /** `width * height * 3` linear values, row-major from the top. */
13
+ readonly data: Float32Array;
14
+ }
15
+
16
+ /**
17
+ * Where a decoded byte sits inside its bucket.
18
+ *
19
+ * Radiance's own `colr_color` is `ldexp(mantissa + 0.5, exponent - (128 + 8))`, and the half is
20
+ * the part every reimplementation drops. Dropping it makes an image about 0.2% dark, which is
21
+ * invisible on its own, survives every eyeball comparison, and is exactly the kind of thing that
22
+ * is never found. It is written as a named constant so that nobody removes it as a typo.
23
+ */
24
+ const BUCKET_CENTRE = 0.5;
25
+
26
+ /** `2^-(128 + 8)`, the scale a stored exponent of zero would otherwise land on. */
27
+ const EXPONENT_BIAS = 128 + 8;
28
+
29
+ /**
30
+ * Read a Radiance RGBE file into linear radiance.
31
+ *
32
+ * **Pure, and it takes bytes rather than a URL.** It knows nothing about a device, a fetch or a
33
+ * texture, which is what lets it be tested exactly and what keeps the fetching decision — cache
34
+ * headers, retries, where the file lives — with the consumer who has to make it.
35
+ *
36
+ * **Both scanline encodings, because only one of them is optional in practice.** A file narrower
37
+ * than 8 or wider than 0x7fff stores flat RGBE quadruples; everything else is new-style
38
+ * run-length, and that is every environment map anybody actually has. A decoder that handles only
39
+ * the flat path passes a hand-built test and fails on every real file.
40
+ *
41
+ * **Every refusal names what it found.** `AGENTS.md` requires failing loudly at load with an
42
+ * actionable message: a decoder that quietly answers black for a header it does not recognise
43
+ * hands a scene an environment of nothing, which is indistinguishable from a probe that has not
44
+ * baked yet and is diagnosed as the renderer's fault.
45
+ *
46
+ * **What it costs** is `width * height * 12` bytes for the result, which at 2048x1024 is 25 MB
47
+ * held while the faces are built. **What would make it wrong** is a consumer streaming an
48
+ * environment larger than memory; this reads whole files, and a tiled format is what that consumer
49
+ * wants — which is one of the reasons KTX2 is named and deliberately not taken.
50
+ */
51
+ export function readRadianceHdr(bytes: Uint8Array): RadianceImage {
52
+ const signature = readLine(bytes, 0);
53
+ if (!signature.text.startsWith('#?RADIANCE') && !signature.text.startsWith('#?RGBE')) {
54
+ throw new Error(
55
+ `readRadianceHdr: not a Radiance file — expected a "#?RADIANCE" signature, found ` +
56
+ `"${signature.text.slice(0, 20)}"`,
57
+ );
58
+ }
59
+
60
+ let at = signature.next;
61
+ let format: string | null = null;
62
+ /* The header runs to a blank line, and the resolution line is the one after it. */
63
+ for (;;) {
64
+ const line = readLine(bytes, at);
65
+ at = line.next;
66
+ if (line.text === '') break;
67
+ if (line.text.startsWith('FORMAT=')) format = line.text.slice('FORMAT='.length).trim();
68
+ if (at >= bytes.length) throw new Error('readRadianceHdr: the header never ended');
69
+ }
70
+
71
+ if (format !== null && format !== '32-bit_rle_rgbe') {
72
+ throw new Error(
73
+ `readRadianceHdr: only 32-bit_rle_rgbe is decoded here, and this file declares ` +
74
+ `"${format}". An XYZE file carries CIE primaries rather than RGB and converting it is a ` +
75
+ 'colour decision rather than a decoding one.',
76
+ );
77
+ }
78
+
79
+ const resolution = readLine(bytes, at);
80
+ at = resolution.next;
81
+ /*
82
+ * `-Y height +X width` only. Radiance permits eight orientations, six of which nothing has
83
+ * produced in decades, and treating one as another silently returns an image that is flipped —
84
+ * which in an environment map puts the sky underfoot and is the most confusing available failure.
85
+ */
86
+ const match = /^-Y\s+(\d+)\s+\+X\s+(\d+)$/.exec(resolution.text.trim());
87
+ if (match === null) {
88
+ throw new Error(
89
+ `readRadianceHdr: only "-Y height +X width" is handled, and this file says ` +
90
+ `"${resolution.text.trim()}". Any other orientation would decode to a flipped image.`,
91
+ );
92
+ }
93
+ const height = Number(match[1]);
94
+ const width = Number(match[2]);
95
+ if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {
96
+ throw new Error(`readRadianceHdr: a ${width} by ${height} image is not decodable`);
97
+ }
98
+
99
+ const data = new Float32Array(width * height * 3);
100
+ /* One scanline of RGBE, reused, because a 2048-wide image would otherwise allocate per row. */
101
+ const scanline = new Uint8Array(width * 4);
102
+
103
+ for (let y = 0; y < height; y++) {
104
+ at = readScanline(bytes, at, scanline, width);
105
+ for (let x = 0; x < width; x++) {
106
+ const exponent = scanline[x * 4 + 3] ?? 0;
107
+ const out = (y * width + x) * 3;
108
+ /*
109
+ * A stored exponent of zero is exactly black and Radiance reserves it for that. Running it
110
+ * through the same arithmetic gives `0.5 * 2^-136`: denormal, nonzero, and enough to make
111
+ * every black texel of a night sky something a prefilter will average into a grey haze.
112
+ */
113
+ if (exponent === 0) {
114
+ data[out] = 0;
115
+ data[out + 1] = 0;
116
+ data[out + 2] = 0;
117
+ continue;
118
+ }
119
+ const scale = 2 ** (exponent - EXPONENT_BIAS);
120
+ data[out] = ((scanline[x * 4] ?? 0) + BUCKET_CENTRE) * scale;
121
+ data[out + 1] = ((scanline[x * 4 + 1] ?? 0) + BUCKET_CENTRE) * scale;
122
+ data[out + 2] = ((scanline[x * 4 + 2] ?? 0) + BUCKET_CENTRE) * scale;
123
+ }
124
+ }
125
+
126
+ return { width, height, data };
127
+ }
128
+
129
+ /** One newline-terminated line as text, and where the next one starts. */
130
+ function readLine(bytes: Uint8Array, from: number): { text: string; next: number } {
131
+ let end = from;
132
+ while (end < bytes.length && bytes[end] !== 0x0a) end++;
133
+ let text = '';
134
+ for (let i = from; i < end; i++) text += String.fromCharCode(bytes[i] ?? 0);
135
+ return { text: text.replace(/\r$/, ''), next: end + 1 };
136
+ }
137
+
138
+ /**
139
+ * One scanline of RGBE into `out`, in either encoding, returning where the next one starts.
140
+ *
141
+ * The new-style marker is `2, 2, hi, lo` with `hi<<8 | lo` equal to the width. That third and
142
+ * fourth byte being the width is what distinguishes it from an old-style scanline whose first
143
+ * pixel happens to be `(2, 2, ...)`, which is a real colour and does occur.
144
+ */
145
+ function readScanline(bytes: Uint8Array, from: number, out: Uint8Array, width: number): number {
146
+ const declared = ((bytes[from + 2] ?? 0) << 8) | (bytes[from + 3] ?? 0);
147
+ const isRle =
148
+ width >= 8 &&
149
+ width < 0x8000 &&
150
+ bytes[from] === 2 &&
151
+ bytes[from + 1] === 2 &&
152
+ declared === width;
153
+
154
+ if (!isRle) {
155
+ /* Flat quadruples, which is what a narrow image and an old encoder both produce. */
156
+ for (let x = 0; x < width; x++) {
157
+ out[x * 4] = bytes[from + x * 4] ?? 0;
158
+ out[x * 4 + 1] = bytes[from + x * 4 + 1] ?? 0;
159
+ out[x * 4 + 2] = bytes[from + x * 4 + 2] ?? 0;
160
+ out[x * 4 + 3] = bytes[from + x * 4 + 3] ?? 0;
161
+ }
162
+ return from + width * 4;
163
+ }
164
+
165
+ let at = from + 4;
166
+ /*
167
+ * The four channels are stored one after another rather than interleaved, which is the whole
168
+ * reason this encoding compresses: a sky's red channel is a smooth ramp and its exponent channel
169
+ * is nearly constant, and neither is compressible while they are interleaved with the others.
170
+ */
171
+ for (let channel = 0; channel < 4; channel++) {
172
+ let x = 0;
173
+ while (x < width) {
174
+ const count = bytes[at] ?? 0;
175
+ at++;
176
+ if (count > 128) {
177
+ /* A run: repeat the next byte this many times, minus the flag bit. */
178
+ const value = bytes[at] ?? 0;
179
+ at++;
180
+ const run = count - 128;
181
+ if (x + run > width) throw new Error('readRadianceHdr: a run overran its scanline');
182
+ for (let i = 0; i < run; i++) out[(x + i) * 4 + channel] = value;
183
+ x += run;
184
+ } else {
185
+ if (count === 0) throw new Error('readRadianceHdr: a zero-length literal run');
186
+ if (x + count > width)
187
+ throw new Error('readRadianceHdr: a literal run overran its scanline');
188
+ for (let i = 0; i < count; i++) out[(x + i) * 4 + channel] = bytes[at + i] ?? 0;
189
+ at += count;
190
+ x += count;
191
+ }
192
+ }
193
+ }
194
+ return at;
195
+ }