diff --git a/src/partibrains.c b/src/partibrains.c
index c9c900f4ef4e10b8add0374a678e79f4f1be5e3f..88dcb8adf783a455ef6a9ca93ce021c564d0fe90 100644
--- a/src/partibrains.c
+++ b/src/partibrains.c
@@ -18,8 +18,11 @@
 # include <unistd.h>
 # include <sys/types.h>
 # include <netinet/in.h>  /* for htonl */
+# include <time.h>
 # include <alloca.h>
-# include "config.h"	/* for WORDS_BIGENDIAN */
+# ifndef WORDS_BIGENDIAN
+#  include "config.h"	/* for WORDS_BIGENDIAN */
+# endif
 #else /*WIN32*/
 # include "winjunk.h"
 # define WORDS_BIGENDIAN 0
@@ -221,6 +224,7 @@ specks_init( int argc, char *argv[] )
   st->textsize = .05;
   st->npolygon = 11;
   st->subsample = 1;
+  st->everycomp = 1;
 
   st->menudemandfps = 4.0;
 
@@ -270,6 +274,8 @@ specks_init( int argc, char *argv[] )
   st->boxlevels = 0;
   st->boxlinewidth = 0.75;
 
+  st->depthsort = 0;
+
   st->clk = NewN(SClock, 1);
   clock_init(st->clk);
   clock_set_running(st->clk, 1);
@@ -970,7 +976,7 @@ void specks_timerange( struct stuff *st, double *tminp, double *tmaxp )
 #endif
    ) {
     *tminp = 0;
-    *tmaxp = st->ntimes + 1;
+    *tmaxp = st->ntimes == 0 ? 0 : st->ntimes - 1;
   }
 }
 
@@ -1108,6 +1114,7 @@ void specks_set_time( struct stuff *st, double newtime )
 
 #if CAVE
   if(ment.tknob[0] == NULL) {	/* if not SC99DEMO */
+    struct specklist *sl = st->sl;
     if(sl != NULL && memcmp(&sl->interest, &lastinterest, sizeof(Point))
 	    && (sl->interest.x[0]!=0 || sl->interest.x[1]!=0
 					    || sl->interest.x[2]!=0)) {
@@ -1248,6 +1255,217 @@ void dumpcpoints( struct cpoint *cp, int n )
     }
 }
 
