Hard-assert on something that has bitten me too many times now.
[movit] / widgets.cpp
1 #include <epoxy/gl.h>
2 #include <math.h>
3
4 #include <string>
5 #include <vector>
6
7 #include "resource_pool.h"
8 #include "widgets.h"
9 #include "util.h"
10
11 #define HSV_WHEEL_SIZE 128
12
13 using namespace std;
14
15 namespace movit {
16
17 GLuint hsv_wheel_texnum = 0;
18 GLuint textured_program_num = 0, colored_program_num = 0, hsv_vao = 0;
19 ResourcePool resource_pool;
20
21 void draw_black_point(float x, float y, float point_size)
22 {
23         glUseProgram(colored_program_num);
24         check_error();
25
26         float vertices[] = { x, y };
27         float colors[] = { 0.0f, 0.0f, 0.0f };
28
29         glPointSize(point_size);
30         check_error();
31         GLuint position_vbo = fill_vertex_attribute(colored_program_num, "position", 2, GL_FLOAT, sizeof(vertices), vertices);
32         GLuint color_vbo = fill_vertex_attribute(colored_program_num, "color", 3, GL_FLOAT, sizeof(colors), colors);
33         check_error();
34         glDrawArrays(GL_POINTS, 0, 1);
35         check_error();
36         cleanup_vertex_attribute(colored_program_num, "position", position_vbo);
37         cleanup_vertex_attribute(colored_program_num, "color", color_vbo);
38 }
39
40 void draw_hsv_wheel(float y, float rad, float theta, float value)
41 {
42         glUseProgram(textured_program_num);
43         check_error();
44         glActiveTexture(GL_TEXTURE0);
45         check_error();
46         glBindTexture(GL_TEXTURE_2D, hsv_wheel_texnum);
47         check_error();
48         glUniform1i(glGetUniformLocation(textured_program_num, "tex"), 0);  // Bind the 2D sampler.
49         check_error();
50         glEnable(GL_BLEND);
51         check_error();
52         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
53         check_error();
54
55         GLuint vao;
56         glGenVertexArrays(1, &vao);
57         check_error();
58         glBindVertexArray(vao);
59         check_error();
60
61         // wheel
62         float wheel_vertices[] = {
63                 0.0f, y,
64                 0.0f, y + 0.2f,
65                 0.2f * 9.0f / 16.0f, y,
66                 0.2f * 9.0f / 16.0f, y + 0.2f,
67         };
68         float wheel_texcoords[] = {
69                 0.0f, 1.0f,
70                 0.0f, 0.0f,
71                 1.0f, 1.0f,
72                 1.0f, 0.0f,
73         };
74         GLuint position_vbo = fill_vertex_attribute(textured_program_num, "position", 2, GL_FLOAT, sizeof(wheel_vertices), wheel_vertices);
75         GLuint texcoord_vbo = fill_vertex_attribute(textured_program_num, "texcoord", 2, GL_FLOAT, sizeof(wheel_texcoords), wheel_texcoords);
76         check_error();
77
78         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
79         check_error();
80
81         cleanup_vertex_attribute(textured_program_num, "position", position_vbo);
82         cleanup_vertex_attribute(textured_program_num, "texcoord", texcoord_vbo);
83
84         // wheel selector
85         draw_black_point(
86             (0.1f + rad * cos(theta) * 0.1f) * 9.0f / 16.0f,
87             y + 0.1f - rad * sin(theta) * 0.1f,
88             5.0f);
89
90         // value slider
91         glUseProgram(colored_program_num);
92         float value_vertices[] = {
93                 0.22f * 9.0f / 16.0f, y,
94                 0.22f * 9.0f / 16.0f, y + 0.2f,
95                 0.24f * 9.0f / 16.0f, y,
96                 0.24f * 9.0f / 16.0f, y + 0.2f,
97         };
98         float value_colors[] = {
99                 0.0f, 0.0f, 0.0f,
100                 1.0f, 1.0f, 1.0f,
101                 0.0f, 0.0f, 0.0f,
102                 1.0f, 1.0f, 1.0f,
103         };
104         position_vbo = fill_vertex_attribute(colored_program_num, "position", 2, GL_FLOAT, sizeof(value_vertices), value_vertices);
105         GLuint color_vbo = fill_vertex_attribute(colored_program_num, "color", 3, GL_FLOAT, sizeof(value_colors), value_colors);
106         check_error();
107         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
108         check_error();
109         cleanup_vertex_attribute(colored_program_num, "position", position_vbo);
110         cleanup_vertex_attribute(colored_program_num, "color", color_vbo);
111
112         // value selector
113         draw_black_point(0.23f * 9.0f / 16.0f, y + value * 0.2f, 5.0f);
114
115         glDeleteVertexArrays(1, &vao);
116         check_error();
117         glUseProgram(0);
118         check_error();
119 }
120
121 void draw_saturation_bar(float y, float saturation)
122 {
123         GLuint vao;
124         glGenVertexArrays(1, &vao);
125         check_error();
126         glBindVertexArray(vao);
127         check_error();
128
129         // value slider
130         glUseProgram(colored_program_num);
131         float value_vertices[] = {
132                 0.0f * 9.0f / 16.0f, y + 0.02f,
133                 0.2f * 9.0f / 16.0f, y + 0.02f,
134                 0.0f * 9.0f / 16.0f, y,
135                 0.2f * 9.0f / 16.0f, y,
136         };
137         float value_colors[] = {
138                 0.0f, 0.0f, 0.0f,
139                 1.0f, 1.0f, 1.0f,
140                 0.0f, 0.0f, 0.0f,
141                 1.0f, 1.0f, 1.0f,
142         };
143         GLuint position_vbo = fill_vertex_attribute(colored_program_num, "position", 2, GL_FLOAT, sizeof(value_vertices), value_vertices);
144         GLuint color_vbo = fill_vertex_attribute(colored_program_num, "color", 3, GL_FLOAT, sizeof(value_colors), value_colors);
145         check_error();
146         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
147         check_error();
148         cleanup_vertex_attribute(colored_program_num, "position", position_vbo);
149         cleanup_vertex_attribute(colored_program_num, "color", color_vbo);
150
151         // value selector
152         draw_black_point(0.2f * saturation * 9.0f / 16.0f, y + 0.01f, 5.0f);
153
154         glDeleteVertexArrays(1, &vao);
155         check_error();
156         glUseProgram(0);
157         check_error();
158 }
159
160 void make_hsv_wheel_texture()
161 {
162         glGenTextures(1, &hsv_wheel_texnum);
163
164         static unsigned char hsv_pix[HSV_WHEEL_SIZE * HSV_WHEEL_SIZE * 4];
165         for (int y = 0; y < HSV_WHEEL_SIZE; ++y) {
166                 for (int x = 0; x < HSV_WHEEL_SIZE; ++x) {
167                         float yf = 2.0f * y / (float)(HSV_WHEEL_SIZE) - 1.0f;
168                         float xf = 2.0f * x / (float)(HSV_WHEEL_SIZE) - 1.0f;
169                         float rad = hypot(xf, yf);
170                         float theta = atan2(yf, xf);
171
172                         float r, g, b;
173                         hsv2rgb(theta, rad, 1.0f, &r, &g, &b);
174                         hsv_pix[(y * HSV_WHEEL_SIZE + x) * 4 + 0] = lrintf(r * 255.0f);
175                         hsv_pix[(y * HSV_WHEEL_SIZE + x) * 4 + 1] = lrintf(g * 255.0f);
176                         hsv_pix[(y * HSV_WHEEL_SIZE + x) * 4 + 2] = lrintf(b * 255.0f);
177
178                         if (rad > 1.0f) {
179                                 hsv_pix[(y * HSV_WHEEL_SIZE + x) * 4 + 3] = 0;
180                         } else {
181                                 hsv_pix[(y * HSV_WHEEL_SIZE + x) * 4 + 3] = 255;
182                         }
183                 }
184         }
185
186         glBindTexture(GL_TEXTURE_2D, hsv_wheel_texnum);
187         check_error();
188         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
189         check_error();
190         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, HSV_WHEEL_SIZE, HSV_WHEEL_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, hsv_pix);
191         check_error();
192 }
193
194 void init_hsv_resources()
195 {
196         vector<string> frag_shader_outputs;
197         textured_program_num = resource_pool.compile_glsl_program(
198                 read_version_dependent_file("vs", "vert"),
199                 read_version_dependent_file("texture1d", "frag"),
200                 frag_shader_outputs);
201         colored_program_num = resource_pool.compile_glsl_program(
202                 read_version_dependent_file("vs-color", "vert"),
203                 read_version_dependent_file("color", "frag"),
204                 frag_shader_outputs);
205         make_hsv_wheel_texture();
206 }
207
208 void cleanup_hsv_resources()
209 {
210         resource_pool.release_glsl_program(textured_program_num);
211         resource_pool.release_glsl_program(colored_program_num);
212 }
213
214 void read_colorwheel(float xf, float yf, float *rad, float *theta, float *value)
215 {
216         if (xf < 0.2f && yf < 0.2f) {
217                 float xp = 2.0f * xf / 0.2f - 1.0f;
218                 float yp = -(2.0f * yf / 0.2f - 1.0f);
219                 *rad = hypot(xp, yp);
220                 *theta = atan2(yp, xp);
221                 if (*rad > 1.0) {
222                         *rad = 1.0;
223                 }
224         } else if (xf >= 0.22f && xf <= 0.24f) {
225                 *value = yf / 0.2f;
226         }
227 }
228
229
230 }  // namespace movit