@flighthq/materials 0.2.0 → 0.2.1-next.410.a23f189
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/customShaderMaterial.d.ts +3 -0
- package/dist/customShaderMaterial.d.ts.map +1 -0
- package/dist/customShaderMaterial.js +15 -0
- package/dist/customShaderMaterial.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/material.d.ts.map +1 -1
- package/dist/material.js +3 -1
- package/dist/material.js.map +1 -1
- package/dist/pbrMaterials.d.ts.map +1 -1
- package/dist/pbrMaterials.js +1 -1
- package/dist/pbrMaterials.js.map +1 -1
- package/dist/phongToPbr.d.ts +6 -0
- package/dist/phongToPbr.d.ts.map +1 -0
- package/dist/phongToPbr.js +53 -0
- package/dist/phongToPbr.js.map +1 -0
- package/dist/unlitMaterials.d.ts.map +1 -1
- package/dist/unlitMaterials.js +4 -2
- package/dist/unlitMaterials.js.map +1 -1
- package/package.json +4 -3
- package/src/colorTransform.test.ts +66 -9
- package/src/customShaderMaterial.test.ts +20 -0
- package/src/material.test.ts +9 -0
- package/src/phongToPbr.test.ts +67 -0
- package/dist/color.d.ts +0 -24
- package/dist/color.d.ts.map +0 -1
- package/dist/color.js +0 -291
- package/dist/color.js.map +0 -1
- package/src/color.test.ts +0 -383
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"customShaderMaterial.d.ts","sourceRoot":"","sources":["../src/customShaderMaterial.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAU5D,wBAAgB,0BAA0B,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC,GAAG,oBAAoB,CAM/G"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { CustomShaderMaterialKind } from '@flighthq/types';
|
|
2
|
+
import { createSurfaceMaterial } from './surfaceMaterial';
|
|
3
|
+
// User-authored shader material. `shaderKey` references a vertex+fragment pair registered on
|
|
4
|
+
// the render state (registerGlCustomMaterialShader); `uniforms` carries flat scalar/vector
|
|
5
|
+
// values; `textures` carries named texture bindings. All default to their sentinel (empty key,
|
|
6
|
+
// null bags) so a bare createCustomShaderMaterial() is structurally valid for tests and
|
|
7
|
+
// serialization even before a shader key is assigned.
|
|
8
|
+
export function createCustomShaderMaterial(opts) {
|
|
9
|
+
const material = createSurfaceMaterial(CustomShaderMaterialKind);
|
|
10
|
+
material.shaderKey = opts?.shaderKey ?? '';
|
|
11
|
+
material.textures = opts?.textures ?? null;
|
|
12
|
+
material.uniforms = opts?.uniforms ?? null;
|
|
13
|
+
return material;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=customShaderMaterial.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"customShaderMaterial.js","sourceRoot":"","sources":["../src/customShaderMaterial.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAE3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,6FAA6F;AAC7F,2FAA2F;AAC3F,+FAA+F;AAC/F,wFAAwF;AACxF,sDAAsD;AACtD,MAAM,UAAU,0BAA0B,CAAC,IAA8C;IACvF,MAAM,QAAQ,GAAG,qBAAqB,CAAC,wBAAwB,CAAyB,CAAC;IACzF,QAAQ,CAAC,SAAS,GAAG,IAAI,EAAE,SAAS,IAAI,EAAE,CAAC;IAC3C,QAAQ,CAAC,QAAQ,GAAG,IAAI,EAAE,QAAQ,IAAI,IAAI,CAAC;IAC3C,QAAQ,CAAC,QAAQ,GAAG,IAAI,EAAE,QAAQ,IAAI,IAAI,CAAC;IAC3C,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
export * from './classicMaterials';
|
|
2
|
-
export * from './color';
|
|
3
2
|
export * from './colorTransform';
|
|
3
|
+
export * from './customShaderMaterial';
|
|
4
4
|
export * from './material';
|
|
5
5
|
export * from './materialPresets';
|
|
6
6
|
export * from './materialValidation';
|
|
7
7
|
export * from './pbrExtensionMaterials';
|
|
8
8
|
export * from './pbrMaterials';
|
|
9
|
+
export * from './phongToPbr';
|
|
9
10
|
export * from './surfaceMaterial';
|
|
10
11
|
export * from './unlitMaterials';
|
|
11
12
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,wBAAwB,CAAC;AACvC,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
export * from './classicMaterials';
|
|
2
|
-
export * from './color';
|
|
3
2
|
export * from './colorTransform';
|
|
3
|
+
export * from './customShaderMaterial';
|
|
4
4
|
export * from './material';
|
|
5
5
|
export * from './materialPresets';
|
|
6
6
|
export * from './materialValidation';
|
|
7
7
|
export * from './pbrExtensionMaterials';
|
|
8
8
|
export * from './pbrMaterials';
|
|
9
|
+
export * from './phongToPbr';
|
|
9
10
|
export * from './surfaceMaterial';
|
|
10
11
|
export * from './unlitMaterials';
|
|
11
12
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,wBAAwB,CAAC;AACvC,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC"}
|
package/dist/material.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"material.d.ts","sourceRoot":"","sources":["../src/material.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAItD,wBAAgB,aAAa,CAAC,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAIlE;AAID,wBAAgB,YAAY,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,GAAG,IAAI,CAG5E;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,QAAQ,
|
|
1
|
+
{"version":3,"file":"material.d.ts","sourceRoot":"","sources":["../src/material.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAItD,wBAAgB,aAAa,CAAC,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAIlE;AAID,wBAAgB,YAAY,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,GAAG,IAAI,CAG5E;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,QAAQ,CAInD;AAKD,wBAAgB,cAAc,CAAC,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC,GAAG,OAAO,CAUpF"}
|
package/dist/material.js
CHANGED
|
@@ -14,7 +14,9 @@ export function copyMaterial(out, source) {
|
|
|
14
14
|
copyMaterialFields(out, source, source.kind);
|
|
15
15
|
}
|
|
16
16
|
export function createMaterial(kind) {
|
|
17
|
-
|
|
17
|
+
const material = createEntity({ kind });
|
|
18
|
+
material.name = null;
|
|
19
|
+
return material;
|
|
18
20
|
}
|
|
19
21
|
// Structural equality for dedup, pooling, and serialization round-trips — NOT the batch
|
|
20
22
|
// flush path (batching keys on material by reference). Compares own enumerable data fields
|
package/dist/material.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"material.js","sourceRoot":"","sources":["../src/material.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGhD,wFAAwF;AACxF,wFAAwF;AACxF,MAAM,UAAU,aAAa,CAAC,MAA0B;IACtD,MAAM,KAAK,GAAG,YAAY,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAa,CAAC;IAC9D,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;IAC/C,OAAO,KAAK,CAAC;AACf,CAAC;AAED,wFAAwF;AACxF,0FAA0F;AAC1F,MAAM,UAAU,YAAY,CAAC,GAAa,EAAE,MAA0B;IACpE,IAAI,GAAG,KAAK,MAAM;QAAE,OAAO;IAC3B,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAU;IACvC,
|
|
1
|
+
{"version":3,"file":"material.js","sourceRoot":"","sources":["../src/material.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGhD,wFAAwF;AACxF,wFAAwF;AACxF,MAAM,UAAU,aAAa,CAAC,MAA0B;IACtD,MAAM,KAAK,GAAG,YAAY,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAa,CAAC;IAC9D,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;IAC/C,OAAO,KAAK,CAAC;AACf,CAAC;AAED,wFAAwF;AACxF,0FAA0F;AAC1F,MAAM,UAAU,YAAY,CAAC,GAAa,EAAE,MAA0B;IACpE,IAAI,GAAG,KAAK,MAAM;QAAE,OAAO;IAC3B,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAU;IACvC,MAAM,QAAQ,GAAG,YAAY,CAAC,EAAE,IAAI,EAAE,CAAa,CAAC;IACpD,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAC;IACrB,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,wFAAwF;AACxF,2FAA2F;AAC3F,mFAAmF;AACnF,MAAM,UAAU,cAAc,CAAC,CAAqB,EAAE,CAAqB;IACzE,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACzB,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IACpC,MAAM,OAAO,GAAG,CAAuC,CAAC;IACxD,MAAM,OAAO,GAAG,CAAuC,CAAC;IACxD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACvC,IAAI,GAAG,KAAK,MAAM;YAAE,SAAS;QAC7B,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;IAClD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,uFAAuF;AACvF,4FAA4F;AAC5F,wDAAwD;AACxD,SAAS,kBAAkB,CAAC,GAAa,EAAE,GAAuB,EAAE,IAAU;IAC5E,MAAM,SAAS,GAAG,GAAyC,CAAC;IAC5D,MAAM,SAAS,GAAG,GAAyC,CAAC;IAC5D,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QACzC,IAAI,GAAG,KAAK,MAAM;YAAE,SAAS;QAC7B,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,GAAG,KAAK,UAAU,IAAI,KAAK,IAAI,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YACrE,uFAAuF;YACvF,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,GAAI,KAAgB,EAAE,CAAC;QAC5C,CAAC;aAAM,CAAC;YACN,SAAS,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACzB,CAAC;IACH,CAAC;IACD,iFAAiF;IACjF,SAAS,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;AAC3B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pbrMaterials.d.ts","sourceRoot":"","sources":["../src/pbrMaterials.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pbrMaterials.d.ts","sourceRoot":"","sources":["../src/pbrMaterials.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,6BAA6B,EAC7B,mBAAmB,EACnB,6BAA6B,EAC9B,MAAM,iBAAiB,CAAC;AAiBzB,wBAAgB,sCAAsC,CACpD,GAAG,EAAE,6BAA6B,EAClC,MAAM,EAAE,QAAQ,CAAC,6BAA6B,CAAC,GAC9C,IAAI,CAmDN;AAKD,wBAAgB,mCAAmC,CACjD,IAAI,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,6BAA6B,CAAC,CAAC,GACtD,6BAA6B,CAe/B;AAKD,wBAAgB,yBAAyB,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC,GAAG,mBAAmB,CAI5G;AAKD,wBAAgB,mCAAmC,CACjD,IAAI,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,6BAA6B,CAAC,CAAC,GACtD,6BAA6B,CAI/B"}
|
package/dist/pbrMaterials.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { unpackColorToLinear } from '@flighthq/color';
|
|
1
2
|
import { SpecularGlossinessPbrMaterialKind, StandardPbrMaterialKind } from '@flighthq/types';
|
|
2
|
-
import { unpackColorToLinear } from './color';
|
|
3
3
|
import { createSurfaceMaterial } from './surfaceMaterial';
|
|
4
4
|
// Converts a legacy specular-glossiness material to a metallic-roughness property block.
|
|
5
5
|
// Writes `out` with the computed base-color, metallic, and roughness values. The conversion
|
package/dist/pbrMaterials.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pbrMaterials.js","sourceRoot":"","sources":["../src/pbrMaterials.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pbrMaterials.js","sourceRoot":"","sources":["../src/pbrMaterials.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { PhongMaterial, StandardPbrMaterial, StandardPbrMaterialProperties } from '@flighthq/types';
|
|
2
|
+
export declare function convertPhongToStandardPbrMaterial(phong: Readonly<PhongMaterial>, opts?: Readonly<Partial<StandardPbrMaterialProperties>>): StandardPbrMaterial;
|
|
3
|
+
export declare function getPbrMetallicFromPhongSpecular(specular: number, diffuse: number): number;
|
|
4
|
+
export declare function getPbrRoughnessFromPhongShininess(shininess: number): number;
|
|
5
|
+
export declare function getPhongToPbrLightExposure(): number;
|
|
6
|
+
//# sourceMappingURL=phongToPbr.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"phongToPbr.d.ts","sourceRoot":"","sources":["../src/phongToPbr.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,mBAAmB,EAAE,6BAA6B,EAAE,MAAM,iBAAiB,CAAC;AAezG,wBAAgB,iCAAiC,CAC/C,KAAK,EAAE,QAAQ,CAAC,aAAa,CAAC,EAC9B,IAAI,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,6BAA6B,CAAC,CAAC,GACtD,mBAAmB,CAUrB;AAMD,wBAAgB,+BAA+B,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEzF;AAKD,wBAAgB,iCAAiC,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE3E;AAcD,wBAAgB,0BAA0B,IAAI,MAAM,CAEnD"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { getColorLuminance } from '@flighthq/color';
|
|
2
|
+
import { createStandardPbrMaterial } from './pbrMaterials';
|
|
3
|
+
// Migrates a classic `PhongMaterial` to a metallic-roughness `StandardPbrMaterial` whose surface
|
|
4
|
+
// reads equivalently. A reference (not exact) mapping: the Phong reflection-vector lobe and the
|
|
5
|
+
// GGX microfacet lobe cannot match at every angle, so this preserves overall appearance —
|
|
6
|
+
// base color, gloss, and brightness — rather than per-highlight shape. `opts` overrides any mapped
|
|
7
|
+
// field (e.g. to force `metallic`). Diffuse and baseColor share the packed sRgb-albedo encoding,
|
|
8
|
+
// so the color transfers unchanged; the renderer decodes both identically.
|
|
9
|
+
//
|
|
10
|
+
// IMPORTANT — brightness: the metallic-roughness diffuse term divides albedo by π that classic
|
|
11
|
+
// Phong does not (see `getPhongToPbrLightExposure`). The material alone cannot compensate a
|
|
12
|
+
// per-light normalization, so scale the scene's light intensity by that exposure or a migrated
|
|
13
|
+
// scene renders ~π× (≈3.2×) too dark.
|
|
14
|
+
export function convertPhongToStandardPbrMaterial(phong, opts) {
|
|
15
|
+
return createStandardPbrMaterial({
|
|
16
|
+
baseColor: phong.diffuse,
|
|
17
|
+
baseColorMap: phong.diffuseMap,
|
|
18
|
+
metallic: getPbrMetallicFromPhongSpecular(phong.specular, phong.diffuse),
|
|
19
|
+
normalMap: phong.normalMap,
|
|
20
|
+
normalScale: phong.normalScale,
|
|
21
|
+
roughness: getPbrRoughnessFromPhongShininess(phong.shininess),
|
|
22
|
+
...opts,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
// Reference metallic guess from a Phong specular/diffuse pair. Phong does not encode metalness, so
|
|
26
|
+
// this is conservative: dielectric (0) unless a strong specular sits over a near-black diffuse — the
|
|
27
|
+
// only Phong configuration that reads unambiguously metallic. Callers that know the material is
|
|
28
|
+
// metal should pass `metallic` through `convertPhongToStandardPbrMaterial`'s `opts` instead.
|
|
29
|
+
export function getPbrMetallicFromPhongSpecular(specular, diffuse) {
|
|
30
|
+
return getColorLuminance(specular) > 0.5 && getColorLuminance(diffuse) < 0.04 ? 1 : 0;
|
|
31
|
+
}
|
|
32
|
+
// Maps a Blinn-Phong specular exponent to a GGX roughness via `sqrt(2 / (shininess + 2))`, clamped
|
|
33
|
+
// to [0, 1]. Monotonic: higher shininess (sharper highlight) → lower roughness (smoother surface).
|
|
34
|
+
// The Phong default shininess of 32 maps to roughness ≈ 0.243.
|
|
35
|
+
export function getPbrRoughnessFromPhongShininess(shininess) {
|
|
36
|
+
return Math.min(1, Math.max(0, Math.sqrt(2 / (Math.max(0, shininess) + 2))));
|
|
37
|
+
}
|
|
38
|
+
// The exposure (in EV) to apply to a scene's lights when migrating classic-Phong materials to
|
|
39
|
+
// metallic-roughness PBR, so brightness is preserved under the same lights. The PBR diffuse BRDF
|
|
40
|
+
// divides albedo by π for energy conservation while classic Phong does not, so PBR diffuse is ~1/π
|
|
41
|
+
// as bright for equal light radiance. This returns `log2(π)` (≈ 1.651 EV) — i.e. a ×π scale —
|
|
42
|
+
// applied via `applyLightExposure(intensity, getPhongToPbrLightExposure())` from `@flighthq/lighting`.
|
|
43
|
+
// Skipping it is the classic "ported scene is far too dark" failure.
|
|
44
|
+
//
|
|
45
|
+
// Assumed input, so it is applied exactly ONCE: light intensities already in Flight's LINEAR-radiance
|
|
46
|
+
// Phong convention. This is the single Phong→PBR energy step; it is NOT a general "engine porting"
|
|
47
|
+
// scale. Porting from a foreign engine whose lights are in a different space (e.g. a gamma-space LDR
|
|
48
|
+
// source) is a separate, earlier conversion into Flight's linear Phong convention that belongs in the
|
|
49
|
+
// importer, not here — do not fold that engine's own boost into this π, and do not apply this twice.
|
|
50
|
+
export function getPhongToPbrLightExposure() {
|
|
51
|
+
return Math.log2(Math.PI);
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=phongToPbr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"phongToPbr.js","sourceRoot":"","sources":["../src/phongToPbr.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAGpD,OAAO,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAE3D,iGAAiG;AACjG,gGAAgG;AAChG,0FAA0F;AAC1F,mGAAmG;AACnG,iGAAiG;AACjG,2EAA2E;AAC3E,EAAE;AACF,+FAA+F;AAC/F,4FAA4F;AAC5F,+FAA+F;AAC/F,sCAAsC;AACtC,MAAM,UAAU,iCAAiC,CAC/C,KAA8B,EAC9B,IAAuD;IAEvD,OAAO,yBAAyB,CAAC;QAC/B,SAAS,EAAE,KAAK,CAAC,OAAO;QACxB,YAAY,EAAE,KAAK,CAAC,UAAU;QAC9B,QAAQ,EAAE,+BAA+B,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC;QACxE,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,SAAS,EAAE,iCAAiC,CAAC,KAAK,CAAC,SAAS,CAAC;QAC7D,GAAG,IAAI;KACR,CAAC,CAAC;AACL,CAAC;AAED,mGAAmG;AACnG,qGAAqG;AACrG,gGAAgG;AAChG,6FAA6F;AAC7F,MAAM,UAAU,+BAA+B,CAAC,QAAgB,EAAE,OAAe;IAC/E,OAAO,iBAAiB,CAAC,QAAQ,CAAC,GAAG,GAAG,IAAI,iBAAiB,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACxF,CAAC;AAED,mGAAmG;AACnG,mGAAmG;AACnG,+DAA+D;AAC/D,MAAM,UAAU,iCAAiC,CAAC,SAAiB;IACjE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/E,CAAC;AAED,8FAA8F;AAC9F,iGAAiG;AACjG,mGAAmG;AACnG,8FAA8F;AAC9F,uGAAuG;AACvG,qEAAqE;AACrE,EAAE;AACF,sGAAsG;AACtG,mGAAmG;AACnG,qGAAqG;AACrG,sGAAsG;AACtG,qGAAqG;AACrG,MAAM,UAAU,0BAA0B;IACxC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC5B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unlitMaterials.d.ts","sourceRoot":"","sources":["../src/unlitMaterials.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,YAAY,EACZ,aAAa,EACb,mBAAmB,EACnB,iBAAiB,EAClB,MAAM,iBAAiB,CAAC;AAgBzB,wBAAgB,mBAAmB,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,GAAG,aAAa,CAK1F;AAID,wBAAgB,sBAAsB,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,GAAG,gBAAgB,CAMnG;AAID,wBAAgB,oBAAoB,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,GAAG,cAAc,CAK7F;AAGD,wBAAgB,oBAAoB,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,GAAG,cAAc,CAK7F;AAID,wBAAgB,kBAAkB,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,GAAG,YAAY,CAOvF;
|
|
1
|
+
{"version":3,"file":"unlitMaterials.d.ts","sourceRoot":"","sources":["../src/unlitMaterials.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,YAAY,EACZ,aAAa,EACb,mBAAmB,EACnB,iBAAiB,EAClB,MAAM,iBAAiB,CAAC;AAgBzB,wBAAgB,mBAAmB,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,GAAG,aAAa,CAK1F;AAID,wBAAgB,sBAAsB,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,GAAG,gBAAgB,CAMnG;AAID,wBAAgB,oBAAoB,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,GAAG,cAAc,CAK7F;AAGD,wBAAgB,oBAAoB,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,GAAG,cAAc,CAK7F;AAID,wBAAgB,kBAAkB,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,GAAG,YAAY,CAOvF;AAKD,wBAAgB,mBAAmB,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,GAAG,aAAa,CAM1F;AAGD,wBAAgB,yBAAyB,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC,GAAG,mBAAmB,CAI5G;AAGD,wBAAgB,uBAAuB,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,GAAG,iBAAiB,CAKtG"}
|
package/dist/unlitMaterials.js
CHANGED
|
@@ -42,12 +42,14 @@ export function createToonMaterial(opts) {
|
|
|
42
42
|
material.steps = opts?.steps ?? 3;
|
|
43
43
|
return material;
|
|
44
44
|
}
|
|
45
|
-
// Lighting-independent flat-color material. `baseColor` defaults to white, `baseColorMap`
|
|
46
|
-
// null. Full fidelity on every backend including Canvas2D
|
|
45
|
+
// Lighting-independent flat-color material. `baseColor` defaults to white, `baseColorMap` and
|
|
46
|
+
// `baseColorVideoMap` to null. Full fidelity on every backend including Canvas2D; a bound
|
|
47
|
+
// `baseColorVideoMap` (live video stream) is sampled only on the GL backend today.
|
|
47
48
|
export function createUnlitMaterial(opts) {
|
|
48
49
|
const material = createSurfaceMaterial(UnlitMaterialKind);
|
|
49
50
|
material.baseColor = opts?.baseColor ?? 0xffffffff;
|
|
50
51
|
material.baseColorMap = opts?.baseColorMap ?? null;
|
|
52
|
+
material.baseColorVideoMap = opts?.baseColorVideoMap ?? null;
|
|
51
53
|
return material;
|
|
52
54
|
}
|
|
53
55
|
// Uses the mesh's `color0` vertex attribute as unlit surface color. `tint` defaults to white.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unlitMaterials.js","sourceRoot":"","sources":["../src/unlitMaterials.ts"],"names":[],"mappings":"AAUA,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,6FAA6F;AAC7F,iEAAiE;AACjE,MAAM,UAAU,mBAAmB,CAAC,IAAuC;IACzE,MAAM,QAAQ,GAAG,qBAAqB,CAAC,iBAAiB,CAAkB,CAAC;IAC3E,QAAQ,CAAC,GAAG,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC,CAAC;IAC9B,QAAQ,CAAC,IAAI,GAAG,IAAI,EAAE,IAAI,IAAI,CAAC,CAAC;IAChC,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,kFAAkF;AAClF,+EAA+E;AAC/E,MAAM,UAAU,sBAAsB,CAAC,IAA0C;IAC/E,MAAM,QAAQ,GAAG,qBAAqB,CAAC,oBAAoB,CAAqB,CAAC;IACjF,QAAQ,CAAC,QAAQ,GAAG,IAAI,EAAE,QAAQ,IAAI,UAAU,CAAC;IACjD,QAAQ,CAAC,WAAW,GAAG,IAAI,EAAE,WAAW,IAAI,IAAI,CAAC;IACjD,QAAQ,CAAC,gBAAgB,GAAG,IAAI,EAAE,gBAAgB,IAAI,CAAC,CAAC;IACxD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,8FAA8F;AAC9F,oEAAoE;AACpE,MAAM,UAAU,oBAAoB,CAAC,IAAwC;IAC3E,MAAM,QAAQ,GAAG,qBAAqB,CAAC,kBAAkB,CAAmB,CAAC;IAC7E,QAAQ,CAAC,MAAM,GAAG,IAAI,EAAE,MAAM,IAAI,IAAI,CAAC;IACvC,QAAQ,CAAC,IAAI,GAAG,IAAI,EAAE,IAAI,IAAI,UAAU,CAAC;IACzC,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,oBAAoB,CAAC,IAAwC;IAC3E,MAAM,QAAQ,GAAG,qBAAqB,CAAC,kBAAkB,CAAmB,CAAC;IAC7E,QAAQ,CAAC,SAAS,GAAG,IAAI,EAAE,SAAS,IAAI,IAAI,CAAC;IAC7C,QAAQ,CAAC,WAAW,GAAG,IAAI,EAAE,WAAW,IAAI,CAAC,CAAC;IAC9C,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,+FAA+F;AAC/F,6FAA6F;AAC7F,MAAM,UAAU,kBAAkB,CAAC,IAAsC;IACvE,MAAM,QAAQ,GAAG,qBAAqB,CAAC,gBAAgB,CAAiB,CAAC;IACzE,QAAQ,CAAC,SAAS,GAAG,IAAI,EAAE,SAAS,IAAI,UAAU,CAAC;IACnD,QAAQ,CAAC,YAAY,GAAG,IAAI,EAAE,YAAY,IAAI,IAAI,CAAC;IACnD,QAAQ,CAAC,IAAI,GAAG,IAAI,EAAE,IAAI,IAAI,IAAI,CAAC;IACnC,QAAQ,CAAC,KAAK,GAAG,IAAI,EAAE,KAAK,IAAI,CAAC,CAAC;IAClC,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,
|
|
1
|
+
{"version":3,"file":"unlitMaterials.js","sourceRoot":"","sources":["../src/unlitMaterials.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flighthq/materials",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1-next.410.a23f189",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/flighthq/flight.git",
|
|
@@ -32,8 +32,9 @@
|
|
|
32
32
|
"clean:dist": "tsx ../../scripts/clean-package-dist.ts"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@flighthq/
|
|
36
|
-
"@flighthq/
|
|
35
|
+
"@flighthq/color": "0.2.1-next.410.a23f189",
|
|
36
|
+
"@flighthq/entity": "0.2.1-next.410.a23f189",
|
|
37
|
+
"@flighthq/types": "0.2.1-next.410.a23f189"
|
|
37
38
|
},
|
|
38
39
|
"devDependencies": {
|
|
39
40
|
"typescript": "^5.3.0"
|
|
@@ -67,15 +67,72 @@ describe('concatColorTransform', () => {
|
|
|
67
67
|
expect(out.redOffset).toBe(2 * 5 + 10);
|
|
68
68
|
});
|
|
69
69
|
|
|
70
|
-
it('
|
|
71
|
-
const a = createColorTransform({
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
70
|
+
it('produces correct result when out aliases source', () => {
|
|
71
|
+
const a = createColorTransform({
|
|
72
|
+
redMultiplier: 2,
|
|
73
|
+
greenMultiplier: 0.5,
|
|
74
|
+
blueMultiplier: 3,
|
|
75
|
+
alphaMultiplier: 0.25,
|
|
76
|
+
redOffset: 10,
|
|
77
|
+
greenOffset: 20,
|
|
78
|
+
blueOffset: 30,
|
|
79
|
+
alphaOffset: 40,
|
|
80
|
+
});
|
|
81
|
+
const b = createColorTransform({
|
|
82
|
+
redMultiplier: 3,
|
|
83
|
+
greenMultiplier: 4,
|
|
84
|
+
blueMultiplier: 0.5,
|
|
85
|
+
alphaMultiplier: 2,
|
|
86
|
+
redOffset: 5,
|
|
87
|
+
greenOffset: 15,
|
|
88
|
+
blueOffset: 25,
|
|
89
|
+
alphaOffset: 35,
|
|
90
|
+
});
|
|
91
|
+
const ref = createColorTransform();
|
|
92
|
+
concatColorTransform(ref, a, b);
|
|
93
|
+
concatColorTransform(a, a, b);
|
|
94
|
+
expect(a.redMultiplier).toBe(ref.redMultiplier);
|
|
95
|
+
expect(a.greenMultiplier).toBe(ref.greenMultiplier);
|
|
96
|
+
expect(a.blueMultiplier).toBe(ref.blueMultiplier);
|
|
97
|
+
expect(a.alphaMultiplier).toBe(ref.alphaMultiplier);
|
|
98
|
+
expect(a.redOffset).toBe(ref.redOffset);
|
|
99
|
+
expect(a.greenOffset).toBe(ref.greenOffset);
|
|
100
|
+
expect(a.blueOffset).toBe(ref.blueOffset);
|
|
101
|
+
expect(a.alphaOffset).toBe(ref.alphaOffset);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('produces correct result when out aliases other', () => {
|
|
105
|
+
const a = createColorTransform({
|
|
106
|
+
redMultiplier: 2,
|
|
107
|
+
greenMultiplier: 0.5,
|
|
108
|
+
blueMultiplier: 3,
|
|
109
|
+
alphaMultiplier: 0.25,
|
|
110
|
+
redOffset: 10,
|
|
111
|
+
greenOffset: 20,
|
|
112
|
+
blueOffset: 30,
|
|
113
|
+
alphaOffset: 40,
|
|
114
|
+
});
|
|
115
|
+
const b = createColorTransform({
|
|
116
|
+
redMultiplier: 3,
|
|
117
|
+
greenMultiplier: 4,
|
|
118
|
+
blueMultiplier: 0.5,
|
|
119
|
+
alphaMultiplier: 2,
|
|
120
|
+
redOffset: 5,
|
|
121
|
+
greenOffset: 15,
|
|
122
|
+
blueOffset: 25,
|
|
123
|
+
alphaOffset: 35,
|
|
124
|
+
});
|
|
125
|
+
const ref = createColorTransform();
|
|
126
|
+
concatColorTransform(ref, a, b);
|
|
127
|
+
concatColorTransform(b, a, b);
|
|
128
|
+
expect(b.redMultiplier).toBe(ref.redMultiplier);
|
|
129
|
+
expect(b.greenMultiplier).toBe(ref.greenMultiplier);
|
|
130
|
+
expect(b.blueMultiplier).toBe(ref.blueMultiplier);
|
|
131
|
+
expect(b.alphaMultiplier).toBe(ref.alphaMultiplier);
|
|
132
|
+
expect(b.redOffset).toBe(ref.redOffset);
|
|
133
|
+
expect(b.greenOffset).toBe(ref.greenOffset);
|
|
134
|
+
expect(b.blueOffset).toBe(ref.blueOffset);
|
|
135
|
+
expect(b.alphaOffset).toBe(ref.alphaOffset);
|
|
79
136
|
});
|
|
80
137
|
});
|
|
81
138
|
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { CustomShaderMaterialKind } from '@flighthq/types';
|
|
2
|
+
|
|
3
|
+
import { createCustomShaderMaterial } from './customShaderMaterial';
|
|
4
|
+
|
|
5
|
+
describe('createCustomShaderMaterial', () => {
|
|
6
|
+
it('creates a custom shader material with default sentinel values', () => {
|
|
7
|
+
const material = createCustomShaderMaterial();
|
|
8
|
+
expect(material.kind).toBe(CustomShaderMaterialKind);
|
|
9
|
+
expect(material.shaderKey).toBe('');
|
|
10
|
+
expect(material.uniforms).toBeNull();
|
|
11
|
+
expect(material.textures).toBeNull();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('applies overrides', () => {
|
|
15
|
+
const uniforms = { u_time: 1.5, u_scale: [2, 3] };
|
|
16
|
+
const material = createCustomShaderMaterial({ shaderKey: 'myShader', uniforms });
|
|
17
|
+
expect(material.shaderKey).toBe('myShader');
|
|
18
|
+
expect(material.uniforms).toBe(uniforms);
|
|
19
|
+
});
|
|
20
|
+
});
|
package/src/material.test.ts
CHANGED
|
@@ -27,6 +27,11 @@ describe('cloneMaterial', () => {
|
|
|
27
27
|
const clone = cloneMaterial(original);
|
|
28
28
|
expect(equalsMaterial(original, clone)).toBe(true);
|
|
29
29
|
});
|
|
30
|
+
it('carries the authored name onto the clone', () => {
|
|
31
|
+
const original = createMaterial(TestMaterialKind);
|
|
32
|
+
original.name = 'canopy';
|
|
33
|
+
expect(cloneMaterial(original).name).toBe('canopy');
|
|
34
|
+
});
|
|
30
35
|
});
|
|
31
36
|
|
|
32
37
|
describe('copyMaterial', () => {
|
|
@@ -50,6 +55,10 @@ describe('createMaterial', () => {
|
|
|
50
55
|
const material = createMaterial(TestMaterialKind);
|
|
51
56
|
expect(material.kind).toBe(TestMaterialKind);
|
|
52
57
|
});
|
|
58
|
+
|
|
59
|
+
it('defaults the authored name to null', () => {
|
|
60
|
+
expect(createMaterial(TestMaterialKind).name).toBeNull();
|
|
61
|
+
});
|
|
53
62
|
});
|
|
54
63
|
|
|
55
64
|
describe('equalsMaterial', () => {
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { StandardPbrMaterialKind } from '@flighthq/types';
|
|
2
|
+
|
|
3
|
+
import { createPhongMaterial } from './classicMaterials';
|
|
4
|
+
import {
|
|
5
|
+
convertPhongToStandardPbrMaterial,
|
|
6
|
+
getPbrMetallicFromPhongSpecular,
|
|
7
|
+
getPbrRoughnessFromPhongShininess,
|
|
8
|
+
getPhongToPbrLightExposure,
|
|
9
|
+
} from './phongToPbr';
|
|
10
|
+
|
|
11
|
+
describe('convertPhongToStandardPbrMaterial', () => {
|
|
12
|
+
it('maps a neutral Phong material to a plausible PBR material', () => {
|
|
13
|
+
const phong = createPhongMaterial();
|
|
14
|
+
const pbr = convertPhongToStandardPbrMaterial(phong);
|
|
15
|
+
expect(pbr.kind).toBe(StandardPbrMaterialKind);
|
|
16
|
+
// Diffuse and baseColor share the packed sRgb-albedo encoding — color transfers unchanged.
|
|
17
|
+
expect(pbr.baseColor).toBe(phong.diffuse);
|
|
18
|
+
expect(pbr.roughness).toBeGreaterThan(0);
|
|
19
|
+
expect(pbr.roughness).toBeLessThan(1);
|
|
20
|
+
// A white specular over a white diffuse is a dielectric, not a metal.
|
|
21
|
+
expect(pbr.metallic).toBe(0);
|
|
22
|
+
});
|
|
23
|
+
it('preserves the normal map and scale', () => {
|
|
24
|
+
const phong = createPhongMaterial({ normalScale: 0.5 });
|
|
25
|
+
const pbr = convertPhongToStandardPbrMaterial(phong);
|
|
26
|
+
expect(pbr.normalScale).toBe(0.5);
|
|
27
|
+
expect(pbr.normalMap).toBe(phong.normalMap);
|
|
28
|
+
});
|
|
29
|
+
it('lets opts override a mapped field', () => {
|
|
30
|
+
const phong = createPhongMaterial();
|
|
31
|
+
const pbr = convertPhongToStandardPbrMaterial(phong, { metallic: 1, roughness: 0.2 });
|
|
32
|
+
expect(pbr.metallic).toBe(1);
|
|
33
|
+
expect(pbr.roughness).toBe(0.2);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
describe('getPbrMetallicFromPhongSpecular', () => {
|
|
38
|
+
it('reads a bright specular over a near-black diffuse as metallic', () => {
|
|
39
|
+
expect(getPbrMetallicFromPhongSpecular(0xffffffff, 0x000000ff)).toBe(1);
|
|
40
|
+
});
|
|
41
|
+
it('reads a white specular over a lit diffuse as dielectric', () => {
|
|
42
|
+
expect(getPbrMetallicFromPhongSpecular(0xffffffff, 0xffffffff)).toBe(0);
|
|
43
|
+
expect(getPbrMetallicFromPhongSpecular(0x808080ff, 0x333333ff)).toBe(0);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe('getPbrRoughnessFromPhongShininess', () => {
|
|
48
|
+
it('maps the Phong default shininess of 32 to roughness ≈ 0.243', () => {
|
|
49
|
+
expect(getPbrRoughnessFromPhongShininess(32)).toBeCloseTo(0.2425, 3);
|
|
50
|
+
});
|
|
51
|
+
it('is monotonic decreasing in shininess', () => {
|
|
52
|
+
expect(getPbrRoughnessFromPhongShininess(2)).toBeGreaterThan(getPbrRoughnessFromPhongShininess(200));
|
|
53
|
+
});
|
|
54
|
+
it('clamps to [0, 1] and handles the degenerate shininess of 0', () => {
|
|
55
|
+
const r = getPbrRoughnessFromPhongShininess(0);
|
|
56
|
+
expect(r).toBeLessThanOrEqual(1);
|
|
57
|
+
expect(r).toBeGreaterThanOrEqual(0);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
describe('getPhongToPbrLightExposure', () => {
|
|
62
|
+
it('returns log2(π) — a ×π light scale that offsets the Lambert 1/π diffuse normalization', () => {
|
|
63
|
+
expect(getPhongToPbrLightExposure()).toBeCloseTo(Math.log2(Math.PI), 10);
|
|
64
|
+
// Applying the exposure multiplies intensity by ≈π (≈3.14) — the anti-too-dark factor.
|
|
65
|
+
expect(2 ** getPhongToPbrLightExposure()).toBeCloseTo(Math.PI, 10);
|
|
66
|
+
});
|
|
67
|
+
});
|
package/dist/color.d.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { LinearColor } from '@flighthq/types';
|
|
2
|
-
export type { LinearColor };
|
|
3
|
-
export type HslColor = [number, number, number];
|
|
4
|
-
export type HsvColor = [number, number, number];
|
|
5
|
-
export declare function computeRgbHexString(color: number): string;
|
|
6
|
-
export declare function createHslColor(): HslColor;
|
|
7
|
-
export declare function createHsvColor(): HsvColor;
|
|
8
|
-
export declare function createLinearColor(): LinearColor;
|
|
9
|
-
export declare function getColorContrastRatio(a: number, b: number): number;
|
|
10
|
-
export declare function getColorLuminance(color: number): number;
|
|
11
|
-
export declare function hslToRgb(out: [number, number, number, number], h: number, s: number, l: number): void;
|
|
12
|
-
export declare function hsvToRgb(out: [number, number, number, number], h: number, s: number, v: number): void;
|
|
13
|
-
export declare function lerpColor(start: number, end: number, t: number): number;
|
|
14
|
-
export declare function lerpLinearColor(out: LinearColor, start: Readonly<LinearColor>, end: Readonly<LinearColor>, t: number): LinearColor;
|
|
15
|
-
export declare function linearChannelToSrgb(value: number): number;
|
|
16
|
-
export declare function packColor(r: number, g: number, b: number, a: number): number;
|
|
17
|
-
export declare function packLinearToColor(color: Readonly<LinearColor>): number;
|
|
18
|
-
export declare function premultiplyColorAlpha(color: number): number;
|
|
19
|
-
export declare function rgbToHsl(out: HslColor, color: number): HslColor;
|
|
20
|
-
export declare function rgbToHsv(out: HsvColor, color: number): HsvColor;
|
|
21
|
-
export declare function unpackColorRgba(out: [number, number, number, number], color: number): void;
|
|
22
|
-
export declare function unpackColorToLinear(out: LinearColor, color: number): LinearColor;
|
|
23
|
-
export declare function unpremultiplyColorAlpha(color: number): number;
|
|
24
|
-
//# sourceMappingURL=color.d.ts.map
|
package/dist/color.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"color.d.ts","sourceRoot":"","sources":["../src/color.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnD,YAAY,EAAE,WAAW,EAAE,CAAC;AAI5B,MAAM,MAAM,QAAQ,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAIhD,MAAM,MAAM,QAAQ,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAKhD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEzD;AAGD,wBAAgB,cAAc,IAAI,QAAQ,CAEzC;AAGD,wBAAgB,cAAc,IAAI,QAAQ,CAEzC;AAGD,wBAAgB,iBAAiB,IAAI,WAAW,CAE/C;AAKD,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAMlE;AAKD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKvD;AAMD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAcrG;AAID,wBAAgB,QAAQ,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CA6CrG;AAMD,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAevE;AAID,wBAAgB,eAAe,CAC7B,GAAG,EAAE,WAAW,EAChB,KAAK,EAAE,QAAQ,CAAC,WAAW,CAAC,EAC5B,GAAG,EAAE,QAAQ,CAAC,WAAW,CAAC,EAC1B,CAAC,EAAE,MAAM,GACR,WAAW,CAeb;AAID,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEzD;AAKD,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAM5E;AAKD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,MAAM,CAMtE;AAMD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAM3D;AAMD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,QAAQ,CA2B/D;AAKD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,QAAQ,CAuB/D;AAID,wBAAgB,eAAe,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAK1F;AAQD,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,GAAG,WAAW,CAMhF;AAKD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAO7D"}
|
package/dist/color.js
DELETED
|
@@ -1,291 +0,0 @@
|
|
|
1
|
-
// Takes a 24-bit RGB color (`0xRRGGBB`, e.g. a TextFormat color) and returns a
|
|
2
|
-
// CSS `#RRGGBB` string. Any high-byte bits are masked off, so a 32-bit RGBA
|
|
3
|
-
// value would keep `GGBBAA` — pass RGB, not RGBA.
|
|
4
|
-
export function computeRgbHexString(color) {
|
|
5
|
-
return `#${(color & 0xffffff).toString(16).padStart(6, '0')}`;
|
|
6
|
-
}
|
|
7
|
-
// Allocates a fresh zeroed `HslColor` for use as an `rgbToHsl` out parameter.
|
|
8
|
-
export function createHslColor() {
|
|
9
|
-
return [0, 0, 0];
|
|
10
|
-
}
|
|
11
|
-
// Allocates a fresh zeroed `HsvColor` for use as an `rgbToHsv` out parameter.
|
|
12
|
-
export function createHsvColor() {
|
|
13
|
-
return [0, 0, 0];
|
|
14
|
-
}
|
|
15
|
-
// Allocates a fresh zeroed `LinearColor` for use as an `unpackColorToLinear` out parameter.
|
|
16
|
-
export function createLinearColor() {
|
|
17
|
-
return [0, 0, 0, 0];
|
|
18
|
-
}
|
|
19
|
-
// WCAG 2.x contrast ratio between two packed sRGB `0xRRGGBBAA` colors (alpha ignored).
|
|
20
|
-
// Returns the ratio in [1, 21]; 1 = no contrast, 21 = black on white. The formula is
|
|
21
|
-
// (L1 + 0.05) / (L2 + 0.05) where L1 ≥ L2 are the relative luminances.
|
|
22
|
-
export function getColorContrastRatio(a, b) {
|
|
23
|
-
const la = getColorLuminance(a);
|
|
24
|
-
const lb = getColorLuminance(b);
|
|
25
|
-
const lighter = Math.max(la, lb);
|
|
26
|
-
const darker = Math.min(la, lb);
|
|
27
|
-
return (lighter + 0.05) / (darker + 0.05);
|
|
28
|
-
}
|
|
29
|
-
// Rec. 709 relative luminance of a packed sRGB `0xRRGGBBAA` color (alpha ignored).
|
|
30
|
-
// Gamma-decodes RGB to linear, then applies the Rec. 709 luminance weights. Returns a
|
|
31
|
-
// value in [0, 1] where 0 is black and 1 is white.
|
|
32
|
-
export function getColorLuminance(color) {
|
|
33
|
-
const r = srgbChannelToLinear(((color >>> 24) & 0xff) / 0xff);
|
|
34
|
-
const g = srgbChannelToLinear(((color >>> 16) & 0xff) / 0xff);
|
|
35
|
-
const b = srgbChannelToLinear(((color >>> 8) & 0xff) / 0xff);
|
|
36
|
-
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
37
|
-
}
|
|
38
|
-
// Converts a packed sRGB `0xRRGGBBAA` color to HSL. Writes `out[0]` = hue [0, 360),
|
|
39
|
-
// `out[1]` = saturation [0, 1], `out[2]` = lightness [0, 1]. Alpha is ignored.
|
|
40
|
-
// The conversion operates in sRGB (non-linear) space, matching artist-facing color pickers.
|
|
41
|
-
// Returns `out`.
|
|
42
|
-
export function hslToRgb(out, h, s, l) {
|
|
43
|
-
// h in [0, 360), s and l in [0, 1]. Writes sRGB [0,1] R/G/B to out[0..2]; leaves out[3].
|
|
44
|
-
if (s === 0) {
|
|
45
|
-
out[0] = l;
|
|
46
|
-
out[1] = l;
|
|
47
|
-
out[2] = l;
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
51
|
-
const p = 2 * l - q;
|
|
52
|
-
const hn = h / 360;
|
|
53
|
-
out[0] = hueToRgbChannel(p, q, hn + 1 / 3);
|
|
54
|
-
out[1] = hueToRgbChannel(p, q, hn);
|
|
55
|
-
out[2] = hueToRgbChannel(p, q, hn - 1 / 3);
|
|
56
|
-
}
|
|
57
|
-
// Converts HSV to RGB floats. Writes sRGB [0,1] to out[0..2] (h in [0, 360), s/v in [0, 1]).
|
|
58
|
-
// Alpha in out[3] is not modified.
|
|
59
|
-
export function hsvToRgb(out, h, s, v) {
|
|
60
|
-
if (s === 0) {
|
|
61
|
-
out[0] = v;
|
|
62
|
-
out[1] = v;
|
|
63
|
-
out[2] = v;
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
const hn = ((h % 360) + 360) % 360;
|
|
67
|
-
const i = Math.floor(hn / 60) % 6;
|
|
68
|
-
const f = hn / 60 - Math.floor(hn / 60);
|
|
69
|
-
const p = v * (1 - s);
|
|
70
|
-
const q = v * (1 - f * s);
|
|
71
|
-
const t = v * (1 - (1 - f) * s);
|
|
72
|
-
switch (i) {
|
|
73
|
-
case 0:
|
|
74
|
-
out[0] = v;
|
|
75
|
-
out[1] = t;
|
|
76
|
-
out[2] = p;
|
|
77
|
-
break;
|
|
78
|
-
case 1:
|
|
79
|
-
out[0] = q;
|
|
80
|
-
out[1] = v;
|
|
81
|
-
out[2] = p;
|
|
82
|
-
break;
|
|
83
|
-
case 2:
|
|
84
|
-
out[0] = p;
|
|
85
|
-
out[1] = v;
|
|
86
|
-
out[2] = t;
|
|
87
|
-
break;
|
|
88
|
-
case 3:
|
|
89
|
-
out[0] = p;
|
|
90
|
-
out[1] = q;
|
|
91
|
-
out[2] = v;
|
|
92
|
-
break;
|
|
93
|
-
case 4:
|
|
94
|
-
out[0] = t;
|
|
95
|
-
out[1] = p;
|
|
96
|
-
out[2] = v;
|
|
97
|
-
break;
|
|
98
|
-
default:
|
|
99
|
-
out[0] = v;
|
|
100
|
-
out[1] = p;
|
|
101
|
-
out[2] = q;
|
|
102
|
-
break;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
// Linearly interpolates between two packed sRGB colors `start` and `end` by `t` in [0, 1].
|
|
106
|
-
// Interpolation is performed in linear space for perceptual correctness (gamma-correct mix),
|
|
107
|
-
// then repacked to sRGB. Alpha is interpolated linearly (alpha is already linear coverage).
|
|
108
|
-
// `t` is clamped to [0, 1].
|
|
109
|
-
export function lerpColor(start, end, t) {
|
|
110
|
-
const tc = Math.min(1, Math.max(0, t));
|
|
111
|
-
const sr = srgbChannelToLinear(((start >>> 24) & 0xff) / 0xff);
|
|
112
|
-
const sg = srgbChannelToLinear(((start >>> 16) & 0xff) / 0xff);
|
|
113
|
-
const sb = srgbChannelToLinear(((start >>> 8) & 0xff) / 0xff);
|
|
114
|
-
const sa = (start & 0xff) / 0xff;
|
|
115
|
-
const er = srgbChannelToLinear(((end >>> 24) & 0xff) / 0xff);
|
|
116
|
-
const eg = srgbChannelToLinear(((end >>> 16) & 0xff) / 0xff);
|
|
117
|
-
const eb = srgbChannelToLinear(((end >>> 8) & 0xff) / 0xff);
|
|
118
|
-
const ea = (end & 0xff) / 0xff;
|
|
119
|
-
const r = sr + (er - sr) * tc;
|
|
120
|
-
const g = sg + (eg - sg) * tc;
|
|
121
|
-
const b = sb + (eb - sb) * tc;
|
|
122
|
-
const a = sa + (ea - sa) * tc;
|
|
123
|
-
return packLinearToColor([r, g, b, a]);
|
|
124
|
-
}
|
|
125
|
-
// Linearly interpolates between two LinearColors in linear space and writes the result to
|
|
126
|
-
// `out`. `t` is clamped to [0, 1]. Alias-safe: reads all input values before writing `out`.
|
|
127
|
-
export function lerpLinearColor(out, start, end, t) {
|
|
128
|
-
const tc = Math.min(1, Math.max(0, t));
|
|
129
|
-
const r0 = start[0];
|
|
130
|
-
const g0 = start[1];
|
|
131
|
-
const b0 = start[2];
|
|
132
|
-
const a0 = start[3];
|
|
133
|
-
const r1 = end[0];
|
|
134
|
-
const g1 = end[1];
|
|
135
|
-
const b1 = end[2];
|
|
136
|
-
const a1 = end[3];
|
|
137
|
-
out[0] = r0 + (r1 - r0) * tc;
|
|
138
|
-
out[1] = g0 + (g1 - g0) * tc;
|
|
139
|
-
out[2] = b0 + (b1 - b0) * tc;
|
|
140
|
-
out[3] = a0 + (a1 - a0) * tc;
|
|
141
|
-
return out;
|
|
142
|
-
}
|
|
143
|
-
// The IEC 61966-2-1 linear-to-sRGB inverse OETF for a single channel in [0, 1].
|
|
144
|
-
// Exported for callers that need per-channel conversion; the packed form is `packLinearToColor`.
|
|
145
|
-
export function linearChannelToSrgb(value) {
|
|
146
|
-
return value <= 0.0031308 ? value * 12.92 : 1.055 * value ** (1 / 2.4) - 0.055;
|
|
147
|
-
}
|
|
148
|
-
// Packs four sRGB-space components (each in [0, 1]) to a `0xRRGGBBAA` integer.
|
|
149
|
-
// Does NOT gamma-encode — use `packLinearToColor` when starting from linear floats.
|
|
150
|
-
// Components are clamped to [0, 1] and rounded to 8-bit precision.
|
|
151
|
-
export function packColor(r, g, b, a) {
|
|
152
|
-
const ri = Math.round(Math.min(1, Math.max(0, r)) * 0xff);
|
|
153
|
-
const gi = Math.round(Math.min(1, Math.max(0, g)) * 0xff);
|
|
154
|
-
const bi = Math.round(Math.min(1, Math.max(0, b)) * 0xff);
|
|
155
|
-
const ai = Math.round(Math.min(1, Math.max(0, a)) * 0xff);
|
|
156
|
-
return ((ri << 24) | (gi << 16) | (bi << 8) | ai) >>> 0;
|
|
157
|
-
}
|
|
158
|
-
// Packs a linear-space RGBA float color to a `0xRRGGBBAA` integer (the inverse of
|
|
159
|
-
// `unpackColorToLinear`). RGB channels are gamma-encoded to sRGB; alpha passes through
|
|
160
|
-
// unchanged (alpha is linear coverage, never gamma-encoded). Channels are clamped to [0, 1].
|
|
161
|
-
export function packLinearToColor(color) {
|
|
162
|
-
const r = Math.round(Math.min(1, Math.max(0, linearChannelToSrgb(color[0]))) * 0xff);
|
|
163
|
-
const g = Math.round(Math.min(1, Math.max(0, linearChannelToSrgb(color[1]))) * 0xff);
|
|
164
|
-
const b = Math.round(Math.min(1, Math.max(0, linearChannelToSrgb(color[2]))) * 0xff);
|
|
165
|
-
const a = Math.round(Math.min(1, Math.max(0, color[3])) * 0xff);
|
|
166
|
-
return ((r << 24) | (g << 16) | (b << 8) | a) >>> 0;
|
|
167
|
-
}
|
|
168
|
-
// Premultiplies the RGB channels of a packed sRGB `0xRRGGBBAA` color by its alpha channel
|
|
169
|
-
// and returns a new packed color. Output RGB = round(RGB × alpha). The alpha channel
|
|
170
|
-
// is preserved unchanged. Fully-transparent (alpha=0) results in black-with-alpha-0.
|
|
171
|
-
// Used when a renderer requires premultiplied-alpha color values.
|
|
172
|
-
export function premultiplyColorAlpha(color) {
|
|
173
|
-
const a = (color & 0xff) / 0xff;
|
|
174
|
-
const r = Math.round(((color >>> 24) & 0xff) * a);
|
|
175
|
-
const g = Math.round(((color >>> 16) & 0xff) * a);
|
|
176
|
-
const b = Math.round(((color >>> 8) & 0xff) * a);
|
|
177
|
-
return ((r << 24) | (g << 16) | (b << 8) | (color & 0xff)) >>> 0;
|
|
178
|
-
}
|
|
179
|
-
// Converts a packed sRGB `0xRRGGBBAA` color to HSL and writes to `out`.
|
|
180
|
-
// `out[0]` = hue in [0, 360), `out[1]` = saturation [0, 1], `out[2]` = lightness [0, 1].
|
|
181
|
-
// Alpha is ignored. The conversion operates in sRGB (non-linear) space, consistent with
|
|
182
|
-
// artist-facing HSL color pickers. Returns `out`.
|
|
183
|
-
export function rgbToHsl(out, color) {
|
|
184
|
-
const r = ((color >>> 24) & 0xff) / 0xff;
|
|
185
|
-
const g = ((color >>> 16) & 0xff) / 0xff;
|
|
186
|
-
const b = ((color >>> 8) & 0xff) / 0xff;
|
|
187
|
-
const max = Math.max(r, g, b);
|
|
188
|
-
const min = Math.min(r, g, b);
|
|
189
|
-
const l = (max + min) / 2;
|
|
190
|
-
if (max === min) {
|
|
191
|
-
out[0] = 0;
|
|
192
|
-
out[1] = 0;
|
|
193
|
-
out[2] = l;
|
|
194
|
-
return out;
|
|
195
|
-
}
|
|
196
|
-
const d = max - min;
|
|
197
|
-
const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
198
|
-
let h;
|
|
199
|
-
if (max === r) {
|
|
200
|
-
h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
|
|
201
|
-
}
|
|
202
|
-
else if (max === g) {
|
|
203
|
-
h = ((b - r) / d + 2) / 6;
|
|
204
|
-
}
|
|
205
|
-
else {
|
|
206
|
-
h = ((r - g) / d + 4) / 6;
|
|
207
|
-
}
|
|
208
|
-
out[0] = h * 360;
|
|
209
|
-
out[1] = s;
|
|
210
|
-
out[2] = l;
|
|
211
|
-
return out;
|
|
212
|
-
}
|
|
213
|
-
// Converts a packed sRGB `0xRRGGBBAA` color to HSV and writes to `out`.
|
|
214
|
-
// `out[0]` = hue in [0, 360), `out[1]` = saturation [0, 1], `out[2]` = value [0, 1].
|
|
215
|
-
// Alpha is ignored. The conversion operates in sRGB (non-linear) space. Returns `out`.
|
|
216
|
-
export function rgbToHsv(out, color) {
|
|
217
|
-
const r = ((color >>> 24) & 0xff) / 0xff;
|
|
218
|
-
const g = ((color >>> 16) & 0xff) / 0xff;
|
|
219
|
-
const b = ((color >>> 8) & 0xff) / 0xff;
|
|
220
|
-
const max = Math.max(r, g, b);
|
|
221
|
-
const min = Math.min(r, g, b);
|
|
222
|
-
const d = max - min;
|
|
223
|
-
const v = max;
|
|
224
|
-
const s = max === 0 ? 0 : d / max;
|
|
225
|
-
let h;
|
|
226
|
-
if (d === 0) {
|
|
227
|
-
h = 0;
|
|
228
|
-
}
|
|
229
|
-
else if (max === r) {
|
|
230
|
-
h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
|
|
231
|
-
}
|
|
232
|
-
else if (max === g) {
|
|
233
|
-
h = ((b - r) / d + 2) / 6;
|
|
234
|
-
}
|
|
235
|
-
else {
|
|
236
|
-
h = ((r - g) / d + 4) / 6;
|
|
237
|
-
}
|
|
238
|
-
out[0] = h * 360;
|
|
239
|
-
out[1] = s;
|
|
240
|
-
out[2] = v;
|
|
241
|
-
return out;
|
|
242
|
-
}
|
|
243
|
-
// Converts a packed sRGB-space `0xRRGGBBAA` integer into four components in [0, 1] and
|
|
244
|
-
// writes them to `out`. Does NOT gamma-decode — use `unpackColorToLinear` for linear space.
|
|
245
|
-
export function unpackColorRgba(out, color) {
|
|
246
|
-
out[0] = ((color >>> 24) & 0xff) / 0xff;
|
|
247
|
-
out[1] = ((color >>> 16) & 0xff) / 0xff;
|
|
248
|
-
out[2] = ((color >>> 8) & 0xff) / 0xff;
|
|
249
|
-
out[3] = (color & 0xff) / 0xff;
|
|
250
|
-
}
|
|
251
|
-
// The single sRgb→linear decode seam for the whole SDK (§0.2): packed `0xRRGGBBAA` is
|
|
252
|
-
// sRgb-albedo, so RGB is gamma-decoded to linear while alpha passes through unchanged
|
|
253
|
-
// (alpha is already linear coverage, never gamma-encoded). Writes four floats in [0, 1]
|
|
254
|
-
// into `out` and returns it. A packed 8-bit integer cannot carry HDR — light and emissive
|
|
255
|
-
// radiance is `unpackColorToLinear(out, color) × intensity`, computed by the caller.
|
|
256
|
-
// Backends must not re-decode packed colors; they consume this output.
|
|
257
|
-
export function unpackColorToLinear(out, color) {
|
|
258
|
-
out[0] = srgbChannelToLinear(((color >>> 24) & 0xff) / 0xff);
|
|
259
|
-
out[1] = srgbChannelToLinear(((color >>> 16) & 0xff) / 0xff);
|
|
260
|
-
out[2] = srgbChannelToLinear(((color >>> 8) & 0xff) / 0xff);
|
|
261
|
-
out[3] = (color & 0xff) / 0xff;
|
|
262
|
-
return out;
|
|
263
|
-
}
|
|
264
|
-
// Reverses premultiplied-alpha encoding for a packed sRGB `0xRRGGBBAA` color.
|
|
265
|
-
// Output RGB = round(RGB / alpha), clamped to [0, 255]. Returns the input unchanged
|
|
266
|
-
// when alpha is 0 (division-by-zero guard: fully-transparent stays black-with-alpha-0).
|
|
267
|
-
export function unpremultiplyColorAlpha(color) {
|
|
268
|
-
const a = (color & 0xff) / 0xff;
|
|
269
|
-
if (a === 0)
|
|
270
|
-
return color;
|
|
271
|
-
const r = Math.min(255, Math.round(((color >>> 24) & 0xff) / a));
|
|
272
|
-
const g = Math.min(255, Math.round(((color >>> 16) & 0xff) / a));
|
|
273
|
-
const b = Math.min(255, Math.round(((color >>> 8) & 0xff) / a));
|
|
274
|
-
return ((r << 24) | (g << 16) | (b << 8) | (color & 0xff)) >>> 0;
|
|
275
|
-
}
|
|
276
|
-
// HSL helper: interpolates a single channel from hue position `t`.
|
|
277
|
-
function hueToRgbChannel(p, q, t) {
|
|
278
|
-
const tn = ((t % 1) + 1) % 1;
|
|
279
|
-
if (tn < 1 / 6)
|
|
280
|
-
return p + (q - p) * 6 * tn;
|
|
281
|
-
if (tn < 1 / 2)
|
|
282
|
-
return q;
|
|
283
|
-
if (tn < 2 / 3)
|
|
284
|
-
return p + (q - p) * (2 / 3 - tn) * 6;
|
|
285
|
-
return p;
|
|
286
|
-
}
|
|
287
|
-
// The IEC 61966-2-1 sRgb electro-optical transfer function for a single channel in [0, 1].
|
|
288
|
-
function srgbChannelToLinear(value) {
|
|
289
|
-
return value <= 0.04045 ? value / 12.92 : ((value + 0.055) / 1.055) ** 2.4;
|
|
290
|
-
}
|
|
291
|
-
//# sourceMappingURL=color.js.map
|
package/dist/color.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"color.js","sourceRoot":"","sources":["../src/color.ts"],"names":[],"mappings":"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"}
|
package/src/color.test.ts
DELETED
|
@@ -1,383 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
computeRgbHexString,
|
|
3
|
-
createHslColor,
|
|
4
|
-
createHsvColor,
|
|
5
|
-
createLinearColor,
|
|
6
|
-
getColorContrastRatio,
|
|
7
|
-
getColorLuminance,
|
|
8
|
-
hslToRgb,
|
|
9
|
-
hsvToRgb,
|
|
10
|
-
lerpColor,
|
|
11
|
-
lerpLinearColor,
|
|
12
|
-
linearChannelToSrgb,
|
|
13
|
-
packColor,
|
|
14
|
-
packLinearToColor,
|
|
15
|
-
premultiplyColorAlpha,
|
|
16
|
-
rgbToHsl,
|
|
17
|
-
rgbToHsv,
|
|
18
|
-
unpackColorRgba,
|
|
19
|
-
unpackColorToLinear,
|
|
20
|
-
unpremultiplyColorAlpha,
|
|
21
|
-
} from './color';
|
|
22
|
-
|
|
23
|
-
describe('computeRgbHexString', () => {
|
|
24
|
-
it('returns a 6-digit hex string of the lower 24 bits', () => {
|
|
25
|
-
expect(computeRgbHexString(0x00ff0000)).toBe('#ff0000');
|
|
26
|
-
expect(computeRgbHexString(0x0000ff00)).toBe('#00ff00');
|
|
27
|
-
expect(computeRgbHexString(0x000000ff)).toBe('#0000ff');
|
|
28
|
-
expect(computeRgbHexString(0x00000000)).toBe('#000000');
|
|
29
|
-
expect(computeRgbHexString(0x00ffffff)).toBe('#ffffff');
|
|
30
|
-
});
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
describe('createHslColor', () => {
|
|
34
|
-
it('allocates a zeroed three-component HSL color', () => {
|
|
35
|
-
expect(createHslColor()).toEqual([0, 0, 0]);
|
|
36
|
-
});
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
describe('createHsvColor', () => {
|
|
40
|
-
it('allocates a zeroed three-component HSV color', () => {
|
|
41
|
-
expect(createHsvColor()).toEqual([0, 0, 0]);
|
|
42
|
-
});
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
describe('createLinearColor', () => {
|
|
46
|
-
it('allocates a zeroed four-component color', () => {
|
|
47
|
-
expect(createLinearColor()).toEqual([0, 0, 0, 0]);
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
describe('getColorContrastRatio', () => {
|
|
52
|
-
it('returns 21 for black on white', () => {
|
|
53
|
-
expect(getColorContrastRatio(0xffffffff, 0x000000ff)).toBeCloseTo(21, 0);
|
|
54
|
-
});
|
|
55
|
-
it('returns 1 for identical colors', () => {
|
|
56
|
-
expect(getColorContrastRatio(0x808080ff, 0x808080ff)).toBeCloseTo(1, 3);
|
|
57
|
-
});
|
|
58
|
-
it('is symmetric — order of arguments does not matter', () => {
|
|
59
|
-
const ratio1 = getColorContrastRatio(0xffffffff, 0x808080ff);
|
|
60
|
-
const ratio2 = getColorContrastRatio(0x808080ff, 0xffffffff);
|
|
61
|
-
expect(ratio1).toBeCloseTo(ratio2, 8);
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
describe('getColorLuminance', () => {
|
|
66
|
-
it('returns 1 for white', () => {
|
|
67
|
-
expect(getColorLuminance(0xffffffff)).toBeCloseTo(1, 5);
|
|
68
|
-
});
|
|
69
|
-
it('returns 0 for black', () => {
|
|
70
|
-
expect(getColorLuminance(0x000000ff)).toBeCloseTo(0, 5);
|
|
71
|
-
});
|
|
72
|
-
it('ignores the alpha channel', () => {
|
|
73
|
-
expect(getColorLuminance(0xffffffff)).toBe(getColorLuminance(0xffffff00));
|
|
74
|
-
});
|
|
75
|
-
it('matches expected Rec. 709 value for mid-gray sRGB', () => {
|
|
76
|
-
// sRGB 0x808080 → linear ≈ 0.21586; Rec.709: 0.2126*R + 0.7152*G + 0.0722*B = R (equal channels)
|
|
77
|
-
expect(getColorLuminance(0x808080ff)).toBeCloseTo(0.21586, 4);
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
describe('hslToRgb', () => {
|
|
82
|
-
it('produces achromatic RGB for saturation = 0', () => {
|
|
83
|
-
const out: [number, number, number, number] = [0, 0, 0, 1];
|
|
84
|
-
hslToRgb(out, 0, 0, 0.5);
|
|
85
|
-
expect(out[0]).toBeCloseTo(0.5);
|
|
86
|
-
expect(out[1]).toBeCloseTo(0.5);
|
|
87
|
-
expect(out[2]).toBeCloseTo(0.5);
|
|
88
|
-
});
|
|
89
|
-
it('round-trips with rgbToHsl for a primary color', () => {
|
|
90
|
-
// Red: hue=0, s=1, l=0.5 → RGB (1, 0, 0)
|
|
91
|
-
const out: [number, number, number, number] = [0, 0, 0, 1];
|
|
92
|
-
hslToRgb(out, 0, 1, 0.5);
|
|
93
|
-
expect(out[0]).toBeCloseTo(1, 5);
|
|
94
|
-
expect(out[1]).toBeCloseTo(0, 5);
|
|
95
|
-
expect(out[2]).toBeCloseTo(0, 5);
|
|
96
|
-
});
|
|
97
|
-
it('does not modify out[3] (alpha)', () => {
|
|
98
|
-
const out: [number, number, number, number] = [0, 0, 0, 0.75];
|
|
99
|
-
hslToRgb(out, 120, 1, 0.5);
|
|
100
|
-
expect(out[3]).toBe(0.75);
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
describe('hsvToRgb', () => {
|
|
105
|
-
it('produces achromatic RGB for saturation = 0', () => {
|
|
106
|
-
const out: [number, number, number, number] = [0, 0, 0, 1];
|
|
107
|
-
hsvToRgb(out, 0, 0, 0.6);
|
|
108
|
-
expect(out[0]).toBeCloseTo(0.6);
|
|
109
|
-
expect(out[1]).toBeCloseTo(0.6);
|
|
110
|
-
expect(out[2]).toBeCloseTo(0.6);
|
|
111
|
-
});
|
|
112
|
-
it('produces pure red for h=0, s=1, v=1', () => {
|
|
113
|
-
const out: [number, number, number, number] = [0, 0, 0, 1];
|
|
114
|
-
hsvToRgb(out, 0, 1, 1);
|
|
115
|
-
expect(out[0]).toBeCloseTo(1, 5);
|
|
116
|
-
expect(out[1]).toBeCloseTo(0, 5);
|
|
117
|
-
expect(out[2]).toBeCloseTo(0, 5);
|
|
118
|
-
});
|
|
119
|
-
it('round-trips with rgbToHsv for a pure green', () => {
|
|
120
|
-
const out: [number, number, number, number] = [0, 0, 0, 1];
|
|
121
|
-
hsvToRgb(out, 120, 1, 1);
|
|
122
|
-
expect(out[0]).toBeCloseTo(0, 5);
|
|
123
|
-
expect(out[1]).toBeCloseTo(1, 5);
|
|
124
|
-
expect(out[2]).toBeCloseTo(0, 5);
|
|
125
|
-
});
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
describe('lerpColor', () => {
|
|
129
|
-
it('returns start at t=0', () => {
|
|
130
|
-
expect(lerpColor(0xff0000ff, 0x0000ffff, 0)).toBe(0xff0000ff);
|
|
131
|
-
});
|
|
132
|
-
it('returns end at t=1', () => {
|
|
133
|
-
expect(lerpColor(0xff0000ff, 0x0000ffff, 1)).toBe(0x0000ffff);
|
|
134
|
-
});
|
|
135
|
-
it('clamps t below 0 to 0', () => {
|
|
136
|
-
expect(lerpColor(0xff0000ff, 0x0000ffff, -1)).toBe(0xff0000ff);
|
|
137
|
-
});
|
|
138
|
-
it('clamps t above 1 to 1', () => {
|
|
139
|
-
expect(lerpColor(0xff0000ff, 0x0000ffff, 2)).toBe(0x0000ffff);
|
|
140
|
-
});
|
|
141
|
-
it('midpoint between black and white is approximately mid-gray', () => {
|
|
142
|
-
// Black (linear 0) and white (linear 1) — midpoint in linear is 0.5, which in sRGB ≈ 0xbc
|
|
143
|
-
const mid = lerpColor(0x000000ff, 0xffffffff, 0.5);
|
|
144
|
-
const r = (mid >>> 24) & 0xff;
|
|
145
|
-
// linear 0.5 → sRGB ≈ 0xbc (188)
|
|
146
|
-
expect(r).toBeCloseTo(0xbc, -1);
|
|
147
|
-
});
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
describe('lerpLinearColor', () => {
|
|
151
|
-
it('returns start at t=0', () => {
|
|
152
|
-
const out = createLinearColor();
|
|
153
|
-
const start: [number, number, number, number] = [1, 0, 0, 1];
|
|
154
|
-
const end: [number, number, number, number] = [0, 0, 1, 1];
|
|
155
|
-
lerpLinearColor(out, start, end, 0);
|
|
156
|
-
expect(out).toEqual(start);
|
|
157
|
-
});
|
|
158
|
-
it('returns end at t=1', () => {
|
|
159
|
-
const out = createLinearColor();
|
|
160
|
-
const start: [number, number, number, number] = [1, 0, 0, 1];
|
|
161
|
-
const end: [number, number, number, number] = [0, 0, 1, 1];
|
|
162
|
-
lerpLinearColor(out, start, end, 1);
|
|
163
|
-
expect(out).toEqual(end);
|
|
164
|
-
});
|
|
165
|
-
it('is alias-safe when out is the same object as start', () => {
|
|
166
|
-
const start: [number, number, number, number] = [1, 0, 0, 1];
|
|
167
|
-
const end: [number, number, number, number] = [0, 0, 1, 1];
|
|
168
|
-
const out = start;
|
|
169
|
-
lerpLinearColor(out, out, end, 0.5);
|
|
170
|
-
expect(out[0]).toBeCloseTo(0.5, 8);
|
|
171
|
-
expect(out[2]).toBeCloseTo(0.5, 8);
|
|
172
|
-
});
|
|
173
|
-
it('returns the out instance', () => {
|
|
174
|
-
const out = createLinearColor();
|
|
175
|
-
const start: [number, number, number, number] = [0, 0, 0, 0];
|
|
176
|
-
const end: [number, number, number, number] = [1, 1, 1, 1];
|
|
177
|
-
expect(lerpLinearColor(out, start, end, 0.5)).toBe(out);
|
|
178
|
-
});
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
describe('linearChannelToSrgb', () => {
|
|
182
|
-
it('maps 0 → 0', () => {
|
|
183
|
-
expect(linearChannelToSrgb(0)).toBe(0);
|
|
184
|
-
});
|
|
185
|
-
it('maps 1 → 1', () => {
|
|
186
|
-
expect(linearChannelToSrgb(1)).toBeCloseTo(1, 8);
|
|
187
|
-
});
|
|
188
|
-
it('is the inverse of the sRGB decode for a round-trip', () => {
|
|
189
|
-
// A known linear value near the breakpoint.
|
|
190
|
-
const linear = 0.5;
|
|
191
|
-
const srgb = linearChannelToSrgb(linear);
|
|
192
|
-
// Re-encode: sRGB(linear(x)) should round-trip within floating-point tolerance.
|
|
193
|
-
const roundTrip = srgb <= 0.04045 ? srgb / 12.92 : ((srgb + 0.055) / 1.055) ** 2.4;
|
|
194
|
-
expect(roundTrip).toBeCloseTo(linear, 5);
|
|
195
|
-
});
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
describe('packColor', () => {
|
|
199
|
-
it('packs white components to 0xffffffff', () => {
|
|
200
|
-
expect(packColor(1, 1, 1, 1)).toBe(0xffffffff);
|
|
201
|
-
});
|
|
202
|
-
it('packs black components to 0x000000ff', () => {
|
|
203
|
-
expect(packColor(0, 0, 0, 1)).toBe(0x000000ff);
|
|
204
|
-
});
|
|
205
|
-
it('clamps out-of-range values', () => {
|
|
206
|
-
expect(packColor(2, -1, 0.5, 1)).toBe(packColor(1, 0, 0.5, 1));
|
|
207
|
-
});
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
describe('packLinearToColor', () => {
|
|
211
|
-
it('is the inverse of unpackColorToLinear for white', () => {
|
|
212
|
-
const out = createLinearColor();
|
|
213
|
-
unpackColorToLinear(out, 0xffffffff);
|
|
214
|
-
expect(packLinearToColor(out)).toBe(0xffffffff);
|
|
215
|
-
});
|
|
216
|
-
it('is the inverse of unpackColorToLinear for black (opaque)', () => {
|
|
217
|
-
const out = createLinearColor();
|
|
218
|
-
unpackColorToLinear(out, 0x000000ff);
|
|
219
|
-
expect(packLinearToColor(out)).toBe(0x000000ff);
|
|
220
|
-
});
|
|
221
|
-
it('passes alpha through without gamma encoding', () => {
|
|
222
|
-
// Alpha 0x80 / 0xff ≈ 0.502; should round-trip through linear-space alpha.
|
|
223
|
-
const color = 0x000000_80 >>> 0;
|
|
224
|
-
const out = createLinearColor();
|
|
225
|
-
unpackColorToLinear(out, color);
|
|
226
|
-
const repacked = packLinearToColor(out);
|
|
227
|
-
expect(repacked & 0xff).toBe(0x80);
|
|
228
|
-
});
|
|
229
|
-
it('round-trips a mid-gray color within 1 LSB', () => {
|
|
230
|
-
const color = 0x808080ff >>> 0;
|
|
231
|
-
const out = createLinearColor();
|
|
232
|
-
unpackColorToLinear(out, color);
|
|
233
|
-
const repacked = packLinearToColor(out);
|
|
234
|
-
const origR = (color >>> 24) & 0xff;
|
|
235
|
-
const repR = (repacked >>> 24) & 0xff;
|
|
236
|
-
expect(Math.abs(repR - origR)).toBeLessThanOrEqual(1);
|
|
237
|
-
});
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
describe('premultiplyColorAlpha', () => {
|
|
241
|
-
it('returns fully-opaque color unchanged (alpha=1)', () => {
|
|
242
|
-
expect(premultiplyColorAlpha(0xff0000ff)).toBe(0xff0000ff);
|
|
243
|
-
});
|
|
244
|
-
it('multiplies RGB by alpha and preserves the alpha channel', () => {
|
|
245
|
-
// Red at 50% alpha: R=255*0.502≈128, A unchanged=0x80
|
|
246
|
-
const result = premultiplyColorAlpha(0xff00007f);
|
|
247
|
-
expect((result >>> 24) & 0xff).toBeCloseTo(0x7f, -1);
|
|
248
|
-
expect(result & 0xff).toBe(0x7f);
|
|
249
|
-
});
|
|
250
|
-
it('returns black-with-alpha-0 for fully transparent color', () => {
|
|
251
|
-
const result = premultiplyColorAlpha(0xff000000);
|
|
252
|
-
expect(result & 0xff).toBe(0);
|
|
253
|
-
expect((result >>> 24) & 0xff).toBe(0);
|
|
254
|
-
});
|
|
255
|
-
it('round-trips with unpremultiplyColorAlpha for fully-opaque', () => {
|
|
256
|
-
const color = 0xab3456ff;
|
|
257
|
-
expect(unpremultiplyColorAlpha(premultiplyColorAlpha(color))).toBe(color);
|
|
258
|
-
});
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
describe('rgbToHsl', () => {
|
|
262
|
-
it('converts pure red to hue=0, s=1, l=0.5', () => {
|
|
263
|
-
const out: [number, number, number] = [0, 0, 0];
|
|
264
|
-
rgbToHsl(out, 0xff0000ff);
|
|
265
|
-
expect(out[0]).toBeCloseTo(0, 3);
|
|
266
|
-
expect(out[1]).toBeCloseTo(1, 5);
|
|
267
|
-
expect(out[2]).toBeCloseTo(0.5, 5);
|
|
268
|
-
});
|
|
269
|
-
it('converts white to hue=0, s=0, l=1', () => {
|
|
270
|
-
const out: [number, number, number] = [0, 0, 0];
|
|
271
|
-
rgbToHsl(out, 0xffffffff);
|
|
272
|
-
expect(out[0]).toBe(0);
|
|
273
|
-
expect(out[1]).toBe(0);
|
|
274
|
-
expect(out[2]).toBeCloseTo(1, 5);
|
|
275
|
-
});
|
|
276
|
-
it('converts black to hue=0, s=0, l=0', () => {
|
|
277
|
-
const out: [number, number, number] = [0, 0, 0];
|
|
278
|
-
rgbToHsl(out, 0x000000ff);
|
|
279
|
-
expect(out[0]).toBe(0);
|
|
280
|
-
expect(out[1]).toBe(0);
|
|
281
|
-
expect(out[2]).toBeCloseTo(0, 5);
|
|
282
|
-
});
|
|
283
|
-
it('returns the out instance', () => {
|
|
284
|
-
const out: [number, number, number] = [0, 0, 0];
|
|
285
|
-
expect(rgbToHsl(out, 0xff0000ff)).toBe(out);
|
|
286
|
-
});
|
|
287
|
-
it('round-trips with hslToRgb within 1 LSB', () => {
|
|
288
|
-
const hsl: [number, number, number] = [0, 0, 0];
|
|
289
|
-
rgbToHsl(hsl, 0x3c8ab5ff);
|
|
290
|
-
const rgb: [number, number, number, number] = [0, 0, 0, 1];
|
|
291
|
-
hslToRgb(rgb, hsl[0], hsl[1], hsl[2]);
|
|
292
|
-
const repacked =
|
|
293
|
-
(Math.round(rgb[0] * 0xff) << 24) | (Math.round(rgb[1] * 0xff) << 16) | (Math.round(rgb[2] * 0xff) << 8) | 0xff;
|
|
294
|
-
const orig = 0x3c8ab5ff >>> 0;
|
|
295
|
-
expect(Math.abs(((repacked >>> 24) & 0xff) - ((orig >>> 24) & 0xff))).toBeLessThanOrEqual(1);
|
|
296
|
-
});
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
describe('rgbToHsv', () => {
|
|
300
|
-
it('converts pure red to hue=0, s=1, v=1', () => {
|
|
301
|
-
const out: [number, number, number] = [0, 0, 0];
|
|
302
|
-
rgbToHsv(out, 0xff0000ff);
|
|
303
|
-
expect(out[0]).toBeCloseTo(0, 3);
|
|
304
|
-
expect(out[1]).toBeCloseTo(1, 5);
|
|
305
|
-
expect(out[2]).toBeCloseTo(1, 5);
|
|
306
|
-
});
|
|
307
|
-
it('converts black to s=0, v=0', () => {
|
|
308
|
-
const out: [number, number, number] = [0, 0, 0];
|
|
309
|
-
rgbToHsv(out, 0x000000ff);
|
|
310
|
-
expect(out[1]).toBe(0);
|
|
311
|
-
expect(out[2]).toBeCloseTo(0, 5);
|
|
312
|
-
});
|
|
313
|
-
it('converts white to s=0, v=1', () => {
|
|
314
|
-
const out: [number, number, number] = [0, 0, 0];
|
|
315
|
-
rgbToHsv(out, 0xffffffff);
|
|
316
|
-
expect(out[1]).toBe(0);
|
|
317
|
-
expect(out[2]).toBeCloseTo(1, 5);
|
|
318
|
-
});
|
|
319
|
-
it('returns the out instance', () => {
|
|
320
|
-
const out: [number, number, number] = [0, 0, 0];
|
|
321
|
-
expect(rgbToHsv(out, 0xff0000ff)).toBe(out);
|
|
322
|
-
});
|
|
323
|
-
});
|
|
324
|
-
|
|
325
|
-
describe('unpackColorRgba', () => {
|
|
326
|
-
it('extracts white as all-ones', () => {
|
|
327
|
-
const out: [number, number, number, number] = [0, 0, 0, 0];
|
|
328
|
-
unpackColorRgba(out, 0xffffffff);
|
|
329
|
-
expect(out[0]).toBeCloseTo(1, 5);
|
|
330
|
-
expect(out[1]).toBeCloseTo(1, 5);
|
|
331
|
-
expect(out[2]).toBeCloseTo(1, 5);
|
|
332
|
-
expect(out[3]).toBeCloseTo(1, 5);
|
|
333
|
-
});
|
|
334
|
-
it('does NOT gamma-decode — mid sRGB stays above the linear midpoint', () => {
|
|
335
|
-
const out: [number, number, number, number] = [0, 0, 0, 0];
|
|
336
|
-
unpackColorRgba(out, 0x808080ff);
|
|
337
|
-
// Without gamma decode, 0x80/0xff ≈ 0.502 — above the linear midpoint.
|
|
338
|
-
expect(out[0]).toBeCloseTo(0x80 / 0xff, 4);
|
|
339
|
-
});
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
describe('unpackColorToLinear', () => {
|
|
343
|
-
it('decodes white and black exactly at the endpoints', () => {
|
|
344
|
-
const out = createLinearColor();
|
|
345
|
-
expect(unpackColorToLinear(out, 0xffffffff)).toEqual([1, 1, 1, 1]);
|
|
346
|
-
expect(unpackColorToLinear(out, 0x000000ff)).toEqual([0, 0, 0, 1]);
|
|
347
|
-
});
|
|
348
|
-
|
|
349
|
-
it('passes alpha through linearly without gamma decode', () => {
|
|
350
|
-
const out = createLinearColor();
|
|
351
|
-
unpackColorToLinear(out, 0x00000080);
|
|
352
|
-
expect(out[3]).toBeCloseTo(0x80 / 0xff, 6);
|
|
353
|
-
});
|
|
354
|
-
|
|
355
|
-
it('gamma-decodes RGB so mid sRgb is below the linear midpoint', () => {
|
|
356
|
-
const out = createLinearColor();
|
|
357
|
-
unpackColorToLinear(out, 0x808080ff);
|
|
358
|
-
expect(out[0]).toBeCloseTo(0.21586, 4);
|
|
359
|
-
expect(out[0]).toBe(out[1]);
|
|
360
|
-
expect(out[1]).toBe(out[2]);
|
|
361
|
-
});
|
|
362
|
-
|
|
363
|
-
it('returns the same out instance it was given', () => {
|
|
364
|
-
const out = createLinearColor();
|
|
365
|
-
expect(unpackColorToLinear(out, 0xff0000ff)).toBe(out);
|
|
366
|
-
});
|
|
367
|
-
});
|
|
368
|
-
|
|
369
|
-
describe('unpremultiplyColorAlpha', () => {
|
|
370
|
-
it('returns fully-opaque color unchanged', () => {
|
|
371
|
-
expect(unpremultiplyColorAlpha(0xff0000ff)).toBe(0xff0000ff);
|
|
372
|
-
});
|
|
373
|
-
it('divides RGB by alpha and preserves the alpha channel', () => {
|
|
374
|
-
// Premultiplied: R=128 (≈0x80), A=0x80 → straight: R ≈ 255
|
|
375
|
-
const premul = premultiplyColorAlpha((0xff0000ff & (0xffffff80 >>> 0)) | 0x80);
|
|
376
|
-
const result = unpremultiplyColorAlpha(premul);
|
|
377
|
-
expect(result & 0xff).toBe(0x80);
|
|
378
|
-
});
|
|
379
|
-
it('returns the input unchanged for alpha=0', () => {
|
|
380
|
-
const color = 0xff000000;
|
|
381
|
-
expect(unpremultiplyColorAlpha(color)).toBe(color);
|
|
382
|
-
});
|
|
383
|
-
});
|