From: havoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Date: Sun, 25 Aug 2002 15:45:41 +0000 (+0000)
Subject: got rid of R_Mesh_Draw and R_Mesh_DrawPolygon, now all 3D geometry is drawn using... 
X-Git-Tag: RELEASE_0_2_0_RC1~310
X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=90fa50f4e170192cce8b5b3321fbf7c4d9be7a41;p=xonotic%2Fdarkplaces.git

got rid of R_Mesh_Draw and R_Mesh_DrawPolygon, now all 3D geometry is drawn using R_Mesh_Draw_GetBuffer and R_Mesh_Render


git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@2285 d7cf8633-e32d-0410-b094-e92efae38249
---

diff --git a/gl_backend.c b/gl_backend.c
index 1dff96e7..0c7c3150 100644
--- a/gl_backend.c
+++ b/gl_backend.c
@@ -70,8 +70,6 @@ void GL_PrintError(int errornumber, char *filename, int linenumber)
 
 float r_mesh_farclip;
 
-int polyindexarray[768];
-
 static float viewdist;
 // sign bits (true if negative) for vpn[] entries, so quick integer compares can be used instead of float compares
 static int vpnbit0, vpnbit1, vpnbit2;
@@ -293,8 +291,6 @@ static void gl_backend_newmap(void)
 
 void gl_backend_init(void)
 {
-	int i;
-
 	Cvar_RegisterVariable(&r_render);
 	Cvar_RegisterVariable(&gl_dither);
 	Cvar_RegisterVariable(&gl_lockarrays);
@@ -308,12 +304,6 @@ void gl_backend_init(void)
 	Cvar_RegisterVariable(&gl_mesh_drawmode);
 	R_RegisterModule("GL_Backend", gl_backend_start, gl_backend_shutdown, gl_backend_newmap);
 	gl_backend_bufferchanges(true);
-	for (i = 0;i < 256;i++)
-	{
-		polyindexarray[i*3+0] = 0;
-		polyindexarray[i*3+1] = i + 1;
-		polyindexarray[i*3+2] = i + 2;
-	}
 }
 
 int arraylocked = false;
@@ -1000,219 +990,6 @@ void R_Mesh_AddTransparent(void)
 	currenttransvertex = 0;
 }
 
