curvedraw

annotate 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
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@0 10 static void draw_grid(float sz, float sep, float alpha = 1.0f);
nuclear@0 11 static void draw_curve(const Curve *curve);
nuclear@0 12 static void on_click(int bn, float u, float v);
nuclear@0 13
nuclear@0 14 static int win_width, win_height;
nuclear@0 15 static float win_aspect;
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@0 44 glClearColor(0.16, 0.16, 0.16, 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@0 78 glColor4f(0.4, 0.4, 0.4, 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@0 98 glBegin(GL_LINE_STRIP);
nuclear@0 99 if(curve == sel_curve) {
nuclear@0 100 glLineWidth(3.0);
nuclear@0 101 glColor3f(0.2, 0.8, 0.3);
nuclear@0 102 } else {
nuclear@0 103 glLineWidth(2.0);
nuclear@0 104 glColor3f(0.8, 0.75, 0.3);
nuclear@0 105 }
nuclear@0 106 for(int i=0; i<segm; i++) {
nuclear@0 107 float t = (float)i / (float)(segm - 1);
nuclear@0 108 Vector2 v = curve->interpolate(t);
nuclear@0 109 glVertex2f(v.x, v.y);
nuclear@0 110 }
nuclear@0 111 glEnd();
nuclear@0 112 glLineWidth(1.0);
nuclear@0 113
nuclear@0 114 glPointSize(5.0);
nuclear@0 115 glBegin(GL_POINTS);
nuclear@0 116 glColor3f(1.0, 0.5, 0.2);
nuclear@0 117 for(int i=0; i<numpt; i++) {
nuclear@0 118 Vector2 pt = curve->get_point(i);
nuclear@0 119 glVertex2f(pt.x, pt.y);
nuclear@0 120 }
nuclear@0 121 glEnd();
nuclear@0 122 glPointSize(1.0);
nuclear@0 123 }
nuclear@0 124
nuclear@0 125 void app_reshape(int x, int y)
nuclear@0 126 {
nuclear@0 127 win_width = x;
nuclear@0 128 win_height = y;
nuclear@0 129 win_aspect = (float)x / (float)y;
nuclear@0 130
nuclear@0 131 glViewport(0, 0, x, y);
nuclear@0 132 glMatrixMode(GL_PROJECTION);
nuclear@0 133 glLoadIdentity();
nuclear@0 134 glOrtho(-win_aspect, win_aspect, -1, 1, -1, 1);
nuclear@0 135 }
nuclear@0 136
nuclear@0 137 void app_keyboard(int key, bool pressed)
nuclear@0 138 {
nuclear@0 139 if(pressed) {
nuclear@0 140 switch(key) {
nuclear@0 141 case 27:
nuclear@0 142 exit(0);
nuclear@0 143
nuclear@0 144 case 'l':
nuclear@0 145 case 'L':
nuclear@0 146 if(sel_curve) {
nuclear@0 147 sel_curve->set_type(CURVE_LINEAR);
nuclear@0 148 post_redisplay();
nuclear@0 149 }
nuclear@0 150 break;
nuclear@0 151
nuclear@0 152 case 'b':
nuclear@0 153 case 'B':
nuclear@0 154 if(sel_curve) {
nuclear@0 155 sel_curve->set_type(CURVE_BSPLINE);
nuclear@0 156 post_redisplay();
nuclear@0 157 }
nuclear@0 158 break;
nuclear@0 159
nuclear@0 160 case 'h':
nuclear@0 161 case 'H':
nuclear@0 162 if(sel_curve) {
nuclear@0 163 sel_curve->set_type(CURVE_HERMITE);
nuclear@0 164 post_redisplay();
nuclear@0 165 }
nuclear@0 166 break;
nuclear@0 167 }
nuclear@0 168 }
nuclear@0 169 }
nuclear@0 170
nuclear@0 171 static Vector2 pixel_to_uv(int x, int y)
nuclear@0 172 {
nuclear@0 173 float u = win_aspect * (2.0 * (float)x / (float)win_width - 1.0);
nuclear@0 174 float v = 1.0 - 2.0 * (float)y / (float)win_height;
nuclear@0 175 return Vector2(u, v);
nuclear@0 176 }
nuclear@0 177
nuclear@0 178 static int prev_x, prev_y;
nuclear@0 179 static int click_pos[8][2];
nuclear@0 180 static unsigned int bnstate;
nuclear@0 181
nuclear@0 182 #define BNBIT(x) (1 << (x))
nuclear@0 183
nuclear@0 184 void app_mouse_button(int bn, bool pressed, int x, int y)
nuclear@0 185 {
nuclear@0 186 prev_x = x;
nuclear@0 187 prev_y = y;
nuclear@0 188 if(pressed) {
nuclear@0 189 bnstate |= BNBIT(bn);
nuclear@0 190 } else {
nuclear@0 191 bnstate &= ~BNBIT(bn);
nuclear@0 192 }
nuclear@0 193
nuclear@0 194 if(pressed) {
nuclear@0 195 click_pos[bn][0] = x;
nuclear@0 196 click_pos[bn][1] = y;
nuclear@0 197 } else {
nuclear@0 198 int dx = x - click_pos[bn][0];
nuclear@0 199 int dy = y - click_pos[bn][1];
nuclear@0 200
nuclear@0 201 if(abs(dx) + abs(dy) < 3) {
nuclear@0 202 Vector2 uv = pixel_to_uv(x, y);
nuclear@0 203 on_click(bn, uv.x, uv.y);
nuclear@0 204 }
nuclear@0 205
nuclear@0 206 if(!(bnstate & BNBIT(2))) {
nuclear@0 207 delete weight_label;
nuclear@0 208 weight_label = 0;
nuclear@0 209 post_redisplay();
nuclear@0 210 }
nuclear@0 211 }
nuclear@0 212 }
nuclear@0 213
nuclear@0 214 static void hover(int x, int y)
nuclear@0 215 {
nuclear@0 216 float thres = pixel_to_uv(5, 0).x - pixel_to_uv(0, 0).x;
nuclear@0 217
nuclear@0 218 Vector2 uv = pixel_to_uv(x, y);
nuclear@0 219 for(size_t i=0; i<curves.size(); i++) {
nuclear@0 220 int pidx = curves[i]->nearest_point(uv);
nuclear@0 221 if(pidx == -1) continue;
nuclear@0 222
nuclear@0 223 Vector2 cp = curves[i]->get_point(pidx);
nuclear@0 224 if((cp - uv).length_sq() < thres * thres) {
nuclear@0 225 sel_curve = curves[i];
nuclear@0 226 sel_pidx = pidx;
nuclear@0 227 return;
nuclear@0 228 }
nuclear@0 229 }
nuclear@0 230
nuclear@0 231 sel_curve = 0;
nuclear@0 232 sel_pidx = -1;
nuclear@0 233 }
nuclear@0 234
nuclear@0 235 void app_mouse_motion(int x, int y)
nuclear@0 236 {
nuclear@0 237 int dx = x - prev_x;
nuclear@0 238 int dy = y - prev_y;
nuclear@0 239 prev_x = x;
nuclear@0 240 prev_y = y;
nuclear@0 241
nuclear@0 242 if(!dx && !dy) return;
nuclear@0 243
nuclear@0 244 if(!new_curve && !bnstate) {
nuclear@0 245 hover(x, y);
nuclear@0 246 post_redisplay();
nuclear@0 247 }
nuclear@0 248
nuclear@0 249 if(sel_curve && sel_pidx != -1) {
nuclear@0 250 if(bnstate & BNBIT(0)) {
nuclear@0 251 float w = sel_curve->get_weight(sel_pidx);
nuclear@0 252 sel_curve->set_point(sel_pidx, pixel_to_uv(x, y), w);
nuclear@0 253 post_redisplay();
nuclear@0 254 }
nuclear@0 255
nuclear@0 256 if(bnstate & BNBIT(2)) {
nuclear@0 257 float w = sel_curve->get_weight(sel_pidx);
nuclear@0 258 w -= dy * 0.1;
nuclear@0 259 if(w < FLT_MIN) w = FLT_MIN;
nuclear@0 260 sel_curve->set_weight(sel_pidx, w);
nuclear@0 261
nuclear@0 262 if(!weight_label) {
nuclear@0 263 weight_label = new Label;
nuclear@0 264 }
nuclear@0 265 weight_label->set_position(pixel_to_uv(x, y));
nuclear@0 266 weight_label->set_textf("w=%g", w);
nuclear@0 267 post_redisplay();
nuclear@0 268 }
nuclear@0 269 }
nuclear@0 270 }
nuclear@0 271
nuclear@0 272 static void on_click(int bn, float u, float v)
nuclear@0 273 {
nuclear@0 274 switch(bn) {
nuclear@0 275 case 0:
nuclear@0 276 if(!new_curve) {
nuclear@0 277 new_curve = new Curve;
nuclear@0 278 }
nuclear@0 279 new_curve->add_point(Vector2(u, v));
nuclear@0 280 post_redisplay();
nuclear@0 281 break;
nuclear@0 282
nuclear@0 283 case 2:
nuclear@0 284 curves.push_back(new_curve);
nuclear@0 285 new_curve = 0;
nuclear@0 286 post_redisplay();
nuclear@0 287 break;
nuclear@0 288
nuclear@0 289 default:
nuclear@0 290 break;
nuclear@0 291 }
nuclear@0 292 }