curvedraw

annotate src/app.cc @ 1:7dcd0f6113e5

some ui and feedback stuff
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 16 Dec 2015 04:49:16 +0200
parents 8e524989c904
children ce7aa9a0594c
rev   line source
nuclear@0 1 #include <stdlib.h>
nuclear@0 2 #include <float.h>
nuclear@0 3 #include <vector>
nuclear@0 4 #include <algorithm>
nuclear@0 5 #include "opengl.h"
nuclear@0 6 #include "app.h"
nuclear@0 7 #include "curve.h"
nuclear@0 8 #include "widgets.h"
nuclear@0 9
nuclear@1 10 int win_width, win_height;
nuclear@1 11 float win_aspect;
nuclear@1 12
nuclear@0 13 static void draw_grid(float sz, float sep, float alpha = 1.0f);
nuclear@0 14 static void draw_curve(const Curve *curve);
nuclear@0 15 static void on_click(int bn, float u, float v);
nuclear@0 16
nuclear@0 17 static float view_pan_x, view_pan_y;
nuclear@0 18 static float view_scale = 1.0f;
nuclear@0 19
nuclear@0 20 static std::vector<Curve*> curves;
nuclear@0 21 static Curve *sel_curve, *new_curve;
nuclear@0 22 static int sel_pidx = -1;
nuclear@0 23
nuclear@0 24 static Label *weight_label;
nuclear@0 25
nuclear@0 26
nuclear@0 27 bool app_init(int argc, char **argv)
nuclear@0 28 {
nuclear@0 29 glEnable(GL_MULTISAMPLE);
nuclear@0 30 glEnable(GL_CULL_FACE);
nuclear@0 31 return true;
nuclear@0 32 }
nuclear@0 33
nuclear@0 34 void app_cleanup()
nuclear@0 35 {
nuclear@0 36 for(size_t i=0; i<curves.size(); i++) {
nuclear@0 37 delete curves[i];
nuclear@0 38 }
nuclear@0 39 curves.clear();
nuclear@0 40 }
nuclear@0 41
nuclear@0 42 void app_draw()
nuclear@0 43 {
nuclear@1 44 glClearColor(0.1, 0.1, 0.1, 1);
nuclear@0 45 glClear(GL_COLOR_BUFFER_BIT);
nuclear@0 46
nuclear@0 47 glMatrixMode(GL_MODELVIEW);
nuclear@0 48 glLoadIdentity();
nuclear@0 49 glTranslatef(-view_pan_x, -view_pan_y, 0);
nuclear@0 50 glScalef(view_scale, view_scale, view_scale);
nuclear@0 51
nuclear@0 52 draw_grid(std::max(win_aspect, 1.0f / win_aspect), 0.1);
nuclear@0 53
nuclear@0 54 for(size_t i=0; i<curves.size(); i++) {
nuclear@0 55 draw_curve(curves[i]);
nuclear@0 56 }
nuclear@0 57 if(new_curve) {
nuclear@0 58 // TODO special drawing with more feedback
nuclear@0 59 draw_curve(new_curve);
nuclear@0 60 }
nuclear@0 61 if(weight_label) {
nuclear@0 62 weight_label->draw();
nuclear@0 63 }
nuclear@0 64 }
nuclear@0 65
nuclear@0 66 static void draw_grid(float sz, float sep, float alpha)
nuclear@0 67 {
nuclear@0 68 float x = 0.0f;
nuclear@0 69
nuclear@0 70 glLineWidth(1.0);
nuclear@0 71 glBegin(GL_LINES);
nuclear@0 72 glColor4f(0.6, 0.3, 0.2, alpha);
nuclear@0 73 glVertex2f(-sz, 0);
nuclear@0 74 glVertex2f(sz, 0);
nuclear@0 75 glColor4f(0.2, 0.3, 0.6, alpha);
nuclear@0 76 glVertex2f(0, -sz);
nuclear@0 77 glVertex2f(0, sz);
nuclear@1 78 glColor4f(0.35, 0.35, 0.35, alpha);
nuclear@0 79 while(x < sz) {
nuclear@0 80 x += sep;
nuclear@0 81 glVertex2f(-sz, x);
nuclear@0 82 glVertex2f(sz, x);
nuclear@0 83 glVertex2f(-sz, -x);
nuclear@0 84 glVertex2f(sz, -x);
nuclear@0 85 glVertex2f(x, -sz);
nuclear@0 86 glVertex2f(x, sz);
nuclear@0 87 glVertex2f(-x, -sz);
nuclear@0 88 glVertex2f(-x, sz);
nuclear@0 89 }
nuclear@0 90 glEnd();
nuclear@0 91 }
nuclear@0 92
nuclear@0 93 static void draw_curve(const Curve *curve)
nuclear@0 94 {
nuclear@0 95 int numpt = curve->get_point_count();
nuclear@0 96 int segm = numpt * 16.0f;
nuclear@0 97
nuclear@1 98 glLineWidth(2.0);
nuclear@1 99 if(curve == sel_curve) {
nuclear@1 100 glColor3f(0.3, 0.4, 1.0);
nuclear@1 101 } else if(curve == new_curve) {
nuclear@1 102 glColor3f(1.0, 0.75, 0.3);
nuclear@1 103 } else {
nuclear@1 104 glColor3f(0.75, 0.75, 0.75);
nuclear@1 105 }
nuclear@0 106 glBegin(GL_LINE_STRIP);
nuclear@0 107 for(int i=0; i<segm; i++) {
nuclear@0 108 float t = (float)i / (float)(segm - 1);
nuclear@0 109 Vector2 v = curve->interpolate(t);
nuclear@0 110 glVertex2f(v.x, v.y);
nuclear@0 111 }
nuclear@0 112 glEnd();
nuclear@0 113 glLineWidth(1.0);
nuclear@0 114
nuclear@1 115 glPointSize(7.0);
nuclear@0 116 glBegin(GL_POINTS);
nuclear@1 117 if(curve == new_curve) {
nuclear@1 118 glColor3f(1.0, 0.0, 0.0);
nuclear@1 119 } else {
nuclear@1 120 glColor3f(0.6, 0.3, 0.2);
nuclear@1 121 }
nuclear@0 122 for(int i=0; i<numpt; i++) {
nuclear@1 123 if(curve == sel_curve) {
nuclear@1 124 if(i == sel_pidx) {
nuclear@1 125 glColor3f(1.0, 0.2, 0.1);
nuclear@1 126 } else {
nuclear@1 127 glColor3f(0.2, 1.0, 0.2);
nuclear@1 128 }
nuclear@1 129 }
nuclear@0 130 Vector2 pt = curve->get_point(i);
nuclear@0 131 glVertex2f(pt.x, pt.y);
nuclear@0 132 }
nuclear@0 133 glEnd();
nuclear@0 134 glPointSize(1.0);
nuclear@0 135 }
nuclear@0 136
nuclear@0 137 void app_reshape(int x, int y)
nuclear@0 138 {
nuclear@0 139 win_width = x;
nuclear@0 140 win_height = y;
nuclear@0 141 win_aspect = (float)x / (float)y;
nuclear@0 142
nuclear@0 143 glViewport(0, 0, x, y);
nuclear@0 144 glMatrixMode(GL_PROJECTION);
nuclear@0 145 glLoadIdentity();
nuclear@0 146 glOrtho(-win_aspect, win_aspect, -1, 1, -1, 1);
nuclear@0 147 }
nuclear@0 148
nuclear@0 149 void app_keyboard(int key, bool pressed)
nuclear@0 150 {
nuclear@0 151 if(pressed) {
nuclear@0 152 switch(key) {
nuclear@1 153 case 'q':
nuclear@1 154 case 'Q':
nuclear@1 155 exit(0);
nuclear@1 156
nuclear@0 157 case 27:
nuclear@1 158 if(new_curve) {
nuclear@1 159 delete new_curve;
nuclear@1 160 new_curve = 0;
nuclear@1 161 post_redisplay();
nuclear@1 162 }
nuclear@1 163 break;
nuclear@0 164
nuclear@0 165 case 'l':
nuclear@0 166 case 'L':
nuclear@0 167 if(sel_curve) {
nuclear@0 168 sel_curve->set_type(CURVE_LINEAR);
nuclear@0 169 post_redisplay();
nuclear@0 170 }
nuclear@1 171 if(new_curve) {
nuclear@1 172 new_curve->set_type(CURVE_LINEAR);
nuclear@1 173 post_redisplay();
nuclear@1 174 }
nuclear@0 175 break;
nuclear@0 176
nuclear@0 177 case 'b':
nuclear@0 178 case 'B':
nuclear@0 179 if(sel_curve) {
nuclear@0 180 sel_curve->set_type(CURVE_BSPLINE);
nuclear@0 181 post_redisplay();
nuclear@0 182 }
nuclear@1 183 if(new_curve) {
nuclear@1 184 new_curve->set_type(CURVE_BSPLINE);
nuclear@1 185 post_redisplay();
nuclear@1 186 }
nuclear@0 187 break;
nuclear@0 188
nuclear@0 189 case 'h':
nuclear@0 190 case 'H':
nuclear@0 191 if(sel_curve) {
nuclear@0 192 sel_curve->set_type(CURVE_HERMITE);
nuclear@0 193 post_redisplay();
nuclear@0 194 }
nuclear@1 195 if(new_curve) {
nuclear@1 196 new_curve->set_type(CURVE_HERMITE);
nuclear@1 197 post_redisplay();
nuclear@1 198 }
nuclear@0 199 break;
nuclear@0 200 }
nuclear@0 201 }
nuclear@0 202 }
nuclear@0 203
nuclear@0 204 static Vector2 pixel_to_uv(int x, int y)
nuclear@0 205 {
nuclear@0 206 float u = win_aspect * (2.0 * (float)x / (float)win_width - 1.0);
nuclear@0 207 float v = 1.0 - 2.0 * (float)y / (float)win_height;
nuclear@0 208 return Vector2(u, v);
nuclear@0 209 }
nuclear@0 210
nuclear@0 211 static int prev_x, prev_y;
nuclear@0 212 static int click_pos[8][2];
nuclear@0 213 static unsigned int bnstate;
nuclear@0 214
nuclear@0 215 #define BNBIT(x) (1 << (x))
nuclear@0 216
nuclear@0 217 void app_mouse_button(int bn, bool pressed, int x, int y)
nuclear@0 218 {
nuclear@0 219 prev_x = x;
nuclear@0 220 prev_y = y;
nuclear@0 221 if(pressed) {
nuclear@0 222 bnstate |= BNBIT(bn);
nuclear@0 223 } else {
nuclear@0 224 bnstate &= ~BNBIT(bn);
nuclear@0 225 }
nuclear@0 226
nuclear@0 227 if(pressed) {
nuclear@0 228 click_pos[bn][0] = x;
nuclear@0 229 click_pos[bn][1] = y;
nuclear@0 230 } else {
nuclear@0 231 int dx = x - click_pos[bn][0];
nuclear@0 232 int dy = y - click_pos[bn][1];
nuclear@0 233
nuclear@0 234 if(abs(dx) + abs(dy) < 3) {
nuclear@0 235 Vector2 uv = pixel_to_uv(x, y);
nuclear@0 236 on_click(bn, uv.x, uv.y);
nuclear@0 237 }
nuclear@0 238
nuclear@0 239 if(!(bnstate & BNBIT(2))) {
nuclear@0 240 delete weight_label;
nuclear@0 241 weight_label = 0;
nuclear@0 242 post_redisplay();
nuclear@0 243 }
nuclear@0 244 }
nuclear@0 245 }
nuclear@0 246
nuclear@0 247 static void hover(int x, int y)
nuclear@0 248 {
nuclear@1 249 float thres = 0.02;
nuclear@0 250
nuclear@0 251 Vector2 uv = pixel_to_uv(x, y);
nuclear@0 252 for(size_t i=0; i<curves.size(); i++) {
nuclear@0 253 int pidx = curves[i]->nearest_point(uv);
nuclear@0 254 if(pidx == -1) continue;
nuclear@0 255
nuclear@0 256 Vector2 cp = curves[i]->get_point(pidx);
nuclear@0 257 if((cp - uv).length_sq() < thres * thres) {
nuclear@0 258 sel_curve = curves[i];
nuclear@0 259 sel_pidx = pidx;
nuclear@0 260 return;
nuclear@0 261 }
nuclear@0 262 }
nuclear@0 263
nuclear@0 264 sel_curve = 0;
nuclear@0 265 sel_pidx = -1;
nuclear@0 266 }
nuclear@0 267
nuclear@0 268 void app_mouse_motion(int x, int y)
nuclear@0 269 {
nuclear@0 270 int dx = x - prev_x;
nuclear@0 271 int dy = y - prev_y;
nuclear@0 272 prev_x = x;
nuclear@0 273 prev_y = y;
nuclear@0 274
nuclear@0 275 if(!dx && !dy) return;
nuclear@0 276
nuclear@0 277 if(!new_curve && !bnstate) {
nuclear@0 278 hover(x, y);
nuclear@0 279 post_redisplay();
nuclear@0 280 }
nuclear@0 281
nuclear@0 282 if(sel_curve && sel_pidx != -1) {
nuclear@0 283 if(bnstate & BNBIT(0)) {
nuclear@0 284 float w = sel_curve->get_weight(sel_pidx);
nuclear@0 285 sel_curve->set_point(sel_pidx, pixel_to_uv(x, y), w);
nuclear@0 286 post_redisplay();
nuclear@0 287 }
nuclear@0 288
nuclear@0 289 if(bnstate & BNBIT(2)) {
nuclear@0 290 float w = sel_curve->get_weight(sel_pidx);
nuclear@1 291 w -= dy * 0.01;
nuclear@0 292 if(w < FLT_MIN) w = FLT_MIN;
nuclear@0 293 sel_curve->set_weight(sel_pidx, w);
nuclear@0 294
nuclear@0 295 if(!weight_label) {
nuclear@0 296 weight_label = new Label;
nuclear@0 297 }
nuclear@0 298 weight_label->set_position(pixel_to_uv(x, y));
nuclear@0 299 weight_label->set_textf("w=%g", w);
nuclear@0 300 post_redisplay();
nuclear@0 301 }
nuclear@0 302 }
nuclear@0 303 }
nuclear@0 304
nuclear@0 305 static void on_click(int bn, float u, float v)
nuclear@0 306 {
nuclear@0 307 switch(bn) {
nuclear@0 308 case 0:
nuclear@0 309 if(!new_curve) {
nuclear@0 310 new_curve = new Curve;
nuclear@0 311 }
nuclear@0 312 new_curve->add_point(Vector2(u, v));
nuclear@0 313 post_redisplay();
nuclear@0 314 break;
nuclear@0 315
nuclear@0 316 case 2:
nuclear@0 317 curves.push_back(new_curve);
nuclear@0 318 new_curve = 0;
nuclear@0 319 post_redisplay();
nuclear@0 320 break;
nuclear@0 321
nuclear@0 322 default:
nuclear@0 323 break;
nuclear@0 324 }
nuclear@0 325 }