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

    } else if(fast) {
	static unsigned char apxsize[MAXPTSIZE*MAXPTSIZE];
	unsigned char faintrand[256];
	int pxsize, oldpxsize;
	int pxmin, pxmax;

	pxmin = 256 * st->pfaint;
	if(st->plarge > MAXPTSIZE) st->plarge = MAXPTSIZE;
	pxmax = 256 * st->plarge * st->plarge;

	if(apxsize[1] == 0) {
	    for(i=0; i<COUNT(apxsize); i++)
		apxsize[i] = (int)ceil(sqrtf(i+1));
	}
	for(i = 0; i < 256; i++)
	    faintrand[i] = randskip[i] * st->pfaint;

	/* Render using fast (non-antialiased) points */
	glDisable( GL_POINT_SMOOTH );
	glEnable( GL_BLEND );
	glBlendFunc( GL_SRC_ALPHA, additive_blend ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA );

	prevrgba = 0;
	prevsize = 0;

	sl = slhead;

	pxsize = oldpxsize = 1;
	glPointSize( pxsize );
	glColor4ubv( (GLubyte *)&rgba );

	for(i = 0; i < MAXPTSIZE*2; i++)
	    nsized[i] = 0;

	glBegin( GL_POINTS );
	for(sl = slhead; sl != NULL; sl = sl->next) {
slevy's avatar
 
slevy committed
	    if(sl->text != NULL || sl->special != SPECKS) continue;
teuben's avatar
teuben committed
	    for(i = 0, p = sl->specks; i < sl->nspecks; i+=skip, p= NextSpeck(p, sl, skip)) {
		int lum, myalpha;
		float dist = VDOT( &p->p, &fwd ) + fwdd;
		if(dist <= 0)	/* Behind eye plane */
		    continue;

		if(usethresh & p->rgba)
		    continue;

		if(useclip &&
		  (p->p.x[0] < clipp0.x[0] ||
		   p->p.x[0] > clipp1.x[0] ||
		   p->p.x[1] < clipp0.x[1] ||
		   p->p.x[1] > clipp1.x[1] ||
		   p->p.x[2] < clipp0.x[2] ||
		   p->p.x[2] > clipp1.x[2]))
		    continue;


		lum = 256 * plum * p->size / (dist*dist);

		if(lum < pxmin) {
		    if(lum <= faintrand[(i*i+i) /*randix++*/ & 0xFF])
			continue;
		    pxsize = 1;
		    myalpha = pxmin;
		} else if(lum < 256) {
		    pxsize = 1;
		    myalpha = lum;
		} else if(lum < pxmax) {
		    pxsize = apxsize[lum>>8];
		    myalpha = lum / (pxsize*pxsize);
		} else {
		    /* Could use a polygon here, instead. */
		    pxsize = st->plarge;
		    myalpha = 255;
		}

		if(pxsize < 1 || pxsize > 6 || myalpha <= 0 || myalpha > 255) {
		    static int oops;
		    oops++;
		}
		if(myalpha < 0 || myalpha > 255 || invgamma[myalpha] <= 0 || invgamma[myalpha] > 255) {
		    static int oops2;
		    oops2++;
		}
		rgba = RGBALPHA( p->rgba&~THRESHBIT, invgamma[myalpha] & 0xFC );

		if(pxsize != oldpxsize) {
		    if(nsized[pxsize] >= PERBUCKET) {
			glEnd();
			glPointSize(pxsize);
			glBegin( GL_POINTS );
			dumpcpoints( &sized[pxsize][0], PERBUCKET );
			nsized[pxsize] = 0;
			oldpxsize = pxsize;
			glColor4ubv( (GLubyte *)&rgba );
			prevrgba = rgba;
			glVertex3fv( &p->p.x[0] );

		    } else {
			struct cpoint *cp = &sized[pxsize][nsized[pxsize]];
			cp->rgba = rgba;
			cp->p = p->p;
			nsized[pxsize]++;
		    }
		} else {
		    /* same as current pointsize */
		    if(rgba != prevrgba) {
			glColor4ubv( (GLubyte *)&rgba );
			prevrgba = rgba;
		    }

		    glVertex3fv( &p->p.x[0] );
		}
	    }
	}
	glEnd();

	for(i = 0; i < MAXPTSIZE; i++) {
	    if(nsized[i] > 0) {
		glPointSize( i );
		glBegin( GL_POINTS );
		dumpcpoints( &sized[i][0], nsized[i] );
		glEnd();
	    }
	}

    } else {

	/* 
	 * Render using anti-aliased points
	 */
	static unsigned char apxsize[(MAXPTSIZE*2)*(MAXPTSIZE*2)];
	unsigned char faintrand[256];
	static float percoverage[MAXPTSIZE*2];
	static int needMesaHack = 0;
	int pxsize, oldpxsize;
	int pxmin, pxmax;
	int minsize, minalpha;

	pxmin = (256 * (2*2)) * st->pfaint;
	if(st->plarge > MAXPTSIZE*2) st->plarge = MAXPTSIZE*2;
	pxmax = (256 * (2*2)) * st->plarge * st->plarge;

	if(apxsize[1] == 0) {
	    char *version = (char *)glGetString( GL_VERSION );

	    /* Hack: MESA doesn't handle small anti-aliased points well;
	     * force them all to be of size 1.0 or 2.0 (i.e. pxsize == 2 or 4),
	     * and non-antialiased.
	     */
	    if(getenv("MESAHACK") != NULL)
		needMesaHack = atoi(getenv("MESAHACK"));
	    else if(version &&
		  (!strncmp(version, "CRIME", 5) || !strncmp(version, "IR", 2)))
		needMesaHack = 0;	/* O2 & IR: nice anti-aliased points */
	    else
		needMesaHack = -1;	/* IMPACT (& others?): ugly AA points */

	    for(i=0; i<COUNT(apxsize); i++) {
		apxsize[i] = (int)ceil(sqrtf(i+1));
		if(needMesaHack>0) {
		    if(apxsize[i] <= 2) apxsize[i] = 2;
		    else if(needMesaHack<2 && apxsize[i] <= 4) apxsize[i] = 4;
		}
	    }

	    for(i = 1; i < MAXPTSIZE*2; i++) {
		percoverage[i] = 1.0 / (i*i);
		if(needMesaHack>0) {
		    if(i <= 2) percoverage[i] = .25;
		    else if(needMesaHack<2 && i <= 4) percoverage[i] = .0625;
		}
	    }
	    percoverage[0] = 1.0;

	    if(needMesaHack < 0)
		percoverage[1] = 0.25;	/* if gfx treats psize 0.5 == 1.0 */

	}

	minsize = apxsize[ pxmin >> 8 ];
	minalpha = pxmin * percoverage[ minsize ];

	for(i = 0; i < 256; i++)
	    faintrand[i] = randskip[i] * st->pfaint;

	/* Render using antialiased points */
	glEnable( GL_POINT_SMOOTH );
	glEnable( GL_BLEND );
	glBlendFunc( GL_SRC_ALPHA, additive_blend ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA );

	prevrgba = 0;
	prevsize = 0;

	sl = slhead;

	pxsize = 2;
	oldpxsize = 99;
	glPointSize( pxsize );
	glColor4ubv( (GLubyte *)&rgba );

	for(i = 0; i < MAXPTSIZE*2; i++)
	    nsized[i] = 0;

	glBegin( GL_POINTS );
	for(sl = slhead; sl != NULL; sl = sl->next) {
slevy's avatar
 
slevy committed
	    if(sl->text != NULL || sl->special != SPECKS) continue;
slevy's avatar
 
slevy committed
	    for(i = 0, p = sl->specks; i < sl->nspecks; i+=skip, p=NextSpeck(p,sl,skip)) {
teuben's avatar
teuben committed
		int lum, myalpha;
		float dist, dist2, dx, dy, dz;

		if(usethresh & p->rgba)
		    continue;
		if(useclip &&
		  (p->p.x[0] < clipp0.x[0] ||
		   p->p.x[0] > clipp1.x[0] ||
		   p->p.x[1] < clipp0.x[1] ||
		   p->p.x[1] > clipp1.x[1] ||
		   p->p.x[2] < clipp0.x[2] ||
		   p->p.x[2] > clipp1.x[2]))
		    continue;


		switch(fademodel) {
		case F_PLANAR:
		    dist = VDOT( &p->p, &fwd ) + fwdd;
		    if(dist <= 0)	/* Behind eye plane */
			continue;
		    dist2 = dist*dist;
		    break;
		case F_CONSTANT:
		    dist2 = orthodist2;
		    break;
		case F_SPHERICAL:
		    dx = p->p.x[0]-eyepoint.x[0];
		    dy = p->p.x[1]-eyepoint.x[1];
		    dz = p->p.x[2]-eyepoint.x[2];
		    dist2 = dx*dx + dy*dy + dz*dz;
		    break;

		case F_LREGION:	/* not impl yet */
		    dist = VDOT( &p->p, &fwd ) + fwdd;
		    if(dist <= 0)	/* Behind eye plane */
			continue;
		    dx = p->p.x[0] - fadecen.x[0];
		    dy = p->p.x[1] - fadecen.x[1];
		    dz = p->p.x[2] - fadecen.x[2];
		    dist2 = dist * st->fadeknee2
				/ (1 + (dx*dx + dy*dy + dz*dz) * faderball2);
		    break;
		case F_LINEAR:
		    dist = VDOT( &p->p, &fwd ) + fwdd;
		    if(dist <= 0)	/* Behind eye plane */
			continue;
		    dist2 = dist * st->fadeknee2;
		    break;
			
		case F_KNEE2:
		    dx = p->p.x[0]-eyepoint.x[0];
		    dy = p->p.x[1]-eyepoint.x[1];
		    dz = p->p.x[2]-eyepoint.x[2];
		    dist2 = dx*dx + dy*dy + dz*dz;
		    if(dist2 > knee2dist2)
			dist2 *= 1 + steep2knee2 * (dist2 - knee2dist2);
		    break;
		case F_KNEE12:
		    dx = p->p.x[0]-eyepoint.x[0];
		    dy = p->p.x[1]-eyepoint.x[1];
		    dz = p->p.x[2]-eyepoint.x[2];
		    dist2 = dx*dx + dy*dy + dz*dz;
		    if(dist2 < knee1dist2)
			dist2 = knee1dist2;
		    else if(dist2 > knee2dist2)
			dist2 *= 1 + steep2knee2 * (dist2 - knee2dist2);
		    break;
		}

		lum = (256 * (2*2)) * plum * p->size / dist2;

		if(lum <= pxmin) {
		    if(lum <= faintrand[(i*i+i) /*randix++*/ & 0xFF])
			continue;
		    pxsize = minsize;
		    myalpha = minalpha;
		} else if(lum < pxmax) {
		    pxsize = apxsize[lum>>8];
		    myalpha = lum * percoverage[pxsize];
		} else {
		    /* Could use a polygon here, instead. */
		    pxsize = 2 * st->plarge;
		    myalpha = 255;
		}

		if(pxsize < 1 || pxsize >= MAXPTSIZE*2 || myalpha <= 0 || myalpha > 255) {
		    static int oops;
		    oops++;
		    pxsize = MAXPTSIZE*2 - 1;
		    myalpha = 255;
		}
		rgba = RGBALPHA( p->rgba&~THRESHBIT, invgamma[myalpha] & 0xFC );

		if(pxsize != oldpxsize) {
		    if(nsized[pxsize] >= PERBUCKET) {
			glEnd();
			if(needMesaHack>0 && (pxsize <= 4) != (oldpxsize <= 4)) {
			    if(pxsize <= 4) glDisable( GL_POINT_SMOOTH );
			    else glEnable( GL_POINT_SMOOTH );
			}
			glPointSize(.5*pxsize);
			glBegin( GL_POINTS );
			dumpcpoints( &sized[pxsize][0], PERBUCKET );
			nsized[pxsize] = 0;
			oldpxsize = pxsize;
			glColor4ubv( (GLubyte *)&rgba );
			prevrgba = rgba;
			glVertex3fv( &p->p.x[0] );

		    } else {
			struct cpoint *cp = &sized[pxsize][nsized[pxsize]];
			cp->rgba = rgba;
			cp->p = p->p;
			nsized[pxsize]++;
		    }
		} else {
		    /* same as current pointsize */
		    if(rgba != prevrgba) {
			glColor4ubv( (GLubyte *)&rgba );
			prevrgba = rgba;
		    }

		    glVertex3fv( &p->p.x[0] );
		}
	    }
	}
	glEnd();

	if(needMesaHack>0)
	    glDisable( GL_POINT_SMOOTH );

	for(i = 0; i < MAXPTSIZE*2; i++) {
	    if(needMesaHack>0 && i == 4)
		glEnable( GL_POINT_SMOOTH );
	    if(nsized[i] > 0) {
		glPointSize( .5*i );
		glBegin( GL_POINTS );
		dumpcpoints( &sized[i][0], nsized[i] );
		glEnd();
	    }
	}

    }
  }

  if(st->usetext && st->textsize != 0) {
teuben's avatar
teuben committed
    for(sl = slhead, slno = 1; sl != NULL; sl = sl->next, slno++) {
	if(sl->text != NULL && (p = sl->specks) != NULL) {
	    float dist = VDOT( &p->p, &fwd ) + fwdd;
	    float tsize;

	    if(dist <= 0)
		continue;

	    if(inpick) glLoadName(slno);

	    tsize = st->textsize * p->size;
	    if(tsize < dist * (radperpix * st->textmin)) {
		/* Could draw a stub here -- a simple line segment of
		 * about the right length
		 */
		Point ep;
		/* extract top row of Ttext -- this is the unit screen-space X
		 * vector, expressed in world coords.  Scale to suit.
		 */
		vcomb( &ep,
		    p->size * sfStrWidth(sl->text), (Point *)&Ttext.m[0],
		    1, &p->p );

		if(p->rgba != cment) {
		    if((unsigned int)p->rgba >= st->textncmap)
			glColor3f( 1, 1, 1 );
		    else
			glColor3ubv( (GLubyte *)&st->textcmap[ p->rgba ].cooked );
		    cment = p->rgba;
		}
teuben's avatar
teuben committed
		glBegin( GL_LINES );
		glVertex3fv( p->p.x );
		glVertex3fv( ep.x );
		glEnd();
		continue;
	    }

	    /* Otherwise, it's big enough to see -- draw actual text */

	    glPushMatrix();
	    glTranslatef( p->p.x[0], p->p.x[1], p->p.x[2] );
	    if(st->usetextaxes) {
		static unsigned char col[3][3] = {255,0,0, 0,255,0, 0,0,255};
		static float pos[3][3] = {1,0,0, 0,1,0, 0,0,1};
		glPushMatrix();
		glScalef( tsize, tsize, tsize );
		glBegin(GL_LINES);
		for(k = 0; k < 3; k++) {
		    glColor3ubv( &col[k][0] );
		    glVertex3f(0,0,0);
		    glVertex3fv( &pos[k][0] );
		}
		glEnd();
		glPopMatrix();
	    }
	    if(p->rgba != cment || st->usetextaxes) {
		if((unsigned int)p->rgba >= st->textncmap)
		    glColor3f( 1, 1, 1 );
		else
		    glColor3ubv( (GLubyte *)&st->textcmap[ p->rgba ].cooked );
		cment = p->rgba;
	    }
teuben's avatar
teuben committed
	    glMultMatrixf( Ttext.m );
	    sfStrDraw( sl->text, p->size, NULL );
	    glPopMatrix();
	}
    }
  }

  if(inpick) glLoadName(0);

  if(st->usemeshes) {
    struct mesh *m;
    int texturing = 0;

    glEnable( GL_BLEND );
    glBlendFunc( GL_SRC_ALPHA, additive_blend ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA );
    glColor4f(1, 1, 1, st->alpha);
    for(m = st->staticmeshes; m != NULL; m = m->next)
	specks_draw_mesh(st, m, &texturing);

    if(texturing) txbind(NULL, NULL);
  }

  if(st->useellipsoids) {
    struct ellipsoid *e;

    glEnable( GL_BLEND );
    glBlendFunc( GL_SRC_ALPHA, additive_blend ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA );
    glColor4f(1, 1, 1, st->alpha);
    for(e = st->staticellipsoids; e != NULL; e = e->next)
	specks_draw_ellipsoid(st, e);
  }


