Skip to content
Snippets Groups Projects
partibrains.c 193 KiB
Newer Older
	    glVertex3fv( pts[ fvs0[3] ].x );
	} else if(fvn < 0) {
	    if(was) {
		glEnd();
		was = 0;
	    }
	    glBegin( GL_TRIANGLE_STRIP );
	    glNormal3fv( m->fnorms[f].x );
	    do {
		glVertex3fv( pts[ *fvs0++ ].x );
	    } while(++fvn < 0);
	    glEnd();
	} else {
	    if(was) {
		glEnd();
		was = 0;
	    }
	    glBegin( GL_POLYGON );
	    glNormal3fv( m->fnorms[f].x );
	    do {
		glVertex3fv( pts[ *fvs0++ ].x );
	    } while(--fvn > 0);
    }
    if(was) glEnd();
    break;
  }
  if(m->fnorms != NULL) {
    glDisable( GL_LIGHTING );
    glDisable( GL_COLOR_MATERIAL );
teuben's avatar
teuben committed
void specks_draw_boxes( struct stuff *st, struct AMRbox *boxes, int boxlevelmask, Matrix Ttext, int oriented )
{
  static short arcs[] = {
	5, 4, 6, 2, 3, 1, 5, 7, 6,
	-1,
	7, 3,
	0, 1,
	0, 2,
	0, 4
  };
  struct AMRbox *box;
  int i;
  float boxscale, s0, s1;
  int isscaled;

  glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
  glLineWidth( st->boxlinewidth );
  glEnable( GL_BLEND );
  glDisable( GL_LINE_SMOOTH );

  /* Scan through the array, whose end is marked with a box at level -1. */
  for(box = boxes; box->level >= 0; box++) {
    boxscale = (box->level < 0) ? 1.0
	   : st->boxscale[ box->level>=MAXBOXLEV ? MAXBOXLEV-1 : box->level ];
    isscaled = (boxscale != 0 && boxscale != 1);
    if(isscaled) {
	s0 = .5*(1 + boxscale);
	s1 = .5*(1 - boxscale);
    }
    if((1 << box->level) & boxlevelmask) {
	int cval = RGBALPHA(st->boxcmap[
		    box->level<0 ? 0
		    : box->level>=st->boxncmap ?
			st->boxncmap-1 : box->level ].cooked,
teuben's avatar
teuben committed
		    0xFF);
	int colorme = 0;

	if(oriented)
	    cval = orientboxcolor;
	glColor4ubv( (GLubyte *)&cval );
	glBegin( GL_LINE_STRIP );
	for(i = 0; i < COUNT(arcs); i++) {
	    int vert = arcs[i];
	    if(vert < 0) {
		glEnd();
		glBegin( GL_LINES );
	    } else {

		if(oriented) {
		    if(vert == 0) {
			glColor4ubv( (GLubyte *)&cval );
			colorme = 1;
		    } else if(colorme) {
			glColor3f( vert&1?1:0, vert&2?1:0, vert&4?1:0 );
		    }
		}

		if(isscaled && !oriented && box->level >= 0) {
		    glVertex3f(
			vert&1	? s0*box->p0.x[0] + s1*box->p1.x[0]
				: s1*box->p0.x[0] + s0*box->p1.x[0],
			vert&2	? s0*box->p0.x[1] + s1*box->p1.x[1]
				: s1*box->p0.x[1] + s0*box->p1.x[1],
			vert&4	? s0*box->p0.x[2] + s1*box->p1.x[2]
				: s1*box->p0.x[2] + s0*box->p1.x[2] );
		} else {
		    glVertex3f(
			(vert&1 ? box->p1.x : box->p0.x)[0],
			(vert&2 ? box->p1.x : box->p0.x)[1],
			(vert&4 ? box->p1.x : box->p0.x)[2]
		    );
		}
	    }
	}
	glEnd();
	if(st->boxlabels && st->boxlabelscale != 0) {
	    float sz = .16 * vdist( &box->p0, &box->p1 ) / st->textsize;
teuben's avatar
teuben committed
	    char lbl[16];
	    vlerp( &mid, .5, &box->p0, &box->p1 );
teuben's avatar
teuben committed
	    sprintf(lbl, "%d", box->boxno);
	    sfStrDrawTJ( lbl, sz, &mid, &Ttext, "c" );
teuben's avatar
teuben committed
	}
    }
  }
  glLineWidth( 1 );
}

int specks_partial_pick_decode( struct stuff *st, int id,
			int nhits, int nents, GLuint *hitbuf,
			unsigned int *bestzp, struct specklist **slp,
			int *specknop, Point *pos )
{
  int i, hi, ns, slno;
  GLuint z0, bestz = *bestzp;
  int bestslno = 0, bestspeck = -1;
  struct specklist *sl, *slhead;

  if(st == NULL)
    return 0;

  if(st->picked != NULL)
    (*st->picked)(st, NULL, NULL, nhits);	/* "prepare for up to nhits calls" */

  slhead = st->frame_sl;		/* st->sl as snapped by specks_ffn() */
  if(slhead == NULL) slhead = st->sl;	/* maybe there is no specks_ffn() */
  if(slhead == NULL) return 0;

teuben's avatar
teuben committed
  for(hi = 0, i = 0; hi < nhits && i < nents; hi++, i += ns + 3) {
    ns = hitbuf[i];
    if(ns < 1 || ns > 16)
	break;			/* trouble */
    z0 = hitbuf[i+1];

    if(id != hitbuf[i+3] || ns <= 1) continue;

teuben's avatar
teuben committed
    if(st->usepoly>1)		/* debug */
	printf(ns>1?"[%x %d/%d]":"[%x %d]", z0, hitbuf[i+3],hitbuf[i+4]);

    if(bestz > z0 && ns > 1 && (slno = hitbuf[i+4]) > 0) {
teuben's avatar
teuben committed
	bestz = z0;
	bestslno = slno;
	bestspeck = (ns>2) ? hitbuf[i+5] : 0;
    }
    if(st->picked != NULL && ns > 2) {
	for(sl = slhead, slno = 1; sl != NULL && slno < hitbuf[i+4]; sl = sl->next, slno++)
	    ;
	if(sl && hitbuf[i+5] < sl->nspecks)
	    if((*st->picked)(st, &hitbuf[i], sl, hitbuf[i+5]))
		return 0;
    }
  }

  if(st->picked != NULL) {
    if((*st->picked)(st, NULL, NULL, 0))
	return 0;
teuben's avatar
teuben committed
  }
  if(bestslno <= 0)
    return 0;

  for(sl = slhead, slno = 1; sl != NULL; sl = sl->next, slno++) {
    if(slno == bestslno) {
	if(bestspeck < 0 || bestspeck >= sl->nspecks) {
	    msg("Bogus pick result: sl %x bestspeck %d of 0..%d!\n",
		sl, bestspeck, sl->nspecks-1);
	    return 0;
	}
	if(slp) *slp = sl;
	if(specknop) *specknop = bestspeck;
	if(pos) {
	    if(bestspeck < 0 || bestspeck >= sl->nspecks)
		bestspeck = 0;
	    *pos = NextSpeck( sl->specks, sl, bestspeck )->p;
	}
	*bestzp = bestz;
	return 1;
    }
  }
  return 0;
}

int selname( struct stuff *st, char *name, int create ) {
    int i, avail;
    if(name == NULL) return 0;
    if(!strcmp(name, "all") || !strcmp(name, "on")) return SEL_ALL;
    if(!strcmp(name, "none") || !strcmp(name, "off")) return SEL_OFF;
    if(!strcmp(name, "thresh")) return SEL_THRESH;
    if(!strcmp(name, "pick")) return SEL_PICK;
    for(i = COUNT(st->selitems); --i >= 0; ) {
	if(!strcmp(name, st->selitems[i].name))
	    return i+1;
	if(st->selitems[i].name[0] == '\0') avail = i;
    }
    if(create) {
	sprintf(st->selitems[avail].name, "%.15s", name);
	return avail+1;
    }
    return 0;
}

void selinit( SelOp *sp ) {
    sp->wanted = 0;
    sp->wanton = 0;
    sp->use = SEL_NONE;
}

static char *selcat( struct stuff *st, char *from, int selno, int preop ) {
    char *what = "";
    static char s[8];
    switch(selno) {
    case SEL_NONE: what = "off"; break;
    case SEL_ALL: what = "all"; break;
    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) {
	    tail = selcat( st, tail, srcp->use, 0 );
	} else if(srcp->use == SEL_USE && srcp->wanted == 0) {
	    tail = selcat( st, tail, SEL_ALL, 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 = *dest;
    } else if(dest->use == SEL_DEST) {
	src->wanted = ~dest->wanted | dest->wanton;
	src->wanton = dest->wanton;
	src->use = SEL_USE;
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;
    } 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;
  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(destp && anydest) *destp = dest;
  if(srcp && anysrc) *srcp = src;
  return (anydest?1:0) + (anysrc?2:0);
  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';
	}
	while(*ip != '"') {
	    if(*ip == '\\') ip++;
	    if(*ip == '\0') goto eol;
	    *op++ = *ip++;
	}
	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;
  int room = 2;
  char *ep;
  static char *space = NULL;
  static int sroom = 0;
  for(k = arg0; k < argc; k++)
    room += strlen(argv[k]) + 1;
  if(room > sroom) {
    if(space) free(space);
    sroom = room + 50;
    space = malloc(sroom);
  }
  for(k = arg0, ep = space; k < argc; k++) {
    ep += sprintf(ep, "%s ", argv[k]);
  }
  if(ep > space) ep--;
  *ep = '\0';
  return space;
}
 
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 );
  int timestep = st->datatime;

  memset(m, 0, sizeof(*m));
  m->type = QUADMESH;
  m->txno = -1;
  m->pts = pts; m->tx = txs;
  alloced = COUNT(pts);

  if(!strcmp(argv[0], "quadmesh") || !strcmp(argv[0], "mesh")) {
    m->type = QUADMESH;
  }

  for(i = 1; i+1 < argc; i += 2) {
    if(!strncmp(argv[i], "-time", 3)) {
	timestep = atoi(argv[i+1]);
    } else if(!strncmp(argv[i], "-t", 2)) {
	havetx = sscanf(argv[i+1], "%d", &m->txno);
    } else if(!strcmp(argv[i], "-static")) {
	timestep = -1;
	i--;
    } 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;
  }

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



