1// Copyright (c) 2015 Sergio Gonzalez. All rights reserved.
2// License: https://github.com/serge-rgb/milton#license
3
4
5// The triangle, in [-1,1].
6uniform vec2 u_pointa;
7uniform vec2 u_pointb;
8uniform vec2 u_pointc;
9
10uniform vec3 u_color;
11uniform float u_angle;
12
13uniform vec2 u_triangle_point;
14
15uniform vec4 u_colors[5]; // Colors for picker buttons.
16
17uniform vec2 u_screen_size;
18
19in vec2 v_norm;
20
21
22#define PI 3.14159
23
24float
25radians_to_degrees(float r)
26{
27    return (180.0 * r) / PI;
28}
29
30// http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl
31vec3
32hsv2rgb(vec3 c)
33{
34    vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
35    vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
36    return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
37}
38
39vec3
40hsv_to_rgb(vec3 hsv)
41{
42    vec3 rgb;
43
44    float h = hsv.x;
45    float s = hsv.y;
46    float v = hsv.z;
47    float hh = h / 60.0;
48    int hi = int(floor(hh));
49    float cr = v * s;
50    float rem = mod(hh, 2.0);
51    float x = cr * (1.0 - abs(rem - 1.0));
52    float m = v - cr;
53
54    if( hi == 0 || hi == 6 ) {
55        rgb.r = cr;
56        rgb.g = x;
57        rgb.b = 0;
58    }
59    if( hi == 1 ) {
60        rgb.r = x;
61        rgb.g = cr;
62        rgb.b = 0;
63    }
64    if( hi == 2 ) {
65        rgb.r = 0;
66        rgb.g = cr;
67        rgb.b = x;
68    }
69    if( hi == 3 ) {
70        rgb.r = 0;
71        rgb.g = x;
72        rgb.b = cr;
73    }
74    if( hi == 4 ) {
75        rgb.r = x;
76        rgb.g = 0;
77        rgb.b = cr;
78    }
79    if( hi == 5 ) {
80        rgb.r = cr;
81        rgb.g = 0;
82        rgb.b = x;
83    }
84    rgb.r += m;
85    rgb.g += m;
86    rgb.b += m;
87
88    return rgb;
89}
90
91// Could be called a signed area. `orientation(a, b, c) / 2` is the area of the
92// triangle.
93// If positive, c is to the left of ab. Negative: right of ab. 0 if
94// colinear.
95float
96orientation(vec2 a, vec2 b, vec2 c)
97{
98    return (b.x - a.x)*(c.y - a.y) - (c.x - a.x)*(b.y - a.y);
99}
100
101bool
102is_inside_triangle(vec2 p)
103{
104    bool is_inside =
105           (orientation(u_pointa, u_pointb, p) <= 0) &&
106           (orientation(u_pointb, u_pointc, p) <= 0) &&
107           (orientation(u_pointc, u_pointa, p) <= 0);
108    return is_inside;
109}
110
111void
112main()
113{
114    // NOTE:
115    //  These constants gotten from gui.cc in gui_init. From bounds_radius_px, wheel_half_width, and so on.
116    float u_ui_scale = 1.75;
117    float half_width = 12.0 / 100.0;
118    float radius = (1.0 - (12.0 + 5) / 100.0);
119
120    /* vec2 screen_point = vec2(gl_FragCoord.x, u_screen_size.y-gl_FragCoord.y); */
121    /* vec2 coord = screen_point / u_screen_size; */
122    /* coord.y = 1-coord.y; */
123    vec4 color = vec4(0.5, 0.5, 0.55, 0.6);
124
125    float dist = distance(vec2(0), v_norm);
126    // Wheel and triangle
127    // Show chosen color in preview circle
128    vec2 preview_center = vec2(0.75,-0.75);
129    const float preview_radius = 0.23;
130
131    float dist_to_preview = distance(preview_center, v_norm);
132    if ( dist_to_preview < preview_radius ) {
133        color = vec4(0,0,0,1);
134        const float epsilon = 0.02;
135        if ( dist_to_preview < preview_radius - epsilon ) {
136            color = vec4(u_color, 1);
137        }
138    }
139    // else if ( dist < radius + half_width ) {
140    //    color = vec4(0,0,0,1);
141    // }
142#if 1
143    else if ( dist < radius+half_width ) {
144        // Wheel
145        if ( dist > radius-half_width ) {
146            vec2 n = v_norm;
147            vec2 v = vec2(1, 0);
148            float angle = acos(dot(n, v)/ (length(n) * length(v)));
149            if ( v_norm.y > 0 ) {
150                angle = (2*PI) - angle;
151            }
152            vec3 hsv = vec3(radians_to_degrees(angle),1.0,1.0);
153            //vec3 hsv = vec3(angle,1.0,1.0);
154            vec3 rgb = hsv_to_rgb(hsv);
155            color = vec4(rgb,1);
156        }
157        // Triangle
158        else if ( is_inside_triangle(v_norm) ) {
159            float area = orientation(u_pointa, u_pointb, u_pointc);
160            float v = 1 - (orientation(v_norm, u_pointc, u_pointa) / area);
161            float s = orientation(u_pointb, v_norm, u_pointa) * v / area;
162            vec3 pure_color = hsv_to_rgb(vec3(u_angle,1.0,1.0));
163            color = vec4((1.0-(1.0-pure_color)*s)*v,1.0);
164        }
165    }
166#endif
167    // Render buttons
168    else if ( v_norm.y >= 1 ) {
169        // Get the color for the rects
170        int rect_i = int(((v_norm.x+1)/4) * 10);
171        vec4 rect_color = u_colors[rect_i];
172        color = rect_color;
173
174        // Black outlines
175        float h = ((v_norm.x+1)/4)*10;
176        float epsilon = 0.01;
177        float epsilon2 = 0.015;
178        if ( v_norm.y > 1.4-epsilon
179             || v_norm.y < 1+epsilon
180             || (h <     epsilon2 && h >   - epsilon2)
181             || (h < 1 + epsilon2 && h > 1 - epsilon2)
182             || (h < 2 + epsilon2 && h > 2 - epsilon2)
183             || (h < 3 + epsilon2 && h > 3 - epsilon2)
184             || (h < 4 + epsilon2 && h > 4 - epsilon2)
185             || (h < 5 + epsilon2 && h > 5 - epsilon2)
186             || (h < 6 + epsilon2 && h > 6 - epsilon2) ) {
187            color = vec4(0,0,0,1);
188        }
189    }
190
191    float dist_to_choice = distance(v_norm, u_triangle_point);
192    const float point_radius = 0.05;
193    const float girth = 0.01;
194    if ( dist_to_choice < point_radius+girth && dist_to_choice > point_radius-girth ) {
195        color.rgb = vec3(1- color.r, 1 - color.g, 1 - color.b);
196    }
197
198    out_color = color;
199}
200