curvedraw
diff src/app.cc @ 0:8e524989c904
getting there
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Tue, 15 Dec 2015 07:15:53 +0200 |
parents | |
children | 7dcd0f6113e5 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/app.cc Tue Dec 15 07:15:53 2015 +0200 1.3 @@ -0,0 +1,292 @@ 1.4 +#include <stdlib.h> 1.5 +#include <float.h> 1.6 +#include <vector> 1.7 +#include <algorithm> 1.8 +#include "opengl.h" 1.9 +#include "app.h" 1.10 +#include "curve.h" 1.11 +#include "widgets.h" 1.12 + 1.13 +static void draw_grid(float sz, float sep, float alpha = 1.0f); 1.14 +static void draw_curve(const Curve *curve); 1.15 +static void on_click(int bn, float u, float v); 1.16 + 1.17 +static int win_width, win_height; 1.18 +static float win_aspect; 1.19 + 1.20 +static float view_pan_x, view_pan_y; 1.21 +static float view_scale = 1.0f; 1.22 + 1.23 +static std::vector<Curve*> curves; 1.24 +static Curve *sel_curve, *new_curve; 1.25 +static int sel_pidx = -1; 1.26 + 1.27 +static Label *weight_label; 1.28 + 1.29 + 1.30 +bool app_init(int argc, char **argv) 1.31 +{ 1.32 + glEnable(GL_MULTISAMPLE); 1.33 + glEnable(GL_CULL_FACE); 1.34 + return true; 1.35 +} 1.36 + 1.37 +void app_cleanup() 1.38 +{ 1.39 + for(size_t i=0; i<curves.size(); i++) { 1.40 + delete curves[i]; 1.41 + } 1.42 + curves.clear(); 1.43 +} 1.44 + 1.45 +void app_draw() 1.46 +{ 1.47 + glClearColor(0.16, 0.16, 0.16, 1); 1.48 + glClear(GL_COLOR_BUFFER_BIT); 1.49 + 1.50 + glMatrixMode(GL_MODELVIEW); 1.51 + glLoadIdentity(); 1.52 + glTranslatef(-view_pan_x, -view_pan_y, 0); 1.53 + glScalef(view_scale, view_scale, view_scale); 1.54 + 1.55 + draw_grid(std::max(win_aspect, 1.0f / win_aspect), 0.1); 1.56 + 1.57 + for(size_t i=0; i<curves.size(); i++) { 1.58 + draw_curve(curves[i]); 1.59 + } 1.60 + if(new_curve) { 1.61 + // TODO special drawing with more feedback 1.62 + draw_curve(new_curve); 1.63 + } 1.64 + if(weight_label) { 1.65 + weight_label->draw(); 1.66 + } 1.67 +} 1.68 + 1.69 +static void draw_grid(float sz, float sep, float alpha) 1.70 +{ 1.71 + float x = 0.0f; 1.72 + 1.73 + glLineWidth(1.0); 1.74 + glBegin(GL_LINES); 1.75 + glColor4f(0.6, 0.3, 0.2, alpha); 1.76 + glVertex2f(-sz, 0); 1.77 + glVertex2f(sz, 0); 1.78 + glColor4f(0.2, 0.3, 0.6, alpha); 1.79 + glVertex2f(0, -sz); 1.80 + glVertex2f(0, sz); 1.81 + glColor4f(0.4, 0.4, 0.4, alpha); 1.82 + while(x < sz) { 1.83 + x += sep; 1.84 + glVertex2f(-sz, x); 1.85 + glVertex2f(sz, x); 1.86 + glVertex2f(-sz, -x); 1.87 + glVertex2f(sz, -x); 1.88 + glVertex2f(x, -sz); 1.89 + glVertex2f(x, sz); 1.90 + glVertex2f(-x, -sz); 1.91 + glVertex2f(-x, sz); 1.92 + } 1.93 + glEnd(); 1.94 +} 1.95 + 1.96 +static void draw_curve(const Curve *curve) 1.97 +{ 1.98 + int numpt = curve->get_point_count(); 1.99 + int segm = numpt * 16.0f; 1.100 + 1.101 + glBegin(GL_LINE_STRIP); 1.102 + if(curve == sel_curve) { 1.103 + glLineWidth(3.0); 1.104 + glColor3f(0.2, 0.8, 0.3); 1.105 + } else { 1.106 + glLineWidth(2.0); 1.107 + glColor3f(0.8, 0.75, 0.3); 1.108 + } 1.109 + for(int i=0; i<segm; i++) { 1.110 + float t = (float)i / (float)(segm - 1); 1.111 + Vector2 v = curve->interpolate(t); 1.112 + glVertex2f(v.x, v.y); 1.113 + } 1.114 + glEnd(); 1.115 + glLineWidth(1.0); 1.116 + 1.117 + glPointSize(5.0); 1.118 + glBegin(GL_POINTS); 1.119 + glColor3f(1.0, 0.5, 0.2); 1.120 + for(int i=0; i<numpt; i++) { 1.121 + Vector2 pt = curve->get_point(i); 1.122 + glVertex2f(pt.x, pt.y); 1.123 + } 1.124 + glEnd(); 1.125 + glPointSize(1.0); 1.126 +} 1.127 + 1.128 +void app_reshape(int x, int y) 1.129 +{ 1.130 + win_width = x; 1.131 + win_height = y; 1.132 + win_aspect = (float)x / (float)y; 1.133 + 1.134 + glViewport(0, 0, x, y); 1.135 + glMatrixMode(GL_PROJECTION); 1.136 + glLoadIdentity(); 1.137 + glOrtho(-win_aspect, win_aspect, -1, 1, -1, 1); 1.138 +} 1.139 + 1.140 +void app_keyboard(int key, bool pressed) 1.141 +{ 1.142 + if(pressed) { 1.143 + switch(key) { 1.144 + case 27: 1.145 + exit(0); 1.146 + 1.147 + case 'l': 1.148 + case 'L': 1.149 + if(sel_curve) { 1.150 + sel_curve->set_type(CURVE_LINEAR); 1.151 + post_redisplay(); 1.152 + } 1.153 + break; 1.154 + 1.155 + case 'b': 1.156 + case 'B': 1.157 + if(sel_curve) { 1.158 + sel_curve->set_type(CURVE_BSPLINE); 1.159 + post_redisplay(); 1.160 + } 1.161 + break; 1.162 + 1.163 + case 'h': 1.164 + case 'H': 1.165 + if(sel_curve) { 1.166 + sel_curve->set_type(CURVE_HERMITE); 1.167 + post_redisplay(); 1.168 + } 1.169 + break; 1.170 + } 1.171 + } 1.172 +} 1.173 + 1.174 +static Vector2 pixel_to_uv(int x, int y) 1.175 +{ 1.176 + float u = win_aspect * (2.0 * (float)x / (float)win_width - 1.0); 1.177 + float v = 1.0 - 2.0 * (float)y / (float)win_height; 1.178 + return Vector2(u, v); 1.179 +} 1.180 + 1.181 +static int prev_x, prev_y; 1.182 +static int click_pos[8][2]; 1.183 +static unsigned int bnstate; 1.184 + 1.185 +#define BNBIT(x) (1 << (x)) 1.186 + 1.187 +void app_mouse_button(int bn, bool pressed, int x, int y) 1.188 +{ 1.189 + prev_x = x; 1.190 + prev_y = y; 1.191 + if(pressed) { 1.192 + bnstate |= BNBIT(bn); 1.193 + } else { 1.194 + bnstate &= ~BNBIT(bn); 1.195 + } 1.196 + 1.197 + if(pressed) { 1.198 + click_pos[bn][0] = x; 1.199 + click_pos[bn][1] = y; 1.200 + } else { 1.201 + int dx = x - click_pos[bn][0]; 1.202 + int dy = y - click_pos[bn][1]; 1.203 + 1.204 + if(abs(dx) + abs(dy) < 3) { 1.205 + Vector2 uv = pixel_to_uv(x, y); 1.206 + on_click(bn, uv.x, uv.y); 1.207 + } 1.208 + 1.209 + if(!(bnstate & BNBIT(2))) { 1.210 + delete weight_label; 1.211 + weight_label = 0; 1.212 + post_redisplay(); 1.213 + } 1.214 + } 1.215 +} 1.216 + 1.217 +static void hover(int x, int y) 1.218 +{ 1.219 + float thres = pixel_to_uv(5, 0).x - pixel_to_uv(0, 0).x; 1.220 + 1.221 + Vector2 uv = pixel_to_uv(x, y); 1.222 + for(size_t i=0; i<curves.size(); i++) { 1.223 + int pidx = curves[i]->nearest_point(uv); 1.224 + if(pidx == -1) continue; 1.225 + 1.226 + Vector2 cp = curves[i]->get_point(pidx); 1.227 + if((cp - uv).length_sq() < thres * thres) { 1.228 + sel_curve = curves[i]; 1.229 + sel_pidx = pidx; 1.230 + return; 1.231 + } 1.232 + } 1.233 + 1.234 + sel_curve = 0; 1.235 + sel_pidx = -1; 1.236 +} 1.237 + 1.238 +void app_mouse_motion(int x, int y) 1.239 +{ 1.240 + int dx = x - prev_x; 1.241 + int dy = y - prev_y; 1.242 + prev_x = x; 1.243 + prev_y = y; 1.244 + 1.245 + if(!dx && !dy) return; 1.246 + 1.247 + if(!new_curve && !bnstate) { 1.248 + hover(x, y); 1.249 + post_redisplay(); 1.250 + } 1.251 + 1.252 + if(sel_curve && sel_pidx != -1) { 1.253 + if(bnstate & BNBIT(0)) { 1.254 + float w = sel_curve->get_weight(sel_pidx); 1.255 + sel_curve->set_point(sel_pidx, pixel_to_uv(x, y), w); 1.256 + post_redisplay(); 1.257 + } 1.258 + 1.259 + if(bnstate & BNBIT(2)) { 1.260 + float w = sel_curve->get_weight(sel_pidx); 1.261 + w -= dy * 0.1; 1.262 + if(w < FLT_MIN) w = FLT_MIN; 1.263 + sel_curve->set_weight(sel_pidx, w); 1.264 + 1.265 + if(!weight_label) { 1.266 + weight_label = new Label; 1.267 + } 1.268 + weight_label->set_position(pixel_to_uv(x, y)); 1.269 + weight_label->set_textf("w=%g", w); 1.270 + post_redisplay(); 1.271 + } 1.272 + } 1.273 +} 1.274 + 1.275 +static void on_click(int bn, float u, float v) 1.276 +{ 1.277 + switch(bn) { 1.278 + case 0: 1.279 + if(!new_curve) { 1.280 + new_curve = new Curve; 1.281 + } 1.282 + new_curve->add_point(Vector2(u, v)); 1.283 + post_redisplay(); 1.284 + break; 1.285 + 1.286 + case 2: 1.287 + curves.push_back(new_curve); 1.288 + new_curve = 0; 1.289 + post_redisplay(); 1.290 + break; 1.291 + 1.292 + default: 1.293 + break; 1.294 + } 1.295 +}