teuben's avatar
teuben committed
  for(i = 0; i < 6; i++)	/* in case clipbox was enabled when we began */
    glDisable( GL_CLIP_PLANE0 + i );


  glColor4ub(255,255,255,255);
  glDisable( GL_BLEND );
  glEnable( GL_DEPTH_TEST );	/* was already enabled */
  glDepthMask( GL_TRUE );
}

void specks_draw_ellipsoid( struct stuff *st, struct ellipsoid *e )
  int nu = e->nu;
  int nv = e->nv;
  float *su = NewA( float, nu );
  float *cu = NewA( float, nu );
  float *sv = NewA( float, nv );
  float *cv = NewA( float, nv );
  int u, v;
  for(u = 0; u < nu; u++) {
    float tu = 2*M_PI*u/nu;
    su[u] = sin(tu);
    cu[u] = cos(tu);
  }
  for(v = 0; v < nv; v++) {
    float tv = M_PI*v/(nv-1);
    sv[v] = sin(tv);
    cv[v] = cos(tv);
  }
  glPushMatrix();
  glTranslatef( e->pos.x[0],e->pos.x[1],e->pos.x[2] );
  if(e->hasori)
    glMultMatrixf( &e->ori.m[0] );
  glScalef( e->size.x[0], e->size.x[1], e->size.x[2] );

  if(e->cindex >= 0) {
    int rgba =
	RGBALPHA(
	   RGBWHITE & st->cmap[(e->cindex < st->ncmap) ? e->cindex : st->ncmap-1].cooked,
	   (int)(st->alpha * 255));
    glColor4ubv((GLubyte *)&rgba);
  }
  switch(e->style) {
  case SOLID:
    for(v = 1; v < nv; v++) {
	glBegin( GL_QUAD_STRIP );
	for(u = 0; u < nu; u++) {
	    glVertex3f( cu[u]*sv[v-1], su[u]*sv[v-1], cv[v-1] );
	    glVertex3f( cu[u]*sv[v], su[u]*sv[v], cv[v] );
	}
	glVertex3f( cu[0]*sv[v-1], su[0]*sv[v-1], cv[v-1] );
	glVertex3f( cu[0]*sv[v], su[0]*sv[v], cv[v] );
	glEnd();
    }
    break;

  case LINE:
    for(v = 1; v < nv-1; v++) {
	glBegin( GL_LINE_LOOP );
	for(u = 0; u < nu; u++)
	    glVertex3f( cu[u]*sv[v], su[u]*sv[v], cv[v] );
	glEnd();
    }
    for(u = 0; u < nu; u++) {
	glBegin( GL_LINE_STRIP );
	for(v = 0; v < nv; v++)
	    glVertex3f( cu[u]*sv[v], su[u]*sv[v], cv[v] );
	glEnd();
    }
    break;
  case PLANE:
    glBegin( GL_LINE_LOOP );
    for(u = 0; u < nu; u++)
	glVertex3f( cu[u], su[u], 0 );
    glEnd();
    glBegin( GL_LINE_LOOP );
    for(u = 0; u < nu; u++)
	glVertex3f( cu[u], 0, su[u] );
    glEnd();
    glBegin( GL_LINE_LOOP );
    for(u = 0; u < nu; u++)
	glVertex3f( 0, cu[u], su[u] );
    glEnd();
    break;

  case POINT:
    glPointSize( 1.0 );
    glBegin( GL_POINTS );
    glVertex3f( 0,0,1 );
    glVertex3f( 0,0,-1 );
    for(v = 1; v < nv-1; v++) {
	for(u = 0; u < nu; u++)
	    glVertex3f( cu[u]*sv[v], su[u]*sv[v], cv[v] );
    }
    glEnd();
    break;
void specks_draw_mesh( struct stuff *st, register struct mesh *m, int *texturing )
{
  int u, v, prev, cur;
  int usetx;

  usetx = (st->usetextures && m->tx != NULL
		&& m->txno >= 0 && m->txno < st->ntextures
		&& st->textures[m->txno] != NULL);
  txbind( usetx ? st->textures[m->txno] : NULL, texturing );
  if(m->cindex >= 0) {
    int rgba =
	RGBALPHA(
	   RGBWHITE & st->cmap[(m->cindex < st->ncmap) ? m->cindex : st->ncmap-1].cooked,
	   (int)(st->alpha * 255));
    glColor4ubv((GLubyte *)&rgba);
  }

  for(v = 1; v < m->nv; v++) {
    prev = (v-1) * m->nu;
    cur = v * m->nu;
    glBegin( GL_QUAD_STRIP );
    for(u = 0; u < m->nu; u++) {
	if(usetx) {
	    glTexCoord2fv( &m->tx[prev+u].x[0] );
	    glVertex3fv( &m->pts[prev+u].x[0] );
	    glTexCoord2fv( &m->tx[cur+u].x[0] );
	    glVertex3fv( &m->pts[cur+u].x[0] );
	} else {
	    glVertex3fv( &m->pts[prev+u].x[0] );
	    glVertex3fv( &m->pts[cur+u].x[0] );
	}
    }
    glEnd();
  }
}

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;
  int blevels = (st->boxlevels > 1 ? st->boxlevels-1 : 1);
  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;
	    char lbl[16];
	    glPushMatrix();
	    glTranslatef( .75*box->p0.x[0] + .25*box->p1.x[0],
			  .75*box->p0.x[1] + .25*box->p1.x[1],
			  .75*box->p0.x[2] + .25*box->p1.x[2]);
	    glMultMatrixf( Ttext.m );
	    sprintf(lbl, "%d", box->boxno);
	    sfStrDraw( lbl, sz, NULL );
	    glPopMatrix();
	}
    }
  }
  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;

  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(st->usepoly>1)		/* debug */
	printf(ns>1?"[%x %d/%d]":"[%x %d]", z0, hitbuf[i+3],hitbuf[i+4]);

    if(id == hitbuf[i+3] && bestz > z0 && ns > 1 && (slno = hitbuf[i+4]) > 0) {
	bestz = z0;
	bestslno = slno;
	bestspeck = (ns>2) ? hitbuf[i+5] : 0;
    }
  }
  if(bestslno <= 0)
    return 0;

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


#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->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);
    }
    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, int keepcomment)
{
  register char *ip = str;
  register char *op = tbuf;
  int argc = 0;

  while(argc < maxargs-1) {
    while(isspace(*ip)) ip++;
    if(*ip == '\0') goto eol;
    argv[argc++] = op;
    switch(*ip) {
    case '#':
	if(keepcomment) {
	    while(*ip && *ip != '\n' && *ip != '\r')
		*op++ = *ip++;
	    *op = '\0';
	} else {
	    argc--;
	}
	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))
    return SOLID;
  if(!strncmp(str, "wire", 4) || !strncmp(str, "line", 4))
    return LINE;
  if(!strncmp(str, "plane", 5) || !strncmp(str, "ax", 2))
    return PLANE;
  if(!strncmp(str, "point", 5))
    return POINT;
  if(!strcmp(str, "off"))
    return OFF;
  msg("Unknown surface style \"%s\": want solid|line|plane|point|off", str);
  return SOLID;
}

/*
 * 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 ) {
  int i;
  struct ellipsoid e, *ep;
  float m3[3*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(argv[argc-1][0] == '#') {
    char *title = &argv[argc-1][1];
    if(*title == ' ') title++;
    e.title = title;
    argc--;
  }

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