Skip to content
Snippets Groups Projects
partibrains.c 168 KiB
Newer Older
	}
    } 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;
  } else {
    msg("ellipsoid: expected 0 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, "r")) == NULL) {
    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() \
teuben's avatar
teuben committed
	addchunk( st, nsp, sizeof(struct speck),	\
		speckscale, speckbuf, NULL,		\
		maxfields >= MAXVAL ? tsl.bytesperspeck \
			: SMALLSPECKSIZE(maxfields) );	\
    }							\
    nsp = maxfields = 0;				\
    sp = speckbuf;					\
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;
	open_parti(st, realfile, argc>2 ? atoi(argv[2]) : 0);
teuben's avatar
teuben committed
#endif

slevy's avatar
 
slevy committed

    } 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], "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 any, more, 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 '\0': more = 0; i++; break;
	  default: more = 0; break;
teuben's avatar
teuben committed
	  }
	}

	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 16: break;
	default:
	    msg("Usage: tfm: expected 1 or 6 or 16 numbers not %s", line);
teuben's avatar
teuben committed
	    continue;
	}
	if(inv)
	    eucinv( &t, &t );
	if(mul)
	    mmmul( &t, &ot, &t );
teuben's avatar
teuben committed

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

    } else if((!strcmp(argv[0], "eval") || !strcmp(argv[0], "feed")
				   || !strcasecmp(argv[0], "VIRDIR"))
		&& argc > 1) {
teuben's avatar
teuben committed
#if CAVE
	if(0 == specks_parse_args( &st, argc-1, argv+1 )) {
	    /* grr, need to skip first word of line */
	    char *s = line;
	    while(isspace(*s)) s++;
	    while(!isspace(*s) && *s) s++;
	    VIDI_queue_commandstr( s );
	}
teuben's avatar
teuben committed

#else /* non-CAVE */
	specks_parse_args( &st, argc-1, argv+1 );
teuben's avatar
teuben committed

#endif /* non-CAVE */

    } else if(!strcmp(argv[0], "filepath")) {
	int k = 0;
teuben's avatar
teuben committed
	char **oldpath = getfiledirs();
	char *path[64], *dir;
	for(i = 1, k = 0; i < argc && k < COUNT(path)-1; i++) {
	    dir = strtok(argv[i], ":");
	    do {
		if(!strcmp(dir,"+")) {
		    int m = 0;
		    while(k<COUNT(path)-1 && oldpath && oldpath[m])
			path[k++] = oldpath[m++];
		} else {
		    path[k++] = dir;
		}
		dir = strtok(NULL, ":");
	    } while(dir && k < COUNT(path)-1);
teuben's avatar
teuben committed
	}
	path[k] = NULL;
	if(k > 0) filedirs(path);

    } else if(!strcmp(argv[0], "texture")) {
	int txno = -1;
teuben's avatar
teuben committed
	int txflags = TXF_SCLAMP | TXF_TCLAMP;
	int txapply = TXF_DECAL;
	int qual = 7;
	char *txfname, *key;
	i = 1;
	if(argc > 1 && sscanf(argv[1], "%d", &txno) > 0)
	    i = 2;
	while(i < argc && (key = argv[i])[0] == '-' || key[0] == '+') {
slevy's avatar
 
slevy committed
	    int tqual = (strchr(key,'m') ? 4:0) |
			(strchr(key,'l') ? 2:0) |
			(strchr(key,'n') ? 1:0);
	    if(key[0] == '-') qual &= ~tqual;
	    else qual |= tqual;
	    if(strchr(key,'a')) txflags |= TXF_ALPHA;
	    if(strchr(key,'i')) txflags |= TXF_INTENSITY;
	    if(strchr(key, 'A')) txflags |= TXF_ADD;
teuben's avatar
teuben committed
	    if(strchr(key, 'M')) txapply = TXF_MODULATE;
	    if(strchr(key, 'D')) txapply = TXF_DECAL;
	    if(strchr(key, 'B')) txapply = TXF_BLEND;
teuben's avatar
teuben committed
	}
	if((i < argc && txno < 0 && sscanf(argv[i++], "%d", &txno) <= 0) ||
	    (txfname = argv[i]) == NULL) {
		msg("Expected ``texture [-lmnaMDB] txno file.sgi'', got %s", line);
slevy's avatar
 
slevy committed
		msg(" opts: -l(inear) -m(ipmap) -n(earest) -i(intensity) -a(lpha) -A(dd) -M(odulate)|-D(ecal)|-B(lend))");
teuben's avatar
teuben committed
	} else {
	    txaddentry( &st->textures, &st->ntextures, fname, txno, txfname, txapply, txflags, qual );
	}

    } else if(!strcmp(argv[0], "polyorivar") && argc == 2) {
	if(1!=specks_set_byvariable( st, argv[1], &st->polyorivar0 ))
	    msg("polyorivar: unknown field %s", argv[1]);
teuben's avatar
teuben committed

    } else if(!strcmp(argv[0], "texturevar") && argc == 2) {
	if(1!=specks_set_byvariable( st, argv[1], &st->texturevar ))
	    msg("texturevar: unknown field %s", argv[1]);
teuben's avatar
teuben committed

    } else if(!strncmp(argv[0], "coord", 5) || !strncmp(argv[0], "altcoord", 8)) {
teuben's avatar
teuben committed
	float *t = &st->altcoord[0].w2coord.m[0];
teuben's avatar
teuben committed
	    msg("coord %s  %g %g %g %g  %g %g %g %g  %g %g %g %g  %g %g %g %g",
		st->altcoord[0].name, t[0],t[1],t[2],t[3],
		t[4],t[5],t[6],t[7],
		t[8],t[9],t[10],t[11],
		t[12],t[13],t[14],t[15]);

	} else if(argc == 18) {
	    sprintf(st->altcoord[0].name, "%.9s", argv[1]);
	    i = getfloats( t, 16, 2, argc, argv );
	    if(i != 16) {
		msg("%s: expected 16 numbers; what's %s", argv[0],argv[i+2]);
		continue;
teuben's avatar
teuben committed
	    }
	} else {
	    msg("expected \"coord\" name  ... 16 world-to-coord tfm floats (GL order) ...");
teuben's avatar
teuben committed
	}

    } else if(!strncmp(argv[0], "dataset", 7) && argc == 3) {
teuben's avatar
teuben committed
	char name[12];
	int indexno;
	if(sscanf(argv[1], "%d", &indexno) <= 0
		|| sscanf(argv[2], "%11s", name) <= 0
teuben's avatar
teuben committed
		|| indexno < 0 || indexno >= MAXFILES) {
	    msg("%s: expected ``dataset <indexno> <datasetname>'' with 0<=indexno<=%d",
		fname, MAXFILES-1);
	    continue;
	}
	strncpyt(st->dataname[indexno], name, sizeof(st->dataname[indexno]));
	st->curdata = indexno;

    } else if(!strncmp(argv[0], "datavar", 7) && argc > 2) {
teuben's avatar
teuben committed
	int varno, nargs;
	struct valdesc vd;

	if(sscanf(argv[1], "%d", &varno)<=0
		|| sscanf(argv[2], "%19s", vd.name)<=0
teuben's avatar
teuben committed
		|| varno < 0 || varno >= MAXVAL) {
	    msg("%s: expected ``datavar <indexno> <variablename> [minval maxval]'' with 0<=indexno<=%d",
		line, MAXVAL-1);
teuben's avatar
teuben committed
	    continue;
	}
	strcpy(st->vdesc[st->curdata][varno].name, vd.name);
	if(argc == 5) {
	    st->vdesc[st->curdata][varno].min = atof(argv[3]);
	    st->vdesc[st->curdata][varno].max = atof(argv[4]);
teuben's avatar
teuben committed
	}

    } else if(!strcmp(argv[0], "datatime") && argc==2) {
teuben's avatar
teuben committed
	int newt = st->curtime;	/* so e.g. "datatime now" => apply to current data */
	sscanf(argv[1], "%d", &newt);
	if(sscanf(argv[1], "%d", &newt) <= 0 || newt < 0) {
	    msg("%s: datatime %s: timestep must be >= 0", fname, argv[1]);
teuben's avatar
teuben committed
	    continue;
	}
	if(newt == st->datatime)	/* no need to change anything */
	    continue;
teuben's avatar
teuben committed
	st->datatime = newt;

    } else if(!strcmp(argv[0], "mesh") || !strcmp(argv[0], "tstrip")
					|| !strcmp(argv[0], "tfan")) {
	specks_read_mesh(st, f, argc, argv, line);
    } else if(!strcmp(argv[0], "textcolor") && argc==2) {
	sscanf(argv[1], "%d", &s.rgba);

    } else if(!strcmp(argv[0], "maxcomment") && argc==2) {
	int newmax = st->maxcomment;
	sscanf(argv[1], "%d", &newmax);
	if(newmax != st->maxcomment) {
	    SPFLUSH();
	    st->maxcomment = newmax;
	    tsl.bytesperspeck =
		(st->maxcomment+1 + (sizeof(s) - sizeof(s.title)) + 3) & ~3;
	    maxnsp = sizeof(speckbuf) / tsl.bytesperspeck;
	}
teuben's avatar
teuben committed
    } else {
	struct valdesc *vdp;
teuben's avatar
teuben committed

	k = getfloats( &s.p.x[0], 3, ignorefirst, argc, argv );
	if(k < 3) {
	    msg("Unrecognized datacmd: %s", line);
teuben's avatar
teuben committed
	    continue;
	i = ignorefirst + k;
teuben's avatar
teuben committed
	vdp = &st->vdesc[st->curdata][0];
	k = getfloats( &s.val[0], COUNT(s.val), i, argc, argv );
	for(m = 0; m < k; m++) {
	    if(vdp->nsamples++ == 0) {
		vdp->min = vdp->max = s.val[m];
	    } else {
		if(vdp->min > s.val[m]) vdp->min = s.val[m];
		else if(vdp->max < s.val[m]) vdp->max = s.val[m];
teuben's avatar
teuben committed
	    }
	    vdp->sum += s.val[m];
	    vdp->mean = vdp->sum / vdp->nsamples;
	    vdp++;
teuben's avatar
teuben committed
	}

	if(maxfields < k) maxfields = k;
	m = i+k;
teuben's avatar
teuben committed
	s.title[0] = '\0';
	    if(!strcmp(argv[m], "text")) {
		s.size = 1;
		if(++m < argc-1 && !strcmp(argv[m], "-size")) {
		    sscanf(argv[m+1], "%f", &s.size);
		    m += 2;
		}
		addchunk( st, 1, SMALLSPECKSIZE(0),
			speckscale, &s,
			rejoinargs(m, argc, argv),
			SMALLSPECKSIZE(0) );
teuben's avatar
teuben committed
	    }
	    else if(!strcmp(argv[m], "ellipsoid")) {
		specks_read_ellipsoid( st, &s.p, argc-m, argv+m, comment );
teuben's avatar
teuben committed

	    } else {
		*sp = s;
		nsp++;
		sp = NextSpeck( speckbuf, &tsl, nsp );
teuben's avatar
teuben committed
	    }
slevy's avatar
slevy committed
	    char *title = comment + (comment[1] == ' ' ? 2 : 1);
	    *sp = s;
	    strncpyt(sp->title, title, st->maxcomment+1);
	    maxfields = MAXVAL+1;	/* "keep titles too" */
	    nsp++;
	    sp = NextSpeck( speckbuf, &tsl, nsp );

	} else {
	    *sp = s;
	    nsp++;
	    sp = NextSpeck( speckbuf, &tsl, nsp );
teuben's avatar
teuben committed
	}
    }
  }
  fclose(f);
  SPFLUSH();
  *stp = st;
}

