@flighthq/effects 0.1.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.
- package/dist/autoExposureEffect.d.ts +3 -0
- package/dist/autoExposureEffect.d.ts.map +1 -0
- package/dist/autoExposureEffect.js +4 -0
- package/dist/autoExposureEffect.js.map +1 -0
- package/dist/barrelDistortionEffect.d.ts +3 -0
- package/dist/barrelDistortionEffect.d.ts.map +1 -0
- package/dist/barrelDistortionEffect.js +4 -0
- package/dist/barrelDistortionEffect.js.map +1 -0
- package/dist/bloomEffect.d.ts +6 -0
- package/dist/bloomEffect.d.ts.map +1 -0
- package/dist/bloomEffect.js +16 -0
- package/dist/bloomEffect.js.map +1 -0
- package/dist/bokehDepthOfFieldEffect.d.ts +3 -0
- package/dist/bokehDepthOfFieldEffect.d.ts.map +1 -0
- package/dist/bokehDepthOfFieldEffect.js +4 -0
- package/dist/bokehDepthOfFieldEffect.js.map +1 -0
- package/dist/brightnessContrastEffect.d.ts +3 -0
- package/dist/brightnessContrastEffect.d.ts.map +1 -0
- package/dist/brightnessContrastEffect.js +4 -0
- package/dist/brightnessContrastEffect.js.map +1 -0
- package/dist/cameraMotionBlurEffect.d.ts +3 -0
- package/dist/cameraMotionBlurEffect.d.ts.map +1 -0
- package/dist/cameraMotionBlurEffect.js +4 -0
- package/dist/cameraMotionBlurEffect.js.map +1 -0
- package/dist/channelMixerEffect.d.ts +3 -0
- package/dist/channelMixerEffect.d.ts.map +1 -0
- package/dist/channelMixerEffect.js +4 -0
- package/dist/channelMixerEffect.js.map +1 -0
- package/dist/chromaticAberrationEffect.d.ts +3 -0
- package/dist/chromaticAberrationEffect.d.ts.map +1 -0
- package/dist/chromaticAberrationEffect.js +4 -0
- package/dist/chromaticAberrationEffect.js.map +1 -0
- package/dist/colorBlindSimulationEffect.d.ts +3 -0
- package/dist/colorBlindSimulationEffect.d.ts.map +1 -0
- package/dist/colorBlindSimulationEffect.js +4 -0
- package/dist/colorBlindSimulationEffect.js.map +1 -0
- package/dist/colorGradeEffect.d.ts +3 -0
- package/dist/colorGradeEffect.d.ts.map +1 -0
- package/dist/colorGradeEffect.js +4 -0
- package/dist/colorGradeEffect.js.map +1 -0
- package/dist/colorScienceMath.d.ts +9 -0
- package/dist/colorScienceMath.d.ts.map +1 -0
- package/dist/colorScienceMath.js +135 -0
- package/dist/colorScienceMath.js.map +1 -0
- package/dist/colorTemperatureMath.d.ts +5 -0
- package/dist/colorTemperatureMath.d.ts.map +1 -0
- package/dist/colorTemperatureMath.js +45 -0
- package/dist/colorTemperatureMath.js.map +1 -0
- package/dist/contactShadowsEffect.d.ts +3 -0
- package/dist/contactShadowsEffect.d.ts.map +1 -0
- package/dist/contactShadowsEffect.js +4 -0
- package/dist/contactShadowsEffect.js.map +1 -0
- package/dist/crtEffect.d.ts +3 -0
- package/dist/crtEffect.d.ts.map +1 -0
- package/dist/crtEffect.js +4 -0
- package/dist/crtEffect.js.map +1 -0
- package/dist/customShaderEffect.d.ts +3 -0
- package/dist/customShaderEffect.d.ts.map +1 -0
- package/dist/customShaderEffect.js +4 -0
- package/dist/customShaderEffect.js.map +1 -0
- package/dist/depthMath.d.ts +4 -0
- package/dist/depthMath.d.ts.map +1 -0
- package/dist/depthMath.js +55 -0
- package/dist/depthMath.js.map +1 -0
- package/dist/directionalBlurEffect.d.ts +3 -0
- package/dist/directionalBlurEffect.d.ts.map +1 -0
- package/dist/directionalBlurEffect.js +4 -0
- package/dist/directionalBlurEffect.js.map +1 -0
- package/dist/displacementEffect.d.ts +3 -0
- package/dist/displacementEffect.d.ts.map +1 -0
- package/dist/displacementEffect.js +4 -0
- package/dist/displacementEffect.js.map +1 -0
- package/dist/ditherEffect.d.ts +3 -0
- package/dist/ditherEffect.d.ts.map +1 -0
- package/dist/ditherEffect.js +4 -0
- package/dist/ditherEffect.js.map +1 -0
- package/dist/edgeDetectMath.d.ts +6 -0
- package/dist/edgeDetectMath.d.ts.map +1 -0
- package/dist/edgeDetectMath.js +72 -0
- package/dist/edgeDetectMath.js.map +1 -0
- package/dist/exposureEffect.d.ts +3 -0
- package/dist/exposureEffect.d.ts.map +1 -0
- package/dist/exposureEffect.js +4 -0
- package/dist/exposureEffect.js.map +1 -0
- package/dist/filmEmulationEffect.d.ts +3 -0
- package/dist/filmEmulationEffect.d.ts.map +1 -0
- package/dist/filmEmulationEffect.js +4 -0
- package/dist/filmEmulationEffect.js.map +1 -0
- package/dist/filmGrainEffect.d.ts +3 -0
- package/dist/filmGrainEffect.d.ts.map +1 -0
- package/dist/filmGrainEffect.js +4 -0
- package/dist/filmGrainEffect.js.map +1 -0
- package/dist/fxaaEffect.d.ts +3 -0
- package/dist/fxaaEffect.d.ts.map +1 -0
- package/dist/fxaaEffect.js +4 -0
- package/dist/fxaaEffect.js.map +1 -0
- package/dist/gaussianMath.d.ts +5 -0
- package/dist/gaussianMath.d.ts.map +1 -0
- package/dist/gaussianMath.js +42 -0
- package/dist/gaussianMath.js.map +1 -0
- package/dist/glitchEffect.d.ts +3 -0
- package/dist/glitchEffect.d.ts.map +1 -0
- package/dist/glitchEffect.js +4 -0
- package/dist/glitchEffect.js.map +1 -0
- package/dist/godRaysEffect.d.ts +3 -0
- package/dist/godRaysEffect.d.ts.map +1 -0
- package/dist/godRaysEffect.js +4 -0
- package/dist/godRaysEffect.js.map +1 -0
- package/dist/godRaysMath.d.ts +8 -0
- package/dist/godRaysMath.d.ts.map +1 -0
- package/dist/godRaysMath.js +49 -0
- package/dist/godRaysMath.js.map +1 -0
- package/dist/grayscaleEffect.d.ts +3 -0
- package/dist/grayscaleEffect.d.ts.map +1 -0
- package/dist/grayscaleEffect.js +4 -0
- package/dist/grayscaleEffect.js.map +1 -0
- package/dist/halftoneEffect.d.ts +3 -0
- package/dist/halftoneEffect.d.ts.map +1 -0
- package/dist/halftoneEffect.js +4 -0
- package/dist/halftoneEffect.js.map +1 -0
- package/dist/hueSaturationEffect.d.ts +3 -0
- package/dist/hueSaturationEffect.d.ts.map +1 -0
- package/dist/hueSaturationEffect.js +4 -0
- package/dist/hueSaturationEffect.js.map +1 -0
- package/dist/index.d.ts +67 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +67 -0
- package/dist/index.js.map +1 -0
- package/dist/invertEffect.d.ts +3 -0
- package/dist/invertEffect.d.ts.map +1 -0
- package/dist/invertEffect.js +4 -0
- package/dist/invertEffect.js.map +1 -0
- package/dist/kuwaharaEffect.d.ts +3 -0
- package/dist/kuwaharaEffect.d.ts.map +1 -0
- package/dist/kuwaharaEffect.js +4 -0
- package/dist/kuwaharaEffect.js.map +1 -0
- package/dist/kuwaharaMath.d.ts +6 -0
- package/dist/kuwaharaMath.d.ts.map +1 -0
- package/dist/kuwaharaMath.js +70 -0
- package/dist/kuwaharaMath.js.map +1 -0
- package/dist/lensDirtEffect.d.ts +3 -0
- package/dist/lensDirtEffect.d.ts.map +1 -0
- package/dist/lensDirtEffect.js +4 -0
- package/dist/lensDirtEffect.js.map +1 -0
- package/dist/lensDistortionEffect.d.ts +3 -0
- package/dist/lensDistortionEffect.d.ts.map +1 -0
- package/dist/lensDistortionEffect.js +4 -0
- package/dist/lensDistortionEffect.js.map +1 -0
- package/dist/lensFlareEffect.d.ts +3 -0
- package/dist/lensFlareEffect.d.ts.map +1 -0
- package/dist/lensFlareEffect.js +4 -0
- package/dist/lensFlareEffect.js.map +1 -0
- package/dist/liftGammaGainEffect.d.ts +3 -0
- package/dist/liftGammaGainEffect.d.ts.map +1 -0
- package/dist/liftGammaGainEffect.js +4 -0
- package/dist/liftGammaGainEffect.js.map +1 -0
- package/dist/lookupTableGradeEffect.d.ts +3 -0
- package/dist/lookupTableGradeEffect.d.ts.map +1 -0
- package/dist/lookupTableGradeEffect.js +4 -0
- package/dist/lookupTableGradeEffect.js.map +1 -0
- package/dist/lutMath.d.ts +7 -0
- package/dist/lutMath.d.ts.map +1 -0
- package/dist/lutMath.js +39 -0
- package/dist/lutMath.js.map +1 -0
- package/dist/motionBlurEffect.d.ts +3 -0
- package/dist/motionBlurEffect.d.ts.map +1 -0
- package/dist/motionBlurEffect.js +4 -0
- package/dist/motionBlurEffect.js.map +1 -0
- package/dist/outlineEffect.d.ts +3 -0
- package/dist/outlineEffect.d.ts.map +1 -0
- package/dist/outlineEffect.js +4 -0
- package/dist/outlineEffect.js.map +1 -0
- package/dist/panniniProjectionEffect.d.ts +3 -0
- package/dist/panniniProjectionEffect.d.ts.map +1 -0
- package/dist/panniniProjectionEffect.js +4 -0
- package/dist/panniniProjectionEffect.js.map +1 -0
- package/dist/pixelateEffect.d.ts +3 -0
- package/dist/pixelateEffect.d.ts.map +1 -0
- package/dist/pixelateEffect.js +4 -0
- package/dist/pixelateEffect.js.map +1 -0
- package/dist/posterizeEffect.d.ts +3 -0
- package/dist/posterizeEffect.d.ts.map +1 -0
- package/dist/posterizeEffect.js +4 -0
- package/dist/posterizeEffect.js.map +1 -0
- package/dist/radialBlurEffect.d.ts +3 -0
- package/dist/radialBlurEffect.d.ts.map +1 -0
- package/dist/radialBlurEffect.js +4 -0
- package/dist/radialBlurEffect.js.map +1 -0
- package/dist/renderEffectDefaults.d.ts +4 -0
- package/dist/renderEffectDefaults.d.ts.map +1 -0
- package/dist/renderEffectDefaults.js +111 -0
- package/dist/renderEffectDefaults.js.map +1 -0
- package/dist/renderEffectInputs.d.ts +5 -0
- package/dist/renderEffectInputs.d.ts.map +1 -0
- package/dist/renderEffectInputs.js +87 -0
- package/dist/renderEffectInputs.js.map +1 -0
- package/dist/renderEffectInterpolation.d.ts +4 -0
- package/dist/renderEffectInterpolation.d.ts.map +1 -0
- package/dist/renderEffectInterpolation.js +75 -0
- package/dist/renderEffectInterpolation.js.map +1 -0
- package/dist/renderEffectValidation.d.ts +3 -0
- package/dist/renderEffectValidation.d.ts.map +1 -0
- package/dist/renderEffectValidation.js +18 -0
- package/dist/renderEffectValidation.js.map +1 -0
- package/dist/scanlinesEffect.d.ts +3 -0
- package/dist/scanlinesEffect.d.ts.map +1 -0
- package/dist/scanlinesEffect.js +4 -0
- package/dist/scanlinesEffect.js.map +1 -0
- package/dist/screenSpaceFogEffect.d.ts +3 -0
- package/dist/screenSpaceFogEffect.d.ts.map +1 -0
- package/dist/screenSpaceFogEffect.js +4 -0
- package/dist/screenSpaceFogEffect.js.map +1 -0
- package/dist/sepiaEffect.d.ts +3 -0
- package/dist/sepiaEffect.d.ts.map +1 -0
- package/dist/sepiaEffect.js +4 -0
- package/dist/sepiaEffect.js.map +1 -0
- package/dist/sharpenEffect.d.ts +3 -0
- package/dist/sharpenEffect.d.ts.map +1 -0
- package/dist/sharpenEffect.js +4 -0
- package/dist/sharpenEffect.js.map +1 -0
- package/dist/sketchEffect.d.ts +3 -0
- package/dist/sketchEffect.d.ts.map +1 -0
- package/dist/sketchEffect.js +4 -0
- package/dist/sketchEffect.js.map +1 -0
- package/dist/smaaEffect.d.ts +3 -0
- package/dist/smaaEffect.d.ts.map +1 -0
- package/dist/smaaEffect.js +4 -0
- package/dist/smaaEffect.js.map +1 -0
- package/dist/ssaoEffect.d.ts +3 -0
- package/dist/ssaoEffect.d.ts.map +1 -0
- package/dist/ssaoEffect.js +4 -0
- package/dist/ssaoEffect.js.map +1 -0
- package/dist/ssrEffect.d.ts +3 -0
- package/dist/ssrEffect.d.ts.map +1 -0
- package/dist/ssrEffect.js +4 -0
- package/dist/ssrEffect.js.map +1 -0
- package/dist/stylizeMath.d.ts +9 -0
- package/dist/stylizeMath.d.ts.map +1 -0
- package/dist/stylizeMath.js +77 -0
- package/dist/stylizeMath.js.map +1 -0
- package/dist/taaEffect.d.ts +3 -0
- package/dist/taaEffect.d.ts.map +1 -0
- package/dist/taaEffect.js +4 -0
- package/dist/taaEffect.js.map +1 -0
- package/dist/tiltShiftEffect.d.ts +3 -0
- package/dist/tiltShiftEffect.d.ts.map +1 -0
- package/dist/tiltShiftEffect.js +4 -0
- package/dist/tiltShiftEffect.js.map +1 -0
- package/dist/toneMapEffect.d.ts +3 -0
- package/dist/toneMapEffect.d.ts.map +1 -0
- package/dist/toneMapEffect.js +4 -0
- package/dist/toneMapEffect.js.map +1 -0
- package/dist/toneMapMath.d.ts +12 -0
- package/dist/toneMapMath.d.ts.map +1 -0
- package/dist/toneMapMath.js +110 -0
- package/dist/toneMapMath.js.map +1 -0
- package/dist/vignetteEffect.d.ts +3 -0
- package/dist/vignetteEffect.d.ts.map +1 -0
- package/dist/vignetteEffect.js +4 -0
- package/dist/vignetteEffect.js.map +1 -0
- package/dist/volumetricLightEffect.d.ts +3 -0
- package/dist/volumetricLightEffect.d.ts.map +1 -0
- package/dist/volumetricLightEffect.js +4 -0
- package/dist/volumetricLightEffect.js.map +1 -0
- package/dist/whiteBalanceEffect.d.ts +3 -0
- package/dist/whiteBalanceEffect.d.ts.map +1 -0
- package/dist/whiteBalanceEffect.js +4 -0
- package/dist/whiteBalanceEffect.js.map +1 -0
- package/package.json +37 -0
- package/src/autoExposureEffect.test.ts +11 -0
- package/src/barrelDistortionEffect.test.ts +11 -0
- package/src/bloomEffect.test.ts +41 -0
- package/src/bokehDepthOfFieldEffect.test.ts +15 -0
- package/src/brightnessContrastEffect.test.ts +14 -0
- package/src/cameraMotionBlurEffect.test.ts +14 -0
- package/src/channelMixerEffect.test.ts +12 -0
- package/src/chromaticAberrationEffect.test.ts +14 -0
- package/src/colorBlindSimulationEffect.test.ts +13 -0
- package/src/colorGradeEffect.test.ts +11 -0
- package/src/colorScienceMath.test.ts +160 -0
- package/src/colorTemperatureMath.test.ts +67 -0
- package/src/contactShadowsEffect.test.ts +14 -0
- package/src/crtEffect.test.ts +16 -0
- package/src/customShaderEffect.test.ts +14 -0
- package/src/depthMath.test.ts +71 -0
- package/src/directionalBlurEffect.test.ts +11 -0
- package/src/displacementEffect.test.ts +15 -0
- package/src/ditherEffect.test.ts +11 -0
- package/src/edgeDetectMath.test.ts +84 -0
- package/src/exposureEffect.test.ts +7 -0
- package/src/filmEmulationEffect.test.ts +14 -0
- package/src/filmGrainEffect.test.ts +15 -0
- package/src/fxaaEffect.test.ts +14 -0
- package/src/gaussianMath.test.ts +93 -0
- package/src/glitchEffect.test.ts +16 -0
- package/src/godRaysEffect.test.ts +15 -0
- package/src/godRaysMath.test.ts +63 -0
- package/src/grayscaleEffect.test.ts +11 -0
- package/src/halftoneEffect.test.ts +11 -0
- package/src/hueSaturationEffect.test.ts +15 -0
- package/src/invertEffect.test.ts +11 -0
- package/src/kuwaharaEffect.test.ts +11 -0
- package/src/kuwaharaMath.test.ts +65 -0
- package/src/lensDirtEffect.test.ts +15 -0
- package/src/lensDistortionEffect.test.ts +11 -0
- package/src/lensFlareEffect.test.ts +16 -0
- package/src/liftGammaGainEffect.test.ts +15 -0
- package/src/lookupTableGradeEffect.test.ts +11 -0
- package/src/lutMath.test.ts +67 -0
- package/src/motionBlurEffect.test.ts +11 -0
- package/src/outlineEffect.test.ts +15 -0
- package/src/panniniProjectionEffect.test.ts +14 -0
- package/src/pixelateEffect.test.ts +11 -0
- package/src/posterizeEffect.test.ts +11 -0
- package/src/radialBlurEffect.test.ts +15 -0
- package/src/renderEffectDefaults.test.ts +70 -0
- package/src/renderEffectInputs.test.ts +60 -0
- package/src/renderEffectInterpolation.test.ts +71 -0
- package/src/renderEffectValidation.test.ts +37 -0
- package/src/scanlinesEffect.test.ts +11 -0
- package/src/screenSpaceFogEffect.test.ts +14 -0
- package/src/sepiaEffect.test.ts +11 -0
- package/src/sharpenEffect.test.ts +11 -0
- package/src/sketchEffect.test.ts +11 -0
- package/src/smaaEffect.test.ts +11 -0
- package/src/ssaoEffect.test.ts +11 -0
- package/src/ssrEffect.test.ts +11 -0
- package/src/stylizeMath.test.ts +99 -0
- package/src/taaEffect.test.ts +11 -0
- package/src/tiltShiftEffect.test.ts +15 -0
- package/src/toneMapEffect.test.ts +7 -0
- package/src/toneMapMath.test.ts +145 -0
- package/src/vignetteEffect.test.ts +16 -0
- package/src/volumetricLightEffect.test.ts +14 -0
- package/src/whiteBalanceEffect.test.ts +11 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import {
|
|
2
|
+
computeOutlineEdgeParams,
|
|
3
|
+
computeOutlineThicknessPx,
|
|
4
|
+
computeSketchEdgeParams,
|
|
5
|
+
getSobelKernelCoefficients,
|
|
6
|
+
} from './edgeDetectMath';
|
|
7
|
+
import { createOutlineEffect } from './outlineEffect';
|
|
8
|
+
import { createSketchEffect } from './sketchEffect';
|
|
9
|
+
|
|
10
|
+
describe('computeOutlineEdgeParams', () => {
|
|
11
|
+
it('writes threshold, feather, and color into out', () => {
|
|
12
|
+
const out: [number, number, number, number, number, number] = [0, 0, 0, 0, 0, 0];
|
|
13
|
+
computeOutlineEdgeParams(createOutlineEffect({ threshold: 0.2, color: 0xff0000ff }), out);
|
|
14
|
+
expect(out[0]).toBeCloseTo(0.2, 6); // threshold
|
|
15
|
+
expect(out[1]).toBeCloseTo(0.1, 6); // feather = threshold * 0.5
|
|
16
|
+
expect(out[2]).toBeCloseTo(1, 5); // r
|
|
17
|
+
expect(out[3]).toBeCloseTo(0, 5); // g
|
|
18
|
+
expect(out[4]).toBeCloseTo(0, 5); // b
|
|
19
|
+
expect(out[5]).toBeCloseTo(1, 5); // a
|
|
20
|
+
});
|
|
21
|
+
it('defaults to black outline', () => {
|
|
22
|
+
const out: [number, number, number, number, number, number] = [0, 0, 0, 0, 0, 0];
|
|
23
|
+
computeOutlineEdgeParams(createOutlineEffect(), out);
|
|
24
|
+
expect(out[2]).toBeCloseTo(0, 5); // r
|
|
25
|
+
expect(out[3]).toBeCloseTo(0, 5); // g
|
|
26
|
+
expect(out[4]).toBeCloseTo(0, 5); // b
|
|
27
|
+
expect(out[5]).toBeCloseTo(1, 5); // a
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe('computeOutlineThicknessPx', () => {
|
|
32
|
+
it('returns default 1', () => {
|
|
33
|
+
expect(computeOutlineThicknessPx(createOutlineEffect())).toBe(1);
|
|
34
|
+
});
|
|
35
|
+
it('rounds to integer', () => {
|
|
36
|
+
expect(computeOutlineThicknessPx(createOutlineEffect({ thickness: 2.7 }))).toBe(3);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
describe('computeSketchEdgeParams', () => {
|
|
41
|
+
it('writes threshold inversely proportional to strength', () => {
|
|
42
|
+
const out: [number, number] = [0, 0];
|
|
43
|
+
computeSketchEdgeParams(createSketchEffect({ strength: 1 }), out);
|
|
44
|
+
const threshold1 = out[0];
|
|
45
|
+
computeSketchEdgeParams(createSketchEffect({ strength: 0.5 }), out);
|
|
46
|
+
const threshold05 = out[0];
|
|
47
|
+
expect(threshold05).toBeGreaterThan(threshold1);
|
|
48
|
+
});
|
|
49
|
+
it('strength=1 produces minimum threshold', () => {
|
|
50
|
+
const out: [number, number] = [0, 0];
|
|
51
|
+
computeSketchEdgeParams(createSketchEffect({ strength: 1 }), out);
|
|
52
|
+
expect(out[0]).toBeCloseTo(0.05, 2);
|
|
53
|
+
expect(out[1]).toBe(1);
|
|
54
|
+
});
|
|
55
|
+
it('strength=0 produces threshold at or near 1', () => {
|
|
56
|
+
const out: [number, number] = [0, 0];
|
|
57
|
+
computeSketchEdgeParams(createSketchEffect({ strength: 0 }), out);
|
|
58
|
+
expect(out[0]).toBeCloseTo(1, 5);
|
|
59
|
+
expect(out[1]).toBe(0);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe('getSobelKernelCoefficients', () => {
|
|
64
|
+
it('writes 18 coefficients', () => {
|
|
65
|
+
const out = new Float32Array(18);
|
|
66
|
+
getSobelKernelCoefficients(out);
|
|
67
|
+
// Gx center column is 0
|
|
68
|
+
expect(out[1]).toBe(0);
|
|
69
|
+
expect(out[4]).toBe(0);
|
|
70
|
+
expect(out[7]).toBe(0);
|
|
71
|
+
// Gy center row is 0
|
|
72
|
+
expect(out[12]).toBe(0);
|
|
73
|
+
expect(out[13]).toBe(0);
|
|
74
|
+
expect(out[14]).toBe(0);
|
|
75
|
+
});
|
|
76
|
+
it('Gx and Gy are antisymmetric', () => {
|
|
77
|
+
const out = new Float32Array(18);
|
|
78
|
+
getSobelKernelCoefficients(out);
|
|
79
|
+
// Gx[0,0] = -Gx[0,2]
|
|
80
|
+
expect(out[0]).toBe(-out[2]);
|
|
81
|
+
// Gy[0,0] = -Gy[2,0]
|
|
82
|
+
expect(out[9]).toBe(-out[15]);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createFilmEmulationEffect } from './filmEmulationEffect';
|
|
2
|
+
|
|
3
|
+
describe('createFilmEmulationEffect', () => {
|
|
4
|
+
it('carries options', () => {
|
|
5
|
+
expect(createFilmEmulationEffect({ grainIntensity: 0.2, halationStrength: 0.4 })).toMatchObject({
|
|
6
|
+
grainIntensity: 0.2,
|
|
7
|
+
halationStrength: 0.4,
|
|
8
|
+
});
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('tags the intent type', () => {
|
|
12
|
+
expect(createFilmEmulationEffect().kind).toBe('FilmEmulationEffect');
|
|
13
|
+
});
|
|
14
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createFilmGrainEffect } from './filmGrainEffect';
|
|
2
|
+
|
|
3
|
+
describe('createFilmGrainEffect', () => {
|
|
4
|
+
it('tags the intent type', () => {
|
|
5
|
+
expect(createFilmGrainEffect().kind).toBe('FilmGrainEffect');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('carries options', () => {
|
|
9
|
+
expect(createFilmGrainEffect({ intensity: 0.3, size: 2, seed: 7 })).toMatchObject({
|
|
10
|
+
intensity: 0.3,
|
|
11
|
+
size: 2,
|
|
12
|
+
seed: 7,
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createFxaaEffect } from './fxaaEffect';
|
|
2
|
+
|
|
3
|
+
describe('createFxaaEffect', () => {
|
|
4
|
+
it('tags the intent type', () => {
|
|
5
|
+
expect(createFxaaEffect().kind).toBe('FxaaEffect');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('carries options', () => {
|
|
9
|
+
expect(createFxaaEffect({ edgeThreshold: 0.05, subpixel: 0.75 })).toMatchObject({
|
|
10
|
+
edgeThreshold: 0.05,
|
|
11
|
+
subpixel: 0.75,
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
});
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import {
|
|
2
|
+
computeGaussianRadiusFromSigma,
|
|
3
|
+
computeGaussianSigmaFromRadius,
|
|
4
|
+
computeSeparableBlurPassCount,
|
|
5
|
+
createGaussianKernelWeights,
|
|
6
|
+
} from './gaussianMath';
|
|
7
|
+
|
|
8
|
+
describe('computeGaussianRadiusFromSigma', () => {
|
|
9
|
+
it('returns 0 for zero sigma', () => {
|
|
10
|
+
expect(computeGaussianRadiusFromSigma(0)).toBe(0);
|
|
11
|
+
});
|
|
12
|
+
it('returns ceil(3 * sigma)', () => {
|
|
13
|
+
expect(computeGaussianRadiusFromSigma(2)).toBe(6);
|
|
14
|
+
expect(computeGaussianRadiusFromSigma(2.5)).toBe(8);
|
|
15
|
+
});
|
|
16
|
+
it('clamps negative sigma to 0', () => {
|
|
17
|
+
expect(computeGaussianRadiusFromSigma(-1)).toBe(0);
|
|
18
|
+
});
|
|
19
|
+
it('round-trips with computeGaussianSigmaFromRadius', () => {
|
|
20
|
+
const sigma = 2;
|
|
21
|
+
const radius = computeGaussianRadiusFromSigma(sigma);
|
|
22
|
+
// sigma -> radius -> sigma may not be exact due to ceil, but should be close.
|
|
23
|
+
expect(computeGaussianSigmaFromRadius(radius)).toBeCloseTo(sigma, 0);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
describe('computeGaussianSigmaFromRadius', () => {
|
|
28
|
+
it('returns 0 for zero radius', () => {
|
|
29
|
+
expect(computeGaussianSigmaFromRadius(0)).toBe(0);
|
|
30
|
+
});
|
|
31
|
+
it('returns radius / 3', () => {
|
|
32
|
+
expect(computeGaussianSigmaFromRadius(6)).toBeCloseTo(2);
|
|
33
|
+
expect(computeGaussianSigmaFromRadius(9)).toBeCloseTo(3);
|
|
34
|
+
});
|
|
35
|
+
it('clamps negative radius to 0', () => {
|
|
36
|
+
expect(computeGaussianSigmaFromRadius(-3)).toBe(0);
|
|
37
|
+
});
|
|
38
|
+
it('round-trips with computeGaussianRadiusFromSigma', () => {
|
|
39
|
+
const radius = 8;
|
|
40
|
+
const sigma = computeGaussianSigmaFromRadius(radius);
|
|
41
|
+
expect(computeGaussianRadiusFromSigma(sigma)).toBe(radius);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
describe('computeSeparableBlurPassCount', () => {
|
|
46
|
+
it('defaults to 1 when samples is undefined', () => {
|
|
47
|
+
expect(computeSeparableBlurPassCount(undefined)).toBe(1);
|
|
48
|
+
});
|
|
49
|
+
it('returns at least 1', () => {
|
|
50
|
+
expect(computeSeparableBlurPassCount(0)).toBe(1);
|
|
51
|
+
expect(computeSeparableBlurPassCount(-5)).toBe(1);
|
|
52
|
+
});
|
|
53
|
+
it('rounds fractional samples', () => {
|
|
54
|
+
expect(computeSeparableBlurPassCount(2.4)).toBe(2);
|
|
55
|
+
expect(computeSeparableBlurPassCount(2.6)).toBe(3);
|
|
56
|
+
});
|
|
57
|
+
it('returns integer pass count', () => {
|
|
58
|
+
expect(computeSeparableBlurPassCount(4)).toBe(4);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe('createGaussianKernelWeights', () => {
|
|
63
|
+
it('writes radius + 1 weights and returns that count', () => {
|
|
64
|
+
const out = new Float32Array(10);
|
|
65
|
+
const count = createGaussianKernelWeights(4, 1.5, out);
|
|
66
|
+
expect(count).toBe(5);
|
|
67
|
+
});
|
|
68
|
+
it('normalized weights sum to 1 (center + 2 * each side)', () => {
|
|
69
|
+
const radius = 4;
|
|
70
|
+
const sigma = 1.5;
|
|
71
|
+
const out = new Float32Array(radius + 1);
|
|
72
|
+
const count = createGaussianKernelWeights(radius, sigma, out);
|
|
73
|
+
let sum = out[0];
|
|
74
|
+
for (let i = 1; i < count; i++) {
|
|
75
|
+
sum += 2 * out[i];
|
|
76
|
+
}
|
|
77
|
+
expect(sum).toBeCloseTo(1, 5);
|
|
78
|
+
});
|
|
79
|
+
it('center weight is the largest', () => {
|
|
80
|
+
const out = new Float32Array(10);
|
|
81
|
+
const count = createGaussianKernelWeights(5, 2, out);
|
|
82
|
+
for (let i = 1; i < count; i++) {
|
|
83
|
+
expect(out[0]).toBeGreaterThan(out[i]);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
it('weights decrease monotonically from center', () => {
|
|
87
|
+
const out = new Float32Array(10);
|
|
88
|
+
const count = createGaussianKernelWeights(5, 2, out);
|
|
89
|
+
for (let i = 1; i < count; i++) {
|
|
90
|
+
expect(out[i - 1]).toBeGreaterThan(out[i]);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createGlitchEffect } from './glitchEffect';
|
|
2
|
+
|
|
3
|
+
describe('createGlitchEffect', () => {
|
|
4
|
+
it('tags the intent type', () => {
|
|
5
|
+
expect(createGlitchEffect().kind).toBe('GlitchEffect');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('carries options', () => {
|
|
9
|
+
expect(createGlitchEffect({ intensity: 0.7, blockSize: 22, colorShift: 12, seed: 3 })).toMatchObject({
|
|
10
|
+
intensity: 0.7,
|
|
11
|
+
blockSize: 22,
|
|
12
|
+
colorShift: 12,
|
|
13
|
+
seed: 3,
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createGodRaysEffect } from './godRaysEffect';
|
|
2
|
+
|
|
3
|
+
describe('createGodRaysEffect', () => {
|
|
4
|
+
it('tags the intent type', () => {
|
|
5
|
+
expect(createGodRaysEffect().kind).toBe('GodRaysEffect');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('carries options', () => {
|
|
9
|
+
expect(createGodRaysEffect({ centerX: 0.5, centerY: 0.25, density: 0.9 })).toMatchObject({
|
|
10
|
+
centerX: 0.5,
|
|
11
|
+
centerY: 0.25,
|
|
12
|
+
density: 0.9,
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { createGodRaysEffect } from './godRaysEffect';
|
|
2
|
+
import {
|
|
3
|
+
computeGodRaysAccumulationScale,
|
|
4
|
+
computeGodRaysLightCenter,
|
|
5
|
+
computeGodRaysSampleWeight,
|
|
6
|
+
computeGodRaysStepSize,
|
|
7
|
+
} from './godRaysMath';
|
|
8
|
+
|
|
9
|
+
describe('computeGodRaysAccumulationScale', () => {
|
|
10
|
+
it('is finite and positive for default parameters', () => {
|
|
11
|
+
const scale = computeGodRaysAccumulationScale(createGodRaysEffect());
|
|
12
|
+
expect(scale).toBeGreaterThan(0);
|
|
13
|
+
expect(isFinite(scale)).toBe(true);
|
|
14
|
+
});
|
|
15
|
+
it('is 1/(samples*weight*exposure) for explicit values', () => {
|
|
16
|
+
const effect = createGodRaysEffect({ samples: 50, weight: 0.5, exposure: 0.2 });
|
|
17
|
+
expect(computeGodRaysAccumulationScale(effect)).toBeCloseTo(1 / (50 * 0.5 * 0.2), 6);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('computeGodRaysLightCenter', () => {
|
|
22
|
+
it('defaults to [0.5, 0.5]', () => {
|
|
23
|
+
const out: [number, number] = [0, 0];
|
|
24
|
+
computeGodRaysLightCenter(createGodRaysEffect(), out);
|
|
25
|
+
expect(out[0]).toBe(0.5);
|
|
26
|
+
expect(out[1]).toBe(0.5);
|
|
27
|
+
});
|
|
28
|
+
it('clamps to [0..1]', () => {
|
|
29
|
+
const out: [number, number] = [0, 0];
|
|
30
|
+
computeGodRaysLightCenter(createGodRaysEffect({ centerX: -1, centerY: 2 }), out);
|
|
31
|
+
expect(out[0]).toBe(0);
|
|
32
|
+
expect(out[1]).toBe(1);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
describe('computeGodRaysSampleWeight', () => {
|
|
37
|
+
it('decreases with sample index due to decay', () => {
|
|
38
|
+
const effect = createGodRaysEffect({ decay: 0.9, weight: 1, exposure: 1 });
|
|
39
|
+
const w0 = computeGodRaysSampleWeight(effect, 0);
|
|
40
|
+
const w5 = computeGodRaysSampleWeight(effect, 5);
|
|
41
|
+
expect(w0).toBeGreaterThan(w5);
|
|
42
|
+
});
|
|
43
|
+
it('sample 0 equals weight*exposure when decay applied once', () => {
|
|
44
|
+
const effect = createGodRaysEffect({ decay: 0.96, weight: 0.4, exposure: 0.1 });
|
|
45
|
+
expect(computeGodRaysSampleWeight(effect, 0)).toBeCloseTo(0.4 * 0.1, 6);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe('computeGodRaysStepSize', () => {
|
|
50
|
+
it('returns zero step when pixel is at the light center', () => {
|
|
51
|
+
const out: [number, number] = [1, 1];
|
|
52
|
+
computeGodRaysStepSize(createGodRaysEffect({ centerX: 0.5, centerY: 0.5 }), 0.5, 0.5, out);
|
|
53
|
+
expect(out[0]).toBeCloseTo(0, 6);
|
|
54
|
+
expect(out[1]).toBeCloseTo(0, 6);
|
|
55
|
+
});
|
|
56
|
+
it('step direction points toward light center', () => {
|
|
57
|
+
const out: [number, number] = [0, 0];
|
|
58
|
+
// pixel at top-left (0, 0), light at center (0.5, 0.5) => step should be positive
|
|
59
|
+
computeGodRaysStepSize(createGodRaysEffect({ centerX: 0.5, centerY: 0.5, density: 1, samples: 10 }), 0, 0, out);
|
|
60
|
+
expect(out[0]).toBeGreaterThan(0);
|
|
61
|
+
expect(out[1]).toBeGreaterThan(0);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createGrayscaleEffect } from './grayscaleEffect';
|
|
2
|
+
|
|
3
|
+
describe('createGrayscaleEffect', () => {
|
|
4
|
+
it('tags the intent type', () => {
|
|
5
|
+
expect(createGrayscaleEffect().kind).toBe('GrayscaleEffect');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('carries options', () => {
|
|
9
|
+
expect(createGrayscaleEffect({ intensity: 0.5 })).toMatchObject({ intensity: 0.5 });
|
|
10
|
+
});
|
|
11
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createHalftoneEffect } from './halftoneEffect';
|
|
2
|
+
|
|
3
|
+
describe('createHalftoneEffect', () => {
|
|
4
|
+
it('tags the intent type', () => {
|
|
5
|
+
expect(createHalftoneEffect().kind).toBe('HalftoneEffect');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('carries options', () => {
|
|
9
|
+
expect(createHalftoneEffect({ scale: 6, angle: 0.5 })).toMatchObject({ scale: 6, angle: 0.5 });
|
|
10
|
+
});
|
|
11
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createHueSaturationEffect } from './hueSaturationEffect';
|
|
2
|
+
|
|
3
|
+
describe('createHueSaturationEffect', () => {
|
|
4
|
+
it('tags the intent type', () => {
|
|
5
|
+
expect(createHueSaturationEffect().kind).toBe('HueSaturationEffect');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('carries options', () => {
|
|
9
|
+
expect(createHueSaturationEffect({ hue: 90, saturation: 1.4, lightness: 0.1 })).toMatchObject({
|
|
10
|
+
hue: 90,
|
|
11
|
+
saturation: 1.4,
|
|
12
|
+
lightness: 0.1,
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createInvertEffect } from './invertEffect';
|
|
2
|
+
|
|
3
|
+
describe('createInvertEffect', () => {
|
|
4
|
+
it('tags the intent type', () => {
|
|
5
|
+
expect(createInvertEffect().kind).toBe('InvertEffect');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('carries options', () => {
|
|
9
|
+
expect(createInvertEffect({ intensity: 0.75 })).toMatchObject({ intensity: 0.75 });
|
|
10
|
+
});
|
|
11
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createKuwaharaEffect } from './kuwaharaEffect';
|
|
2
|
+
|
|
3
|
+
describe('createKuwaharaEffect', () => {
|
|
4
|
+
it('tags the intent type', () => {
|
|
5
|
+
expect(createKuwaharaEffect().kind).toBe('KuwaharaEffect');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('carries options', () => {
|
|
9
|
+
expect(createKuwaharaEffect({ radius: 3 })).toMatchObject({ radius: 3 });
|
|
10
|
+
});
|
|
11
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { createKuwaharaEffect } from './kuwaharaEffect';
|
|
2
|
+
import {
|
|
3
|
+
computeKuwaharaGaussianWeights,
|
|
4
|
+
computeKuwaharaSectorOffsets,
|
|
5
|
+
computeKuwaharaSectorPixelCount,
|
|
6
|
+
computeKuwaharaSectorSize,
|
|
7
|
+
} from './kuwaharaMath';
|
|
8
|
+
|
|
9
|
+
describe('computeKuwaharaGaussianWeights', () => {
|
|
10
|
+
it('returns normalized weights summing to ~1', () => {
|
|
11
|
+
const out = new Float32Array(16);
|
|
12
|
+
const n = computeKuwaharaGaussianWeights(3, out);
|
|
13
|
+
let sum = 0;
|
|
14
|
+
for (let i = 0; i < n; i++) sum += out[i];
|
|
15
|
+
expect(sum).toBeCloseTo(1, 5);
|
|
16
|
+
});
|
|
17
|
+
it('returns (radius+1)^2 weights', () => {
|
|
18
|
+
const out = new Float32Array(25);
|
|
19
|
+
const n = computeKuwaharaGaussianWeights(4, out);
|
|
20
|
+
expect(n).toBe(25); // (4+1)^2
|
|
21
|
+
});
|
|
22
|
+
it('center weight (0,0) is largest for radius >= 1', () => {
|
|
23
|
+
const r = 3;
|
|
24
|
+
const size = r + 1;
|
|
25
|
+
const out = new Float32Array(size * size);
|
|
26
|
+
computeKuwaharaGaussianWeights(r, out);
|
|
27
|
+
const center = out[0]; // top-left corner is the closest to center of sector
|
|
28
|
+
expect(center).toBeGreaterThan(0);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe('computeKuwaharaSectorOffsets', () => {
|
|
33
|
+
it('writes 8 values into out', () => {
|
|
34
|
+
const out: [number, number, number, number, number, number, number, number] = [0, 0, 0, 0, 0, 0, 0, 0];
|
|
35
|
+
computeKuwaharaSectorOffsets(3, out);
|
|
36
|
+
// top-left starts at (-3, -3)
|
|
37
|
+
expect(out[0]).toBe(-3);
|
|
38
|
+
expect(out[1]).toBe(-3);
|
|
39
|
+
// top-right starts at (0, -3)
|
|
40
|
+
expect(out[2]).toBe(0);
|
|
41
|
+
expect(out[3]).toBe(-3);
|
|
42
|
+
// bottom-left starts at (-3, 0)
|
|
43
|
+
expect(out[4]).toBe(-3);
|
|
44
|
+
expect(out[5]).toBe(0);
|
|
45
|
+
// bottom-right starts at (0, 0)
|
|
46
|
+
expect(out[6]).toBe(0);
|
|
47
|
+
expect(out[7]).toBe(0);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
describe('computeKuwaharaSectorPixelCount', () => {
|
|
52
|
+
it('returns (radius+1)^2 for default radius 3', () => {
|
|
53
|
+
expect(computeKuwaharaSectorPixelCount(createKuwaharaEffect())).toBe(16);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
describe('computeKuwaharaSectorSize', () => {
|
|
58
|
+
it('returns radius+1', () => {
|
|
59
|
+
expect(computeKuwaharaSectorSize(createKuwaharaEffect({ radius: 3 }))).toBe(4);
|
|
60
|
+
expect(computeKuwaharaSectorSize(createKuwaharaEffect({ radius: 5 }))).toBe(6);
|
|
61
|
+
});
|
|
62
|
+
it('minimum is 2 (radius 1)', () => {
|
|
63
|
+
expect(computeKuwaharaSectorSize(createKuwaharaEffect({ radius: 1 }))).toBe(2);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createLensDirtEffect } from './lensDirtEffect';
|
|
2
|
+
|
|
3
|
+
describe('createLensDirtEffect', () => {
|
|
4
|
+
it('tags the intent type', () => {
|
|
5
|
+
expect(createLensDirtEffect().kind).toBe('LensDirtEffect');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('carries options', () => {
|
|
9
|
+
expect(createLensDirtEffect({ intensity: 1.5, threshold: 0.45, seed: 4 })).toMatchObject({
|
|
10
|
+
intensity: 1.5,
|
|
11
|
+
threshold: 0.45,
|
|
12
|
+
seed: 4,
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createLensDistortionEffect } from './lensDistortionEffect';
|
|
2
|
+
|
|
3
|
+
describe('createLensDistortionEffect', () => {
|
|
4
|
+
it('tags the intent type', () => {
|
|
5
|
+
expect(createLensDistortionEffect().kind).toBe('LensDistortionEffect');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('carries options', () => {
|
|
9
|
+
expect(createLensDistortionEffect({ amount: 0.3, scale: 0.9 })).toMatchObject({ amount: 0.3, scale: 0.9 });
|
|
10
|
+
});
|
|
11
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createLensFlareEffect } from './lensFlareEffect';
|
|
2
|
+
|
|
3
|
+
describe('createLensFlareEffect', () => {
|
|
4
|
+
it('tags the intent type', () => {
|
|
5
|
+
expect(createLensFlareEffect().kind).toBe('LensFlareEffect');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('carries options', () => {
|
|
9
|
+
expect(createLensFlareEffect({ threshold: 0.8, intensity: 2, ghosts: 4, halo: 0.5 })).toMatchObject({
|
|
10
|
+
threshold: 0.8,
|
|
11
|
+
intensity: 2,
|
|
12
|
+
ghosts: 4,
|
|
13
|
+
halo: 0.5,
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createLiftGammaGainEffect } from './liftGammaGainEffect';
|
|
2
|
+
|
|
3
|
+
describe('createLiftGammaGainEffect', () => {
|
|
4
|
+
it('tags the intent type', () => {
|
|
5
|
+
expect(createLiftGammaGainEffect().kind).toBe('LiftGammaGainEffect');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('carries options', () => {
|
|
9
|
+
expect(createLiftGammaGainEffect({ lift: 0x808080ff, gamma: 0x808080ff, gain: 0x808080ff })).toMatchObject({
|
|
10
|
+
lift: 0x808080ff,
|
|
11
|
+
gamma: 0x808080ff,
|
|
12
|
+
gain: 0x808080ff,
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createLookupTableGradeEffect } from './lookupTableGradeEffect';
|
|
2
|
+
|
|
3
|
+
describe('createLookupTableGradeEffect', () => {
|
|
4
|
+
it('tags the intent type', () => {
|
|
5
|
+
expect(createLookupTableGradeEffect().kind).toBe('LookupTableGradeEffect');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('carries options', () => {
|
|
9
|
+
expect(createLookupTableGradeEffect({ size: 32, strength: 0.8 })).toMatchObject({ size: 32, strength: 0.8 });
|
|
10
|
+
});
|
|
11
|
+
});
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { computeLookupTableCoord, getLookupTableTileLayout } from './lutMath';
|
|
2
|
+
|
|
3
|
+
describe('computeLookupTableCoord', () => {
|
|
4
|
+
it('writes two values into out', () => {
|
|
5
|
+
const out: [number, number] = [0, 0];
|
|
6
|
+
computeLookupTableCoord(0.5, 0.5, 0.5, 16, out);
|
|
7
|
+
expect(typeof out[0]).toBe('number');
|
|
8
|
+
expect(typeof out[1]).toBe('number');
|
|
9
|
+
});
|
|
10
|
+
it('black (0,0,0) maps to near (0, 0)', () => {
|
|
11
|
+
const out: [number, number] = [0, 0];
|
|
12
|
+
computeLookupTableCoord(0, 0, 0, 16, out);
|
|
13
|
+
expect(out[0]).toBeGreaterThanOrEqual(0);
|
|
14
|
+
expect(out[1]).toBeGreaterThanOrEqual(0);
|
|
15
|
+
});
|
|
16
|
+
it('U and V are in [0, 1] range for valid input', () => {
|
|
17
|
+
const out: [number, number] = [0, 0];
|
|
18
|
+
computeLookupTableCoord(0.5, 0.5, 0.5, 16, out);
|
|
19
|
+
expect(out[0]).toBeGreaterThanOrEqual(0);
|
|
20
|
+
expect(out[0]).toBeLessThanOrEqual(1);
|
|
21
|
+
expect(out[1]).toBeGreaterThanOrEqual(0);
|
|
22
|
+
expect(out[1]).toBeLessThanOrEqual(1);
|
|
23
|
+
});
|
|
24
|
+
it('high G shifts V up', () => {
|
|
25
|
+
const outLow: [number, number] = [0, 0];
|
|
26
|
+
const outHigh: [number, number] = [0, 0];
|
|
27
|
+
computeLookupTableCoord(0.5, 0.1, 0.5, 16, outLow);
|
|
28
|
+
computeLookupTableCoord(0.5, 0.9, 0.5, 16, outHigh);
|
|
29
|
+
expect(outHigh[1]).toBeGreaterThan(outLow[1]);
|
|
30
|
+
});
|
|
31
|
+
it('high B shifts U right', () => {
|
|
32
|
+
const outLow: [number, number] = [0, 0];
|
|
33
|
+
const outHigh: [number, number] = [0, 0];
|
|
34
|
+
computeLookupTableCoord(0.5, 0.5, 0.1, 16, outLow);
|
|
35
|
+
computeLookupTableCoord(0.5, 0.5, 0.9, 16, outHigh);
|
|
36
|
+
expect(outHigh[0]).toBeGreaterThan(outLow[0]);
|
|
37
|
+
});
|
|
38
|
+
it('clamps out-of-range input', () => {
|
|
39
|
+
const out1: [number, number] = [0, 0];
|
|
40
|
+
const out2: [number, number] = [0, 0];
|
|
41
|
+
computeLookupTableCoord(0, 0, 0, 16, out1);
|
|
42
|
+
computeLookupTableCoord(-0.5, -0.5, -0.5, 16, out2);
|
|
43
|
+
expect(out1[0]).toBeCloseTo(out2[0], 5);
|
|
44
|
+
expect(out1[1]).toBeCloseTo(out2[1], 5);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
describe('getLookupTableTileLayout', () => {
|
|
49
|
+
it('returns [size², size] for a given LUT size', () => {
|
|
50
|
+
const out: [number, number] = [0, 0];
|
|
51
|
+
getLookupTableTileLayout(16, out);
|
|
52
|
+
expect(out[0]).toBe(256); // 16 * 16
|
|
53
|
+
expect(out[1]).toBe(16);
|
|
54
|
+
});
|
|
55
|
+
it('works for size 32', () => {
|
|
56
|
+
const out: [number, number] = [0, 0];
|
|
57
|
+
getLookupTableTileLayout(32, out);
|
|
58
|
+
expect(out[0]).toBe(1024);
|
|
59
|
+
expect(out[1]).toBe(32);
|
|
60
|
+
});
|
|
61
|
+
it('handles size 1 without dividing by zero', () => {
|
|
62
|
+
const out: [number, number] = [0, 0];
|
|
63
|
+
getLookupTableTileLayout(1, out);
|
|
64
|
+
expect(out[0]).toBe(1);
|
|
65
|
+
expect(out[1]).toBe(1);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createMotionBlurEffect } from './motionBlurEffect';
|
|
2
|
+
|
|
3
|
+
describe('createMotionBlurEffect', () => {
|
|
4
|
+
it('tags the intent type', () => {
|
|
5
|
+
expect(createMotionBlurEffect().kind).toBe('MotionBlurEffect');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('carries options', () => {
|
|
9
|
+
expect(createMotionBlurEffect({ intensity: 0.8, samples: 12 })).toMatchObject({ intensity: 0.8, samples: 12 });
|
|
10
|
+
});
|
|
11
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createOutlineEffect } from './outlineEffect';
|
|
2
|
+
|
|
3
|
+
describe('createOutlineEffect', () => {
|
|
4
|
+
it('tags the intent type', () => {
|
|
5
|
+
expect(createOutlineEffect().kind).toBe('OutlineEffect');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('carries options', () => {
|
|
9
|
+
expect(createOutlineEffect({ threshold: 0.2, thickness: 1.5, color: 0x000000ff })).toMatchObject({
|
|
10
|
+
threshold: 0.2,
|
|
11
|
+
thickness: 1.5,
|
|
12
|
+
color: 0x000000ff,
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createPanniniProjectionEffect } from './panniniProjectionEffect';
|
|
2
|
+
|
|
3
|
+
describe('createPanniniProjectionEffect', () => {
|
|
4
|
+
it('carries options', () => {
|
|
5
|
+
expect(createPanniniProjectionEffect({ compression: 0.7, crop: 0.1 })).toMatchObject({
|
|
6
|
+
compression: 0.7,
|
|
7
|
+
crop: 0.1,
|
|
8
|
+
});
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('tags the intent type', () => {
|
|
12
|
+
expect(createPanniniProjectionEffect().kind).toBe('PanniniProjectionEffect');
|
|
13
|
+
});
|
|
14
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createPixelateEffect } from './pixelateEffect';
|
|
2
|
+
|
|
3
|
+
describe('createPixelateEffect', () => {
|
|
4
|
+
it('tags the intent type', () => {
|
|
5
|
+
expect(createPixelateEffect().kind).toBe('PixelateEffect');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('carries options', () => {
|
|
9
|
+
expect(createPixelateEffect({ size: 8 })).toMatchObject({ size: 8 });
|
|
10
|
+
});
|
|
11
|
+
});
|