@@ -20,95 +20,104 @@ const CENTER_X = 0.5;
2020 */
2121const CENTER_Y = 0.5 ;
2222
23- // color conversions grabbed from https://gist.github.com/mjackson/5311256
23+ /**
24+ * Reused memory location for storing an HSV color value.
25+ * @type {Array<number> }
26+ */
27+ const __hsv = [ 0 , 0 , 0 ] ;
2428
2529/**
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].
30+ * Converts an RGB color value to HSV . Conversion formula
31+ * adapted from http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv .
32+ * Assumes r, g, and b are in the range [0, 255] and
33+ * returns h, s, and v in the range [0, 1].
3034 *
31- * @param {number } r The red color value
32- * @param {number } g The green color value
33- * @param {number } b The blue color value
34- * @return {Array } The HSL representation
35+ * @param {Array<number> } rgb The RGB color value
36+ * @param {number } rgb.r The red color value
37+ * @param {number } rgb.g The green color value
38+ * @param {number } rgb.b The blue color value
39+ * @param {Array<number> } dst The array to store the RGB values in
40+ * @return {Array<number> } The `dst` array passed in
3541 */
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- }
42+ const rgbToHsv = ( [ _r , _g , _b ] , dst ) => {
43+ let K = 0.0 ;
44+
45+ let r = _r / 255 ;
46+ let g = _g / 255 ;
47+ let b = _b / 255 ;
48+ let tmp = 0 ;
49+
50+ if ( g < b ) {
51+ tmp = g ;
52+ g = b ;
53+ b = tmp ;
5854
59- h /= 6 ;
55+ K = - 1 ;
6056 }
6157
62- return [ h , s , l ] ;
63- } ;
58+ if ( r < g ) {
59+ tmp = r ;
60+ r = g ;
61+ g = tmp ;
6462
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- } ;
63+ K = ( - 2 / 6 ) - K ;
64+ }
8165
66+ const chroma = r - Math . min ( g , b ) ;
67+ const h = Math . abs ( K + ( ( g - b ) / ( ( 6 * chroma ) + Number . EPSILON ) ) ) ;
68+ const s = chroma / ( r + Number . EPSILON ) ;
69+ const v = r ;
70+
71+ dst [ 0 ] = h ;
72+ dst [ 1 ] = s ;
73+ dst [ 2 ] = v ;
74+
75+ return dst ;
76+ } ;
8277
8378/**
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
79+ * Converts an HSV color value to RGB. Conversion formula
80+ * adapted from https ://gist.github.com/mjackson/5311256 .
81+ * Assumes h, s, and v are contained in the set [0, 1] and
8782 * returns r, g, and b in the set [0, 255].
8883 *
89- * @param {number } h The hue
90- * @param {number } s The saturation
91- * @param {number } l The lightness
92- * @return {Array } The RGB representation
84+ * @param {Array<number> } hsv The HSV color value
85+ * @param {number } hsv.h The hue
86+ * @param {number } hsv.s The saturation
87+ * @param {number } hsv.v The value
88+ * @param {Uint8Array|Uint8ClampedArray } dst The array to store the RGB values in
89+ * @return {Uint8Array|Uint8ClampedArray } The `dst` array passed in
9390 */
94- const hslToRgb = ( [ h , s , l ] ) => {
95- let r ;
96- let g ;
97- let b ;
98-
91+ const hsvToRgb = ( [ h , s , v ] , dst ) => {
9992 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 ;
93+ dst [ 0 ] = dst [ 1 ] = dst [ 2 ] = ( v * 255 ) + 0.5 ;
94+ return dst ;
95+ }
10596
106- r = hue2rgb ( p , q , h + ( 1 / 3 ) ) ;
107- g = hue2rgb ( p , q , h ) ;
108- b = hue2rgb ( p , q , h - ( 1 / 3 ) ) ;
97+ const i = ( h * 6 ) | 0 ;
98+ const f = ( h * 6 ) - i ;
99+ const p = v * ( 1 - s ) ;
100+ const q = v * ( 1 - ( s * f ) ) ;
101+ const t = v * ( 1 - ( s * ( 1 - f ) ) ) ;
102+
103+ let r = 0 ;
104+ let g = 0 ;
105+ let b = 0 ;
106+
107+ switch ( i ) {
108+ case 0 : r = v ; g = t ; b = p ; break ;
109+ case 1 : r = q ; g = v ; b = p ; break ;
110+ case 2 : r = p ; g = v ; b = t ; break ;
111+ case 3 : r = p ; g = q ; b = v ; break ;
112+ case 4 : r = t ; g = p ; b = v ; break ;
113+ case 5 : r = v ; g = p ; b = q ; break ;
109114 }
110115
111- return [ r * 255 , g * 255 , b * 255 ] ;
116+ // Add 0.5 in order to round. Setting integer TypedArray elements implicitly floors.
117+ dst [ 0 ] = ( r * 255 ) + 0.5 ;
118+ dst [ 1 ] = ( g * 255 ) + 0.5 ;
119+ dst [ 2 ] = ( b * 255 ) + 0.5 ;
120+ return dst ;
112121} ;
113122
114123class EffectTransform {
@@ -145,38 +154,43 @@ class EffectTransform {
145154 inOutColor [ 1 ] /= alpha ;
146155 inOutColor [ 2 ] /= alpha ;
147156
148- // vec3 hsl = convertRGB2HSL(gl_FragColor.xyz);
149- const hsl = rgbToHsl ( inOutColor ) ;
150-
151157 if ( enableColor ) {
158+ // vec3 hsv = convertRGB2HSV(gl_FragColor.xyz);
159+ const hsv = rgbToHsv ( inOutColor , __hsv ) ;
160+
152161 // this code forces grayscale values to be slightly saturated
153162 // so that some slight change of hue will be visible
154163 // const float minLightness = 0.11 / 2.0;
155- const minL = 0.11 / 2.0 ;
164+ const minV = 0.11 / 2.0 ;
156165 // const float minSaturation = 0.09;
157166 const minS = 0.09 ;
158- // if (hsl .z < minLightness) hsl = vec3(0.0, 1.0, minLightness);
159- if ( hsl [ 2 ] < minL ) {
160- hsl [ 0 ] = 0 ;
161- hsl [ 1 ] = 1 ;
162- hsl [ 2 ] = minL ;
163- // else if (hsl .y < minSaturation) hsl = vec3(0.0, minSaturation, hsl .z);
164- } else if ( hsl [ 1 ] < minS ) {
165- hsl [ 0 ] = 0 ;
166- hsl [ 1 ] = minS ;
167+ // if (hsv .z < minLightness) hsv = vec3(0.0, 1.0, minLightness);
168+ if ( hsv [ 2 ] < minV ) {
169+ hsv [ 0 ] = 0 ;
170+ hsv [ 1 ] = 1 ;
171+ hsv [ 2 ] = minV ;
172+ // else if (hsv .y < minSaturation) hsv = vec3(0.0, minSaturation, hsv .z);
173+ } else if ( hsv [ 1 ] < minS ) {
174+ hsv [ 0 ] = 0 ;
175+ hsv [ 1 ] = minS ;
167176 }
168177
169- // hsl.x = mod(hsl.x + u_color, 1.0);
170- // if (hsl.x < 0.0) hsl.x += 1.0;
171- hsl [ 0 ] = ( uniforms . u_color + hsl [ 0 ] + 1 ) % 1 ;
178+ // hsv.x = mod(hsv.x + u_color, 1.0);
179+ // if (hsv.x < 0.0) hsv.x += 1.0;
180+ hsv [ 0 ] = ( uniforms . u_color + hsv [ 0 ] + 1 ) % 1 ;
181+
182+ // gl_FragColor.rgb = convertHSV2RGB(hsl);
183+ hsvToRgb ( hsv , inOutColor ) ;
172184 }
173185
174186 if ( enableBrightness ) {
175- // hsl.z = clamp(hsl.z + u_brightness, 0.0, 1.0);
176- hsl [ 2 ] = Math . min ( 1 , hsl [ 2 ] + uniforms . u_brightness ) ;
187+ const brightness = uniforms . u_brightness * 255 ;
188+ // gl_FragColor.rgb = clamp(gl_FragColor.rgb + vec3(u_brightness), vec3(0), vec3(1));
189+ // We don't need to clamp because the Uint8ClampedArray does that for us
190+ inOutColor [ 0 ] += brightness ;
191+ inOutColor [ 1 ] += brightness ;
192+ inOutColor [ 2 ] += brightness ;
177193 }
178- // gl_FragColor.rgb = convertHSL2RGB(hsl);
179- inOutColor . set ( hslToRgb ( hsl ) ) ;
180194
181195 // gl_FragColor.rgb *= gl_FragColor.a + epsilon;
182196 // Now we're doing the reverse, premultiplying by the alpha once again.
0 commit comments