/* Add a static (eternal) box to display list */
int specks_add_box( struct stuff *st, struct AMRbox *box, int timestep )
{
  int i;
  if(box->level >= 0 && st->boxlevels <= box->level)
    st->boxlevels = box->level+1;
  for(i = 0; i < st->staticboxroom && st->staticboxes[i].level >= 0; i++) {
    if(box->boxno != -1 && box->boxno == st->staticboxes[i].boxno) {
	st->staticboxes[i] = *box;
	return ~i;
    }
  }

  if(i >= st->staticboxroom-1) {
    st->staticboxroom = (st->staticboxroom>0) ? st->staticboxroom*2 : 12;
    st->staticboxes = RenewN( st->staticboxes, struct AMRbox, st->staticboxroom );
  }
  st->staticboxes[i] = *box;
  st->staticboxes[i+1].level = -1;
  return i;
}


void specks_read_boxes( struct stuff *st, char *fname, int timebase )
{
  FILE *f = fopen(fname, "r");
  char line[1024];
  int ntimes = -1, maxbox = -1, curbox = 0, curtime = 0, level = -1, i;
  int lno = 0;
  int boxseq, boxno;
  struct AMRbox *boxes = NULL;
  struct AMRbox box;

  if(timebase < 0)	/* if unspecified time, start at first timestep */
    timebase = 0;

  if(f == NULL) {
    msg("Can't open AMRboxes file %s (as from hier2boxes.pl)", fname);
    return;
  }
  while(fgets(line, sizeof(line), f) != NULL) {
    lno++;
    boxno = -1;
    if(sscanf(line, "%f%f%f %f%f%f # %d",
		&box.p0.x[0],&box.p0.x[1],&box.p0.x[2],
		&box.p1.x[0],&box.p1.x[1],&box.p1.x[2], &boxno) >= 6) {
	for(i = 0; i < 3; i++) {
	    box.p0.x[i] *= st->spacescale;
	    box.p1.x[i] *= st->spacescale;
	}
	if(boxno != -1)
	    box.boxno = boxno;
	else
	    box.boxno = boxseq++;
	if(curbox < maxbox && boxes != NULL && level >= 0) {
	    boxes[curbox] = box;
	    curbox++;
	} else {
	    msg("%s line %d: Excess box (only expected %d at timestep %d)",
		fname, lno, maxbox, curtime);
	}
    }
    else if(sscanf(line, "AMRboxes %d timesteps", &ntimes) > 0 && ntimes >= 0) {
	int needtimes = ntimes + (timebase<0 ? 0 : timebase);
	if(st->boxtimes <= needtimes+1) {
	    needtimes += st->boxtimes + 15;	/* leave lots of extra room */
	    st->boxes = RenewN( st->boxes, struct AMRbox *, needtimes );
	    memset( &st->boxes[st->boxtimes], 0,
			(needtimes - st->boxtimes) * sizeof(struct AMRbox *) );
	    if(st->boxtimes < ntimes+timebase)
		st->boxtimes = ntimes+timebase;
	}
	boxes = NULL;
    }
    else if(sscanf(line, "timestep %d %d grids", &curtime, &maxbox) == 2) {
	boxseq = 1;
	if(ntimes < 0) {
	    msg(
"%s line %d: ``AMRboxes N timesteps'' must precede ``timestep'' lines!",
		    fname, lno);
	    curtime = -1;
	    boxes = NULL;
	    continue;
	} else if(curtime<0 || curtime>=ntimes || maxbox<0) {
	    msg("%s line %d: bad timestep number", fname, lno); 
	    curtime = -1;
	    boxes = NULL;
	    continue;
	}
	if((boxes = st->boxes[curtime+timebase]) != NULL) {
	    msg("%s line %d: Respecifying timestep %d",
		fname, lno, curtime);
	    Free( st->boxes[curtime+timebase] );
	}
	boxes = NewN( struct AMRbox, maxbox+1 );
	for(curbox = 0; curbox <= maxbox; curbox++)
	    boxes[curbox].level = -(maxbox+1);
	st->boxes[curtime+timebase] = boxes;

	/* Ensure that known span of time includes this timestep */
	(void) specks_timespecksptr( st, st->curdata, curtime+timebase );

	curbox = 0;
    }
    else if(sscanf(line, "level %d", &level) > 0) {
	if(boxes == NULL) {
	    msg("%s line %d: Must specify timestep before level",
		fname, lno);
	    level = -1;
	}
	if(st->boxlevels <= level)
	    st->boxlevels = level+1;
	box.level = level;
    }
  }
  fclose(f);

  /* st->boxlevelmask |= (1 << st->boxlevels) - 1;
   * Don't do this -- it turns on all boxlevels whenever we get a new box!
   */
}