-void R_Mesh_Draw(const rmeshinfo_t *m)
-{
-	// these are static because gcc runs out of virtual registers otherwise
-	static int i, j, overbright, *index;
-	static float *in, scaler;
-	static float cr, cg, cb, ca;
-	static buf_mesh_t *mesh;
-	static buf_vertex_t *vert;
-	static buf_fcolor_t *fcolor;
-	static buf_texcoord_t *texcoord[MAX_TEXTUREUNITS];
-
-	if (!backendactive)
-		Sys_Error("R_Mesh_Draw: called when backend is not active\n");
-
-	if (m->index == NULL
-	 || !m->numtriangles
-	 || m->vertex == NULL
-	 || !m->numverts)
-		Host_Error("R_Mesh_Draw: no triangles or verts\n");
-
-	// ignore meaningless alpha meshs
-	if (!m->depthwrite && m->blendfunc1 == GL_SRC_ALPHA && (m->blendfunc2 == GL_ONE || m->blendfunc2 == GL_ONE_MINUS_SRC_ALPHA))
-	{
-		if (m->color)
-		{
-			for (i = 0, in = m->color + 3;i < m->numverts;i++, (int)in += m->colorstep)
-				if (*in >= 0.01f)
-					break;
-			if (i == m->numverts)
-				return;
-		}
-		else if (m->ca < 0.01f)
-			return;
-	}
-
-	if (!backendactive)
-		Sys_Error("R_Mesh_Draw: called when backend is not active\n");
-
-#ifdef DEBUGGL
-	for (i = 0;i < m->numtriangles * 3;i++)
-		if ((unsigned int) m->index[i] >= (unsigned int) m->numverts)
-			Host_Error("R_Mesh_Draw: invalid index (%i of %i verts)\n", m->index, m->numverts);
-#endif
-
-	// LordHavoc: removed this error condition because with floatcolors 0,
-	// the 3DFX driver works with very large meshs
-	// FIXME: we can work around this by falling back on non-array renderer if buffers are too big
-	//if (m->numtriangles > 1024 || m->numverts > 3072)
-	//{
-	//	Con_Printf("R_Mesh_Draw: mesh too big for 3DFX drivers, rejected\n");
-	//	return;
-	//}
-
-	i = max(m->numtriangles * 3, m->numverts);
-	if (overflowedverts < i)
-		overflowedverts = i;
-
-	if (m->numtriangles > max_meshs || m->numverts > max_verts)
-	{
-		Con_Printf("R_Mesh_Draw: mesh too big for current gl_mesh_maxtriangles setting, increasing limits\n");
-		return;
-	}
-
-	if (m->transparent)
-	{
-		overflowedtransverts += max(m->numtriangles * 3, m->numverts);
-		if (currenttransmesh >= max_transmeshs || (currenttranstriangle + m->numtriangles) > max_transmeshs || (currenttransvertex + m->numverts) > max_transverts)
-		{
-			if (!transranout)
-			{
-				Con_Printf("R_Mesh_Draw: ran out of room for transparent meshs\n");
-				transranout = true;
-			}
-			return;
-		}
-
-		c_transmeshs++;
-		c_transtris += m->numtriangles;
-		vert = &buf_transvertex[currenttransvertex];
-		fcolor = &buf_transfcolor[currenttransvertex];
-		for (i = 0;i < backendunits;i++)
-			texcoord[i] = &buf_transtexcoord[i][currenttransvertex];
-
-		// transmesh is only for storage of transparent meshs until they
-		// are inserted into the main mesh array
-		mesh = &buf_transmesh[currenttransmesh++];
-		mesh->firsttriangle = currenttranstriangle;
-		mesh->firstvert = currenttransvertex;
-		index = &buf_transtri[currenttranstriangle].index[0];
-
-		currenttranstriangle += m->numtriangles;
-		currenttransvertex += m->numverts;
-	}
-	else
-	{
-		if (currentmesh)
-		{
-			R_Mesh_Render();
-			Con_Printf("mesh queue not empty, flushing.\n");
-		}
-
-		c_meshs++;
-		c_meshtris += m->numtriangles;
-		vert = &buf_vertex[currentvertex];
-		fcolor = &buf_fcolor[currentvertex];
-		for (i = 0;i < backendunits;i++)
-			texcoord[i] = &buf_texcoord[i][currentvertex];
-
-		// opaque meshs are rendered directly
-		mesh = &buf_mesh[currentmesh++];
-		mesh->firsttriangle = currenttriangle;
-		mesh->firstvert = currentvertex;
-		index = &buf_tri[currenttriangle].index[0];
-
-		currenttriangle += m->numtriangles;
-		currentvertex += m->numverts;
-	}
-
-	// code shared for transparent and opaque meshs
-	memcpy(index, m->index, sizeof(int[3]) * m->numtriangles);
-	mesh->blendfunc1 = m->blendfunc1;
-	mesh->blendfunc2 = m->blendfunc2;
-	mesh->depthmask = (m->blendfunc2 == GL_ZERO || m->depthwrite);
-	mesh->depthtest = !m->depthdisable;
-	mesh->triangles = m->numtriangles;
-	mesh->verts = m->numverts;
-
-	overbright = false;
-	scaler = 1;
-	if (m->blendfunc1 == GL_DST_COLOR)
-	{
-		// check if it is a 2x modulate with framebuffer
-		if (m->blendfunc2 == GL_SRC_COLOR)
-			scaler *= 0.5f;
-	}
-	else if (m->blendfunc2 != GL_SRC_COLOR)
-	{
-		if (m->tex[0])
-		{
-			overbright = gl_combine.integer;
-			if (overbright)
-				scaler *= 0.25f;
-		}
-		scaler *= overbrightscale;
-	}
-
-
-	j = -1;
-	for (i = 0;i < backendunits;i++)
-	{
-		if ((mesh->textures[i] = m->tex[i]))
-			j = i;
-		mesh->texturergbscale[i] = m->texrgbscale[i];
-		if (mesh->texturergbscale[i] != 1 && mesh->texturergbscale[i] != 2 && mesh->texturergbscale[i] != 4)
-			mesh->texturergbscale[i] = 1;
-	}
-	if (overbright && j >= 0)
-		mesh->texturergbscale[j] = 4;
-
-	if (m->vertexstep != sizeof(buf_vertex_t))
-	{
-		for (i = 0, in = m->vertex;i < m->numverts;i++, (int)in += m->vertexstep)
-		{
-			vert[i].v[0] = in[0];
-			vert[i].v[1] = in[1];
-			vert[i].v[2] = in[2];
-		}
-	}
-	else
-		memcpy(vert, m->vertex, m->numverts * sizeof(buf_vertex_t));
-
-	if (m->color)
-	{
-		for (i = 0, in = m->color;i < m->numverts;i++, (int)in += m->colorstep)
-		{
-			fcolor[i].c[0] = in[0] * scaler;
-			fcolor[i].c[1] = in[1] * scaler;
-			fcolor[i].c[2] = in[2] * scaler;
-			fcolor[i].c[3] = in[3];
-		}
-	}
-	else
-	{
-		cr = m->cr * scaler;
-		cg = m->cg * scaler;
-		cb = m->cb * scaler;
-		ca = m->ca;
-		for (i = 0;i < m->numverts;i++)
-		{
-			fcolor[i].c[0] = cr;
-			fcolor[i].c[1] = cg;
-			fcolor[i].c[2] = cb;
-			fcolor[i].c[3] = ca;
-		}
-	}
-
-	for (j = 0;j < MAX_TEXTUREUNITS && m->tex[j];j++)
-	{
-		if (j >= backendunits)
-			Sys_Error("R_Mesh_Draw: texture %i supplied when there are only %i texture units\n", j + 1, backendunits);
-		if (m->texcoordstep[j] != sizeof(buf_texcoord_t))
-		{
-			for (i = 0, in = m->texcoords[j];i < m->numverts;i++, (int)in += m->texcoordstep[j])
-			{
-				texcoord[j][i].t[0] = in[0];
-				texcoord[j][i].t[1] = in[1];
-			}
-		}
-		else
-			memcpy(&texcoord[j][0].t[0], m->texcoords[j], m->numverts * sizeof(buf_texcoord_t));
-	}
-}
-
 // allocates space in geometry buffers, and fills in pointers to the buffers in passsed struct
 // (this is used for very high speed rendering, no copying)
 int R_Mesh_Draw_GetBuffer(rmeshbufferinfo_t *m, int wantoverbright)
@@ -1223,11 +1000,11 @@ int R_Mesh_Draw_GetBuffer(rmeshbufferinfo_t *m, int wantoverbright)
 	buf_mesh_t *mesh;
 
 	if (!backendactive)
-		Sys_Error("R_Mesh_Draw: called when backend is not active\n");
+		Sys_Error("R_Mesh_Draw_GetBuffer: called when backend is not active\n");
 
 	if (!m->numtriangles
 	 || !m->numverts)
-		Host_Error("R_Mesh_Draw: no triangles or verts\n");
+		Host_Error("R_Mesh_Draw_GetBuffer: no triangles or verts\n");
 
 	// LordHavoc: removed this error condition because with floatcolors 0,
 	// the 3DFX driver works with very large meshs
@@ -1255,7 +1032,7 @@ int R_Mesh_Draw_GetBuffer(rmeshbufferinfo_t *m, int wantoverbright)
 		{
 			if (!transranout)
 			{
-				Con_Printf("R_Mesh_Draw: ran out of room for transparent meshs\n");
+				Con_Printf("R_Mesh_Draw_GetBuffer: ran out of room for transparent meshs\n");
 				transranout = true;
 			}
 			return false;
@@ -1348,24 +1125,6 @@ int R_Mesh_Draw_GetBuffer(rmeshbufferinfo_t *m, int wantoverbright)
 	return true;
 }
 
