#include #include #include #include #include #include #include #include "xfpp3d.h" /*--------------------------------------------------------------------*/ /* xfpp3d: Simple visualization of 3-d particle motion using OpenGL */ /* and XForms. */ /* */ /* History: 'pp3d' and xforms 'gl' demo. */ /* */ /* Copyright 2000, M.W. Choptuik, UBC */ /*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/ /* Prototypes ... (see also xfpp3d.h) */ /*--------------------------------------------------------------------*/ double clamped(double val,double min,double max); void badstream_exit(char *s); void getinput(void); void gl_init(void); void display(void); void tumble(void); FL_IO_CALLBACK handle_stdin(int fd,FD_form *ui); /* Main form pointer ... */ FD_form *ui; /* Controls tracing ... */ int Trace = 0; /* Counts number of idle callbacks, and controls idle callback tracing frequency ... */ int N_idle_cb = 0; int Freq_idle_cb = 100; /* Maintains state of input stream ... */ int EOF_stdin = 0; int Detached_stdin = 0; int Init = 0; int Done = 0; /* For status info ... */ char Buffer[1024]; /* Defines frustum for projection transformation ... */ double ProjectionBbox[] = { -1.0, 1.0, -1.0, 1.0, 5.0, 15.0 }; /* For tumbling rotations ... */ int Tumble = 1; 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; /* Controls plotting of point at origin ... */ int DrawOrigin = 1; /* Controls pause function ... */ int Pause = 0; /* Controls size of markers ... */ double BaseSize = 5.0; double MinSize = 3.0; double MaxSize = 20.0; /* Particle information: number of particles, # of time steps processed, current time, particle sizes and particle coordinates ... */ int Np = 0; int Nt = 0; double TimeLoc; double *Size = (double *) NULL; double *Coords = (double *) NULL; /* Controls antialising ... */ int AntiA = 1; /* Some (primary) color definitions ... */ 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); /* Counts number of times 'display' is invoked ... */ int N_display = 0; /*--------------------------------------------------------------------*/ /* 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 error message to stderr and exits ... */ /*--------------------------------------------------------------------*/ void badstream_exit(char *s) { fprintf(stderr,"Error reading %s\n",s); exit(0); } /*--------------------------------------------------------------------*/ /* Processes input (stdin) ... */ /*--------------------------------------------------------------------*/ void getinput(void) { int i; if( Trace ) { fprintf(stderr,"getinput: In routine: Done <%d> Pause <%d> Init <%d>\n", Done,Pause,Init); } if( Done || Pause ) { idle_cb(0, 0); return; } if( Init == 0 ) { Init = 1; idle_cb(0, 0); 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( Trace ) { 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( Trace ) { 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, set pause if at first time, */ /* and call idle callback to plot data ... */ if( scanf("%lf",&TimeLoc) == 1 ) { if( Trace ) fprintf(stderr,"getinput: Time %g\n",TimeLoc); for( i = 0; i < Np; i++ ) { if( scanf("%lf %lf %lf",Coords + 3*i, Coords + 3*i + 1,Coords + 3*i + 2) == 3 ) { if( Trace ) { 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; fl_set_button(ui->pause_button,Pause); } } else { Done = 1; } idle_cb(0,0); } /*--------------------------------------------------------------------*/ /* Graphics initialization ... */ /*--------------------------------------------------------------------*/ void gl_init(void) { if( AntiA ) glEnable(GL_POINT_SMOOTH); glClearColor(0.0,0.0,0.0,0.0); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); glFrustum(ProjectionBbox[0],ProjectionBbox[1], ProjectionBbox[2],ProjectionBbox[3], ProjectionBbox[4],ProjectionBbox[5]); glMatrixMode( GL_MODELVIEW ); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glXSwapBuffers(fl_display, fl_get_canvas_id(ui->canvas)); } /*--------------------------------------------------------------------*/ /* Displays particles ... most of the OpenGL graphics calls are */ /* in this routine. */ /*--------------------------------------------------------------------*/ void display(void) { int i; int ltrace; if( Trace ) { fprintf(stderr,"display: In routine: Np <%d>\n",Np); } N_display++; ltrace = Trace ? !(N_display % 100) : 0; if( ltrace ) fprintf(stderr,"display: In routine\n"); fl_activate_glcanvas(ui->canvas); /* Clear the back buffer and set the viewing transformation ... */ glMatrixMode(GL_MODELVIEW); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* Save the base viewing transformation ... */ 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 ) { /* Plot the particles as points ... */ 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(); } } /* (Optionally) plot a point at the origin ... */ if( DrawOrigin ) { glColor3d(R[0],G[0],B[0]); glPointSize((GLfloat) (BaseSize * 1)); glBegin(GL_POINTS); glVertex3d(0.0,0.0,0.0); glEnd(); } /* Swap buffers to display geometry ... */ glXSwapBuffers(fl_display, fl_get_canvas_id(ui->canvas)); glFlush(); /* Restore the base viewing transformation ... */ glPopMatrix(); } /*--------------------------------------------------------------------*/ /* Implements tumbling transformation ... */ /*--------------------------------------------------------------------*/ void tumble(void) { if( !Tumble ) return; if( Trace ) { 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; } } /*--------------------------------------------------------------------*/ /* Routine which is invoked when data is present on standard input ... */ /*--------------------------------------------------------------------*/ FL_IO_CALLBACK handle_stdin(int fd,FD_form *ui) { getinput(); return 0; } /*--------------------------------------------------------------------*/ /* Routine which is called when gl_canvas is exposed ... */ /*--------------------------------------------------------------------*/ int canvas_expose(FL_OBJECT *ob, Window win, int w, int h, XEvent *xev, void *ud) { /* Set the viewport, initialize graphics and call the idle callback */ /* routine to display graphics if necessary ... */ glViewport(0,0, (GLint)w, (GLint)h); gl_init(); idle_cb(0, 0); return 0; } /*--------------------------------------------------------------------*/ /* Idle call-back routine ... */ /*--------------------------------------------------------------------*/ int idle_cb(XEvent *ev, void *data) { if(!ui->form->visible || ! ui->canvas->visible) { return 0; } N_idle_cb++; if( Trace && !(N_idle_cb % Freq_idle_cb) ) { fprintf(stderr,"idle_cb: In routine %d\n",N_idle_cb); } if( EOF_stdin && !Detached_stdin ) { fl_remove_io_callback(0,FL_READ,(FL_IO_CALLBACK) handle_stdin); Detached_stdin = 1; if( Trace ) { fprintf(stderr,"idle_cb: Removed handle_stdin callback\n"); sleep(2); } } /* Set status line ... */ if( Done ) { sprintf(Buffer,"Done Reading (%d steps)",Nt); } else { if( Pause ) { sprintf(Buffer,"Reading/Paused (Step %d)",Nt); } else { sprintf(Buffer,"Reading (Step %d)",Nt); } } fl_set_object_label(ui->status_text,Buffer); /* Set time ... */ sprintf(Buffer,"T = %g",TimeLoc); fl_set_object_label(ui->time_text,Buffer); /* Set number of particles ... */ sprintf(Buffer,"%d particles",Np); fl_set_object_label(ui->np_text,Buffer); /* Display the particles and apply tumble rotation ... */ display(); tumble(); return 0; } /*--------------------------------------------------------------------*/ /* Button call-back routines ... */ /*--------------------------------------------------------------------*/ void zoom_in_button_cb(FL_OBJECT *ob, long val) { Zoom *= ZoomFactor; idle_cb(0, 0); } void zoom_out_button_cb(FL_OBJECT *ob, long val) { Zoom /= ZoomFactor; idle_cb(0, 0); } void exit_button_cb(FL_OBJECT *ob, long val) { if( fl_show_question("Really Exit?",1) ) exit(1); } void tumble_button_cb(FL_OBJECT *ob, long val) { Tumble = !Tumble; idle_cb(0, 0); } void tumble_slower_button_cb(FL_OBJECT *ob, long val) { Xstep /= TumbleFactor; Ystep /= TumbleFactor; Zstep /= TumbleFactor; idle_cb(0, 0); } void tumble_faster_button_cb(FL_OBJECT *ob, long val) { Xstep *= TumbleFactor; Ystep *= TumbleFactor; Zstep *= TumbleFactor; idle_cb(0, 0); } void pause_button_cb(FL_OBJECT *ob, long val) { Pause = !Pause; idle_cb(0, 0); } void origin_button_cb(FL_OBJECT *ob, long val) { DrawOrigin = !DrawOrigin; idle_cb(0, 0); } /*--------------------------------------------------------------------*/ /* M A I N R O U T I N E . . . */ /*--------------------------------------------------------------------*/ int main(int argc, char *argv[]) { /* Initialize form library, create and display main form ... */ fl_initialize(&argc, argv, "xfpp3d", 0, 0); ui = create_form_form(); fl_show_form(ui->form, FL_PLACE_CENTER | FL_FREE_SIZE, FL_FULLBORDER, "xfpp3d"); /* Register various callbacks ... */ fl_add_canvas_handler(ui->canvas, Expose, canvas_expose, 0); fl_set_idle_delta(1); fl_set_idle_callback(idle_cb, 0); fl_add_io_callback(0,FL_READ,(FL_IO_CALLBACK) handle_stdin,ui); /* Set minimum size of form ... */ fl_set_form_minsize(ui->form, 340, 280); /* Initialize graphics ... */ gl_init(); /* Set initial state of some buttons ... */ fl_set_button(ui->tumble_button,Tumble); fl_set_button(ui->pause_button,Pause); fl_set_button(ui->origin_button,DrawOrigin); /* Enter main forms loop ... */ fl_do_forms(); fl_finish(); return 0; }