rev |
line source |
nuclear@0
|
1 #include <stdlib.h>
|
nuclear@0
|
2 #include <float.h>
|
nuclear@0
|
3 #include <vector>
|
nuclear@0
|
4 #include <algorithm>
|
nuclear@0
|
5 #include "opengl.h"
|
nuclear@0
|
6 #include "app.h"
|
nuclear@0
|
7 #include "curve.h"
|
nuclear@0
|
8 #include "widgets.h"
|
nuclear@0
|
9
|
nuclear@1
|
10 int win_width, win_height;
|
nuclear@1
|
11 float win_aspect;
|
nuclear@1
|
12
|
nuclear@0
|
13 static void draw_grid(float sz, float sep, float alpha = 1.0f);
|
nuclear@0
|
14 static void draw_curve(const Curve *curve);
|
nuclear@0
|
15 static void on_click(int bn, float u, float v);
|
nuclear@0
|
16
|
nuclear@0
|
17 static float view_pan_x, view_pan_y;
|
nuclear@0
|
18 static float view_scale = 1.0f;
|
nuclear@0
|
19
|
nuclear@0
|
20 static std::vector<Curve*> curves;
|
nuclear@0
|
21 static Curve *sel_curve, *new_curve;
|
nuclear@0
|
22 static int sel_pidx = -1;
|
nuclear@0
|
23
|
nuclear@0
|
24 static Label *weight_label;
|
nuclear@0
|
25
|
nuclear@0
|
26
|
nuclear@0
|
27 bool app_init(int argc, char **argv)
|
nuclear@0
|
28 {
|
nuclear@0
|
29 glEnable(GL_MULTISAMPLE);
|
nuclear@0
|
30 glEnable(GL_CULL_FACE);
|
nuclear@0
|
31 return true;
|
nuclear@0
|
32 }
|
nuclear@0
|
33
|
nuclear@0
|
34 void app_cleanup()
|
nuclear@0
|
35 {
|
nuclear@0
|
36 for(size_t i=0; i<curves.size(); i++) {
|
nuclear@0
|
37 delete curves[i];
|
nuclear@0
|
38 }
|
nuclear@0
|
39 curves.clear();
|
nuclear@0
|
40 }
|
nuclear@0
|
41
|
nuclear@0
|
42 void app_draw()
|
nuclear@0
|
43 {
|
nuclear@1
|
44 glClearColor(0.1, 0.1, 0.1, 1);
|
nuclear@0
|
45 glClear(GL_COLOR_BUFFER_BIT);
|
nuclear@0
|
46
|
nuclear@0
|
47 glMatrixMode(GL_MODELVIEW);
|
nuclear@0
|
48 glLoadIdentity();
|
nuclear@0
|
49 glTranslatef(-view_pan_x, -view_pan_y, 0);
|
nuclear@0
|
50 glScalef(view_scale, view_scale, view_scale);
|
nuclear@0
|
51
|
nuclear@0
|
52 draw_grid(std::max(win_aspect, 1.0f / win_aspect), 0.1);
|
nuclear@0
|
53
|
nuclear@0
|
54 for(size_t i=0; i<curves.size(); i++) {
|
nuclear@0
|
55 draw_curve(curves[i]);
|
nuclear@0
|
56 }
|
nuclear@0
|
57 if(new_curve) {
|
nuclear@0
|
58 // TODO special drawing with more feedback
|
nuclear@0
|
59 draw_curve(new_curve);
|
nuclear@0
|
60 }
|
nuclear@0
|
61 if(weight_label) {
|
nuclear@0
|
62 weight_label->draw();
|
nuclear@0
|
63 }
|
nuclear@0
|
64 }
|
nuclear@0
|
65
|
nuclear@0
|
66 static void draw_grid(float sz, float sep, float alpha)
|
nuclear@0
|
67 {
|
nuclear@0
|
68 float x = 0.0f;
|
nuclear@0
|
69
|
nuclear@0
|
70 glLineWidth(1.0);
|
nuclear@0
|
71 glBegin(GL_LINES);
|
nuclear@0
|
72 glColor4f(0.6, 0.3, 0.2, alpha);
|
nuclear@0
|
73 glVertex2f(-sz, 0);
|
nuclear@0
|
74 glVertex2f(sz, 0);
|
nuclear@0
|
75 glColor4f(0.2, 0.3, 0.6, alpha);
|
nuclear@0
|
76 glVertex2f(0, -sz);
|
nuclear@0
|
77 glVertex2f(0, sz);
|
nuclear@1
|
78 glColor4f(0.35, 0.35, 0.35, alpha);
|
nuclear@0
|
79 while(x < sz) {
|
nuclear@0
|
80 x += sep;
|
nuclear@0
|
81 glVertex2f(-sz, x);
|
nuclear@0
|
82 glVertex2f(sz, x);
|
nuclear@0
|
83 glVertex2f(-sz, -x);
|
nuclear@0
|
84 glVertex2f(sz, -x);
|
nuclear@0
|
85 glVertex2f(x, -sz);
|
nuclear@0
|
86 glVertex2f(x, sz);
|
nuclear@0
|
87 glVertex2f(-x, -sz);
|
nuclear@0
|
88 glVertex2f(-x, sz);
|
nuclear@0
|
89 }
|
nuclear@0
|
90 glEnd();
|
nuclear@0
|
91 }
|
nuclear@0
|
92
|
nuclear@0
|
93 static void draw_curve(const Curve *curve)
|
nuclear@0
|
94 {
|
nuclear@0
|
95 int numpt = curve->get_point_count();
|
nuclear@0
|
96 int segm = numpt * 16.0f;
|
nuclear@0
|
97
|
nuclear@1
|
98 glLineWidth(2.0);
|
nuclear@1
|
99 if(curve == sel_curve) {
|
nuclear@1
|
100 glColor3f(0.3, 0.4, 1.0);
|
nuclear@1
|
101 } else if(curve == new_curve) {
|
nuclear@1
|
102 glColor3f(1.0, 0.75, 0.3);
|
nuclear@1
|
103 } else {
|
nuclear@1
|
104 glColor3f(0.75, 0.75, 0.75);
|
nuclear@1
|
105 }
|
nuclear@0
|
106 glBegin(GL_LINE_STRIP);
|
nuclear@0
|
107 for(int i=0; i<segm; i++) {
|
nuclear@0
|
108 float t = (float)i / (float)(segm - 1);
|
nuclear@0
|
109 Vector2 v = curve->interpolate(t);
|
nuclear@0
|
110 glVertex2f(v.x, v.y);
|
nuclear@0
|
111 }
|
nuclear@0
|
112 glEnd();
|
nuclear@0
|
113 glLineWidth(1.0);
|
nuclear@0
|
114
|
nuclear@1
|
115 glPointSize(7.0);
|
nuclear@0
|
116 glBegin(GL_POINTS);
|
nuclear@1
|
117 if(curve == new_curve) {
|
nuclear@1
|
118 glColor3f(1.0, 0.0, 0.0);
|
nuclear@1
|
119 } else {
|
nuclear@1
|
120 glColor3f(0.6, 0.3, 0.2);
|
nuclear@1
|
121 }
|
nuclear@0
|
122 for(int i=0; i<numpt; i++) {
|
nuclear@1
|
123 if(curve == sel_curve) {
|
nuclear@1
|
124 if(i == sel_pidx) {
|
nuclear@1
|
125 glColor3f(1.0, 0.2, 0.1);
|
nuclear@1
|
126 } else {
|
nuclear@1
|
127 glColor3f(0.2, 1.0, 0.2);
|
nuclear@1
|
128 }
|
nuclear@1
|
129 }
|
nuclear@0
|
130 Vector2 pt = curve->get_point(i);
|
nuclear@0
|
131 glVertex2f(pt.x, pt.y);
|
nuclear@0
|
132 }
|
nuclear@0
|
133 glEnd();
|
nuclear@0
|
134 glPointSize(1.0);
|
nuclear@0
|
135 }
|
nuclear@0
|
136
|
nuclear@0
|
137 void app_reshape(int x, int y)
|
nuclear@0
|
138 {
|
nuclear@0
|
139 win_width = x;
|
nuclear@0
|
140 win_height = y;
|
nuclear@0
|
141 win_aspect = (float)x / (float)y;
|
nuclear@0
|
142
|
nuclear@0
|
143 glViewport(0, 0, x, y);
|
nuclear@0
|
144 glMatrixMode(GL_PROJECTION);
|
nuclear@0
|
145 glLoadIdentity();
|
nuclear@0
|
146 glOrtho(-win_aspect, win_aspect, -1, 1, -1, 1);
|
nuclear@0
|
147 }
|
nuclear@0
|
148
|
nuclear@0
|
149 void app_keyboard(int key, bool pressed)
|
nuclear@0
|
150 {
|
nuclear@0
|
151 if(pressed) {
|
nuclear@0
|
152 switch(key) {
|
nuclear@1
|
153 case 'q':
|
nuclear@1
|
154 case 'Q':
|
nuclear@1
|
155 exit(0);
|
nuclear@1
|
156
|
nuclear@0
|
157 case 27:
|
nuclear@1
|
158 if(new_curve) {
|
nuclear@1
|
159 delete new_curve;
|
nuclear@1
|
160 new_curve = 0;
|
nuclear@1
|
161 post_redisplay();
|
nuclear@1
|
162 }
|
nuclear@1
|
163 break;
|
nuclear@0
|
164
|
nuclear@0
|
165 case 'l':
|
nuclear@0
|
166 case 'L':
|
nuclear@0
|
167 if(sel_curve) {
|
nuclear@0
|
168 sel_curve->set_type(CURVE_LINEAR);
|
nuclear@0
|
169 post_redisplay();
|
nuclear@0
|
170 }
|
nuclear@1
|
171 if(new_curve) {
|
nuclear@1
|
172 new_curve->set_type(CURVE_LINEAR);
|
nuclear@1
|
173 post_redisplay();
|
nuclear@1
|
174 }
|
nuclear@0
|
175 break;
|
nuclear@0
|
176
|
nuclear@0
|
177 case 'b':
|
nuclear@0
|
178 case 'B':
|
nuclear@0
|
179 if(sel_curve) {
|
nuclear@0
|
180 sel_curve->set_type(CURVE_BSPLINE);
|
nuclear@0
|
181 post_redisplay();
|
nuclear@0
|
182 }
|
nuclear@1
|
183 if(new_curve) {
|
nuclear@1
|
184 new_curve->set_type(CURVE_BSPLINE);
|
nuclear@1
|
185 post_redisplay();
|
nuclear@1
|
186 }
|
nuclear@0
|
187 break;
|
nuclear@0
|
188
|
nuclear@0
|
189 case 'h':
|
nuclear@0
|
190 case 'H':
|
nuclear@0
|
191 if(sel_curve) {
|
nuclear@0
|
192 sel_curve->set_type(CURVE_HERMITE);
|
nuclear@0
|
193 post_redisplay();
|
nuclear@0
|
194 }
|
nuclear@1
|
195 if(new_curve) {
|
nuclear@1
|
196 new_curve->set_type(CURVE_HERMITE);
|
nuclear@1
|
197 post_redisplay();
|
nuclear@1
|
198 }
|
nuclear@0
|
199 break;
|
nuclear@0
|
200 }
|
nuclear@0
|
201 }
|
nuclear@0
|
202 }
|
nuclear@0
|
203
|
nuclear@0
|
204 static Vector2 pixel_to_uv(int x, int y)
|
nuclear@0
|
205 {
|
nuclear@0
|
206 float u = win_aspect * (2.0 * (float)x / (float)win_width - 1.0);
|
nuclear@0
|
207 float v = 1.0 - 2.0 * (float)y / (float)win_height;
|
nuclear@0
|
208 return Vector2(u, v);
|
nuclear@0
|
209 }
|
nuclear@0
|
210
|
nuclear@0
|
211 static int prev_x, prev_y;
|
nuclear@0
|
212 static int click_pos[8][2];
|
nuclear@0
|
213 static unsigned int bnstate;
|
nuclear@0
|
214
|
nuclear@0
|
215 #define BNBIT(x) (1 << (x))
|
nuclear@0
|
216
|
nuclear@0
|
217 void app_mouse_button(int bn, bool pressed, int x, int y)
|
nuclear@0
|
218 {
|
nuclear@0
|
219 prev_x = x;
|
nuclear@0
|
220 prev_y = y;
|
nuclear@0
|
221 if(pressed) {
|
nuclear@0
|
222 bnstate |= BNBIT(bn);
|
nuclear@0
|
223 } else {
|
nuclear@0
|
224 bnstate &= ~BNBIT(bn);
|
nuclear@0
|
225 }
|
nuclear@0
|
226
|
nuclear@0
|
227 if(pressed) {
|
nuclear@0
|
228 click_pos[bn][0] = x;
|
nuclear@0
|
229 click_pos[bn][1] = y;
|
nuclear@0
|
230 } else {
|
nuclear@0
|
231 int dx = x - click_pos[bn][0];
|
nuclear@0
|
232 int dy = y - click_pos[bn][1];
|
nuclear@0
|
233
|
nuclear@0
|
234 if(abs(dx) + abs(dy) < 3) {
|
nuclear@0
|
235 Vector2 uv = pixel_to_uv(x, y);
|
nuclear@0
|
236 on_click(bn, uv.x, uv.y);
|
nuclear@0
|
237 }
|
nuclear@0
|
238
|
nuclear@0
|
239 if(!(bnstate & BNBIT(2))) {
|
nuclear@0
|
240 delete weight_label;
|
nuclear@0
|
241 weight_label = 0;
|
nuclear@0
|
242 post_redisplay();
|
nuclear@0
|
243 }
|
nuclear@0
|
244 }
|
nuclear@0
|
245 }
|
nuclear@0
|
246
|
nuclear@0
|
247 static void hover(int x, int y)
|
nuclear@0
|
248 {
|
nuclear@1
|
249 float thres = 0.02;
|
nuclear@0
|
250
|
nuclear@0
|
251 Vector2 uv = pixel_to_uv(x, y);
|
nuclear@0
|
252 for(size_t i=0; i<curves.size(); i++) {
|
nuclear@0
|
253 int pidx = curves[i]->nearest_point(uv);
|
nuclear@0
|
254 if(pidx == -1) continue;
|
nuclear@0
|
255
|
nuclear@0
|
256 Vector2 cp = curves[i]->get_point(pidx);
|
nuclear@0
|
257 if((cp - uv).length_sq() < thres * thres) {
|
nuclear@0
|
258 sel_curve = curves[i];
|
nuclear@0
|
259 sel_pidx = pidx;
|
nuclear@0
|
260 return;
|
nuclear@0
|
261 }
|
nuclear@0
|
262 }
|
nuclear@0
|
263
|
nuclear@0
|
264 sel_curve = 0;
|
nuclear@0
|
265 sel_pidx = -1;
|
nuclear@0
|
266 }
|
nuclear@0
|
267
|
nuclear@0
|
268 void app_mouse_motion(int x, int y)
|
nuclear@0
|
269 {
|
nuclear@0
|
270 int dx = x - prev_x;
|
nuclear@0
|
271 int dy = y - prev_y;
|
nuclear@0
|
272 prev_x = x;
|
nuclear@0
|
273 prev_y = y;
|
nuclear@0
|
274
|
nuclear@0
|
275 if(!dx && !dy) return;
|
nuclear@0
|
276
|
nuclear@0
|
277 if(!new_curve && !bnstate) {
|
nuclear@0
|
278 hover(x, y);
|
nuclear@0
|
279 post_redisplay();
|
nuclear@0
|
280 }
|
nuclear@0
|
281
|
nuclear@0
|
282 if(sel_curve && sel_pidx != -1) {
|
nuclear@0
|
283 if(bnstate & BNBIT(0)) {
|
nuclear@0
|
284 float w = sel_curve->get_weight(sel_pidx);
|
nuclear@0
|
285 sel_curve->set_point(sel_pidx, pixel_to_uv(x, y), w);
|
nuclear@0
|
286 post_redisplay();
|
nuclear@0
|
287 }
|
nuclear@0
|
288
|
nuclear@0
|
289 if(bnstate & BNBIT(2)) {
|
nuclear@0
|
290 float w = sel_curve->get_weight(sel_pidx);
|
nuclear@1
|
291 w -= dy * 0.01;
|
nuclear@0
|
292 if(w < FLT_MIN) w = FLT_MIN;
|
nuclear@0
|
293 sel_curve->set_weight(sel_pidx, w);
|
nuclear@0
|
294
|
nuclear@0
|
295 if(!weight_label) {
|
nuclear@0
|
296 weight_label = new Label;
|
nuclear@0
|
297 }
|
nuclear@0
|
298 weight_label->set_position(pixel_to_uv(x, y));
|
nuclear@0
|
299 weight_label->set_textf("w=%g", w);
|
nuclear@0
|
300 post_redisplay();
|
nuclear@0
|
301 }
|
nuclear@0
|
302 }
|
nuclear@0
|
303 }
|
nuclear@0
|
304
|
nuclear@0
|
305 static void on_click(int bn, float u, float v)
|
nuclear@0
|
306 {
|
nuclear@0
|
307 switch(bn) {
|
nuclear@0
|
308 case 0:
|
nuclear@0
|
309 if(!new_curve) {
|
nuclear@0
|
310 new_curve = new Curve;
|
nuclear@0
|
311 }
|
nuclear@0
|
312 new_curve->add_point(Vector2(u, v));
|
nuclear@0
|
313 post_redisplay();
|
nuclear@0
|
314 break;
|
nuclear@0
|
315
|
nuclear@0
|
316 case 2:
|
nuclear@0
|
317 curves.push_back(new_curve);
|
nuclear@0
|
318 new_curve = 0;
|
nuclear@0
|
319 post_redisplay();
|
nuclear@0
|
320 break;
|
nuclear@0
|
321
|
nuclear@0
|
322 default:
|
nuclear@0
|
323 break;
|
nuclear@0
|
324 }
|
nuclear@0
|
325 }
|