-void R_Mesh_DrawPolygon(rmeshinfo_t *m, int numverts)
-{
-	m->index = polyindexarray;
-	m->numverts = numverts;
-	m->numtriangles = numverts - 2;
-	if (m->numtriangles < 1)
-	{
-		Con_Printf("R_Mesh_DrawPolygon: invalid vertex count\n");
-		return;
-	}
-	if (m->numtriangles >= 256)
-	{
-		Con_Printf("R_Mesh_DrawPolygon: only up to 256 triangles (258 verts) supported\n");
-		return;
-	}
-	R_Mesh_Draw(m);
-}
-
 /*
 ==============================================================================
 
diff --git a/gl_backend.h b/gl_backend.h
index 01dc1060..2efbd9a0 100644
--- a/gl_backend.h
+++ b/gl_backend.h
@@ -68,20 +68,13 @@ void R_Mesh_ClearDepth(void);
 // (only valid between R_Mesh_Start and R_Mesh_Finish)
 void R_Mesh_Render(void);
 
-// queues a mesh to be rendered (invokes Render if queue is full)
-// (only valid between R_Mesh_Start and R_Mesh_Finish)
-void R_Mesh_Draw(const rmeshinfo_t *m);
-
 // renders the queued transparent meshs
 // (only valid between R_Mesh_Start and R_Mesh_Finish)
 void R_Mesh_AddTransparent(void);
 
-// ease-of-use frontend to R_Mesh_Draw, set up meshinfo, except for index and numtriangles and numverts, then call this
-// (only valid between R_Mesh_Start and R_Mesh_Finish)
-void R_Mesh_DrawPolygon(rmeshinfo_t *m, int numverts);
-
 // allocates space in geometry buffers, and fills in pointers to the buffers in passsed struct
-// (this is used for very high speed rendering, no copying)
+// (it is up to the caller to fill in the geometry data)
+// (make sure you scale your colors by the colorscale field)
 // (only valid between R_Mesh_Start and R_Mesh_Finish)
 int R_Mesh_Draw_GetBuffer(rmeshbufferinfo_t *m, int wantoverbright);
 
diff --git a/gl_models.c b/gl_models.c
index 47efa6d2..8b40edda 100644
--- a/gl_models.c
+++ b/gl_models.c
@@ -20,8 +20,6 @@ float *aliasvertnorm;
 int *aliasvertusage;
 zymbonematrix *zymbonepose;
 
-rmeshinfo_t aliasmeshinfo;
-
 mempool_t *gl_models_mempool;
 
 void gl_models_start(void)
@@ -200,41 +198,6 @@ void R_AliasLerpVerts(int vertcount,
 	}
 }
 
-void R_DrawModelMesh(rtexture_t *skin, float *colors, float cred, float cgreen, float cblue)
-{
-	aliasmeshinfo.tex[0] = R_GetTexture(skin);
-	aliasmeshinfo.color = colors;
-	if (colors == NULL)
-	{
-		aliasmeshinfo.cr = cred;
-		aliasmeshinfo.cg = cgreen;
-		aliasmeshinfo.cb = cblue;
-		aliasmeshinfo.ca = currentrenderentity->alpha;
-	}
-
-	c_alias_polys += aliasmeshinfo.numtriangles;
-	R_Mesh_Draw(&aliasmeshinfo);
-	R_Mesh_Render();
-
-	// leave it in a state for additional passes
-	aliasmeshinfo.blendfunc1 = GL_SRC_ALPHA;
-	aliasmeshinfo.blendfunc2 = GL_ONE;
-}
-
-void R_TintModel(float *in, float *out, int verts, float r, float g, float b)
-{
-	int i;
-	for (i = 0;i < verts;i++)
-	{
-		out[0] = in[0] * r;
-		out[1] = in[1] * g;
-		out[2] = in[2] * b;
-		out[3] = in[3];
-		in += 4;
-		out += 4;
-	}
-}
-
 skinframe_t *R_FetchSkinFrame(void)
 {
 	model_t *model = currentrenderentity->model;
@@ -272,231 +235,197 @@ void R_SetupMDLMD2Frames(float colorr, float colorg, float colorb)
 
 void R_DrawQ1Q2AliasModel (float fog)
 {
+	int c, pantsfullbright, shirtfullbright, colormapped;
+	float pantscolor[3], shirtcolor[3];
+	qbyte *bcolor;
+	rmeshbufferinfo_t m;
 	model_t *model;
 	skinframe_t *skinframe;
 
 	model = currentrenderentity->model;
 
 	skinframe = R_FetchSkinFrame();
-	if (fog && !(currentrenderentity->effects & EF_ADDITIVE))
-	{
-		R_SetupMDLMD2Frames(1 - fog, 1 - fog, 1 - fog);
-
-		memset(&aliasmeshinfo, 0, sizeof(aliasmeshinfo));
-
-		aliasmeshinfo.vertex = aliasvert;
-		aliasmeshinfo.vertexstep = sizeof(float[4]);
-		aliasmeshinfo.numverts = model->numverts;
-		aliasmeshinfo.numtriangles = model->numtris;
-		aliasmeshinfo.index = model->mdlmd2data_indices;
-		aliasmeshinfo.colorstep = sizeof(float[4]);
-		aliasmeshinfo.texcoords[0] = model->mdlmd2data_texcoords;
-		aliasmeshinfo.texcoordstep[0] = sizeof(float[2]);
 
+	colormapped = !skinframe->merged || (currentrenderentity->colormap >= 0 && skinframe->base && (skinframe->pants || skinframe->shirt));
+	if (!colormapped && !fog && !skinframe->glow && !skinframe->fog)
+	{
+		// fastpath for the normal situation (one texture)
+		memset(&m, 0, sizeof(m));
 		if (currentrenderentity->effects & EF_ADDITIVE)
 		{
-			aliasmeshinfo.transparent = true;
-			aliasmeshinfo.blendfunc1 = GL_SRC_ALPHA;
-			aliasmeshinfo.blendfunc2 = GL_ONE;
+			m.transparent = true;
+			m.blendfunc1 = GL_SRC_ALPHA;
+			m.blendfunc2 = GL_ONE;
 		}
 		else if (currentrenderentity->alpha != 1.0 || skinframe->fog != NULL)
 		{
-			aliasmeshinfo.transparent = true;
-			aliasmeshinfo.blendfunc1 = GL_SRC_ALPHA;
-			aliasmeshinfo.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
+			m.transparent = true;
+			m.blendfunc1 = GL_SRC_ALPHA;
+			m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
 		}
 		else
 		{
-			aliasmeshinfo.transparent = false;
-			aliasmeshinfo.blendfunc1 = GL_ONE;
-			aliasmeshinfo.blendfunc2 = GL_ZERO;
+			m.transparent = false;
+			m.blendfunc1 = GL_ONE;
+			m.blendfunc2 = GL_ZERO;
 		}
+		m.numtriangles = model->numtris;
+		m.numverts = model->numverts;
+		m.tex[0] = R_GetTexture(skinframe->merged);
 
-		if (skinframe->base || skinframe->pants || skinframe->shirt || skinframe->glow || skinframe->merged)
+		c_alias_polys += m.numtriangles;
+		if (R_Mesh_Draw_GetBuffer(&m, true))
 		{
-			if (currentrenderentity->colormap >= 0 && (skinframe->base || skinframe->pants || skinframe->shirt))
-			{
-				int c;
-				qbyte *color;
-				if (skinframe->base)
-					R_DrawModelMesh(skinframe->base, aliasvertcolor, 0, 0, 0);
-				if (skinframe->pants)
-				{
-					c = (currentrenderentity->colormap & 0xF) << 4;c += (c >= 128 && c < 224) ? 4 : 12; // 128-224 are backwards ranges
-					color = (qbyte *) (&d_8to24table[c]);
-					if (c >= 224) // fullbright ranges
-						R_DrawModelMesh(skinframe->pants, NULL, color[0] * (1.0f / 255.0f), color[1] * (1.0f / 255.0f), color[2] * (1.0f / 255.0f));
-					else
-					{
-						R_TintModel(aliasvertcolor, aliasvertcolor2, model->numverts, color[0] * (1.0f / 255.0f), color[1] * (1.0f / 255.0f), color[2] * (1.0f / 255.0f));
-						R_DrawModelMesh(skinframe->pants, aliasvertcolor2, 0, 0, 0);
-					}
-				}
-				if (skinframe->shirt)
-				{
-					c = currentrenderentity->colormap & 0xF0      ;c += (c >= 128 && c < 224) ? 4 : 12; // 128-224 are backwards ranges
-					color = (qbyte *) (&d_8to24table[c]);
-					if (c >= 224) // fullbright ranges
-						R_DrawModelMesh(skinframe->shirt, NULL, color[0] * (1.0f / 255.0f), color[1] * (1.0f / 255.0f), color[2] * (1.0f / 255.0f));
-					else
-					{
-						R_TintModel(aliasvertcolor, aliasvertcolor2, model->numverts, color[0] * (1.0f / 255.0f), color[1] * (1.0f / 255.0f), color[2] * (1.0f / 255.0f));
-						R_DrawModelMesh(skinframe->shirt, aliasvertcolor2, 0, 0, 0);
-					}
-				}
-			}
-			else
-			{
-				if (skinframe->merged)
-					R_DrawModelMesh(skinframe->merged, aliasvertcolor, 0, 0, 0);
-				else
-				{
-					if (skinframe->base) R_DrawModelMesh(skinframe->base, aliasvertcolor, 0, 0, 0);
-					if (skinframe->pants) R_DrawModelMesh(skinframe->pants, aliasvertcolor, 0, 0, 0);
-					if (skinframe->shirt) R_DrawModelMesh(skinframe->shirt, aliasvertcolor, 0, 0, 0);
-				}
-			}
-			if (skinframe->glow) R_DrawModelMesh(skinframe->glow, NULL, 1 - fog, 1 - fog, 1 - fog);
-		}
-		else
-			R_DrawModelMesh(0, NULL, 1 - fog, 1 - fog, 1 - fog);
-
-		aliasmeshinfo.tex[0] = R_GetTexture(skinframe->fog);
-		aliasmeshinfo.blendfunc1 = GL_SRC_ALPHA;
-		aliasmeshinfo.blendfunc2 = GL_ONE;
-		aliasmeshinfo.color = NULL;
+			memcpy(m.index, model->mdlmd2data_indices, m.numtriangles * sizeof(int[3]));
+			memcpy(m.texcoords[0], model->mdlmd2data_texcoords, m.numverts * sizeof(float[2]));
 
-		aliasmeshinfo.cr = fogcolor[0];
-		aliasmeshinfo.cg = fogcolor[1];
-		aliasmeshinfo.cb = fogcolor[2];
-		aliasmeshinfo.ca = currentrenderentity->alpha * fog;
+			aliasvert = m.vertex;
+			aliasvertcolor = m.color;
+			R_SetupMDLMD2Frames(m.colorscale * (1 - fog), m.colorscale * (1 - fog), m.colorscale * (1 - fog));
+			aliasvert = aliasvertbuf;
+			aliasvertcolor = aliasvertcolorbuf;
 
-		c_alias_polys += aliasmeshinfo.numtriangles;
-		R_Mesh_Draw(&aliasmeshinfo);
-		R_Mesh_Render();
+			R_Mesh_Render();
+		}
+		return;
 	}
-	else if (currentrenderentity->colormap >= 0 || !skinframe->merged || skinframe->glow || !r_quickmodels.integer)
-	{
-		R_SetupMDLMD2Frames(1 - fog, 1 - fog, 1 - fog);
 
-		memset(&aliasmeshinfo, 0, sizeof(aliasmeshinfo));
+	R_SetupMDLMD2Frames(1 - fog, 1 - fog, 1 - fog);
 
-		aliasmeshinfo.vertex = aliasvert;
-		aliasmeshinfo.vertexstep = sizeof(float[4]);
-		aliasmeshinfo.numverts = model->numverts;
-		aliasmeshinfo.numtriangles = model->numtris;
-		aliasmeshinfo.index = model->mdlmd2data_indices;
-		aliasmeshinfo.colorstep = sizeof(float[4]);
-		aliasmeshinfo.texcoords[0] = model->mdlmd2data_texcoords;
-		aliasmeshinfo.texcoordstep[0] = sizeof(float[2]);
+	if (colormapped)
+	{
+		// 128-224 are backwards ranges
+		c = (currentrenderentity->colormap & 0xF) << 4;c += (c >= 128 && c < 224) ? 4 : 12;
+		bcolor = (qbyte *) (&d_8to24table[c]);
+		pantsfullbright = c >= 224;
+		VectorScale(bcolor, (1.0f / 255.0f), pantscolor);
+		c = (currentrenderentity->colormap & 0xF0);c += (c >= 128 && c < 224) ? 4 : 12;
+		bcolor = (qbyte *) (&d_8to24table[c]);
+		shirtfullbright = c >= 224;
+		VectorScale(bcolor, (1.0f / 255.0f), shirtcolor);
+	}
+	else
+	{
+		pantscolor[0] = pantscolor[1] = pantscolor[2] = shirtcolor[0] = shirtcolor[1] = shirtcolor[2] = 1;
+		pantsfullbright = shirtfullbright = false;
+	}
 
-		if (currentrenderentity->effects & EF_ADDITIVE)
-		{
-			aliasmeshinfo.transparent = true;
-			aliasmeshinfo.blendfunc1 = GL_SRC_ALPHA;
-			aliasmeshinfo.blendfunc2 = GL_ONE;
-		}
-		else if (currentrenderentity->alpha != 1.0 || skinframe->fog != NULL)
-		{
-			aliasmeshinfo.transparent = true;
-			aliasmeshinfo.blendfunc1 = GL_SRC_ALPHA;
-			aliasmeshinfo.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
-		}
-		else
-		{
-			aliasmeshinfo.transparent = false;
-			aliasmeshinfo.blendfunc1 = GL_ONE;
-			aliasmeshinfo.blendfunc2 = GL_ZERO;
-		}
+	memset(&m, 0, sizeof(m));
+	if (currentrenderentity->effects & EF_ADDITIVE)
+	{
+		m.transparent = true;
+		m.blendfunc1 = GL_SRC_ALPHA;
+		m.blendfunc2 = GL_ONE;
+	}
+	else if (currentrenderentity->alpha != 1.0 || skinframe->fog != NULL)
+	{
+		m.transparent = true;
+		m.blendfunc1 = GL_SRC_ALPHA;
+		m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
+	}
+	else
+	{
+		m.transparent = false;
+		m.blendfunc1 = GL_ONE;
+		m.blendfunc2 = GL_ZERO;
+	}
+	m.numtriangles = model->numtris;
+	m.numverts = model->numverts;
+	m.tex[0] = colormapped ? R_GetTexture(skinframe->base) : R_GetTexture(skinframe->merged);
+	if (R_Mesh_Draw_GetBuffer(&m, true))
+	{
+		c_alias_polys += m.numtriangles;
+		R_ModulateColors(aliasvertcolor, m.color, m.numverts, m.colorscale, m.colorscale, m.colorscale);
+		memcpy(m.index, model->mdlmd2data_indices, m.numtriangles * sizeof(int[3]));
+		memcpy(m.vertex, aliasvert, m.numverts * sizeof(float[4]));
+		memcpy(m.texcoords[0], model->mdlmd2data_texcoords, m.numverts * sizeof(float[2]));
+		R_Mesh_Render();
+	}
 
-		if (skinframe->base || skinframe->pants || skinframe->shirt || skinframe->glow || skinframe->merged)
+	if (colormapped)
+	{
+		if (skinframe->pants)
 		{
-			if (currentrenderentity->colormap >= 0 && (skinframe->base || skinframe->pants || skinframe->shirt))
+			memset(&m, 0, sizeof(m));
+			m.transparent = currentrenderentity->effects & EF_ADDITIVE || currentrenderentity->alpha != 1.0 || skinframe->fog != NULL;
+			m.blendfunc1 = GL_SRC_ALPHA;
+			m.blendfunc2 = GL_ONE;
+			m.numtriangles = model->numtris;
+			m.numverts = model->numverts;
+			m.tex[0] = R_GetTexture(skinframe->pants);
+			if (R_Mesh_Draw_GetBuffer(&m, true))
 			{
-				int c;
-				qbyte *color;
-				if (skinframe->base)
-					R_DrawModelMesh(skinframe->base, aliasvertcolor, 0, 0, 0);
-				if (skinframe->pants)
-				{
-					c = (currentrenderentity->colormap & 0xF) << 4;c += (c >= 128 && c < 224) ? 4 : 12; // 128-224 are backwards ranges
-					color = (qbyte *) (&d_8to24table[c]);
-					if (c >= 224) // fullbright ranges
-						R_DrawModelMesh(skinframe->pants, NULL, color[0] * (1.0f / 255.0f), color[1] * (1.0f / 255.0f), color[2] * (1.0f / 255.0f));
-					else
-					{
-						R_TintModel(aliasvertcolor, aliasvertcolor2, model->numverts, color[0] * (1.0f / 255.0f), color[1] * (1.0f / 255.0f), color[2] * (1.0f / 255.0f));
-						R_DrawModelMesh(skinframe->pants, aliasvertcolor2, 0, 0, 0);
-					}
-				}
-				if (skinframe->shirt)
-				{
-					c = currentrenderentity->colormap & 0xF0      ;c += (c >= 128 && c < 224) ? 4 : 12; // 128-224 are backwards ranges
-					color = (qbyte *) (&d_8to24table[c]);
-					if (c >= 224) // fullbright ranges
-						R_DrawModelMesh(skinframe->shirt, NULL, color[0] * (1.0f / 255.0f), color[1] * (1.0f / 255.0f), color[2] * (1.0f / 255.0f));
-					else
-					{
-						R_TintModel(aliasvertcolor, aliasvertcolor2, model->numverts, color[0] * (1.0f / 255.0f), color[1] * (1.0f / 255.0f), color[2] * (1.0f / 255.0f));
-						R_DrawModelMesh(skinframe->shirt, aliasvertcolor2, 0, 0, 0);
-					}
-				}
+				c_alias_polys += m.numtriangles;
+				if (pantsfullbright)
+					R_FillColors(m.color, m.numverts, pantscolor[0] * m.colorscale, pantscolor[1] * m.colorscale, pantscolor[2] * m.colorscale, currentrenderentity->alpha);
+				else
+					R_ModulateColors(aliasvertcolor, m.color, m.numverts, pantscolor[0] * m.colorscale, pantscolor[1] * m.colorscale, pantscolor[2] * m.colorscale);
+				memcpy(m.index, model->mdlmd2data_indices, m.numtriangles * sizeof(int[3]));
+				memcpy(m.vertex, aliasvert, m.numverts * sizeof(float[4]));
+				memcpy(m.texcoords[0], model->mdlmd2data_texcoords, m.numverts * sizeof(float[2]));
+				R_Mesh_Render();
 			}
-			else
+		}
+		if (skinframe->shirt)
+		{
+			memset(&m, 0, sizeof(m));
+			m.transparent = currentrenderentity->effects & EF_ADDITIVE || currentrenderentity->alpha != 1.0 || skinframe->fog != NULL;
+			m.blendfunc1 = GL_SRC_ALPHA;
+			m.blendfunc2 = GL_ONE;
+			m.numtriangles = model->numtris;
+			m.numverts = model->numverts;
+			m.tex[0] = R_GetTexture(skinframe->shirt);
+			if (R_Mesh_Draw_GetBuffer(&m, true))
 			{
-				if (skinframe->merged)
-					R_DrawModelMesh(skinframe->merged, aliasvertcolor, 0, 0, 0);
+				c_alias_polys += m.numtriangles;
+				if (shirtfullbright)
+					R_FillColors(m.color, m.numverts, shirtcolor[0] * m.colorscale, shirtcolor[1] * m.colorscale, shirtcolor[2] * m.colorscale, currentrenderentity->alpha);
 				else
-				{
-					if (skinframe->base) R_DrawModelMesh(skinframe->base, aliasvertcolor, 0, 0, 0);
-					if (skinframe->pants) R_DrawModelMesh(skinframe->pants, aliasvertcolor, 0, 0, 0);
-					if (skinframe->shirt) R_DrawModelMesh(skinframe->shirt, aliasvertcolor, 0, 0, 0);
-				}
+					R_ModulateColors(aliasvertcolor, m.color, m.numverts, shirtcolor[0] * m.colorscale, shirtcolor[1] * m.colorscale, shirtcolor[2] * m.colorscale);
+				memcpy(m.index, model->mdlmd2data_indices, m.numtriangles * sizeof(int[3]));
+				memcpy(m.vertex, aliasvert, m.numverts * sizeof(float[4]));
+				memcpy(m.texcoords[0], model->mdlmd2data_texcoords, m.numverts * sizeof(float[2]));
+				R_Mesh_Render();
 			}
-			if (skinframe->glow) R_DrawModelMesh(skinframe->glow, NULL, 1 - fog, 1 - fog, 1 - fog);
 		}
-		else
-			R_DrawModelMesh(0, NULL, 1 - fog, 1 - fog, 1 - fog);
 	}
-	else
+	if (skinframe->glow)
 	{
-		rmeshbufferinfo_t bufmesh;
-		memset(&bufmesh, 0, sizeof(bufmesh));
-		if (currentrenderentity->effects & EF_ADDITIVE)
-		{
-			bufmesh.transparent = true;
-			bufmesh.blendfunc1 = GL_SRC_ALPHA;
-			bufmesh.blendfunc2 = GL_ONE;
-		}
-		else if (currentrenderentity->alpha != 1.0 || skinframe->fog != NULL)
+		memset(&m, 0, sizeof(m));
+		m.transparent = currentrenderentity->effects & EF_ADDITIVE || currentrenderentity->alpha != 1.0 || skinframe->fog != NULL;
+		m.blendfunc1 = GL_SRC_ALPHA;
+		m.blendfunc2 = GL_ONE;
+		m.numtriangles = model->numtris;
+		m.numverts = model->numverts;
+		m.tex[0] = R_GetTexture(skinframe->glow);
+		if (R_Mesh_Draw_GetBuffer(&m, true))
 		{
-			bufmesh.transparent = true;
-			bufmesh.blendfunc1 = GL_SRC_ALPHA;
-			bufmesh.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
+			c_alias_polys += m.numtriangles;
+			R_FillColors(m.color, m.numverts, (1 - fog) * m.colorscale, (1 - fog) * m.colorscale, (1 - fog) * m.colorscale, currentrenderentity->alpha);
+			memcpy(m.index, model->mdlmd2data_indices, m.numtriangles * sizeof(int[3]));
+			memcpy(m.vertex, aliasvert, m.numverts * sizeof(float[4]));
+			memcpy(m.texcoords[0], model->mdlmd2data_texcoords, m.numverts * sizeof(float[2]));
+			R_Mesh_Render();
 		}
-		else
+	}
+	if (fog)
+	{
+		memset(&m, 0, sizeof(m));
+		m.transparent = currentrenderentity->effects & EF_ADDITIVE || currentrenderentity->alpha != 1.0 || skinframe->fog != NULL;
+		m.blendfunc1 = GL_SRC_ALPHA;
+		m.blendfunc2 = GL_ONE;
+		m.numtriangles = model->numtris;
+		m.numverts = model->numverts;
+		m.tex[0] = R_GetTexture(skinframe->fog);
+		if (R_Mesh_Draw_GetBuffer(&m, false))
 		{
-			bufmesh.transparent = false;
-			bufmesh.blendfunc1 = GL_ONE;
-			bufmesh.blendfunc2 = GL_ZERO;
+			c_alias_polys += m.numtriangles;
+			R_FillColors(m.color, m.numverts, fog * m.colorscale, fog * m.colorscale, fog * m.colorscale, currentrenderentity->alpha);
+			memcpy(m.index, model->mdlmd2data_indices, m.numtriangles * sizeof(int[3]));
+			memcpy(m.vertex, aliasvert, m.numverts * sizeof(float[4]));
+			memcpy(m.texcoords[0], model->mdlmd2data_texcoords, m.numverts * sizeof(float[2]));
+			R_Mesh_Render();
 		}
-		bufmesh.numtriangles = model->numtris;
-		bufmesh.numverts = model->numverts;
-		bufmesh.tex[0] = R_GetTexture(skinframe->merged);
-
-		R_Mesh_Draw_GetBuffer(&bufmesh, true);
-
-		aliasvert = bufmesh.vertex;
-		aliasvertcolor = bufmesh.color;
-		memcpy(bufmesh.index, model->mdlmd2data_indices, bufmesh.numtriangles * sizeof(int[3]));
-		memcpy(bufmesh.texcoords[0], model->mdlmd2data_texcoords, bufmesh.numverts * sizeof(float[2]));
-
-		fog = bufmesh.colorscale * (1 - fog);
-		R_SetupMDLMD2Frames(fog, fog, fog);
-
-		aliasvert = aliasvertbuf;
-		aliasvertcolor = aliasvertcolorbuf;
-		R_Mesh_Render();
 	}
 }
 
@@ -760,76 +689,76 @@ void ZymoticCalcNormals(int vertcount, int shadercount, int *renderlist)
 	}
 }
 
-void R_DrawZymoticModelMesh(zymtype1header_t *m)
+void R_DrawZymoticModelMesh(zymtype1header_t *m, float fog)
 {
+	rmeshbufferinfo_t mbuf;
 	int i, *renderlist;
 	rtexture_t **texture;
 
-	// FIXME: do better fog
-	renderlist = (int *)(m->lump_render.start + (int) m);
 	texture = (rtexture_t **)(m->lump_shaders.start + (int) m);
 
-	aliasmeshinfo.vertex = aliasvert;
-	aliasmeshinfo.vertexstep = sizeof(float[4]);
-	aliasmeshinfo.color = aliasvertcolor;
-	aliasmeshinfo.colorstep = sizeof(float[4]);
-	aliasmeshinfo.texcoords[0] = (float *)(m->lump_texcoords.start + (int) m);
-	aliasmeshinfo.texcoordstep[0] = sizeof(float[2]);
-
+	renderlist = (int *)(m->lump_render.start + (int) m);
 	for (i = 0;i < m->numshaders;i++)
 	{
-		aliasmeshinfo.tex[0] = R_GetTexture(texture[i]);
+		memset(&mbuf, 0, sizeof(mbuf));
+		mbuf.numverts = m->numverts;
+		mbuf.numtriangles = *renderlist++;
 		if (currentrenderentity->effects & EF_ADDITIVE)
 		{
-			aliasmeshinfo.transparent = true;
-			aliasmeshinfo.blendfunc1 = GL_SRC_ALPHA;
-			aliasmeshinfo.blendfunc2 = GL_ONE;
+			mbuf.transparent = true;
+			mbuf.blendfunc1 = GL_SRC_ALPHA;
+			mbuf.blendfunc2 = GL_ONE;
 		}
 		else if (currentrenderentity->alpha != 1.0 || R_TextureHasAlpha(texture[i]))
 		{
-			aliasmeshinfo.transparent = true;
-			aliasmeshinfo.blendfunc1 = GL_SRC_ALPHA;
-			aliasmeshinfo.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
+			mbuf.transparent = true;
+			mbuf.blendfunc1 = GL_SRC_ALPHA;
+			mbuf.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
 		}
 		else
 		{
-			aliasmeshinfo.transparent = false;
-			aliasmeshinfo.blendfunc1 = GL_ONE;
-			aliasmeshinfo.blendfunc2 = GL_ZERO;
+			mbuf.transparent = false;
+			mbuf.blendfunc1 = GL_ONE;
+			mbuf.blendfunc2 = GL_ZERO;
 		}
-		aliasmeshinfo.numtriangles = *renderlist++;
-		aliasmeshinfo.index = renderlist;
-		c_alias_polys += aliasmeshinfo.numtriangles;
-		R_Mesh_Draw(&aliasmeshinfo);
-		R_Mesh_Render();
-		renderlist += aliasmeshinfo.numtriangles * 3;
+		mbuf.tex[0] = R_GetTexture(texture[i]);
+		if (R_Mesh_Draw_GetBuffer(&mbuf, true))
+		{
+			c_alias_polys += mbuf.numtriangles;
+			memcpy(mbuf.index, renderlist, mbuf.numtriangles * sizeof(int[3]));
+			memcpy(mbuf.vertex, aliasvert, mbuf.numverts * sizeof(float[4]));
+			R_ModulateColors(aliasvertcolor, mbuf.color, mbuf.numverts, mbuf.colorscale, mbuf.colorscale, mbuf.colorscale);
+			//memcpy(mbuf.color, aliasvertcolor, mbuf.numverts * sizeof(float[4]));
+			memcpy(mbuf.texcoords[0], (float *)(m->lump_texcoords.start + (int) m), mbuf.numverts * sizeof(float[2]));
+			R_Mesh_Render();
+		}
+		renderlist += mbuf.numtriangles * 3;
 	}
-}
 
-void R_DrawZymoticModelMeshFog(vec3_t org, zymtype1header_t *m, float fog)
-{
-	int i, *renderlist;
-
-	// FIXME: do better fog
-	renderlist = (int *)(m->lump_render.start + (int) m);
-
-	aliasmeshinfo.tex[0] = 0;
-	aliasmeshinfo.blendfunc1 = GL_SRC_ALPHA;
-	aliasmeshinfo.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
-
-	aliasmeshinfo.cr = fogcolor[0];
-	aliasmeshinfo.cg = fogcolor[1];
-	aliasmeshinfo.cb = fogcolor[2];
-	aliasmeshinfo.ca = currentrenderentity->alpha * fog;
-
-	for (i = 0;i < m->numshaders;i++)
+	if (fog)
 	{
-		aliasmeshinfo.numtriangles = *renderlist++;
-		aliasmeshinfo.index = renderlist;
-		c_alias_polys += aliasmeshinfo.numtriangles;
-		R_Mesh_Draw(&aliasmeshinfo);
-		R_Mesh_Render();
-		renderlist += aliasmeshinfo.numtriangles * 3;
+		renderlist = (int *)(m->lump_render.start + (int) m);
+		for (i = 0;i < m->numshaders;i++)
+		{
+			memset(&mbuf, 0, sizeof(mbuf));
+			mbuf.numverts = m->numverts;
+			mbuf.numtriangles = *renderlist++;
+			mbuf.transparent = currentrenderentity->effects & EF_ADDITIVE || currentrenderentity->alpha != 1.0 || R_TextureHasAlpha(texture[i]);
+			mbuf.blendfunc1 = GL_SRC_ALPHA;
+			mbuf.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
+			// FIXME: need alpha mask for fogging...
+			//mbuf.tex[0] = R_GetTexture(texture[i]);
+			if (R_Mesh_Draw_GetBuffer(&mbuf, false))
+			{
+				c_alias_polys += mbuf.numtriangles;
+				memcpy(mbuf.index, renderlist, mbuf.numtriangles * sizeof(int[3]));
+				memcpy(mbuf.vertex, aliasvert, mbuf.numverts * sizeof(float[4]));
+				R_FillColors(mbuf.color, mbuf.numverts, fogcolor[0] * mbuf.colorscale, fogcolor[1] * mbuf.colorscale, fogcolor[2] * mbuf.colorscale, currentrenderentity->alpha * fog);
+				//memcpy(mbuf.texcoords[0], (float *)(m->lump_texcoords.start + (int) m), mbuf.numverts * sizeof(float[2]));
+				R_Mesh_Render();
+			}
+			renderlist += mbuf.numtriangles * 3;
+		}
 	}
 }
 
@@ -845,13 +774,7 @@ void R_DrawZymoticModel (float fog)
 
 	R_LightModel(m->numverts, 1 - fog, 1 - fog, 1 - fog, true);
 
-	memset(&aliasmeshinfo, 0, sizeof(aliasmeshinfo));
-	aliasmeshinfo.numverts = m->numverts;
-
-	R_DrawZymoticModelMesh(m);
-
-	if (fog)
-		R_DrawZymoticModelMeshFog(currentrenderentity->origin, m, fog);
+	R_DrawZymoticModelMesh(m, fog);
 }
 
 void R_DrawAliasModel (void)
diff --git a/gl_rmain.c b/gl_rmain.c
index ad66314d..7640985b 100644
--- a/gl_rmain.c
+++ b/gl_rmain.c
@@ -69,6 +69,33 @@ cvar_t gl_fogend = {0, "gl_fogend","0"};
 
 cvar_t r_textureunits = {0, "r_textureunits", "32"};
 
+void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
+{
+	int i;
+	for (i = 0;i < verts;i++)
+	{
+		out[0] = in[0] * r;
+		out[1] = in[1] * g;
+		out[2] = in[2] * b;
+		out[3] = in[3];
+		in += 4;
+		out += 4;
+	}
+}
+
+void R_FillColors(float *out, int verts, float r, float g, float b, float a)
+{
+	int i;
+	for (i = 0;i < verts;i++)
+	{
+		out[0] = r;
+		out[1] = g;
+		out[2] = b;
+		out[3] = a;
+		out += 4;
+	}
+}
+
 /*
 ====================
 R_TimeRefresh_f
diff --git a/gl_rsurf.c b/gl_rsurf.c
index dbe515c4..c9ce94ca 100644
--- a/gl_rsurf.c
+++ b/gl_rsurf.c
@@ -1884,48 +1884,49 @@ void R_DrawSurfaces (int type)
 	}
 }
 
-static float portalpointbuffer[256][3];
-
 void R_DrawPortals(void)
 {
 	int drawportals, i;
+	float *v;
 	mportal_t *portal, *endportal;
-	mvertex_t *point;
-	rmeshinfo_t m;
+	rmeshbufferinfo_t m;
 	drawportals = r_drawportals.integer;
 
 	if (drawportals < 1)
 		return;
 
-	memset(&m, 0, sizeof(m));
-	m.transparent = true;
-	m.blendfunc1 = GL_SRC_ALPHA;
-	m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
-	m.vertex = &portalpointbuffer[0][0];
-	m.vertexstep = sizeof(float[3]);
-	m.ca = 0.125;
 	for (portal = cl.worldmodel->portals, endportal = portal + cl.worldmodel->numportals;portal < endportal;portal++)
 	{
 		if (portal->visframe == r_portalframecount)
 		{
-			if (portal->numpoints <= 256)
+			memset(&m, 0, sizeof(m));
+			m.transparent = true;
+			m.blendfunc1 = GL_SRC_ALPHA;
+			m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
+			m.numverts = portal->numpoints;
+			m.numtriangles = portal->numpoints - 2;
+			if (R_Mesh_Draw_GetBuffer(&m, false))
 			{
+				for (i = 0;i < m.numtriangles;i++)
+				{
+					m.index[i * 3 + 0] = 0;
+					m.index[i * 3 + 1] = i + 1;
+					m.index[i * 3 + 2] = i + 2;
+				}
 				i = portal - cl.worldmodel->portals;
-				m.cr = ((i & 0x0007) >> 0) * (1.0f / 7.0f);
-				m.cg = ((i & 0x0038) >> 3) * (1.0f / 7.0f);
-				m.cb = ((i & 0x01C0) >> 6) * (1.0f / 7.0f);
-				point = portal->points;
+				R_FillColors(m.color, m.numverts,
+					((i & 0x0007) >> 0) * (1.0f / 7.0f) * m.colorscale,
+					((i & 0x0038) >> 3) * (1.0f / 7.0f) * m.colorscale,
+					((i & 0x01C0) >> 6) * (1.0f / 7.0f) * m.colorscale,
+					0.125f);
 				if (PlaneDiff(r_origin, (&portal->plane)) > 0)
 				{
-					for (i = portal->numpoints - 1;i >= 0;i--)
-						VectorCopy(point[i].position, portalpointbuffer[i]);
+					for (i = portal->numpoints - 1, v = m.vertex;i >= 0;i--, v += 4)
+						VectorCopy(portal->points[i].position, v);
 				}
 				else
-				{
-					for (i = 0;i < portal->numpoints;i++)
-						VectorCopy(point[i].position, portalpointbuffer[i]);
-				}
-				R_Mesh_DrawPolygon(&m, portal->numpoints);
+					for (i = 0, v = m.vertex;i < portal->numpoints;i++, v += 4)
+						VectorCopy(portal->points[i].position, v);
 				R_Mesh_Render();
 			}
 		}
diff --git a/render.h b/render.h
index 16c158bc..394cc410 100644
--- a/render.h
+++ b/render.h
@@ -68,6 +68,10 @@ extern cvar_t r_novis;
 // detail texture stuff
 extern cvar_t r_detailtextures;
 
+// useful functions for rendering
+void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b);
+void R_FillColors(float *out, int verts, float r, float g, float b, float a);
+
 #define	TOP_RANGE		16			// soldier uniform colors
 #define	BOTTOM_RANGE	96