#include <stdio.h> #include <stdlib.h> #ifdef WIN32 # include "winjunk.h" #endif #include <GL/gl.h> #include "Gview.H" #include "partiview.H" #include "geometry.h" #include "shmem.h" #include <string.h> #include <stdarg.h> #include <math.h> #include <errno.h> #include "partiviewc.h" #include <FL/Fl.H> #include <FL/fl_file_chooser.H> static char local_id[] = "$Id$"; struct _ppui ppui; struct stuff *stuffs[MAXSTUFF]; static int specks_commandstr( struct stuff **stp, const char *str ) { if(stp == NULL || *stp == NULL || str == NULL) return 0; #define MAXARGS 128 char *av[MAXARGS]; int ac; char *txt = (char *)alloca( strlen(str) + 1 ); char *s = txt; strcpy(txt, str); for(ac = 0; ac < MAXARGS-1; ac++) { av[ac] = strtok(s, " \t\n"); if(av[ac] == NULL) break; s = NULL; } av[ac] = NULL; return specks_parse_args( stp, ac,av); } int specks_commandfmt( struct stuff **stp, const char *fmt, ... ) { char cmd[1024]; int ok; va_list args; va_start(args, fmt); vsprintf(cmd, fmt, args); va_end(args); ok = specks_commandstr( stp, cmd ); if(ok && ppui.view) ppui.view->redraw(); return ok; } /* =================================================================== */ void pp_nav_init(Fl_Menu_Button *); int pp_viewevent_cb( Fl_Gview *, int ev ); void pp_ui_init() { pp_nav_init(ppui.nav); /* ppui.cmd->handle_cb = pp_cmd_handle_cb; No, this doesn't work yet */ ppui.view->eventhook = pp_viewevent_cb; } void pp_clk_init() { ppui.clk = NewN( SClock, 1 ); clock_init( ppui.clk ); clock_set_speed( ppui.clk, 1.0 ); ppui.clk->continuous = 1; // is this used? ppui.clk->walltimed = 1; } void pp_ui_postinit() { parti_set_timebase( ppui.st, 0.0 ); parti_set_timestep( ppui.st, 0.0 ); parti_set_running( ppui.st, 0 ); parti_set_fwd( ppui.st, 1 ); ppui.stepspeed->logstyle( FL_LOG_LINEAR ); ppui.stepspeed->truebounds( 1.0e-6, 10.0 ); ppui.stepspeed->truevalue( clock_speed( ppui.clk ) ); clock_set_step( ppui.clk, 0.1 * clock_speed( ppui.clk ) ); ppui.steprow->hide(); } void pp_cmd_cb( HistInput* inp, void * ) { if(inp->hist()) inp->hist()->addline( inp->value(), 0 ); specks_commandstr( &ppui.st, inp->value() ); ppui_refresh( ppui.st ); ppui.view->redraw(); } static enum Gv_Nav codes[] = { GV_FLY, GV_ORBIT, GV_ROTATE, GV_TRANSLATE }; static char *navtitles[] = {"[f]ly","[o]rbit","[r]ot","[t]ran"}; void pp_nav_init(Fl_Menu_Button *m) { m->add("[f]ly|[o]rbit|[r]ot|[t]ran"); for(int i = m->size(); --i >= 0; ) (((Fl_Menu_Item *)(m->menu()))[i]).labelcolor( m->labelcolor() ); } void pp_nav_cb(Fl_Menu_Button* m, struct stuff **vst) { int v = m->value(); if(v >= 0 && v < COUNT(codes)) ppui.view->nav( codes[v] ); } void pp_obj_cb(Fl_Menu_Button* m, void *) { parti_object( m->text(), &ppui.st ); } void pp_objtog_cb(Fl_Button* b, void *) { int objno = 1; sscanf(b->label(), "g%d", &objno); if(objno<0||objno>=MAXSTUFF||stuffs[objno]==NULL) return; if(Fl::event_button() == FL_RIGHT_MOUSE) { stuffs[objno]->useme = 1; parti_object( b->label(), &ppui.st ); b->value(1); } else { stuffs[objno]->useme = !stuffs[objno]->useme; } ppui_refresh( ppui.st ); ppui.view->redraw(); } void pp_slum_cb(Fl_Value_Slider* sl, struct stuff ** ) { struct stuff *st = ppui.st; int cd = st->curdata, by = st->sizedby; if((unsigned int)cd >= MAXFILES) cd = 0; if((unsigned int)by >= MAXVAL+1) by = 0; struct valdesc *vd = &st->vdesc[cd][by]; vd->lum = pow(10., sl->value()); ppui.view->redraw(); } void pp_stepper( void *vst ) { struct stuff *st = (struct stuff *)vst; if(st) { clock_tick( st->clk ); specks_set_timestep( ppui.st ); ppui.view->redraw(); } } void parti_stepping( struct stuff *st, int on ) { if(clock_running(st->clk) != on) { if(on) Fl::add_idle( pp_stepper, st ); else Fl::remove_idle( pp_stepper, st ); if(st->clk) st->clk->walltimed = 1; clock_set_running(st->clk, on); } ppui.runstop[0]->value( on && clock_fwd(st->clk) < 0 ); ppui.runstop[1]->value( on && clock_fwd(st->clk) > 0 ); } void pp_step_cb( Fl_Button * , void *stepsign ) { double sign = (int)stepsign; parti_stepping( ppui.st, 0 ); switch(Fl::event_button()) { case FL_RIGHT_MOUSE: sign *= 10; break; case FL_MIDDLE_MOUSE: sign *= 0.1; break; } clock_step( ppui.st->clk, sign ); specks_set_timestep( ppui.st ); ppui.view->redraw(); } void pp_run_cb( Fl_Button *runbtn, void *stepsign ) { clock_set_fwd( ppui.st->clk, (int)stepsign ); parti_stepping( ppui.st, runbtn->value() ); } void pp_timeinput_cb( Fl_Input *inp, void * ) { double v; parti_stepping( ppui.st, 0 ); if(sscanf(inp->value(), "%lf", &v)) clock_set_time( ppui.st->clk, v + ppui.timebasetime ); } void pp_timebaseinput_cb( Fl_Input *inp, void * ) { double newbase; parti_stepping( ppui.st, 0 ); if(sscanf(inp->value(), "%lf", &newbase)) { double now = clock_time( ppui.st->clk ); parti_set_timestep( ppui.st, now - newbase ); ppui.timebasetime = newbase; } } void pp_jog_cb( Fl_Roller *rol, void * ) { static double lastrol; double v = rol->value(); clock_step( ppui.st->clk, v - lastrol ); lastrol = v; parti_stepping( ppui.st, 0 ); specks_set_timestep( ppui.st ); parti_set_timestep( ppui.st, clock_time( ppui.st->clk ) ); ppui.view->redraw(); } void pp_settrip_cb( Fl_Button *, void * ) { char str[32]; ppui.timebasetime = clock_time( ppui.st->clk ); ppui.timestep->value( "0" ); sprintf(str, "%.16lg", ppui.timebasetime); ppui.timebase->value(str); } void pp_backtrip_cb( Fl_Button *, void * ) { clock_set_time( ppui.st->clk, ppui.timebasetime ); ppui.timestep->value( "0" ); } void pp_stepspeed_cb( Fl_Log_Slider *spd, void * ) { double speed = spd->truevalue(); clock_set_speed( ppui.st->clk, speed ); clock_set_step( ppui.st->clk, 0.1 * speed ); } void pp_rdata_cb( Fl_Button *, struct stuff ** ) { struct stuff *st = ppui.st; const char *result; result = fl_file_chooser("Choose virdir .wf path", "*.wf", NULL); if (result) parti_readpath( st, result ); } void pp_playframe_cb( Fl_Counter *counter, struct stuff ** ) { struct stuff *st = ppui.st; if(ppui.playing) parti_play( st, "0" ); parti_setframe( st, (int)counter->value() ); } void pp_playtime_cb( Fl_Value_Slider *slider, struct stuff ** ) { struct stuff *st = ppui.st; struct wfpath *path = &ppui.path; if(ppui.playing) parti_play( st, "0" ); parti_setframe( st, (int) (slider->value() * path->fps + path->frame0) ); } void pp_play_cb( Fl_Button *play, struct stuff ** ) { if(Fl::event_state(FL_BUTTON3)) { ppui.playmenu->popup(); } else { parti_play( ppui.st, play->value() ? NULL /*play at default speed*/ : "0" /*stop*/ ); } } int pp_viewevent_cb( Fl_Gview *view, int ev ) { char snapinfo[1024]; int fno; double bump; struct stuff *st = ppui.st; if(ev == FL_KEYBOARD || ev == FL_SHORTCUT) { if(ppui.cmdhist && ppui.cmdhist->handle_nav(ev)) return 1; switch(Fl::event_key()) { case FL_Print: if(view->num.has) { ppui.snapfno = view->num.value(); view->num.has = 0; } fno = parti_snapshot(snapinfo); if(fno >= 0) msg("Snapped %s", snapinfo); return 1; } int key = Fl::event_text()[0]; switch(key) { case '\t': if(!ppui.cmdhist || !ppui.cmdhist->input()) return 0; ppui.cmdhist->input()->take_focus(); return 1; case 'S': if(view->num.has) { float v = view->num.fvalue(); if(v == 0) { parti_stereo("off"); } else { if(fabs(v) < 1) /* plausible? */ view->stereosep( v ); parti_stereo("on"); } view->num.has = 0; } else { parti_stereo( view->stereo()==GV_MONO ? "on" : "off" ); } msg("stereo %s (focallen %g)", parti_stereo(NULL), view->focallen()); return 1; case '>': bump = 1; goto step; case '<': bump = -1; step: if(view->num.has) clock_set_step( st->clk, view->num.fvalue() ); view->num.has = 0; clock_step( st->clk, bump ); parti_stepping( st, 0 ); /* clock_notify( st->clk ); NOTYET NOTIFY */ // ppui_refresh(); ??? Yes, after we add an animation panel view->redraw(); return 1; case '{': case '}': clock_set_fwd( st->clk, key=='}' ); parti_stepping( st, 1 ); return 1; } } return 0; } void ppui_refresh( struct stuff *st ) { if(ppui.view == NULL) return; /* Possibly switch selected object */ int targ = ppui.view->target(); if(targ >= 0 && targ < MAXSTUFF && stuffs[targ] != NULL && stuffs[targ] != ppui.st) { st = ppui.st = stuffs[targ]; } enum Gv_Nav nav = ppui.view->nav(); for(int navcode = 0; navcode < COUNT(codes); navcode++) { if(codes[navcode] == nav) { ppui.nav->value( navcode ); if(strcmp(ppui.nav->label(), navtitles[navcode])) { ppui.nav->label( navtitles[navcode] ); ppui.nav->parent()->redraw(); } } } int tno, maxobject = 0; int timeshown = ppui.steprow->visible(); for(tno = 0; tno < MAXSTUFF; tno++) { struct stuff *tst = stuffs[tno]; if(tst == NULL) continue; maxobject = tno; if(!timeshown && tst->clk->tmin != tst->clk->tmax) { ppui.steprow->show(); ppui.steprow->parent()->redraw(); timeshown = 1; } if(ppui.st == stuffs[tno]) { char oname[12]; Fl_Font lfont = ppui.view->movingtarget() ? FL_HELVETICA_BOLD_ITALIC : FL_HELVETICA; sprintf(oname, "[g%d]", tno); if(strcmp(ppui.obj->label(), oname) || lfont != ppui.obj->labelfont()) { ppui.obj->label( strdup( oname ) ); // Iff we might actually move the target object, // display its [gN] title in BOLD ITALICs. ppui.obj->labelfont( lfont ); ppui.obj->parent()->redraw(); } } } if(st == NULL) return; if(ppui.objgroup->active() != st->useme) { if(st->useme) ppui.objgroup->activate(); else ppui.objgroup->deactivate(); } // objtogs is wrapped in a Group which is invisible by default. if(!ppui.objtogs->parent()->visible() && maxobject > 1) { ppui.objtogs->parent()->show(); } if(ppui.objtogs->visible()) { Fl_Button *b, *b0 = (Fl_Button *)ppui.objtogs->child(0); for(tno = 0; tno <= maxobject; tno++) { if(tno >= ppui.objtogs->children()) { char name[8]; sprintf(name, "g%d", tno); b = new Fl_Button( b0->x(),b0->y(),b0->w(),b0->h(), strdup(name) ); b->labelcolor( b0->labelcolor() ); b->color( b0->color() ); b->selection_color( b0->selection_color() ); b->down_box( b0->down_box() ); b->type( b0->type() ); b->callback( (Fl_Callback*)pp_objtog_cb ); ppui.objtogs->add( b ); } b = (Fl_Button *)ppui.objtogs->child(tno); if(stuffs[tno] == NULL) { if(b->visible()) b->hide(); } else { if((b->value() != 0) != stuffs[tno]->useme) b->value( stuffs[tno]->useme ); if(!b->visible()) b->show(); } } } ppui.point->value( st->usepoint ); ppui.poly->value( st->usepoly ); ppui.label->value( st->usetext ); ppui.texture->value( st->usetextures ); ppui.box->value( st->useboxes!=0 ); int boxcolor = ( st->useboxes==2 ? 1/*red*/ : 2/*green*/ ); if(boxcolor != ppui.box->color2()) { ppui.box->color2( boxcolor ); ppui.box->redraw(); } int cd = st->curdata, by = st->sizedby; if((unsigned int)cd >= MAXFILES) cd = 0; if((unsigned int)by >= MAXVAL+1) by = 0; struct valdesc *vd = &st->vdesc[cd][by]; float lum = vd->lum; if(lum <= 0) lum = 1; ppui.slum->value( log10( lum ) ); char slumlabel[20]; if(st->vdesc[cd][by].name[0]) sprintf( slumlabel, "logslum %.10s", vd->name ); else sprintf( slumlabel, "logslum(var%d)", by ); if(strcmp(ppui.slum->label(), slumlabel)) { static char slumlab[20]; strcpy(slumlab, slumlabel); ppui.slum->label(slumlab); ppui.slum->parent()->redraw(); } } void pp_viewchanged( Fl_Gview *gview, void *st ) { ppui_refresh( ppui.st ); } int msg( const char *fmt, ... ) { char str[10240]; va_list args; va_start(args, fmt); vsprintf(str, fmt, args); va_end(args); if(ppui.cmdhist) ppui.cmdhist->addline( str, 1 ); return printf("%s\n", str); } void quietwarning( const char *fmt, ... ) { char msg[10240]; static char avoid[] = "X_ChangeProperty: "; va_list args; va_start(args, fmt); vsprintf(msg, fmt, args); va_end(args); if(0!=strncmp(msg, avoid, sizeof(avoid)-1)) fputs(msg, stderr); } void drawjunk(Fl_Gview *view, void *obj, void *arg) { static Point xyz[3] = {{1,0,0}, {0,1,0}, {0,0,1}}; static Point nxyz[3] = {{-1,0,0}, {0,-1,0}, {0,0,-1}}; static Point zero = {0,0,0}; static float white[3] = {1,1,1}; float censize = parti_getcensize(); int i; glDisable(GL_LIGHTING); if(censize > 0) { glPushMatrix(); glScalef(censize,censize,censize); glBegin(GL_LINES); for(i = 0; i < 3; i++) { glColor3fv(xyz[i].x); glVertex3fv(xyz[i].x); glVertex3f(0,0,0); } glEnd(); glPopMatrix(); } if(censize != 0) { censize = fabs(censize); glPushMatrix(); const Point *cen = view->center(); glTranslatef(cen->x[0],cen->x[1],cen->x[2]); glScalef(censize, censize, censize); glBegin(GL_LINES); for(i = 0; i < 3; i++) { glColor3fv(white); glVertex3fv(nxyz[i].x); glVertex3fv(zero.x); glColor3fv(xyz[i].x); glVertex3fv(zero.x); glVertex3fv(xyz[i].x); } glEnd(); glPopMatrix(); } } int main(int argc, char *argv[]) { GLuint pickbuffer[20480]; Fl::warning = quietwarning; pp_clk_init(); ppui.mainwin = make_window(); static Point black = {0,0,0}; ppui.view->bgcolor( &black ); /* make_window() sets ppui.view, etc. */ pp_ui_init(); ppui.view->add_drawer( drawjunk, NULL, NULL, NULL, 0 ); ppui.view->pickbuffer( COUNT(pickbuffer), pickbuffer ); ppui.view->zspeed = 5; ppui.view->farclip( 2500 ); ppui.censize = 1.0; ppui.view->movingtarget( 0 ); ppui.view->msg = msg; ppui.playspeed = 1; ppui.playframe->lstep(10); parti_object( "g1", NULL ); for(int i = 1; i < argc; i++) { specks_read( &ppui.st, argv[i] ); } pp_ui_postinit(); ppui.view->notifier( pp_viewchanged, ppui.st ); ppui_refresh( ppui.st ); ppui.mainwin->show(1, argv); ppui.view->show(); return Fl::run(); }