#include "xfpp3d_main.h" #include "mpeg.h" /* History: gl.c demo from xforms distribution and pp3d.c */ extern void help(void); char *P; int Trace = 0; char *InputFile = (char *) NULL; int EOF_stdin = 0; int Detached_stdin = 0; int N_cb_idle = 0; int Freq_cb_idle = 100; FD_main *Main; FD_mpeg *Mpeg; /* For status info ... */ char Buffer[1024]; /* Defines frustum for projection ... */ double ProjBbox[] = { -1.0, 1.0, -1.0, 1.0, 5.0, 15.0 }; /* For controlling animation speed ... */ double Sleep_sec = 0; /* Set default sleep interval for approx. 30 frames/sec maximum ... */ double Default_sleep_slider_value = 3.0; /* Single step ... */ int Single_step = 0; /* For tumbling rotations ... */ double Xrot = 0.0; double Xstep0 = 0.2; double Xstep = 0.0; double Yrot = 0.0; double Ystep0 = 0.4; double Ystep = 0.0; double Zrot = 0.0; double Zstep0 = 0.5; double Zstep = 0.0; /* For translations ... */ double Xtrans = 0.0; double Ytrans = 0.0; /* For Zoom-in/Zoom-out ... */ double ZoomFactor = 1.1; double Zoom = 1.0; int ShowOrigin = 1; int Ltrace = 0; int Win_w, Win_h; double Win_Xsize = 500; double Win_Ysize = 500; int Init = 0, Done = 0; double BaseSize = 5.0; double MinSize = 3.0; double MaxSize = 20.0; int Np = 0; double TimeLoc; double *Size = (double *) NULL; double *Coords = (double *) NULL; int Color_code = 0; int *Color = (int *) NULL; double *Color_R = (double *) NULL; double *Color_G = (double *) NULL; double *Color_B = (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; /*--------------------------------------------------------------------*/ /* Dumps error message to stderr and exits */ /*--------------------------------------------------------------------*/ void badstream_exit(char *s) { fprintf(stderr,"Error reading %s\n",s); exit(0); } double dmin(double x1,double x2) { return (x1 < x2 ) ? x1 : x2; } double dmax(double x1,double x2) { return (x1 > x2 ) ? x1 : x2; } /*--------------------------------------------------------------------*/ /* Processes input */ /*--------------------------------------------------------------------*/ void getinput(void) { int i; if( Ltrace ) { fprintf(stderr,"getinput: In routine: Done <%d> Pause <%d> Init <%d>\n", Done,Pause,Init); } if( Done || Pause ) { cb_idle(0, 0); return; } if( fl_get_timer(Main->display_timer) ) return; if( Init == 0 ) { Init = 1; cb_idle(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( Ltrace ) { fprintf(stderr,"getinput: %d particles\n",Np); } Size = (double *) malloc(Np * sizeof(double)); Coords = (double *) malloc(3 * Np * sizeof(double)); if( Color_code ) { Color_R = (double *) malloc(Np * sizeof(double)); Color_G = (double *) malloc(Np * sizeof(double)); Color_B = (double *) malloc(Np * sizeof(double)); } for( i = 0; i < Np; i++ ) { if( Color_code ) { if( scanf("%lf %lf %lf %lf", Size + i,Color_R + i,Color_G + i,Color_B + i) == 4 ) { if( Ltrace ) { fprintf(stderr,"getinput: Particle=%d Size=%g Color=[%g,%g,%g]\n", i+1,Size[i],Color_R[i],Color_G[i],Color_B[i]); } } else { badstream_exit("particle sizes/colors"); } } else { 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",&TimeLoc) == 1 ) { if( Ltrace ) 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( Ltrace ) { fprintf(stderr,"getinput: Particle %d Pos (%g,%g,%g)\n", i,Coords[3*i],Coords[3*i+1],Coords[3*i+2]); } } } Nt++; Mpeg_newdata = 1; if( Nt == 1 ) { Pause = 1; fl_set_button(Main->pause_button,Pause); } } else { Done = 1; } cb_idle(0,0); if( Single_step ) { Single_step = 0; Pause = 1; fl_set_button(Main->pause_button,Pause); } fl_set_timer(Main->display_timer,Sleep_sec); } /*--------------------------------------------------------------------*/ /* Displays particles ... most of the OpenGL graphics calls are */ /* in this routine. */ /*--------------------------------------------------------------------*/ int N_display = 0; void display(void) { int i; int ltrace; int ic; if( !Pause && !Done && Ltrace ) { fprintf(stderr,"display: In routine: Np=%d TimeLoc=%g\n",Np,TimeLoc); } N_display++; ltrace = Ltrace ? !(N_display % 100) : 0; if( ltrace ) fprintf(stderr,"display: In routine\n"); fl_activate_glcanvas(Main->canvas); glMatrixMode(GL_MODELVIEW); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glTranslated( 0.0, 0.0, -0.5 * (ProjBbox[4] + ProjBbox[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++ ) { 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]); } if( Color_code ) { glColor3d(Color_R[i],Color_G[i],Color_B[i]); } else { 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( ShowOrigin ) { glColor3d(R[0],G[0],B[0]); glPointSize((GLfloat) (BaseSize * 1)); glBegin(GL_POINTS); glVertex3d(0.0,0.0,0.0); glEnd(); } glXSwapBuffers(fl_display, fl_get_canvas_id(Main->canvas)); if( (Mpeg_state == MPEG_RECORD) && Mpeg_newdata && !Pause && !Done ) { gl_to_jpeg(Main->canvas,Mpeg_dir,Mpeg_fname,Mpeg_seqno); Mpeg_seqno++; Mpeg_newdata = 0; widgets_set_mpeg(); } glFlush(); glPopMatrix(); } void tumble(void) { 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; } } int cb_buttonpress(FL_OBJECT *ob, Window win, int w, int h, XEvent *xev, void *ud) { return 0; } void cb_zoom_in_button(FL_OBJECT *ob, long val) { Zoom *= ZoomFactor; cb_idle(0,0); } void cb_zoom_out_button(FL_OBJECT *ob, long val) { Zoom /= ZoomFactor; cb_idle(0,0); } void cb_exit_button(FL_OBJECT *ob, long val) { if( fl_show_question("Are you sure you want to exit?",1) ) exit(0); } void cb_pause_button(FL_OBJECT *ob, long val) { Pause = !Pause; cb_idle(0,0); } typedef enum { OptionsOrigin = 1 } OptionsType; void cb_options_menu(FL_OBJECT *ob, long val) { int menuID = fl_get_menu_popup(ob); int item = fl_get_menu(ob); switch( item ) { case OptionsOrigin: ShowOrigin = fl_get_menu_item_mode(ob,OptionsOrigin) & FL_PUP_CHECK; if( Ltrace ) fprintf(stderr,"ShowOrigin is %s\n", ShowOrigin ? "on" : "off"); break; default: break; } } int gl_init(void) { if( AntiA ) glEnable(GL_POINT_SMOOTH); glClearColor(0.0,0.0,0.0,0.0); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); glFrustum(ProjBbox[0],ProjBbox[1], ProjBbox[2],ProjBbox[3], ProjBbox[4],ProjBbox[5]); glMatrixMode( GL_MODELVIEW ); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glXSwapBuffers(fl_display, fl_get_canvas_id(Main->canvas)); return 0; } int canvas_expose(FL_OBJECT *ob, Window win, int w, int h, XEvent *xev, void *ud) { glViewport(0,0, (GLint)w, (GLint)h); gl_init(); /* refresh */ cb_idle(0, 0); return 0; } int cb_idle(XEvent *ev, void *data) { if(!Main->main->visible || ! Main->canvas->visible) { return 0; } N_cb_idle++; if( Trace && !(N_cb_idle % Freq_cb_idle) ) { fprintf(stderr,"cb_idle: In routine %d\n",N_cb_idle); } if( EOF_stdin && !Detached_stdin ) { fl_remove_io_callback(0,FL_READ,(FL_IO_CALLBACK) handle_stdin); Detached_stdin = 1; if( Trace ) { fprintf(stderr,"cb_idle: Removed handle_stdin callback\n"); sleep(2); } } /* Set status line ... */ if( Done ) { sprintf(Buffer,"Done Reading\n%d steps",Nt); } else { if( Pause ) { sprintf(Buffer,"Reading/Paused\nStep %d",Nt); } else { sprintf(Buffer,"Reading\nStep %d",Nt); } } fl_set_object_label(Main->status_text,Buffer); /* Set time ... */ sprintf(Buffer,"T = %g",TimeLoc); fl_set_object_label(Main->time_text,Buffer); /* Set number of particles ... */ sprintf(Buffer,"%d particles",Np); fl_set_object_label(Main->np_text,Buffer); display(); tumble(); return 0; } void cb_input_file(FL_OBJECT *the, long arg) { if( InputFile ) { free(InputFile); } InputFile = strdup(fl_get_input(the)); if( Trace ) { fprintf(stderr,"cb_input_file: Input File: <%s>\n",InputFile); } } FL_IO_CALLBACK handle_stdin(int fd,FD_main *Main) { getinput(); return 0; } FL_IO_CALLBACK handle_stdin_old(int fd,FD_main *Main) { int val; if( EOF_stdin) return 0; if( Trace ) { fprintf(stderr,"handle_stdin: In routine\n"); } switch( fscanf(stdin,"%d",&val) ) { case EOF: EOF_stdin = 1; break; case 0: fprintf(stderr,"handle_stdin: Error reading stdin\n"); break; case 1: fprintf(stderr,"handle_stdin: Read <%d>\n",val); break; default: fprintf(stderr,"handle_stdin Unexpected case\n"); break; } return 0; } void cb_sleep_slider(FL_OBJECT *the, long val) { Sleep_sec = fl_get_slider_value(the) / 100; fl_set_timer(Main->display_timer,Sleep_sec); } void cb_tumble_slider(FL_OBJECT *the, long val) { double tumble_speed; tumble_speed = fl_get_slider_value(the); Xstep = Xstep0 * tumble_speed; Ystep = Ystep0 * tumble_speed; Zstep = Zstep0 * tumble_speed; } void cb_display_timer(FL_OBJECT *the, long val) { } void cb_single_step_button(FL_OBJECT *the, long val) { Single_step = 1; Pause = 0; fl_set_button(Main->pause_button,Pause); cb_idle(0,0); } void cb_reset_view_button(FL_OBJECT *the, long val) { Xrot = 0.0; Yrot = 0.0; Zrot = 0.0; Zoom = 1.0; cb_idle(0,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; } } /*========================================================================= at_close routine for main which prompts user for exit confirmation. =========================================================================*/ int at_close_main(FL_FORM *form, void *data) { if( fl_show_question("Are you sure you want to exit?",1) ) { exit(1); } else { /* Recurse to stay alive, potential stack problem ... */ fl_do_forms(); } return FL_IGNORE; } /*========================================================================= Main program. =========================================================================*/ int main(int argc, char *argv[]) { int c; int errflg = 0; /* Parse command line arguments ... see 'man getopy' for more info */ /* on the 'getopt' function. */ P = argv[0]; while ((c = getopt(argc, argv, "ch")) != -1) { switch(c) { case 'c': Color_code = 1; break; case 'h': help(); break; default: errflg = 1; break; } } if( errflg ) help(); fl_initialize(&argc, argv, "xfpp3d", 0, 0); Mpeg = create_form_mpeg(); Main = create_form_main(); fl_show_form(Main->main, FL_PLACE_CENTER | FL_FREE_SIZE, FL_FULLBORDER, "xfpp3d"); fl_set_form_atclose(Main->main,at_close_main,NULL); fl_set_form_atclose(Mpeg->mpeg,at_close_mpeg_form,NULL); fl_add_canvas_handler(Main->canvas, Expose, canvas_expose, 0); fl_add_canvas_handler(Main->canvas, ButtonPress, cb_buttonpress, 0); fl_set_idle_delta(1); fl_set_idle_callback(cb_idle, 0); fl_add_io_callback(0,FL_READ,(FL_IO_CALLBACK) handle_stdin,Main); /* geometry stuff */ fl_set_form_minsize(Main->main, 340, 280); /* Create a timer object for controlling animation speed ... */ fl_set_timer(Main->display_timer,0.0); /* ... set sleep interval slider, and invoke callback to initialize timer ... */ fl_set_slider_value(Main->sleep_slider,Default_sleep_slider_value); fl_set_button(Main->pause_button,Pause); fl_set_menu_item_mode(Main->options_menu,OptionsOrigin, ShowOrigin ? FL_PUP_CHECK : FL_PUP_BOX); gl_init(); fl_do_forms(); fl_finish(); exit(0); Usage: fprintf(stderr,"usage: %s [-c]\n",P); exit(1); }