# HG changeset patch # User John Tsiombikas # Date 1422110194 -7200 # Node ID e467998dcc64f0437a499bc8f77e10efbe3374b4 initial commit diff -r 000000000000 -r e467998dcc64 .hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Sat Jan 24 16:36:34 2015 +0200 @@ -0,0 +1,4 @@ +\.o$ +\.d$ +\.swp$ +^proj_plot$ diff -r 000000000000 -r e467998dcc64 Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Makefile Sat Jan 24 16:36:34 2015 +0200 @@ -0,0 +1,13 @@ +src = $(wildcard *.cc) +obj = $(src:.cc=.o) +bin = proj_plot + +CXXFLAGS = -pedantic -Wall -g +LDFLAGS = -lGL -lglut -lm -lvmath -ldrawtext + +$(bin): $(obj) + $(CXX) -o $@ $(obj) $(LDFLAGS) + +.PHONY: clean +clean: + rm -f $(obj) $(bin) diff -r 000000000000 -r e467998dcc64 README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README Sat Jan 24 16:36:34 2015 +0200 @@ -0,0 +1,3 @@ +dependencies: +- libvmath: http://code.google.com/p/libvmath/ +- libdrawtext: http://nuclear.mutantstargoat.com/sw/libdrawtext diff -r 000000000000 -r e467998dcc64 data/font.ttf Binary file data/font.ttf has changed diff -r 000000000000 -r e467998dcc64 main.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cc Sat Jan 24 16:36:34 2015 +0200 @@ -0,0 +1,219 @@ +#include +#include +#include +#include +#include +#include +#include + +bool init(); +void display(); +void draw_grid(); +void draw_label(const Vector2 &pos, const char *fmt, ...); +void reshape(int x, int y); +void keyb(unsigned char key, int x, int y); +void keyb_up(unsigned char key, int x, int y); +void mouse(int bn, int st, int x, int y); +void motion(int x, int y); +Vector2 screen_to_world(int x, int y); + +int win_xsz, win_ysz; +float aspect; + +Matrix4x4 proj; +Vector2 cur_point; +bool cur_point_valid; + +bool keystate[256]; +dtx_font *font; +float pan[2], zoom = 1.0; + +int main(int argc, char **argv) +{ + glutInit(&argc, argv); + glutInitWindowSize(1024, 768); + glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_MULTISAMPLE); + glutCreateWindow("Interactive projection diagram"); + + glutDisplayFunc(display); + glutReshapeFunc(reshape); + glutKeyboardFunc(keyb); + glutKeyboardUpFunc(keyb_up); + glutMouseFunc(mouse); + glutMotionFunc(motion); + + if(!init()) { + return 1; + } + + glutMainLoop(); + return 0; +} + +bool init() +{ + if(!(font = dtx_open_font("data/font.ttf", 16))) { + fprintf(stderr, "failed to open font\n"); + return false; + } + + glEnable(GL_MULTISAMPLE); + proj.set_perspective(DEG_TO_RAD(60), 1, 0.5, 500.0); + return true; +} + +void display() +{ + glClear(GL_COLOR_BUFFER_BIT); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(-pan[0], -pan[1], 0); + glScalef(zoom, zoom, zoom); + + draw_grid(); + + if(cur_point_valid) { + glPointSize(7.0); + glBegin(GL_POINTS); + glColor3f(0.2, 1, 0.2); + glVertex2f(cur_point.x, cur_point.y); + glEnd(); + + glColor3f(0.15, 0.5, 0.15); + draw_label(cur_point, "(%.2f, %.2f)", cur_point.x, cur_point.y); + } + + glutSwapBuffers(); + assert(glGetError() == GL_NO_ERROR); +} + +#define LINE(x0, y0, x1, y1) (glVertex2f(x0, y0), glVertex2f(x1, y1)) + +void draw_grid() +{ + float ymin = -1; + float ymax = 1; + float xmin = -1; + float xmax = 1; + float ticksz = 0.015; + + glBegin(GL_LINES); + glColor3f(1, 1, 1); + LINE(0, -1, 0, 1); + LINE(-1, 0, 1, 0); + + for(int i=1; i<11; i++) { + for(int j=0; j<2; j++) { + float x = (float)i / 10.0 * (j ? -1.0 : 1.0); + + glColor3f(0.15, 0.15, 0.15); + LINE(x, ymin, x, ymax); + LINE(xmin, x, xmax, x); + + glColor3f(0.4, 0.4, 0.4); + LINE(x, -ticksz, x, ticksz); + LINE(-ticksz, x, ticksz, x); + } + } + glEnd(); +} + +void draw_label(const Vector2 &pos, const char *fmt, ...) +{ + static char buf[512]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(buf, sizeof buf - 1, fmt, ap); + va_end(ap); + + glPushMatrix(); + glTranslatef(pos.x + 0.01, pos.y + 0.01, 0); + float s = 2.0 / (win_ysz * zoom); + glScalef(s, s, s); + + dtx_string(buf); + + glPopMatrix(); +} + +void reshape(int x, int y) +{ + win_xsz = x; + win_ysz = y; + aspect = (float)x / (float)y; + + glViewport(0, 0, x, y); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glScalef(1.0 / aspect, 1.0, 1.0); +} + +void keyb(unsigned char key, int x, int y) +{ + keystate[key] = 1; + + switch(key) { + case 27: + exit(0); + } +} + +void keyb_up(unsigned char key, int x, int y) +{ + keystate[key] = 0; +} + +bool bnstate[16]; +int prev_x, prev_y; + +void mouse(int bn, int st, int x, int y) +{ + bnstate[bn - GLUT_LEFT_BUTTON] = st == GLUT_DOWN; + prev_x = x; + prev_y = y; + + if(bn == GLUT_LEFT_BUTTON && st == GLUT_DOWN) { + cur_point = screen_to_world(x, y); + cur_point_valid = true; + glutPostRedisplay(); + } +} + +void motion(int x, int y) +{ + float dx = 2.0 * aspect * (x - prev_x) / (float)win_xsz; + float dy = 2.0 * (y - prev_y) / (float)win_ysz; + prev_x = x; + prev_y = y; + + if(bnstate[0]) { + cur_point = screen_to_world(x, y); + glutPostRedisplay(); + } + if(bnstate[1]) { + pan[0] -= dx; + pan[1] += dy; + + glutPostRedisplay(); + } + if(bnstate[2]) { + zoom += dy; + + if(zoom < 1e-4) zoom = 1e-4; + glutPostRedisplay(); + } +} + +Vector2 screen_to_world(int px, int py) +{ + float sx = 2.0 * aspect * (1.0 / zoom) / (float)win_xsz; + float sy = 2.0 * (1.0 / zoom) / (float)win_ysz; + + float x = (float)px * sx - (aspect + pan[0]) / zoom; + float y = (float)(win_ysz - py) * sy - (1.0 + pan[1]) / zoom; + + return Vector2(x, y); +}