Skip to content
Snippets Groups Projects
partibrains.c 189 KiB
Newer Older
teuben's avatar
teuben committed
    glMatrixMode( GL_TEXTURE );
    glLoadIdentity();
    glTranslatef( .5, .5, 0 );
    glScalef( st->txscale, st->txscale, st->txscale );
    glMatrixMode( GL_MODELVIEW );

    /* Textures seem to be multiplied by some mysterious factor,
     * unless we're in GL_SMOOTH mode.  What gives?
     */
    glShadeModel( texturevar >= 0 ? GL_SMOOTH : GL_FLAT );

teuben's avatar
teuben committed

    polyminrad = st->polymin * radperpix;
    polymaxrad = st->polymax * radperpix;
    mins2d = polyminrad*polyminrad;

    if(sizevar == -1) {
	/* If polygon size is tied to point size,
	 * then include pointsize scale factors in polygon scaling.
	 */
      if((unsigned int)st->sizedby <= MAXVAL
		&& (unsigned int)st->curdata < MAXFILES
		&& st->vdesc[st->curdata][st->sizedby].lum != 0)
	polysize *= st->vdesc[st->curdata][st->sizedby].lum;
slevy's avatar
 
slevy committed
      if(st->subsample > 0 && st->everycomp)
teuben's avatar
teuben committed
        polysize *= st->subsample; /* Compensate for "every" subsampling */
    }

slevy's avatar
 
slevy committed
    if(st->depthsort && !inpick) {
	depth_fwd = fwd;
	depth_d = fwdd;
	sortedpolys( st, slhead, &Tc2w, radperpix, polysize );

    } else {
      int polyalpha = alpha;
      int usepolymax = (st->polymax < 1e8);

#ifdef POLYFADE
      int polyfade = 0;
      if(st->polyfademax > st->polymin) {
	polyfade = 1;
	polyfadesize = 
	glEnable(GL_BLEND);
	glBlendFunc( GL_SRC_ALPHA, additive_blend ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA );
      }
#endif

slevy's avatar
 
slevy committed
      for(sl = slhead, slno = 1; sl != NULL; sl = sl->next, slno++) {
slevy's avatar
 
slevy committed
	if(sl->text != NULL || sl->special != SPECKS) continue;
teuben's avatar
teuben committed
	if(inpick) {
	    glLoadName(slno);
	    glPushName(0);
	}
	for(i = 0, p = sl->specks; i < sl->nspecks; i+=skip, p = NextSpeck( p, sl, skip )) {
	    float dist = VDOT( &p->p, &fwd ) + fwdd;
	    float size;

	    if(!SELECTED(sl->sel[i], &seesel))
teuben's avatar
teuben committed
		continue;

	    size = p->val[sizevar] * polysize;

	    if(dist + size <= 0) continue;
teuben's avatar
teuben committed
	    if(usearea) {
		if(size < dist * dist * mins2d)
		    continue;
		size = sqrtf(size);
	    } else {
		if(size < dist * polyminrad)
		    continue;
	    } 
	    if(usepolymax && size > dist * polymaxrad && dist > 0)
teuben's avatar
teuben committed
		size = dist * polymaxrad;

	    rgba = p->rgba & RGBBITS;
teuben's avatar
teuben committed
	    if(rgba != prevrgba) {
		prevrgba = rgba;
		rgba = RGBALPHA( prevrgba, alpha );
		glColor4ubv( (GLubyte *)&rgba );
	    }
	    if(st->polyorivar0 >= 0 && p->val[st->polyorivar0] < 9) {
		for(k = 0; k < nxyfan; k++) {
		    vcomb( &fan[k],
			size*xyfan[k][0], (Point *)&p->val[st->polyorivar0],
			size*xyfan[k][1], (Point *)&p->val[st->polyorivar0+3] );
		}
	    } else if(p->size != prevsize) {
		float s = scl*size;
		for(k = 0; k < nxyfan; k++) {
slevy's avatar
 
slevy committed
		    vcomb( &fan[k], s*xyfan[k][0], (Point *)&Tc2w.m[0*4+0],
				    s*xyfan[k][1], (Point *)&Tc2w.m[1*4+0] );
teuben's avatar
teuben committed
		}
		prevsize = size;
	    }

#define PFAN(vno, comp)  p->p.x[comp] + fan[vno].x[comp]

	    if(inpick) {
		glLoadName( i );
		glBegin( GL_TRIANGLE_FAN );
		for(k = 0; k < nxyfan; k++) {
		    glVertex3f( PFAN(k,0), PFAN(k,1), PFAN(k,2) );
		}
		glEnd();

	    } else if(texturevar >= 0
slevy's avatar
 
slevy committed
		    && (txno = p->val[texturevar]) >= 0
teuben's avatar
teuben committed
		    && txno < st->ntextures &&
		    st->textures[txno] != NULL) {

		txbind( st->textures[txno], &texturing );

		glBegin( GL_TRIANGLE_FAN );
		for(k = 0; k < nxyfan; k++) {
		    glTexCoord2fv( &xyfan[k][0] );
		    glVertex3f( PFAN(k,0), PFAN(k,1), PFAN(k,2) );
		}
		glEnd();

	    } else {
		if(texturing) {
		    texturing = 0;
		    glDisable( GL_TEXTURE_2D );
		}
		glBegin(GL_TRIANGLE_FAN);
		for(k = 0; k < nxyfan; k++)
		    glVertex3f( PFAN(k,0), PFAN(k,1), PFAN(k,2) );
		glEnd();
	    }
#undef PFAN

	}
	if(inpick) glPopName();
slevy's avatar
 
slevy committed
      }
teuben's avatar
teuben committed
    }
    if(texturing) {
slevy's avatar
 
slevy committed
	txbind( NULL, NULL );
teuben's avatar
teuben committed
	glDisable( GL_TEXTURE_2D );
    }
    glMatrixMode( GL_TEXTURE );
    glLoadIdentity();
    glMatrixMode( GL_MODELVIEW );
  }

  if(st->usepoint && !(st->useboxes == 2)) {

#define MAXPTSIZE 32	/* in half-point units */
teuben's avatar
teuben committed
#define PERBUCKET 64	/* max points per bucket */

    struct cpoint sized[MAXPTSIZE*2][PERBUCKET];
    int nsized[MAXPTSIZE*2];
    unsigned char invgamma[256];
    float invgam = (st->gamma <= 0) ? 0 : 1/st->gamma;

    for(i = 0; i < 256; i++)
	invgamma[i] = (int) (255.99 * pow( i/255., invgam ));

    if(inpick) {
	for(sl = slhead, slno = 1; sl != NULL; sl = sl->next, slno++) {
slevy's avatar
 
slevy committed
	    if(sl->text != NULL || sl->special != SPECKS) continue;
teuben's avatar
teuben committed
	    glLoadName(slno);
	    glPushName(0);
	    for(i = 0, p = sl->specks; i < sl->nspecks; i+=skip, p = NextSpeck(p, sl, skip)) {
		if(!SELECTED(sl->sel[i], &seesel))
teuben's avatar
teuben committed
		    continue;

		glLoadName(i);
		glBegin(GL_POINTS);
		glVertex3fv( &p->p.x[0] );
		glEnd();
	    }
	    glPopName();
	}

    } 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(!SELECTED(sl->sel[i], &seesel))
teuben's avatar
teuben committed
		    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&RGBBITS, invgamma[myalpha] & 0xFC );
