Skip to content
Snippets Groups Projects
partibrains.c 189 KiB
Newer Older
teuben's avatar
teuben committed

    while(asyncmd[i] && (none || brackets > 0)) {
	int c = (brackets>0) ? fnextc(asyncmd[i], 1)
			     : async_fnextc(asyncmd[i], 1);
	switch(c) {
	case EOF:
	    if(getenv("DBG")) msg("Closing async %d", i);
#if !CAVEMENU
	    parti_unasyncfd( fileno( asyncmd[i] ) );
#endif
	    pclose(asyncmd[i]);
	    asyncmd[i] = NULL;
	    break;
	case -2: /* NODATA */
	    none = 0;
	    break;
	default:
	    /* Got something.  Assume that we can read a whole line quickly. */
	    if(fgets(buf, sizeof(buf), asyncmd[i]) == NULL) {
		if(getenv("DBG")) msg("fgets: Closing async %d", i);
		pclose(asyncmd[i]);
		asyncmd[i] = NULL;
		break;
	    }
	    nlines++;
	    any++;

	    for(c = 0; isspace(buf[c]) || buf[c] == '{' || buf[c] == '}'; c++) {
		if(buf[c] == '{') brackets++;
		else if(buf[c] == '}' && brackets > 0) brackets--;
		buf[c] = ' ';
	    }
	    if(getenv("DBG")) msg("async %d[%d]{%d}: %s", i, nlines, brackets, buf);
	    ac = tokenize( buf, tbuf, COUNT(av), av, 0 );
	    if(ac > 0) {
teuben's avatar
teuben committed
		none = 0;
#if CAVEMENU
		if(!specks_parse_args( stp, ac, av ))
		    VIDI_queue_commandstr( buf );
teuben's avatar
teuben committed

#else /* non-virdir version */
		parti_redraw();
		specks_parse_args( stp, ac, av );
#endif
	    }

	}
    }
  }
  reentered = 0;
#endif /*unix not WIN32*/
  return any;
}

teuben's avatar
teuben committed
int getbool( char *str, int defval ) {
  int v;
  char *ep;
  if(str == NULL) return defval;

  if(!strcasecmp(str, "on")) return 1;
  if(!strcasecmp(str, "off")) return 0;
slevy's avatar
 
slevy committed
  if(!strcasecmp(str, "toggle")) return !defval;
teuben's avatar
teuben committed
  if(!strcasecmp(str, "all")) return -1;
  v = strtol(str, &ep, 0);
  if(str == ep) return defval;
  return v;
}

slevy's avatar
 
slevy committed
double getfloat( char *str, double defval ) {
  double v;
teuben's avatar
teuben committed
  char *ep;
  int prefix = 0;
  if(str == NULL) return defval;
  if(str[0] == '-' && (str[1] == '=' || str[1] == '-'))	/* -=, -- */
    prefix = *str++;
  if(str[0] == '*' || str[0] == '+' || str[0] == '/' || str[0] == 'x')
    prefix = *str++;
  if(str[0] == '=')
    str++;
  v = strtod(str, &ep);
  if(ep == str) {
    v = defval;
  } else {
    switch(prefix) {
    case '-': v = defval - v; break;
    case '+': v = defval + v; break;
    case '*': v = defval * v; break;
    case '/': v = (v != 0) ? defval / v : 0; break;
    }  /* default: just use v */
  }
  return v;
}

int getfloats( float *v, int nfloats, int arg0, int argc, char **argv ) {
  int i;
  char *ep;
  for(i = 0; i < nfloats && arg0+i < argc; i++) {
    float tv = strtod( argv[arg0+i], &ep );
    if(ep == argv[arg0+i])
	break;
    v[i] = tv;
  }
  return i;
}

void editcmap( struct stuff *st, int ncmap, struct cment *cmap, char *range,
		char *whose, char *colorstr )
{
    int i, min, max;
    char *cp;
    struct cment cm;

    cp = colorstr;
    while(isspace(*cp)) cp++;
    if(*cp == ':' || *cp == '=') {
	char junk;
	do cp++; while(*cp == '=');
	if(sscanf(cp, "%d%c", &i, &junk) != 1) {
	    msg("%s: expected entrynumber(s) := oldindex, not %s", whose, colorstr);
	    return;
	}
	if(i < 0 || i >= ncmap) {
	    msg("%s: clamping index %d to 0..%d", whose, i, ncmap-1);
	    i = (i < 0) ? 0 : ncmap-1;
	}
	cm = cmap[i];
    } else {
	float r, g, b;
	if(sscanf(cp, "%f%f%f", &r,&g,&b) != 3) {
	    msg("%s: expected entrynumber(s) r g b, not %s", whose, colorstr);
	    return;
	}
	cm.raw = PACKRGBA( (int)(r*255), (int)(g*255), (int)(b*255), 0 );
	cm.cooked = specks_cookcment( st, cm.raw );
    }

    for(cp = range; ; cp++) {
	while(isspace(*cp) || *cp == ',') cp++;
	if((i = sscanf(cp, "%d-%d", &min, &max)) > 0) {
	    if(i == 1) max = min;
	} else if((i = sscanf(cp, ">%d", &min)) > 0) {
	    max = ncmap-1;
	} else if((i = sscanf(cp, "<%d", &max)) > 0) {
	    min = 0;
	}
	if(i > 0) {
	    if(min < 0) min = 0;
	    if(max >= ncmap) max = ncmap-1;
	    for(i = min; i <= max; i++)
		cmap[i] = cm;
	}
	while(*cp != ',' && !isspace(*cp)) {
	    if(*cp == '\0') return;
	    cp++;
	}
    }
}
teuben's avatar
teuben committed