+static Point depth_fwd;
+static float depth_d;
+
+struct order {
+  float z;
+  struct speck *sp;
+  struct specklist *sl;
+};
+
+static int depthcmp( const void *a, const void *b )
+{
+  return ((struct order *)a)->z < ((struct order *)b)->z ?    1
+	: ((struct order *)a)->z > ((struct order *)b)->z ? -1 : 0;
+}
+
+static int additive_blend;
+
+void sortedpolys( struct stuff *st, struct specklist *slhead, Matrix *Tc2wp, float radperpix, float polysize )
+{
+  struct speck *sp, *sbase;
+  struct order *op, *obase;
+  int i, k, total, skip;
+  struct specklist *sl;
+  int usethresh = st->usethresh&P_USETHRESH ? THRESHBIT : 0;
+  int bps = 0;
+  int prevrgba = -1;
+  int usearea = st->polyarea;
+  int sizevar = st->polysizevar;
+  int polyorivar = st->polyorivar0;
+  int texturevar = st->texturevar;
+  int txno;
+  int texturing = -1;
+  float s;
+  float polyminrad = st->polymin * radperpix;
+  float polymaxrad = st->polymax * radperpix;
+  float mins2d = polyminrad * polyminrad;
+  int rgba;
+  int alpha = st->alpha * 255;
+  int nfan = st->npolygon<MAXXYFAN ? st->npolygon : MAXXYFAN;
+  float xyfan[MAXXYFAN][2];
+  Point sfan[MAXXYFAN], pfan[MAXXYFAN];
+  Matrix Tc2w = *Tc2wp;
+  float scl = vlength( (Point *)&Tc2w.m[0*4+0] );
+  Texture *wanttx;
+  int additive = additive_blend;
+  int wantblend = additive;
+
+  int useclip = (st->clipbox.level > 0);
+  Point clipp0 = st->clipbox.p0;
+  Point clipp1 = st->clipbox.p1;
+
+  for(total = 0, sl = slhead; sl != NULL; sl = sl->next) {
+    if(sl->text != NULL || sl->nspecks == 0 || sl->special != SPECKS)
+	continue;
+    skip = st->subsample;
+    if(sl->subsampled != 0)	/* if already subsampled */
+	skip /= sl->subsampled;
+    if(skip <= 0) skip = 1;
+
+    if(bps < sl->bytesperspeck) bps = sl->bytesperspeck;
+    if(usethresh) {
+	for(i=sl->nspecks, sp=sl->specks; i>0; i-=skip, sp=NextSpeck(sp,sl,skip)) {
+	    if((usethresh & sp->rgba) == 0)
+		total++;
+	}
+    } else {
+	total += sl->nspecks / skip;
+    }
+  }
+
+  obase = op = (struct order *)malloc( (total+1) * sizeof(struct order) );
+  for(sl = slhead; sl != NULL; sl = sl->next) {
+    if(sl->text != NULL || sl->nspecks == 0 || sl->special != SPECKS)
+	continue;
+    skip = st->subsample;
+    if(sl->subsampled != 0)	/* if already subsampled */
+	skip /= sl->subsampled;
+    if(skip <= 0) skip = 1;
+    for(i=sl->nspecks, sp=sl->specks; i > 0; i-=skip, sp=NextSpeck(sp,sl,skip)) {
+	float dist;
+	if(usethresh & sp->rgba)
+	    continue;
+	dist = VDOT( &sp->p, &depth_fwd ) + depth_d;
+	if(dist < 0)
+	    continue;
+	if(useclip &&
+	  (sp->p.x[0] < clipp0.x[0] ||
+	   sp->p.x[0] > clipp1.x[0] ||
+	   sp->p.x[1] < clipp0.x[1] ||
+	   sp->p.x[1] > clipp1.x[1] ||
+	   sp->p.x[2] < clipp0.x[2] ||
+	   sp->p.x[2] > clipp1.x[2]))
+	    continue;
+	op->z = dist;
+	op->sp = sp;
+	op->sl = sl;
+	op++;
+    }
+  }
+
+  total = op - obase;
+  qsort( obase, total, sizeof(*obase), depthcmp );
+
+  prevrgba = 0;
+
+  /* Build prototype fan -- unit disk in screen plane */
+  for(i = 0; i < nfan; i++) {
+    float theta = 2*M_PI*i/nfan;
+    xyfan[i][0] = cos(theta);
+    xyfan[i][1] = sin(theta);
+    vcomb( &sfan[i], xyfan[i][0] / scl, (Point *)&Tc2w.m[0*4+0],
+		     xyfan[i][1] / scl, (Point *)&Tc2w.m[1*4+0] );
+  }
+
+  if(st->usetextures == 0 || SMALLSPECKSIZE(texturevar) > bps)
+    texturevar = -1;
+  if(SMALLSPECKSIZE(polyorivar) > bps)
+    polyorivar = -1;
+
+  for(i = 0, op = obase; i < total; i++, op++) {
+    float dist, size;
+
+    sp = op->sp;
+    dist = op->z;
+    size = sp->val[sizevar] * polysize;
+    if(usearea) {
+	if(size < dist * dist * mins2d)
+	    continue;
+	size = sqrtf(size);
+    } else {
+	if(size < dist * polyminrad)
+	    continue;
+    } 
+    if(size > dist * polymaxrad)
+	size = dist * polymaxrad;
+
+    rgba = sp->rgba & ~THRESHBIT;
+    if(rgba != prevrgba) {
+	prevrgba = rgba;
+	rgba = RGBALPHA( prevrgba, alpha );
+	glColor4ubv( (GLubyte *)&rgba );
+    }
+
+    if(texturevar >= 0 &&
+	    (txno = sp->val[texturevar]) >= 0 &&
+	    txno < st->ntextures &&
+	    (wanttx = st->textures[txno]) != NULL) {
+
+	txbind( wanttx, &texturing );
+	wantblend = (wanttx->flags & TXF_ADD) ? 1 : additive_blend;
+    } else if(texturing) {
+	glDisable( GL_TEXTURE_2D );
+	texturing = 0;
+    }
+
+    if(wantblend != additive) {
+	additive = wantblend;
+	glBlendFunc( GL_SRC_ALPHA, additive ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA );
+    }
+
+    if(polyorivar >= 0 && sp->val[polyorivar] < 9) {
+	float *xv = &sp->val[polyorivar];
+	float *yv = &sp->val[polyorivar+3];
+
+	glBegin( GL_TRIANGLE_FAN );
+	if(texturing) {
+	    for(k = 0; k < nfan; k++) {
+		glTexCoord2fv( &xyfan[k][0] );
+		glVertex3f(
+		    sp->p.x[0] + size*(xyfan[k][0]*xv[0] + xyfan[k][1]*yv[0]),
+		    sp->p.x[1] + size*(xyfan[k][0]*xv[1] + xyfan[k][1]*yv[1]),
+		    sp->p.x[2] + size*(xyfan[k][0]*xv[2] + xyfan[k][1]*yv[2]));
+	    }
+	} else {
+	    for(k = 0; k < nfan; k++) {
+		glVertex3f(
+		    sp->p.x[0] + size*(xyfan[k][0]*xv[0] + xyfan[k][1]*yv[0]),
+		    sp->p.x[1] + size*(xyfan[k][0]*xv[1] + xyfan[k][1]*yv[1]),
+		    sp->p.x[2] + size*(xyfan[k][0]*xv[2] + xyfan[k][1]*yv[2]));
+	    }
+	}
+	glEnd();
+
+    } else {
+	glBegin( GL_TRIANGLE_FAN );
+	if(texturing) {
+	    for(k = 0; k < nfan; k++) {
+		glTexCoord2fv( &xyfan[k][0] );
+		glVertex3f(
+		    sp->p.x[0] + size*sfan[k].x[0],
+		    sp->p.x[1] + size*sfan[k].x[1],
+		    sp->p.x[2] + size*sfan[k].x[2] );
+	    }
+	} else {
+	    for(k = 0; k < nfan; k++) {
+		glVertex3f(
+		    sp->p.x[0] + size*sfan[k].x[0],
+		    sp->p.x[1] + size*sfan[k].x[1],
+		    sp->p.x[2] + size*sfan[k].x[2] );
+	    }
+	}
+	glEnd();
+    }
+  }
+  free(obase);
+  if(texturing > 0)
+    txbind( NULL, NULL );
+}
+  
+  
+
 void drawspecks( struct stuff *st )
 {
   int i, slno, k;
@@ -1271,7 +1489,6 @@ void drawspecks( struct stuff *st )
   int randix = 0;
   int fast = st->fast;
   int inpick = st->inpick;
-  int additive_blend = 1;
   int usethresh = st->usethresh&P_USETHRESH ? THRESHBIT : 0;
   int fixeddist;
   float polyminrad, polymaxrad;
@@ -1312,12 +1529,10 @@ void drawspecks( struct stuff *st )
   }
 
 
