curvedraw

annotate src/app.cc @ 13:4da693339d99

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