curvedraw

annotate src/app.cc @ 14:b625f0575d66

point snapping
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 17 Dec 2015 16:41:42 +0200
parents 9f75208b81cd
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@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@14 356 {
nuclear@14 357 Curve *nearest_curve = 0;
nuclear@14 358 int nearest_curve_pidx = -1;
nuclear@14 359 float nearest_dist_sq = FLT_MAX;
nuclear@14 360
nuclear@14 361 if(new_curve) {
nuclear@14 362 // find the closest point, ignoring the last
nuclear@14 363 for(int i=0; i<new_curve->size() - 1; i++) {
nuclear@14 364 Vector2 cp = new_curve->get_point(i);
nuclear@14 365 float distsq = (cp - p).length_sq();
nuclear@14 366 if(distsq < nearest_dist_sq) {
nuclear@14 367 nearest_curve = new_curve;
nuclear@14 368 nearest_dist_sq = distsq;
nuclear@14 369 nearest_curve_pidx = i;
nuclear@14 370 }
nuclear@14 371 }
nuclear@14 372 }
nuclear@14 373
nuclear@14 374
nuclear@14 375 for(size_t i=0; i<curves.size(); i++) {
nuclear@14 376 int pidx = curves[i]->nearest_point(p);
nuclear@14 377 Vector2 cp = curves[i]->get_point(pidx);
nuclear@14 378 float dist_sq = (cp - p).length_sq();
nuclear@14 379 if(dist_sq < nearest_dist_sq) {
nuclear@14 380 nearest_curve = curves[i];
nuclear@14 381 nearest_curve_pidx = pidx;
nuclear@14 382 nearest_dist_sq = dist_sq;
nuclear@14 383 }
nuclear@14 384 }
nuclear@14 385
nuclear@14 386 if(nearest_curve) {
nuclear@14 387 return nearest_curve->get_point(nearest_curve_pidx);
nuclear@14 388 }
nuclear@14 389 }
nuclear@14 390 break;
nuclear@14 391
nuclear@3 392 default:
nuclear@3 393 break;
nuclear@3 394 }
nuclear@3 395 return p;
nuclear@3 396 }
nuclear@3 397
nuclear@0 398 void app_mouse_motion(int x, int y)
nuclear@0 399 {
nuclear@3 400 Vector2 prev_uv = pixel_to_uv(prev_x, prev_y);
nuclear@3 401
nuclear@0 402 int dx = x - prev_x;
nuclear@0 403 int dy = y - prev_y;
nuclear@0 404 prev_x = x;
nuclear@0 405 prev_y = y;
nuclear@0 406
nuclear@0 407 if(!dx && !dy) return;
nuclear@0 408
nuclear@2 409 Vector2 uv = pixel_to_uv(x, y);
nuclear@3 410 #ifdef DRAW_MOUSE_POINTER
nuclear@3 411 mouse_pointer = uv;
nuclear@3 412 post_redisplay();
nuclear@3 413 #endif
nuclear@2 414
nuclear@2 415 /* when entering a new curve, have the last (extra) point following
nuclear@2 416 * the mouse until it's entered by a click (see on_click).
nuclear@2 417 */
nuclear@3 418 if(new_curve) {
nuclear@3 419 new_curve->move_point(new_curve->size() - 1, snap(uv));
nuclear@2 420 post_redisplay();
nuclear@2 421 }
nuclear@2 422
nuclear@4 423 if(!new_curve && !bnstate) {
nuclear@3 424 // not dragging, highlight curve under mouse
nuclear@2 425 point_hit_test(uv, &hover_curve, &sel_pidx);
nuclear@0 426 post_redisplay();
nuclear@0 427
nuclear@3 428 } else {
nuclear@3 429 // we're dragging with one or more buttons held down
nuclear@0 430
nuclear@3 431 if(sel_curve && sel_pidx != -1) {
nuclear@3 432 // we have a curve and a point of the curve selected
nuclear@0 433
nuclear@3 434 if(bnstate & BNBIT(0)) {
nuclear@3 435 // dragging point with left button: move it
nuclear@3 436 sel_curve->move_point(sel_pidx, snap(uv));
nuclear@3 437 post_redisplay();
nuclear@0 438 }
nuclear@3 439
nuclear@3 440 if(bnstate & BNBIT(2)) {
nuclear@3 441 // dragging point with right button: change weight
nuclear@3 442 float w = sel_curve->get_weight(sel_pidx);
nuclear@3 443 w -= dy * 0.01;
nuclear@3 444 if(w < FLT_MIN) w = FLT_MIN;
nuclear@3 445 sel_curve->set_weight(sel_pidx, w);
nuclear@3 446
nuclear@3 447 // popup floating weight label if not already there
nuclear@3 448 if(!weight_label) {
nuclear@3 449 weight_label = new Label;
nuclear@3 450 }
nuclear@3 451 weight_label->set_position(uv);
nuclear@3 452 weight_label->set_textf("w=%g", w);
nuclear@3 453 post_redisplay();
nuclear@3 454 }
nuclear@3 455 } else {
nuclear@3 456 // no selection, we're dragging in empty space: manipulate viewport
nuclear@3 457 Vector2 dir = uv - prev_uv;
nuclear@3 458
nuclear@3 459 if(bnstate & (BNBIT(0) | BNBIT(1))) {
nuclear@3 460 // panning
nuclear@3 461 view_pan += dir;
nuclear@3 462 calc_view_matrix();
nuclear@3 463 post_redisplay();
nuclear@3 464 }
nuclear@3 465 if(bnstate & BNBIT(2)) {
nuclear@3 466 // zooming
nuclear@3 467 view_scale -= ((float)dy / (float)win_height) * view_scale * 5.0;
nuclear@3 468 if(view_scale < 1e-4) view_scale = 1e-4;
nuclear@3 469 calc_view_matrix();
nuclear@3 470 post_redisplay();
nuclear@3 471 }
nuclear@0 472 }
nuclear@0 473 }
nuclear@0 474 }
nuclear@0 475
nuclear@0 476 static void on_click(int bn, float u, float v)
nuclear@0 477 {
nuclear@2 478 Vector2 uv = Vector2(u, v);
nuclear@2 479
nuclear@0 480 switch(bn) {
nuclear@2 481 case 0: // ------- LEFT CLICK ------
nuclear@2 482 if(hover_curve) {
nuclear@2 483 // if we're hovering: click selects
nuclear@2 484 sel_curve = hover_curve;
nuclear@2 485 hover_curve = 0;
nuclear@2 486 } else if(sel_curve) {
nuclear@2 487 // if we have a selected curve: click adds point (enter new_curve mode)
nuclear@2 488 std::vector<Curve*>::iterator it = std::find(curves.begin(), curves.end(), sel_curve);
nuclear@2 489 assert(it != curves.end());
nuclear@2 490 curves.erase(it, it + 1);
nuclear@2 491
nuclear@2 492 new_curve = sel_curve;
nuclear@2 493 sel_curve = 0;
nuclear@2 494 sel_pidx = -1;
nuclear@2 495
nuclear@2 496 new_curve->add_point(uv);
nuclear@2 497 } else {
nuclear@2 498 // otherwise, click starts a new curve
nuclear@2 499 if(!new_curve) {
nuclear@2 500 new_curve = new Curve;
nuclear@2 501 new_curve->add_point(uv);
nuclear@2 502 }
nuclear@2 503 new_curve->add_point(uv);
nuclear@0 504 }
nuclear@0 505 post_redisplay();
nuclear@0 506 break;
nuclear@0 507
nuclear@2 508 case 2: // ------- RIGHT CLICK ------
nuclear@2 509 if(new_curve) {
nuclear@2 510 // in new-curve mode: finish curve (cancels last floating segment)
nuclear@2 511 new_curve->remove_point(new_curve->size() - 1);
nuclear@2 512 if(new_curve->empty()) {
nuclear@2 513 delete new_curve;
nuclear@2 514 } else {
nuclear@2 515 curves.push_back(new_curve);
nuclear@2 516 }
nuclear@2 517 new_curve = 0;
nuclear@2 518
nuclear@2 519 } else if(sel_curve) {
nuclear@2 520 // in selected curve mode: delete control point or unselect
nuclear@2 521 Curve *hit_curve;
nuclear@2 522 int hit_pidx;
nuclear@2 523 if(point_hit_test(uv, &hit_curve, &hit_pidx) && hit_curve == sel_curve) {
nuclear@2 524 hit_curve->remove_point(hit_pidx);
nuclear@2 525 sel_pidx = -1;
nuclear@2 526 } else {
nuclear@2 527 sel_curve = 0;
nuclear@2 528 sel_pidx = -1;
nuclear@2 529 }
nuclear@2 530 }
nuclear@0 531 post_redisplay();
nuclear@0 532 break;
nuclear@0 533
nuclear@0 534 default:
nuclear@0 535 break;
nuclear@0 536 }
nuclear@0 537 }