curvedraw
diff src/app.cc @ 2:ce7aa9a0594c
improved curve editing
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Thu, 17 Dec 2015 05:13:25 +0200 |
parents | 7dcd0f6113e5 |
children | bf78387a9925 |
line diff
1.1 --- a/src/app.cc Wed Dec 16 04:49:16 2015 +0200 1.2 +++ b/src/app.cc Thu Dec 17 05:13:25 2015 +0200 1.3 @@ -1,5 +1,6 @@ 1.4 #include <stdlib.h> 1.5 #include <float.h> 1.6 +#include <assert.h> 1.7 #include <vector> 1.8 #include <algorithm> 1.9 #include "opengl.h" 1.10 @@ -14,20 +15,26 @@ 1.11 static void draw_curve(const Curve *curve); 1.12 static void on_click(int bn, float u, float v); 1.13 1.14 -static float view_pan_x, view_pan_y; 1.15 +// viewport control 1.16 +static Vector2 view_pan; 1.17 static float view_scale = 1.0f; 1.18 1.19 static std::vector<Curve*> curves; 1.20 -static Curve *sel_curve, *new_curve; 1.21 -static int sel_pidx = -1; 1.22 +static Curve *sel_curve; // selected curve being edited 1.23 +static Curve *new_curve; // new curve being entered 1.24 +static Curve *hover_curve; // curve the mouse is hovering over (click to select) 1.25 +static int sel_pidx = -1; // selected point of the selected or hovered-over curve 1.26 1.27 -static Label *weight_label; 1.28 +static Label *weight_label; // floating label for the cp weight 1.29 1.30 1.31 bool app_init(int argc, char **argv) 1.32 { 1.33 glEnable(GL_MULTISAMPLE); 1.34 glEnable(GL_CULL_FACE); 1.35 + 1.36 + glEnable(GL_BLEND); 1.37 + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 1.38 return true; 1.39 } 1.40 1.41 @@ -46,7 +53,7 @@ 1.42 1.43 glMatrixMode(GL_MODELVIEW); 1.44 glLoadIdentity(); 1.45 - glTranslatef(-view_pan_x, -view_pan_y, 0); 1.46 + glTranslatef(-view_pan.x, -view_pan.y, 0); 1.47 glScalef(view_scale, view_scale, view_scale); 1.48 1.49 draw_grid(std::max(win_aspect, 1.0f / win_aspect), 0.1); 1.50 @@ -55,7 +62,6 @@ 1.51 draw_curve(curves[i]); 1.52 } 1.53 if(new_curve) { 1.54 - // TODO special drawing with more feedback 1.55 draw_curve(new_curve); 1.56 } 1.57 if(weight_label) { 1.58 @@ -92,16 +98,30 @@ 1.59 1.60 static void draw_curve(const Curve *curve) 1.61 { 1.62 - int numpt = curve->get_point_count(); 1.63 - int segm = numpt * 16.0f; 1.64 + int numpt = curve->size(); 1.65 + int segm = numpt * 16; 1.66 1.67 - glLineWidth(2.0); 1.68 + /*if(curve == hover_curve) { 1.69 + glLineWidth(3.0); 1.70 + glColor4f(0.8, 0.8, 0.0, 1.0); 1.71 + 1.72 + glBegin(GL_LINE_STRIP); 1.73 + for(int i=0; i<segm; i++) { 1.74 + float t = (float)i / (float)(segm - 1); 1.75 + Vector2 v = curve->interpolate(t); 1.76 + glVertex2f(v.x, v.y); 1.77 + } 1.78 + glEnd(); 1.79 + } 1.80 + */ 1.81 + 1.82 + glLineWidth(curve == hover_curve ? 4.0 : 2.0); 1.83 if(curve == sel_curve) { 1.84 glColor3f(0.3, 0.4, 1.0); 1.85 } else if(curve == new_curve) { 1.86 glColor3f(1.0, 0.75, 0.3); 1.87 } else { 1.88 - glColor3f(0.75, 0.75, 0.75); 1.89 + glColor3f(0.6, 0.6, 0.6); 1.90 } 1.91 glBegin(GL_LINE_STRIP); 1.92 for(int i=0; i<segm; i++) { 1.93 @@ -112,7 +132,7 @@ 1.94 glEnd(); 1.95 glLineWidth(1.0); 1.96 1.97 - glPointSize(7.0); 1.98 + glPointSize(curve == hover_curve ? 10.0 : 7.0); 1.99 glBegin(GL_POINTS); 1.100 if(curve == new_curve) { 1.101 glColor3f(1.0, 0.0, 0.0); 1.102 @@ -244,25 +264,24 @@ 1.103 } 1.104 } 1.105 1.106 -static void hover(int x, int y) 1.107 +static bool point_hit_test(const Vector2 &pos, Curve **curveret, int *pidxret) 1.108 { 1.109 float thres = 0.02; 1.110 1.111 - Vector2 uv = pixel_to_uv(x, y); 1.112 for(size_t i=0; i<curves.size(); i++) { 1.113 - int pidx = curves[i]->nearest_point(uv); 1.114 + int pidx = curves[i]->nearest_point(pos); 1.115 if(pidx == -1) continue; 1.116 1.117 Vector2 cp = curves[i]->get_point(pidx); 1.118 - if((cp - uv).length_sq() < thres * thres) { 1.119 - sel_curve = curves[i]; 1.120 - sel_pidx = pidx; 1.121 - return; 1.122 + if((cp - pos).length_sq() < thres * thres) { 1.123 + *curveret = curves[i]; 1.124 + *pidxret = pidx; 1.125 + return true; 1.126 } 1.127 } 1.128 - 1.129 - sel_curve = 0; 1.130 - sel_pidx = -1; 1.131 + *curveret = 0; 1.132 + *pidxret = -1; 1.133 + return false; 1.134 } 1.135 1.136 void app_mouse_motion(int x, int y) 1.137 @@ -274,15 +293,25 @@ 1.138 1.139 if(!dx && !dy) return; 1.140 1.141 + Vector2 uv = pixel_to_uv(x, y); 1.142 + 1.143 + /* when entering a new curve, have the last (extra) point following 1.144 + * the mouse until it's entered by a click (see on_click). 1.145 + */ 1.146 + if(new_curve && !new_curve->empty()) { 1.147 + new_curve->move_point(new_curve->size() - 1, uv); 1.148 + post_redisplay(); 1.149 + } 1.150 + 1.151 if(!new_curve && !bnstate) { 1.152 - hover(x, y); 1.153 + point_hit_test(uv, &hover_curve, &sel_pidx); 1.154 post_redisplay(); 1.155 } 1.156 1.157 if(sel_curve && sel_pidx != -1) { 1.158 if(bnstate & BNBIT(0)) { 1.159 float w = sel_curve->get_weight(sel_pidx); 1.160 - sel_curve->set_point(sel_pidx, pixel_to_uv(x, y), w); 1.161 + sel_curve->set_point(sel_pidx, uv, w); 1.162 post_redisplay(); 1.163 } 1.164 1.165 @@ -295,7 +324,7 @@ 1.166 if(!weight_label) { 1.167 weight_label = new Label; 1.168 } 1.169 - weight_label->set_position(pixel_to_uv(x, y)); 1.170 + weight_label->set_position(uv); 1.171 weight_label->set_textf("w=%g", w); 1.172 post_redisplay(); 1.173 } 1.174 @@ -304,18 +333,59 @@ 1.175 1.176 static void on_click(int bn, float u, float v) 1.177 { 1.178 + Vector2 uv = Vector2(u, v); 1.179 + 1.180 switch(bn) { 1.181 - case 0: 1.182 - if(!new_curve) { 1.183 - new_curve = new Curve; 1.184 + case 0: // ------- LEFT CLICK ------ 1.185 + if(hover_curve) { 1.186 + // if we're hovering: click selects 1.187 + sel_curve = hover_curve; 1.188 + hover_curve = 0; 1.189 + } else if(sel_curve) { 1.190 + // if we have a selected curve: click adds point (enter new_curve mode) 1.191 + std::vector<Curve*>::iterator it = std::find(curves.begin(), curves.end(), sel_curve); 1.192 + assert(it != curves.end()); 1.193 + curves.erase(it, it + 1); 1.194 + 1.195 + new_curve = sel_curve; 1.196 + sel_curve = 0; 1.197 + sel_pidx = -1; 1.198 + 1.199 + new_curve->add_point(uv); 1.200 + } else { 1.201 + // otherwise, click starts a new curve 1.202 + if(!new_curve) { 1.203 + new_curve = new Curve; 1.204 + new_curve->add_point(uv); 1.205 + } 1.206 + new_curve->add_point(uv); 1.207 } 1.208 - new_curve->add_point(Vector2(u, v)); 1.209 post_redisplay(); 1.210 break; 1.211 1.212 - case 2: 1.213 - curves.push_back(new_curve); 1.214 - new_curve = 0; 1.215 + case 2: // ------- RIGHT CLICK ------ 1.216 + if(new_curve) { 1.217 + // in new-curve mode: finish curve (cancels last floating segment) 1.218 + new_curve->remove_point(new_curve->size() - 1); 1.219 + if(new_curve->empty()) { 1.220 + delete new_curve; 1.221 + } else { 1.222 + curves.push_back(new_curve); 1.223 + } 1.224 + new_curve = 0; 1.225 + 1.226 + } else if(sel_curve) { 1.227 + // in selected curve mode: delete control point or unselect 1.228 + Curve *hit_curve; 1.229 + int hit_pidx; 1.230 + if(point_hit_test(uv, &hit_curve, &hit_pidx) && hit_curve == sel_curve) { 1.231 + hit_curve->remove_point(hit_pidx); 1.232 + sel_pidx = -1; 1.233 + } else { 1.234 + sel_curve = 0; 1.235 + sel_pidx = -1; 1.236 + } 1.237 + } 1.238 post_redisplay(); 1.239 break; 1.240