rev |
line source |
nuclear@0
|
1 #include <stdio.h>
|
nuclear@0
|
2 #include <stdlib.h>
|
nuclear@0
|
3 #include <stdarg.h>
|
nuclear@0
|
4 #include <assert.h>
|
nuclear@0
|
5 #include <GL/glut.h>
|
nuclear@0
|
6 #include <vmath/vmath.h>
|
nuclear@0
|
7 #include <drawtext.h>
|
nuclear@0
|
8
|
nuclear@0
|
9 bool init();
|
nuclear@0
|
10 void display();
|
nuclear@0
|
11 void draw_grid();
|
nuclear@0
|
12 void draw_label(const Vector2 &pos, const char *fmt, ...);
|
nuclear@0
|
13 void reshape(int x, int y);
|
nuclear@0
|
14 void keyb(unsigned char key, int x, int y);
|
nuclear@0
|
15 void keyb_up(unsigned char key, int x, int y);
|
nuclear@0
|
16 void mouse(int bn, int st, int x, int y);
|
nuclear@0
|
17 void motion(int x, int y);
|
nuclear@0
|
18 Vector2 screen_to_world(int x, int y);
|
nuclear@0
|
19
|
nuclear@0
|
20 int win_xsz, win_ysz;
|
nuclear@0
|
21 float aspect;
|
nuclear@0
|
22
|
nuclear@0
|
23 Matrix4x4 proj;
|
nuclear@0
|
24 Vector2 cur_point;
|
nuclear@0
|
25 bool cur_point_valid;
|
nuclear@0
|
26
|
nuclear@0
|
27 bool keystate[256];
|
nuclear@0
|
28 dtx_font *font;
|
nuclear@0
|
29 float pan[2], zoom = 1.0;
|
nuclear@0
|
30
|
nuclear@0
|
31 int main(int argc, char **argv)
|
nuclear@0
|
32 {
|
nuclear@0
|
33 glutInit(&argc, argv);
|
nuclear@0
|
34 glutInitWindowSize(1024, 768);
|
nuclear@0
|
35 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_MULTISAMPLE);
|
nuclear@0
|
36 glutCreateWindow("Interactive projection diagram");
|
nuclear@0
|
37
|
nuclear@0
|
38 glutDisplayFunc(display);
|
nuclear@0
|
39 glutReshapeFunc(reshape);
|
nuclear@0
|
40 glutKeyboardFunc(keyb);
|
nuclear@0
|
41 glutKeyboardUpFunc(keyb_up);
|
nuclear@0
|
42 glutMouseFunc(mouse);
|
nuclear@0
|
43 glutMotionFunc(motion);
|
nuclear@0
|
44
|
nuclear@0
|
45 if(!init()) {
|
nuclear@0
|
46 return 1;
|
nuclear@0
|
47 }
|
nuclear@0
|
48
|
nuclear@0
|
49 glutMainLoop();
|
nuclear@0
|
50 return 0;
|
nuclear@0
|
51 }
|
nuclear@0
|
52
|
nuclear@0
|
53 bool init()
|
nuclear@0
|
54 {
|
nuclear@0
|
55 if(!(font = dtx_open_font("data/font.ttf", 16))) {
|
nuclear@0
|
56 fprintf(stderr, "failed to open font\n");
|
nuclear@0
|
57 return false;
|
nuclear@0
|
58 }
|
nuclear@0
|
59
|
nuclear@0
|
60 glEnable(GL_MULTISAMPLE);
|
nuclear@0
|
61 proj.set_perspective(DEG_TO_RAD(60), 1, 0.5, 500.0);
|
nuclear@0
|
62 return true;
|
nuclear@0
|
63 }
|
nuclear@0
|
64
|
nuclear@0
|
65 void display()
|
nuclear@0
|
66 {
|
nuclear@0
|
67 glClear(GL_COLOR_BUFFER_BIT);
|
nuclear@0
|
68
|
nuclear@0
|
69 glMatrixMode(GL_MODELVIEW);
|
nuclear@0
|
70 glLoadIdentity();
|
nuclear@0
|
71 glTranslatef(-pan[0], -pan[1], 0);
|
nuclear@0
|
72 glScalef(zoom, zoom, zoom);
|
nuclear@0
|
73
|
nuclear@0
|
74 draw_grid();
|
nuclear@0
|
75
|
nuclear@0
|
76 if(cur_point_valid) {
|
nuclear@0
|
77 glPointSize(7.0);
|
nuclear@0
|
78 glBegin(GL_POINTS);
|
nuclear@0
|
79 glColor3f(0.2, 1, 0.2);
|
nuclear@0
|
80 glVertex2f(cur_point.x, cur_point.y);
|
nuclear@0
|
81 glEnd();
|
nuclear@0
|
82
|
nuclear@0
|
83 glColor3f(0.15, 0.5, 0.15);
|
nuclear@0
|
84 draw_label(cur_point, "(%.2f, %.2f)", cur_point.x, cur_point.y);
|
nuclear@0
|
85 }
|
nuclear@0
|
86
|
nuclear@0
|
87 glutSwapBuffers();
|
nuclear@0
|
88 assert(glGetError() == GL_NO_ERROR);
|
nuclear@0
|
89 }
|
nuclear@0
|
90
|
nuclear@0
|
91 #define LINE(x0, y0, x1, y1) (glVertex2f(x0, y0), glVertex2f(x1, y1))
|
nuclear@0
|
92
|
nuclear@0
|
93 void draw_grid()
|
nuclear@0
|
94 {
|
nuclear@0
|
95 float ymin = -1;
|
nuclear@0
|
96 float ymax = 1;
|
nuclear@0
|
97 float xmin = -1;
|
nuclear@0
|
98 float xmax = 1;
|
nuclear@0
|
99 float ticksz = 0.015;
|
nuclear@0
|
100
|
nuclear@0
|
101 glBegin(GL_LINES);
|
nuclear@0
|
102 glColor3f(1, 1, 1);
|
nuclear@0
|
103 LINE(0, -1, 0, 1);
|
nuclear@0
|
104 LINE(-1, 0, 1, 0);
|
nuclear@0
|
105
|
nuclear@0
|
106 for(int i=1; i<11; i++) {
|
nuclear@0
|
107 for(int j=0; j<2; j++) {
|
nuclear@0
|
108 float x = (float)i / 10.0 * (j ? -1.0 : 1.0);
|
nuclear@0
|
109
|
nuclear@0
|
110 glColor3f(0.15, 0.15, 0.15);
|
nuclear@0
|
111 LINE(x, ymin, x, ymax);
|
nuclear@0
|
112 LINE(xmin, x, xmax, x);
|
nuclear@0
|
113
|
nuclear@0
|
114 glColor3f(0.4, 0.4, 0.4);
|
nuclear@0
|
115 LINE(x, -ticksz, x, ticksz);
|
nuclear@0
|
116 LINE(-ticksz, x, ticksz, x);
|
nuclear@0
|
117 }
|
nuclear@0
|
118 }
|
nuclear@0
|
119 glEnd();
|
nuclear@0
|
120 }
|
nuclear@0
|
121
|
nuclear@0
|
122 void draw_label(const Vector2 &pos, const char *fmt, ...)
|
nuclear@0
|
123 {
|
nuclear@0
|
124 static char buf[512];
|
nuclear@0
|
125 va_list ap;
|
nuclear@0
|
126
|
nuclear@0
|
127 va_start(ap, fmt);
|
nuclear@0
|
128 vsnprintf(buf, sizeof buf - 1, fmt, ap);
|
nuclear@0
|
129 va_end(ap);
|
nuclear@0
|
130
|
nuclear@0
|
131 glPushMatrix();
|
nuclear@0
|
132 glTranslatef(pos.x + 0.01, pos.y + 0.01, 0);
|
nuclear@0
|
133 float s = 2.0 / (win_ysz * zoom);
|
nuclear@0
|
134 glScalef(s, s, s);
|
nuclear@0
|
135
|
nuclear@0
|
136 dtx_string(buf);
|
nuclear@0
|
137
|
nuclear@0
|
138 glPopMatrix();
|
nuclear@0
|
139 }
|
nuclear@0
|
140
|
nuclear@0
|
141 void reshape(int x, int y)
|
nuclear@0
|
142 {
|
nuclear@0
|
143 win_xsz = x;
|
nuclear@0
|
144 win_ysz = y;
|
nuclear@0
|
145 aspect = (float)x / (float)y;
|
nuclear@0
|
146
|
nuclear@0
|
147 glViewport(0, 0, x, y);
|
nuclear@0
|
148
|
nuclear@0
|
149 glMatrixMode(GL_PROJECTION);
|
nuclear@0
|
150 glLoadIdentity();
|
nuclear@0
|
151 glScalef(1.0 / aspect, 1.0, 1.0);
|
nuclear@0
|
152 }
|
nuclear@0
|
153
|
nuclear@0
|
154 void keyb(unsigned char key, int x, int y)
|
nuclear@0
|
155 {
|
nuclear@0
|
156 keystate[key] = 1;
|
nuclear@0
|
157
|
nuclear@0
|
158 switch(key) {
|
nuclear@0
|
159 case 27:
|
nuclear@0
|
160 exit(0);
|
nuclear@0
|
161 }
|
nuclear@0
|
162 }
|
nuclear@0
|
163
|
nuclear@0
|
164 void keyb_up(unsigned char key, int x, int y)
|
nuclear@0
|
165 {
|
nuclear@0
|
166 keystate[key] = 0;
|
nuclear@0
|
167 }
|
nuclear@0
|
168
|
nuclear@0
|
169 bool bnstate[16];
|
nuclear@0
|
170 int prev_x, prev_y;
|
nuclear@0
|
171
|
nuclear@0
|
172 void mouse(int bn, int st, int x, int y)
|
nuclear@0
|
173 {
|
nuclear@0
|
174 bnstate[bn - GLUT_LEFT_BUTTON] = st == GLUT_DOWN;
|
nuclear@0
|
175 prev_x = x;
|
nuclear@0
|
176 prev_y = y;
|
nuclear@0
|
177
|
nuclear@0
|
178 if(bn == GLUT_LEFT_BUTTON && st == GLUT_DOWN) {
|
nuclear@0
|
179 cur_point = screen_to_world(x, y);
|
nuclear@0
|
180 cur_point_valid = true;
|
nuclear@0
|
181 glutPostRedisplay();
|
nuclear@0
|
182 }
|
nuclear@0
|
183 }
|
nuclear@0
|
184
|
nuclear@0
|
185 void motion(int x, int y)
|
nuclear@0
|
186 {
|
nuclear@0
|
187 float dx = 2.0 * aspect * (x - prev_x) / (float)win_xsz;
|
nuclear@0
|
188 float dy = 2.0 * (y - prev_y) / (float)win_ysz;
|
nuclear@0
|
189 prev_x = x;
|
nuclear@0
|
190 prev_y = y;
|
nuclear@0
|
191
|
nuclear@0
|
192 if(bnstate[0]) {
|
nuclear@0
|
193 cur_point = screen_to_world(x, y);
|
nuclear@0
|
194 glutPostRedisplay();
|
nuclear@0
|
195 }
|
nuclear@0
|
196 if(bnstate[1]) {
|
nuclear@0
|
197 pan[0] -= dx;
|
nuclear@0
|
198 pan[1] += dy;
|
nuclear@0
|
199
|
nuclear@0
|
200 glutPostRedisplay();
|
nuclear@0
|
201 }
|
nuclear@0
|
202 if(bnstate[2]) {
|
nuclear@0
|
203 zoom += dy;
|
nuclear@0
|
204
|
nuclear@0
|
205 if(zoom < 1e-4) zoom = 1e-4;
|
nuclear@0
|
206 glutPostRedisplay();
|
nuclear@0
|
207 }
|
nuclear@0
|
208 }
|
nuclear@0
|
209
|
nuclear@0
|
210 Vector2 screen_to_world(int px, int py)
|
nuclear@0
|
211 {
|
nuclear@0
|
212 float sx = 2.0 * aspect * (1.0 / zoom) / (float)win_xsz;
|
nuclear@0
|
213 float sy = 2.0 * (1.0 / zoom) / (float)win_ysz;
|
nuclear@0
|
214
|
nuclear@0
|
215 float x = (float)px * sx - (aspect + pan[0]) / zoom;
|
nuclear@0
|
216 float y = (float)(win_ysz - py) * sy - (1.0 + pan[1]) / zoom;
|
nuclear@0
|
217
|
nuclear@0
|
218 return Vector2(x, y);
|
nuclear@0
|
219 }
|