shithub: qk1

Download patch

ref: f925d22c8fba04eb85fa9e39dd5f034ec4f6e764
parent: fc395539c767849d9c3acc1b6e4d0979e054b708
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Tue Nov 28 19:50:46 EST 2023

initial version of 24-bit rendering

--- a/cl_parse.c
+++ b/cl_parse.c
@@ -532,7 +532,7 @@
 {
 	int		i, j;
 	int		top, bottom;
-	byte	*dest, *source;
+	pixel_t	*dest, *source;
 
 	if (slot > cl.maxclients)
 		fatal ("CL_NewTranslation: slot > cl.maxclients");
@@ -544,14 +544,14 @@
 
 	for (i=0 ; i<VID_GRADES ; i++, dest += 256, source+=256)
 	{
-		if (top < 128)	// the artists made some backwards ranges.  sigh.
-			memcpy (dest + TOP_RANGE, source + top, 16);
+		if(top < 128)	// the artists made some backwards ranges.  sigh.
+			memcpy (dest + TOP_RANGE, source + top, 16*sizeof(pixel_t));
 		else
 			for (j=0 ; j<16 ; j++)
 				dest[TOP_RANGE+j] = source[top+15-j];
 
-		if (bottom < 128)
-			memcpy (dest + BOTTOM_RANGE, source + bottom, 16);
+		if(bottom < 128)
+			memcpy (dest + BOTTOM_RANGE, source + bottom, 16*sizeof(pixel_t));
 		else
 			for (j=0 ; j<16 ; j++)
 				dest[BOTTOM_RANGE+j] = source[bottom+15-j];
--- a/client.h
+++ b/client.h
@@ -20,7 +20,7 @@
 	float	entertime;
 	int		frags;
 	int		colors;			// two 4 bit fields
-	byte	translations[VID_GRADES*256];
+	pixel_t	translations[VID_GRADES*256];
 } scoreboard_t;
 
 typedef struct
--- a/common.c
+++ b/common.c
@@ -6,6 +6,18 @@
 
 bool		standard_quake = true, rogue, hipnotic;
 
+void
+torgbx(byte *in, pixel_t *out, int n)
+{
+	if(in < (byte*)out || in > (byte*)(out+n) || in+n < (byte*)out){
+		while(n-- > 0)
+			*out++ = q1pal[*in++];
+	}else{
+		while(n-- > 0)
+			out[n] = q1pal[in[n]];
+	}
+}
+
 /*
 
 
--- a/d_alpha.c
+++ b/d_alpha.c
@@ -1,122 +1,5 @@
 #include "quakedef.h"
 
-typedef struct Col Col;
-
-struct Col {
-	Col *s[2];
-	u8int c[3];
-	u8int x;
-};
-
-static Col *lookup;
-
-static void
-ins(u8int c[3], u8int x)
-{
-	Col **p, *e, *l;
-	int i;
-
-	for(l = lookup, p = &lookup, e = lookup, i = 0; e != nil; i = (i+1)%3){
-		l = *p;
-		p = &e->s[c[i] >= e->c[i]];
-		e = *p;
-	}
-	if(l != nil && memcmp(l->c, c, 3) == 0)
-		return;
-	e = calloc(1, sizeof(*e));
-	memmove(e->c, c, 3);
-	e->x = x;
-	*p = e;
-}
-
-static void
-closest_(u8int c[3], Col *t, int i, Col **best, int *min)
-{
-	int d, d2, nd;
-
-	if(t == nil)
-		return;
-
-	i %= 3;
-	nd = (int)t->c[i] - (int)c[i];
-	i = (i+1)%3;
-	d = (int)t->c[i] - (int)c[i];
-	i = (i+1)%3;
-	d2 = (int)t->c[i] - (int)c[i];
-	d = nd*nd + d*d + d2*d2;
-
-	if(*min > d){
-		*min = d;
-		*best = t;
-	}
-
-	i += 2;
-	closest_(c, t->s[nd <= 0], i, best, min);
-	if(nd*nd < *min)
-		closest_(c, t->s[nd > 0], i, best, min);
-}
-
-static Col *
-closest(u8int c[3])
-{
-	Col *best;
-	int min;
-
-	best = nil;
-	min = 99999;
-	closest_(c, lookup, 0, &best, &min);
-	return best;
-}
-
-byte *alphamap[256>>AlphaStep];
-
-void
-initalpha(void)
-{
-	extern s32int fbpal[256];
-	int a, b, ai, alpha, i;
-	byte *ca, *cb, *p;
-	u8int c[3];
-	Col *best;
-
-	if(lookup != nil)
-		return;
-
-	p = (byte*)fbpal;
-	for(i = 0; i < 64; i++){
-		ins(p+(64+i)*4, 64+i);
-		ins(p+(63-i)*4, 63-i);
-		ins(p+(128+i)*4, 128+i);
-		ins(p+(255-i)*4, 255-i);
-	}
-
-	for(alpha = 1; alpha <= 128; alpha += 1<<AlphaStep){
-		ai = alpha >> AlphaStep;
-		alphamap[ai] = malloc(256*256);
-
-		ca = p;
-		for(a = 0; a < 256; a++, ca += 4){
-			cb = p;
-			for(b = 0; b < 256; b++, cb++){
-				c[0] = (alpha*ca[0] + (255 - alpha)*(*cb++))>>8;
-				c[1] = (alpha*ca[1] + (255 - alpha)*(*cb++))>>8;
-				c[2] = (alpha*ca[2] + (255 - alpha)*(*cb++))>>8;
-				best = closest(c);
-				alphamap[ai][a<<8 | b] = best->x;
-			}
-		}
-	}
-	for(alpha = 128+AlphaStep; alpha < 256; alpha += 1<<AlphaStep){
-		ai = alpha >> AlphaStep;
-		alphamap[ai] = malloc(256*256);
-		i = (256-alpha)>>AlphaStep;
-		for(a = 0; a < 256; a++){
-			for(b = 0; b < 256; b++)
-				alphamap[ai][b<<8 | a] = alphamap[i][a<<8 | b];
-		}
-	}
-}
-
 float
 alphafor(int flags)
 {
--- a/d_edge.c
+++ b/d_edge.c
@@ -27,30 +27,17 @@
 
 // FIXME: clean this up
 static void
-D_DrawSolidSurface(surf_t *surf, int color)
+D_DrawSolidSurface(surf_t *surf, pixel_t color)
 {
 	espan_t *span;
-	byte *pdest;
-	int u, u2, pix;
+	pixel_t *pdest;
+	int u, u2;
 
-	pix = (color<<24) | (color<<16) | (color<<8) | color;
 	for(span = surf->spans; span; span=span->pnext){
-		pdest = (byte *)d_viewbuffer + screenwidth*span->v;
-		u = span->u;
+		pdest = d_viewbuffer + screenwidth*span->v;
 		u2 = span->u + span->count - 1;
-		pdest[u] = pix;
-
-		if (u2 - u < 8){
-			for(u++; u <= u2; u++)
-				pdest[u] = pix;
-		}else{
-			for(u++ ; u & 3; u++)
-				pdest[u] = pix;
-			for(u2 -= 4; u <= u2; u += 4)
-				*(int *)(pdest + u) = pix;
-			for(u2 += 4; u <= u2; u++)
-				pdest[u] = pix;
-		}
+		for(u = span->u; u <= u2; u++)
+			pdest[u] = color;
 	}
 }
 
@@ -137,7 +124,7 @@
 			d_zistepv = 0;
 			d_ziorigin = -0.9;
 
-			D_DrawSolidSurface(s, (int)r_clearcolor.value & 0xFF);
+			D_DrawSolidSurface(s, q1pal[(int)r_clearcolor.value & 0xFF]);
 			D_DrawZSpans(s->spans);
 		}else if(s->flags & SURF_DRAWTURB){
 			pface = s->data;
--- a/d_iface.h
+++ b/d_iface.h
@@ -21,7 +21,7 @@
 {
 	// driver-usable fields
 	vec3_t		org;
-	float		color;
+	pixel_t		color;
 	// drivers never touch the following fields
 	struct particle_s	*next;
 	vec3_t		vel;
@@ -47,7 +47,7 @@
 // !!! if this is changed, it must be changed in d_ifacea.h too !!!
 typedef struct
 {
-	void				*pskin;
+	pixel_t				*pskin;
 	maliasskindesc_t	*pskindesc;
 	int					skinwidth;
 	int					skinheight;
@@ -58,11 +58,6 @@
 	int					seamfixupX16;
 } affinetridesc_t;
 
-// !!! if this is changed, it must be changed in d_ifacea.h too !!!
-typedef struct {
-	float	u, v, zi, color;
-} screenpart_t;
-
 typedef struct
 {
 	int			nump;
@@ -92,9 +87,8 @@
 extern vec3_t	r_pright, r_pup, r_ppn;
 
 
-void D_Aff8Patch (void *pcolormap);
-void D_PolysetDraw (byte *colormap);
-void D_PolysetDrawFinalVerts (finalvert_t *fv, int numverts, byte *colormap, byte alpha);
+void D_PolysetDraw (pixel_t *colormap);
+void D_PolysetDrawFinalVerts (finalvert_t *fv, int numverts, pixel_t *colormap, byte alpha);
 void D_DrawParticle (particle_t *pparticle);
 void D_DrawPoly (void);
 void D_DrawSprite (void);
@@ -112,15 +106,12 @@
 void D_PolysetUpdateTables (void);
 
 // these are currently for internal use only, and should not be used by drivers
-extern byte				*r_skysource[2];
+extern pixel_t *r_skysource[2];
 
 // transparency types for D_DrawRect ()
 #define DR_SOLID		0
 #define DR_TRANSPARENT	1
 
-// !!! must be kept the same as in quakeasm.h !!!
-#define TRANSPARENT_COLOR	0xFF
-
 extern void *acolormap;	// FIXME: should go away
 
 //=======================================================================//
@@ -158,5 +149,5 @@
 extern int		c_surf;
 extern vrect_t	scr_vrect;
 
-extern byte		*r_warpbuffer;
+extern pixel_t *r_warpbuffer;
 
--- a/d_init.c
+++ b/d_init.c
@@ -29,7 +29,7 @@
 		d_viewbuffer = r_warpbuffer;
 		screenwidth = WARP_WIDTH;
 	}else{
-		d_viewbuffer = (void *)vid.buffer;
+		d_viewbuffer = vid.buffer;
 		screenwidth = vid.rowbytes;
 	}
 
--- a/d_local.h
+++ b/d_local.h
@@ -20,11 +20,11 @@
 	int					lightadj[MAXLIGHTMAPS]; // checked for strobe flush
 	int					dlight;
 	int					size;		// including header
-	unsigned			width;
-	unsigned			height;		// DEBUG only needed for debug
+	int					width;
+	int					height;		// DEBUG only needed for debug
 	float				mipscale;
 	struct texture_s	*texture;	// checked for animating textures
-	byte				data[4];	// width*height elements
+	pixel_t				data[];	// width*height elements
 } surfcache_t;
 
 // !!! if this is changed, it must be changed in asm_draw.h too !!!
@@ -73,15 +73,24 @@
 extern int d_minmip;
 extern float d_scalemip[3];
 
-enum {
-	// perhaps a bit too much, but looks ok
-	AlphaStep = 2,
-};
+#define blendalpha(ca, cb, alpha) \
+	((((alpha)*(((ca)>> 0)&0xff) + (255-(alpha))*(((cb)>> 0)&0xff))>> 8) << 0 | \
+	 (((alpha)*(((ca)>> 8)&0xff) + (255-(alpha))*(((cb)>> 8)&0xff))>> 8) << 8 | \
+	 (((alpha)*(((ca)>>16)&0xff) + (255-(alpha))*(((cb)>>16)&0xff))>> 8) << 16)
 
-extern byte *alphamap[256>>AlphaStep];
+#define CIND(p) ((p)>>24)
 
-#define blendalpha(a, b, alpha) \
-	alphamap[alpha>>AlphaStep][(u16int)((a)<<8 | (b))]
-
-void initalpha(void);
+/*
+static inline pixel_t
+blendalpha(pixel_t ca, pixel_t cb, int alpha)
+{
+	//pixel_t x;
+	//x.r = alpha*ca.r + (255-alpha)*cb.r;
+	//x.g = alpha*ca.g + (255-alpha)*cb.g;
+	//x.b = alpha*ca.b + (255-alpha)*cb.b;
+	USED(cb);
+	USED(alpha);
+	return ca;
+}
+*/
 float alphafor(int flags);
--- a/d_part.c
+++ b/d_part.c
@@ -7,7 +7,7 @@
 {
 	vec3_t local, transformed;
 	double zi;
-	byte *pdest, color;
+	pixel_t *pdest, color;
 	uzint *pz;
 	int i, izi, pix, count, u, v;
 
--- a/d_polyse.c
+++ b/d_polyse.c
@@ -2,10 +2,10 @@
 
 // !!! if this is changed, it must be changed in asm_draw.h too !!!
 typedef struct {
-	void			*pdest;
+	pixel_t			*pdest;
 	uzint			*pz;
 	int				count;
-	byte			*ptex;
+	pixel_t			*ptex;
 	int				sfrac, tfrac, light, zi;
 } spanpackage_t;
 
@@ -27,7 +27,7 @@
 									// 1 extra for spanpackage that marks end
 
 static int r_p0[6], r_p1[6], r_p2[6];
-static byte *d_pcolormap;
+static pixel_t *d_pcolormap;
 static int d_xdenom;
 static edgetable *pedgetable;
 
@@ -54,7 +54,7 @@
 
 static spanpackage_t *d_pedgespanpackage;
 static int ystart;
-static byte *d_pdest, *d_ptex;
+static pixel_t *d_pdest, *d_ptex;
 static uzint *d_pz;
 static int d_sfrac, d_tfrac, d_light, d_zi;
 static int d_ptexextrastep, d_sfracextrastep;
@@ -74,13 +74,13 @@
 #include "adivtab.h"
 };
 
-static byte *skintable[MAX_LBM_HEIGHT];
-static byte *skinstart;
+static pixel_t *skintable[MAX_LBM_HEIGHT];
+static pixel_t *skinstart;
 int skinwidth;
 
-void D_PolysetDrawSpans8 (spanpackage_t *pspanpackage, byte *colormap, byte alpha);
+void D_PolysetDrawSpans8 (spanpackage_t *pspanpackage, pixel_t *colormap, byte alpha);
 void D_PolysetCalcGradients (int skinwidth);
-void D_DrawSubdiv (byte *colormap);
+void D_DrawSubdiv (pixel_t *colormap);
 void D_DrawNonSubdiv (void);
 void D_PolysetRecursiveTriangle (int *p1, int *p2, int *p3, byte alpha);
 void D_PolysetSetEdgeTable (void);
@@ -92,7 +92,7 @@
 D_PolysetDraw
 ================
 */
-void D_PolysetDraw (byte *colormap)
+void D_PolysetDraw (pixel_t *colormap)
 {
 	if (r_affinetridesc.drawtype)
 	{
@@ -110,7 +110,7 @@
 D_PolysetDrawFinalVerts
 ================
 */
-void D_PolysetDrawFinalVerts (finalvert_t *fv, int numverts, byte *colormap, byte alpha)
+void D_PolysetDrawFinalVerts (finalvert_t *fv, int numverts, pixel_t *colormap, byte alpha)
 {
 	int		i, z;
 	uzint	*zbuf;
@@ -125,17 +125,14 @@
 			z = fv->v[5]>>16;
 			zbuf = zspantable[fv->v[1]] + fv->v[0];
 			if (z >= *zbuf){
+				int pix = CIND(skintable[fv->v[3]>>16][fv->v[2]>>16]);
+				pixel_t p = colormap[pix + (fv->v[4] & 0xFF00)];
+				int n = d_scantable[fv->v[1]] + fv->v[0];
 				if(r_drawflags & DRAW_BLEND){
-					int n = d_scantable[fv->v[1]] + fv->v[0];
-					int pix = skintable[fv->v[3]>>16][fv->v[2]>>16];
-					pix = colormap[pix + (fv->v[4] & 0xFF00) ];
-					d_viewbuffer[n] = blendalpha(pix, d_viewbuffer[n], alpha);
+					d_viewbuffer[n] = blendalpha(p, d_viewbuffer[n], alpha);
 				}else{
-					int		pix;
+					d_viewbuffer[n] = p;
 					*zbuf = z;
-					pix = skintable[fv->v[3]>>16][fv->v[2]>>16];
-					pix = colormap[pix + (fv->v[4] & 0xFF00) ];
-					d_viewbuffer[d_scantable[fv->v[1]] + fv->v[0]] = pix;
 				}
 			}
 		}
@@ -148,7 +145,7 @@
 D_DrawSubdiv
 ================
 */
-void D_DrawSubdiv (byte *colormap)
+void D_DrawSubdiv (pixel_t *colormap)
 {
 	mtriangle_t		*ptri;
 	finalvert_t		*pfv, *index0, *index1, *index2;
@@ -340,15 +337,13 @@
 	z = new[5]>>16;
 	zbuf = zspantable[new[1]] + new[0];
 	if (z >= *zbuf){
+		pixel_t p = d_pcolormap[CIND(skintable[new[3]>>16][new[2]>>16])];
+		int n = d_scantable[new[1]] + new[0];
 		if(r_drawflags & DRAW_BLEND){
-			int n = d_scantable[new[1]] + new[0];
-			int pix = d_pcolormap[skintable[new[3]>>16][new[2]>>16]];
-			d_viewbuffer[n] = blendalpha(pix, d_viewbuffer[n], alpha);
+			d_viewbuffer[n] = blendalpha(p, d_viewbuffer[n], alpha);
 		}else{
-			int		pix;
+			d_viewbuffer[n] = p;
 			*zbuf = z;
-			pix = d_pcolormap[skintable[new[3]>>16][new[2]>>16]];
-			d_viewbuffer[d_scantable[new[1]] + new[0]] = pix;
 		}
 	}
 
@@ -367,7 +362,7 @@
 void D_PolysetUpdateTables (void)
 {
 	int		i;
-	byte	*s;
+	pixel_t	*s;
 
 	if (r_affinetridesc.skinwidth != skinwidth ||
 		r_affinetridesc.pskin != skinstart)
@@ -545,11 +540,10 @@
 D_PolysetDrawSpans8
 ================
 */
-void D_PolysetDrawSpans8 (spanpackage_t *pspanpackage, byte *colormap, byte alpha)
+void D_PolysetDrawSpans8 (spanpackage_t *pspanpackage, pixel_t *colormap, byte alpha)
 {
 	int		lcount;
-	byte	*lpdest;
-	byte	*lptex;
+	pixel_t	*lpdest, *lptex;
 	int		lsfrac, ltfrac;
 	int		llight;
 	int		lzi;
@@ -583,14 +577,15 @@
 			do
 			{
 				if ((lzi >> 16) >= *lpz){
+					pixel_t p = colormap[CIND(*lptex) + (llight & 0xFF00)];
 					if(r_drawflags & DRAW_BLEND){
 						*lpdest = blendalpha(
-							colormap[*lptex + (llight & 0xFF00)],
+							p,
 							*lpdest,
 							alpha
 						);
 					}else{
-						*lpdest = colormap[*lptex + (llight & 0xFF00)];
+						*lpdest = p;
 						// gel mapping	*lpdest = gelmap[*lpdest];
 						*lpz = lzi >> 16;
 					}
@@ -647,7 +642,7 @@
 	ystart = plefttop[1];
 	d_aspancount = plefttop[0] - prighttop[0];
 
-	d_ptex = (byte *)r_affinetridesc.pskin + (plefttop[2] >> 16) +
+	d_ptex = r_affinetridesc.pskin + (plefttop[2] >> 16) +
 			(plefttop[3] >> 16) * r_affinetridesc.skinwidth;
 	d_sfrac = plefttop[2] & 0xFFFF;
 	d_tfrac = plefttop[3] & 0xFFFF;
@@ -654,8 +649,7 @@
 	d_light = plefttop[4];
 	d_zi = plefttop[5];
 
-	d_pdest = (byte *)d_viewbuffer +
-			ystart * screenwidth + plefttop[0];
+	d_pdest = d_viewbuffer + ystart * screenwidth + plefttop[0];
 	d_pz = d_pzbuffer + ystart * d_zwidth + plefttop[0];
 
 	if (initialleftheight == 1)
@@ -728,7 +722,7 @@
 
 		ystart = plefttop[1];
 		d_aspancount = plefttop[0] - prighttop[0];
-		d_ptex = (byte *)r_affinetridesc.pskin + (plefttop[2] >> 16) +
+		d_ptex = r_affinetridesc.pskin + (plefttop[2] >> 16) +
 				(plefttop[3] >> 16) * r_affinetridesc.skinwidth;
 		d_sfrac = 0;
 		d_tfrac = 0;
@@ -735,7 +729,7 @@
 		d_light = plefttop[4];
 		d_zi = plefttop[5];
 
-		d_pdest = (byte *)d_viewbuffer + ystart * screenwidth + plefttop[0];
+		d_pdest = d_viewbuffer + ystart * screenwidth + plefttop[0];
 		d_pz = d_pzbuffer + ystart * d_zwidth + plefttop[0];
 
 		if (height == 1)
--- a/d_scan.c
+++ b/d_scan.c
@@ -1,10 +1,10 @@
 #include "quakedef.h"
 
-static unsigned char	*r_turb_pbase, *r_turb_pdest;
-static fixed16_t		r_turb_s, r_turb_t, r_turb_sstep, r_turb_tstep;
-static int				*r_turb_turb;
-static int				r_turb_spancount;
-static uzint	*r_turb_z;
+static pixel_t *r_turb_pbase, *r_turb_pdest;
+static fixed16_t r_turb_s, r_turb_t, r_turb_sstep, r_turb_tstep;
+static int *r_turb_turb;
+static int r_turb_spancount;
+static uzint *r_turb_z;
 
 /*
 =============
@@ -16,14 +16,11 @@
 */
 void D_WarpScreen (void)
 {
-	int		w, h;
-	int		u,v;
-	byte	*dest;
-	int		*turb;
-	int		*col;
-	byte	**row;
+	int		w, h, u, v, *turb, *col;
+	pixel_t	*dest;
+	pixel_t	**row;
 	float	wratio, hratio;
-	static byte	*rowptr[MAXHEIGHT+(AMP2*2)];
+	static pixel_t	*rowptr[MAXHEIGHT+(AMP2*2)];
 	static int	column[MAXWIDTH+(AMP2*2)];
 
 	w = r_refdef.vrect.width;
@@ -89,7 +86,7 @@
 	r_turb_sstep = 0;	// keep compiler happy
 	r_turb_tstep = 0;	// ditto
 
-	r_turb_pbase = (byte*)cacheblock;
+	r_turb_pbase = cacheblock;
 
 	sdivz16stepu = d_sdivzstepu * 16;
 	tdivz16stepu = d_tdivzstepu * 16;
@@ -96,7 +93,7 @@
 	zi16stepu = d_zistepu * 16;
 
 	do{
-		r_turb_pdest = (byte *)d_viewbuffer + screenwidth*pspan->v + pspan->u;
+		r_turb_pdest = d_viewbuffer + screenwidth*pspan->v + pspan->u;
 		r_turb_z = d_pzbuffer + d_zwidth*pspan->v + pspan->u;
 
 		count = pspan->count;
@@ -178,7 +175,7 @@
 D_DrawSpans16(espan_t *pspan, int forceblend, byte alpha) //qbism- up it from 8 to 16
 {
 	int			count, spancount, izistep;
-	byte		*pbase, *pdest;
+	pixel_t		*pbase, *pdest;
 	uzint		*pz;
 	fixed16_t	s, t, snext, tnext, sstep, tstep;
 	double		sdivz, tdivz, zi, z, du, dv, spancountminus1;
@@ -187,7 +184,7 @@
 	sstep = 0;	// keep compiler happy
 	tstep = 0;	// ditto
 
-	pbase = (byte*)cacheblock;
+	pbase = cacheblock;
 
 	sdivzstepu = d_sdivzstepu * 16;
 	tdivzstepu = d_tdivzstepu * 16;
@@ -195,7 +192,7 @@
 	izistep = (int)(d_zistepu * 0x8000 * 0x10000);
 
 	do{
-		pdest = (byte *)d_viewbuffer + screenwidth*pspan->v + pspan->u;
+		pdest = d_viewbuffer + screenwidth*pspan->v + pspan->u;
 		pz = d_pzbuffer + d_zwidth*pspan->v + pspan->u;
 
 		count = pspan->count;
@@ -267,8 +264,8 @@
 			}
 
 			if(spancount > 0){
-				void dospan(byte *, byte *, int, int, int, int, int, int);
-				void dospan_alpha(byte *, byte *, int, int, int, int, int, int, byte, uzint *, int,int);
+				void dospan(pixel_t *, pixel_t *, int, int, int, int, int, int);
+				void dospan_alpha(pixel_t *, pixel_t *, int, int, int, int, int, int, byte, uzint *, int, int);
 				if((r_drawflags & DRAW_BLEND) != 0 || forceblend)
 					dospan_alpha(pdest, pbase, s, t, sstep, tstep, spancount, cachewidth, alpha, pz, (int)(zi * 0x8000 * 0x10000), izistep);
 				else
@@ -287,8 +284,7 @@
 void
 D_DrawZSpans(espan_t *pspan)
 {
-	int			count, doublecount, izistep;
-	int			izi;
+	int			count, doublecount, izistep, izi;
 	uzint		*pdest;
 	unsigned	ltemp;
 	double		zi;
--- a/d_sky.c
+++ b/d_sky.c
@@ -38,11 +38,10 @@
 */
 void D_DrawSkyScans8 (espan_t *pspan)
 {
-	int				count, spancount, u, v;
-	unsigned char	*pdest, m;
-	fixed16_t		s[2], t[2], snext[2], tnext[2], sstep[2], tstep[2];
-	int				spancountminus1;
-	float			skydist;
+	int count, spancount, u, v, spancountminus1;
+	pixel_t *pdest, m;
+	fixed16_t s[2], t[2], snext[2], tnext[2], sstep[2], tstep[2];
+	float skydist;
 
 	sstep[0] = sstep[1] = 0;	// keep compiler happy
 	tstep[0] = tstep[1] = 0;	// ditto
@@ -50,9 +49,7 @@
 
 	do
 	{
-		pdest = (unsigned char *)((byte *)d_viewbuffer +
-				(screenwidth * pspan->v) + pspan->u);
-
+		pdest = d_viewbuffer + (screenwidth * pspan->v) + pspan->u;
 		count = pspan->count;
 
 		// calculate the initial s & t
--- a/d_sprite.c
+++ b/d_sprite.c
@@ -13,11 +13,10 @@
 {
 	int			count, spancount, izistep;
 	int			izi;
-	byte		*pbase, *pdest;
+	pixel_t		*pbase, *pdest, btemp;
 	fixed16_t	s, t, snext, tnext, sstep, tstep;
 	float		sdivz, tdivz, zi, z, du, dv, spancountminus1;
 	float		sdivz8stepu, tdivz8stepu, zi8stepu;
-	byte		btemp;
 	uzint		*pz;
 
 	sstep = 0;	// keep compiler happy
@@ -34,7 +33,7 @@
 
 	do
 	{
-		pdest = (byte *)d_viewbuffer + (screenwidth * pspan->v) + pspan->u;
+		pdest = d_viewbuffer + (screenwidth * pspan->v) + pspan->u;
 		pz = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
 
 		count = pspan->count;
@@ -136,7 +135,7 @@
 			do
 			{
 				btemp = *(pbase + (s >> 16) + (t >> 16) * cachewidth);
-				if (btemp != 255)
+				if (opaque(btemp))
 				{
 					if (*pz <= (izi >> 16)){	/* FIXME: segfault: assumed 32bit ptr? */
 						if(r_drawflags & DRAW_BLEND){
@@ -402,7 +401,7 @@
 
 	cachewidth = r_spritedesc.pspriteframe->width;
 	sprite_height = r_spritedesc.pspriteframe->height;
-	cacheblock = (byte *)&r_spritedesc.pspriteframe->pixels[0];
+	cacheblock = &r_spritedesc.pspriteframe->pixels[0];
 
 	// copy the first vertex to the last vertex, so we don't have to deal with
 	// wrapping
--- a/d_surf.c
+++ b/d_surf.c
@@ -16,7 +16,7 @@
 
 	size = SURFCACHE_SIZE_AT_320X200;
 
-	pix = width*height;
+	pix = width*height*sizeof(pixel_t);
 	if (pix > 64000)
 		size += (pix-64000)*3;
 
@@ -97,22 +97,19 @@
 D_SCAlloc
 =================
 */
-surfcache_t	 *D_SCAlloc (int width, uintptr size)
+static surfcache_t *
+D_SCAlloc(int width, int size)
 {
 	surfcache_t			 *new;
 	bool				wrapped_this_time;
 
-	if ((width < 0) || (width > 256))
-		Host_Error("D_SCAlloc: bad cache width %d\n", width);
+	if(width < 0 || size <= 0)
+		Host_Error("D_SCAlloc: width=%d size=%d\n", width, size);
 
-	if ((size <= 0) || (size > 0x10000))
-		Host_Error("D_SCAlloc: bad cache size %zud\n", size);
+	size = (sizeof(surfcache_t) + size + 3) & ~3;
+	if(size > sc_size)
+		Host_Error("D_SCAlloc: %d > cache size",size);
 
-	size = (uintptr)&((surfcache_t *)0)->data[size];
-	size = (size + 3) & ~3;
-	if (size > (uintptr)sc_size)
-		Host_Error("D_SCAlloc: %zud > cache size",size);
-
 	// if there is not size bytes after the rover, reset to the start
 	wrapped_this_time = false;
 
@@ -130,7 +127,7 @@
 	if (sc_rover->owner)
 		*sc_rover->owner = nil;
 
-	while ((uintptr)new->size < size)
+	while (new->size < size)
 	{
 		// free another
 		sc_rover = sc_rover->next;
@@ -160,7 +157,7 @@
 	new->width = width;
 	// DEBUG
 	if (width > 0)
-		new->height = (size - sizeof(*new) + sizeof(new->data)) / width;
+		new->height = (size - sizeof(*new)) / width / sizeof(pixel_t);
 
 	new->owner = nil;			  // should be set properly after return
 
@@ -217,16 +214,13 @@
 	if (!cache)	 // if a texture just animated, don't reallocate it
 	{
 		cache = D_SCAlloc (r_drawsurf.surfwidth,
-						   r_drawsurf.surfwidth * r_drawsurf.surfheight);
+						   r_drawsurf.surfwidth * r_drawsurf.surfheight * sizeof(pixel_t));
 		surface->cachespots[miplevel] = cache;
 		cache->owner = &surface->cachespots[miplevel];
 		cache->mipscale = surfscale;
 	}
 
-	if (surface->dlightframe == r_framecount)
-		cache->dlight = 1;
-	else
-		cache->dlight = 0;
+	cache->dlight = surface->dlightframe == r_framecount;
 
 	r_drawsurf.surfdat = (pixel_t *)cache->data;
 
--- a/draw.c
+++ b/draw.c
@@ -4,14 +4,14 @@
 	vrect_t	rect;
 	int		width;
 	int		height;
-	byte	*ptexbytes;
+	pixel_t	*ptexpixels;
 	int		rowbytes;
 } rectdesc_t;
 
 qpic_t *draw_disc;
 
-static rectdesc_t	r_rectdesc;
-static byte *draw_chars;				// 8*8 graphic characters
+static rectdesc_t r_rectdesc;
+static pixel_t *draw_chars;				// 8*8 graphic characters
 static qpic_t *draw_backtile;
 
 //=============================================================================
@@ -27,11 +27,33 @@
 static cachepic_t menu_cachepics[MAX_CACHED_PICS];
 static int menu_numcachepics;
 
-qpic_t	*Draw_PicFromWad (char *name)
+qpic_t *
+Draw_PicFromWad (char *name)
 {
-	return W_GetLumpName (name);
+	mem_user_t dummy = {0};
+	qpic_t *p, *q = W_GetLumpName (name);
+	int n;
+
+	n = q->width*q->height;
+	memset(&dummy, 0, sizeof(dummy));
+	p = Cache_Alloc(&dummy, sizeof(*q)+n*sizeof(pixel_t));
+	memmove(p, q, sizeof(*q));
+	torgbx((byte*)q->data, p->data, n);
+	return p;
 }
 
+void
+CachedPicConv(cachepic_t *p)
+{
+	qpic_t *q;
+	int n;
+
+	q = Cache_Check(&p->cache);
+	n = q->width*q->height;
+	q = Cache_Realloc(&p->cache, sizeof(*q)+n*sizeof(pixel_t));
+	torgbx((byte*)q->data, q->data, n);
+}
+
 /*
 ================
 Draw_CachePic
@@ -55,9 +77,9 @@
 		strcpy (pic->name, path);
 	}
 
-	dat = Cache_Check (&pic->cache);
+	dat = Cache_Check(&pic->cache);
 
-	if (dat)
+	if(dat)
 		return dat;
 
 	// load the pic from disk
@@ -64,10 +86,10 @@
 	dat = loadcachelmp(path, &pic->cache);
 	if(dat == nil)
 		fatal("Draw_CachePic: %s", lerr());
+	SwapPic(dat);
+	CachedPicConv(pic);
 
-	SwapPic (dat);
-
-	return dat;
+	return Cache_Check(&pic->cache);
 }
 
 
@@ -79,17 +101,18 @@
 */
 void Draw_Init (void)
 {
-	draw_chars = W_GetLumpName ("conchars");
-	draw_disc = W_GetLumpName ("disc");
-	draw_backtile = W_GetLumpName ("backtile");
+	mem_user_t dummy = {0};
+
+	draw_chars = Cache_Alloc(&dummy, 128*128*sizeof(pixel_t));
+	torgbx(W_GetLumpName("conchars"), draw_chars, 128*128);
+	draw_disc = Draw_PicFromWad("disc");
+	draw_backtile = Draw_PicFromWad("backtile");
 	r_rectdesc.width = draw_backtile->width;
 	r_rectdesc.height = draw_backtile->height;
-	r_rectdesc.ptexbytes = draw_backtile->data;
+	r_rectdesc.ptexpixels = draw_backtile->data;
 	r_rectdesc.rowbytes = draw_backtile->width;
 }
 
-
-
 /*
 ================
 Draw_Character
@@ -101,10 +124,8 @@
 */
 void Draw_Character (int x, int y, int num)
 {
-	byte			*dest;
-	byte			*source;
-	int				drawline;
-	int				row, col;
+	pixel_t *dest, *source;
+	int drawline, row, col;
 
 	num &= 255;
 
@@ -167,7 +188,7 @@
 */
 void Draw_Pic (int x, int y, qpic_t *pic)
 {
-	byte			*dest, *source;
+	pixel_t *dest, *source;
 	int px, py;
 
 	if ((x < 0) ||
@@ -181,7 +202,7 @@
 	dest = vid.buffer + y * vid.rowbytes + x;
 	for(py = 0; py < pic->height; py++){
 		for(px = 0; px < pic->width; px++){
-			if(source[px] != 255)
+			if(opaque(source[px]))
 				dest[px] = source[px];
 		}
 		dest += vid.rowbytes;
@@ -197,8 +218,8 @@
 */
 void Draw_TransPic (int x, int y, qpic_t *pic)
 {
-	byte	*dest, *source, tbyte;
-	int				v, u;
+	pixel_t *dest, *source, tpix;
+	int v, u;
 
 	if (x < 0 || y < 0 || x+pic->width > vid.width || y+pic->height > vid.height)
 		fatal ("Draw_TransPic: bad coordinates");
@@ -208,8 +229,8 @@
 	if(pic->width & 7){	// general
 		for(v=0; v<pic->height; v++){
 			for(u=0; u<pic->width; u++)
-				if((tbyte = source[u]) != TRANSPARENT_COLOR)
-					dest[u] = tbyte;
+				if(opaque(tpix = source[u]))
+					dest[u] = tpix;
 			dest += vid.rowbytes;
 			source += pic->width;
 		}
@@ -216,22 +237,22 @@
 	}else{	// unwound
 		for(v=0; v<pic->height; v++){
 			for(u=0; u<pic->width; u+=8){
-				if((tbyte = source[u]) != TRANSPARENT_COLOR)
-					dest[u] = tbyte;
-				if((tbyte = source[u+1]) != TRANSPARENT_COLOR)
-					dest[u+1] = tbyte;
-				if((tbyte = source[u+2]) != TRANSPARENT_COLOR)
-					dest[u+2] = tbyte;
-				if((tbyte = source[u+3]) != TRANSPARENT_COLOR)
-					dest[u+3] = tbyte;
-				if((tbyte = source[u+4]) != TRANSPARENT_COLOR)
-					dest[u+4] = tbyte;
-				if((tbyte = source[u+5]) != TRANSPARENT_COLOR)
-					dest[u+5] = tbyte;
-				if((tbyte = source[u+6]) != TRANSPARENT_COLOR)
-					dest[u+6] = tbyte;
-				if((tbyte = source[u+7]) != TRANSPARENT_COLOR)
-					dest[u+7] = tbyte;
+				if(opaque(tpix = source[u]))
+					dest[u] = tpix;
+				if(opaque(tpix = source[u+1]))
+					dest[u+1] = tpix;
+				if(opaque(tpix = source[u+2]))
+					dest[u+2] = tpix;
+				if(opaque(tpix = source[u+3]))
+					dest[u+3] = tpix;
+				if(opaque(tpix = source[u+4]))
+					dest[u+4] = tpix;
+				if(opaque(tpix = source[u+5]))
+					dest[u+5] = tpix;
+				if(opaque(tpix = source[u+6]))
+					dest[u+6] = tpix;
+				if(opaque(tpix = source[u+7]))
+					dest[u+7] = tpix;
 			}
 			dest += vid.rowbytes;
 			source += pic->width;
@@ -247,7 +268,7 @@
 */
 void Draw_TransPicTranslate (int x, int y, qpic_t *pic, byte *translation)
 {
-	byte	*dest, *source, tbyte;
+	pixel_t	*dest, *source, tpix;
 	int				v, u;
 
 	if (x < 0 || y < 0 || x+pic->width > vid.width || y+pic->height > vid.height)
@@ -258,8 +279,8 @@
 	if (pic->width & 7){	// general
 		for(v=0; v<pic->height; v++){
 			for(u=0; u<pic->width; u++)
-				if((tbyte = source[u]) != TRANSPARENT_COLOR)
-					dest[u] = translation[tbyte];
+				if(opaque(tpix = source[u]))
+					dest[u] = q1pal[translation[CIND(tpix)]];
 			dest += vid.rowbytes;
 			source += pic->width;
 		}
@@ -266,22 +287,22 @@
 	}else{	// unwound
 		for(v=0; v<pic->height; v++){
 			for(u=0; u<pic->width; u+=8){
-				if((tbyte = source[u]) != TRANSPARENT_COLOR)
-					dest[u] = translation[tbyte];
-				if((tbyte = source[u+1]) != TRANSPARENT_COLOR)
-					dest[u+1] = translation[tbyte];
-				if((tbyte = source[u+2]) != TRANSPARENT_COLOR)
-					dest[u+2] = translation[tbyte];
-				if((tbyte = source[u+3]) != TRANSPARENT_COLOR)
-					dest[u+3] = translation[tbyte];
-				if((tbyte = source[u+4]) != TRANSPARENT_COLOR)
-					dest[u+4] = translation[tbyte];
-				if((tbyte = source[u+5]) != TRANSPARENT_COLOR)
-					dest[u+5] = translation[tbyte];
-				if((tbyte = source[u+6]) != TRANSPARENT_COLOR)
-					dest[u+6] = translation[tbyte];
-				if((tbyte = source[u+7]) != TRANSPARENT_COLOR)
-					dest[u+7] = translation[tbyte];
+				if(opaque(tpix = source[u]))
+					dest[u] = q1pal[translation[CIND(tpix)]];
+				if(opaque(tpix = source[u+1]))
+					dest[u+1] = q1pal[translation[CIND(tpix)]];
+				if(opaque(tpix = source[u+2]))
+					dest[u+2] = q1pal[translation[CIND(tpix)]];
+				if(opaque(tpix = source[u+3]))
+					dest[u+3] = q1pal[translation[CIND(tpix)]];
+				if(opaque(tpix = source[u+4]))
+					dest[u+4] = q1pal[translation[CIND(tpix)]];
+				if(opaque(tpix = source[u+5]))
+					dest[u+5] = q1pal[translation[CIND(tpix)]];
+				if(opaque(tpix = source[u+6]))
+					dest[u+6] = q1pal[translation[CIND(tpix)]];
+				if(opaque(tpix = source[u+7]))
+					dest[u+7] = q1pal[translation[CIND(tpix)]];
 			}
 			dest += vid.rowbytes;
 			source += pic->width;
@@ -290,12 +311,10 @@
 }
 
 
-void Draw_CharToConback (int num, byte *dest)
+static void Draw_CharToConback (int num, pixel_t *dest)
 {
-	int		row, col;
-	byte	*source;
-	int		drawline;
-	int		x;
+	int row, col, drawline, x;
+	pixel_t	*source;
 
 	row = num>>4;
 	col = num&15;
@@ -306,8 +325,8 @@
 	while (drawline--)
 	{
 		for (x=0 ; x<8 ; x++)
-			if (source[x])
-				dest[x] = 0x60 + source[x];
+			if(source[x] != 0) /* black is transparent */
+				dest[x] = q1pal[0x60 + CIND(source[x])];
 		source += 128;
 		dest += 320;
 	}
@@ -323,7 +342,7 @@
 void Draw_ConsoleBackground (int lines)
 {
 	int				x, y, v, n;
-	byte			*src, *dest;
+	pixel_t			*src, *dest;
 	int				f, fstep;
 	qpic_t			*conback;
 	char			ver[100];
@@ -342,7 +361,7 @@
 		v = (vid.conheight - lines + y) * 200 / vid.conheight;
 		src = conback->data + v * 320;
 		if(vid.conwidth == 320)
-			memcpy(dest, src, vid.conwidth);
+			memcpy(dest, src, vid.conwidth*sizeof(pixel_t));
 		else{
 			f = 0;
 			fstep = 320 * 0x10000 / vid.conwidth;
@@ -362,12 +381,10 @@
 R_DrawRect8
 ==============
 */
-void R_DrawRect8 (vrect_t *prect, int rowbytes, byte *psrc,
-	int transparent)
+void R_DrawRect8 (vrect_t *prect, int rowbytes, pixel_t *psrc, int transparent)
 {
-	byte	t;
+	pixel_t	t, *pdest;
 	int		i, j, srcdelta, destdelta;
-	byte	*pdest;
 
 	pdest = vid.buffer + (prect->y * vid.rowbytes) + prect->x;
 
@@ -376,16 +393,10 @@
 
 	if (transparent)
 	{
-		for (i=0 ; i<prect->height ; i++)
-		{
-			for (j=0 ; j<prect->width ; j++)
-			{
-				t = *psrc;
-				if (t != TRANSPARENT_COLOR)
-				{
+		for (i=0 ; i<prect->height ; i++){
+			for (j=0 ; j<prect->width ; j++){
+				if(opaque(t = *psrc))
 					*pdest = t;
-				}
-
 				psrc++;
 				pdest++;
 			}
@@ -393,12 +404,9 @@
 			psrc += srcdelta;
 			pdest += destdelta;
 		}
-	}
-	else
-	{
-		for (i=0 ; i<prect->height ; i++)
-		{
-			memcpy (pdest, psrc, prect->width);
+	}else{
+		for (i=0 ; i<prect->height ; i++){
+			memcpy (pdest, psrc, prect->width*sizeof(pixel_t));
 			psrc += rowbytes;
 			pdest += vid.rowbytes;
 		}
@@ -416,7 +424,7 @@
 void Draw_TileClear (int x, int y, int w, int h)
 {
 	int				width, height, tileoffsetx, tileoffsety;
-	byte			*psrc;
+	pixel_t			*psrc;
 	vrect_t			vr;
 
 	r_rectdesc.rect.x = x;
@@ -454,7 +462,7 @@
 			if (vr.width > width)
 				vr.width = width;
 
-			psrc = r_rectdesc.ptexbytes +
+			psrc = r_rectdesc.ptexpixels +
 					(tileoffsety * r_rectdesc.rowbytes) + tileoffsetx;
 			R_DrawRect8(&vr, r_rectdesc.rowbytes, psrc, 0);
 			vr.x += vr.width;
@@ -476,9 +484,9 @@
 Fills a box of pixels with a single color
 =============
 */
-void Draw_Fill (int x, int y, int w, int h, int c)
+void Draw_Fill (int x, int y, int w, int h, pixel_t c)
 {
-	byte			*dest;
+	pixel_t			*dest;
 	int				u, v;
 
 	dest = vid.buffer + y*vid.rowbytes + x;
@@ -496,13 +504,13 @@
 void Draw_FadeScreen (void)
 {
 	int			x,y;
-	byte		*pbuf;
+	pixel_t		*pbuf;
 
 	for (y=0 ; y<vid.height ; y++)
 	{
 		int	t;
 
-		pbuf = (byte *)(vid.buffer + vid.rowbytes*y);
+		pbuf = vid.buffer + vid.rowbytes*y;
 		t = (y & 1) << 1;
 
 		for (x=0 ; x<vid.width ; x++)
--- a/draw.h
+++ b/draw.h
@@ -12,7 +12,7 @@
 void Draw_BeginDisc (void);
 void Draw_EndDisc (void);
 void Draw_TileClear (int x, int y, int w, int h);
-void Draw_Fill (int x, int y, int w, int h, int c);
+void Draw_Fill (int x, int y, int w, int h, pixel_t c);
 void Draw_FadeScreen (void);
 void Draw_String (int x, int y, char *str);
 qpic_t *Draw_PicFromWad (char *name);
--- a/fs.c
+++ b/fs.c
@@ -431,7 +431,7 @@
 		p->next = active_particles;
 		active_particles = p;
 		p->die = Q_MAXFLOAT;
-		p->color = -nv & 15;
+		p->color = q1pal[(byte)(-nv & 15)];
 		p->type = pt_static;
 		VectorCopy(vec3_origin, p->vel);
 		VectorCopy(v3, p->org);
--- a/host.c
+++ b/host.c
@@ -94,12 +94,14 @@
 		fatal("Host_Error: recursively entered");
 	inerror = true;
 
-	SCR_EndLoadingPlaque();	// reenable screen updates
-
 	va_start(arg, fmt);
 	vsnprint(s, sizeof s, fmt, arg);
 	va_end(arg);
 
+	fprintf(stderr, "Host_Error: %s\n", s);
+
+	SCR_EndLoadingPlaque();	// reenable screen updates
+
 	Con_Printf("Host_Error: %s\n", s);
 
 	if(sv.active)
@@ -599,6 +601,7 @@
 		host_basepal = loadhunklmp("gfx/palette.lmp", nil);
 		if(host_basepal == nil)
 			fatal("Host_Init: %s", lerr());
+		setpal(host_basepal);
 		host_colormap = loadhunklmp("gfx/colormap.lmp", nil);
 		if(host_colormap == nil)
 			fatal("Host_Init: %s", lerr());
--- a/mkfile
+++ b/mkfile
@@ -5,7 +5,6 @@
 CFLAGS=$CFLAGS -D__plan9__
 
 OFILES=\
-	pal`{test -f pal_$objtype.s && echo -n _$objtype}.$O\
 	span`{test -f span_$objtype.s && echo -n _$objtype}.$O\
 	span_alpha.$O\
 	dotproduct`{test -f span_$objtype.s && echo -n _$objtype}.$O\
--- a/model.h
+++ b/model.h
@@ -46,13 +46,13 @@
 
 typedef struct texture_s
 {
-	char		name[16];
-	unsigned	width, height;
-	int			anim_total;				// total tenths in sequence ( 0 = no)
-	int			anim_min, anim_max;		// time for this frame min <=time< max
+	char name[16];
+	int width, height;
+	int anim_total;				// total tenths in sequence ( 0 = no)
+	int anim_min, anim_max;		// time for this frame min <=time< max
 	struct texture_s *anim_next;		// in the animation sequence
 	struct texture_s *alternate_anims;	// bmodels in frmae 1 use these
-	unsigned	offsets[MIPLEVELS];		// four mip maps stored
+	int offsets[MIPLEVELS];		// four mip maps stored
 } texture_t;
 
 enum {
@@ -179,7 +179,7 @@
 	int		height;
 	void	*pcachespot;			// remove?
 	float	up, down, left, right;
-	byte	pixels[4];
+	pixel_t	pixels[];
 } mspriteframe_t;
 
 typedef struct
--- a/model_alias.c
+++ b/model_alias.c
@@ -105,12 +105,13 @@
 static void *
 Mod_LoadAliasSkin(void * pin, int *pskinindex, int skinsize, aliashdr_t *pheader)
 {
-	uchar *pskin, *pinskin;
+	uchar *pinskin;
+	pixel_t *pskin;
 
 	*pskinindex = Hunk_From(pheader);
-	pskin = Hunk_Alloc(skinsize);
+	pskin = Hunk_Alloc(skinsize*4);
 	pinskin = (uchar *)pin;
-	memcpy(pskin, pinskin, skinsize);
+	torgbx(pinskin, pskin, skinsize);
 	pinskin += skinsize;
 	return (void *)pinskin;
 }
--- a/model_bsp.c
+++ b/model_bsp.c
@@ -100,17 +100,17 @@
 		p = in0+off+16;
 		w = le32(p);
 		h = le32(p);
-		pixels = w*h/64*85;
-		tx = Hunk_Alloc(sizeof(*tx) + pixels);
+		pixels = w*h*85/64;
+		tx = Hunk_Alloc(sizeof(*tx) + pixels*sizeof(pixel_t));
 		strncpy(tx->name, (char*)in0+off, sizeof(tx->name)-1);
 		tx->name[sizeof(tx->name)-1] = 0;
 		for(j = 0; j < MIPLEVELS; j++)
-			tx->offsets[j] = le32(p) + sizeof(texture_t) - (16+2*4+4*4);
+			tx->offsets[j] = sizeof(texture_t) + (le32(p) - (16+2*4+4*4))*sizeof(pixel_t);
 		mod->textures[i] = tx;
 		tx->width = w;
 		tx->height = h;
 		// the pixels immediately follow the structures
-		memcpy(tx+1, p, pixels);
+		torgbx(p, (pixel_t*)(tx+1), pixels);
 		if(strncmp(tx->name, "sky", 3) == 0)
 			R_InitSky(tx);
 	}
--- a/model_sprite.c
+++ b/model_sprite.c
@@ -23,7 +23,7 @@
 	if(e-in < (size = w*h))
 		goto toosmall;
 
-	*ppframe = pspriteframe = Hunk_Alloc(sizeof(*pspriteframe) + size);
+	*ppframe = pspriteframe = Hunk_Alloc(sizeof(*pspriteframe) + size*sizeof(pixel_t));
 	pspriteframe->width = w;
 	pspriteframe->height = h;
 	pspriteframe->up = origin[1];
@@ -30,7 +30,7 @@
 	pspriteframe->down = origin[1] - h;
 	pspriteframe->left = origin[0];
 	pspriteframe->right = w + origin[0];
-	memmove(pspriteframe->pixels, in, size);
+	torgbx(in, pspriteframe->pixels, size);
 	in += size;
 
 	return in;
--- a/quakedef.h
+++ b/quakedef.h
@@ -174,11 +174,15 @@
 
 extern	bool	host_initialized;		// true if into command execution
 extern	double		host_frametime;
-extern	byte		*host_basepal;
-extern	byte		*host_colormap;
+extern	byte		*host_basepal, *host_colormap;
 extern	int		host_framecount;	// incremented every frame, never reset
 extern	double		realtime;		// not bounded in any way, changed at
 						// start of every frame, never reset
+
+#define opaque(p) (((p)>>24) != 0xff)
+
+extern pixel_t q1pal[256];
+void torgbx(byte *in, pixel_t *out, int n);
 
 void Host_ClearMemory (void);
 void Host_ServerFrame (void);
--- a/r_alias.c
+++ b/r_alias.c
@@ -225,7 +225,7 @@
 General clipped case
 ================
 */
-void R_AliasPreparePoints (trivertx_t *apverts, auxvert_t *auxverts, byte *colormap)
+void R_AliasPreparePoints (trivertx_t *apverts, auxvert_t *auxverts, pixel_t *colormap)
 {
 	int			i;
 	stvert_t	*pstverts;
@@ -478,7 +478,7 @@
 R_AliasPrepareUnclippedPoints
 ================
 */
-void R_AliasPrepareUnclippedPoints (trivertx_t *pverts, byte *colormap)
+void R_AliasPrepareUnclippedPoints (trivertx_t *pverts, pixel_t *colormap)
 {
 	stvert_t	*pstverts;
 	finalvert_t	*fv;
--- a/r_main.c
+++ b/r_main.c
@@ -5,7 +5,7 @@
 static alight_t r_viewlighting = {128, 192, viewlightvec};
 int			r_numallocatededges;
 int			r_numallocatedbasespans;
-byte		*r_basespans;
+void		*r_basespans;
 bool	r_recursiveaffinetriangles = true;
 float		r_aliasuvscale = 1.0;
 int			r_outofsurfaces;
@@ -21,7 +21,7 @@
 bool	r_surfsonstack;
 int			r_clipflags;
 
-byte		*r_warpbuffer;
+pixel_t *r_warpbuffer;
 
 //
 // view origin
@@ -102,27 +102,27 @@
 void	R_InitTextures (void)
 {
 	int		x,y, m;
-	byte	*dest;
+	pixel_t	*dest;
 
 	// create a simple checkerboard texture for the default
-	r_notexture_mip = Hunk_Alloc(16*16+8*8+4*4+2*2 + sizeof *r_notexture_mip);
+	r_notexture_mip = Hunk_Alloc((16*16+8*8+4*4+2*2)*sizeof(pixel_t) + sizeof *r_notexture_mip);
 
 	r_notexture_mip->width = r_notexture_mip->height = 16;
-	r_notexture_mip->offsets[0] = sizeof *r_notexture_mip;
-	r_notexture_mip->offsets[1] = r_notexture_mip->offsets[0] + 16*16;
-	r_notexture_mip->offsets[2] = r_notexture_mip->offsets[1] + 8*8;
-	r_notexture_mip->offsets[3] = r_notexture_mip->offsets[2] + 4*4;
+	r_notexture_mip->offsets[0] = sizeof(*r_notexture_mip);
+	r_notexture_mip->offsets[1] = r_notexture_mip->offsets[0] + 16*16*sizeof(pixel_t);
+	r_notexture_mip->offsets[2] = r_notexture_mip->offsets[1] + 8*8*sizeof(pixel_t);
+	r_notexture_mip->offsets[3] = r_notexture_mip->offsets[2] + 4*4*sizeof(pixel_t);
 
 	for (m=0 ; m<4 ; m++)
 	{
-		dest = (byte *)r_notexture_mip + r_notexture_mip->offsets[m];
+		dest = (pixel_t*)((byte*)r_notexture_mip + r_notexture_mip->offsets[m]);
 		for (y=0 ; y< (16>>m) ; y++)
-			for (x=0 ; x< (16>>m) ; x++)
+			for (x=0 ; x< (16>>m) ; x++, dest++)
 			{
 				if (  (y< (8>>m) ) ^ (x< (8>>m) ) )
-					*dest++ = 0;
+					*dest = 0;
 				else
-					*dest++ = 0xff;
+					*dest = 0xf0f0f0f0;
 			}
 	}
 }
@@ -691,10 +691,12 @@
 */
 void R_RenderView (void)
 {
-	static byte	warpbuffer[WARP_WIDTH * WARP_HEIGHT];
+	static pixel_t *warpbuffer;
 	entity_t *e;
 	int i;
 
+	if(warpbuffer == nil)
+		warpbuffer = malloc(WARP_WIDTH * WARP_HEIGHT * sizeof(*warpbuffer));
 	r_warpbuffer = warpbuffer;
 
 	R_SetupFrame ();
--- a/r_part.c
+++ b/r_part.c
@@ -73,7 +73,7 @@
 		active_particles = p;
 
 		p->die = cl.time + 0.01;
-		p->color = 0x6f;
+		p->color = q1pal[0x6f];
 		p->type = pt_explode;
 
 		p->org[0] = ent->origin[0] + r_avertexnormals[i][0]*dist + forward[0]*beamlength;
@@ -143,7 +143,7 @@
 		active_particles = p;
 
 		p->die = cl.time + 5;
-		p->color = ramp1[0];
+		p->color = q1pal[ramp1[0]];
 		p->ramp = rand()&3;
 		if (i & 1)
 		{
@@ -188,7 +188,7 @@
 		active_particles = p;
 
 		p->die = cl.time + 0.3;
-		p->color = colorStart + (colorMod % colorLength);
+		p->color = q1pal[colorStart + (colorMod % colorLength)];
 		colorMod++;
 
 		p->type = pt_blob;
@@ -225,7 +225,7 @@
 		if (i & 1)
 		{
 			p->type = pt_blob;
-			p->color = 66 + rand()%6;
+			p->color = q1pal[66 + rand()%6];
 			for (j=0 ; j<3 ; j++)
 			{
 				p->org[j] = org[j] + ((rand()%32)-16);
@@ -235,7 +235,7 @@
 		else
 		{
 			p->type = pt_blob2;
-			p->color = 150 + rand()%6;
+			p->color = q1pal[150 + rand()%6];
 			for (j=0 ; j<3 ; j++)
 			{
 				p->org[j] = org[j] + ((rand()%32)-16);
@@ -268,7 +268,7 @@
 		if (count == 1024)
 		{	// rocket explosion
 			p->die = cl.time + 5;
-			p->color = ramp1[0];
+			p->color = q1pal[ramp1[0]];
 			p->ramp = rand()&3;
 			if (i & 1)
 			{
@@ -292,7 +292,7 @@
 		else
 		{
 			p->die = cl.time + 0.1*(rand()%5);
-			p->color = (color&~7) + (rand()&7);
+			p->color = q1pal[(color&~7) + (rand()&7)];
 			p->type = pt_slowgrav;
 			for (j=0 ; j<3 ; j++)
 			{
@@ -329,7 +329,7 @@
 				active_particles = p;
 
 				p->die = cl.time + 2 + (rand()&31) * 0.02;
-				p->color = 224 + (rand()&7);
+				p->color = q1pal[224 + (rand()&7)];
 				p->type = pt_slowgrav;
 
 				dir[0] = j*8 + (rand()&7);
@@ -371,7 +371,7 @@
 				active_particles = p;
 
 				p->die = cl.time + 0.2 + (rand()&7) * 0.02;
-				p->color = 7 + (rand()&7);
+				p->color = q1pal[7 + (rand()&7)];
 				p->type = pt_slowgrav;
 
 				dir[0] = j*8;
@@ -425,7 +425,7 @@
 		{
 			case 0:	// rocket trail
 				p->ramp = (rand()&3);
-				p->color = ramp3[(int)p->ramp];
+				p->color = q1pal[ramp3[(int)p->ramp]];
 				p->type = pt_fire;
 				for (j=0 ; j<3 ; j++)
 					p->org[j] = start[j] + ((rand()%6)-3);
@@ -433,7 +433,7 @@
 
 			case 1:	// smoke smoke
 				p->ramp = (rand()&3) + 2;
-				p->color = ramp3[(int)p->ramp];
+				p->color = q1pal[ramp3[(int)p->ramp]];
 				p->type = pt_fire;
 				for (j=0 ; j<3 ; j++)
 					p->org[j] = start[j] + ((rand()%6)-3);
@@ -441,7 +441,7 @@
 
 			case 2:	// blood
 				p->type = pt_grav;
-				p->color = 67 + (rand()&3);
+				p->color = q1pal[67 + (rand()&3)];
 				for (j=0 ; j<3 ; j++)
 					p->org[j] = start[j] + ((rand()%6)-3);
 				break;
@@ -451,9 +451,9 @@
 				p->die = cl.time + 0.5;
 				p->type = pt_static;
 				if (type == 3)
-					p->color = 52 + ((tracercount&4)<<1);
+					p->color = q1pal[52 + ((tracercount&4)<<1)];
 				else
-					p->color = 230 + ((tracercount&4)<<1);
+					p->color = q1pal[230 + ((tracercount&4)<<1)];
 
 				tracercount++;
 
@@ -472,7 +472,7 @@
 
 			case 4:	// slight blood
 				p->type = pt_grav;
-				p->color = 67 + (rand()&3);
+				p->color = q1pal[67 + (rand()&3)];
 				for (j=0 ; j<3 ; j++)
 					p->org[j] = start[j] + ((rand()%6)-3);
 				len -= 3;
@@ -479,7 +479,7 @@
 				break;
 
 			case 6:	// voor trail
-				p->color = 9*16 + 8 + (rand()&3);
+				p->color = q1pal[9*16 + 8 + (rand()&3)];
 				p->type = pt_static;
 				p->die = cl.time + 0.3;
 				for (j=0 ; j<3 ; j++)
@@ -562,7 +562,7 @@
 			if (p->ramp >= 6)
 				p->die = -1;
 			else
-				p->color = ramp3[(int)p->ramp];
+				p->color = q1pal[ramp3[(int)p->ramp]];
 			p->vel[2] += grav;
 			break;
 
@@ -571,7 +571,7 @@
 			if (p->ramp >=8)
 				p->die = -1;
 			else
-				p->color = ramp1[(int)p->ramp];
+				p->color = q1pal[ramp1[(int)p->ramp]];
 			for (i=0 ; i<3 ; i++)
 				p->vel[i] += p->vel[i]*dvel;
 			p->vel[2] -= grav;
@@ -582,7 +582,7 @@
 			if (p->ramp >=8)
 				p->die = -1;
 			else
-				p->color = ramp2[(int)p->ramp];
+				p->color = q1pal[ramp2[(int)p->ramp]];
 			for (i=0 ; i<3 ; i++)
 				p->vel[i] -= p->vel[i]*frametime;
 			p->vel[2] -= grav;
--- a/r_shared.h
+++ b/r_shared.h
@@ -71,7 +71,7 @@
 } surf_t;
 
 extern int r_numallocatedbasespans;
-extern byte *r_basespans;
+extern void *r_basespans;
 
 extern	surf_t	*surfaces, *surface_p, *surf_max;
 
--- a/r_sky.c
+++ b/r_sky.c
@@ -6,7 +6,7 @@
 
 float skyspeed, skytime;
 
-byte *r_skysource[2];
+pixel_t *r_skysource[2];
 
 static int r_skymade;
 int skyw, skyh;
@@ -19,15 +19,15 @@
 void R_InitSky (texture_t *mt)
 {
 	int x, y, w, n;
-	byte *src;
+	pixel_t *src;
 
-	src = (byte *)mt + mt->offsets[0];
+	src = (pixel_t*)((byte *)mt + mt->offsets[0]);
 	w = mt->width;
 	skyh = mt->height;
 	if(w == skyh){ // probably without a mask?
 		skyw = w;
 		n = skyw*skyh;
-		r_skysource[0] = Hunk_Alloc(n);
+		r_skysource[0] = Hunk_Alloc(n*sizeof(pixel_t));
 		r_skysource[1] = r_skysource[0];
 		memmove(r_skysource[0], src, n);
 		return;
@@ -34,7 +34,7 @@
 	}
 	skyw = w/2;
 	n = skyw*skyh;
-	r_skysource[0] = Hunk_Alloc(n*2);
+	r_skysource[0] = Hunk_Alloc(n*sizeof(pixel_t)*2);
 	r_skysource[1] = r_skysource[0] + n;
 	for(y=0 ; y<skyh; y++){
 		for(x=0 ; x<skyw; x++){
--- a/r_surf.c
+++ b/r_surf.c
@@ -6,10 +6,10 @@
 static int surfrowbytes;	// used by ASM files
 static int r_stepback;
 static int r_numhblocks, r_numvblocks;
-static byte *r_source, *r_sourcemax;
+static pixel_t *r_source, *r_sourcemax;
 static unsigned *r_lightptr;
 static int r_lightwidth;
-static byte *pbasesource;
+static pixel_t *pbasesource;
 static void *prowdestbase;
 
 static void R_DrawSurfaceBlock8_mip0 (void);
@@ -204,12 +204,12 @@
 */
 void R_DrawSurface (void)
 {
-	unsigned char	*basetptr;
+	pixel_t	*basetptr;
 	int				smax, tmax, twidth;
 	int				u, blockdivshift, blocksize;
 	int				soffset, basetoffset, texwidth;
 	int				horzblockstep;
-	unsigned char	*pcolumndest;
+	pixel_t	*pcolumndest;
 	void			(*pblockdrawer)(void);
 	texture_t		*mt;
 
@@ -220,7 +220,7 @@
 
 	mt = r_drawsurf.texture;
 
-	r_source = (byte *)mt + mt->offsets[r_drawsurf.surfmip];
+	r_source = (pixel_t*)((byte*)mt + mt->offsets[r_drawsurf.surfmip]);
 
 	// the fractional light values should range from 0 to (VID_GRADES - 1) << 16
 	// from a source range of 0 - 255
@@ -286,7 +286,7 @@
 static void R_DrawSurfaceBlock8_mip0 (void)
 {
 	int				v, i, lightstep, lighttemp, light, lightleft, lightright;
-	unsigned char	*psource, *prowdest;
+	pixel_t	*psource, *prowdest;
 
 	psource = pbasesource;
 	prowdest = prowdestbase;
@@ -307,22 +307,22 @@
 
 			light = lightright;
 
-			prowdest[15] = vid.colormap[((light += lightstep) & 0xFF00) + psource[15]];
-			prowdest[14] = vid.colormap[((light += lightstep) & 0xFF00) + psource[14]];
-			prowdest[13] = vid.colormap[((light += lightstep) & 0xFF00) + psource[13]];
-			prowdest[12] = vid.colormap[((light += lightstep) & 0xFF00) + psource[12]];
-			prowdest[11] = vid.colormap[((light += lightstep) & 0xFF00) + psource[11]];
-			prowdest[10] = vid.colormap[((light += lightstep) & 0xFF00) + psource[10]];
-			prowdest[9] = vid.colormap[((light += lightstep) & 0xFF00) + psource[9]];
-			prowdest[8] = vid.colormap[((light += lightstep) & 0xFF00) + psource[8]];
-			prowdest[7] = vid.colormap[((light += lightstep) & 0xFF00) + psource[7]];
-			prowdest[6] = vid.colormap[((light += lightstep) & 0xFF00) + psource[6]];
-			prowdest[5] = vid.colormap[((light += lightstep) & 0xFF00) + psource[5]];
-			prowdest[4] = vid.colormap[((light += lightstep) & 0xFF00) + psource[4]];
-			prowdest[3] = vid.colormap[((light += lightstep) & 0xFF00) + psource[3]];
-			prowdest[2] = vid.colormap[((light += lightstep) & 0xFF00) + psource[2]];
-			prowdest[1] = vid.colormap[((light += lightstep) & 0xFF00) + psource[1]];
-			prowdest[0] = vid.colormap[(light & 0xFF00) + psource[0]];
+			prowdest[15] = vid.colormap[((light += lightstep) & 0xFF00) + CIND(psource[15])];
+			prowdest[14] = vid.colormap[((light += lightstep) & 0xFF00) + CIND(psource[14])];
+			prowdest[13] = vid.colormap[((light += lightstep) & 0xFF00) + CIND(psource[13])];
+			prowdest[12] = vid.colormap[((light += lightstep) & 0xFF00) + CIND(psource[12])];
+			prowdest[11] = vid.colormap[((light += lightstep) & 0xFF00) + CIND(psource[11])];
+			prowdest[10] = vid.colormap[((light += lightstep) & 0xFF00) + CIND(psource[10])];
+			prowdest[9] = vid.colormap[((light += lightstep) & 0xFF00) + CIND(psource[9])];
+			prowdest[8] = vid.colormap[((light += lightstep) & 0xFF00) + CIND(psource[8])];
+			prowdest[7] = vid.colormap[((light += lightstep) & 0xFF00) + CIND(psource[7])];
+			prowdest[6] = vid.colormap[((light += lightstep) & 0xFF00) + CIND(psource[6])];
+			prowdest[5] = vid.colormap[((light += lightstep) & 0xFF00) + CIND(psource[5])];
+			prowdest[4] = vid.colormap[((light += lightstep) & 0xFF00) + CIND(psource[4])];
+			prowdest[3] = vid.colormap[((light += lightstep) & 0xFF00) + CIND(psource[3])];
+			prowdest[2] = vid.colormap[((light += lightstep) & 0xFF00) + CIND(psource[2])];
+			prowdest[1] = vid.colormap[((light += lightstep) & 0xFF00) + CIND(psource[1])];
+			prowdest[0] = vid.colormap[(light & 0xFF00) + CIND(psource[0])];
 
 			psource += sourcetstep;
 			lightright += lightrightstep;
@@ -344,7 +344,7 @@
 static void R_DrawSurfaceBlock8_mip1 (void)
 {
 	int				v, i, b, lightstep, lighttemp, light, lightleft, lightright;
-	unsigned char	pix, *psource, *prowdest;
+	pixel_t	pix, *psource, *prowdest;
 
 	psource = pbasesource;
 	prowdest = prowdestbase;
@@ -368,8 +368,7 @@
 			for (b=7; b>=0; b--)
 			{
 				pix = psource[b];
-				prowdest[b] = ((unsigned char *)vid.colormap)
-						[(light & 0xFF00) + pix];
+				prowdest[b] = vid.colormap[(light & 0xFF00) + CIND(pix)];
 				light += lightstep;
 			}
 
@@ -392,8 +391,8 @@
 */
 static void R_DrawSurfaceBlock8_mip2 (void)
 {
-	int				v, i, b, lightstep, lighttemp, light, lightleft, lightright;
-	unsigned char	pix, *psource, *prowdest;
+	int v, i, b, lightstep, lighttemp, light, lightleft, lightright;
+	pixel_t pix, *psource, *prowdest;
 
 	psource = pbasesource;
 	prowdest = prowdestbase;
@@ -417,8 +416,7 @@
 			for (b=3; b>=0; b--)
 			{
 				pix = psource[b];
-				prowdest[b] = ((unsigned char *)vid.colormap)
-						[(light & 0xFF00) + pix];
+				prowdest[b] = vid.colormap[(light & 0xFF00) + CIND(pix)];
 				light += lightstep;
 			}
 
@@ -441,8 +439,8 @@
 */
 static void R_DrawSurfaceBlock8_mip3 (void)
 {
-	int				v, i, b, lightstep, lighttemp, light, lightleft, lightright;
-	unsigned char	pix, *psource, *prowdest;
+	int v, i, b, lightstep, lighttemp, light, lightleft, lightright;
+	pixel_t pix, *psource, *prowdest;
 
 	psource = pbasesource;
 	prowdest = prowdestbase;
@@ -466,8 +464,7 @@
 			for (b=1; b>=0; b--)
 			{
 				pix = psource[b];
-				prowdest[b] = ((unsigned char *)vid.colormap)
-						[(light & 0xFF00) + pix];
+				prowdest[b] = vid.colormap[(light & 0xFF00) + CIND(pix)];
 				light += lightstep;
 			}
 
--- a/render.h
+++ b/render.h
@@ -33,7 +33,7 @@
 	struct efrag_s			*efrag;			// linked list of efrags
 	int						frame;
 	float					syncbase;		// for client-side animations
-	byte					*colormap;
+	pixel_t					*colormap;
 	int						effects;		// light, particals, etc
 	int						skinnum;		// for Alias models
 	int						visframe;		// last frame this entity was
--- a/sbar.c
+++ b/sbar.c
@@ -695,8 +695,8 @@
 		top = Sbar_ColorForMap (top);
 		bottom = Sbar_ColorForMap (bottom);
 
-		Draw_Fill (xofs + x*8 + 10, y, 28, 4, top);
-		Draw_Fill (xofs + x*8 + 10, y+4, 28, 3, bottom);
+		Draw_Fill (xofs + x*8 + 10, y, 28, 4, q1pal[top]);
+		Draw_Fill (xofs + x*8 + 10, y+4, 28, 3, q1pal[bottom]);
 
 		// draw number
 		f = s->frags;
@@ -752,8 +752,8 @@
 			xofs = ((vid.width - 320)>>1) + 113;
 
 		Sbar_DrawPic (112, 0, rsb_teambord);
-		Draw_Fill (xofs, vid.height-SBAR_HEIGHT+3, 22, 9, top);
-		Draw_Fill (xofs, vid.height-SBAR_HEIGHT+12, 22, 9, bottom);
+		Draw_Fill (xofs, vid.height-SBAR_HEIGHT+3, 22, 9, q1pal[top]);
+		Draw_Fill (xofs, vid.height-SBAR_HEIGHT+12, 22, 9, q1pal[bottom]);
 
 		// draw number
 		f = s->frags;
@@ -1014,8 +1014,8 @@
 		top = Sbar_ColorForMap (top);
 		bottom = Sbar_ColorForMap (bottom);
 
-		Draw_Fill ( x, y, 40, 4, top);
-		Draw_Fill ( x, y+4, 40, 4, bottom);
+		Draw_Fill ( x, y, 40, 4, q1pal[top]);
+		Draw_Fill ( x, y+4, 40, 4, q1pal[bottom]);
 
 		// draw number
 		f = s->frags;
@@ -1111,8 +1111,8 @@
 		top = Sbar_ColorForMap (top);
 		bottom = Sbar_ColorForMap (bottom);
 
-		Draw_Fill ( x, y+1, 40, 3, top);
-		Draw_Fill ( x, y+4, 40, 4, bottom);
+		Draw_Fill ( x, y+1, 40, 3, q1pal[top]);
+		Draw_Fill ( x, y+4, 40, 4, q1pal[bottom]);
 
 		// draw number
 		f = s->frags;
--- a/span.c
+++ b/span.c
@@ -1,7 +1,7 @@
 #include "quakedef.h"
 
 void
-dospan(byte *pdest, byte *pbase, int s, int t, int sstep, int tstep, int spancount, int cachewidth)
+dospan(pixel_t *pdest, pixel_t *pbase, int s, int t, int sstep, int tstep, int spancount, int cachewidth)
 {
 	do{
 		*pdest++ = pbase[(s >> 16) + (t >> 16) * cachewidth];
--- a/span_alpha.c
+++ b/span_alpha.c
@@ -1,14 +1,14 @@
 #include "quakedef.h"
 
 void
-dospan_alpha(byte *pdest, byte *pbase, int s, int t, int sstep, int tstep, int spancount, int cachewidth, u8int alpha, uzint *pz, int izi, int izistep)
+dospan_alpha(pixel_t *pdest, pixel_t *pbase, int s, int t, int sstep, int tstep, int spancount, int cachewidth, u8int alpha, uzint *pz, int izi, int izistep)
 {
-	uchar pix;
+	pixel_t pix;
 
 	if(alpha != 255){
 		do{
 			pix = pbase[(s >> 16) + (t >> 16) * cachewidth];
-			if(pix != 255 && *pz <= (izi >> 16))
+			if(opaque(pix) && *pz <= (izi >> 16))
 				*pdest = blendalpha(pix, *pdest, alpha);
 			pdest++;
 			pz++;
@@ -19,7 +19,7 @@
 	}else{
 		do{
 			pix = pbase[(s >> 16) + (t >> 16) * cachewidth];
-			if(pix != 255 && *pz <= (izi >> 16)){
+			if(opaque(pix) && *pz <= (izi >> 16)){
 				*pdest = pix;
 				*pz = izi >> 16;
 			}
--- a/span_arm64.s
+++ b/span_arm64.s
@@ -13,9 +13,9 @@
 	SUBW $1, R6
 	MADDW R7, R9, R8, R8
 	ADDW R5, R3
-	MOVBU (R1)[R8], R10
+	MOVW (R1)[R8], R10
 	ADDW R4, R2
-	MOVBU R10, 1(R0)!
+	MOVW R10, 4(R0)!
 	LSRW $16, R3, R9
 	LSRW $16, R2, R8
 	CBNZ R6, _l
--- a/unix/u.h
+++ b/unix/u.h
@@ -37,6 +37,7 @@
 #define getcallerpc(x) nil
 #define getmalloctag(p) (USED(p), 0)
 #define setmalloctag(p, t) do{USED(p); USED(t);}while(0)
+#define setrealloctag(p, t) do{USED(p); USED(t);}while(0)
 
 extern char lasterr[256];
 #define werrstr(fmt...) do{snprint(lasterr, sizeof(lasterr), fmt); }while(0)
--- a/unix/vid.c
+++ b/unix/vid.c
@@ -6,12 +6,11 @@
 static SDL_Renderer *rend;
 static SDL_Texture *fbi;
 static SDL_Window *win;
-static u8int *vidbuffer;
+static pixel_t *vidbuffer;
 
 s32int fbpal[256];
+pixel_t q1pal[256];
 
-void pal2xrgb(int n, s32int *pal, u8int *s, u32int *d);
-
 static void
 resetfb(void)
 {
@@ -34,11 +33,11 @@
 	vid.conheight = vid.height;
 
 	free(vidbuffer);
-	vidbuffer = emalloc(vid.width*vid.height+16);
+	vidbuffer = emalloc((vid.width*vid.height+16)*4);
 
 	if(fbi != nil)
 		SDL_DestroyTexture(fbi);
-	fbi = SDL_CreateTexture(rend, SDL_PIXELFORMAT_XRGB8888, SDL_TEXTUREACCESS_STREAMING, vid.width, vid.height);
+	fbi = SDL_CreateTexture(rend, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_STREAMING, vid.width, vid.height);
 	if(fbi == NULL)
 		fatal("SDL_CreateTexture: %s", SDL_GetError());
 	SDL_SetTextureBlendMode(fbi, SDL_BLENDMODE_NONE);
@@ -58,7 +57,7 @@
 	scachesz = D_SurfaceCacheForRes(vid.width, vid.height);
 	hunkvbuf += scachesz;
 	d_pzbuffer = emalloc(hunkvbuf);
-	surfcache = (byte *)d_pzbuffer + vid.width * vid.height * sizeof *d_pzbuffer;
+	surfcache = (byte *)(d_pzbuffer + vid.width * vid.height);
 	D_InitCaches(surfcache, scachesz);
 }
 
@@ -84,7 +83,7 @@
 	}
 
 	SDL_LockTexture(fbi, NULL, &p, &pitch);
-	pal2xrgb(vid.width*vid.height, fbpal, vidbuffer, p);
+	memmove(p, vidbuffer, vid.width*vid.height*4);
 	SDL_UnlockTexture(fbi);
 	SDL_RenderCopy(rend, fbi, NULL, NULL);
 	SDL_RenderPresent(rend);
@@ -91,14 +90,16 @@
 }
 
 void
-setpal(uchar *p)
+setpal(uchar *p0)
 {
-	int *fp;
+	int *fp, x;
+	uchar *p;
 
-	for(fp=fbpal; fp<fbpal+nelem(fbpal); p+=3, fp++)
+	for(p = p0, fp=fbpal; fp<fbpal+nelem(fbpal); p+=3, fp++)
 		*fp = p[0] << 16 | p[1] << 8 | p[2];
 
-	initalpha();
+	for(p = p0, x = 0; x < 256; x++, p += 3)
+		q1pal[x] = x<<24 | p[0]<<16 | p[1]<<8 | p[2];
 
 	scr_fullupdate = 0;
 }
@@ -109,7 +110,8 @@
 	vid.maxwarpwidth = WARP_WIDTH;
 	vid.maxwarpheight = WARP_HEIGHT;
 	vid.numpages = 2;
-	vid.colormap = host_colormap;
+	vid.colormap = malloc(256*64*sizeof(pixel_t));
+	torgbx(host_colormap, vid.colormap, 256*64);
 	vid.fullbright = 256 - LittleLong(*((int *)vid.colormap + 2048));
 
 	if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) < 0)
--- a/vid.c
+++ b/vid.c
@@ -8,10 +8,10 @@
 Rectangle grabr;
 
 s32int fbpal[256];
-static uchar *fbs;
+pixel_t q1pal[256];
 static Image *fbi;
 static Rectangle fbr;
-static u8int *vidbuffers[2];
+static pixel_t *vidbuffers[2];
 static int bufi = 0;
 static Channel *frame;
 
@@ -43,7 +43,7 @@
 	hunkvbuf += scachesz;
 	if((d_pzbuffer = realloc(d_pzbuffer, hunkvbuf)) == nil)
 		sysfatal("%r");
-	surfcache = (byte *)d_pzbuffer + vid.width * vid.height * sizeof *d_pzbuffer;
+	surfcache = (byte*)(d_pzbuffer + vid.width * vid.height);
 	D_InitCaches(surfcache, scachesz);
 
 	vid.rowbytes = vid.width;
@@ -58,7 +58,7 @@
 	p = Pt(vid.width/4, vid.height/4);
 	grabr = Rpt(subpt(center, p), addpt(center, p));
 	for(i = 0; i < nelem(vidbuffers); i++)
-		vidbuffers[i] = realloc(vidbuffers[i], vid.width*vid.height+16);
+		vidbuffers[i] = realloc(vidbuffers[i], (vid.width*vid.height+16)*sizeof(pixel_t));
 	freeimage(fbi);
 	fbi = allocimage(display, Rect(0, 0, vid.width, vid.height), XRGB32, 0, 0);
 	if(fbi == nil)
@@ -69,26 +69,23 @@
 }
 
 static void
-loader(void *p)
+loader(void *)
 {
-	u8int *f, *fb;
+	byte *f;
 	Rectangle r;
 	int n;
 
-	fb = p;
 	r = Rect(0, 0, vid.width, vid.height);
 	n = vid.width * vid.height;
 	for(;;){
 		if((f = recvp(frame)) == nil)
 			break;
-		pal2xrgb(n, fbpal, f, (u32int*)fb);
-		if(loadimage(fbi, r, fb, n*4) != n*4)
+		if(loadimage(fbi, r, f, n*4) != n*4)
 			sysfatal("%r");
 		draw(screen, fbr, fbi, nil, ZP);
 		if(flushimage(display, 1) < 0)
 			sysfatal("%r");
 	}
-	free(fb);
 	threadexits(nil);
 }
 
@@ -117,8 +114,8 @@
 		return;
 	}
 	if(frame == nil){
-		frame = chancreate(sizeof(u8int*), 0);
-		proccreate(loader, mallocalign(vid.width*vid.height*4+16, 64, 0, 0), 4096);
+		frame = chancreate(sizeof(pixel_t*), 0);
+		proccreate(loader, nil, 4096);
 	}
 	if(sendp(frame, vidbuffers[bufi]) > 0){
 		bufi = (bufi+1) % nelem(vidbuffers);
@@ -128,14 +125,16 @@
 }
 
 void
-setpal(uchar *p)
+setpal(uchar *p0)
 {
-	int *fp;
+	int *fp, x;
+	uchar *p;
 
-	for(fp=fbpal; fp<fbpal+nelem(fbpal); p+=3, fp++)
+	for(p = p0, fp=fbpal; fp<fbpal+nelem(fbpal); p+=3, fp++)
 		*fp = p[0] << 16 | p[1] << 8 | p[2];
 
-	initalpha();
+	for(p = p0, x = 0; x < 256; x++, p += 3)
+		q1pal[x] = x<<24 | p[0]<<16 | p[1]<<8 | p[2];
 
 	scr_fullupdate = 0;
 }
@@ -146,7 +145,8 @@
 	vid.maxwarpwidth = WARP_WIDTH;
 	vid.maxwarpheight = WARP_HEIGHT;
 	vid.numpages = 2;
-	vid.colormap = host_colormap;
+	vid.colormap = malloc(256*64*sizeof(pixel_t));
+	torgbx(host_colormap, vid.colormap, 256*64);
 	vid.fullbright = 256 - LittleLong(*((int *)vid.colormap + 2048));
 	if(initdraw(nil, nil, "quake") < 0)
 		sysfatal("initdraw: %r\n");
--- a/vid.h
+++ b/vid.h
@@ -3,8 +3,7 @@
 #define VID_CBITS	6
 #define VID_GRADES	(1 << VID_CBITS)
 
-// a pixel can be one, two, or four bytes
-typedef byte pixel_t;
+typedef u32int pixel_t;
 
 typedef struct vrect_s
 {
@@ -16,7 +15,6 @@
 {
 	pixel_t			*buffer;		// invisible buffer
 	pixel_t			*colormap;		// 256 * VID_GRADES size
-	unsigned short	*colormap16;	// 256 * VID_GRADES size
 	int				fullbright;		// index of first fullbright color
 	unsigned		rowbytes;	// may be > width if displayed in a window
 	int				width;
@@ -30,8 +28,6 @@
 	unsigned		conheight;
 	int				maxwarpwidth;
 	int				maxwarpheight;
-	pixel_t			*direct;		// direct drawing to framebuffer, if not
-									//  NULL
 } viddef_t;
 
 extern	viddef_t	vid;				// global video state
--- a/wad.h
+++ b/wad.h
@@ -17,11 +17,9 @@
 
 typedef struct
 {
-	int			width, height;
-	byte		data[4];			// variably sized
+	int width, height;
+	pixel_t data[]; // variably sized
 } qpic_t;
-
-
 
 typedef struct
 {
--- a/zone.c
+++ b/zone.c
@@ -41,6 +41,7 @@
 	}
 	assert(n != nil && (void*)(n+1) == p);
 	data = Cache_Alloc(c, size);
+	setmalloctag((mem_t*)data-1, getcallerpc(&c));
 
 	hunk_head = n->next;
 	if(hunk_head != nil)
@@ -62,6 +63,7 @@
 	m = calloc(1, sizeof(*m) + size);
 	if(m == nil)
 		fatal("Hunk_Alloc: size=%d: %s", size, lerr());
+	setmalloctag(m, getcallerpc(&size));
 	m->size = size;
 	m->next = hunk_head;
 	if(hunk_head != nil)
@@ -75,11 +77,9 @@
 Hunk_Double(void *p)
 {
 	mem_t *m, *n;
-	ulong t;
 
 	m = p;
 	m--;
-	t = getmalloctag(m);
 	n = realloc(m, sizeof(*m) + m->size*2);
 	if(m == nil)
 		fatal("Hunk_Double: %s", lerr());
@@ -86,7 +86,7 @@
 	if(hunk_head == m)
 		hunk_head = n;
 	m = n;
-	setmalloctag(m, t);
+	setrealloctag(m, getcallerpc(&p));
 	memset((byte*)(m+1) + m->size, 0, m->size);
 	m->size *= 2;
 	if(m->prev != nil)
@@ -125,6 +125,7 @@
 		buf = realloc(buf, size);
 		if(buf == nil)
 			fatal("Hunk_TempAlloc: %s", lerr());
+		setmalloctag(buf, getcallerpc(&size));
 		bufsz = size;
 	}
 	memset(buf, 0, size);
@@ -175,7 +176,7 @@
 {
 	mem_t *cs;
 
-	if(c->data)
+	if(c->data != nil)
 		fatal("Cache_Alloc: already allocated");
 	if(size <= 0)
 		fatal("Cache_Alloc: size %d", size);
@@ -183,13 +184,45 @@
 	cs = calloc(1, sizeof(*cs) + size);
 	if(cs == nil)
 		fatal("Cache_Alloc: %s", lerr());
+	setmalloctag(cs, getcallerpc(&c));
 	cs->size = size;
 	cs->next = cache_head;
 	if(cache_head != nil)
 		cache_head->prev = cs;
 	cache_head = cs;
+	cs->user = c;
 	c->data = cs+1;
+
+	return c->data;
+}
+
+void *
+Cache_Realloc(mem_user_t *c, int size)
+{
+	mem_t *cs, *o;
+
+	if(c->data == nil)
+		return Cache_Alloc(c, size);
+	if(size <= 0)
+		fatal("Cache_Alloc: size %d", size);
+
+	cs = (mem_t *)c->data - 1;
+	o = cs;
+	cs = realloc(cs, sizeof(*cs) + size);
+	if(cs == nil)
+		fatal("Cache_Realloc: %s", lerr());
+	if(cache_head == o)
+		cache_head = cs;
+	if(cs->prev != nil)
+		cs->prev->next = cs;
+	if(cs->next != nil)
+		cs->next->prev = cs;
+	setrealloctag(cs, getcallerpc(&c));
+	if(size > cs->size)
+		memset((byte*)(cs+1) + cs->size, 0, size - cs->size);
+	cs->size = size;
 	cs->user = c;
+	c->data = cs+1;
 
 	return c->data;
 }
--- a/zone.h
+++ b/zone.h
@@ -15,6 +15,7 @@
 void *Hunk_TempAlloc(int size);
 
 void *Cache_Alloc(mem_user_t *c, int size);
+void *Cache_Realloc(mem_user_t *c, int size);
 void *Cache_Check(mem_user_t *c);
 void Cache_Free(mem_user_t *c);