teuben's avatar
teuben committed

		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(!SELECTED(sl->sel[i], &seesel))
teuben's avatar
teuben committed
		    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&RGBBITS, invgamma[myalpha] & 0xFC );
teuben's avatar
teuben committed

		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) {
    int textmin = abs(st->textmin);
    int label_stubs = (st->textmin < 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 * textmin)) {
		if(label_stubs) {
		    /* Draw a stub: 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;
		    }
		    glBegin( GL_LINES );
		    glVertex3fv( p->p.x );
		    glVertex3fv( ep.x );
		    glEnd();
teuben's avatar
teuben committed
		continue;
	    }

	    /* Otherwise, label is big enough to see -- draw actual text */
teuben's avatar
teuben committed

	    if(st->usetextaxes) {
		static unsigned char col[3][3] = {255,0,0, 0,255,0, 0,0,255};
		glBegin(GL_LINES);
		for(k = 0; k < 3; k++) {
		    glColor3ubv( &col[k][0] );
		    glVertex3fv( p->p.x );
		    glVertex3f( p->p.x[0] + (k==0?tsize:0),
				p->p.x[1] + (k==1?tsize:0), 
				p->p.x[2] + (k==2?tsize:0) );
teuben's avatar
teuben committed
		}
		glEnd();
	    }
	    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;
	    }
	    sfStrDrawTJ( sl->text, p->size, &p->p, &Ttext, NULL );
teuben's avatar
teuben committed
	}
    }
  }

  if(inpick) glLoadName(0);

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

    if(additive_blend) {
	glEnable( GL_BLEND );
	glBlendFunc( GL_SRC_ALPHA, GL_ONE );
    } else {
	glDisable( GL_BLEND );
    }
    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;

    if(additive_blend) {
	glEnable( GL_BLEND );
	glBlendFunc( GL_SRC_ALPHA, GL_ONE );
    } else {
	glDisable( GL_BLEND );
    }
    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;
  int u, v;
  float *su, *cu, *sv, *cv;

  if(st->boxlevelmask == 0 || e->level >= 0 && ((1 << e->level) & st->boxlevelmask) == 0)
    return;

  if(nu == 0 && nv == 0) {
    nu = 15;
    nv = 10;
  }
  su = NewA( float, nu );
  cu = NewA( float, nu );
  sv = NewA( float, nv );
  cv = NewA( float, nv );
  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) {
    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;

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

    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);
  }
  switch(m->style) {
    case S_SOLID:
    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] );
	    }
    break;

    case S_LINE:
    	for(v = 0; v < m->nv; v++) {
	    glBegin( GL_LINE_STRIP );
	    cur = v * m->nu;
	    for(u = 0; u < m->nu; u++)
		glVertex3fv( &m->pts[cur+u].x[0] );
	    glEnd();
	}
	for(u = 0; u < m->nu; u++) {
	    glBegin( GL_LINE_STRIP );
	    for(v = 0; v < m->nv; v++)
		glVertex3fv( &m->pts[v*m->nu + u].x[0] );
	    glEnd();
	}
	break;

    case S_POINT:
	cur = m->nu * m->nv;
	glBegin( GL_POINTS );
	for(u = 0; u < cur; u++)
	    glVertex3fv( &m->pts[u].x[0] );
	glEnd();
	break;

    case S_PLANE:
	glBegin( GL_LINE_LOOP );
	for(u = 0; u < m->nu; u++)
	    glVertex3fv( &m->pts[u].x[0] );
	for(v = 1; v < m->nv; v++)
	    glVertex3fv( &m->pts[v*m->nu + m->nu-1].x[0] );
	cur = (m->nv-1) * m->nu;
	for(u = m->nu; --u >= 0; )
	    glVertex3fv( &m->pts[cur+u].x[0] );
	for(v = m->nv-1; --v > 0; )
	    glVertex3fv( &m->pts[v*m->nu].x[0] );
	glEnd();
	break;
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;
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;
    }