-#if !CAVEMENU
   { float r=0,g=0,b=0;	/* Ugh. Allow background to be non-black */
-    sscanf(parti_bgcolor(NULL), "%f %f %f", &r,&g,&b);
-    if(r+g+b > 0) additive_blend = 0;
+    sscanf(parti_bgcolor(NULL), "%f%f%f", &r,&g,&b);
+    additive_blend = (r+g+b == 0);
   }
-#endif
 
   if(st->clipbox.level != 0) {
     GLdouble plane[4];
@@ -1436,7 +1651,7 @@ void drawspecks( struct stuff *st )
 			&& st->vdesc[st->curdata][st->sizedby].lum != 0) {
 	plum *= st->vdesc[st->curdata][st->sizedby].lum;
   }
-  if(st->subsample > 0)
+  if(st->subsample > 0 && st->everycomp)
       plum *= st->subsample;	/* Compensate for "every" subsampling */
 
 
@@ -1452,6 +1667,7 @@ void drawspecks( struct stuff *st )
 
   if(inpick) glLoadName(0);
   
+
   if(st->usepoly && st->polysize > 0) {
     int texturing = 0;
     int texturevar = st->usetextures && st->texturevar >= 0
@@ -1483,11 +1699,17 @@ void drawspecks( struct stuff *st )
 		&& (unsigned int)st->curdata < MAXFILES
 		&& st->vdesc[st->curdata][st->sizedby].lum != 0)
 	polysize *= st->vdesc[st->curdata][st->sizedby].lum;
-      if(st->subsample > 0)
+      if(st->subsample > 0 && st->everycomp)
         polysize *= st->subsample; /* Compensate for "every" subsampling */
     }
 
