#include #include #include #include "pp3d.h" /*---------------------------------------------------------------------- History: pp2d Simple program for animating 3d particle motion. Copyright 2000- Matthew W Choptuik, UBC This program uses OpenGL and the GLUT toolkit. If linked with the MesaGL libraries, it should display on any X client. Usage: See 'help()' function below or type 'pp3d -h' ----------------------------------------------------------------------*/ /*---------------------------------------------------------------------- G L O B A L V A R I A B L E S Ltrace: Enables debugging output if non-zero Win_w: Current graphics window width (pixels) Win_h: Current graphics window height (pixels) Win_Xsize Requested graphics window width (pixels) Win_Ysize Requested graphics window height (pixels) Init: Flag specifying whether input stream has been initialized Done: Flag specifying whether input stream has been exhausted Xmin: Physical x coordinate of lower left corner of window Ymin: Physical y coordinate of lower left corner of window Xmax: Physical x coordinate of upper right corner of window Ymax: Physical y coordinate of upper right corner of window BaseSize: Base size of particles (pixels) MinSize: Minimum size of particles (pixels) MaxSize: Maximum size of particles (pixels) Np: Number of particles Time: Current display time Size: : Vector of particle sizes Coords: Vector of particle coordinates Nt: Number of time steps processed so far Pause: Pauses/Continues display. Zoom: Controls amount of zoom-in / zoom-out. DSize: Controls amount of rescale in BaseSize. Trans: Controls amount of translation. Win_Title: Buffer for window title Dbuff: Non-zero for double buffering AnitA: Non-zero for antialiasing R, G, B: RGB color vectors for markers; Ncol: # of colors to use (1 for monochrome) Dummy: "Don't care" double ----------------------------------------------------------------------*/ /* Defines frustum for projection ... */ double ProjectionBbox[] = { -1.0, 1.0, -1.0, 1.0, 5.0, 15.0 }; /* For tumbling rotations ... */ int Tumble = 0; double Xrot = 0.0; double Xstep = 0.1; double Yrot = 0.0; double Ystep = 0.2; double Zrot = 0.0; double Zstep = 0.3; double TumbleFactor = 1.1; /* For Zoom-in/Zoom-out ... */ double ZoomFactor = 1.1; double Zoom = 1.0; int DrawOrigin = 1; int Ltrace = 0; int Win_w, Win_h; double Win_Xsize = 500; double Win_Ysize = 500; int Init = 0, Done = 0; double Xmin = -2.0, Ymin = -2.0, Xmax = 2.0, Ymax = 2.0; double BaseSize = 5.0; double MinSize = 3.0; double MaxSize = 20.0; int Np = 0; double Time; double *Size = (double *) NULL; double *Coords = (double *) NULL; int Nt = 0; int Pause = 0; double DSize = 1.2; double Trans = 0.05; char Win_Title[1024]; int Dbuff = 1; int AntiA = 1; double R[] = { 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0 }, G[] = { 1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0 }, B[] = { 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0 }; int Ncol = sizeof(R) / sizeof(double); double Dummy; /*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/ /* Returns val clamped to min ... max */ /*--------------------------------------------------------------------*/ double clamped(double val,double min,double max) { if( val < min ) { return min; } else if( val > max ) { return max; } else { return val; } } /*--------------------------------------------------------------------*/ /* Dumps help to standard output */ /*--------------------------------------------------------------------*/ void help(void) { printf("usage: pp3d [-hm]\n\n"); printf("Displays animations of three dimensional particle motion\n\n"); printf(" Flags: -h help\n"); printf(" -m monochrome\n\n"); printf("-----------------------------------------------------------------------------\n"); printf("pp3d expects the following formatted input on standard input:\n"); printf("-----------------------------------------------------------------------------\n\n"); printf(" ! Number of particles\n"); printf(" ! Relative display size of particle 1\n"); printf(" ! Relative display size of particle 2\n"); printf(" .\n"); printf(" .\n"); printf(" .\n"); printf(" ! Relative display size of particle np\n"); printf(" ! First display time\n"); printf(" ! Coordinates of particle 1 at t_1\n"); printf(" ! Coordinates of particle 2 at t_1\n"); printf(" .\n"); printf(" .\n"); printf(" .\n"); printf(" ! Coordinates of particle np at t_1\n"); printf(" ! Second display time\n"); printf(" ! Coordinates of particle 1 at t_2\n"); printf(" ! Coordinates of particle 2 at t_2\n"); printf(" .\n"); printf(" .\n"); printf(" .\n"); printf(" ! Coordinates of particle np at t_2\n"); printf(" ! Third display time\n"); printf(" .\n"); printf(" .\n"); printf(" .\n"); printf("\n"); printf(" All values are expected to be real numbers except for which is\n"); printf(" an integer.\n"); printf("\n"); printf("-----------------------------------------------------------------------------\n"); printf("pp3d keyboard assigments (commands are case-insensitive):\n"); printf("-----------------------------------------------------------------------------\n\n"); printf(" ESC: Exit program\n"); printf(" p: Pause/continue animation\n\n"); printf(" z: Zoom-in on solution domain\n"); printf(" x: Zoom-out on solution domain\n\n"); printf(" a: Enlarge marker size\n"); printf(" s: Reduce marker size\n\n"); printf(" q: Enlarge window size\n"); printf(" w: Reduce window size\n\n"); printf(" t: Start/stop tumbling\n\n"); printf(" y: Increase tumbling rate\n\n"); printf(" r: Decrease tumbling rate\n\n"); printf(" o: Toggle visibility of origin\n"); printf("\n"); printf("-----------------------------------------------------------------------------\n"); printf("Miscellaneous\n"); printf("-----------------------------------------------------------------------------\n\n"); printf("The initial (default) viewing region is:\n"); printf(" %g <= x <= %g\n",ProjectionBbox[0],ProjectionBbox[1]); printf(" %g <= y <= %g\n",ProjectionBbox[2],ProjectionBbox[3]); printf(" %g <= z <= %g\n",-0.5*(ProjectionBbox[5]-ProjectionBbox[4]), 0.5*(ProjectionBbox[5]-ProjectionBbox[4])); printf("\n"); printf("The base marker size is %g pixels\n",BaseSize); printf("Markers can range from %g to %g pixels in size\n",MinSize,MaxSize); exit(1); } /*--------------------------------------------------------------------*/ /* Dumps error message to stderr and exits */ /*--------------------------------------------------------------------*/ void badstream_exit(char *s) { fprintf(stderr,"Error reading %s\n",s); exit(0); } /*--------------------------------------------------------------------*/ /* Processes input */ /*--------------------------------------------------------------------*/ void getinput(void) { int i; if( Done || Pause ) { glutPostRedisplay(); return; } if( Init == 0 ) { glutPostRedisplay(); Init = 1; return; } if( Init == 1 ) { /*------------------------------------------------------------------- Initialization: Read number of particles and particle sizes, allocate storage for particle coordinates and sizes. -------------------------------------------------------------------*/ if( scanf("%d",&Np) == 1 ) { if( Ltrace ) { fprintf(stderr,"getinput: %d particles\n",Np); } Size = (double *) malloc(Np * sizeof(double)); Coords = (double *) malloc(3 * Np * sizeof(double)); for( i = 0; i < Np; i++ ) { if( scanf("%lf",Size + i) == 1 ) { if( Ltrace ) { fprintf(stderr,"getinput: Particle %d Size %g\n", i+1,Size[i]); } } else { badstream_exit("particle sizes"); } } } else { badstream_exit("number of particles"); } Init = 2; } /*------------------------------------------------------------------- Read new time, particle positions and post redisplay request. -------------------------------------------------------------------*/ if( scanf("%lf",&Time) == 1 ) { if( Ltrace ) fprintf(stderr,"getinput: Time %g\n",Time); for( i = 0; i < Np; i++ ) { if( scanf("%lf %lf %lf",Coords + 3*i, Coords + 3*i + 1,Coords + 3*i + 2) == 3 ) { if( Ltrace ) { fprintf(stderr,"getinput: Particle %d Pos (%g,%g,%g)\n", i,Coords[3*i],Coords[3*i+1],Coords[3*i+2]); } } } Nt++; if( Nt == 1 ) { Pause = 1; reshape(Win_w,Win_h); } } else { Done = 1; glutSetWindowTitle("Esc exits"); } glutPostRedisplay(); } /*--------------------------------------------------------------------*/ /* 'idle' function. GLUT driver calls this whenever there's nothing */ /* else to do */ /*--------------------------------------------------------------------*/ void idle(void) { getinput(); if( Tumble ) tumble(); } void tumble(void) { if( Ltrace ) { fprintf(stderr,"tumble: Rotation angles: %g %g %g\n",Xrot,Yrot,Zrot); } Xrot += Xstep; Yrot += Ystep; Zrot += Zstep; if (Xrot>=360.0) { Xrot = Xrot - 360; } else if (Yrot>=360.0) { Yrot = Yrot - 360; } else if (Zrot>=360.0) { Zrot = Zrot - 360; } } /*--------------------------------------------------------------------*/ /* Handles keyboard events. */ /*--------------------------------------------------------------------*/ void keyboard(unsigned char key,int x, int y) { double ocx, ocy, odx, ody; switch( key ) { case 'a': case 'A': /* A-key: Increase particle sizes ... */ BaseSize *= DSize; glutPostRedisplay(); break; case 's': case 'S': /* S-key: Decrease particle sizes ... */ BaseSize /= DSize; glutPostRedisplay(); break; case 'x': case 'X': /* X-key: Zoom-out ... */ Zoom /= ZoomFactor; glutPostRedisplay(); break; case 'z': case 'Z': /* Z-key: Zoom-in ... */ Zoom *= ZoomFactor; glutPostRedisplay(); break; case 'q': case 'Q': /* W-key: Make window larger ... */ Win_Xsize *= Zoom; Win_Ysize *= Zoom; glutReshapeWindow(Win_Xsize, Win_Ysize); glutPostRedisplay(); break; case 'w': case 'W': /* W-key: Make window smaller ... */ Win_Xsize /= Zoom; Win_Ysize /= Zoom; glutReshapeWindow(Win_Xsize, Win_Ysize); glutPostRedisplay(); break; case 'P': case 'p': /* P-key: Pause/Continue ... */ Pause = !Pause; glutPostRedisplay(); reshape(Win_w,Win_h); break; case 'O': case 'o': /* O-key: Toggle visibility of origin ... */ DrawOrigin = !DrawOrigin; glutPostRedisplay(); reshape(Win_w,Win_h); break; case 'T': case 't': /* T-key: Toggle tumbling ... */ Tumble = !Tumble; glutPostRedisplay(); reshape(Win_w,Win_h); break; case 'R': case 'r': /* R-key: Decrease tumbling rate ... */ Xstep /= TumbleFactor; Ystep /= TumbleFactor; Zstep /= TumbleFactor; glutPostRedisplay(); break; case 'Y': case 'y': /* Y-key: Increase tumbling rate ... */ Xstep *= TumbleFactor; Ystep *= TumbleFactor; Zstep *= TumbleFactor; glutPostRedisplay(); break; case 27: /* Escape Key: Exit program ... */ exit(0); default: break; } } /*--------------------------------------------------------------------*/ /* Handles special keys. */ /*--------------------------------------------------------------------*/ void special(int key, int x, int y ) { int odx, ody; switch( key ) { case GLUT_KEY_LEFT: break; case GLUT_KEY_RIGHT: break; case GLUT_KEY_UP: break; case GLUT_KEY_DOWN: break; default: break; } } /*--------------------------------------------------------------------*/ /* Displays particles ... most of the OpenGL graphics calls are */ /* in this routine. */ /*--------------------------------------------------------------------*/ void display(void) { int i; if( Ltrace ) fprintf(stderr,"display: In routine\n"); glMatrixMode(GL_MODELVIEW); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glTranslatef( 0.0, 0.0, -0.5 * (ProjectionBbox[4] + ProjectionBbox[5])); if( Ltrace ) { fprintf(stderr,"display: Rotation angles: %g %g %g\n",Xrot,Yrot,Zrot); } glRotated( Xrot, 1.0, 0.0, 0.0 ); glRotated( Yrot, 0.0, 1.0, 0.0 ); glRotated( Zrot, 0.0, 0.0, 1.0 ); glScaled( Zoom, Zoom, Zoom ); if( Np ) { for( i = 0; i < Np; i++ ) { int ic = i % Ncol; if( Ltrace ) { fprintf(stderr,"display: Particle %d Size %g Pos (%g,%g,%g)\n", i+1,BaseSize*Size[i],Coords[3*i],Coords[3*i+1],Coords[3*i+2]); } glColor3d(R[1],G[1],B[1]); glPointSize((GLfloat) clamped(BaseSize * Size[i],MinSize,MaxSize)); glBegin(GL_POINTS); glVertex3d(Coords[3*i],Coords[3*i+1],Coords[3*i+2]); glEnd(); } } if( DrawOrigin ) { glColor3d(R[0],G[0],B[0]); glPointSize((GLfloat) (BaseSize * 1)); glBegin(GL_POINTS); glVertex3d(0.0,0.0,0.0); glEnd(); } glFlush(); if( Dbuff) glutSwapBuffers(); glPopMatrix(); } /*--------------------------------------------------------------------*/ /* Routine called when window has been reshaped. */ /*--------------------------------------------------------------------*/ void reshape(int nw, int nh) { if( Ltrace ) fprintf(stderr,"reshape: New shape %d x %d\n",nw,nh); Win_w = nw; Win_h = nh; glViewport(0, 0, Win_w, Win_h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(ProjectionBbox[0],ProjectionBbox[1], ProjectionBbox[2],ProjectionBbox[3], ProjectionBbox[4],ProjectionBbox[5]); glMatrixMode(GL_MODELVIEW); if( Pause ) { if( Tumble ) { glutSetWindowTitle("p continues, t stops tumble"); } else { glutSetWindowTitle("p continues, t starts tumble"); } } else if ( Done ) { if( Tumble ) { glutSetWindowTitle(" exits, t stops tumble"); } else { glutSetWindowTitle(" exits, t starts tumble"); } } else { if( Tumble ) { glutSetWindowTitle("p pauses, t stops tumble"); } else { glutSetWindowTitle("p pauses, t starts tumble"); } } glutPostRedisplay(); } /*--------------------------------------------------------------------*/ /* M A I N routine */ /*--------------------------------------------------------------------*/ int main(int argc,char **argv) { int c; int errflg = 0; /* Parse command line options ... see 'man getopt' for more info */ /* on the 'getopt' funcion */ while ((c = getopt(argc, argv, "hm")) != -1) { switch(c) { case 'h': help(); break; case 'm': Ncol = 1; break; default: errflg = 1; break; } } if( errflg ) { fprintf(stderr,"usage: pp3d [-hm]\n\n"); fprintf(stderr," Use 'pp3d -h' for help\n"); exit(2); } /* Set up graphics, register callbacks etc. */ glutInit(&argc, argv); if( Dbuff ) { glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGB); } else { glutInitDisplayMode(GLUT_DEPTH | GLUT_RGB); } glutInitWindowSize(Win_Xsize, Win_Ysize); glutCreateWindow("pp3d"); glutKeyboardFunc(keyboard); glutDisplayFunc(display); glutSpecialFunc(special); glutReshapeFunc(reshape); glutIdleFunc(idle); if( AntiA ) glEnable(GL_POINT_SMOOTH); /* Enter GLUT main loop. */ glutMainLoop(); return 0; }