int
specks_parse_args( struct stuff **stp, int argc, char *argv[] )
{
  int i;
  struct stuff *st = *stp;

  while( argc>0 &&
	(!strncmp( argv[0], "specks", 4 ) ||
	 !strcmp( argv[0], "feed" ) ||
	 !strcmp( argv[0], "eval" )) ) {
teuben's avatar
teuben committed
    argc--, argv++;
    /* VD_select_menu( specks_menuindex ); */
  }

  if(argc <= 0)
    return 0;

  if( st->dyn.enabled && st->dyn.ctlcmd &&
		(*st->dyn.ctlcmd)( &st->dyn, st, argc, argv ) ) {
    /* OK, dyn command handled it */

  } else if(!strcmp( argv[0], "?" ) || !strcmp( argv[0], "help" )) {
teuben's avatar
teuben committed
    static char *help1[] = {
"specks commands:",
" speed   data-steps per VirDir second",
" step N  -or-  step +N  -or-  step -N  Go to data step N, or step fwd/back",
slevy's avatar
 
slevy committed
" trange on|off|MIN MAX [WRAP]	limit range of datastep times",
" run				toggle auto-play (run/step)",
teuben's avatar
teuben committed
" color VARNO-or-NAME		color particles by VARNO'th variable (0..%d)",
" color const R G B		set all particles to be that color",
" lum   VARNO-or-NAME		tie particle size/luminosity to VARNOth var",
" lum   const LUM		set all particles to be brightness LUM",
" slum  SCALEFACTOR		scale particle brightness by SCALEFACTOR",
" psize SIZE			scale particle brightness by SIZE * SCALEFACTOR",
slevy's avatar
 
slevy committed
" depthsort			sort polygons by depth",
" see   DATASETNO-or-NAME	show that dataset (e.g. \"seedata 0\" or \"seedata gas\")",
teuben's avatar
teuben committed
" read  [-t time] DATAFILENAME	read data file (e.g. to add new specks)",
" ieee  [-t time] IEEEIOFILE	read IEEEIO file (starting at given timestep)",
" sdb   [-t time] SDBFILE	read .sdb star-data file",
" annot [-t time] string	set annotation string (for given timestep)",
slevy's avatar
 
slevy committed
" add  DATAFILECOMMAND		enter a single datafile command (ditto)",
teuben's avatar
teuben committed
" every N			subsample: show every Nth particle",
" bound				show bounds (coordinate range of all particles)",
" clipbox {on | off | X0,X1 Y0,Y1 Z0,Z1 | CENX,Y,Z RADX,Y,Z | X0 Y0 Z0  X1 Y1 Z1} clipping region",
" add box [-n boxno] [-l level] CENX,Y,Z RX,RY,RZ | X0 Y0 Z0 X1 Y1 Z1  marker-box",
" boxlabels                     show box numbers",
" boxaxes                       show R/G/B axes from X0,Y0,Z0 box corner"
#if CAVEMENU
" boxes {off|on|only}		hide/show all AMR boxes",
" {hide|show} LEVELNO ...	hide/show AMR boxes of those levels (or \"all\")",
" {point|polygon|texture} {on|off}",
" fmenu HEIGHT  -or-  fmenu XPOS YPOS  -or- fmenu wall WALLNO",
#else
" readpath  FILENAME.wf		read Wavefront camera path (from virdir \"wfout\")",
" play  SPEED[f]		play path (at SPEED times normal speed)",
"			(with \"f\" suffix, play every SPEEDth frame)",
" frame FRAMENO			go to Nth frame",
" focal FOCALLEN		focal length (determines fly/tran speed)",
" clip  NEAR FAR		clipping distances",
" jump  X Y Z [RX RY RZ]	put viewpoint there",
" center X Y Z			set center of rotation for orbit/rotate",
" censize RADIUS		size of center marker",
teuben's avatar
teuben committed
" snapset  filestem [frameno]	set snapshot parameters",
" snapshot [frameno]		take snapshot [uses convert(1)]",
slevy's avatar
 
slevy committed
" kira {node|ring|size|scale|span|track}  starlab controls; try \"kira ?\"",
teuben's avatar
teuben committed
#endif
    };

    for(i = 0; i < COUNT(help1); i++)
	msg(help1[i], MAXVAL-1);

    if(st->dyn.enabled && st->dyn.help)
	(*st->dyn.help)(&st->dyn, st, 0);
teuben's avatar
teuben committed
  

  } else if(!strcmp( argv[0], "read" )) {
	if(argc > 1) {
	    char *foundfile = findfile( NULL, argv[1] );
	    if(foundfile == NULL)
		msg("%s: read: can't find file %s", argv[1]);
	    else
		specks_read( &st, foundfile );
	}
teuben's avatar
teuben committed

  } else if(!strcmp( argv[0], "include" )) {
#ifdef NOTYET
#endif

  } else if( !strcmp(argv[0], "on") || !strcmp(argv[0], "off")
	    || !strcmp(argv[0], "enable") || !strcmp(argv[0], "disable") ) {

	st->useme = argc>1 ? getbool(argv[1], st->useme) : (argv[0][1]=='n');
	msg(st->useme ? "enabled" : "disabled");
	
  } else if(!strcmp(argv[0], "add")) {
teuben's avatar
teuben committed
	int k, io[2];
	FILE *tf;
	char fdname[64+L_tmpnam];

#ifdef WIN32
	tmpnam(fdname);
	tf = fopen(fdname, "w");
#else /* unix */
	pipe(io);
	sprintf(fdname, "/dev/fd/%d", io[0]);
	tf = fdopen(io[1], "w");
#endif
	if(tf == NULL) {
	    fprintf(stderr, "Yeow: can't make temp file?\n");
	} else {
	    for(k = 1; k < argc; k++)
		fprintf(tf, "%s ", argv[k]);
	    fprintf(tf, "\n");
	    fclose(tf);
	    specks_read( &st, fdname );
#ifdef WIN32
	    unlink(fdname);
#endif
	}

#ifndef WIN32
	close(io[0]);
#endif

  } else if(!strcmp( argv[0], "async" )) {
	char tbuf[5120];
	tbuf[0] = '\0';
	for(i = 1; i < argc; i++)
	    sprintf(tbuf+strlen(tbuf), " %s", argv[i]);
	specks_add_async( st, tbuf );

  } else if(!strcmp( argv[0], "update" )) {
	parti_update();

  } else if(!strcmp( argv[0], "hist" )) {
	register struct specklist *sl;
	register struct speck *sp;
	Point xmin,xmax, mean, mid, radius;
	int nspecks, nclipped, nthreshed, nlow, nhigh, nundefined;
	int clipping = (st->clipbox.level > 0);
	int threshing = st->usethresh & P_USETHRESH;
	int nbuckets = 11;
	int dolog = 0;
	int *bucket;
	float v, vmin, vmax, vrange;
	int histvar;
	int i, k, bno;
	struct valdesc *vd;

	for(i=1,k=1; i+1 < argc; k++) {
	    int yes = argv[i][0] == '-';
	    if(argv[i][0] != '-' && argv[i][1] != '+') break;
	    switch(argv[i][k]) {
		case 't': threshing = yes ? THRESHBIT : 0; break;
		case 'c':
		case 'b': clipping = yes; break;
		case 'n':
		    sscanf(argv[i][++k] ? &argv[i][k] : argv[++i],
			"%d", &nbuckets);
		    i++; k=0;
		    break;
		case 'l': dolog = yes; break;
		case '\0': i++; k=0;
	    }
	}

	if(!specks_set_byvariable( st, argv[i], &histvar )) {
	    msg("hist %s: expected name/index of data variable", argv[i]);
	    return 1;
	}

	vd = &st->vdesc[st->curdata][histvar];
	vmin = vd->min;
	vmax = vd->max;

	if(i+1<argc) sscanf(argv[i+1], "%f", &vmin);
	if(i+2<argc) sscanf(argv[i+2], "%f", &vmax);

	if(vmax < vmin)
	    v = vmax, vmax = vmin, vmin = v;

	if(dolog && (vmin <= 0 || vmax <= 0)) {
	    msg("hist: can't take logs (-l) if range includes zero!");
	    dolog = 0;
	}
	if(dolog) {
	    vmin = log(vmin);
	    vmax = log(vmax);
	}
	vrange = (nbuckets-1) / ((vmax>vmin) ? vmax - vmin : 1);

	if(nbuckets<=0 || nbuckets>20000) {
	    msg("hist -n %d: Incredible number of histogram buckets", nbuckets);
	    return -1;
	}

	bucket = NewA(int, nbuckets);
	memset(bucket, 0, nbuckets*sizeof(int));

	nspecks = nclipped = nthreshed = nundefined = nlow = nhigh = 0;
	for(sl = st->sl; sl != NULL; sl = sl->next) {
	    if((sp = sl->specks) == NULL || sl->text != NULL)
		continue;
	    nspecks += sl->nspecks;
	    if(sl->bytesperspeck < SMALLSPECKSIZE(histvar+1)) {
		nundefined += sl->nspecks;
		continue;
	    }
	    for(i = sl->nspecks; --i >= 0; sp = NextSpeck( sp, sl, 1 )) {
		if(clipping &&
		  (sp->p.x[0] < st->clipbox.p0.x[0] ||
		   sp->p.x[0] > st->clipbox.p1.x[0] ||
		   sp->p.x[1] < st->clipbox.p0.x[1] ||
		   sp->p.x[1] > st->clipbox.p1.x[1] ||
		   sp->p.x[2] < st->clipbox.p0.x[2] ||
		   sp->p.x[2] > st->clipbox.p1.x[2])) {
			nclipped++;
			continue;
		}
		if(threshing & sp->rgba) {
			nthreshed++;
			continue;
		}
		v = sp->val[histvar];
		if(dolog) {
		    if(v <= 0) {
			nundefined++;
			continue;
		    }
		    v = log(v);
		}
		bno = (int) ((v - vmin)*vrange);
		if(bno < 0) nlow++;
		else if(bno >= nbuckets) nhigh++;
		else bucket[bno]++;
	    }
	}
	if(nspecks == 0) {
	    msg("No specks loaded yet");
	} else {
	    msg("hist -n %d %s%s%s%d(%s) %g %g => ",
		nbuckets, dolog?"-l ":"", clipping?"-c ":"", threshing?"-t ":"",
		histvar, vd->name,
		dolog ? exp(vmin) : vmin,
		dolog ? exp(vmax) : vmax);
	    msg("Total %d, %d < min, %d > max, %d undefined, %d clipped, %d threshed",
		nspecks, nlow, nhigh, nundefined, nclipped, nthreshed);
	    k = nlow;
	    msg("%d\t< %g", nlow, dolog ? exp(vmin) : vmin);
	    for(i = 0; i < nbuckets; i++) {
		v = vmin + ( (vrange>0) ? i / vrange : 0 );
		msg("%d\t>= %g", bucket[i], dolog ? exp(v) : v);
	    }
	    msg("%d\t> %g", nhigh, dolog ? exp(vmax) : vmax);
	}


  } else if(!strcmp( argv[0], "bound" )) {
	register struct specklist *sl;
	register struct speck *sp;
	Point xmin,xmax, mean, mid, radius;
	int minmaxk = MAXVAL+1, maxmaxk = 0;
	int nspecks = 0;

	xmin.x[0] = xmin.x[1] = xmin.x[2] = 1e38;
	xmax.x[0] = xmax.x[1] = xmax.x[2] = -1e38;
	mean.x[0] = mean.x[1] = mean.x[2] = 0;
	for(sl = st->sl; sl != NULL; sl = sl->next) {
	    int i, maxk;
	    if((sp = sl->specks) == NULL)
		continue;
	    for(maxk=0; maxk<MAXVAL && SMALLSPECKSIZE(maxk)<sl->bytesperspeck; maxk++)
		;
	    if(minmaxk > maxk) minmaxk = maxk;
	    if(maxmaxk < maxk) maxmaxk = maxk;
	    for(i = sl->nspecks; --i >= 0; sp = NextSpeck( sp, sl, 1 )) {
		if(xmin.x[0] > sp->p.x[0]) xmin.x[0] = sp->p.x[0];
		if(xmax.x[0] < sp->p.x[0]) xmax.x[0] = sp->p.x[0];
		mean.x[0] += sp->p.x[0];
		if(xmin.x[1] > sp->p.x[1]) xmin.x[1] = sp->p.x[1];
		if(xmax.x[1] < sp->p.x[1]) xmax.x[1] = sp->p.x[1];
		mean.x[1] += sp->p.x[1];
		if(xmin.x[2] > sp->p.x[2]) xmin.x[2] = sp->p.x[2];
		if(xmax.x[2] < sp->p.x[2]) xmax.x[2] = sp->p.x[2];
		mean.x[2] += sp->p.x[2];
	    }
	    nspecks += sl->nspecks;
	}
	if(nspecks == 0) {
	    msg("No specks loaded yet");
	} else {
	
	    vscale( &mean, 1.0/nspecks, &mean );
	    vcomb( &mid, .5,&xmin, .5,&xmax );
	    vcomb( &radius, .5,&xmax, -.5,&xmin );
	    msg( "%d specks in range %g %g %g .. %g %g %g",
		nspecks, xmin.x[0],xmin.x[1],xmin.x[2],
		xmax.x[0],xmax.x[1],xmax.x[2]);
	    msg( "midbbox %g %g %g  boxradius %g %g %g",
		mid.x[0],mid.x[1],mid.x[2],
		radius.x[0],radius.x[1],radius.x[2]);
	    msg( "mean %g %g %g", mean.x[0],mean.x[1],mean.x[2] );
	}

  } else if(!strcmp( argv[0], "fspeed" )) {
	if(argc>1) {
teuben's avatar
teuben committed
	    specks_set_fspeed( st, getfloat(argv[1], st->fspeed) );
teuben's avatar
teuben committed
	    st->playnext = 0.0;
	}
	msg("fspeed %g steps per real-time second", st->fspeed);

  } else if(!strcmp( argv[0], "speed" )) {
	if(argc>1)
slevy's avatar
 
slevy committed
	    specks_set_speed( st, getfloat(argv[1], clock_speed(st->clk)) );
	msg("speed %g steps per anim second", clock_speed(st->clk));
teuben's avatar
teuben committed
	
  } else if(!strcmp( argv[0], "run" )) {
slevy's avatar
 
slevy committed
	parti_set_running( st, getbool( argv[1], 1 ) );
teuben's avatar
teuben committed
	st->playnext = 0.0;

slevy's avatar
 
slevy committed
  } else if(!strcmp( argv[0], "depthsort" )) {
	if(argc > 1) st->depthsort = getbool(argv[1], st->depthsort);
	msg("depthsort %s", st->depthsort ? "on" : "off" );

teuben's avatar
teuben committed
  } else if(!strcmp( argv[0], "fade" )) {
	char *fmt = "fade what?";
	if(argc>1) {
	    if(!strncmp(argv[1],"sph",3) || !strncmp(argv[1],"rad",3))
		st->fade = F_SPHERICAL;
	    else if(!strncmp(argv[1],"pla",3))
		st->fade = F_PLANAR;
	    else if(!strncmp(argv[1],"con",3) || !strncmp(argv[1],"ort",3))
		st->fade = F_CONSTANT;
	    else if(!strncmp(argv[1],"knee",3))
		st->fade = F_KNEE12;
	    else if(!strncmp(argv[1],"lin",3))
		st->fade = F_LINEAR;
	    else {
		msg("fade {sph|planar|const|linear|knees}");
		return -1;
	    }
	}
	if(argc>2) sscanf(argv[2], "%f", &st->fadeknee2);
	if(argc>3) sscanf(argv[3], "%f", &st->knee2steep);
	if(argc>4) sscanf(argv[4], "%f", &st->fadeknee1);
	if(argc>5) sscanf(argv[5], "%f%*c%f%*c%f",
			&st->fadecen.x[0], &st->fadecen.x[1], &st->fadecen.x[2]);
	if(argc>6) sscanf(argv[6], "%f", &st->fadecen.x[1]);
	if(argc>7) sscanf(argv[7], "%f", &st->fadecen.x[2]);
	switch(st->fade) {
	case F_SPHERICAL: fmt = "fade spherical  (1/r^2 from eyepoint)"; break;
	case F_PLANAR:    fmt = "fade planar     (1/r^2 from eye plane)"; break;
	case F_CONSTANT:  fmt = "fade const %g   (as if seen at given dist)"; break;
	case F_LINEAR:    fmt = "fade linear %g  (1/r, scaled to match planar at dist)"; break;
	case F_KNEE12:	  fmt = "fade knees %g %g  %g (fardist, steepness, neardist)"; break;
	case F_LREGION:	  fmt = "fade lregion %g  %g %g  %g %g %g (refdist; steepness, Rregion)"; break;
	}
	msg(fmt, st->fadeknee2, st->knee2steep, st->fadeknee1,
		st->fadecen.x[0], st->fadecen.x[1], st->fadecen.x[2]);

  } else if(!strcmp( argv[0], "clipbox" ) || !strcmp( argv[0], "cb" )) {
	Point cen, rad;
	int k;
	switch(argc) {
	case 2:	st->clipbox.level = getbool(argv[1], st->clipbox.level);
		if(!strcmp(argv[1], "hide")) st->clipbox.level = -1;
teuben's avatar
teuben committed
		break;
	case 3: if(3==sscanf(argv[1], "%f%*c%f%*c%f",
				&cen.x[0],&cen.x[1],&cen.x[2])
			&& 0 < (k = sscanf(argv[2], "%f%*c%f%*c%f",
				&rad.x[0],&rad.x[1],&rad.x[2]))) {
		    if(k==1) rad.x[1] = rad.x[2] = rad.x[0];
		    vsub( &st->clipbox.p0, &cen, &rad );
		    vadd( &st->clipbox.p1, &cen, &rad );
		    if(st->clipbox.level==0)
			st->clipbox.level = 1;	/* activate */
teuben's avatar
teuben committed
		} else {
		    msg("clipbox: xmin,xmax ymin,ymax zmin,zmax  or cenx,y,z radiusx,y,z");
		}
		break;
	case 4:
		if(2 == sscanf(argv[1], "%f%*c%f", &cen.x[0], &rad.x[0]) &&
		   2 == sscanf(argv[2], "%f%*c%f", &cen.x[1], &rad.x[1]) &&
		   2 == sscanf(argv[3], "%f%*c%f", &cen.x[2], &rad.x[2])) {
		    st->clipbox.p0 = cen;
		    st->clipbox.p1 = rad;
		    if(st->clipbox.level==0)
			st->clipbox.level = 1;	/* activate */
teuben's avatar
teuben committed
		} else {
		    msg("clipbox: xmin,xmax ymin,ymax zmin,zmax  or cenx,y,z radiusx,y,z");
		}
		break;

	case 7: for(k = 0; k < 3; k++) {
		    if(sscanf(argv[k+1], "%f", &st->clipbox.p0.x[k]) <= 0
			|| sscanf(argv[k+4], "%f", &st->clipbox.p1.x[k]) <= 0)
			break;
		}
		if(k == 3) {
		    if(st->clipbox.level == 0)
			st->clipbox.level = 1;
teuben's avatar
teuben committed
		} else {
		    msg("clipbox: xmin ymin zmin  xmax ymax zmax");
		}
		break;
	default:
		msg("clipbox: on|off|hide | x0,x1 y0,y1 z0,z1 | Cenx,y,z Rx,y,z | x0 y0 z0 x1 y1 z1");
		break;
teuben's avatar
teuben committed
	}
	vcomb( &cen, .5, &st->clipbox.p0, .5, &st->clipbox.p1 );
	vcomb( &rad, -.5, &st->clipbox.p0, .5, &st->clipbox.p1 );
	msg("clipbox %s  (%g,%g  %g,%g  %g,%g  or  %g,%g,%g %g,%g,%g)",
		st->clipbox.level ? (st->clipbox.level<0 ? "hide":"on") :"off",
teuben's avatar
teuben committed
		st->clipbox.p0.x[0], st->clipbox.p1.x[0],
		st->clipbox.p0.x[1], st->clipbox.p1.x[1],
		st->clipbox.p0.x[2], st->clipbox.p1.x[2],
		cen.x[0],cen.x[1],cen.x[2],  rad.x[0],rad.x[1],rad.x[2]);

  } else if(!strcmp( argv[0], "object" ) || sscanf( argv[0], "g%d", &i ) > 0) {
	struct stuff *tst = st;
	int a = argv[0][0]=='g' ? 0 : 1;
	char *ep;
	i = parti_object( argv[a], &tst, 0 );
	ep = argv[a] ? strchr(argv[a], '=') : NULL;

	if(a && argc==1) {
	    msg(tst->alias ? "object g%d=%s" : "object g%d", i, tst->alias);

	} else if(i<0) {
	    /* never mind */

	} else if(ep) {
	    parti_set_alias( tst, ep+1 );
	    msg("g%d = %s", i, ep+1);

	} else if(a+2 == argc && argv[a+1][0] == '=') {
	    parti_set_alias( tst, argv[a+2] );
	    msg("g%d = %s", i, argv[a+2]);

	} else if(a+1 < argc) {
	    specks_parse_args( &tst, argc-a-1, argv+a+1 );

teuben's avatar
teuben committed
	} else {
	    char *alias = parti_get_alias( tst );
teuben's avatar
teuben committed
	    st = tst;
	    msg(alias ? "object g%d=%s selected (%d particles)" :
			"object g%d%.0s selected (%d particles)",
		i, alias,
teuben's avatar
teuben committed
		specks_count( st->sl ));
	}

slevy's avatar
 
slevy committed
  } else if(!strcmp( argv[0], "gall" ) || !strncmp( argv[0], "allobj", 6 )) {
	int verbose = (argc>1 && !strcmp(argv[1], "-v"));
	parti_allobjs( argc-1-verbose, argv+1+verbose, verbose );
teuben's avatar
teuben committed

  } else if(!strcmp(argv[0], "tfm")) {
	int inv = 0;
	int mulWorldside = 0, mulObjside = 0;
	int hpr = 0;
	int calc = 0;
	int any, more, a0;
	float scl;
	Matrix ot, t;
	Point xyz;
	float aer[3];
	char *key;

	i = 1;
	key = argv[i];
	if(key == NULL) key = "";
	for(more = 1; *key != '\0' && more; key++) {
	  switch(*key) {
	  case '=': break;
	  case '*': mulWorldside = 1; break;
	  case '/': inv = 1; break;
	  case 'h': case 'p': case 'r': hpr = 1; break;
	  case ' ': case '\t': break;
	  case '\0':
		if(i < argc-1) {
		    key = argv[++i];
		    break;
		}
		/* else fall into default */
	  default: more = 0; key--; break;
	  }
	}

	parti_geto2w( st, parti_object( NULL, &st, 0 ), &ot );
teuben's avatar
teuben committed

	
	a0 = i;
	argv[a0] = key;
	for(any = 0; any < 16 && a0+any<argc
			&& sscanf(argv[a0+any], "%f", &t.m[any]) > 0; any++)
		;
	switch(any) {
	case 1:
		scl = t.m[0];
		t = Tidentity;
		t.m[0*4+0] = t.m[1*4+1] = t.m[2*4+2] = scl;
		break;
	case 6:
	case 7:		/* ignore fovy if included */
		xyz = *(Point *)&t.m[0];
		if(hpr) {
		    aer[0] = t.m[3], aer[1] = t.m[4], aer[2] = t.m[5];
		} else {
		    /* Note we permute: px py pz rx ry rz == px py pz e a r */
		    aer[1] = t.m[3], aer[0] = t.m[4], aer[2] = t.m[5];
		}
		xyzaer2tfm( &t, &xyz, aer );
		break;

	case 16: break;
	case 0:  t = ot; break;
	default:
	    msg("Usage: tfm [*] [/] [\"hpr\"] [16 numbers or 6 numbers] [=]");
	    return -1;
	}

	for(i = a0+any-1; i < argc; i++) {
	    if(strchr(argv[i], '=')) calc = 1;
	    if(strchr(argv[i], '*')) mulObjside = 1;
	}

	if(any) {
	    if(inv)
		eucinv( &t, &t );
	    if(mulWorldside)
		mmmul( &t, &ot, &t );
	    if(mulObjside)
		mmmul( &t, &t, &ot );

	    /* with trailing '=', just print result without assignment */

	    if(!calc)
		parti_seto2w( st, parti_object( NULL, &st, 0 ), &t );
teuben's avatar
teuben committed
	}

	tfm2xyzaer( &xyz, aer, &t );
	msg("obj2w:  x y z %s   %g %g %g  %g %g %g",  hpr?"h p r":"rx ry rz",
		xyz.x[0],xyz.x[1],xyz.x[2],  aer[1-hpr],aer[hpr],aer[2] );
	for(i = 0; i < 3; i++)
	    msg(" %10.7f %10.7f %10.7f %10.7f", t.m[i*4+0],t.m[i*4+1],t.m[i*4+2],t.m[i*4+3]);
	msg(" %10.7g %10.7g %10.7g %10.7g", t.m[3*4+0],t.m[3*4+1],t.m[3*4+2],t.m[3*4+3]);
	eucinv( &t, &t );
	tfm2xyzaer( &xyz, aer, &t );
	msg("w2obj:  x y z %s   %g %g %g  %g %g %g",  hpr?"h p r":"rx ry rz",
		xyz.x[0],xyz.x[1],xyz.x[2],  aer[1-hpr],aer[hpr],aer[2] );
	for(i = 0; i < 3; i++)
	    msg(" %10.7f %10.7f %10.7f %10.7f", t.m[i*4+0],t.m[i*4+1],t.m[i*4+2],t.m[i*4+3]);
	msg(" %10.7g %10.7g %10.7g %10.7g", t.m[3*4+0],t.m[3*4+1],t.m[3*4+2],t.m[3*4+3]);

  } else if(!strcmp( argv[0], "bgcolor" )) {
	char *result, given[64];
	if(argc == 4) {
	    sprintf(given, "%.10s,%.10s,%.10s", argv[1],argv[2],argv[3]);
	    result = parti_bgcolor( given );
	} else {
	    result = parti_bgcolor( argv[1] );
	}
	msg("bgcolor %s", result);

	    
#if !CAVEMENU
	/* virdir emulation */

  } 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 ) ) );

