@@ -20,96 +20,97 @@ const CENTER_X = 0.5;
2020 */
2121const CENTER_Y = 0.5 ;
2222
23- // color conversions grabbed from https://gist.github.com/mjackson/5311256
24-
2523/**
26- * Converts an RGB color value to HSL . Conversion formula
27- * adapted from http://en.wikipedia.org/wiki/HSL_color_space .
28- * Assumes r, g, and b are contained in the set [0, 255] and
29- * returns h, s, and l in the set [0, 1].
24+ * Converts an RGB color value to HSV . Conversion formula
25+ * adapted from http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv .
26+ * Assumes r, g, and b are in the range [0, 255] and
27+ * returns h, s, and v in the range [0, 1].
3028 *
3129 * @param {number } r The red color value
3230 * @param {number } g The green color value
3331 * @param {number } b The blue color value
34- * @return {Array } The HSL representation
32+ * @return {Array<number> } The HSV representation
3533 */
36- const rgbToHsl = ( [ r , g , b ] ) => {
37- r /= 255 ;
38- g /= 255 ;
39- b /= 255 ;
40-
41- const max = Math . max ( r , g , b ) ;
42- const min = Math . min ( r , g , b ) ;
43- let h ;
44- let s ;
45- const l = ( max + min ) / 2 ;
46-
47- if ( max === min ) {
48- h = s = 0 ; // achromatic
49- } else {
50- const d = max - min ;
51- s = l > 0.5 ? d / ( 2 - max - min ) : d / ( max + min ) ;
52-
53- switch ( max ) {
54- case r : h = ( ( g - b ) / d ) + ( g < b ? 6 : 0 ) ; break ;
55- case g : h = ( ( b - r ) / d ) + 2 ; break ;
56- case b : h = ( ( r - g ) / d ) + 4 ; break ;
57- }
34+ const rgbToHsv = ( [ _r , _g , _b ] ) => {
35+ let K = 0.0 ;
36+
37+ let r = _r / 255 ;
38+ let g = _g / 255 ;
39+ let b = _b / 255 ;
40+ let tmp = 0 ;
5841
59- h /= 6 ;
42+ if ( g < b ) {
43+ tmp = g ;
44+ g = b ;
45+ b = tmp ;
46+
47+ K = - 1 ;
6048 }
6149
62- return [ h , s , l ] ;
63- } ;
50+ if ( r < g ) {
51+ tmp = r ;
52+ r = g ;
53+ g = tmp ;
6454
65- /**
66- * Helper function for hslToRgb is called with varying 't' values to get
67- * red green and blue values from the p/q/t color space calculations
68- * @param {number } p vector coordinates
69- * @param {number } q vector coordinates
70- * @param {number } t vector coordinates
71- * @return {number } amount of r/g/b byte
72- */
73- const hue2rgb = ( p , q , t ) => {
74- if ( t < 0 ) t += 1 ;
75- if ( t > 1 ) t -= 1 ;
76- if ( t < 1 / 6 ) return p + ( ( q - p ) * 6 * t ) ;
77- if ( t < 1 / 2 ) return q ;
78- if ( t < 2 / 3 ) return p + ( ( q - p ) * ( ( 2 / 3 ) - t ) * 6 ) ;
79- return p ;
80- } ;
55+ K = ( - 2 / 6 ) - K ;
56+ }
8157
58+ const chroma = r - Math . min ( g , b ) ;
59+ const h = Math . abs ( K + ( ( g - b ) / ( ( 6 * chroma ) + Number . EPSILON ) ) ) ;
60+ const s = chroma / ( r + Number . EPSILON ) ;
61+ const v = r ;
8262
63+ return [ h , s , v ] ;
64+ } ;
65+
66+ /* eslint-disable valid-jsdoc */
67+ /* it doesn't seem to work with destructured parameters */
8368/**
84- * Converts an HSL color value to RGB. Conversion formula
85- * adapted from http ://en.wikipedia.org/wiki/HSL_color_space .
86- * Assumes h, s, and l are contained in the set [0, 1] and
69+ * Converts an HSV color value to RGB. Conversion formula
70+ * adapted from https ://gist.github.com/mjackson/5311256 .
71+ * Assumes h, s, and v are contained in the set [0, 1] and
8772 * returns r, g, and b in the set [0, 255].
8873 *
89- * @param {number } h The hue
90- * @param {number } s The saturation
91- * @param {number } l The lightness
92- * @return {Array } The RGB representation
74+ * @param {number } h The hue
75+ * @param {number } s The saturation
76+ * @param {number } v The value
77+ * @param {Array<number> } dst The array to store the RGB values in
78+ * @return {Array<number> } The `dst` array passed in
9379 */
94- const hslToRgb = ( [ h , s , l ] ) => {
95- let r ;
96- let g ;
97- let b ;
98-
80+ const hsvToRgb = ( [ h , s , v ] , dst ) => {
9981 if ( s === 0 ) {
100- r = g = b = l ; // achromatic
101- } else {
102-
103- const q = l < 0.5 ? l * ( 1 + s ) : l + s - ( l * s ) ;
104- const p = ( 2 * l ) - q ;
82+ dst [ 0 ] = v ;
83+ dst [ 1 ] = v ;
84+ dst [ 2 ] = v ;
85+ return dst ;
86+ }
10587
106- r = hue2rgb ( p , q , h + ( 1 / 3 ) ) ;
107- g = hue2rgb ( p , q , h ) ;
108- b = hue2rgb ( p , q , h - ( 1 / 3 ) ) ;
88+ const i = ( h * 6 ) | 0 ;
89+ const f = ( h * 6 ) - i ;
90+ const p = v * ( 1 - s ) ;
91+ const q = v * ( 1 - ( s * f ) ) ;
92+ const t = v * ( 1 - ( s * ( 1 - f ) ) ) ;
93+
94+ let r = 0 ;
95+ let g = 0 ;
96+ let b = 0 ;
97+
98+ switch ( i ) {
99+ case 0 : r = v ; g = t ; b = p ; break ;
100+ case 1 : r = q ; g = v ; b = p ; break ;
101+ case 2 : r = p ; g = v ; b = t ; break ;
102+ case 3 : r = p ; g = q ; b = v ; break ;
103+ case 4 : r = t ; g = p ; b = v ; break ;
104+ case 5 : r = v ; g = p ; b = q ; break ;
109105 }
110106
111- return [ r * 255 , g * 255 , b * 255 ] ;
107+ // Add 0.5 in order to round. Setting integer TypedArray elements implicitly floors.
108+ dst [ 0 ] = ( r * 255 ) + 0.5 ;
109+ dst [ 1 ] = ( g * 255 ) + 0.5 ;
110+ dst [ 2 ] = ( b * 255 ) + 0.5 ;
111+ return dst ;
112112} ;
113+ /* eslint-enable valid-jsdoc */
113114
114115class EffectTransform {
115116
@@ -135,42 +136,42 @@ class EffectTransform {
135136 inOutColor [ 3 ] *= uniforms . u_ghost ;
136137 }
137138
138- const enableColor = ( effects & ShaderManager . EFFECT_INFO . color . mask ) !== 0 ;
139- const enableBrightness = ( effects & ShaderManager . EFFECT_INFO . brightness . mask ) !== 0 ;
140-
141- if ( enableColor || enableBrightness ) {
142- // vec3 hsl = convertRGB2HSL(gl_FragColor.xyz);
143- const hsl = rgbToHsl ( inOutColor ) ;
144-
145- if ( enableColor ) {
146- // this code forces grayscale values to be slightly saturated
147- // so that some slight change of hue will be visible
148- // const float minLightness = 0.11 / 2.0;
149- const minL = 0.11 / 2.0 ;
150- // const float minSaturation = 0.09;
151- const minS = 0.09 ;
152- // if (hsl.z < minLightness) hsl = vec3(0.0, 1.0, minLightness);
153- if ( hsl [ 2 ] < minL ) {
154- hsl [ 0 ] = 0 ;
155- hsl [ 1 ] = 1 ;
156- hsl [ 2 ] = minL ;
157- // else if (hsl.y < minSaturation) hsl = vec3(0.0, minSaturation, hsl.z);
158- } else if ( hsl [ 1 ] < minS ) {
159- hsl [ 0 ] = 0 ;
160- hsl [ 1 ] = minS ;
161- }
162-
163- // hsl.x = mod(hsl.x + u_color, 1.0);
164- // if (hsl.x < 0.0) hsl.x += 1.0;
165- hsl [ 0 ] = ( uniforms . u_color + hsl [ 0 ] + 1 ) % 1 ;
139+ if ( ( effects & ShaderManager . EFFECT_INFO . color . mask ) !== 0 ) {
140+ // vec3 hsv = convertRGB2HSV(gl_FragColor.xyz);
141+ const hsv = rgbToHsv ( inOutColor ) ;
142+
143+ // this code forces grayscale values to be slightly saturated
144+ // so that some slight change of hue will be visible
145+ // const float minLightness = 0.11 / 2.0;
146+ const minV = 0.11 / 2.0 ;
147+ // const float minSaturation = 0.09;
148+ const minS = 0.09 ;
149+ // if (hsv.z < minLightness) hsv = vec3(0.0, 1.0, minLightness);
150+ if ( hsv [ 2 ] < minV ) {
151+ hsv [ 0 ] = 0 ;
152+ hsv [ 1 ] = 1 ;
153+ hsv [ 2 ] = minV ;
154+ // else if (hsv.y < minSaturation) hsv = vec3(0.0, minSaturation, hsv.z);
155+ } else if ( hsv [ 1 ] < minS ) {
156+ hsv [ 0 ] = 0 ;
157+ hsv [ 1 ] = minS ;
166158 }
167159
168- if ( enableBrightness ) {
169- // hsl.z = clamp(hsl.z + u_brightness, 0.0, 1.0);
170- hsl [ 2 ] = Math . min ( 1 , hsl [ 2 ] + uniforms . u_brightness ) ;
171- }
172- // gl_FragColor.rgb = convertHSL2RGB(hsl);
173- inOutColor . set ( hslToRgb ( hsl ) ) ;
160+ // hsv.x = mod(hsv.x + u_color, 1.0);
161+ // if (hsv.x < 0.0) hsv.x += 1.0;
162+ hsv [ 0 ] = ( uniforms . u_color + hsv [ 0 ] + 1 ) % 1 ;
163+
164+ // gl_FragColor.rgb = convertHSV2RGB(hsl);
165+ hsvToRgb ( hsv , inOutColor ) ;
166+ }
167+
168+ if ( ( effects & ShaderManager . EFFECT_INFO . brightness . mask ) !== 0 ) {
169+ const brightness = uniforms . u_brightness ;
170+ // gl_FragColor.rgb = clamp(gl_FragColor.rgb + vec3(u_brightness), vec3(0), vec3(1));
171+ // We don't need to clamp because the Uint8ClampedArray does that for us
172+ inOutColor [ 0 ] = inOutColor [ 0 ] + brightness ;
173+ inOutColor [ 1 ] = inOutColor [ 1 ] + brightness ;
174+ inOutColor [ 2 ] = inOutColor [ 2 ] + brightness ;
174175 }
175176
176177 return inOutColor ;
0 commit comments