curvedraw
view 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 source
1 #include <stdlib.h>
2 #include <float.h>
3 #include <vector>
4 #include <algorithm>
5 #include "opengl.h"
6 #include "app.h"
7 #include "curve.h"
8 #include "widgets.h"
10 static void draw_grid(float sz, float sep, float alpha = 1.0f);
11 static void draw_curve(const Curve *curve);
12 static void on_click(int bn, float u, float v);
14 static int win_width, win_height;
15 static float win_aspect;
17 static float view_pan_x, view_pan_y;
18 static float view_scale = 1.0f;
20 static std::vector<Curve*> curves;
21 static Curve *sel_curve, *new_curve;
22 static int sel_pidx = -1;
24 static Label *weight_label;
27 bool app_init(int argc, char **argv)
28 {
29 glEnable(GL_MULTISAMPLE);
30 glEnable(GL_CULL_FACE);
31 return true;
32 }
34 void app_cleanup()
35 {
36 for(size_t i=0; i<curves.size(); i++) {
37 delete curves[i];
38 }
39 curves.clear();
40 }
42 void app_draw()
43 {
44 glClearColor(0.16, 0.16, 0.16, 1);
45 glClear(GL_COLOR_BUFFER_BIT);
47 glMatrixMode(GL_MODELVIEW);
48 glLoadIdentity();
49 glTranslatef(-view_pan_x, -view_pan_y, 0);
50 glScalef(view_scale, view_scale, view_scale);
52 draw_grid(std::max(win_aspect, 1.0f / win_aspect), 0.1);
54 for(size_t i=0; i<curves.size(); i++) {
55 draw_curve(curves[i]);
56 }
57 if(new_curve) {
58 // TODO special drawing with more feedback
59 draw_curve(new_curve);
60 }
61 if(weight_label) {
62 weight_label->draw();
63 }
64 }
66 static void draw_grid(float sz, float sep, float alpha)
67 {
68 float x = 0.0f;
70 glLineWidth(1.0);
71 glBegin(GL_LINES);
72 glColor4f(0.6, 0.3, 0.2, alpha);
73 glVertex2f(-sz, 0);
74 glVertex2f(sz, 0);
75 glColor4f(0.2, 0.3, 0.6, alpha);
76 glVertex2f(0, -sz);
77 glVertex2f(0, sz);
78 glColor4f(0.4, 0.4, 0.4, alpha);
79 while(x < sz) {
80 x += sep;
81 glVertex2f(-sz, x);
82 glVertex2f(sz, x);
83 glVertex2f(-sz, -x);
84 glVertex2f(sz, -x);
85 glVertex2f(x, -sz);
86 glVertex2f(x, sz);
87 glVertex2f(-x, -sz);
88 glVertex2f(-x, sz);
89 }
90 glEnd();
91 }
93 static void draw_curve(const Curve *curve)
94 {
95 int numpt = curve->get_point_count();
96 int segm = numpt * 16.0f;
98 glBegin(GL_LINE_STRIP);
99 if(curve == sel_curve) {
100 glLineWidth(3.0);
101 glColor3f(0.2, 0.8, 0.3);
102 } else {
103 glLineWidth(2.0);
104 glColor3f(0.8, 0.75, 0.3);
105 }
106 for(int i=0; i<segm; i++) {
107 float t = (float)i / (float)(segm - 1);
108 Vector2 v = curve->interpolate(t);
109 glVertex2f(v.x, v.y);
110 }
111 glEnd();
112 glLineWidth(1.0);
114 glPointSize(5.0);
115 glBegin(GL_POINTS);
116 glColor3f(1.0, 0.5, 0.2);
117 for(int i=0; i<numpt; i++) {
118 Vector2 pt = curve->get_point(i);
119 glVertex2f(pt.x, pt.y);
120 }
121 glEnd();
122 glPointSize(1.0);
123 }
125 void app_reshape(int x, int y)
126 {
127 win_width = x;
128 win_height = y;
129 win_aspect = (float)x / (float)y;
131 glViewport(0, 0, x, y);
132 glMatrixMode(GL_PROJECTION);
133 glLoadIdentity();
134 glOrtho(-win_aspect, win_aspect, -1, 1, -1, 1);
135 }
137 void app_keyboard(int key, bool pressed)
138 {
139 if(pressed) {
140 switch(key) {
141 case 27:
142 exit(0);
144 case 'l':
145 case 'L':
146 if(sel_curve) {
147 sel_curve->set_type(CURVE_LINEAR);
148 post_redisplay();
149 }
150 break;
152 case 'b':
153 case 'B':
154 if(sel_curve) {
155 sel_curve->set_type(CURVE_BSPLINE);
156 post_redisplay();
157 }
158 break;
160 case 'h':
161 case 'H':
162 if(sel_curve) {
163 sel_curve->set_type(CURVE_HERMITE);
164 post_redisplay();
165 }
166 break;
167 }
168 }
169 }
171 static Vector2 pixel_to_uv(int x, int y)
172 {
173 float u = win_aspect * (2.0 * (float)x / (float)win_width - 1.0);
174 float v = 1.0 - 2.0 * (float)y / (float)win_height;
175 return Vector2(u, v);
176 }
178 static int prev_x, prev_y;
179 static int click_pos[8][2];
180 static unsigned int bnstate;
182 #define BNBIT(x) (1 << (x))
184 void app_mouse_button(int bn, bool pressed, int x, int y)
185 {
186 prev_x = x;
187 prev_y = y;
188 if(pressed) {
189 bnstate |= BNBIT(bn);
190 } else {
191 bnstate &= ~BNBIT(bn);
192 }
194 if(pressed) {
195 click_pos[bn][0] = x;
196 click_pos[bn][1] = y;
197 } else {
198 int dx = x - click_pos[bn][0];
199 int dy = y - click_pos[bn][1];
201 if(abs(dx) + abs(dy) < 3) {
202 Vector2 uv = pixel_to_uv(x, y);
203 on_click(bn, uv.x, uv.y);
204 }
206 if(!(bnstate & BNBIT(2))) {
207 delete weight_label;
208 weight_label = 0;
209 post_redisplay();
210 }
211 }
212 }
214 static void hover(int x, int y)
215 {
216 float thres = pixel_to_uv(5, 0).x - pixel_to_uv(0, 0).x;
218 Vector2 uv = pixel_to_uv(x, y);
219 for(size_t i=0; i<curves.size(); i++) {
220 int pidx = curves[i]->nearest_point(uv);
221 if(pidx == -1) continue;
223 Vector2 cp = curves[i]->get_point(pidx);
224 if((cp - uv).length_sq() < thres * thres) {
225 sel_curve = curves[i];
226 sel_pidx = pidx;
227 return;
228 }
229 }
231 sel_curve = 0;
232 sel_pidx = -1;
233 }
235 void app_mouse_motion(int x, int y)
236 {
237 int dx = x - prev_x;
238 int dy = y - prev_y;
239 prev_x = x;
240 prev_y = y;
242 if(!dx && !dy) return;
244 if(!new_curve && !bnstate) {
245 hover(x, y);
246 post_redisplay();
247 }
249 if(sel_curve && sel_pidx != -1) {
250 if(bnstate & BNBIT(0)) {
251 float w = sel_curve->get_weight(sel_pidx);
252 sel_curve->set_point(sel_pidx, pixel_to_uv(x, y), w);
253 post_redisplay();
254 }
256 if(bnstate & BNBIT(2)) {
257 float w = sel_curve->get_weight(sel_pidx);
258 w -= dy * 0.1;
259 if(w < FLT_MIN) w = FLT_MIN;
260 sel_curve->set_weight(sel_pidx, w);
262 if(!weight_label) {
263 weight_label = new Label;
264 }
265 weight_label->set_position(pixel_to_uv(x, y));
266 weight_label->set_textf("w=%g", w);
267 post_redisplay();
268 }
269 }
270 }
272 static void on_click(int bn, float u, float v)
273 {
274 switch(bn) {
275 case 0:
276 if(!new_curve) {
277 new_curve = new Curve;
278 }
279 new_curve->add_point(Vector2(u, v));
280 post_redisplay();
281 break;
283 case 2:
284 curves.push_back(new_curve);
285 new_curve = 0;
286 post_redisplay();
287 break;
289 default:
290 break;
291 }
292 }