static struct AMRbox *findboxno( struct AMRbox *box, int boxno, int *count, int *bmin, int *bmax ) {
  if(box == NULL) return NULL;
  while(box->level >= 0) {
    if(box->boxno == boxno)
	return box;
    if(*bmin > box->boxno) *bmin = box->boxno;
    if(*bmax < box->boxno) *bmax = box->boxno;
    ++*count;
    box++;
  } 
  return NULL;
}

int specks_gobox( struct stuff *st, int boxno, int argc, char *argv[] )
{
  Point pmid;
  float sz, scale;
  char cmd[128];
  int bmin = 1<<30, bmax = -1<<30;
  int count = 0;
  struct AMRbox *box = NULL;

  if(st->boxes && st->curtime < st->boxtimes)
    box = findboxno( st->boxes[st->curtime], boxno, &count, &bmin, &bmax );
  if(box == NULL)
    box = findboxno( st->staticboxes, boxno, &count, &bmin, &bmax );

  if(box == NULL) {
    if(count == 0)
	msg("No AMR boxes for timestep %d", st->curtime);
    else
	msg("%d AMR boxes (numbered %d..%d) for timestep %d, but no box number %d",
	    count, bmin, bmax, st->curtime, boxno);
    return 0;
  }

  vlerp( &pmid, .5*st->gscale, &box->p0, &box->p1 );
  set_interest_point( &pmid );

  sz = vdist( &box->p0, &box->p1 );
  sprintf(cmd, "%.1g", st->gscale * st->goboxscale * sz);
		/* round to 1 decimal */
  scale = atof(cmd);
#if CAVE
  {
    Point pmid, fwd, headv, pos, offset, newpos;
    static Point zvec = {0,0,1};
    CAVENavConvertVectorCAVEToWorld( zvec.x, fwd.x );
    CAVEGetPosition( CAVE_HEAD, headv.x );
    headv.x[2] -= 10.0;	/* a point in front of head, in CAVE coords */
    CAVENavConvertVectorCAVEToWorld( headv.x, offset.x );
    msg("scale %g caveunit %g offsetW %g %g %g", scale, vlength(&fwd), offset.x[0],offset.x[1],offset.x[2]);
    vsadd( &newpos, &pmid, -scale / vlength(&fwd), &offset );
    sprintf(cmd,
	sz > 0	? "jumpto %g %g %g  . . .  %g"
		: "jumpto %g %g %g",
	newpos.x[0], newpos.x[1], newpos.x[2], scale);
    VIDI_queue_commandstr( cmd );
  }
#endif

  return 1;
}

