nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: nuclear@0: bool init(); nuclear@0: void display(); nuclear@0: void draw_grid(); nuclear@0: void draw_label(const Vector2 &pos, const char *fmt, ...); nuclear@0: void reshape(int x, int y); nuclear@0: void keyb(unsigned char key, int x, int y); nuclear@0: void keyb_up(unsigned char key, int x, int y); nuclear@0: void mouse(int bn, int st, int x, int y); nuclear@0: void motion(int x, int y); nuclear@0: Vector2 screen_to_world(int x, int y); nuclear@0: nuclear@0: int win_xsz, win_ysz; nuclear@0: float aspect; nuclear@0: nuclear@0: Matrix4x4 proj; nuclear@0: Vector2 cur_point; nuclear@0: bool cur_point_valid; nuclear@0: nuclear@0: bool keystate[256]; nuclear@0: dtx_font *font; nuclear@0: float pan[2], zoom = 1.0; nuclear@0: nuclear@0: int main(int argc, char **argv) nuclear@0: { nuclear@0: glutInit(&argc, argv); nuclear@0: glutInitWindowSize(1024, 768); nuclear@0: glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_MULTISAMPLE); nuclear@0: glutCreateWindow("Interactive projection diagram"); nuclear@0: nuclear@0: glutDisplayFunc(display); nuclear@0: glutReshapeFunc(reshape); nuclear@0: glutKeyboardFunc(keyb); nuclear@0: glutKeyboardUpFunc(keyb_up); nuclear@0: glutMouseFunc(mouse); nuclear@0: glutMotionFunc(motion); nuclear@0: nuclear@0: if(!init()) { nuclear@0: return 1; nuclear@0: } nuclear@0: nuclear@0: glutMainLoop(); nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: bool init() nuclear@0: { nuclear@0: if(!(font = dtx_open_font("data/font.ttf", 16))) { nuclear@0: fprintf(stderr, "failed to open font\n"); nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: glEnable(GL_MULTISAMPLE); nuclear@0: proj.set_perspective(DEG_TO_RAD(60), 1, 0.5, 500.0); nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: void display() nuclear@0: { nuclear@0: glClear(GL_COLOR_BUFFER_BIT); nuclear@0: nuclear@0: glMatrixMode(GL_MODELVIEW); nuclear@0: glLoadIdentity(); nuclear@0: glTranslatef(-pan[0], -pan[1], 0); nuclear@0: glScalef(zoom, zoom, zoom); nuclear@0: nuclear@0: draw_grid(); nuclear@0: nuclear@0: if(cur_point_valid) { nuclear@0: glPointSize(7.0); nuclear@0: glBegin(GL_POINTS); nuclear@0: glColor3f(0.2, 1, 0.2); nuclear@0: glVertex2f(cur_point.x, cur_point.y); nuclear@0: glEnd(); nuclear@0: nuclear@0: glColor3f(0.15, 0.5, 0.15); nuclear@0: draw_label(cur_point, "(%.2f, %.2f)", cur_point.x, cur_point.y); nuclear@0: } nuclear@0: nuclear@0: glutSwapBuffers(); nuclear@0: assert(glGetError() == GL_NO_ERROR); nuclear@0: } nuclear@0: nuclear@0: #define LINE(x0, y0, x1, y1) (glVertex2f(x0, y0), glVertex2f(x1, y1)) nuclear@0: nuclear@0: void draw_grid() nuclear@0: { nuclear@0: float ymin = -1; nuclear@0: float ymax = 1; nuclear@0: float xmin = -1; nuclear@0: float xmax = 1; nuclear@0: float ticksz = 0.015; nuclear@0: nuclear@0: glBegin(GL_LINES); nuclear@0: glColor3f(1, 1, 1); nuclear@0: LINE(0, -1, 0, 1); nuclear@0: LINE(-1, 0, 1, 0); nuclear@0: nuclear@0: for(int i=1; i<11; i++) { nuclear@0: for(int j=0; j<2; j++) { nuclear@0: float x = (float)i / 10.0 * (j ? -1.0 : 1.0); nuclear@0: nuclear@0: glColor3f(0.15, 0.15, 0.15); nuclear@0: LINE(x, ymin, x, ymax); nuclear@0: LINE(xmin, x, xmax, x); nuclear@0: nuclear@0: glColor3f(0.4, 0.4, 0.4); nuclear@0: LINE(x, -ticksz, x, ticksz); nuclear@0: LINE(-ticksz, x, ticksz, x); nuclear@0: } nuclear@0: } nuclear@0: glEnd(); nuclear@0: } nuclear@0: nuclear@0: void draw_label(const Vector2 &pos, const char *fmt, ...) nuclear@0: { nuclear@0: static char buf[512]; nuclear@0: va_list ap; nuclear@0: nuclear@0: va_start(ap, fmt); nuclear@0: vsnprintf(buf, sizeof buf - 1, fmt, ap); nuclear@0: va_end(ap); nuclear@0: nuclear@0: glPushMatrix(); nuclear@0: glTranslatef(pos.x + 0.01, pos.y + 0.01, 0); nuclear@0: float s = 2.0 / (win_ysz * zoom); nuclear@0: glScalef(s, s, s); nuclear@0: nuclear@0: dtx_string(buf); nuclear@0: nuclear@0: glPopMatrix(); nuclear@0: } nuclear@0: nuclear@0: void reshape(int x, int y) nuclear@0: { nuclear@0: win_xsz = x; nuclear@0: win_ysz = y; nuclear@0: aspect = (float)x / (float)y; nuclear@0: nuclear@0: glViewport(0, 0, x, y); nuclear@0: nuclear@0: glMatrixMode(GL_PROJECTION); nuclear@0: glLoadIdentity(); nuclear@0: glScalef(1.0 / aspect, 1.0, 1.0); nuclear@0: } nuclear@0: nuclear@0: void keyb(unsigned char key, int x, int y) nuclear@0: { nuclear@0: keystate[key] = 1; nuclear@0: nuclear@0: switch(key) { nuclear@0: case 27: nuclear@0: exit(0); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void keyb_up(unsigned char key, int x, int y) nuclear@0: { nuclear@0: keystate[key] = 0; nuclear@0: } nuclear@0: nuclear@0: bool bnstate[16]; nuclear@0: int prev_x, prev_y; nuclear@0: nuclear@0: void mouse(int bn, int st, int x, int y) nuclear@0: { nuclear@0: bnstate[bn - GLUT_LEFT_BUTTON] = st == GLUT_DOWN; nuclear@0: prev_x = x; nuclear@0: prev_y = y; nuclear@0: nuclear@0: if(bn == GLUT_LEFT_BUTTON && st == GLUT_DOWN) { nuclear@0: cur_point = screen_to_world(x, y); nuclear@0: cur_point_valid = true; nuclear@0: glutPostRedisplay(); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void motion(int x, int y) nuclear@0: { nuclear@0: float dx = 2.0 * aspect * (x - prev_x) / (float)win_xsz; nuclear@0: float dy = 2.0 * (y - prev_y) / (float)win_ysz; nuclear@0: prev_x = x; nuclear@0: prev_y = y; nuclear@0: nuclear@0: if(bnstate[0]) { nuclear@0: cur_point = screen_to_world(x, y); nuclear@0: glutPostRedisplay(); nuclear@0: } nuclear@0: if(bnstate[1]) { nuclear@0: pan[0] -= dx; nuclear@0: pan[1] += dy; nuclear@0: nuclear@0: glutPostRedisplay(); nuclear@0: } nuclear@0: if(bnstate[2]) { nuclear@0: zoom += dy; nuclear@0: nuclear@0: if(zoom < 1e-4) zoom = 1e-4; nuclear@0: glutPostRedisplay(); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: Vector2 screen_to_world(int px, int py) nuclear@0: { nuclear@0: float sx = 2.0 * aspect * (1.0 / zoom) / (float)win_xsz; nuclear@0: float sy = 2.0 * (1.0 / zoom) / (float)win_ysz; nuclear@0: nuclear@0: float x = (float)px * sx - (aspect + pan[0]) / zoom; nuclear@0: float y = (float)(win_ysz - py) * sy - (1.0 + pan[1]) / zoom; nuclear@0: nuclear@0: return Vector2(x, y); nuclear@0: }