curvedraw
changeset 3:bf78387a9925
pan/zoom, grid snapping
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Thu, 17 Dec 2015 07:10:10 +0200 |
parents | ce7aa9a0594c |
children | 9f75208b81cd |
files | src/app.cc |
diffstat | 1 files changed, 159 insertions(+), 54 deletions(-) [+] |
line diff
1.1 --- a/src/app.cc Thu Dec 17 05:13:25 2015 +0200 1.2 +++ b/src/app.cc Thu Dec 17 07:10:10 2015 +0200 1.3 @@ -8,6 +8,12 @@ 1.4 #include "curve.h" 1.5 #include "widgets.h" 1.6 1.7 +enum SnapMode { 1.8 + SNAP_NONE, 1.9 + SNAP_GRID, 1.10 + SNAP_POINT 1.11 +}; 1.12 + 1.13 int win_width, win_height; 1.14 float win_aspect; 1.15 1.16 @@ -17,7 +23,11 @@ 1.17 1.18 // viewport control 1.19 static Vector2 view_pan; 1.20 -static float view_scale = 1.0f; 1.21 +static float view_scale = 0.2f; 1.22 +static Matrix4x4 view_matrix; 1.23 + 1.24 +static float grid_size = 1.0; 1.25 +static SnapMode snap_mode; 1.26 1.27 static std::vector<Curve*> curves; 1.28 static Curve *sel_curve; // selected curve being edited 1.29 @@ -27,6 +37,10 @@ 1.30 1.31 static Label *weight_label; // floating label for the cp weight 1.32 1.33 +#ifdef DRAW_MOUSE_POINTER 1.34 +static Vector2 mouse_pointer; 1.35 +#endif 1.36 + 1.37 1.38 bool app_init(int argc, char **argv) 1.39 { 1.40 @@ -53,10 +67,11 @@ 1.41 1.42 glMatrixMode(GL_MODELVIEW); 1.43 glLoadIdentity(); 1.44 - glTranslatef(-view_pan.x, -view_pan.y, 0); 1.45 + glTranslatef(view_pan.x * view_scale, view_pan.y * view_scale, 0); 1.46 glScalef(view_scale, view_scale, view_scale); 1.47 1.48 - draw_grid(std::max(win_aspect, 1.0f / win_aspect), 0.1); 1.49 + float max_aspect = std::max(win_aspect, 1.0f / win_aspect); 1.50 + draw_grid(max_aspect, grid_size); 1.51 1.52 for(size_t i=0; i<curves.size(); i++) { 1.53 draw_curve(curves[i]); 1.54 @@ -67,33 +82,61 @@ 1.55 if(weight_label) { 1.56 weight_label->draw(); 1.57 } 1.58 + 1.59 +#ifdef DRAW_MOUSE_POINTER 1.60 + glPointSize(6.0); 1.61 + glBegin(GL_POINTS); 1.62 + glColor3f(0, 0, 1); 1.63 + glVertex2f(mouse_pointer.x, mouse_pointer.y); 1.64 + glEnd(); 1.65 +#endif 1.66 } 1.67 1.68 static void draw_grid(float sz, float sep, float alpha) 1.69 { 1.70 float x = 0.0f; 1.71 + float s = 1.0 / view_scale; 1.72 + 1.73 + sz *= s; 1.74 + sz += sep; // one more step for when we have non-zero fractional pan 1.75 + float end = std::min(sz, 100.0f * sep); 1.76 + 1.77 + // fractional pan 1.78 + Vector2 pan = view_pan; 1.79 + Vector2 fpan = Vector2(fmod(pan.x, sep), fmod(pan.y, sep)); 1.80 + Vector2 offset = fpan - pan; 1.81 + 1.82 + glMatrixMode(GL_MODELVIEW); 1.83 + glPushMatrix(); 1.84 + glTranslatef(offset.x, offset.y, 0); 1.85 + 1.86 + glBegin(GL_LINES); 1.87 + glColor4f(0.35, 0.35, 0.35, alpha); 1.88 + while(x <= end) { 1.89 + glVertex2f(-end, x); 1.90 + glVertex2f(end, x); 1.91 + glVertex2f(-end, -x); 1.92 + glVertex2f(end, -x); 1.93 + glVertex2f(x, -end); 1.94 + glVertex2f(x, end); 1.95 + glVertex2f(-x, -end); 1.96 + glVertex2f(-x, end); 1.97 + x += sep; 1.98 + } 1.99 + glEnd(); 1.100 + glPopMatrix(); 1.101 + 1.102 1.103 glLineWidth(1.0); 1.104 glBegin(GL_LINES); 1.105 glColor4f(0.6, 0.3, 0.2, alpha); 1.106 - glVertex2f(-sz, 0); 1.107 - glVertex2f(sz, 0); 1.108 + glVertex2f(-sz + offset.x, 0); 1.109 + glVertex2f(sz + offset.x, 0); 1.110 glColor4f(0.2, 0.3, 0.6, alpha); 1.111 - glVertex2f(0, -sz); 1.112 - glVertex2f(0, sz); 1.113 - glColor4f(0.35, 0.35, 0.35, alpha); 1.114 - while(x < sz) { 1.115 - x += sep; 1.116 - glVertex2f(-sz, x); 1.117 - glVertex2f(sz, x); 1.118 - glVertex2f(-sz, -x); 1.119 - glVertex2f(sz, -x); 1.120 - glVertex2f(x, -sz); 1.121 - glVertex2f(x, sz); 1.122 - glVertex2f(-x, -sz); 1.123 - glVertex2f(-x, sz); 1.124 - } 1.125 + glVertex2f(0, -sz + offset.y); 1.126 + glVertex2f(0, sz + offset.y); 1.127 glEnd(); 1.128 + 1.129 } 1.130 1.131 static void draw_curve(const Curve *curve) 1.132 @@ -101,20 +144,6 @@ 1.133 int numpt = curve->size(); 1.134 int segm = numpt * 16; 1.135 1.136 - /*if(curve == hover_curve) { 1.137 - glLineWidth(3.0); 1.138 - glColor4f(0.8, 0.8, 0.0, 1.0); 1.139 - 1.140 - glBegin(GL_LINE_STRIP); 1.141 - for(int i=0; i<segm; i++) { 1.142 - float t = (float)i / (float)(segm - 1); 1.143 - Vector2 v = curve->interpolate(t); 1.144 - glVertex2f(v.x, v.y); 1.145 - } 1.146 - glEnd(); 1.147 - } 1.148 - */ 1.149 - 1.150 glLineWidth(curve == hover_curve ? 4.0 : 2.0); 1.151 if(curve == sel_curve) { 1.152 glColor3f(0.3, 0.4, 1.0); 1.153 @@ -219,13 +248,43 @@ 1.154 break; 1.155 } 1.156 } 1.157 + 1.158 + 1.159 + switch(key) { 1.160 + case 's': 1.161 + snap_mode = pressed ? SNAP_GRID : SNAP_NONE; 1.162 + break; 1.163 + 1.164 + case 'S': 1.165 + snap_mode = pressed ? SNAP_POINT : SNAP_NONE; 1.166 + break; 1.167 + 1.168 + default: 1.169 + break; 1.170 + } 1.171 +} 1.172 + 1.173 +static void calc_view_matrix() 1.174 +{ 1.175 + view_matrix.reset_identity(); 1.176 + view_matrix.scale(Vector3(view_scale, view_scale, view_scale)); 1.177 + view_matrix.translate(Vector3(view_pan.x, view_pan.y, 0.0)); 1.178 } 1.179 1.180 static Vector2 pixel_to_uv(int x, int y) 1.181 { 1.182 float u = win_aspect * (2.0 * (float)x / (float)win_width - 1.0); 1.183 float v = 1.0 - 2.0 * (float)y / (float)win_height; 1.184 + 1.185 + u = u / view_scale - view_pan.x; 1.186 + v = v / view_scale - view_pan.y; 1.187 return Vector2(u, v); 1.188 + /* 1.189 + Matrix4x4 inv_view_matrix = view_matrix.inverse(); 1.190 + Vector4 res = Vector4(u, v, 0.0, 1.0).transformed(inv_view_matrix); 1.191 + 1.192 + return Vector2(res.x, res.y); 1.193 + */ 1.194 } 1.195 1.196 static int prev_x, prev_y; 1.197 @@ -266,7 +325,7 @@ 1.198 1.199 static bool point_hit_test(const Vector2 &pos, Curve **curveret, int *pidxret) 1.200 { 1.201 - float thres = 0.02; 1.202 + float thres = 0.02 / view_scale; 1.203 1.204 for(size_t i=0; i<curves.size(); i++) { 1.205 int pidx = curves[i]->nearest_point(pos); 1.206 @@ -284,8 +343,23 @@ 1.207 return false; 1.208 } 1.209 1.210 +static Vector2 snap(const Vector2 &p) 1.211 +{ 1.212 + switch(snap_mode) { 1.213 + case SNAP_GRID: 1.214 + return Vector2(round(p.x / grid_size) * grid_size, round(p.y / grid_size) * grid_size); 1.215 + case SNAP_POINT: 1.216 + // TODO 1.217 + default: 1.218 + break; 1.219 + } 1.220 + return p; 1.221 +} 1.222 + 1.223 void app_mouse_motion(int x, int y) 1.224 { 1.225 + Vector2 prev_uv = pixel_to_uv(prev_x, prev_y); 1.226 + 1.227 int dx = x - prev_x; 1.228 int dy = y - prev_y; 1.229 prev_x = x; 1.230 @@ -294,39 +368,70 @@ 1.231 if(!dx && !dy) return; 1.232 1.233 Vector2 uv = pixel_to_uv(x, y); 1.234 +#ifdef DRAW_MOUSE_POINTER 1.235 + mouse_pointer = uv; 1.236 + post_redisplay(); 1.237 +#endif 1.238 1.239 /* when entering a new curve, have the last (extra) point following 1.240 * the mouse until it's entered by a click (see on_click). 1.241 */ 1.242 - if(new_curve && !new_curve->empty()) { 1.243 - new_curve->move_point(new_curve->size() - 1, uv); 1.244 + if(new_curve) { 1.245 + new_curve->move_point(new_curve->size() - 1, snap(uv)); 1.246 post_redisplay(); 1.247 + return; 1.248 } 1.249 + // from this point on we're definitely not in new-curve mode 1.250 1.251 - if(!new_curve && !bnstate) { 1.252 + if(!bnstate) { 1.253 + // not dragging, highlight curve under mouse 1.254 point_hit_test(uv, &hover_curve, &sel_pidx); 1.255 post_redisplay(); 1.256 - } 1.257 1.258 - if(sel_curve && sel_pidx != -1) { 1.259 - if(bnstate & BNBIT(0)) { 1.260 - float w = sel_curve->get_weight(sel_pidx); 1.261 - sel_curve->set_point(sel_pidx, uv, w); 1.262 - post_redisplay(); 1.263 - } 1.264 + } else { 1.265 + // we're dragging with one or more buttons held down 1.266 1.267 - if(bnstate & BNBIT(2)) { 1.268 - float w = sel_curve->get_weight(sel_pidx); 1.269 - w -= dy * 0.01; 1.270 - if(w < FLT_MIN) w = FLT_MIN; 1.271 - sel_curve->set_weight(sel_pidx, w); 1.272 + if(sel_curve && sel_pidx != -1) { 1.273 + // we have a curve and a point of the curve selected 1.274 1.275 - if(!weight_label) { 1.276 - weight_label = new Label; 1.277 + if(bnstate & BNBIT(0)) { 1.278 + // dragging point with left button: move it 1.279 + sel_curve->move_point(sel_pidx, snap(uv)); 1.280 + post_redisplay(); 1.281 } 1.282 - weight_label->set_position(uv); 1.283 - weight_label->set_textf("w=%g", w); 1.284 - post_redisplay(); 1.285 + 1.286 + if(bnstate & BNBIT(2)) { 1.287 + // dragging point with right button: change weight 1.288 + float w = sel_curve->get_weight(sel_pidx); 1.289 + w -= dy * 0.01; 1.290 + if(w < FLT_MIN) w = FLT_MIN; 1.291 + sel_curve->set_weight(sel_pidx, w); 1.292 + 1.293 + // popup floating weight label if not already there 1.294 + if(!weight_label) { 1.295 + weight_label = new Label; 1.296 + } 1.297 + weight_label->set_position(uv); 1.298 + weight_label->set_textf("w=%g", w); 1.299 + post_redisplay(); 1.300 + } 1.301 + } else { 1.302 + // no selection, we're dragging in empty space: manipulate viewport 1.303 + Vector2 dir = uv - prev_uv; 1.304 + 1.305 + if(bnstate & (BNBIT(0) | BNBIT(1))) { 1.306 + // panning 1.307 + view_pan += dir; 1.308 + calc_view_matrix(); 1.309 + post_redisplay(); 1.310 + } 1.311 + if(bnstate & BNBIT(2)) { 1.312 + // zooming 1.313 + view_scale -= ((float)dy / (float)win_height) * view_scale * 5.0; 1.314 + if(view_scale < 1e-4) view_scale = 1e-4; 1.315 + calc_view_matrix(); 1.316 + post_redisplay(); 1.317 + } 1.318 } 1.319 } 1.320 }