void specks_read_cmap( struct stuff *st, char *fname, int *ncmapp, struct cment **cmapp )
teuben's avatar
teuben committed
{
  int i;
  char *cp;
  char line[256];
  int k, count = 0;
  int *tcmap;
teuben's avatar
teuben committed
  float fr,fg,fb,fa;
  int big = 0;
  int lno = 0;
  int ncmap = 0;
  int cval;
  int csrc;

  FILE *f = fopen(fname, "r");
  if(f == NULL) {
    msg("Can't open colormap file %s", fname);
    return;
  }
  tcmap = NULL;

  ncmap = 0;
  while(fgets(line, sizeof(line), f) != NULL) {
    lno++;
    cp = line;
   rescan:
    for( ; isspace(*cp); cp++)
	;
    if(*cp == '\0' || *cp == '#')
	continue;
    fa = 1.0;
    k = sscanf(cp, "%f%f%f", &fr,&fg,&fb/*,&fa*/);
    if(k == 1) {
	if(count == 0 && fr == (int)fr && fr > 0) {
	    count = fr;
	    if(count >= 1 && count < 1000000)		/* OK */
		continue;
	    msg("Unreasonable number of colormap entries claimed in header");
	    /* and fall into error case */
	} else {
	    while(isspace(*cp) || isdigit(*cp)) cp++;
	    if(*cp == ':') {
		ncmap = fr;
		if(ncmap < 0) {
		    ncmap = 0;		/* don't continue -- fall into error */
		} else if(ncmap >= count) {
		    msg("Colormap index %g exceeds size %d given in header",
			fr, count);	/* don't continue -- ditto */
		} else {
		    cp++;
		    goto rescan;		/* All's well */
		}
	    }
	}
    } else if(k >= 3) {
	if(fr > 2 || fg > 2 || fb > 2 || fa > 2)
	    big = 1;
	if(!big) {
	    fr *= 255; fg *= 255; fb *= 255; /*fa *= 255;*/
	}
	cval = PACKRGBA( (int)fr, (int)fg, (int)fb, 0 );
	if(tcmap == NULL) {
	    tcmap = NewA( int, count );
	    /* Fill unused entries with gray */
	    memset(tcmap, 0x80, count*sizeof(int));
	}
	tcmap[ncmap>=count ? count-1 : ncmap<0 ? 0 : ncmap] = cval;
	ncmap++;
	if(ncmap >= count)
	    break;
	continue;

    } else if(sscanf(cp, "=%d", &csrc) > 0) {
	if(csrc < 0 || csrc >= count || ncmap < 0 || ncmap >= count || tcmap == NULL) {
	    msg("Colormap index out of range: %d or %d isn't in 0..%d",
		ncmap, csrc, count-1);
	} else {
	    tcmap[ncmap++] = tcmap[csrc];
	    continue;
	}
	/* Fall through into error */
    }
    msg("Trouble reading colormap file %s: bad line %d: %s",
		fname, lno, line);
    fclose(f);
    return;
  }
  fclose(f);
  if(tcmap == NULL)
    return;

  *ncmapp = count;
  if(*ncmapp < 2) {
    *ncmapp = 2;
    tcmap[1] = tcmap[0];
  }
  *cmapp = cm = RenewN( *cmapp, struct cment, *ncmapp );
  k = *ncmapp;
  for(i = 0; i < k; i++) {
    cm[i].raw = tcmap[i];
    cm[i].cooked = specks_cookcment( st, tcmap[i] );
slevy's avatar
 
slevy committed
  }
teuben's avatar
teuben committed
}


