#include #include #include #include #include #include #include #include #include #include #include #include "3darith.h" #include "mathutils.h" #define WINX 400 #define WINY 400 extern const char *__progname; #define UNUSED __attribute__((__unused__)) static Display *disp; static XVisualInfo *vi; static GLXContext ctx; static Screen *scr; static int scrwidth; static int scrheight; static int depth; static Window rootwin; static Colormap cmap; static Window win; static XColor bgcolour; static XColor fgcolour; static GC gc; static struct timeval nexttick; static unsigned int t; static XYZ pts[12]; static int lines[30][2]; static void open_display(void) { disp = XOpenDisplay(0); if (disp == 0) { fprintf(stderr,"%s: can't open display\n",__progname); exit(1); } } static void find_visual(void) { XVisualInfo template; int nvi; template.visualid = 35; vi = XGetVisualInfo(disp,VisualIDMask,&template,&nvi); if (nvi < 1) { fprintf(stderr,"%s: can't find visual\n",__progname); exit(1); } if (nvi > 1) { fprintf(stderr,"%s: found multiple visuals\n",__progname); exit(1); } } static void setup_X(void) { Pixmap p; scr = XScreenOfDisplay(disp,vi->screen); scrwidth = XWidthOfScreen(scr); scrheight = XHeightOfScreen(scr); depth = vi->depth; rootwin = XRootWindowOfScreen(scr); cmap = XCreateColormap(disp,rootwin,vi->visual,AllocNone); XParseColor(disp,cmap,"#646",&bgcolour); XAllocColor(disp,cmap,&bgcolour); XParseColor(disp,cmap,"#fff",&fgcolour); XAllocColor(disp,cmap,&fgcolour); p = XCreatePixmap(disp,rootwin,1,1,depth); gc = XCreateGC(disp,p,0,0); XFreePixmap(disp,p); } static void setup_context(void) { ctx = glXCreateContext(disp,vi,0,True); if (! ctx) { fprintf(stderr,"%s: can't create GL context\n",__progname); exit(1); } } static void create_window(void) { XSetWindowAttributes attr; unsigned long int attrmask; attrmask = 0; attr.background_pixel = bgcolour.pixel; attrmask |= CWBackPixel; attr.event_mask = StructureNotifyMask |VisibilityChangeMask | KeyPressMask | KeyReleaseMask; attrmask |= CWEventMask; attr.colormap = cmap; attrmask |= CWColormap; win = XCreateWindow(disp,rootwin,0,0,WINX*2,WINY,0,depth,InputOutput,vi->visual,attrmask,&attr); XMapRaised(disp,win); } static void setup_gl(void) { if (glXMakeCurrent(disp,(GLXDrawable)win,ctx) != True) { fprintf(stderr,"%s: can't make context current\n",__progname); exit(1); } glShadeModel(GL_SMOOTH); glClearColor(0,0,0,0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-1.5,1.5,-1.5,1.5,-100,100); glMatrixMode(GL_MODELVIEW); t = 0; } static void xyzvertex(XYZ p) { glVertex3f(p.x,p.y,p.z); } static void setup_model(void) { int i; double k; double z; double x; int lx; void addline(int x1, int x2) { lines[lx][0] = x1; lines[lx][1] = x2; lx ++; } /* * c = cos(36°) * s = sin(36°) * C = cos(72°) * S = sin(72°) * top-ring point, tp = (x,0,z) * distance tp to top, dt = sqrt(x^2+(z-1)^2) = sqrt(x*x+z*z-2z+1) * bottom-ring point, bp = (c*x,s*x,-z) * distance tp to bp, dp = sqrt((x-(c*x))^2+(s*x)^2+(2z)^2) * next top-ring point, rp = (C*x,S*x,z) * distance tp to rp, dr = sqrt((x-C*x))^2+(S*x)^2) * constraint: dt == dp == dr * constraint: x*x + z*z == 1 * let K = c + 3*C - 2 * we find z = (-4 ± sqrt(16+8K+4K^2)) / 2K * turns out we must pick + for the ±, else z>1 and x is imaginary */ k = cosdeg(36) + (3 * cosdeg(72)) - 2; z = (-4 + sqrt(16+(8*k)+(4*k*k))) / (2*k); x = sqrt(1-(z*z)); pts[0] = (XYZ){0,0,1}; pts[1] = (XYZ){0,0,-1}; pts[2] = (XYZ){x,0,z}; for (i=3;i<12;i++) { pts[i] = xyzrotate( (XYZ){pts[i-1].x,pts[i-1].y,-pts[i-1].z}, 36, (XYZ){0,0,1} ); } lx = 0; for (i=0;i<5;i++) { addline(0,2+i+i); addline(1,3+i+i); addline(2+i+i,2+(2*((i+1)%5))); addline(3+i+i,3+(2*((i+1)%5))); } for (i=3;i<12;i++) addline(i-1,i); addline(11,2); } static void drawstuff(void) { int i; glRotatef(t,1,1,1); glRotatef(t*.3,1,-1,0); glRotatef(t*.1,1,0,0); glBegin(GL_LINES); glColor3f(1,1,1); for (i=30-1;i>=0;i--) { xyzvertex(pts[lines[i][0]]); xyzvertex(pts[lines[i][1]]); } glEnd(); } static void render(void) { glViewport(0,0,WINX*2,WINY); glClear(GL_COLOR_BUFFER_BIT); glLoadIdentity(); glViewport(0,0,WINX,WINY); glRotatef(5,0,1,0); glPushMatrix(); drawstuff(); glPopMatrix(); glViewport(WINX,0,WINX,WINY); glRotatef(-5,0,1,0); glPushMatrix(); drawstuff(); glPopMatrix(); glXSwapBuffers(disp,win); glXWaitGL(); glXWaitX(); } static void setup_ticks(void) { gettimeofday(&nexttick,0); } static void motion(void) { } static void events(void) { } static void await(void) { struct timeval now; int ms; t ++; nexttick.tv_usec += 25000; if (nexttick.tv_usec >= 1000000) { nexttick.tv_usec -= 1000000; nexttick.tv_sec ++; } while (1) { gettimeofday(&now,0); if ( (now.tv_sec > nexttick.tv_sec) || ( (now.tv_sec == nexttick.tv_sec) && (now.tv_usec >= nexttick.tv_usec) ) ) return; ms = ((nexttick.tv_sec - now.tv_sec) * 1000) + 1 + (nexttick.tv_usec / 1000) - (now.tv_usec / 1000); if (ms < 1) ms = 1; poll(0,0,ms); } } static void tick(void) { motion(); render(); events(); await(); } int main(void); int main(void) { open_display(); find_visual(); setup_X(); setup_context(); create_window(); setup_gl(); setup_model(); setup_ticks(); while (1) tick(); }