@@ -20,95 +20,104 @@ const CENTER_X = 0.5;
20
20
*/
21
21
const CENTER_Y = 0.5 ;
22
22
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 ] ;
24
28
25
29
/**
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].
30
34
*
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
35
41
*/
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 ;
58
54
59
- h /= 6 ;
55
+ K = - 1 ;
60
56
}
61
57
62
- return [ h , s , l ] ;
63
- } ;
58
+ if ( r < g ) {
59
+ tmp = r ;
60
+ r = g ;
61
+ g = tmp ;
64
62
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
+ }
81
65
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
+ } ;
82
77
83
78
/**
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
87
82
* returns r, g, and b in the set [0, 255].
88
83
*
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
93
90
*/
94
- const hslToRgb = ( [ h , s , l ] ) => {
95
- let r ;
96
- let g ;
97
- let b ;
98
-
91
+ const hsvToRgb = ( [ h , s , v ] , dst ) => {
99
92
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
+ }
105
96
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 ;
109
114
}
110
115
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 ;
112
121
} ;
113
122
114
123
class EffectTransform {
@@ -145,38 +154,43 @@ class EffectTransform {
145
154
inOutColor [ 1 ] /= alpha ;
146
155
inOutColor [ 2 ] /= alpha ;
147
156
148
- // vec3 hsl = convertRGB2HSL(gl_FragColor.xyz);
149
- const hsl = rgbToHsl ( inOutColor ) ;
150
-
151
157
if ( enableColor ) {
158
+ // vec3 hsv = convertRGB2HSV(gl_FragColor.xyz);
159
+ const hsv = rgbToHsv ( inOutColor , __hsv ) ;
160
+
152
161
// this code forces grayscale values to be slightly saturated
153
162
// so that some slight change of hue will be visible
154
163
// const float minLightness = 0.11 / 2.0;
155
- const minL = 0.11 / 2.0 ;
164
+ const minV = 0.11 / 2.0 ;
156
165
// const float minSaturation = 0.09;
157
166
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 ;
167
176
}
168
177
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 ) ;
172
184
}
173
185
174
186
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 ;
177
193
}
178
- // gl_FragColor.rgb = convertHSL2RGB(hsl);
179
- inOutColor . set ( hslToRgb ( hsl ) ) ;
180
194
181
195
// gl_FragColor.rgb *= gl_FragColor.a + epsilon;
182
196
// Now we're doing the reverse, premultiplying by the alpha once again.
0 commit comments