-    for(sl = slhead, slno = 1; sl != NULL; sl = sl->next, slno++) {
+    if(st->depthsort && !inpick) {
+	depth_fwd = fwd;
+	depth_d = fwdd;
+	sortedpolys( st, slhead, &Tc2w, radperpix, polysize );
+
+    } else {
+      for(sl = slhead, slno = 1; sl != NULL; sl = sl->next, slno++) {
 	if(sl->text != NULL || sl->special != SPECKS) continue;
 	if(inpick) {
 	    glLoadName(slno);
@@ -1529,10 +1751,8 @@ void drawspecks( struct stuff *st )
 	    } else if(p->size != prevsize) {
 		float s = scl*size;
 		for(k = 0; k < nxyfan; k++) {
-		    tp.x[0] = s*xyfan[k][0];
-		    tp.x[1] = s*xyfan[k][1];
-		    tp.x[2] = 0;
-		    vtfmvector( &fan[k], &tp, &Tc2w );
+		    vcomb( &fan[k], s*xyfan[k][0], (Point *)&Tc2w.m[0*4+0],
+				    s*xyfan[k][1], (Point *)&Tc2w.m[1*4+0] );
 		}
 		prevsize = size;
 	    }
@@ -1548,7 +1768,7 @@ void drawspecks( struct stuff *st )
 		glEnd();
 
 	    } else if(texturevar >= 0
-		    && (txno = (p->val[texturevar] - 1)) >= 0
+		    && (txno = p->val[texturevar]) >= 0
 		    && txno < st->ntextures &&
 		    st->textures[txno] != NULL) {
 
@@ -1575,9 +1795,10 @@ void drawspecks( struct stuff *st )
 
 	}
 	if(inpick) glPopName();
+      }
     }
     if(texturing) {
-	txload( NULL );
+	txbind( NULL, NULL );
 	glDisable( GL_TEXTURE_2D );
     }
     glMatrixMode( GL_TEXTURE );
