Skip to content
Snippets Groups Projects
partibrains.c 189 KiB
Newer Older
    case SEL_THRESH: what = "thresh"; break;
    case SEL_PICK: what = "pick"; break;
    default:
	if(selno > 0 && selno <= MAXSEL && st->selitems[selno-1].name[0] != '\0')
	    what = &st->selitems[selno-1].name[0];
	else {
	    sprintf(s, "%d", selno<0||selno>MAXSEL?0:selno);
	    what = s;
	}
    }
    if(preop)
	*from++ = preop;
    return from + sprintf(from, "%.15s ", what);
}


char *show_selexpr( struct stuff *st, SelOp *destp, SelOp *srcp )
{
    char str[(MAXSELNAME + 2)*33];
    char *tail = str;
    static char *sstr;
    static int sroom = -1;
    int i;

    if(destp) {
	if(destp->wanted == 0) {
	    tail = selcat(st, tail, SEL_ALL, 0 );
	} else {
	    for(i = SEL_THRESH; i > 0; i--) {
		if(~destp->wanted & SELMASK(i)) {
		    tail = selcat( st, tail, i,
				destp->wanton & SELMASK(i) ? 0 : '-' );
		} else if(destp->wanton & SELMASK(i)) {
		    tail = selcat( st, tail, i, '^' );
		}
	    }
	}
	if(srcp)
	    tail += sprintf(tail, "= ");
	if(srcp->use == SEL_NONE || srcp->use == SEL_ALL) {
	    tail = selcat( st, tail, srcp->use, 0 );
	} else {
	    for(i = SEL_THRESH; i > 0; i--) {
		if(srcp->wanted & SELMASK(i)) {
		    tail = selcat( st, tail, i,
				srcp->wanton & SELMASK(i) ? 0 : '-' );
		} else if(srcp->wanton & SELMASK(i)) {
		    tail = selcat( st, tail, i, '^' );
		}
	    }
	}
    }
    if(tail - str > sroom) {
	if(sstr) Free(sstr);
	sroom = tail - str + 60;
	sstr = NewN( char, sroom );
    }
    if(tail == str) strcpy(sstr, "null");
    else {
	tail[-1] = '\0';
	strcpy(sstr, str);
    }
    return sstr;
}

enum SelToken {
    SEL_ERR,		/* unknown */
    SEL_EOF,
    SEL_WORD,		/* bare word or +word */
    SEL_EQUALS		/* = */
};

