Skip to content
Snippets Groups Projects
partibrains.c 205 KiB
Newer Older
		    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 && st->alpha < 1) {
	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);
    for(m = CURDATATIME(meshes); 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 );
teuben's avatar
teuben committed
}

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);
  }
  glLineWidth( e->linewidth > 0 ? e->linewidth : 1.0f );

  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;
slevy's avatar
slevy committed
  int usetx, usetx3d;
  float gap, ungap;
  int f, was;
  int usemullions = (st->mullions > 0);

  usetx = (st->usetextures && m->tx != NULL
		&& m->txno >= 0 && m->txno < st->ntextures
		&& st->textures[m->txno] != NULL);
slevy's avatar
slevy committed
  usetx3d = usetx && (st->textures[m->txno]->flags & TXF_3D);
  glLineWidth( m->linewidth > 0 ? m->linewidth : 1.0f );
  txbind( usetx ? st->textures[m->txno] : NULL, texturing );
  if(m->fnorms != NULL && st->usemeshes != 2) {
    static float amb[4] = { 0,0,0, 1 };
    static float spec[4] = { .8,.8,.8, 1 };
    glEnable( GL_LIGHTING );
    glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
    glEnable( GL_COLOR_MATERIAL );
    glShadeModel( GL_SMOOTH );
    glMaterialf( GL_FRONT_AND_BACK, GL_SHININESS, 20. );
    glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, amb );
    glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, spec );
  } else {
    glDisable( GL_LIGHTING );
    glDisable( GL_COLOR_MATERIAL );
  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);
  } else if(st->coloredby == CONSTVAL) {
    struct valdesc *vd = &st->vdesc[st->curdata][CONSTVAL];
    glColor4f( vd->cmin, vd->cmax, vd->mean, st->alpha );
  switch(m->type) {
  case MODEL:
    if(m->objrender)
	(*m->objrender)( st, m );
    break;
  case QUADMESH:
    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 );
slevy's avatar
slevy committed
	    if(usetx) {
		if(usetx3d) {
		    for(u = 0; u < m->nu; u++) {
			glTexCoord3fv( &m->tx[prev+u].x[0] );
			glVertex3fv( &m->pts[prev+u].x[0] );
			glTexCoord3fv( &m->tx[cur+u].x[0] );
			glVertex3fv( &m->pts[cur+u].x[0] );
		    }
slevy's avatar
slevy committed
		    for(u = 0; u < m->nu; u++) {
			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 {
		for(u = 0; u < m->nu; u++) {
		    glVertex3fv( &m->pts[prev+u].x[0] );
		    glVertex3fv( &m->pts[cur+u].x[0] );
		}
	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] );
	    break;
    }
    break;

  case POLYMESH:
    gap = st->mullions;
    ungap = 1 - gap;
   
    was = 0;
    for(f = 0; f < m->nfaces; f++) {
	int fv0 = m->fv0[f];
	int fvn = m->fvn[f];
	int *fvs0 = &m->fvs[ fv0 ];
	Point *pts = m->pts;
	Point *txs = m->tx;
	Point *vnorms = m->vnorms;

#define FVERT(i)   fvs0[(i)*FVSTEP + FVS_VERT]
#define FTX(i)     fvs0[(i)*FVSTEP + FVS_TX]
#define FVNORM(i)  fvs0[(i)*FVSTEP + FVS_VNORM]

	int usevn = unlit ? -1 : (FVNORM(0) >= 0) ? 1 : 0;
	int usetex = usetx && (FTX(0) >= 0);
	    glNormal3fv( m->fnorms[f].x );

	if(fvn == 2) {
	    if(was != GL_LINES) {
		if(was) glEnd();
		glBegin( was=GL_LINES );
	    }
	    glVertex3fv( pts[ FVERT(0) ].x );
	    glVertex3fv( pts[ FVERT(1) ].x );

	} else if(fvn == 3) {
	    Point bary, *p0, *p1, *p2;
	    if(usemullions) {
		p0 = &pts[ FVERT(0) ];
		p1 = &pts[ FVERT(1) ];
		p2 = &pts[ FVERT(2) ];
		bary.x[0] = (p0->x[0] + p1->x[0] + p2->x[0]) * 0.3333333333f;
		bary.x[1] = (p0->x[1] + p1->x[1] + p2->x[1]) * 0.3333333333f;
		bary.x[2] = (p0->x[2] + p1->x[2] + p2->x[2]) * 0.3333333333f;
#define INTERP(p) p->x[0]*gap + bary.x[0]*ungap, p->x[1]*gap + bary.x[1]*ungap, p->x[2]*gap + bary.x[2]*ungap
#define TXINTERP(tx) tx->x[0]*gap + txbary[0]*ungap, tx->x[1]*gap + txbary[1]*ungap

		if(was) {
		    was = 0;
		    glEnd();
		}
		glBegin( GL_QUAD_STRIP );
		    Point *tx0 = &txs[ FTX(0) ];
		    Point *tx1 = &txs[ FTX(1) ];
		    Point *tx2 = &txs[ FTX(2) ];
		    float txbary[2];

		    txbary[0] = (tx0->x[0] + tx1->x[0] + tx2->x[0]) * 0.33333333f;
		    txbary[1] = (tx0->x[1] + tx1->x[1] + tx2->x[1]) * 0.33333333f;
		    if(usevn>0) glNormal3fv( vnorms[ FVNORM(0) ].x );
		    glTexCoord2fv( tx0->x );
		    glVertex3fv( p0->x );
		    glTexCoord2f( TXINTERP( tx0 ) );
		    glVertex3f( INTERP( p0 ) );

		    if(usevn>0) glNormal3fv( vnorms[ FVNORM(1) ].x );
		    glTexCoord2fv( tx1->x );
		    glVertex3fv( p1->x );
		    glTexCoord2f( TXINTERP( tx1 ) );
		    glVertex3f( INTERP( p1 ) );

		    if(usevn>0) glNormal3fv( vnorms[ FVNORM(2) ].x );
		    glTexCoord2fv( tx2->x );
		    glVertex3fv( p2->x );
		    glTexCoord2f( TXINTERP( tx2 ) );
		    glVertex3f( INTERP( p2 ) );

		    if(usevn>0) glNormal3fv( vnorms[ FVNORM(0) ].x );
		    glTexCoord2fv( tx2->x );
		    glVertex3fv( p0->x );
		    glTexCoord2f( TXINTERP( tx0 ) );
		    glVertex3f( INTERP( p0 ) );

		} else if(usevn>0) {
		    glNormal3fv( vnorms[FVNORM(0)].x );
		    glVertex3fv(p0->x); glVertex3f( INTERP(p0) );

		    glNormal3fv( vnorms[FVNORM(1)].x );
		    glVertex3fv(p1->x); glVertex3f( INTERP(p1) );

		    glNormal3fv( vnorms[FVNORM(2)].x );
		    glVertex3fv(p2->x); glVertex3f( INTERP(p2) );

		    glNormal3fv( vnorms[FVNORM(0)].x );
		    glVertex3fv(p0->x); glVertex3f( INTERP(p0) );

		} else {
		    glVertex3fv(p0->x); glVertex3f( INTERP(p0) );
		    glVertex3fv(p1->x); glVertex3f( INTERP(p1) );
		    glVertex3fv(p2->x); glVertex3f( INTERP(p2) );
		    glVertex3fv(p0->x); glVertex3f( INTERP(p0) );
		}

	    } else {
		/* No mullions */
		if(was != GL_TRIANGLES) {
		    if(was) glEnd();
		    glBegin( was=GL_TRIANGLES );
		}
			glNormal3fv( vnorms[FVNORM(0)].x );
			glTexCoord2fv( txs[ FTX(0) ].x );
			glVertex3fv( pts[ FVERT(0) ].x );
			glNormal3fv( vnorms[FVNORM(1)].x );
			glTexCoord2fv( txs[ FTX(1) ].x );
			glVertex3fv( pts[ FVERT(1) ].x );
			glNormal3fv( vnorms[FVNORM(2)].x );
			glTexCoord2fv( txs[ FTX(2) ].x );
			glVertex3fv( pts[ FVERT(2) ].x );
		    } else {
			glTexCoord2fv( txs[ FTX(0) ].x );
			glVertex3fv( pts[ FVERT(0) ].x );
			glTexCoord2fv( txs[ FTX(1) ].x );
			glVertex3fv( pts[ FVERT(1) ].x );
			glTexCoord2fv( txs[ FTX(2) ].x );
			glVertex3fv( pts[ FVERT(2) ].x );
		    }
		} else if(usevn>0) {
		    glNormal3fv( vnorms[FVNORM(0)].x );
		    glVertex3fv( pts[ FVERT(0) ].x );
		    glNormal3fv( vnorms[FVNORM(1)].x );
		    glVertex3fv( pts[ FVERT(1) ].x );
		    glNormal3fv( vnorms[FVNORM(2)].x );
		    glVertex3fv( pts[ FVERT(2) ].x );
		} else {
		    glVertex3fv( pts[ FVERT(0) ].x );
		    glVertex3fv( pts[ FVERT(1) ].x );
		    glVertex3fv( pts[ FVERT(2) ].x );
		}
	    }
	} else if(fvn == 4) {
	    if(was != GL_QUADS) {
		if(was) glEnd();
		glBegin( was=GL_QUADS );
	    }
		    glNormal3fv( vnorms[FVNORM(0)].x );
		    glTexCoord2fv( txs[FTX(0)].x );
		    glVertex3fv( pts[ FVERT(0) ].x );
		    glNormal3fv( vnorms[FVNORM(1)].x );
		    glTexCoord2fv( txs[FTX(1)].x );
		    glVertex3fv( pts[ FVERT(1) ].x );
		    glNormal3fv( vnorms[FVNORM(2)].x );
		    glTexCoord2fv( txs[FTX(2)].x );
		    glVertex3fv( pts[ FVERT(2) ].x );
		    glNormal3fv( vnorms[FVNORM(3)].x );
		    glTexCoord2fv( txs[FTX(3)].x );
		    glVertex3fv( pts[ FVERT(3) ].x );
		} else {
		    glTexCoord2fv( txs[FTX(0)].x );
		    glVertex3fv( pts[ FVERT(0) ].x );
		    glTexCoord2fv( txs[FTX(1)].x );
		    glVertex3fv( pts[ FVERT(1) ].x );
		    glTexCoord2fv( txs[FTX(2)].x );
		    glVertex3fv( pts[ FVERT(2) ].x );
		    glTexCoord2fv( txs[FTX(3)].x );
		    glVertex3fv( pts[ FVERT(3) ].x );
		}
	    } else {
		    glNormal3fv( vnorms[FVNORM(0)].x );
		    glVertex3fv( pts[ FVERT(0) ].x );
		    glNormal3fv( vnorms[FVNORM(1)].x );
		    glVertex3fv( pts[ FVERT(1) ].x );
		    glNormal3fv( vnorms[FVNORM(2)].x );
		    glVertex3fv( pts[ FVERT(2) ].x );
		    glNormal3fv( vnorms[FVNORM(3)].x );
		    glVertex3fv( pts[ FVERT(3) ].x );
		} else {
		    glVertex3fv( pts[ FVERT(0) ].x );
		    glVertex3fv( pts[ FVERT(1) ].x );
		    glVertex3fv( pts[ FVERT(2) ].x );
		    glVertex3fv( pts[ FVERT(3) ].x );
		}
	    }
	} else if(fvn < 0) {
	    if(was) {
		glEnd();
		was = 0;
	    }
	    glBegin( GL_TRIANGLE_STRIP );
		if(usevn>0) glNormal3fv( vnorms[ FVNORM(0) ].x );
		if(usetex) glTexCoord2fv( txs[ FTX(0) ].x );
		glVertex3fv( pts[ FVERT(0) ].x );
		fvs0 += FVSTEP;
	    } while(++fvn < 0);
	    glEnd();
	    if(was) {
		glEnd();
		was = 0;
	    }
	    glBegin( GL_POLYGON );
		if(usevn>0) glNormal3fv( vnorms[ FVNORM(0) ].x );
		if(usetex) glTexCoord2fv( txs[ FTX(0) ].x );
		glVertex3fv( pts[ FVERT(0) ].x );
		fvs0 += FVSTEP;
	    } 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 ) {
    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( CONST char **sp, int *leadcp, char word[MAXSELNAME] ) {
    CONST 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, CONST char *str, SelOp *destp, SelOp *srcp, CONST char *plaint )
  char wd[MAXSELNAME], w[MAXSELNAME];
  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


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