teuben's avatar
teuben committed
  } else if(!strncmp( argv[0], "snapset", 7 ) || !strcmp( argv[0], "snapshot" )) {
	char *frameno = NULL, *basename = NULL;
	char *tail = 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;
	if(argc > 1)
	    basename = rejoinargs( 1, argc, argv );
	parti_snapset( basename, frameno, size );
teuben's avatar
teuben committed
	    char snapinfo[1024]; 
	    if(parti_snapshot(snapinfo) >= 0)
		msg("Snapped %s", snapinfo);
	}

  } else if(!strcmp( argv[0], "move" ) || !strcmp( argv[0], "move-objects" )) {
	i = parti_move( argv[1], &st );
	msg(i>=0 ? "move-objects on ; g%d selected" : "move-objects off", i);
	    
  } 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 ));

teuben's avatar
teuben committed
  } 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);
	}

teuben's avatar
teuben committed
  } else if(!strncmp( argv[0], "focal", 5 )) {
	float focallen = parti_focal( (argc>1) ? argv[1] : NULL );
	msg("focallength %g", focallen);

  } 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;
	parti_getc2w( &c2w );
	tfm2xyzaer( &xyz, aer, &c2w );
	if(argc>1) {
	    for(i=1; i<argc && i<4+3; i++) {
		if(i-1<3) xyz.x[i-1] = getfloat(argv[i], xyz.x[i-1]);
		else aer[stupid[i-4]] = getfloat(argv[i], aer[stupid[i-4]]);
	    }
	    xyzaer2tfm( &c2w, &xyz, aer );
	    parti_setc2w( &c2w );
	}
	msg("jump %g %g %g  %g %g %g  (XYZ RxRyRz)",
		xyz.x[0],xyz.x[1],xyz.x[2],
		aer[1],aer[0],aer[2]);

  } else if((!strcmp( argv[0], "rdata" ) || !strcmp(argv[0], "readpath"))
		&& argc>1) {
	char *tfname = argv[1];
	char *realfile = findfile( NULL, tfname );
	if(realfile == NULL) {
	    tfname = (char *)alloca(strlen(argv[1]) + 32);
	    sprintf(tfname, "data/record/%s%s", argv[1],
		strstr(argv[1], ".wf") ? "" : ".wf");
	    realfile = findfile( NULL, tfname+12 );
	}
	if(realfile == NULL)
	    realfile = findfile( NULL, tfname );
	if(realfile)
	    parti_readpath( st, realfile );
	else
	    msg("%s: can't find \"%s\" nor data/record/... nor ...wf",
		argv[0],argv[1]);

  } else if(!strcmp( argv[0], "play" )) {
	parti_play( st, argc>1 ? argv[1] : NULL );

  } else if(!strcmp( argv[0], "frame" )) {
slevy's avatar
slevy committed
	CONST struct wfpath *pp;
teuben's avatar
teuben committed
	i = parti_frame( st, argv[1], &pp );
	msg("frame %d (of %d..%d)", pp->curframe,
		pp->frame0, pp->nframes + pp->frame0 - 1);

  } else if(!strcmp( argv[0], "interest") || !strcmp( argv[0], "int" ) ||
		!strcmp( argv[0], "center" ) ||
		!strcmp( argv[0], "cen" )) {
	Point cen;
	float censize = parti_getcensize();
	parti_getcenter( &cen );
	if(argc > 1) {
	    sscanf(argv[1], "%f%*c%f%*c%f%*c%f",
		&cen.x[0],&cen.x[1],&cen.x[2], &censize);
	    if(argc > 3)
		for(i=0;i<3;i++)
		    cen.x[i] = getfloat(argv[i+1], cen.x[i]);
	    if(argc == 3 || argc == 5)
		sscanf(argv[argc-1], "%f", &censize);
	    parti_center( &cen );
	    if(censize != parti_getcensize())
		parti_censize( censize );
	}
#if CAVEMENU
	msg("center %g %g %g", cen.x[0],cen.x[1],cen.x[2]);
#else
	msg("center %g %g %g  %g(radius)", cen.x[0],cen.x[1],cen.x[2], censize);
#endif
  } else if(!strcmp( argv[0], "censize" )) {
	if(argc>1)
	    parti_censize( getfloat(argv[1], parti_getcensize()));
	msg("censize %g  (interest-marker size)", parti_getcensize());

#endif /*non-CAVEMENU*/

#if MATT_VIRDIR
  } else if(!strcmp( argv[0], "time" )) {
	float newnow, now;
	if(argc > 1 && sscanf(argv[1], "%f", &newnow) > 0)
	    now = vd_camera_time( &newnow );
	else 
	    now = vd_camera_time( NULL );
	msg("time %g", now);

  } else if(!strcmp( argv[0], "key" )) {
	int curkey;
	if(argc == 1) {
	    curkey = vd_create_key();
	} else {
	    curkey = vd_select_key( atoi(argv[1]), 0 );
	}
	msg("key %d", curkey);

  } else if(!strcmp( argv[0], "attach" )) {
	vd_attach( getbool( argv[1], 1 ) );

  } else if(!strcmp( argv[0], "rem" )) {
	vd_remove_key( argc, argv );
  
#endif /* MATT_VIRDIR */

  } else if(!strcmp( argv[0], "step" )) {
slevy's avatar
 
slevy committed
	if(argc>1) {
	    if(argv[1][0] == '+') {
		if(argv[1][1] != '\0')
		    clock_set_step( st->clk, getfloat(&argv[1][1], 0) );
		clock_step( st->clk, 1 );
	    } else if(!strcmp(argv[1], "-")) {
		clock_step( st->clk, -1 );
	    } else {
		clock_set_time( st->clk, getfloat(argv[1], 0) );
	    }
teuben's avatar
teuben committed
	}
slevy's avatar
 
slevy committed

teuben's avatar
teuben committed

#if !CAVEMENU
slevy's avatar
 
slevy committed
	parti_set_running( st, 0 );
	specks_set_timestep(st);
teuben's avatar
teuben committed
#endif
teuben's avatar
teuben committed
	msg("step %g", st->currealtime);
teuben's avatar
teuben committed

slevy's avatar
 
slevy committed
  } else if(!strcmp( argv[0], "trange" ) || !strcmp( argv[0], "steprange" )) {
	double utmin = st->utmin;
	double utmax = st->utmax;
	double utwrap = st->utwrap;
	if(argc>1) {
	    if(!strcmp(argv[1],"on")) st->usertrange = 1;
	    else if(!strcmp(argv[1],"off")) st->usertrange = 0;
	    else {
		st->utmin = getfloat( argv[1], utmin );
		if(argc>2) st->utmax = getfloat( argv[2], utmax );
		if(argc>3) st->utwrap = getfloat( argv[3], utwrap );
		if(utmin != st->utmin || utmax != st->utmax)
		    st->usertrange = 1;
	    }
	}
	msg(st->usertrange ?
	    "trange %lg %lg  %lg (tmin tmax twrap)"
	  : "trange off   (%lg %lg  %lg  tmin tmax twrap)",
		st->utmin, st->utmax, st->utwrap);
slevy's avatar
 
slevy committed

teuben's avatar
teuben committed
  } else if(!strcmp( argv[0], "fwd" )) {
slevy's avatar
 
slevy committed
	if(argc>1)
	    clock_set_fwd( st->clk, getbool(argv[1], 1) );
	IFMENU( set_fwd( clock_fwd(st->clk), ment.fwd, st ) );
teuben's avatar
teuben committed

  } else if(!strcmp( argv[0], "gscale" )) {
	if(argc>1) sscanf(argv[1], "%f", &st->gscale);
	msg("gscale %g (scaling particles), then translating by %g %g %g",
		st->gscale, st->gtrans.x[0],st->gtrans.x[1],st->gtrans.x[2]);

  } else if(!strcmp( argv[0], "clearobj" )) {
	struct specklist **slp;
	struct mesh *m, *nm;
	struct ellipsoid *e, *ne;
teuben's avatar
teuben committed
	slp = specks_timespecksptr( st, st->curdata, st->curtime );
	specks_discard( st, slp );
	st->sl = *slp;
	for(m = st->staticmeshes, st->staticmeshes = NULL; m; m = nm) {
	    nm = m->next;
	    Free(m);
	}
	for(e = st->staticellipsoids, st->staticellipsoids = NULL; e; e = ne) {
	    ne = e->next;
	    Free(e);
	}
teuben's avatar
teuben committed

  } else if(!strcmp( argv[0], "every" )) {
	if(argc>1) sscanf(argv[1], "%d", &st->subsample);
	if(st->subsample <= 0) st->subsample = 1;
	msg("display every %dth particle (of %d)",
			st->subsample, specks_count(st->sl));

slevy's avatar
 
slevy committed
  } else if(!strncmp( argv[0], "everycomp", 9 )) {
	st->everycomp = getbool(argv[1], st->everycomp);
	msg("everycomp %d (%s compensate for \"every\" subsampling)",
		st->everycomp,
		st->everycomp ? "do" : "don't");

teuben's avatar
teuben committed
  } else if(!strncmp( argv[0], "color", 5 )) {
	struct valdesc *vd;
	if(argc>1) {
	    if(!specks_set_byvariable( st, argv[1], &st->coloredby ))
		st->coloredby = CONSTVAL;