#if CAVEMENU
void set_psize( float psize, MenuEnt *me, void *st ) {
   char str[20];
   ((struct stuff *)st)->psize = psize;
   sprintf(str, "pointsize %.3g", psize);
   menu_settitle( me, str );
}

	/* set_tknob() only used if PARTIMENU mentions "survey" */
void set_tknob( float val, MenuEnt *me, void *vtb ) {
  char str[128];
  struct stuff *st = ((struct boxleveler *)vtb)->st;
  int self = ((struct boxleveler *)vtb)->level;
  static int mod[3] = { 1, 4, 16 };
  static char *fmt[3] = {
	"StarMassEjFrac [%d/4]",
	"SNFeedback     [%d/4]",
	"StarEfficiency [%d/4]",
  };
  int range = 4, mine, rest, above;
  above = mod[self] * range;
  rest = st->curtime % mod[self] + (st->curtime / above) * above;
  mine = (st->curtime / mod[self]) % range;
  if(me->state == ME_PICKED || me->state == ME_HELD) {
    mine = val;
    if(mine < 0) mine = 0; else if(mine >= range) mine = range-1;
slevy's avatar
 
slevy committed
    clock_set_time( st->clk, rest + mine*mod[self] );
    clock_set_running( st->clk, 0 );
teuben's avatar
teuben committed
  }
  sprintf(str, fmt[self], mine+1);
  menu_settitle( me, str );
}

void set_step( float time0, MenuEnt *me, void *vst ) {
   char str[32];
   struct stuff *st = (struct stuff *)vst;
   if(me->state == ME_PICKED) {
slevy's avatar
 
slevy committed
	time0 += clock_fwd(st->clk);
teuben's avatar
teuben committed
	st->timeplay = 0;
	me->state = ME_HELD;