rev |
line source |
nuclear@0
|
1 #include <stdlib.h>
|
nuclear@0
|
2 #include <float.h>
|
nuclear@2
|
3 #include <assert.h>
|
nuclear@0
|
4 #include <vector>
|
nuclear@0
|
5 #include <algorithm>
|
nuclear@0
|
6 #include "opengl.h"
|
nuclear@0
|
7 #include "app.h"
|
nuclear@0
|
8 #include "curve.h"
|
nuclear@0
|
9 #include "widgets.h"
|
nuclear@0
|
10
|
nuclear@3
|
11 enum SnapMode {
|
nuclear@3
|
12 SNAP_NONE,
|
nuclear@3
|
13 SNAP_GRID,
|
nuclear@3
|
14 SNAP_POINT
|
nuclear@3
|
15 };
|
nuclear@3
|
16
|
nuclear@1
|
17 int win_width, win_height;
|
nuclear@1
|
18 float win_aspect;
|
nuclear@1
|
19
|
nuclear@0
|
20 static void draw_grid(float sz, float sep, float alpha = 1.0f);
|
nuclear@0
|
21 static void draw_curve(const Curve *curve);
|
nuclear@0
|
22 static void on_click(int bn, float u, float v);
|
nuclear@0
|
23
|
nuclear@2
|
24 // viewport control
|
nuclear@2
|
25 static Vector2 view_pan;
|
nuclear@3
|
26 static float view_scale = 0.2f;
|
nuclear@3
|
27 static Matrix4x4 view_matrix;
|
nuclear@3
|
28
|
nuclear@3
|
29 static float grid_size = 1.0;
|
nuclear@3
|
30 static SnapMode snap_mode;
|
nuclear@0
|
31
|
nuclear@0
|
32 static std::vector<Curve*> curves;
|
nuclear@2
|
33 static Curve *sel_curve; // selected curve being edited
|
nuclear@2
|
34 static Curve *new_curve; // new curve being entered
|
nuclear@2
|
35 static Curve *hover_curve; // curve the mouse is hovering over (click to select)
|
nuclear@2
|
36 static int sel_pidx = -1; // selected point of the selected or hovered-over curve
|
nuclear@0
|
37
|
nuclear@2
|
38 static Label *weight_label; // floating label for the cp weight
|
nuclear@0
|
39
|
nuclear@3
|
40 #ifdef DRAW_MOUSE_POINTER
|
nuclear@3
|
41 static Vector2 mouse_pointer;
|
nuclear@3
|
42 #endif
|
nuclear@3
|
43
|
nuclear@0
|
44
|
nuclear@0
|
45 bool app_init(int argc, char **argv)
|
nuclear@0
|
46 {
|
nuclear@0
|
47 glEnable(GL_MULTISAMPLE);
|
nuclear@0
|
48 glEnable(GL_CULL_FACE);
|
nuclear@2
|
49
|
nuclear@2
|
50 glEnable(GL_BLEND);
|
nuclear@2
|
51 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
nuclear@0
|
52 return true;
|
nuclear@0
|
53 }
|
nuclear@0
|
54
|
nuclear@0
|
55 void app_cleanup()
|
nuclear@0
|
56 {
|
nuclear@0
|
57 for(size_t i=0; i<curves.size(); i++) {
|
nuclear@0
|
58 delete curves[i];
|
nuclear@0
|
59 }
|
nuclear@0
|
60 curves.clear();
|
nuclear@0
|
61 }
|
nuclear@0
|
62
|
nuclear@0
|
63 void app_draw()
|
nuclear@0
|
64 {
|
nuclear@1
|
65 glClearColor(0.1, 0.1, 0.1, 1);
|
nuclear@0
|
66 glClear(GL_COLOR_BUFFER_BIT);
|
nuclear@0
|
67
|
nuclear@0
|
68 glMatrixMode(GL_MODELVIEW);
|
nuclear@0
|
69 glLoadIdentity();
|
nuclear@3
|
70 glTranslatef(view_pan.x * view_scale, view_pan.y * view_scale, 0);
|
nuclear@0
|
71 glScalef(view_scale, view_scale, view_scale);
|
nuclear@0
|
72
|
nuclear@3
|
73 float max_aspect = std::max(win_aspect, 1.0f / win_aspect);
|
nuclear@3
|
74 draw_grid(max_aspect, grid_size);
|
nuclear@0
|
75
|
nuclear@0
|
76 for(size_t i=0; i<curves.size(); i++) {
|
nuclear@0
|
77 draw_curve(curves[i]);
|
nuclear@0
|
78 }
|
nuclear@0
|
79 if(new_curve) {
|
nuclear@0
|
80 draw_curve(new_curve);
|
nuclear@0
|
81 }
|
nuclear@3
|
82
|
nuclear@3
|
83 #ifdef DRAW_MOUSE_POINTER
|
nuclear@3
|
84 glPointSize(6.0);
|
nuclear@3
|
85 glBegin(GL_POINTS);
|
nuclear@3
|
86 glColor3f(0, 0, 1);
|
nuclear@3
|
87 glVertex2f(mouse_pointer.x, mouse_pointer.y);
|
nuclear@3
|
88 glEnd();
|
nuclear@3
|
89 #endif
|
nuclear@4
|
90
|
nuclear@4
|
91 glMatrixMode(GL_MODELVIEW);
|
nuclear@4
|
92 glLoadIdentity();
|
nuclear@4
|
93
|
nuclear@4
|
94 if(weight_label) {
|
nuclear@4
|
95 weight_label->draw();
|
nuclear@4
|
96 }
|
nuclear@0
|
97 }
|
nuclear@0
|
98
|
nuclear@0
|
99 static void draw_grid(float sz, float sep, float alpha)
|
nuclear@0
|
100 {
|
nuclear@0
|
101 float x = 0.0f;
|
nuclear@3
|
102 float s = 1.0 / view_scale;
|
nuclear@3
|
103
|
nuclear@3
|
104 sz *= s;
|
nuclear@3
|
105 sz += sep; // one more step for when we have non-zero fractional pan
|
nuclear@3
|
106 float end = std::min(sz, 100.0f * sep);
|
nuclear@3
|
107
|
nuclear@3
|
108 // fractional pan
|
nuclear@3
|
109 Vector2 pan = view_pan;
|
nuclear@3
|
110 Vector2 fpan = Vector2(fmod(pan.x, sep), fmod(pan.y, sep));
|
nuclear@3
|
111 Vector2 offset = fpan - pan;
|
nuclear@3
|
112
|
nuclear@3
|
113 glMatrixMode(GL_MODELVIEW);
|
nuclear@3
|
114 glPushMatrix();
|
nuclear@3
|
115 glTranslatef(offset.x, offset.y, 0);
|
nuclear@3
|
116
|
nuclear@3
|
117 glBegin(GL_LINES);
|
nuclear@3
|
118 glColor4f(0.35, 0.35, 0.35, alpha);
|
nuclear@3
|
119 while(x <= end) {
|
nuclear@3
|
120 glVertex2f(-end, x);
|
nuclear@3
|
121 glVertex2f(end, x);
|
nuclear@3
|
122 glVertex2f(-end, -x);
|
nuclear@3
|
123 glVertex2f(end, -x);
|
nuclear@3
|
124 glVertex2f(x, -end);
|
nuclear@3
|
125 glVertex2f(x, end);
|
nuclear@3
|
126 glVertex2f(-x, -end);
|
nuclear@3
|
127 glVertex2f(-x, end);
|
nuclear@3
|
128 x += sep;
|
nuclear@3
|
129 }
|
nuclear@3
|
130 glEnd();
|
nuclear@3
|
131 glPopMatrix();
|
nuclear@3
|
132
|
nuclear@0
|
133
|
nuclear@0
|
134 glLineWidth(1.0);
|
nuclear@0
|
135 glBegin(GL_LINES);
|
nuclear@0
|
136 glColor4f(0.6, 0.3, 0.2, alpha);
|
nuclear@3
|
137 glVertex2f(-sz + offset.x, 0);
|
nuclear@3
|
138 glVertex2f(sz + offset.x, 0);
|
nuclear@0
|
139 glColor4f(0.2, 0.3, 0.6, alpha);
|
nuclear@3
|
140 glVertex2f(0, -sz + offset.y);
|
nuclear@3
|
141 glVertex2f(0, sz + offset.y);
|
nuclear@0
|
142 glEnd();
|
nuclear@3
|
143
|
nuclear@0
|
144 }
|
nuclear@0
|
145
|
nuclear@0
|
146 static void draw_curve(const Curve *curve)
|
nuclear@0
|
147 {
|
nuclear@2
|
148 int numpt = curve->size();
|
nuclear@2
|
149 int segm = numpt * 16;
|
nuclear@0
|
150
|
nuclear@2
|
151 glLineWidth(curve == hover_curve ? 4.0 : 2.0);
|
nuclear@1
|
152 if(curve == sel_curve) {
|
nuclear@1
|
153 glColor3f(0.3, 0.4, 1.0);
|
nuclear@1
|
154 } else if(curve == new_curve) {
|
nuclear@1
|
155 glColor3f(1.0, 0.75, 0.3);
|
nuclear@1
|
156 } else {
|
nuclear@2
|
157 glColor3f(0.6, 0.6, 0.6);
|
nuclear@1
|
158 }
|
nuclear@0
|
159 glBegin(GL_LINE_STRIP);
|
nuclear@0
|
160 for(int i=0; i<segm; i++) {
|
nuclear@0
|
161 float t = (float)i / (float)(segm - 1);
|
nuclear@0
|
162 Vector2 v = curve->interpolate(t);
|
nuclear@0
|
163 glVertex2f(v.x, v.y);
|
nuclear@0
|
164 }
|
nuclear@0
|
165 glEnd();
|
nuclear@0
|
166 glLineWidth(1.0);
|
nuclear@0
|
167
|
nuclear@2
|
168 glPointSize(curve == hover_curve ? 10.0 : 7.0);
|
nuclear@0
|
169 glBegin(GL_POINTS);
|
nuclear@1
|
170 if(curve == new_curve) {
|
nuclear@1
|
171 glColor3f(1.0, 0.0, 0.0);
|
nuclear@1
|
172 } else {
|
nuclear@1
|
173 glColor3f(0.6, 0.3, 0.2);
|
nuclear@1
|
174 }
|
nuclear@0
|
175 for(int i=0; i<numpt; i++) {
|
nuclear@1
|
176 if(curve == sel_curve) {
|
nuclear@1
|
177 if(i == sel_pidx) {
|
nuclear@1
|
178 glColor3f(1.0, 0.2, 0.1);
|
nuclear@1
|
179 } else {
|
nuclear@1
|
180 glColor3f(0.2, 1.0, 0.2);
|
nuclear@1
|
181 }
|
nuclear@1
|
182 }
|
nuclear@0
|
183 Vector2 pt = curve->get_point(i);
|
nuclear@0
|
184 glVertex2f(pt.x, pt.y);
|
nuclear@0
|
185 }
|
nuclear@0
|
186 glEnd();
|
nuclear@0
|
187 glPointSize(1.0);
|
nuclear@0
|
188 }
|
nuclear@0
|
189
|
nuclear@0
|
190 void app_reshape(int x, int y)
|
nuclear@0
|
191 {
|
nuclear@0
|
192 win_width = x;
|
nuclear@0
|
193 win_height = y;
|
nuclear@0
|
194 win_aspect = (float)x / (float)y;
|
nuclear@0
|
195
|
nuclear@0
|
196 glViewport(0, 0, x, y);
|
nuclear@0
|
197 glMatrixMode(GL_PROJECTION);
|
nuclear@0
|
198 glLoadIdentity();
|
nuclear@0
|
199 glOrtho(-win_aspect, win_aspect, -1, 1, -1, 1);
|
nuclear@0
|
200 }
|
nuclear@0
|
201
|
nuclear@0
|
202 void app_keyboard(int key, bool pressed)
|
nuclear@0
|
203 {
|
nuclear@0
|
204 if(pressed) {
|
nuclear@0
|
205 switch(key) {
|
nuclear@1
|
206 case 'q':
|
nuclear@1
|
207 case 'Q':
|
nuclear@1
|
208 exit(0);
|
nuclear@1
|
209
|
nuclear@0
|
210 case 27:
|
nuclear@1
|
211 if(new_curve) {
|
nuclear@1
|
212 delete new_curve;
|
nuclear@1
|
213 new_curve = 0;
|
nuclear@1
|
214 post_redisplay();
|
nuclear@1
|
215 }
|
nuclear@1
|
216 break;
|
nuclear@0
|
217
|
nuclear@0
|
218 case 'l':
|
nuclear@0
|
219 case 'L':
|
nuclear@0
|
220 if(sel_curve) {
|
nuclear@0
|
221 sel_curve->set_type(CURVE_LINEAR);
|
nuclear@0
|
222 post_redisplay();
|
nuclear@0
|
223 }
|
nuclear@1
|
224 if(new_curve) {
|
nuclear@1
|
225 new_curve->set_type(CURVE_LINEAR);
|
nuclear@1
|
226 post_redisplay();
|
nuclear@1
|
227 }
|
nuclear@0
|
228 break;
|
nuclear@0
|
229
|
nuclear@0
|
230 case 'b':
|
nuclear@0
|
231 case 'B':
|
nuclear@0
|
232 if(sel_curve) {
|
nuclear@0
|
233 sel_curve->set_type(CURVE_BSPLINE);
|
nuclear@0
|
234 post_redisplay();
|
nuclear@0
|
235 }
|
nuclear@1
|
236 if(new_curve) {
|
nuclear@1
|
237 new_curve->set_type(CURVE_BSPLINE);
|
nuclear@1
|
238 post_redisplay();
|
nuclear@1
|
239 }
|
nuclear@0
|
240 break;
|
nuclear@0
|
241
|
nuclear@0
|
242 case 'h':
|
nuclear@0
|
243 case 'H':
|
nuclear@0
|
244 if(sel_curve) {
|
nuclear@0
|
245 sel_curve->set_type(CURVE_HERMITE);
|
nuclear@0
|
246 post_redisplay();
|
nuclear@0
|
247 }
|
nuclear@1
|
248 if(new_curve) {
|
nuclear@1
|
249 new_curve->set_type(CURVE_HERMITE);
|
nuclear@1
|
250 post_redisplay();
|
nuclear@1
|
251 }
|
nuclear@0
|
252 break;
|
nuclear@0
|
253 }
|
nuclear@0
|
254 }
|
nuclear@3
|
255
|
nuclear@3
|
256
|
nuclear@3
|
257 switch(key) {
|
nuclear@3
|
258 case 's':
|
nuclear@3
|
259 snap_mode = pressed ? SNAP_GRID : SNAP_NONE;
|
nuclear@3
|
260 break;
|
nuclear@3
|
261
|
nuclear@3
|
262 case 'S':
|
nuclear@3
|
263 snap_mode = pressed ? SNAP_POINT : SNAP_NONE;
|
nuclear@3
|
264 break;
|
nuclear@3
|
265
|
nuclear@3
|
266 default:
|
nuclear@3
|
267 break;
|
nuclear@3
|
268 }
|
nuclear@3
|
269 }
|
nuclear@3
|
270
|
nuclear@3
|
271 static void calc_view_matrix()
|
nuclear@3
|
272 {
|
nuclear@3
|
273 view_matrix.reset_identity();
|
nuclear@3
|
274 view_matrix.scale(Vector3(view_scale, view_scale, view_scale));
|
nuclear@3
|
275 view_matrix.translate(Vector3(view_pan.x, view_pan.y, 0.0));
|
nuclear@0
|
276 }
|
nuclear@0
|
277
|
nuclear@0
|
278 static Vector2 pixel_to_uv(int x, int y)
|
nuclear@0
|
279 {
|
nuclear@0
|
280 float u = win_aspect * (2.0 * (float)x / (float)win_width - 1.0);
|
nuclear@0
|
281 float v = 1.0 - 2.0 * (float)y / (float)win_height;
|
nuclear@3
|
282
|
nuclear@3
|
283 u = u / view_scale - view_pan.x;
|
nuclear@3
|
284 v = v / view_scale - view_pan.y;
|
nuclear@0
|
285 return Vector2(u, v);
|
nuclear@3
|
286 /*
|
nuclear@3
|
287 Matrix4x4 inv_view_matrix = view_matrix.inverse();
|
nuclear@3
|
288 Vector4 res = Vector4(u, v, 0.0, 1.0).transformed(inv_view_matrix);
|
nuclear@3
|
289
|
nuclear@3
|
290 return Vector2(res.x, res.y);
|
nuclear@3
|
291 */
|
nuclear@0
|
292 }
|
nuclear@0
|
293
|
nuclear@0
|
294 static int prev_x, prev_y;
|
nuclear@0
|
295 static int click_pos[8][2];
|
nuclear@0
|
296 static unsigned int bnstate;
|
nuclear@0
|
297
|
nuclear@0
|
298 #define BNBIT(x) (1 << (x))
|
nuclear@0
|
299
|
nuclear@0
|
300 void app_mouse_button(int bn, bool pressed, int x, int y)
|
nuclear@0
|
301 {
|
nuclear@0
|
302 prev_x = x;
|
nuclear@0
|
303 prev_y = y;
|
nuclear@0
|
304 if(pressed) {
|
nuclear@0
|
305 bnstate |= BNBIT(bn);
|
nuclear@0
|
306 } else {
|
nuclear@0
|
307 bnstate &= ~BNBIT(bn);
|
nuclear@0
|
308 }
|
nuclear@0
|
309
|
nuclear@0
|
310 if(pressed) {
|
nuclear@0
|
311 click_pos[bn][0] = x;
|
nuclear@0
|
312 click_pos[bn][1] = y;
|
nuclear@0
|
313 } else {
|
nuclear@0
|
314 int dx = x - click_pos[bn][0];
|
nuclear@0
|
315 int dy = y - click_pos[bn][1];
|
nuclear@0
|
316
|
nuclear@0
|
317 if(abs(dx) + abs(dy) < 3) {
|
nuclear@0
|
318 Vector2 uv = pixel_to_uv(x, y);
|
nuclear@0
|
319 on_click(bn, uv.x, uv.y);
|
nuclear@0
|
320 }
|
nuclear@0
|
321
|
nuclear@0
|
322 if(!(bnstate & BNBIT(2))) {
|
nuclear@0
|
323 delete weight_label;
|
nuclear@0
|
324 weight_label = 0;
|
nuclear@0
|
325 post_redisplay();
|
nuclear@0
|
326 }
|
nuclear@0
|
327 }
|
nuclear@0
|
328 }
|
nuclear@0
|
329
|
nuclear@2
|
330 static bool point_hit_test(const Vector2 &pos, Curve **curveret, int *pidxret)
|
nuclear@0
|
331 {
|
nuclear@3
|
332 float thres = 0.02 / view_scale;
|
nuclear@0
|
333
|
nuclear@0
|
334 for(size_t i=0; i<curves.size(); i++) {
|
nuclear@2
|
335 int pidx = curves[i]->nearest_point(pos);
|
nuclear@0
|
336 if(pidx == -1) continue;
|
nuclear@0
|
337
|
nuclear@0
|
338 Vector2 cp = curves[i]->get_point(pidx);
|
nuclear@2
|
339 if((cp - pos).length_sq() < thres * thres) {
|
nuclear@2
|
340 *curveret = curves[i];
|
nuclear@2
|
341 *pidxret = pidx;
|
nuclear@2
|
342 return true;
|
nuclear@0
|
343 }
|
nuclear@0
|
344 }
|
nuclear@2
|
345 *curveret = 0;
|
nuclear@2
|
346 *pidxret = -1;
|
nuclear@2
|
347 return false;
|
nuclear@0
|
348 }
|
nuclear@0
|
349
|
nuclear@3
|
350 static Vector2 snap(const Vector2 &p)
|
nuclear@3
|
351 {
|
nuclear@3
|
352 switch(snap_mode) {
|
nuclear@3
|
353 case SNAP_GRID:
|
nuclear@3
|
354 return Vector2(round(p.x / grid_size) * grid_size, round(p.y / grid_size) * grid_size);
|
nuclear@3
|
355 case SNAP_POINT:
|
nuclear@3
|
356 // TODO
|
nuclear@3
|
357 default:
|
nuclear@3
|
358 break;
|
nuclear@3
|
359 }
|
nuclear@3
|
360 return p;
|
nuclear@3
|
361 }
|
nuclear@3
|
362
|
nuclear@0
|
363 void app_mouse_motion(int x, int y)
|
nuclear@0
|
364 {
|
nuclear@3
|
365 Vector2 prev_uv = pixel_to_uv(prev_x, prev_y);
|
nuclear@3
|
366
|
nuclear@0
|
367 int dx = x - prev_x;
|
nuclear@0
|
368 int dy = y - prev_y;
|
nuclear@0
|
369 prev_x = x;
|
nuclear@0
|
370 prev_y = y;
|
nuclear@0
|
371
|
nuclear@0
|
372 if(!dx && !dy) return;
|
nuclear@0
|
373
|
nuclear@2
|
374 Vector2 uv = pixel_to_uv(x, y);
|
nuclear@3
|
375 #ifdef DRAW_MOUSE_POINTER
|
nuclear@3
|
376 mouse_pointer = uv;
|
nuclear@3
|
377 post_redisplay();
|
nuclear@3
|
378 #endif
|
nuclear@2
|
379
|
nuclear@2
|
380 /* when entering a new curve, have the last (extra) point following
|
nuclear@2
|
381 * the mouse until it's entered by a click (see on_click).
|
nuclear@2
|
382 */
|
nuclear@3
|
383 if(new_curve) {
|
nuclear@3
|
384 new_curve->move_point(new_curve->size() - 1, snap(uv));
|
nuclear@2
|
385 post_redisplay();
|
nuclear@2
|
386 }
|
nuclear@2
|
387
|
nuclear@4
|
388 if(!new_curve && !bnstate) {
|
nuclear@3
|
389 // not dragging, highlight curve under mouse
|
nuclear@2
|
390 point_hit_test(uv, &hover_curve, &sel_pidx);
|
nuclear@0
|
391 post_redisplay();
|
nuclear@0
|
392
|
nuclear@3
|
393 } else {
|
nuclear@3
|
394 // we're dragging with one or more buttons held down
|
nuclear@0
|
395
|
nuclear@3
|
396 if(sel_curve && sel_pidx != -1) {
|
nuclear@3
|
397 // we have a curve and a point of the curve selected
|
nuclear@0
|
398
|
nuclear@3
|
399 if(bnstate & BNBIT(0)) {
|
nuclear@3
|
400 // dragging point with left button: move it
|
nuclear@3
|
401 sel_curve->move_point(sel_pidx, snap(uv));
|
nuclear@3
|
402 post_redisplay();
|
nuclear@0
|
403 }
|
nuclear@3
|
404
|
nuclear@3
|
405 if(bnstate & BNBIT(2)) {
|
nuclear@3
|
406 // dragging point with right button: change weight
|
nuclear@3
|
407 float w = sel_curve->get_weight(sel_pidx);
|
nuclear@3
|
408 w -= dy * 0.01;
|
nuclear@3
|
409 if(w < FLT_MIN) w = FLT_MIN;
|
nuclear@3
|
410 sel_curve->set_weight(sel_pidx, w);
|
nuclear@3
|
411
|
nuclear@3
|
412 // popup floating weight label if not already there
|
nuclear@3
|
413 if(!weight_label) {
|
nuclear@3
|
414 weight_label = new Label;
|
nuclear@3
|
415 }
|
nuclear@3
|
416 weight_label->set_position(uv);
|
nuclear@3
|
417 weight_label->set_textf("w=%g", w);
|
nuclear@3
|
418 post_redisplay();
|
nuclear@3
|
419 }
|
nuclear@3
|
420 } else {
|
nuclear@3
|
421 // no selection, we're dragging in empty space: manipulate viewport
|
nuclear@3
|
422 Vector2 dir = uv - prev_uv;
|
nuclear@3
|
423
|
nuclear@3
|
424 if(bnstate & (BNBIT(0) | BNBIT(1))) {
|
nuclear@3
|
425 // panning
|
nuclear@3
|
426 view_pan += dir;
|
nuclear@3
|
427 calc_view_matrix();
|
nuclear@3
|
428 post_redisplay();
|
nuclear@3
|
429 }
|
nuclear@3
|
430 if(bnstate & BNBIT(2)) {
|
nuclear@3
|
431 // zooming
|
nuclear@3
|
432 view_scale -= ((float)dy / (float)win_height) * view_scale * 5.0;
|
nuclear@3
|
433 if(view_scale < 1e-4) view_scale = 1e-4;
|
nuclear@3
|
434 calc_view_matrix();
|
nuclear@3
|
435 post_redisplay();
|
nuclear@3
|
436 }
|
nuclear@0
|
437 }
|
nuclear@0
|
438 }
|
nuclear@0
|
439 }
|
nuclear@0
|
440
|
nuclear@0
|
441 static void on_click(int bn, float u, float v)
|
nuclear@0
|
442 {
|
nuclear@2
|
443 Vector2 uv = Vector2(u, v);
|
nuclear@2
|
444
|
nuclear@0
|
445 switch(bn) {
|
nuclear@2
|
446 case 0: // ------- LEFT CLICK ------
|
nuclear@2
|
447 if(hover_curve) {
|
nuclear@2
|
448 // if we're hovering: click selects
|
nuclear@2
|
449 sel_curve = hover_curve;
|
nuclear@2
|
450 hover_curve = 0;
|
nuclear@2
|
451 } else if(sel_curve) {
|
nuclear@2
|
452 // if we have a selected curve: click adds point (enter new_curve mode)
|
nuclear@2
|
453 std::vector<Curve*>::iterator it = std::find(curves.begin(), curves.end(), sel_curve);
|
nuclear@2
|
454 assert(it != curves.end());
|
nuclear@2
|
455 curves.erase(it, it + 1);
|
nuclear@2
|
456
|
nuclear@2
|
457 new_curve = sel_curve;
|
nuclear@2
|
458 sel_curve = 0;
|
nuclear@2
|
459 sel_pidx = -1;
|
nuclear@2
|
460
|
nuclear@2
|
461 new_curve->add_point(uv);
|
nuclear@2
|
462 } else {
|
nuclear@2
|
463 // otherwise, click starts a new curve
|
nuclear@2
|
464 if(!new_curve) {
|
nuclear@2
|
465 new_curve = new Curve;
|
nuclear@2
|
466 new_curve->add_point(uv);
|
nuclear@2
|
467 }
|
nuclear@2
|
468 new_curve->add_point(uv);
|
nuclear@0
|
469 }
|
nuclear@0
|
470 post_redisplay();
|
nuclear@0
|
471 break;
|
nuclear@0
|
472
|
nuclear@2
|
473 case 2: // ------- RIGHT CLICK ------
|
nuclear@2
|
474 if(new_curve) {
|
nuclear@2
|
475 // in new-curve mode: finish curve (cancels last floating segment)
|
nuclear@2
|
476 new_curve->remove_point(new_curve->size() - 1);
|
nuclear@2
|
477 if(new_curve->empty()) {
|
nuclear@2
|
478 delete new_curve;
|
nuclear@2
|
479 } else {
|
nuclear@2
|
480 curves.push_back(new_curve);
|
nuclear@2
|
481 }
|
nuclear@2
|
482 new_curve = 0;
|
nuclear@2
|
483
|
nuclear@2
|
484 } else if(sel_curve) {
|
nuclear@2
|
485 // in selected curve mode: delete control point or unselect
|
nuclear@2
|
486 Curve *hit_curve;
|
nuclear@2
|
487 int hit_pidx;
|
nuclear@2
|
488 if(point_hit_test(uv, &hit_curve, &hit_pidx) && hit_curve == sel_curve) {
|
nuclear@2
|
489 hit_curve->remove_point(hit_pidx);
|
nuclear@2
|
490 sel_pidx = -1;
|
nuclear@2
|
491 } else {
|
nuclear@2
|
492 sel_curve = 0;
|
nuclear@2
|
493 sel_pidx = -1;
|
nuclear@2
|
494 }
|
nuclear@2
|
495 }
|
nuclear@0
|
496 post_redisplay();
|
nuclear@0
|
497 break;
|
nuclear@0
|
498
|
nuclear@0
|
499 default:
|
nuclear@0
|
500 break;
|
nuclear@0
|
501 }
|
nuclear@0
|
502 }
|