@@ -1821,7 +2042,7 @@ void drawspecks( struct stuff *st )
 	glBegin( GL_POINTS );
 	for(sl = slhead; sl != NULL; sl = sl->next) {
 	    if(sl->text != NULL || sl->special != SPECKS) continue;
-	    for(i = 0, p = sl->specks; i < sl->nspecks; i+=skip, p= NextSpeck(p, sl, skip)) {
+	    for(i = 0, p = sl->specks; i < sl->nspecks; i+=skip, p=NextSpeck(p,sl,skip)) {
 		int lum, myalpha;
 		float dist, dist2, dx, dy, dz;
 
@@ -2664,23 +2885,31 @@ void specks_read( struct stuff **stp, char *fname )
 	while(--k >= 0) free(path[k]);
 
     } else if(!strcmp(key, "texture")) {
-	int txno;
+	int txno = 0;
 	int txflags = TXF_SCLAMP | TXF_TCLAMP;
 	int txapply = TXF_DECAL;
 	int qual = 7;
 	char *txfname;
 	key = strtok(NULL, separ);
-	while(key != NULL && key[0] == '-') {
-	    qual |= (strchr(key,'m') ? 4:0) | (strchr(key,'l') ? 2:0) | (strchr(key,'n') ? 1:0);
+	sscanf(key, "%d", &txno);
+	while(key != NULL && (key[0] == '-' || key[0] == '+')) {
+	    int tqual = (strchr(key,'m') ? 4:0) |
+			(strchr(key,'l') ? 2:0) |
+			(strchr(key,'n') ? 1:0);
+	    if(key[0] == '-') qual &= ~tqual;
+	    else qual |= tqual;
+	    if(strchr(key,'a')) txflags |= TXF_ALPHA;
+	    if(strchr(key,'i')) txflags |= TXF_INTENSITY;
+	    if(strchr(key, 'A')) txflags |= TXF_ADD;
 	    if(strchr(key, 'M')) txapply = TXF_MODULATE;
 	    if(strchr(key, 'D')) txapply = TXF_DECAL;
 	    if(strchr(key, 'B')) txapply = TXF_BLEND;
 	    key = strtok(NULL, separ);
 	}
-	if(key == NULL || sscanf(key, "%d", &txno) <= 0
+	if(key == NULL || (txno == 0 && sscanf(key, "%d", &txno) <= 0)
 	   || (txfname = strtok(NULL, separ)) == NULL) {
-		msg("Expected ``texture [-lmnMDB] txno file.sgi'', got %s", oline);
-		msg(" (options -l(inear) -m(ipmap) -n(earest) -M(odulate)|-D(ecal)|-B(lend))");
+		msg("Expected ``texture [-lmnaMDB] txno file.sgi'', got %s", oline);
+		msg(" opts: -l(inear) -m(ipmap) -n(earest) -i(intensity) -a(lpha) -A(dd) -M(odulate)|-D(ecal)|-B(lend))");
 	} else {
 	    txaddentry( &st->textures, &st->ntextures, fname, txno, txfname, txapply, txflags, qual );
 	}
@@ -3156,7 +3385,7 @@ void set_step( float time0, MenuEnt *me, void *vst ) {
 	st->timeplay = 0;
 	me->state = ME_HELD;
    }
-   clock_set_time( me->val = (int) time0 );
+   clock_set_time( st->clk, me->val = (int) time0 );
    /* NOTE we use the static values snapped by the framefunction.
     * st->curtime etc. might have changed since then.
     */
@@ -3167,7 +3396,7 @@ void set_step( float time0, MenuEnt *me, void *vst ) {
 }
 
 void set_fwd( int fwd, MenuEnt *me, void *st ) {
-   clock_set_fwd( st->clk, fwd );
+   clock_set_fwd( ((struct stuff *)st)->clk, fwd );
    menu_settitle( me, fwd ? ">>> fwd >>>" : "<<< rev <<<" );
 }
 
@@ -3629,6 +3858,7 @@ int getbool( char *str, int defval ) {
 
   if(!strcasecmp(str, "on")) return 1;
   if(!strcasecmp(str, "off")) return 0;
+  if(!strcasecmp(str, "toggle")) return !defval;
   if(!strcasecmp(str, "all")) return -1;
   v = strtol(str, &ep, 0);
   if(str == ep) return defval;
@@ -3688,12 +3918,13 @@ specks_parse_args( struct stuff **stp, int argc, char *argv[] )
 " lum   const LUM		set all particles to be that brightness",
 " slum  SCALEFACTOR		scale particle size by SCALEFACTOR",
 " psize SIZE			scale particle size by SIZE * SCALEFACTOR",
+" depthsort			sort polygons by depth",
 " see   DATASETNO-or-NAME	show that dataset (e.g. \"see 0\" or \"see gas\")",
 " read  [-t time] DATAFILENAME	read data file (e.g. to add new specks)",
 " ieee  [-t time] IEEEIOFILE	read IEEEIO file (starting at given timestep)",
 " sdb   [-t time] SDBFILE	read .sdb star-data file",
 " annot [-t time] string	set annotation string (for given timestep)",
-" eval  DATAFILECOMMAND		enter a single datafile command (ditto)",
+" add  DATAFILECOMMAND		enter a single datafile command (ditto)",
 " every N			subsample: show every Nth particle",
 " bound				show bounds (coordinate range of all particles)",
 " clipbox {on | off | X0,X1 Y0,Y1 Z0,Z1 | CENX,Y,Z RADX,Y,Z | X0 Y0 Z0  X1 Y1 Z1} clipping region",
@@ -3963,6 +4194,10 @@ specks_parse_args( struct stuff **stp, int argc, char *argv[] )
 	parti_set_running( st, getbool( argv[1], 1 ) );
 	st->playnext = 0.0;
 
+  } else if(!strcmp( argv[0], "depthsort" )) {
+	if(argc > 1) st->depthsort = getbool(argv[1], st->depthsort);
+	msg("depthsort %s", st->depthsort ? "on" : "off" );
+
   } else if(!strcmp( argv[0], "fade" )) {
 	char *fmt = "fade what?";
 	if(argc>1) {
@@ -4061,6 +4296,8 @@ specks_parse_args( struct stuff **stp, int argc, char *argv[] )
 		specks_count( st->sl ));
 	}
 
+  } else if(!strcmp( argv[0], "gall" ) || !strncmp( argv[0], "allobj", 6 )) {
+	parti_allobjs( argc-1, argv+1 );
 
   } else if(!strcmp(argv[0], "tfm")) {
 	int inv = 0;
@@ -4358,6 +4595,12 @@ specks_parse_args( struct stuff **stp, int argc, char *argv[] )
 	msg("display every %dth particle (of %d)",
 			st->subsample, specks_count(st->sl));
 
+  } else if(!strncmp( argv[0], "everycomp", 9 )) {
+	st->everycomp = getbool(argv[1], st->everycomp);
+	msg("everycomp %d (%s compensate for \"every\" subsampling)",
+		st->everycomp,
+		st->everycomp ? "do" : "don't");
+
   } else if(!strncmp( argv[0], "color", 5 )) {
 	struct valdesc *vd;
 	if(argc>1) {