#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> 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_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; 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_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; } switch(Fl::event_text()[0]) { 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: static double bumpunit; if(view->num.has) bumpunit = view->num.fvalue(); view->num.has = 0; st->time0 += bump * bumpunit; st->timeplay = 0; specks_set_time( st, 0.0 ); // ppui_refresh(); ??? Yes, after we add an animation panel view->redraw(); 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; for(tno = 0; tno < MAXSTUFF; tno++) { if(stuffs[tno]) maxobject = tno; 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; 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] ); } ppui.view->notifier( pp_viewchanged, ppui.st ); ppui_refresh( ppui.st ); ppui.mainwin->show(1, argv); ppui.view->show(); return Fl::run(); }