void specks_read_waveobj( struct stuff *st, int argc, char **argv, char *line, char *infname )
{
  struct mesh *m = NewN( struct mesh, 1 );
  int lno;
  int i, f;
  int timestep = st->datatime;
  FILE *inf;
  char *fname, *fullname;
#define CHUNK 500
  int kpts, kfvs, kfv0, kfvn;
  int npts, nfvs, nfv0, nfvn;
  struct chain {
	void *data;
	int pos;
	struct chain *next;
  } *cpts, *cfvs, *cfv0, *cfvn;
  Point vpts[CHUNK];
  int vfvs[CHUNK], vfv0[CHUNK], vfvn[CHUNK];


  memset(m, 0, sizeof(*m));
  m->type = POLYMESH;
  m->cindex = -1;
  m->txno = -1;

  for(i = 1; i+1 < argc; i += 2) {
    if(!strncmp(argv[i], "-time", 2)) {
	timestep = atoi(argv[i+1]);
    } else if(!strncmp(argv[i], "-texture", 3) || !strncmp(argv[i], "-tx", 3)) {
	sscanf(argv[i+1], "%d", &m->txno);
    } else if(!strcmp(argv[i], "-static")) {
	timestep = -1;
	i--;
    } 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;
    }
  }

  fname = argv[i];
  fullname = findfile( infname, fname );
  if(fullname == NULL || (inf = fopen(fullname, "r")) == NULL) {
    msg("waveobj: can't find .obj file %s", fname);
    return;
  }

#define VINIT(what) c##what = NULL, k##what = n##what = 0
#define VTOTAL(what) (k##what + n##what)
#define VNEXT(what) \
    if(++k##what >= CHUNK) { \
	struct chain *ct = (struct chain *)malloc(sizeof(*ct)); \
	ct->data = malloc(sizeof(v##what)); \
	memcpy(ct->data, v##what, sizeof(v##what)); \
	ct->pos = n##what; \
	ct->next = c##what; \
	c##what = ct; \
	k##what = 0; \
	n##what += CHUNK; \
    }
#define VSTUFF(dest, what) { \