Skip to content
Snippets Groups Projects
partiview.cc 31.7 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*
     * Main program for FLTK-based partiview.
     * Stuart Levy, slevy@ncsa.uiuc.edu
     * National Center for Supercomputing Applications,
     * University of Illinois 2001.
    
     * This file is part of partiview, released under the
     * Illinois Open Source License; see the file LICENSE.partiview for details.
    
    #include <stdio.h>
    #include <stdlib.h>
    
    #ifdef WIN32
    # include "winjunk.h"
    #endif
    
    slevy's avatar
    slevy committed
    #include "specks.h"
    
    #include "Gview.H"
    #include "partiview.H"
    #include "shmem.h"
    #include <string.h>
    #include <stdarg.h>
    
    #include <ctype.h>
    
    #include <math.h>
    #include <errno.h>
    
    #include "partiviewc.h"
    
    slevy's avatar
    slevy committed
    #ifdef FLHACK
    # include "flhack.H"
    
    slevy's avatar
    slevy committed
    # include <FL/Fl.H>
    # include <FL/fl_draw.H>
    # include "genericslider.H"  //steven marx: generic slider introduced version 0.7.02
    # include <FL/Fl_Tooltip.H>  //steven marx: version 0.7.02 now using fltk-1.1.2
    
    # if HAVE_OLD_FILE_CHOOSER_H
    #  include <FL/fl_file_chooser.H>	/* fltk 1.0.* and 1.1.rcX for X<6 */
    # else
    #  include <FL/Fl_File_Chooser.H>	/* fltk 1.1.0rc6 and later */
    # endif
    
    #include <FL/glut.H>		// for GLUT_MULTISAMPLE if fltk knows it
    
    slevy's avatar
    slevy committed
    #endif /* !FLHACK */
    
    slevy's avatar
     
    slevy committed
    static char local_id[] = "$Id$";
    
    slevy's avatar
    slevy committed
    #ifdef EMBEDHACK
    # include "pview_funcs.h"
    #endif
    
    
    extern "C" { extern void plugin_init(); }
    
    
    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], *cp;
    
      int ok;
      va_list args;
      va_start(args, fmt);
      vsprintf(cmd, fmt, args);
      va_end(args);
    
      for(cp = cmd; isspace(*cp); cp++)
          ;
      if(*cp == '\0') return 1;	// accept null command implicitly
    
      ok = specks_commandstr( stp, cmd );
    
      else msg("Unrecognized control command: %s", cmd);
    
      return ok;
    }
    
    
    /* =================================================================== */
    
    
    slevy's avatar
     
    slevy committed
    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;
    
    slevy's avatar
     
    slevy committed
    
    
    slevy's avatar
     
    slevy committed
    }
    
    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 ) );
    
    slevy's avatar
     
    slevy committed
      clock_set_step( ppui.clk, 0.1 * clock_speed( ppui.clk ) );
    
    slevy's avatar
     
    slevy committed
    
      ppui.steprow->hide();
    
    slevy's avatar
    slevy committed
      if(ppui.detached) {
        char code[2] = { ppui.detached, '\0' };
        parti_detachview(code);
      }
    
    slevy's avatar
     
    slevy committed
    }
    
    slevy's avatar
    slevy committed
    
    #ifdef FLHACK
    
    void ppui_refresh()
    { }
    
    #else /* !FLHACK */
    
    void pp_nav_init(Fl_Menu_Button *);
    int  pp_viewevent_cb( Fl_Gview *, int ev );
    
    int gensliderchg = 0; //steven marx: generic slider introduced version 0.7.02
    
    void pp_ui_init() {
    
      pp_nav_init(ppui.nav);
    
      pp_sldtype_init(ppui.sldtype); //steven marx: version 0.7.02
      genericslider_initparam();     //steven marx: version 0.7.02
    
      /* ppui.cmd->handle_cb = pp_cmd_handle_cb;  No, this doesn't work yet */
    
      ppui.view->eventhook = pp_viewevent_cb;
    
      parti_inertia( 1 );
    
      if(getenv("CMDFONT"))
        ppui.cmdhist->scaletext( atoi( getenv("CMDFONT") ) );
      ppui.freewin = NULL;
      ppui.boundwin = ppui.view;
      ppui.detached = 0;
    
    #ifdef DEFAULT_ELUMENS
      ppui.detached = 'f';
    #endif
    }
    
    
    void pp_cmd_cb( HistInput* inp, void * ) {
      if(inp->hist())
        inp->hist()->addline( inp->value(), 0 );
    
      const char *cp;
      for(cp = inp->value(); isspace(*cp); cp++)
          ;
      if(*cp == '\0')
          return;	// accept null command implicitly
    
    
      int ok = specks_commandstr( &ppui.st, inp->value() );
      if(!ok)
        msg("Unrecognized control command: %s", inp->value());
    
      ppui_refresh( ppui.st );
    
      parti_redraw();        
      genericslider_setparam(); //steven marx version 0.7.02 update generic slider
    
    }
    
    
    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, 0 );
    
    }
    
    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;
    
    
      //================ marx added version 0.7.04 to support 1 button mac mouse ======================
    #ifndef __APPLE__
    
    slevy's avatar
     
    slevy committed
      if(Fl::event_button() == FL_RIGHT_MOUSE) {
    
    #else
      if( (Fl::event_button() == FL_RIGHT_MOUSE) ||  ((Fl::event_button() == FL_LEFT_MOUSE) && Fl::event_alt())  ) {
    #endif
     //================  end 1 button mac mouse =======================================================
    
    
    slevy's avatar
     
    slevy committed
        stuffs[objno]->useme = 1;
    
        parti_object( b->label(), &ppui.st, 0 );
    
    slevy's avatar
     
    slevy committed
        b->value(1);
      } else {
        stuffs[objno]->useme = !stuffs[objno]->useme;
      }
    
      ppui_refresh( ppui.st );
    
    
    void pp_genericslider_cb(Fl_Value_Slider* sl, void*) { //steven marx: version 0.7.02
      gensliderchg = 1;
      genericslider_setparam();
      gensliderchg = 0;
    }
    
    
    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();
    }
    
    
    slevy's avatar
     
    slevy committed
    void pp_step_cb( Fl_Button * , void *stepsign ) {
    
    slevy's avatar
     
    slevy committed
      double sign = (int)stepsign;
    
      parti_set_running( ppui.st, 0 );
    
    slevy's avatar
     
    slevy committed
      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 );
    
    slevy's avatar
     
    slevy committed
      specks_set_timestep( ppui.st );
    
    slevy's avatar
     
    slevy committed
    }
    
    void pp_run_cb( Fl_Button *runbtn, void *stepsign ) {
      clock_set_fwd( ppui.st->clk, (int)stepsign );
    
      parti_set_running( ppui.st, runbtn->value() );
    
    slevy's avatar
     
    slevy committed
    }
    
    void pp_timeinput_cb( Fl_Input *inp, void * ) {
        double v;
    
    
        parti_set_running( ppui.st, 0 );
    
        if(sscanf(inp->value(), "%lf", &v)) {
    
    slevy's avatar
     
    slevy committed
    	clock_set_time( ppui.st->clk, v + ppui.timebasetime );
    
    	parti_set_timestep( ppui.st, v + ppui.timebasetime );
    	parti_redraw();
        }
    
    slevy's avatar
     
    slevy committed
    }
    
    void pp_timebaseinput_cb( Fl_Input *inp, void * ) {
        double newbase;
    
    
        parti_set_running( ppui.st, 0 );
    
    slevy's avatar
     
    slevy committed
        if(sscanf(inp->value(), "%lf", &newbase)) {
    
    	parti_set_timebase( ppui.st, newbase );
    
    slevy's avatar
     
    slevy committed
    	ppui.timebasetime = newbase;
    
    	parti_redraw();
    
    slevy's avatar
     
    slevy committed
        }
    }
    
    void pp_jog_cb( Fl_Roller *rol, void * ) {
        static double lastrol;
        double v = rol->value();
    
    slevy's avatar
     
    slevy committed
        clock_step( ppui.st->clk, v - lastrol );
    
    slevy's avatar
     
    slevy committed
        lastrol = v;
    
    
        parti_set_running( ppui.st, 0 );
    
    slevy's avatar
     
    slevy committed
        specks_set_timestep( ppui.st );
        parti_set_timestep( ppui.st, clock_time( ppui.st->clk ) );
    
    slevy's avatar
     
    slevy committed
    }
    
    
    void pp_feed_cb( Fl_Light_Button *, void * ) {
        msg("can't feed yet...");
    }
    
    
    slevy's avatar
     
    slevy committed
    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" );
    
    slevy's avatar
     
    slevy committed
    }
    
    void pp_stepspeed_cb( Fl_Log_Slider *spd, void * ) {
        double speed = spd->truevalue();
        clock_set_speed( ppui.st->clk, speed );
    
    slevy's avatar
     
    slevy committed
        clock_set_step( ppui.st->clk, 0.1 * speed );
    
    slevy's avatar
     
    slevy committed
    }
    
    
    void pp_rdata_cb( Fl_Button *, struct stuff ** ) {
      const char *result;
      result = fl_file_chooser("Choose virdir .wf path", "*.wf", NULL);
      if (result)
    
        parti_readpath( result );
    
    }
    
    void pp_playframe_cb( Fl_Counter *counter, struct stuff ** ) {
      if(ppui.playing)
    
      parti_setframe( (int)counter->value() );
    
    }
    
    void pp_playtime_cb( Fl_Value_Slider *slider, struct stuff ** ) {
      struct wfpath *path = &ppui.path;
      if(ppui.playing)
    
      parti_setframe( (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 {
    
    	play->value() ? NULL /*play at default speed*/ 
    
    	);
      }
    }
    
    int pp_viewevent_cb( Fl_Gview *view, int ev ) {
      char snapinfo[1024];
      int fno;
      double bump;
      struct stuff *st = ppui.st;
    
    
    slevy's avatar
    slevy committed
    #define CTRL(x) ((x) & 0x1F)
    
    
      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;
        }
    
    slevy's avatar
     
    slevy committed
        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:
    
    slevy's avatar
     
    slevy committed
    	if(view->num.has)
    	    clock_set_step( st->clk, view->num.fvalue() );
    
    	view->num.has = 0;
    
    slevy's avatar
     
    slevy committed
    	clock_step( st->clk, bump );
    
    	parti_set_running( st, 0 );
    
    slevy's avatar
     
    slevy committed
    	/* clock_notify( st->clk );  NOTYET NOTIFY */
    
    slevy's avatar
     
    slevy committed
    
        case '{':
        case '}':
    	clock_set_fwd( st->clk, key=='}' );
    
    	parti_set_running( st, 1 );
    
    slevy's avatar
     
    slevy committed
    	return 1;
    
        case '~':
    	if(clock_running(st->clk)) {
    
    	    parti_set_running( st, 0 );
    
    	} else {
    	    int fwd = -clock_fwd( st->clk );
    	    clock_set_fwd( st->clk, fwd );
    	    parti_set_fwd( st, fwd );
    
    	    parti_set_running( st, 1 );
    
    slevy's avatar
    slevy committed
        case 'z':
        case 'Z':
    	if(view->num.has) {
    	    specks_set_speed( st, view->num.fvalue() );
    	    view->num.has = 0;
    	} else {
    	    specks_set_speed( st,
    			clock_speed(st->clk) * (key=='z' ? .5 : 2) );
    	}
    	clock_set_step( st->clk, 0.1 * clock_speed(st->clk) );
    	return 1;
    
    slevy's avatar
    slevy committed
        
        case CTRL('K'):
    	if(view->num.has) {
    	    ppui.cmdhist->scaletext( view->num.fvalue() );
    	    view->num.has = 0;
    	}
    	return 1;
    
    
        case CTRL('T'):
    	msg("%.4g fps", ppui.view->fps());
    	return 1;
    
    static void fitlabel( Fl_Widget *w, int excess = 4 ) {
    
    #ifdef __APPLE__
      int width = (int)fl_width( w->label(), strlen(w->label()) ) + excess; //marx added the strlen param
      w->hide();
      w->size( width, w->h() );
      w->show();
    #else
    
      int ofont = fl_font(), osize = fl_size();
      fl_font( w->labelfont(), w->labelsize() );
    
      int width = (int)fl_width( w->label()) + excess; //marx added the strlen param
    
    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.toprow->parent()->redraw();
    
      if(ppui.view->inertia()) ppui.inertiaon->set();
      else ppui.inertiaon->clear();
    
    
      int tno, maxobject = 0;
    
    slevy's avatar
     
    slevy committed
      int timeshown = ppui.steprow->visible();
    
      for(tno = 0; tno < MAXSTUFF; tno++) {
    
    slevy's avatar
     
    slevy committed
        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()->hide();	// force top-level Pack to be redraw()n
    	ppui.steprow->parent()->show(); // for some reason just ->redraw() doesn't.
    
    slevy's avatar
     
    slevy committed
    	timeshown = 1;
        }
    
    
        if(ppui.st == stuffs[tno]) {
    	char oname[12];
    	Fl_Font lfont = ppui.view->movingtarget()
    					? FL_HELVETICA_BOLD_ITALIC
    					: FL_HELVETICA;
    
    
    	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();
    
        ppui.steprow->parent()->hide(); // force top-level Pack to be redraw()n
        ppui.steprow->parent()->show(); // for some reason just ->redraw() doesn't.
    
      }
    
      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->labelfont( b0->labelfont() );
    	    b->labelsize( b0->labelsize() );
    
    	    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 );
    
    	    b->when(FL_WHEN_RELEASE_ALWAYS); //marx: release 0.7.06   - allows data group buttons callback to respond when inflight 
    
    	    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[50], *ep = slumlabel;
      if(parti_get_alias(st)[0]) {
        ep = slumlabel + sprintf(slumlabel, "[%.17s] ", parti_get_alias(st));
      }
      if(by == CONSTVAL) {
        sprintf( ep, "logslum %g", vd->lmin );
      } else if(st->vdesc[cd][by].name[0]) {
        sprintf( ep, "logslum %.10s", vd->name );
      } else {
        sprintf( ep, "logslum(field%d)", by );
      }
    
      if(strcmp(ppui.slum->label(), slumlabel)) {
    
        strcpy(slumlab, slumlabel);
        ppui.slum->label(slumlab);
        ppui.slum->parent()->redraw();
    
    
        //steve marx version 0.7.02 support for generic slider. provides update to generic slider label upon data group change
        int menunum = ppui.sldtype->value();
        if(menunum >= 0 && menunum < NUMSLD && menunum != SLUM)
          genericslider_setparam();
    
      }
    }
    
    
    void pp_viewchanged( Fl_Gview *gview, void *st ) {
      ppui_refresh( ppui.st );
    
    slevy's avatar
    slevy committed
    #if MATT_VIRDIR
      vd_ffn();
    #endif
    
    void pp_hrdiag_on_cb( Fl_Menu_ *menu, void * ) {
      const Fl_Menu_Item *item = menu->mvalue();
    
      if(ppui.hrdiag == NULL || ppui.hrdiagwin == NULL) return;
    
      parti_hrdiag_on( item->value() );
    
    void pp_inertia_on_cb( Fl_Menu_ *menu, void * ) {
      const Fl_Menu_Item *item = menu->mvalue();
      ppui.view->inertia( item->value() );
      msg("inertia %s", ppui.view->inertia() ? "on" : "off");
    
    slevy's avatar
    slevy committed
    #endif /*!FLHACK*/
    
    slevy's avatar
    slevy committed
    int pp_read( struct stuff **, int argc, char *argv[], char *fromfname, void * ) {
        if(!strcmp( argv[0], "subcam")) {
    	if(argc >= 9) {
    	    parti_make_subcam( argv[1], argc-2, argv+2 );
    	} else {
    	    msg("subcam: expected name az el rol L R B T, not %s",
    		rejoinargs( 1, argc, argv ));
    	}
    	return 1;
        }
        return 0;
    }
    
    
    static int whichobjname( const char *str ) {
      if(str == NULL) return -1;
      if(str[0] == '[') str++;
      int objno = -1;
      sscanf(str, "g%d", &objno);
      return objno;
    }
    
    void parti_set_alias( struct stuff *st, char *alias ) {
    
      if(st == NULL) return;
    
      if(alias == NULL) alias = "";
      alias = strdup(alias);
      if(st->alias) free(st->alias);
      st->alias = alias;
    
    #ifndef FLHACK
      int slotno, menuno, btno;
      for(slotno = 0; slotno < MAXSTUFF; slotno++) {
        if(stuffs[slotno] == st) {
    	char lbl[32];
    	sprintf(lbl, "[g%d]%.24s", slotno, alias);
    	for(menuno = ppui.obj->size()-1; --menuno >= 0; ) {
    	    if(whichobjname( ppui.obj->text(menuno) ) == slotno) {
    		ppui.obj->replace( menuno, strdup(lbl) );
    		break;
    	    }
    	}
    
    	sprintf(lbl, alias[0]=='\0' ? "g%d" : "g%d=%.24s", slotno, alias);
    
    	for(btno = ppui.objtogs->children(); --btno >= 0; ) {
    	    Fl_Button *btn = (Fl_Button *)(ppui.objtogs->child(btno));
    	    if(btn && whichobjname( btn->label() ) == slotno) {
    		btn->label( strdup(lbl) );
    		fitlabel( btn, 8 );
    		break;
    	    }
    	}
        }
      }
    #endif /*!FLHACK*/
    }
    
    int vmsg( const char *fmt, va_list args ) {
    
    slevy's avatar
    slevy committed
    #ifdef HAVE_SNPRINTF
      vsnprintf(str, sizeof(str), fmt, args);
    #else
    
      vsprintf(str, fmt, args);
    
    slevy's avatar
    slevy committed
    #endif
    
    
    slevy's avatar
    slevy committed
    #ifndef FLHACK
      if(gensliderchg) //steven marx: version 0.7.02 - we don't want voluminous generic slider output
        return 0;
    
      if(ppui.cmdhist)
        ppui.cmdhist->addline( str, 1 );
    
      return printf("%s\n", str);
    
    slevy's avatar
    slevy committed
    
    #elif defined(EMBEDHACK)
      _pviewmsg = _pviewmsg + str + "\n";
      return 1;
    #else
      return 1;	/* FLHACK but not EMBEDHACK */
    #endif /*FLHACK*/
    
    slevy's avatar
    slevy committed
    int msg( const char *fmt, ... ) {
      int val;
    
    
      va_list args;
      va_start(args, fmt);
    
    slevy's avatar
    slevy committed
      val = vmsg( fmt, args );
      va_end(args);
      return val;
    }
    
    void warn( const char *fmt, ... ) {
    
      va_list args;
      static char avoid[] = "X_ChangeProperty: "; /* ignore spurious X errors */
      if(0==strncmp(fmt, avoid, sizeof(avoid)-1))
         return;
    
      va_start(args, fmt);
      vmsg(fmt, args);
    
    void parti_lighting() {
        static GLuint lightlist = 0;
    
        if(lightlist > 0) {
    	glCallList( lightlist );
    	return;
        }
        lightlist = glGenLists( 1 );
        glNewList( lightlist, GL_COMPILE_AND_EXECUTE );
    
    
        static GLfloat lmambient[] = { 0.1, 0.1, 0.1, 1.0 };
    
        static GLfloat amblight[] = { 0.1,	0.1, 0.1, 1.0 };
        static GLfloat whitelight[] = { 1, 1, 1, 1 };
        static GLfloat Ce[] = { 0, 0, 0, 1 };
    
        static GLfloat Ca[] = { 1, 1, 1, 1 };
    
        static GLfloat Cd[] = { 1, 1, 1, 1 };
        static GLfloat Cs[] = { 1, 1, 1, 1 };
        static GLfloat lightpos[3][4] = {
    		0, 0, -1, 0,
    		1, 0, -.5, 0,
    		0, 1, 0, 0,
        };
    
        glShadeModel( GL_SMOOTH );
    
        glLightModeli( GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE );
    
        glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE );
    
        glLightModelfv( GL_LIGHT_MODEL_AMBIENT, lmambient );
        glDisable( GL_LIGHTING );
    
        int i;
    
        for(i = 0; i < 8; i++)
    	glDisable( GL_LIGHT0+i );
    
    
    slevy's avatar
    slevy committed
        for(i = 0; i < 3; i++) {
    
    	glLightfv( GL_LIGHT0+i, GL_AMBIENT, amblight );
    	glLightfv( GL_LIGHT0+i, GL_SPECULAR, whitelight );
    	glLightfv( GL_LIGHT0+i, GL_DIFFUSE, whitelight );
    	glLightfv( GL_LIGHT0+i, GL_POSITION, lightpos[i] );
    	glEnable( GL_LIGHT0+i );
        }
    
    
        glMaterialfv( GL_FRONT_AND_BACK, GL_EMISSION, Ce );
        glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, Ca );
        glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, Cd );
        glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, Cs );
        glMaterialf( GL_FRONT_AND_BACK, GL_SHININESS, 32.0 );
    
        glColorMaterial( GL_FRONT_AND_BACK, GL_DIFFUSE );
        glDisable( GL_COLOR_MATERIAL );
    
        glEnable( GL_BLEND );
        glBlendFunc( GL_SRC_ALPHA,  GL_ONE_MINUS_SRC_ALPHA );
        glDisable( GL_BLEND );
    
        glEndList();
    }
    
    
    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;
    
      if(ppui.drawtrace)
          (*ppui.drawtrace)();
    
    
      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();
      }
    }
    
    
    void readrc( struct stuff **stp ) {
    
      char *rc = findfile( NULL, "~/.partiviewrc" );
      if(rc) specks_read( stp, rc );
      rc = findfile( NULL, "./.partiviewrc" );
      if(rc) specks_read( stp, rc );
    }
    
    static int cmdargs(int argc, char **argv, int & optind) {
      char *arg = argv[optind];
      if(!strcmp("-c", arg)) {
    
        arg = argv[optind+1];
    
        char *t = NewA(char, strlen(arg)+1);
        char *av[128];
        int ac = tokenize(arg, t, 128, av, NULL);
        specks_parse_args( &ppui.st, ac, av );
        optind += 2;
        return 1;
      }
    
    slevy's avatar
    slevy committed
    
    
      if(!strcmp("-hideui", arg)) {
        ppui.detached = 'h';
        optind++;
        return 1;
      }
    
    slevy's avatar
    slevy committed
      if(!strcmp("-detach", arg)) {
    
        ppui.detached = 'd';
    
    slevy's avatar
    slevy committed
        optind++;
        return 1;
      }
    
    slevy's avatar
    slevy committed
    
    
      if(!strcmp("-geom", arg) || !strcmp("-geometry", arg)) {
        ppui.reqwinsize = NULL;	/* override any initial "winsize" */
        			/* but let fltk parse it anyway */
    
    slevy's avatar
    slevy committed
    int pp_parse_args( struct stuff **, int argc, char *argv[], char *fromfname, void * ) {
    
      if(argc < 1) return 0;
    
      int i;
    
    slevy's avatar
    slevy committed
      if(!strcmp( argv[0], "exit" )) {
          	exit(0);
    
      } else if(!strcmp( argv[0], "stereo" )) {
    
    	for(i = 1; i < argc; i++)
    	    parti_stereo( argv[i] );
    
    	msg("stereo %s", parti_stereo(NULL));
    
      } else if(!strcmp( argv[0], "winsize" )) {
    	msg("winsize %s", parti_winsize( rejoinargs( 1, argc, argv ) ) );
    
      } else if(!strncmp( argv[0], "snapset", 7 ) || !strcmp( argv[0], "snapshot" )) {
    	char *frameno = NULL, *basename = NULL;
    	char *size = NULL;
    	int now = (0 == strcmp(argv[0], "snapshot"));
    	while(argc > 2) {
    	    if(!strcmp(argv[1], "-w")) {
    		size = argv[2];
    	    } else if(!strcmp(argv[1], "-n")) {
    		frameno = argv[2];
    	    } else
    		break;
    	    argc -= 2, argv += 2;
    	}
    	if(argc > 1)
    	    basename = rejoinargs( 1, argc, argv );
    	parti_snapset( basename, frameno, size );
    	if(now) {
    	    char snapinfo[1024]; 
    	    if(parti_snapshot(snapinfo) >= 0)
    		msg("Snapped %s", snapinfo);
    	}
    
      } else if(!strcmp( argv[0], "clip" )) {
    	msg("%s", parti_clip( argv[1], argc>2?argv[2]:NULL ) );
    
      } else if(!strcmp( argv[0], "ortho" )) {
    #ifdef NOTYET
    	int ortho = parti_ortho( argc>1 ? argv[1] : NULL);
    	float fov = parti_fov(NULL);
    
    	msg(ortho ? "ortho on (fov %g units)" : "ortho off (fov %g degrees)");
    
    #endif
    
      } else if(!strcmp( argv[0], "pickrange" )) {
    	float pickrange = parti_pickrange( argv[1] );
    	msg("pickrange %g", parti_pickrange( NULL ));
    
      } else if(!strcmp( argv[0], "fov" ) || !strcmp( argv[0], "fovy" )) {
    	float fovy = parti_fovy( (argc>1) ? argv[1] : NULL );
    	msg("fovy %g", fovy);
    
      } else if(!strcmp( argv[0], "subcam")) {
    	int index;
    	if(argc > 1) {
    	    if(!strcmp(argv[1], "-") || !strcmp(argv[1], "off")) {
    		parti_select_subcam(0);
    	    } else {
    
    		index = parti_make_subcam( argv[1], argc-2, argv+2 );
    
    		if(index > 0) {
    		    parti_select_subcam(index);
    		} else {
    		    char *what = parti_subcam_list();
    		    msg(what[0]=='\0' ?  "No subcams defined yet" :
    					"Known subcams: %s", what);
    		}
    	    }
    	}
    	index = parti_current_subcam();
    	if(index > 0) {
    	    char params[100];
    	    char *name = parti_get_subcam( index, params );
    	    msg("subcam %s  %s # az el rol  L R B T", name, params);
    	} else {
    	    int wx, wy;
    	    float hx, hy = .5 * parti_fovy(NULL);
    	    sscanf( parti_winsize(NULL), "%d%*c%d", &wx, &wy );
    	    if(wy == 0) wy = 1;
    	    hx = atan( tan(hy*(M_PI/180))*wx / wy ) * (180/M_PI);
    	    msg("subcam off  0 0 0  %g %g  %g %g # a e r   L R B T (default)",
    			hx, hx, hy, hy);
    	}
    
    
    slevy's avatar
    slevy committed
      } else if(!strncmp( argv[0], "focallen", 8 )) {
    
    	float focallen = parti_focal( (argc>1) ? argv[1] : NULL );
    	msg("focallength %g", focallen);
    
    slevy's avatar
    slevy committed
    	
      } else if(!strcmp( argv[0], "focalpoint" )) {
            /* args:
    	 * on/off
    	 * x y z [minfocallen]
    	 */
            Point fpt;
    	float minlen;
    
    	int ison = parti_focalpoint( argc-1,  (argv+1), &fpt, &minlen );
    
    slevy's avatar
    slevy committed
    
    	msg(ison ? "focalpoint %g %g %g  %g # pointxyz minfocallen"
    		 : "focalpoint off # %g %g %g  %g # pointxyz minfocallen",
    		 fpt.x[0],fpt.x[1],fpt.x[2], minlen);
    
    
    
      } else if(!strncmp( argv[0], "jump", 4 )) {
    
        Point xyz;
        float aer[3];
        static int stupid[3] = {1,0,2};	/* aer -> rx ry rz */
        Matrix c2w;