static enum SelToken seltoken( char **sp, int *leadcp, char word[MAXSELNAME] ) {
    char *p = *sp;
    int k;
    *leadcp = '\0';
    word[0] = '\0';
    while(isspace(*p)) p++;
    if(*p == '\0')
	return SEL_EOF;
    if(*p == '-' || *p == '^' || *p == '+')
	*leadcp = *p++;
    if(*p == '=') {
	*sp = p+1;
	return SEL_EQUALS;
    }
    if(!(isalnum(*p) || *p == '_'))
	return SEL_ERR;
    word[0] = *p++;
    for(k = 1; isalnum(*p) || *p == '_'; p++) {
	if(k < MAXSELNAME-1) word[k++] = *p;
    }
    word[k] = '\0';
    *sp = p;
    return SEL_WORD;
void seldest2src( struct stuff *st, CONST SelOp *dest, SelOp *src ) {
    selinit( src );
    if(dest->use == SEL_USE) {
	src->wanted = ~dest->wanted | dest->wanton;
	src->wanton = dest->wanton;
    }
}

void selsrc2dest( struct stuff *st, CONST SelOp *src, SelOp *dest ) {
    *dest = *src;
    if(src->use == SEL_USE) {
	dest->wanted = ~src->wanted;
	dest->wanton = src->wanton & src->wanted;
	dest->use = SEL_DEST;
    }
}

void seldestinvert( struct stuff *st, SelOp *dest ) {
    dest->wanton ^= ~dest->wanted;
}

int seldest( struct stuff *st, SelOp *dest, int selno, int selch ) {
    SelMask mask;
    if(dest == NULL)
	return 0;
    if(selno == SEL_ALL) {
	mask = ~0;
    } else if(selno <= 0 || selno > 32) {
	return 0;
    } else {
	mask = SELMASK(selno);
    }
    if(dest->use != SEL_DEST) {
	dest->use = SEL_DEST;
	dest->wanted = ~0;
	dest->wanton = 0;
    }
    switch(selch) {
    case '^':
	dest->wanted |= mask;
	dest->wanton |= mask;
	break;
    case '-':
	dest->wanted &= ~mask;
	dest->wanton &= ~mask;
	break;
    case '+':
    case '\0':
	dest->wanted &= ~mask;
	dest->wanton |= mask;
	break;
    default:
int selsrc( struct stuff *st, SelOp *src, int selno, int selch ) {
    SelMask mask;
    if(src == NULL)
	return 0;
    if(src->use == SEL_DEST) {
	src->wanted = 0;
	src->wanton = 0;
	src->use = SEL_USE;
    }
    if(selno == SEL_OFF) {
	src->wanted = src->wanton = mask = ~0;
	src->use = SEL_NONE;
    } else if(selno == SEL_ALL) {
	src->wanted = src->wanton = mask = 0;
	src->use = SEL_ALL;
    } else if(selno > 0 && selno <= 32) {
	mask = SELMASK(selno);
	src->use = SEL_USE;
    } else {
	return 0;
    }
    switch(selch) {
    case '-':
	src->wanted |= mask;
	src->wanton &= ~mask;
	break;
    case '+':
    case '\0':
	src->wanted |= mask;
	src->wanton |= mask;
	break;
    default:
	return 0;
    }
    return 1;
}
/*
 * [word [op]=] { [op]word }*
 */
int parse_selexpr( struct stuff *st, char *str, SelOp *destp, SelOp *srcp, char *plaint )
{
  SelOp dest, src;
  char wd[MAXSELNAME], w[MAXSELNAME];
  char *p = str;
  int leadc, leadc2;
  enum SelToken tok, tok2, tok3;
  int ok = 1;
  int anysrc = 0, anydest = 0;

  selinit(&dest); selinit(&src);
  tok = seltoken( &p, &leadc, wd );
  if(tok == SEL_EOF)
      return 0;
  if(destp) {
      /* Had better begin with a word, and with no prefix */
    int destno;
    if(tok != SEL_WORD) goto fail;
    destno = selname( st, wd, 1 );
    tok2 = seltoken( &p, &leadc2, w );
    if(tok2 == SEL_ERR) goto fail;
    ok = seldest( st, &dest, destno, leadc ? leadc : leadc2 );
    anydest = 1;
    if(!ok) goto fail;
    if(tok2 == SEL_WORD) {
	tok = SEL_WORD;
	leadc = leadc2;
	strcpy(wd, w);
    } else {
	tok = seltoken( &p, &leadc, wd );
    }
  }
  while(srcp && tok == SEL_WORD) {
    ok = selsrc( st, &src, selname( st, wd, 0 ), leadc );
    if(!ok) goto fail;
    if(src.use == SEL_NONE && src.wanted != 0 && destp) {
	seldestinvert( st, &dest );
	selsrc( st, &src, SEL_ALL, 0 );	/* X = off  <=> -X = on */
    }
    anysrc = 1;
    tok = seltoken( &p, &leadc, wd );
  if(tok != SEL_EOF)
      goto fail;
  if(!anysrc && !anydest)
      return 0;
  if(destp && anydest) *destp = dest;
  if(srcp && anysrc) *srcp = src;
  return 1;

fail:
  if(plaint)
      msg("%s: um, %s", plaint, str);
  return 0; /*XXX*/
}

CONST char *selcounts( struct stuff *st, struct specklist *sl, SelOp *selp ) {
    int i;
    static char counts[24];
    int yes, total;
    SelOp selop;

    if(selp == NULL) return "";
    if(selp->use == SEL_DEST)
	seldest2src( st, selp, &selop );
    else
	selop = *selp;
    for(yes = total = 0; sl != NULL; sl = sl->next) {
	SelMask *sel = sl->sel;
	if(sl->text != NULL || sl->nsel < sl->nspecks || sl->special != SPECKS)
	    continue;
	total += sl->nspecks;
	for(i = 0; i < sl->nspecks; i++)
	    if(SELECTED(sel[i], &selop))
		yes++;
    }
    if(selop.use == SEL_NONE) yes = 0;
    sprintf(counts, "%d of %d", yes, total);
    return counts;
}

SpecksPickFunc specks_all_picks( struct stuff *st, SpecksPickFunc func, void *arg ) {
    SpecksPickFunc was = st->picked;
    st->picked = func;
    st->pickinfo = arg;
    return was;
}
teuben's avatar
teuben committed

#if CAVE

void parti_seto2w( struct stuff *st, int objno, CONST Matrix *newTo2w ) {
    st->objTo2w = *newTo2w;	/* ignores objno -- there's only one right now! */
}

void parti_geto2w( struct stuff *st, int objno, Matrix *curTo2w ) {
    *curTo2w = st->objTo2w;	/* ignores objno -- there's only one right now! */
}
    
void specks_display( struct stuff *st )
{
    int showmenus;
    int menuhit = 0;
slevy's avatar
 
slevy committed
    int empty = st->ntimes == 0 && st->sl == NULL;
teuben's avatar
teuben committed
    static int hidescene;

    if( CAT_dsp_mode == APP_DSP_NORMAL ) {

#if !(MENU_IN_PPR)
	if( CAVEEye == CAVE_LEFT_EYE ) {
	    menu_check( pmenu, pmenu->cavewall );
	    menu_check( stubmenu, stubmenu->cavewall );

slevy's avatar
 
slevy committed
	    menu_sethidden( pmenu, st->hidemenu || empty );
	    menu_sethidden( stubmenu, st->hidemenu<=0 || empty );
teuben's avatar
teuben committed
	}
#endif

	glPushMatrix();
	/* The following only works if our transformation is exactly the
	 * Cave nav transform, i.e. if the CAT system hasn't
	 * translated us further; but that's true for this app.
	 */
	CAVENavInverseTransform();

	menu_draw( pmenu );

	if(!pmenu->hidden) {
	    menuhit = (pmenu->wallhit > 0);
	    menu_setpos( stubmenu, ment.menu->x0, ment.menu->y0 );
	}
	menu_draw( stubmenu );

	glPopMatrix();

    }

    if(hidescene && !menuhit)
	hidescene = 0;
    if(menuhit && *CAVEFramesPerSecond < st->menudemandfps)
	hidescene = 1;		/* Don't draw scene if too slow to operate menu easily */
    if(hidescene)
	return;

    glPushMatrix();
    glTranslatef( st->gtrans.x[0], st->gtrans.x[1], st->gtrans.x[2] );
    glScalef( st->gscale, st->gscale, st->gscale );
    glMultMatrixf( st->objTo2w.m );
    drawspecks( st );
    glPopMatrix();
}
#endif /*NOCAVE*/

static void addchunk( struct stuff *st, int nsp, int bytesperspeck,
			float scaledby, struct speck *sp, char *text,
			int outbytesperspeck )
{
    struct specklist **slp, *sl = NewN( struct specklist, 1 );
    memset( sl, 0, sizeof(*sl) );
    sl->speckseq = ++st->speckseq;
teuben's avatar
teuben committed

    sl->bytesperspeck = outbytesperspeck;

    sl->specks = NewNSpeck( sl, nsp );
    sl->nspecks = nsp;
    sl->scaledby = scaledby;
    if(text) {
	sl->text = NewN( char, strlen(text)+1 );
	strcpy(sl->text, text);
    } else {
	sl->text = NULL;
    }
    if(bytesperspeck == outbytesperspeck) {
	memcpy( sl->specks, sp, nsp*sl->bytesperspeck );
    } else {
	int i;
	for(i = 0; i < nsp; i++)
	    memcpy(((char *)sl->specks) + i*outbytesperspeck,
		   ((char *)sp) + i*bytesperspeck,
		   outbytesperspeck);
    }
    sl->sel = NewN( SelMask, nsp );
    sl->nsel = nsp;
    memset(sl->sel, 0, nsp*sizeof(SelMask));

teuben's avatar
teuben committed
    slp = specks_timespecksptr(st, st->curdata, st->datatime);
    sl->next = *slp;
    *slp = sl;
    st->sl = specks_timespecks(st, st->curdata, st->curtime); /* in case it changed */
    sl->colorseq = -1;		/* Force recomputing colors */
    sl->sizeseq = -1;		/* Force recomputing sizes */
}

int specks_count( struct specklist *sl ) {
    int n;
    for(n = 0; sl != NULL; sl = sl->next)
	if(sl->text == NULL)
	    n += sl->nspecks * (sl->subsampled>0 ? sl->subsampled : 1);
    return n;
}

teuben's avatar
teuben committed
static float speckscale = 1;

#define LINEBUFSIZE 2048

static char *getline(FILE *f, char *buf) {
  buf[0] = '\0';
  while(fgets(buf, LINEBUFSIZE, f) != NULL) {
    char *cp = buf;
    while(isspace(*cp)) cp++;
    if(*cp != '#' && *cp != '\0')
	return cp;
  }
  return NULL;
}

int tokenize(char *str, char *tbuf, int maxargs, char **argv, char **commentp)
{
  register char *ip = str;
  register char *op = tbuf;
  int argc = 0;

  if(commentp) *commentp = NULL;

  while(argc < maxargs-1) {
    while(isspace(*ip)) ip++;
    if(*ip == '\0') goto eol;
    argv[argc++] = op;
    switch(*ip) {
    case '#':
	if(commentp != NULL) {
	    *commentp = op;
	    while(*ip && *ip != '\n' && *ip != '\r')
		*op++ = *ip++;
	    *op = '\0';
	}
	goto eol;

    case '"':
	while(*ip != '"') {
	    if(*ip == '\\') ip++;
	    if(*ip == '\0') goto eol;
	    *op++ = *ip++;
	}
	break;

    case '\'':
	while(*ip != '\'') {
	    if(*ip == '\\') ip++;
	    if(*ip == '\0') goto eol;
	    *op++ = *ip++;
	}
	break;

    default:
	while(!isspace(*ip)) {
	    if(*ip == '\\') ip++;
	    if(*ip == '\0') goto eol;
	    *op++ = *ip++;
	}
	break;
    }
    *op++ = '\0';
  }
  /* oh no, too many entries for argv[] array --
   * leave all remaining chars in last argument.
   */
  strcpy(op, ip);
  argv[argc++] = op;
 eol:
  *op = '\0';
  argv[argc] = NULL;
  return argc;
}

char *rejoinargs( int arg0, int argc, char **argv )
{
  int k;
  if(arg0 >= argc)
    return "";
  for(k = argc; --k > arg0; ) {
    if(&argv[k][-1] == argv[k-1] + strlen(argv[k-1]))
	argv[k][-1] = ' ';
  }
  return argv[arg0];
}
 
static enum SurfStyle getstyle( char *str )
{
  if(str == NULL || !strcmp(str, "solid") || !strncmp(str, "fill", 4)
		 || !strncmp(str, "poly", 4))
  if(!strncmp(str, "wire", 4) || !strncmp(str, "line", 4))
  if(!strncmp(str, "plane", 5) || !strncmp(str, "ax", 2))
  if(!strncmp(str, "point", 5))
  if(!strcmp(str, "off"))
  msg("Unknown surface style \"%s\": want solid|line|plane|point|off", str);
}

/*
 * Xcen Ycen Zcen ellipsoid [-t txno] [-c cindex] [-s surfstyle] [-n nu[,nv]] [-r sizex[,y,z]] [0-or-9-or-16-numbers-tfm]
 */
void specks_read_ellipsoid( struct stuff *st, Point *pos, int argc, char **argv, char *comment ) {
  int i;
  struct ellipsoid e, *ep;
  float m3[3*3];
slevy's avatar
slevy committed
  float rxyz[3];

  memset(&e, 0, sizeof(e));
  e.cindex = -1;
  e.pos = *pos;
  e.size.x[0] = e.size.x[1] = e.size.x[2] = 1;

  if(comment) {
    e.title = (comment[1] == ' ') ? comment+2 : comment+1;
  }

  for(i = 1; i+1 < argc; i += 2) {
    if(!strncmp(argv[i], "-c", 2)) {
	sscanf(argv[i+1], "%d", &e.cindex);
    } else if(!strncmp(argv[i], "-s", 2)) {
	e.style = getstyle(argv[i+1]);
    } else if(!strcmp(argv[i], "-r")) {
	int k = sscanf(argv[i+1], "%f%*c%f%*c%f", &e.size.x[0],&e.size.x[1],&e.size.x[2]);
	switch(k) {
	case 1: e.size.x[2] = e.size.x[1] = e.size.x[0]; break;
	case 3: break;
	default: msg("ellipsoid -r: expected 1 or 3 comma-separated semimajor axes not %s", argv[i+1]);
	}
    } else if(!strcmp(argv[i], "-n")) {
	int k = sscanf(argv[i+1], "%d%*c%d", &e.nu, &e.nv);
	switch(k) {
	case 1: e.nv = e.nu/2 + 1; break;
	case 2: break;
	default: msg("ellipsoid -n: expected nu or nu,nv but not %s", argv[i+1]);
	}
    } else if(!strcmp(argv[i], "-l")) {
	sscanf(argv[i+1], "%d", &e.level);
    } else {
	break;
    }
  }

  if(i == argc) {
    /* OK */
  } else if(i+9 == argc && 9==getfloats(m3, 9, i, argc, argv)) {
    memcpy(&e.ori.m[0*4+0], &m3[0], 3*sizeof(float));
    memcpy(&e.ori.m[1*4+0], &m3[3], 3*sizeof(float));
    memcpy(&e.ori.m[2*4+0], &m3[6], 3*sizeof(float));
    e.ori.m[3*4+3] = 1;
    e.hasori = 1;
  } else if(i+16 == argc && 16==getfloats(&e.ori.m[0], 16, i, argc, argv)) {
    e.hasori = 1;
slevy's avatar
slevy committed
  } else if(i+3 == argc && 3==getfloats(rxyz, 3, i, argc, argv)) {
    float aer[3];
    aer[0] = rxyz[1];
    aer[1] = rxyz[0];
    aer[2] = rxyz[2];
    xyzaer2tfm( &e.ori, NULL, aer );
    e.hasori = 1;
slevy's avatar
slevy committed
    msg("ellipsoid: expected 0 or 3 (RxRyRz) or 9 or 16 numbers after options, not %s",
	rejoinargs(i, argc, argv));
    return;
  }

  /* OK, take it */
  ep = NewN( struct ellipsoid, 1 );
  *ep = e;
  if(e.title) ep->title = shmstrdup(e.title);
  ep->next = st->staticellipsoids;
  st->staticellipsoids = ep;
}

void specks_read_mesh( struct stuff *st, FILE *f, int argc, char **argv, char *buf )
{
  char *cp, *ep;
  int i, count, alloced, err = 0;
  int havetx = 0;
  Point pts[300], txs[300];
  struct mesh *m = NewN( struct mesh, 1 );
  
  memset(m, 0, sizeof(*m));
  m->type = TSTRIPS;
  m->txno = -1;
  m->pts = pts; m->tx = txs;
  alloced = COUNT(pts);

  if(!strcmp(argv[0], "quadmesh") || !strcmp(argv[0], "mesh")) {
    m->type = QUADMESH;
  } else if(!strncmp(argv[0], "tfan", 4) || !strncmp(argv[0], "trifan", 6)) {
    m->type = TFANS;
  } else {
    m->type = TSTRIPS;
  }

  for(i = 1; i+1 < argc; i += 2) {
    if(!strncmp(argv[i], "-t", 2)) {
	havetx = sscanf(argv[i+1], "%d", &m->txno);
    } else if(!strncmp(argv[i], "-c", 2)) {
	sscanf(argv[i+1], "%d", &m->cindex);
    } else if(!strncmp(argv[i], "-s", 2)) {
	m->style = getstyle(argv[i+1]);
    } else {
	break;
    }
  }

  if(m->type == QUADMESH) {
    getline(f, buf);
    if(sscanf(buf, "%d%d", &m->nu, &m->nv) != 2
			|| m->nu <= 0 || m->nv <= 0) {
	msg("quadmesh: expected nu nv, got %s", buf);
	Free(m);
	return;
    }
    alloced = m->nverts = m->nu * m->nv;
    m->pts = NewN( Point, m->nverts );
    m->tx = havetx ? NewN( Point, m->nverts ) : NULL;
  }
    

  count = 0;
  while((cp = getline(f, buf)) != NULL) {
    int ngot;
    Point *tp;
#define BRA '{'
#define CKET '}'
    if(*cp == BRA) continue;
    if(*cp == CKET) break;

    if(count >= alloced) {
	if(m->type == QUADMESH) {
	    err = 1;
	    msg("Only expected %d*%d=%d vertices; what's %s",
		m->nu,m->nv, alloced, cp);
	    break;
	}
	/* otherwise, ask for more */
	/* XXX maybe later */
	break;
    }
	
    tp = &m->pts[count];
    for(ngot = 0; ngot < 3; ngot++, cp = ep) {
	tp->x[ngot] = strtod(cp, &ep);
	if(cp == ep) break;
    }
    if(havetx && ngot == 3) {
	tp = &m->tx[count];
	for(ngot = 0; ngot < 2; ngot++, cp = ep) {
	    tp->x[ngot] = strtod(cp, &ep);
	    if(cp == ep) break;
	}
	ngot++;
    }
    if(ngot != 3) {
	msg("Expected %d numbers per line; what's %s",
		havetx?5:3, buf); 
	err = 1;
	break;
    }
    count++;
  }
  if(m->type == QUADMESH && count < alloced) {
    err = 1;
    msg("Expected %d*%d = %d vertices, only got %d", m->nu,m->nv, alloced, count);
  }
  if(err) {
    if(m->pts != pts) Free(m->pts);
    if(m->tx != txs && m->tx != NULL) Free(m->tx);
    Free(m);
    return;
  }

  m->next = st->staticmeshes;
  st->staticmeshes = m;
}

teuben's avatar
teuben committed
void specks_read( struct stuff **stp, char *fname )
{
  FILE *f;
  char line[LINEBUFSIZE], oline[LINEBUFSIZE], *tcp;
teuben's avatar
teuben committed
  struct stuff *st = *stp;
  int maxfields = 0;

slevy's avatar
 
slevy committed
#define SPECKCHUNK 2001	/* should be bigger, but too many machines have tiny stack areas! */
#define MAXARGS 48
  int argc;
  char *argv[MAXARGS+1];
  struct speck speckbuf[SPECKCHUNK];
  struct speck *sp;
teuben's avatar
teuben committed
  struct speck s;
  struct specklist tsl;
  int i, nsp, maxnsp;
teuben's avatar
teuben committed
  int ignorefirst = 0;
  int lno = 0;
teuben's avatar
teuben committed

  if(fname == NULL) return;

  tcp = NewA( char, strlen(fname)+1 );	/* fname's space might get reused */
  strcpy(tcp, fname);
  fname = tcp;
teuben's avatar
teuben committed

  if((f = fopen(fname, "rb")) == NULL) {
teuben's avatar
teuben committed
    msg("%s: can't open: %s", fname, strerror(errno));
    return;
  }

  tsl.bytesperspeck = (st->maxcomment+1 +
			(sizeof(s) - sizeof(s.title)) + 3) & ~3;
teuben's avatar
teuben committed
  s.size = 1;
  nsp = 0;
  sp = speckbuf;
  maxnsp = sizeof(speckbuf) / tsl.bytesperspeck;
teuben's avatar
teuben committed

#define SPFLUSH() \
	addchunk( st, nsp, tsl.bytesperspeck,		\
		speckscale, speckbuf, NULL,		\
		maxfields >= MAXVAL ? tsl.bytesperspeck \
			: SMALLSPECKSIZE(maxfields) );	\
    }							\
    nsp = maxfields = 0;				\
teuben's avatar
teuben committed

  line[sizeof(line)-1] = '\1';
  while( fgets(line, sizeof(line), f) != NULL ) {
    lno++;
    if(line[sizeof(line)-1] != 1) {
	if(line[sizeof(line)-2] != '\n') {
	    while((i = getc(f)) != EOF && i != '\n')
		;
	}
	line[sizeof(line)-1] = '\1';
	line[sizeof(line)-2] = '\0';
	msg("%s line %d: truncated (>%d chars long!)",
		fname, lno, sizeof(line)-2);
teuben's avatar
teuben committed
    }

    argc = tokenize(line, oline, MAXARGS, argv, &comment);
teuben's avatar
teuben committed

    while(argc > 0 && !strcmp(argv[0], "add")) {
	for(i = 1; i <= argc; i++) argv[i-1] = argv[i];
	argc--;
    }
teuben's avatar
teuben committed
	continue;

    if(nsp >= maxnsp || (isalnum(argv[0][0]) && !isdigit(argv[0][0]))) {
teuben's avatar
teuben committed
	SPFLUSH();
    }

    if(!strcmp(argv[0], "include") || !strcmp(argv[0], "read")) {
teuben's avatar
teuben committed
	float oldscale = speckscale;
	char *infname = argv[1];
teuben's avatar
teuben committed
	char *realfile = findfile( fname, infname );
	if(realfile == NULL) {
	    msg("%s: Can't find include-file %s", fname, infname);
	} else {
	    specks_read( &st, realfile );
	}
	speckscale = oldscale;

#ifdef USE_IEEEIO
    } else if(!strcmp(argv[0], "ieee")) {
teuben's avatar
teuben committed
	int timestepno = st->datatime;
	char *realfile;
teuben's avatar
teuben committed

	if(argc>2 && !strcmp(argv[1], "-t")) {
	    if((timestepno = getfloat(argv[2], st->datatime)) < 0) {
teuben's avatar
teuben committed
		msg("ieee -t: expected timestepnumber(0-based), not %s", s);
		continue;
	    }
teuben's avatar
teuben committed
	}
	realfile = findfile( fname, argv[i] );
teuben's avatar
teuben committed
	if(realfile == NULL) {
	    msg("%s: ieee: can't find file %s", fname, argv[i]);
teuben's avatar
teuben committed
	} else {
	    /* Load IEEE dataset into time slot */
	    specks_ieee_open( st, realfile, st->curdata, timestepno );
	}
#endif

    } else if(!strcmp(argv[0], "object") && argc>1) {
teuben's avatar
teuben committed

	char *eq = strchr(argv[1], '=');

	i = 1;
	parti_object( argv[1], &st, 1 );
	if(eq) {
	    parti_set_alias( st, eq+1 );
	} else if(argc >= 3 && !strcmp(argv[2], "=")) {
	    /* object g3 = alias */
	    parti_set_alias( st, argv[3] );
teuben's avatar
teuben committed

    } else if(!strcmp(argv[0], "kira")) {
	char *realfile = findfile( fname, argv[1] );
teuben's avatar
teuben committed
#ifndef USE_KIRA
	msg("Need to recompile with -DUSE_KIRA");
#else
slevy's avatar
 
slevy committed
	st->clk->continuous = 1;
	kira_open(&st->dyn, st,
		realfile ? realfile : argv[1],
		argc>2 ? atoi(argv[2]) : 0);
teuben's avatar
teuben committed
#endif

slevy's avatar
 
slevy committed

slevy's avatar
slevy committed
    } else if(!strcmp(argv[0], "warp")) {
#ifndef USE_WARP
	msg("Need to recompile with -DUSE_WARP");
#else
	st->clk->continuous = 1;
	warp_setup(&st->dyn, st, argc, argv);
    } else if(!strcmp(argv[0], "sdb") && argc>1) {
teuben's avatar
teuben committed
	int tno = st->datatime;
	char *realfile;
	i = 1;
	if(argc>3 && !strcmp(argv[1], "-t")) {
	    if((tno = getfloat(argv[2], st->datatime)) < 0) {
		msg("sdb -t: expected timestepnumber(0-based), not %s", argv[2]);
teuben's avatar
teuben committed
		continue;
	    }
teuben's avatar
teuben committed
	}
	realfile = findfile( fname, argv[i] );
teuben's avatar
teuben committed
	if(realfile == NULL) {
	    msg("%s: sdb: can't find file %s", fname, argv[i]);
teuben's avatar
teuben committed
	} else {
	    specks_read_sdb( st, realfile, tno );
	}

    } else if(!strcmp(argv[0], "sdbvars")) {
	if(argc > 1) {
	    if(argv[1][strspn(argv[1], "mMcrogtxyzSn")] != '\0') {
teuben's avatar
teuben committed
		msg("sdbvars: pattern must contain only chars from: mMcrogtxyzSn, not %s",
teuben's avatar
teuben committed
	    } else {
		if(st->sdbvars) Free(st->sdbvars);
		st->sdbvars = shmstrdup(argv[1]);
teuben's avatar
teuben committed
	    }
	} else {
	    msg("sdbvars %s", st->sdbvars);
	}

    } else if(!strcmp(argv[0], "box") || !strcmp(argv[0], "boxes")) {
teuben's avatar
teuben committed
	Point cen, rad;
	struct AMRbox box;
teuben's avatar
teuben committed

	int tno = -1;

	box.boxno = -1;
	box.level = 0;

	i = 1;
	while(i+2 < argc && argv[i][0] == '-') {
	    if(argv[i][1] == 'n' && sscanf(argv[i+1], "%d", &box.boxno)>0)
		i += 2;
	    else if(argv[i][1] == 'l' && sscanf(argv[i+1], "%d", &box.level)>0)
		i += 2;
	    else if(argv[i][1] == 't' && (tno = getfloat(argv[i+1], st->datatime)) >= 0)
		i += 2;
teuben's avatar
teuben committed
	    else
		break;
	}
	if(i+2 == argc &&
	     3==sscanf(argv[i], "%f%*c%f%*c%f", &cen.x[0],&cen.x[1],&cen.x[2]) &&
	     0<(k=sscanf(argv[i+1], "%f%*c%f%*c%f", &rad.x[0],&rad.x[1],&rad.x[2]))) {
teuben's avatar
teuben committed
	    if(k<3) rad.x[1] = rad.x[2] = rad.x[0];	/* if scalar radius */
	    vsub(&box.p0, &cen, &rad);
	    vadd(&box.p1, &cen, &rad);
	    specks_add_box( st, &box, tno );

	} else if(i+3 == argc &&
		    2==sscanf(argv[i], "%f%*c%f",&box.p0.x[0],&box.p1.x[0]) &&
		    2==sscanf(argv[i+1], "%f%*c%f",&box.p0.x[1],&box.p1.x[1]) &&
		    2==sscanf(argv[i+2], "%f%*c%f",&box.p0.x[2],&box.p1.x[2])) {
teuben's avatar
teuben committed

	    specks_add_box( st, &box, tno );

	} else if(i+6 == argc) {
	    k = getfloats( &box.p0.x[0], 3, i, argc, argv )
	      + getfloats( &box.p1.x[0], 3, i+3, argc, argv );
	    if(k==6)
teuben's avatar
teuben committed
		specks_add_box( st, &box, tno );
	    else
		msg("box: expected xmin ymin zmin  xmax ymax zmax  -or- xmin,xmax ymin,ymax zmin,zmax -or- xcen,ycen,zcen xrad,yrad,zrad");

	} else if(i+1 == argc) {
	    char *realfile = findfile( fname, argv[i] );
teuben's avatar
teuben committed
	    if(realfile == NULL) {
		msg("%s: boxes: can't find file %s", fname, argv[i]);
teuben's avatar
teuben committed
	    } else {
		specks_read_boxes( st, realfile, tno );
	    }
	} else {
	    msg("usage: box [-t timestep] AMRboxfile  -or-");
	    msg("  box [-t time] [-n boxno] [-l level] xcen,ycen,zcen  xradius,yradius,zradius  -or-");
	    msg("  box [options]  xmin ymin zmin  xmax ymax zmax");
	    msg(" options: -n <boxno>  box number, for \"gobox\" and \"boxlabel\" cmds (dflt -1)");
	    msg("   -l <boxlevel>      level-number (0..31) for \"showboxlevel\" cmds (dflt 0)");
	    msg("   -t <time>		timestep, if animated; default eternal,");
	    msg("			or (for animated AMRboxfile) start time 0");
	}

    } else if(!strncmp(argv[0], "annot", 5)) {
teuben's avatar
teuben committed
	static char ausage[] = "Usage: annot [-t timestep]  string...";
teuben's avatar
teuben committed
	int tno = st->datatime;

	i = 1;
	if(argc>1 && !strcmp(argv[1], "-t")) {
	    tno = getfloat(argv[2], -1);
	    i = 3;
	}
	if(i >= argc || tno < 0) {
teuben's avatar
teuben committed
	    msg(ausage);
	    continue;
	}
	specks_add_annotation( st, rejoinargs( i, argc, argv ), tno );
teuben's avatar
teuben committed

    } else if(!strcmp(argv[0], "cment") || !strcmp(argv[0], "textcment")
		|| !strcmp(argv[0], "boxcment")) {
	specks_parse_args( &st, argc, argv );

    } else if(!strcmp(argv[0], "size") && argc>1) {
	sscanf(argv[1], "%f", &s.size);
teuben's avatar
teuben committed

    } else if(!strcmp(argv[0], "scale") && argc>1) {
		/* "scale" in data file, not as VIRDIR command */
	float v = 0;
	sscanf(argv[1], "%f", &v);
	if(v != 0)
teuben's avatar
teuben committed
	    st->spacescale = speckscale = v;

    } else if(!strcmp(argv[0], "tfm") && argc>1) {
teuben's avatar
teuben committed
	int inv = 0;
	int mul = 0;
	int hpr = 0;
	int camparent = -1;
	int any, more, j, k;
teuben's avatar
teuben committed
	float scl;
	Matrix ot, t;
	Point xyz;
	float aer[3];
	char *key;
	i = 1;
	for(more = 1, key = argv[1]; *key != '\0' && more; key++) {
teuben's avatar
teuben committed
	  switch(*key) {
	  case '*': mul = 1; break;
	  case '/': inv = 1; break;
	  case 'h': case 'p': case 'r': hpr = 1; break;
	  case 'c': camparent = 1; i++; more = 0; break;
	  case 'w': camparent = 0; i++; more = 0; break;
	  case '\0': more = 0; i++; break;
	  default: more = 0; break;
teuben's avatar
teuben committed
	  }
	}

	if(camparent>=0)
	    parti_parent( st, camparent ? -1 : 0 );

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

	k = getfloats( &t.m[0], 16, i, argc, argv );
	switch(k) {
teuben's avatar
teuben committed
	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 9:
		for(i = 2; i >= 0; i--)