Skip to content
Snippets Groups Projects
partibrains.c 194 KiB
Newer Older
  VSTUFF( m->fv0, fv0 );
  m->fvn = NewN( int, VTOTAL(fvn) );
  VSTUFF( m->fvn, fvn );
  m->fvs = NewN( int, VTOTAL(fvs) );
  VSTUFF( m->fvs, fvs );
  m->nfaces = VTOTAL(fvn);
  m->nfv = VTOTAL(fvs);
  m->nverts = VTOTAL(pts);
  for(i = m->nfv; --i >= 0; ) {
    if(m->fvs[i] < 0 || m->fvs[i] >= m->nverts) {
	fprintf(stderr, "%s: vert index %d out of range 1..%d\n",
		fullname, m->fvs[i]+1, m->nverts);
	m->fvs[i] = 0;
    }
  }
  m->fnorms = NewN( Point, m->nfaces );
  for(f = 0; f < m->nfaces; f++) {
    Point vab, vac, normal;
    int myfv0 = m->fv0[f];
    if(m->fvn[f] > 3 && m->fvs[myfv0] == m->fvs[myfv0+1])
	myfv0++;		/* degenerate quad? */
    vsub( &vab, &m->pts[ m->fvs[myfv0+1] ], &m->pts[ m->fvs[myfv0] ] );
    vsub( &vac, &m->pts[ m->fvs[myfv0+2] ], &m->pts[ m->fvs[myfv0] ] );
    vcross( &normal, &vab, &vac );
    vunit( &m->fnorms[f], &normal );
  }

  if(timestep >= 0) {
    if(timestep >= st->ntimes)
	specks_timespecksptr( st, st->curdata, timestep );
    m->next = st->meshes[st->curdata][timestep];
    st->meshes[st->curdata][timestep] = m;
  } else {
    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...";
	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;
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--)
		    for(j = 2; j >= 0; j--)
			t.m[i*4+j] = t.m[i*3+j];
		t.m[0*4+3] = t.m[1*4+3] = t.m[2*4+3] =
			t.m[3*4+0] = t.m[3*4+1] = t.m[3*4+2] = 0;
		t.m[3*4+3] = 1;
		break;

teuben's avatar
teuben committed
	case 16: break;
	case 0: if(camparent >= 0) continue;	/* allow "tfm c" or "tfm w" */
teuben's avatar
teuben committed
	default:
	    msg("Usage: tfm: expected 1 or 6 or 9 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;
	int txflags = TXF_SCLAMP | TXF_TCLAMP | TXF_ADD;
teuben's avatar
teuben committed
	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;
	    if(strchr(key, 'O')) txflags = (txflags & ~TXF_ADD) | TXF_OVER;
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);
		msg(" opts: -l(inear) -m(ipmap) -n(earest) -i(intensity) -a(lpha) -A(dd) -O(ver(notAdd)) -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
	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], "waveobj")) {
	specks_read_waveobj(st, argc, argv, line, fname);
	
    } 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, "rb");
teuben's avatar
teuben committed
  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;
  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 );

		/* round to 1 decimal */
#if CAVE
  {
    Point pmid, fwd, headv, pos, offset, newpos;
    static Point zvec = {0,0,1};
    float sz, scale;
    char cmd[128];
    sz = vdist( &box->p0, &box->p1 );
    sprintf(cmd, "%.1g", st->gscale * st->goboxscale * sz);
    scale = atof(cmd);
teuben's avatar
teuben committed
    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, "rb");
teuben's avatar
teuben committed
  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;
   }
slevy's avatar
 
slevy committed
   clock_set_time( st->clk, me->val = (int) time0 );
teuben's avatar
teuben committed
   /* NOTE we use the static values snapped by the framefunction.
    * st->curtime etc. might have changed since then.
    */
   sprintf(str, "step %2d of 0..%d", st->frame_time, st->ntimes - 1);
   if(st->fetching > 0)
	sprintf(str+strlen(str), " (loading %d)", st->fetchtime);
   menu_settitle( me, str );
}

void set_fwd( int fwd, MenuEnt *me, void *st ) {
slevy's avatar
 
slevy committed
   clock_set_fwd( ((struct stuff *)st)->clk, fwd );
teuben's avatar
teuben committed
   menu_settitle( me, fwd ? ">>> fwd >>>" : "<<< rev <<<" );
}

void set_viewall( int all, MenuEnt *me, void *vst ) {
  struct stuff *st = (struct stuff *)vst;
  if(all) {
    strcpy( st->vdcmd, "\002jump all" );
    menu_settitle( me, "view all" );
  }
  else {
    strcpy( st->vdcmd, "\002jump peak" );
    menu_settitle( me, "view peak" );
  }
}

float get_nav_scale(void)
{
  float nav[4][4];
  CAVENavGetMatrix( nav );
  return 1 / sqrtf( vdot( (Point *)&nav[0][0], (Point *)&nav[0][0] ) );
}

void set_scale( float logscale, MenuEnt *me, void *vst ) {
  struct stuff *st = (struct stuff *)vst;
  float scl = pow(10., logscale);
  char str[64];

  if(me->state == ME_PICKED || me->state == ME_HELD) {
    sprintf( st->vdcmd, "\002scale %g", scl);
  } else {
    scl = get_nav_scale();
    me->val = scl<=0 ? -6 : log10( scl );
  }
  sprintf( str, "scale %.4g", scl );
  menu_settitle( me, str );
}


void set_dataset( int which, MenuEnt *me, void *vst ) {
   char str[32];
   struct stuff *st = (struct stuff *)vst;
   if(which < 0 || which >= st->ndata || which >= MAXFILES) which = 0;
   st->curdata = which;
   sprintf(str, "viewing %s (%d)", st->dataname[which], which);
   menu_settitle( me, str );
}

void set_lumvar( int lumvar, MenuEnt *me, void *vst ) {
   char str[80];
   struct stuff *st = (struct stuff *)vst;
   struct valdesc *vd;
   if(lumvar < 0 || lumvar >= MAXVAL+1) lumvar = 0;
   st->sizedby = lumvar;