hdr-canvas 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hdr-canvas.js +289 -8
- package/dist/hdr-canvas.js.map +1 -1
- package/dist/hdr-canvas.min.js +1 -1
- package/dist/hdr-canvas.min.js.map +1 -1
- package/dist/hdr-canvas.umd.js +289 -8
- package/dist/hdr-canvas.umd.js.map +1 -1
- package/docs/release-notes-0.1.2.md +16 -0
- package/package.json +3 -2
- package/scripts/check.sh +1 -0
- package/src/Float16Image.ts +20 -7
- package/src/Uint16Image.ts +1 -0
- package/src/hdr-canvas.ts +5 -2
- package/src/types/HDRCanvas.d.ts +5 -0
- package/three/HDRWebGPUBackend.js +1 -0
- package/three/HDRWebGPURenderer.js +1 -0
package/dist/hdr-canvas.js
CHANGED
|
@@ -5902,6 +5902,283 @@ class Uint16Image extends HDRImage {
|
|
|
5902
5902
|
}
|
|
5903
5903
|
}
|
|
5904
5904
|
|
|
5905
|
+
/* eslint-disable no-restricted-globals, no-restricted-syntax */
|
|
5906
|
+
/* global SharedArrayBuffer */
|
|
5907
|
+
|
|
5908
|
+
|
|
5909
|
+
/** @type {<T extends (...args: any) => any>(target: T) => (thisArg: ThisType<T>, ...args: any[]) => any} */
|
|
5910
|
+
function uncurryThis(target) {
|
|
5911
|
+
return (thisArg, ...args) => {
|
|
5912
|
+
return ReflectApply(target, thisArg, args);
|
|
5913
|
+
};
|
|
5914
|
+
}
|
|
5915
|
+
|
|
5916
|
+
/** @type {(target: any, key: string | symbol) => (thisArg: any, ...args: any[]) => any} */
|
|
5917
|
+
function uncurryThisGetter(target, key) {
|
|
5918
|
+
return uncurryThis(
|
|
5919
|
+
ReflectGetOwnPropertyDescriptor(
|
|
5920
|
+
target,
|
|
5921
|
+
key
|
|
5922
|
+
).get
|
|
5923
|
+
);
|
|
5924
|
+
}
|
|
5925
|
+
|
|
5926
|
+
// Reflect
|
|
5927
|
+
const {
|
|
5928
|
+
apply: ReflectApply,
|
|
5929
|
+
getOwnPropertyDescriptor: ReflectGetOwnPropertyDescriptor,
|
|
5930
|
+
getPrototypeOf: ReflectGetPrototypeOf} = Reflect;
|
|
5931
|
+
|
|
5932
|
+
// Number
|
|
5933
|
+
const {
|
|
5934
|
+
EPSILON,
|
|
5935
|
+
isFinite: NumberIsFinite,
|
|
5936
|
+
isNaN: NumberIsNaN,
|
|
5937
|
+
} = Number;
|
|
5938
|
+
|
|
5939
|
+
// Symbol
|
|
5940
|
+
const {
|
|
5941
|
+
iterator: SymbolIterator,
|
|
5942
|
+
toStringTag: SymbolToStringTag} = Symbol;
|
|
5943
|
+
|
|
5944
|
+
// Math
|
|
5945
|
+
const {
|
|
5946
|
+
abs: MathAbs} = Math;
|
|
5947
|
+
|
|
5948
|
+
// ArrayBuffer
|
|
5949
|
+
const NativeArrayBuffer = ArrayBuffer;
|
|
5950
|
+
const ArrayBufferPrototype = NativeArrayBuffer.prototype;
|
|
5951
|
+
/** @type {(buffer: ArrayBuffer) => ArrayBuffer} */
|
|
5952
|
+
uncurryThisGetter(ArrayBufferPrototype, "byteLength");
|
|
5953
|
+
|
|
5954
|
+
// SharedArrayBuffer
|
|
5955
|
+
const NativeSharedArrayBuffer = typeof SharedArrayBuffer !== "undefined" ? SharedArrayBuffer : null;
|
|
5956
|
+
/** @type {(buffer: SharedArrayBuffer) => SharedArrayBuffer} */
|
|
5957
|
+
NativeSharedArrayBuffer
|
|
5958
|
+
&& uncurryThisGetter(NativeSharedArrayBuffer.prototype, "byteLength");
|
|
5959
|
+
|
|
5960
|
+
// TypedArray
|
|
5961
|
+
/** @typedef {Uint8Array|Uint8ClampedArray|Uint16Array|Uint32Array|Int8Array|Int16Array|Int32Array|Float32Array|Float64Array|BigUint64Array|BigInt64Array} TypedArray */
|
|
5962
|
+
/** @type {any} */
|
|
5963
|
+
const TypedArray = ReflectGetPrototypeOf(Uint8Array);
|
|
5964
|
+
TypedArray.from;
|
|
5965
|
+
const TypedArrayPrototype = TypedArray.prototype;
|
|
5966
|
+
TypedArrayPrototype[SymbolIterator];
|
|
5967
|
+
/** @type {(typedArray: TypedArray) => IterableIterator<number>} */
|
|
5968
|
+
uncurryThis(TypedArrayPrototype.keys);
|
|
5969
|
+
/** @type {(typedArray: TypedArray) => IterableIterator<number>} */
|
|
5970
|
+
uncurryThis(
|
|
5971
|
+
TypedArrayPrototype.values
|
|
5972
|
+
);
|
|
5973
|
+
/** @type {(typedArray: TypedArray) => IterableIterator<[number, number]>} */
|
|
5974
|
+
uncurryThis(
|
|
5975
|
+
TypedArrayPrototype.entries
|
|
5976
|
+
);
|
|
5977
|
+
/** @type {(typedArray: TypedArray, array: ArrayLike<number>, offset?: number) => void} */
|
|
5978
|
+
uncurryThis(TypedArrayPrototype.set);
|
|
5979
|
+
/** @type {<T extends TypedArray>(typedArray: T) => T} */
|
|
5980
|
+
uncurryThis(
|
|
5981
|
+
TypedArrayPrototype.reverse
|
|
5982
|
+
);
|
|
5983
|
+
/** @type {<T extends TypedArray>(typedArray: T, value: number, start?: number, end?: number) => T} */
|
|
5984
|
+
uncurryThis(TypedArrayPrototype.fill);
|
|
5985
|
+
/** @type {<T extends TypedArray>(typedArray: T, target: number, start: number, end?: number) => T} */
|
|
5986
|
+
uncurryThis(
|
|
5987
|
+
TypedArrayPrototype.copyWithin
|
|
5988
|
+
);
|
|
5989
|
+
/** @type {<T extends TypedArray>(typedArray: T, compareFn?: (a: number, b: number) => number) => T} */
|
|
5990
|
+
uncurryThis(TypedArrayPrototype.sort);
|
|
5991
|
+
/** @type {<T extends TypedArray>(typedArray: T, start?: number, end?: number) => T} */
|
|
5992
|
+
uncurryThis(TypedArrayPrototype.slice);
|
|
5993
|
+
/** @type {<T extends TypedArray>(typedArray: T, start?: number, end?: number) => T} */
|
|
5994
|
+
uncurryThis(
|
|
5995
|
+
TypedArrayPrototype.subarray
|
|
5996
|
+
);
|
|
5997
|
+
/** @type {((typedArray: TypedArray) => ArrayBuffer)} */
|
|
5998
|
+
uncurryThisGetter(
|
|
5999
|
+
TypedArrayPrototype,
|
|
6000
|
+
"buffer"
|
|
6001
|
+
);
|
|
6002
|
+
/** @type {((typedArray: TypedArray) => number)} */
|
|
6003
|
+
uncurryThisGetter(
|
|
6004
|
+
TypedArrayPrototype,
|
|
6005
|
+
"byteOffset"
|
|
6006
|
+
);
|
|
6007
|
+
/** @type {((typedArray: TypedArray) => number)} */
|
|
6008
|
+
uncurryThisGetter(
|
|
6009
|
+
TypedArrayPrototype,
|
|
6010
|
+
"length"
|
|
6011
|
+
);
|
|
6012
|
+
/** @type {(target: unknown) => string} */
|
|
6013
|
+
uncurryThisGetter(
|
|
6014
|
+
TypedArrayPrototype,
|
|
6015
|
+
SymbolToStringTag
|
|
6016
|
+
);
|
|
6017
|
+
|
|
6018
|
+
// Uint8Array
|
|
6019
|
+
const NativeUint8Array = Uint8Array;
|
|
6020
|
+
|
|
6021
|
+
// Uint16Array
|
|
6022
|
+
const NativeUint16Array = Uint16Array;
|
|
6023
|
+
|
|
6024
|
+
// Uint32Array
|
|
6025
|
+
const NativeUint32Array = Uint32Array;
|
|
6026
|
+
|
|
6027
|
+
// ArrayIterator
|
|
6028
|
+
/** @type {any} */
|
|
6029
|
+
const ArrayIteratorPrototype = ReflectGetPrototypeOf([][SymbolIterator]());
|
|
6030
|
+
/** @type {<T>(arrayIterator: IterableIterator<T>) => IteratorResult<T>} */
|
|
6031
|
+
uncurryThis(ArrayIteratorPrototype.next);
|
|
6032
|
+
|
|
6033
|
+
// Generator
|
|
6034
|
+
/** @type {<T = unknown, TReturn = any, TNext = unknown>(generator: Generator<T, TReturn, TNext>, value?: TNext) => T} */
|
|
6035
|
+
uncurryThis((function* () {})().next);
|
|
6036
|
+
|
|
6037
|
+
// Iterator
|
|
6038
|
+
ReflectGetPrototypeOf(ArrayIteratorPrototype);
|
|
6039
|
+
|
|
6040
|
+
const INVERSE_OF_EPSILON = 1 / EPSILON;
|
|
6041
|
+
|
|
6042
|
+
/**
|
|
6043
|
+
* rounds to the nearest value;
|
|
6044
|
+
* if the number falls midway, it is rounded to the nearest value with an even least significant digit
|
|
6045
|
+
* @param {number} num
|
|
6046
|
+
* @returns {number}
|
|
6047
|
+
*/
|
|
6048
|
+
function roundTiesToEven(num) {
|
|
6049
|
+
return (num + INVERSE_OF_EPSILON) - INVERSE_OF_EPSILON;
|
|
6050
|
+
}
|
|
6051
|
+
|
|
6052
|
+
const FLOAT16_MIN_VALUE = 6.103515625e-05;
|
|
6053
|
+
const FLOAT16_MAX_VALUE = 65504;
|
|
6054
|
+
const FLOAT16_EPSILON = 0.0009765625;
|
|
6055
|
+
|
|
6056
|
+
const FLOAT16_EPSILON_MULTIPLIED_BY_FLOAT16_MIN_VALUE = FLOAT16_EPSILON * FLOAT16_MIN_VALUE;
|
|
6057
|
+
const FLOAT16_EPSILON_DEVIDED_BY_EPSILON = FLOAT16_EPSILON * INVERSE_OF_EPSILON;
|
|
6058
|
+
|
|
6059
|
+
/**
|
|
6060
|
+
* round a number to a half float number
|
|
6061
|
+
* @param {unknown} num - double float
|
|
6062
|
+
* @returns {number} half float number
|
|
6063
|
+
*/
|
|
6064
|
+
function roundToFloat16(num) {
|
|
6065
|
+
const number = +num;
|
|
6066
|
+
|
|
6067
|
+
// NaN, Infinity, -Infinity, 0, -0
|
|
6068
|
+
if (!NumberIsFinite(number) || number === 0) {
|
|
6069
|
+
return number;
|
|
6070
|
+
}
|
|
6071
|
+
|
|
6072
|
+
// finite except 0, -0
|
|
6073
|
+
const sign = number > 0 ? 1 : -1;
|
|
6074
|
+
const absolute = MathAbs(number);
|
|
6075
|
+
|
|
6076
|
+
// small number
|
|
6077
|
+
if (absolute < FLOAT16_MIN_VALUE) {
|
|
6078
|
+
return sign * roundTiesToEven(absolute / FLOAT16_EPSILON_MULTIPLIED_BY_FLOAT16_MIN_VALUE) * FLOAT16_EPSILON_MULTIPLIED_BY_FLOAT16_MIN_VALUE;
|
|
6079
|
+
}
|
|
6080
|
+
|
|
6081
|
+
const temp = (1 + FLOAT16_EPSILON_DEVIDED_BY_EPSILON) * absolute;
|
|
6082
|
+
const result = temp - (temp - absolute);
|
|
6083
|
+
|
|
6084
|
+
// large number
|
|
6085
|
+
if (result > FLOAT16_MAX_VALUE || NumberIsNaN(result)) {
|
|
6086
|
+
return sign * Infinity;
|
|
6087
|
+
}
|
|
6088
|
+
|
|
6089
|
+
return sign * result;
|
|
6090
|
+
}
|
|
6091
|
+
|
|
6092
|
+
const baseTable = new NativeUint16Array(512);
|
|
6093
|
+
const shiftTable = new NativeUint8Array(512);
|
|
6094
|
+
|
|
6095
|
+
for (let i = 0; i < 256; ++i) {
|
|
6096
|
+
const e = i - 127;
|
|
6097
|
+
|
|
6098
|
+
// very small number (0, -0)
|
|
6099
|
+
if (e < -24) {
|
|
6100
|
+
baseTable[i] = 0x0000;
|
|
6101
|
+
baseTable[i | 0x100] = 0x8000;
|
|
6102
|
+
shiftTable[i] = 24;
|
|
6103
|
+
shiftTable[i | 0x100] = 24;
|
|
6104
|
+
|
|
6105
|
+
// small number (denorm)
|
|
6106
|
+
} else if (e < -14) {
|
|
6107
|
+
baseTable[i] = 0x0400 >> (-e - 14);
|
|
6108
|
+
baseTable[i | 0x100] = (0x0400 >> (-e - 14)) | 0x8000;
|
|
6109
|
+
shiftTable[i] = -e - 1;
|
|
6110
|
+
shiftTable[i | 0x100] = -e - 1;
|
|
6111
|
+
|
|
6112
|
+
// normal number
|
|
6113
|
+
} else if (e <= 15) {
|
|
6114
|
+
baseTable[i] = (e + 15) << 10;
|
|
6115
|
+
baseTable[i | 0x100] = ((e + 15) << 10) | 0x8000;
|
|
6116
|
+
shiftTable[i] = 13;
|
|
6117
|
+
shiftTable[i | 0x100] = 13;
|
|
6118
|
+
|
|
6119
|
+
// large number (Infinity, -Infinity)
|
|
6120
|
+
} else if (e < 128) {
|
|
6121
|
+
baseTable[i] = 0x7c00;
|
|
6122
|
+
baseTable[i | 0x100] = 0xfc00;
|
|
6123
|
+
shiftTable[i] = 24;
|
|
6124
|
+
shiftTable[i | 0x100] = 24;
|
|
6125
|
+
|
|
6126
|
+
// stay (NaN, Infinity, -Infinity)
|
|
6127
|
+
} else {
|
|
6128
|
+
baseTable[i] = 0x7c00;
|
|
6129
|
+
baseTable[i | 0x100] = 0xfc00;
|
|
6130
|
+
shiftTable[i] = 13;
|
|
6131
|
+
shiftTable[i | 0x100] = 13;
|
|
6132
|
+
}
|
|
6133
|
+
}
|
|
6134
|
+
|
|
6135
|
+
const mantissaTable = new NativeUint32Array(2048);
|
|
6136
|
+
for (let i = 1; i < 1024; ++i) {
|
|
6137
|
+
let m = i << 13; // zero pad mantissa bits
|
|
6138
|
+
let e = 0; // zero exponent
|
|
6139
|
+
|
|
6140
|
+
// normalized
|
|
6141
|
+
while ((m & 0x00800000) === 0) {
|
|
6142
|
+
m <<= 1;
|
|
6143
|
+
e -= 0x00800000; // decrement exponent
|
|
6144
|
+
}
|
|
6145
|
+
|
|
6146
|
+
m &= -8388609; // clear leading 1 bit
|
|
6147
|
+
e += 0x38800000; // adjust bias
|
|
6148
|
+
|
|
6149
|
+
mantissaTable[i] = m | e;
|
|
6150
|
+
}
|
|
6151
|
+
for (let i = 1024; i < 2048; ++i) {
|
|
6152
|
+
mantissaTable[i] = 0x38000000 + ((i - 1024) << 13);
|
|
6153
|
+
}
|
|
6154
|
+
|
|
6155
|
+
const exponentTable = new NativeUint32Array(64);
|
|
6156
|
+
for (let i = 1; i < 31; ++i) {
|
|
6157
|
+
exponentTable[i] = i << 23;
|
|
6158
|
+
}
|
|
6159
|
+
exponentTable[31] = 0x47800000;
|
|
6160
|
+
exponentTable[32] = 0x80000000;
|
|
6161
|
+
for (let i = 33; i < 63; ++i) {
|
|
6162
|
+
exponentTable[i] = 0x80000000 + ((i - 32) << 23);
|
|
6163
|
+
}
|
|
6164
|
+
exponentTable[63] = 0xc7800000;
|
|
6165
|
+
|
|
6166
|
+
const offsetTable = new NativeUint16Array(64);
|
|
6167
|
+
for (let i = 1; i < 64; ++i) {
|
|
6168
|
+
if (i !== 32) {
|
|
6169
|
+
offsetTable[i] = 1024;
|
|
6170
|
+
}
|
|
6171
|
+
}
|
|
6172
|
+
|
|
6173
|
+
/**
|
|
6174
|
+
* returns the nearest half-precision float representation of a number
|
|
6175
|
+
* @param {number} x
|
|
6176
|
+
* @returns {number}
|
|
6177
|
+
*/
|
|
6178
|
+
function f16round(x) {
|
|
6179
|
+
return roundToFloat16(x);
|
|
6180
|
+
}
|
|
6181
|
+
|
|
5905
6182
|
class Float16Image extends HDRImage {
|
|
5906
6183
|
data;
|
|
5907
6184
|
static DEFAULT_PIXELFORMAT = "rgba-float16";
|
|
@@ -5958,17 +6235,17 @@ class Float16Image extends HDRImage {
|
|
|
5958
6235
|
return Float16Array.from(hlg);
|
|
5959
6236
|
}
|
|
5960
6237
|
static convertArrayToRec2100_hlg(data) {
|
|
5961
|
-
const
|
|
5962
|
-
for (let i = 0; i < data.length; i
|
|
5963
|
-
const
|
|
5964
|
-
|
|
5965
|
-
uint16Data.set(pixel, i);
|
|
6238
|
+
const float16Array = new Float16Array(data.length);
|
|
6239
|
+
for (let i = 0; i < data.length; i++) {
|
|
6240
|
+
const normalizedFloat = data[i] / 255.0;
|
|
6241
|
+
float16Array[i] = f16round(normalizedFloat);
|
|
5966
6242
|
}
|
|
5967
|
-
return
|
|
6243
|
+
return float16Array;
|
|
5968
6244
|
}
|
|
5969
6245
|
pixelCallback(fn) {
|
|
5970
6246
|
for (let i = 0; i < this.data.length; i += 4) {
|
|
5971
|
-
|
|
6247
|
+
const pixel = fn(this.data[i], this.data[i + 1], this.data[i + 2], this.data[i + 3]);
|
|
6248
|
+
this.data.set(pixel, i);
|
|
5972
6249
|
}
|
|
5973
6250
|
}
|
|
5974
6251
|
static fromImageData(imageData) {
|
|
@@ -6034,6 +6311,7 @@ function getHdrOptions() {
|
|
|
6034
6311
|
if (browserMajorVersion == null) {
|
|
6035
6312
|
console.warn(`Unsupported / untested browser (${navigator.userAgent}) detected - using more modern defaults`);
|
|
6036
6313
|
hdrOptions["colorType"] = "float16";
|
|
6314
|
+
hdrOptions["toneMapping"] = { mode: "extended" };
|
|
6037
6315
|
}
|
|
6038
6316
|
else {
|
|
6039
6317
|
if (browserMajorVersion < 134) {
|
|
@@ -6046,7 +6324,10 @@ function getHdrOptions() {
|
|
|
6046
6324
|
return hdrOptions;
|
|
6047
6325
|
}
|
|
6048
6326
|
function initHDRCanvas(canvas) {
|
|
6049
|
-
|
|
6327
|
+
const browserMajorVersion = getBrowserVersion();
|
|
6328
|
+
if (browserMajorVersion !== null && browserMajorVersion < 134) {
|
|
6329
|
+
canvas.configureHighDynamicRange({ mode: "extended" });
|
|
6330
|
+
}
|
|
6050
6331
|
const ctx = canvas.getContext("2d", getHdrOptions());
|
|
6051
6332
|
return ctx;
|
|
6052
6333
|
}
|