[PATCH] Move r_bsp.c into common dir

diff -urN -X exclude a/NQ/r_bsp.c head/NQ/r_bsp.c
--- a/NQ/r_bsp.c	2006-05-28 15:04:03.000000000 +0930
+++ head/NQ/r_bsp.c	1970-01-01 09:30:00.000000000 +0930
@@ -1,615 +0,0 @@
-/*
-Copyright (C) 1996-1997 Id Software, Inc.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
-*/
-// r_bsp.c
-
-#include "quakedef.h"
-#include "r_local.h"
-#include "sys.h"
-#include "console.h"
-
-//
-// current entity info
-//
-qboolean insubmodel;
-entity_t *currententity;
-
-// modelorg is the viewpoint reletive to
-// the currently rendering entity
-vec3_t modelorg, base_modelorg;
-
-vec3_t r_entorigin;	// the currently rendering entity in world coordinates
-
-static float entity_rotation[3][3];
-
-vec3_t r_worldmodelorg;
-
-int r_currentbkey;
-
-typedef enum { touchessolid, drawnode, nodrawnode } solidstate_t;
-
-#define MAX_BMODEL_VERTS	500	// 6K
-#define MAX_BMODEL_EDGES	1000	// 12K
-
-static mvertex_t *pbverts;
-static bedge_t *pbedges;
-static int numbverts, numbedges;
-
-static mvertex_t *pfrontenter, *pfrontexit;
-
-static qboolean makeclippededge;
-
-
-//===========================================================================
-
-/*
-================
-R_EntityRotate
-================
-*/
-static void
-R_EntityRotate(vec3_t vec)
-{
-    vec3_t tvec;
-
-    VectorCopy(vec, tvec);
-    vec[0] = DotProduct(entity_rotation[0], tvec);
-    vec[1] = DotProduct(entity_rotation[1], tvec);
-    vec[2] = DotProduct(entity_rotation[2], tvec);
-}
-
-
-/*
-================
-R_RotateBmodel
-================
-*/
-void
-R_RotateBmodel(void)
-{
-    float angle, s, c, temp1[3][3], temp2[3][3], temp3[3][3];
-
-// TODO: should use a look-up table
-// TODO: should really be stored with the entity instead of being reconstructed
-// TODO: could cache lazily, stored in the entity
-// TODO: share work with R_SetUpAliasTransform
-
-// yaw
-    angle = currententity->angles[YAW];
-    angle = angle * M_PI * 2 / 360;
-    s = sin(angle);
-    c = cos(angle);
-
-    temp1[0][0] = c;
-    temp1[0][1] = s;
-    temp1[0][2] = 0;
-    temp1[1][0] = -s;
-    temp1[1][1] = c;
-    temp1[1][2] = 0;
-    temp1[2][0] = 0;
-    temp1[2][1] = 0;
-    temp1[2][2] = 1;
-
-// pitch
-    angle = currententity->angles[PITCH];
-    angle = angle * M_PI * 2 / 360;
-    s = sin(angle);
-    c = cos(angle);
-
-    temp2[0][0] = c;
-    temp2[0][1] = 0;
-    temp2[0][2] = -s;
-    temp2[1][0] = 0;
-    temp2[1][1] = 1;
-    temp2[1][2] = 0;
-    temp2[2][0] = s;
-    temp2[2][1] = 0;
-    temp2[2][2] = c;
-
-    R_ConcatRotations(temp2, temp1, temp3);
-
-// roll
-    angle = currententity->angles[ROLL];
-    angle = angle * M_PI * 2 / 360;
-    s = sin(angle);
-    c = cos(angle);
-
-    temp1[0][0] = 1;
-    temp1[0][1] = 0;
-    temp1[0][2] = 0;
-    temp1[1][0] = 0;
-    temp1[1][1] = c;
-    temp1[1][2] = s;
-    temp1[2][0] = 0;
-    temp1[2][1] = -s;
-    temp1[2][2] = c;
-
-    R_ConcatRotations(temp1, temp3, entity_rotation);
-
-//
-// rotate modelorg and the transformation matrix
-//
-    R_EntityRotate(modelorg);
-    R_EntityRotate(vpn);
-    R_EntityRotate(vright);
-    R_EntityRotate(vup);
-
-    R_TransformFrustum();
-}
-
-
-/*
-================
-R_RecursiveClipBPoly
-================
-*/
-static void
-R_RecursiveClipBPoly(bedge_t *pedges, mnode_t *pnode, msurface_t *psurf)
-{
-    bedge_t *psideedges[2], *pnextedge, *ptedge;
-    int i, side, lastside;
-    float dist, frac, lastdist;
-    mplane_t *splitplane, tplane;
-    mvertex_t *pvert, *plastvert, *ptvert;
-    mnode_t *pn;
-
-    psideedges[0] = psideedges[1] = NULL;
-
-    makeclippededge = false;
-
-// transform the BSP plane into model space
-// FIXME: cache these?
-    splitplane = pnode->plane;
-    tplane.dist = splitplane->dist -
-	DotProduct(r_entorigin, splitplane->normal);
-    tplane.normal[0] = DotProduct(entity_rotation[0], splitplane->normal);
-    tplane.normal[1] = DotProduct(entity_rotation[1], splitplane->normal);
-    tplane.normal[2] = DotProduct(entity_rotation[2], splitplane->normal);
-
-// clip edges to BSP plane
-    for (; pedges; pedges = pnextedge) {
-	pnextedge = pedges->pnext;
-
-	// set the status for the last point as the previous point
-	// FIXME: cache this stuff somehow?
-	plastvert = pedges->v[0];
-	lastdist = DotProduct(plastvert->position, tplane.normal) -
-	    tplane.dist;
-
-	if (lastdist > 0)
-	    lastside = 0;
-	else
-	    lastside = 1;
-
-	pvert = pedges->v[1];
-
-	dist = DotProduct(pvert->position, tplane.normal) - tplane.dist;
-
-	if (dist > 0)
-	    side = 0;
-	else
-	    side = 1;
-
-	if (side != lastside) {
-	    // clipped
-	    if (numbverts >= MAX_BMODEL_VERTS)
-		return;
-
-	    // generate the clipped vertex
-	    frac = lastdist / (lastdist - dist);
-	    ptvert = &pbverts[numbverts++];
-	    ptvert->position[0] = plastvert->position[0] +
-		frac * (pvert->position[0] - plastvert->position[0]);
-	    ptvert->position[1] = plastvert->position[1] +
-		frac * (pvert->position[1] - plastvert->position[1]);
-	    ptvert->position[2] = plastvert->position[2] +
-		frac * (pvert->position[2] - plastvert->position[2]);
-
-	    // split into two edges, one on each side, and remember entering
-	    // and exiting points
-	    // FIXME: share the clip edge by having a winding direction flag?
-	    if (numbedges >= (MAX_BMODEL_EDGES - 1)) {
-		Con_Printf("Out of edges for bmodel\n");
-		return;
-	    }
-
-	    ptedge = &pbedges[numbedges];
-	    ptedge->pnext = psideedges[lastside];
-	    psideedges[lastside] = ptedge;
-	    ptedge->v[0] = plastvert;
-	    ptedge->v[1] = ptvert;
-
-	    ptedge = &pbedges[numbedges + 1];
-	    ptedge->pnext = psideedges[side];
-	    psideedges[side] = ptedge;
-	    ptedge->v[0] = ptvert;
-	    ptedge->v[1] = pvert;
-
-	    numbedges += 2;
-
-	    if (side == 0) {
-		// entering for front, exiting for back
-		pfrontenter = ptvert;
-		makeclippededge = true;
-	    } else {
-		pfrontexit = ptvert;
-		makeclippededge = true;
-	    }
-	} else {
-	    // add the edge to the appropriate side
-	    pedges->pnext = psideedges[side];
-	    psideedges[side] = pedges;
-	}
-    }
-
-// if anything was clipped, reconstitute and add the edges along the clip
-// plane to both sides (but in opposite directions)
-    if (makeclippededge) {
-	if (numbedges >= (MAX_BMODEL_EDGES - 2)) {
-	    Con_Printf("Out of edges for bmodel\n");
-	    return;
-	}
-
-	ptedge = &pbedges[numbedges];
-	ptedge->pnext = psideedges[0];
-	psideedges[0] = ptedge;
-	ptedge->v[0] = pfrontexit;
-	ptedge->v[1] = pfrontenter;
-
-	ptedge = &pbedges[numbedges + 1];
-	ptedge->pnext = psideedges[1];
-	psideedges[1] = ptedge;
-	ptedge->v[0] = pfrontenter;
-	ptedge->v[1] = pfrontexit;
-
-	numbedges += 2;
-    }
-
-    /* draw or recurse further */
-    for (i = 0; i < 2; i++) {
-	if (psideedges[i]) {
-	    /*
-	     * draw if we've reached a non-solid leaf, done if all that's left
-	     * is a solid leaf, and continue down the tree if it's not a leaf
-	     */
-	    pn = pnode->children[i];
-
-	    // we're done with this branch if the node or leaf isn't in the PVS
-	    if (pn->visframe == r_visframecount) {
-		if (pn->contents < 0) {
-		    if (pn->contents != CONTENTS_SOLID) {
-			r_currentbkey = ((mleaf_t *)pn)->key;
-			R_RenderBmodelFace(psideedges[i], psurf);
-		    }
-		} else {
-		    R_RecursiveClipBPoly(psideedges[i], pnode->children[i],
-					 psurf);
-		}
-	    }
-	}
-    }
-}
-
-
-/*
-================
-R_DrawSolidClippedSubmodelPolygons
-================
-*/
-void
-R_DrawSolidClippedSubmodelPolygons(model_t *pmodel)
-{
-    int i, j, lindex;
-    vec_t dot;
-    msurface_t *psurf;
-    int numsurfaces;
-    mplane_t *pplane;
-    mvertex_t bverts[MAX_BMODEL_VERTS];
-    bedge_t bedges[MAX_BMODEL_EDGES], *pbedge;
-    medge_t *pedge, *pedges;
-
-// FIXME: use bounding-box-based frustum clipping info?
-
-    psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
-    numsurfaces = pmodel->nummodelsurfaces;
-    pedges = pmodel->edges;
-
-    for (i = 0; i < numsurfaces; i++, psurf++) {
-	// find which side of the node we are on
-	pplane = psurf->plane;
-
-	dot = DotProduct(modelorg, pplane->normal) - pplane->dist;
-
-	// draw the polygon
-	if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
-	    (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) {
-	    // FIXME: use bounding-box-based frustum clipping info?
-
-	    // copy the edges to bedges, flipping if necessary so always
-	    // clockwise winding
-
-	    /*
-	     * FIXME: if edges and vertices get caches, these assignments must
-	     * move outside the loop, and overflow checking must be done here
-	     */
-	    pbverts = bverts;
-	    pbedges = bedges;
-	    numbverts = numbedges = 0;
-
-	    if (psurf->numedges > 0) {
-		pbedge = &bedges[numbedges];
-		numbedges += psurf->numedges;
-
-		for (j = 0; j < psurf->numedges; j++) {
-		    lindex = pmodel->surfedges[psurf->firstedge + j];
-
-		    if (lindex > 0) {
-			pedge = &pedges[lindex];
-			pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[0]];
-			pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[1]];
-		    } else {
-			lindex = -lindex;
-			pedge = &pedges[lindex];
-			pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[1]];
-			pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[0]];
-		    }
-		    pbedge[j].pnext = &pbedge[j + 1];
-		}
-		pbedge[j - 1].pnext = NULL;	// mark end of edges
-
-		R_RecursiveClipBPoly(pbedge, currententity->topnode, psurf);
-	    } else {
-		Sys_Error("no edges in bmodel");
-	    }
-	}
-    }
-}
-
-
-/*
-================
-R_DrawSubmodelPolygons
-================
-*/
-void
-R_DrawSubmodelPolygons(model_t *pmodel, int clipflags)
-{
-    int i;
-    vec_t dot;
-    msurface_t *psurf;
-    int numsurfaces;
-    mplane_t *pplane;
-
-// FIXME: use bounding-box-based frustum clipping info?
-
-    psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
-    numsurfaces = pmodel->nummodelsurfaces;
-
-    for (i = 0; i < numsurfaces; i++, psurf++) {
-	// find which side of the node we are on
-	pplane = psurf->plane;
-
-	dot = DotProduct(modelorg, pplane->normal) - pplane->dist;
-
-	// draw the polygon
-	if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
-	    (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) {
-	    r_currentkey = ((mleaf_t *)currententity->topnode)->key;
-
-	    // FIXME: use bounding-box-based frustum clipping info?
-	    R_RenderFace(psurf, clipflags);
-	}
-    }
-}
-
-
-/*
-================
-R_RecursiveWorldNode
-================
-*/
-static void
-R_RecursiveWorldNode(mnode_t *node, int clipflags)
-{
-    int i, c, side, *pindex;
-    vec3_t acceptpt, rejectpt;
-    mplane_t *plane;
-    msurface_t *surf, **mark;
-    mleaf_t *pleaf;
-    double d, dot;
-
-    if (node->contents == CONTENTS_SOLID)
-	return;			// solid
-
-    if (node->visframe != r_visframecount)
-	return;
-
-// cull the clipping planes if not trivial accept
-// FIXME: the compiler is doing a lousy job of optimizing here; it could be
-//  twice as fast in ASM
-    if (clipflags) {
-	for (i = 0; i < 4; i++) {
-	    if (!(clipflags & (1 << i)))
-		continue;	// don't need to clip against it
-
-	    // generate accept and reject points
-	    // FIXME: do with fast look-ups or integer tests based on the sign
-	    // bit of the floating point values
-
-	    pindex = pfrustum_indexes[i];
-
-	    rejectpt[0] = (float)node->minmaxs[pindex[0]];
-	    rejectpt[1] = (float)node->minmaxs[pindex[1]];
-	    rejectpt[2] = (float)node->minmaxs[pindex[2]];
-
-	    d = DotProduct(rejectpt, view_clipplanes[i].normal);
-	    d -= view_clipplanes[i].dist;
-
-	    if (d <= 0)
-		return;
-
-	    acceptpt[0] = (float)node->minmaxs[pindex[3 + 0]];
-	    acceptpt[1] = (float)node->minmaxs[pindex[3 + 1]];
-	    acceptpt[2] = (float)node->minmaxs[pindex[3 + 2]];
-
-	    d = DotProduct(acceptpt, view_clipplanes[i].normal);
-	    d -= view_clipplanes[i].dist;
-
-	    if (d >= 0)
-		clipflags &= ~(1 << i);	// node is entirely on screen
-	}
-    }
-
-    /* if a leaf node, draw stuff */
-    if (node->contents < 0) {
-	pleaf = (mleaf_t *)node;
-
-	mark = pleaf->firstmarksurface;
-	c = pleaf->nummarksurfaces;
-
-	if (c) {
-	    do {
-		(*mark)->visframe = r_framecount;
-		mark++;
-	    } while (--c);
-	}
-
-	// deal with model fragments in this leaf
-	if (pleaf->efrags) {
-	    R_StoreEfrags(&pleaf->efrags);
-	}
-
-	pleaf->key = r_currentkey;
-	r_currentkey++;		// all bmodels in a leaf share the same key
-    } else {
-	// node is just a decision point, so go down the apropriate sides
-	// find which side of the node we are on
-	plane = node->plane;
-	switch (plane->type) {
-	case PLANE_X:
-	    dot = modelorg[0] - plane->dist;
-	    break;
-	case PLANE_Y:
-	    dot = modelorg[1] - plane->dist;
-	    break;
-	case PLANE_Z:
-	    dot = modelorg[2] - plane->dist;
-	    break;
-	default:
-	    dot = DotProduct(modelorg, plane->normal) - plane->dist;
-	    break;
-	}
-	side = (dot >= 0) ? 0 : 1;
-
-	// recurse down the children, front side first
-	R_RecursiveWorldNode(node->children[side], clipflags);
-
-	// draw stuff
-	c = node->numsurfaces;
-
-	if (c) {
-	    surf = cl.worldmodel->surfaces + node->firstsurface;
-
-	    if (dot < -BACKFACE_EPSILON) {
-		do {
-		    if ((surf->flags & SURF_PLANEBACK) &&
-			(surf->visframe == r_framecount)) {
-			if (r_drawpolys) {
-			    if (r_worldpolysbacktofront) {
-				if (numbtofpolys < MAX_BTOFPOLYS) {
-				    pbtofpolys[numbtofpolys].clipflags =
-					clipflags;
-				    pbtofpolys[numbtofpolys].psurf = surf;
-				    numbtofpolys++;
-				}
-			    } else {
-				R_RenderPoly(surf, clipflags);
-			    }
-			} else {
-			    R_RenderFace(surf, clipflags);
-			}
-		    }
-		    surf++;
-		} while (--c);
-	    } else if (dot > BACKFACE_EPSILON) {
-		do {
-		    if (!(surf->flags & SURF_PLANEBACK) &&
-			(surf->visframe == r_framecount)) {
-			if (r_drawpolys) {
-			    if (r_worldpolysbacktofront) {
-				if (numbtofpolys < MAX_BTOFPOLYS) {
-				    pbtofpolys[numbtofpolys].clipflags =
-					clipflags;
-				    pbtofpolys[numbtofpolys].psurf = surf;
-				    numbtofpolys++;
-				}
-			    } else {
-				R_RenderPoly(surf, clipflags);
-			    }
-			} else {
-			    R_RenderFace(surf, clipflags);
-			}
-		    }
-		    surf++;
-		} while (--c);
-	    }
-	    // all surfaces on the same node share the same sequence number
-	    r_currentkey++;
-	}
-	// recurse down the back side
-	R_RecursiveWorldNode(node->children[!side], clipflags);
-    }
-}
-
-
-
-/*
-================
-R_RenderWorld
-================
-*/
-void
-R_RenderWorld(void)
-{
-    int i;
-    model_t *clmodel;
-    btofpoly_t btofpolys[MAX_BTOFPOLYS];
-
-    pbtofpolys = btofpolys;
-
-#ifdef NQ_HACK
-    currententity = &cl_entities[0];
-#endif
-#ifdef QW_HACK
-    currententity = &r_worldentity;
-#endif
-    VectorCopy(r_origin, modelorg);
-    clmodel = currententity->model;
-    r_pcurrentvertbase = clmodel->vertexes;
-
-    R_RecursiveWorldNode(clmodel->nodes, 15);
-
-// if the driver wants the polygons back to front, play the visible ones back
-// in that order
-    if (r_worldpolysbacktofront) {
-	for (i = numbtofpolys - 1; i >= 0; i--) {
-	    R_RenderPoly(btofpolys[i].psurf, btofpolys[i].clipflags);
-	}
-    }
-}
diff -urN -X exclude a/QW/client/r_bsp.c head/QW/client/r_bsp.c
--- a/QW/client/r_bsp.c	2006-05-28 15:04:03.000000000 +0930
+++ head/QW/client/r_bsp.c	1970-01-01 09:30:00.000000000 +0930
@@ -1,615 +0,0 @@
-/*
-Copyright (C) 1996-1997 Id Software, Inc.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
-*/
-// r_bsp.c
-
-#include "quakedef.h"
-#include "r_local.h"
-#include "sys.h"
-#include "console.h"
-
-//
-// current entity info
-//
-qboolean insubmodel;
-entity_t *currententity;
-
-// modelorg is the viewpoint reletive to
-// the currently rendering entity
-vec3_t modelorg, base_modelorg;
-
-vec3_t r_entorigin;	// the currently rendering entity in world coordinates
-
-static float entity_rotation[3][3];
-
-vec3_t r_worldmodelorg;
-
-int r_currentbkey;
-
-typedef enum { touchessolid, drawnode, nodrawnode } solidstate_t;
-
-#define MAX_BMODEL_VERTS	500	// 6K
-#define MAX_BMODEL_EDGES	1000	// 12K
-
-static mvertex_t *pbverts;
-static bedge_t *pbedges;
-static int numbverts, numbedges;
-
-static mvertex_t *pfrontenter, *pfrontexit;
-
-static qboolean makeclippededge;
-
-
-//===========================================================================
-
-/*
-================
-R_EntityRotate
-================
-*/
-static void
-R_EntityRotate(vec3_t vec)
-{
-    vec3_t tvec;
-
-    VectorCopy(vec, tvec);
-    vec[0] = DotProduct(entity_rotation[0], tvec);
-    vec[1] = DotProduct(entity_rotation[1], tvec);
-    vec[2] = DotProduct(entity_rotation[2], tvec);
-}
-
-
-/*
-================
-R_RotateBmodel
-================
-*/
-void
-R_RotateBmodel(void)
-{
-    float angle, s, c, temp1[3][3], temp2[3][3], temp3[3][3];
-
-// TODO: should use a look-up table
-// TODO: should really be stored with the entity instead of being reconstructed
-// TODO: could cache lazily, stored in the entity
-// TODO: share work with R_SetUpAliasTransform
-
-// yaw
-    angle = currententity->angles[YAW];
-    angle = angle * M_PI * 2 / 360;
-    s = sin(angle);
-    c = cos(angle);
-
-    temp1[0][0] = c;
-    temp1[0][1] = s;
-    temp1[0][2] = 0;
-    temp1[1][0] = -s;
-    temp1[1][1] = c;
-    temp1[1][2] = 0;
-    temp1[2][0] = 0;
-    temp1[2][1] = 0;
-    temp1[2][2] = 1;
-
-// pitch
-    angle = currententity->angles[PITCH];
-    angle = angle * M_PI * 2 / 360;
-    s = sin(angle);
-    c = cos(angle);
-
-    temp2[0][0] = c;
-    temp2[0][1] = 0;
-    temp2[0][2] = -s;
-    temp2[1][0] = 0;
-    temp2[1][1] = 1;
-    temp2[1][2] = 0;
-    temp2[2][0] = s;
-    temp2[2][1] = 0;
-    temp2[2][2] = c;
-
-    R_ConcatRotations(temp2, temp1, temp3);
-
-// roll
-    angle = currententity->angles[ROLL];
-    angle = angle * M_PI * 2 / 360;
-    s = sin(angle);
-    c = cos(angle);
-
-    temp1[0][0] = 1;
-    temp1[0][1] = 0;
-    temp1[0][2] = 0;
-    temp1[1][0] = 0;
-    temp1[1][1] = c;
-    temp1[1][2] = s;
-    temp1[2][0] = 0;
-    temp1[2][1] = -s;
-    temp1[2][2] = c;
-
-    R_ConcatRotations(temp1, temp3, entity_rotation);
-
-//
-// rotate modelorg and the transformation matrix
-//
-    R_EntityRotate(modelorg);
-    R_EntityRotate(vpn);
-    R_EntityRotate(vright);
-    R_EntityRotate(vup);
-
-    R_TransformFrustum();
-}
-
-
-/*
-================
-R_RecursiveClipBPoly
-================
-*/
-static void
-R_RecursiveClipBPoly(bedge_t *pedges, mnode_t *pnode, msurface_t *psurf)
-{
-    bedge_t *psideedges[2], *pnextedge, *ptedge;
-    int i, side, lastside;
-    float dist, frac, lastdist;
-    mplane_t *splitplane, tplane;
-    mvertex_t *pvert, *plastvert, *ptvert;
-    mnode_t *pn;
-
-    psideedges[0] = psideedges[1] = NULL;
-
-    makeclippededge = false;
-
-// transform the BSP plane into model space
-// FIXME: cache these?
-    splitplane = pnode->plane;
-    tplane.dist = splitplane->dist -
-	DotProduct(r_entorigin, splitplane->normal);
-    tplane.normal[0] = DotProduct(entity_rotation[0], splitplane->normal);
-    tplane.normal[1] = DotProduct(entity_rotation[1], splitplane->normal);
-    tplane.normal[2] = DotProduct(entity_rotation[2], splitplane->normal);
-
-// clip edges to BSP plane
-    for (; pedges; pedges = pnextedge) {
-	pnextedge = pedges->pnext;
-
-	// set the status for the last point as the previous point
-	// FIXME: cache this stuff somehow?
-	plastvert = pedges->v[0];
-	lastdist = DotProduct(plastvert->position, tplane.normal) -
-	    tplane.dist;
-
-	if (lastdist > 0)
-	    lastside = 0;
-	else
-	    lastside = 1;
-
-	pvert = pedges->v[1];
-
-	dist = DotProduct(pvert->position, tplane.normal) - tplane.dist;
-
-	if (dist > 0)
-	    side = 0;
-	else
-	    side = 1;
-
-	if (side != lastside) {
-	    // clipped
-	    if (numbverts >= MAX_BMODEL_VERTS)
-		return;
-
-	    // generate the clipped vertex
-	    frac = lastdist / (lastdist - dist);
-	    ptvert = &pbverts[numbverts++];
-	    ptvert->position[0] = plastvert->position[0] +
-		frac * (pvert->position[0] - plastvert->position[0]);
-	    ptvert->position[1] = plastvert->position[1] +
-		frac * (pvert->position[1] - plastvert->position[1]);
-	    ptvert->position[2] = plastvert->position[2] +
-		frac * (pvert->position[2] - plastvert->position[2]);
-
-	    // split into two edges, one on each side, and remember entering
-	    // and exiting points
-	    // FIXME: share the clip edge by having a winding direction flag?
-	    if (numbedges >= (MAX_BMODEL_EDGES - 1)) {
-		Con_Printf("Out of edges for bmodel\n");
-		return;
-	    }
-
-	    ptedge = &pbedges[numbedges];
-	    ptedge->pnext = psideedges[lastside];
-	    psideedges[lastside] = ptedge;
-	    ptedge->v[0] = plastvert;
-	    ptedge->v[1] = ptvert;
-
-	    ptedge = &pbedges[numbedges + 1];
-	    ptedge->pnext = psideedges[side];
-	    psideedges[side] = ptedge;
-	    ptedge->v[0] = ptvert;
-	    ptedge->v[1] = pvert;
-
-	    numbedges += 2;
-
-	    if (side == 0) {
-		// entering for front, exiting for back
-		pfrontenter = ptvert;
-		makeclippededge = true;
-	    } else {
-		pfrontexit = ptvert;
-		makeclippededge = true;
-	    }
-	} else {
-	    // add the edge to the appropriate side
-	    pedges->pnext = psideedges[side];
-	    psideedges[side] = pedges;
-	}
-    }
-
-// if anything was clipped, reconstitute and add the edges along the clip
-// plane to both sides (but in opposite directions)
-    if (makeclippededge) {
-	if (numbedges >= (MAX_BMODEL_EDGES - 2)) {
-	    Con_Printf("Out of edges for bmodel\n");
-	    return;
-	}
-
-	ptedge = &pbedges[numbedges];
-	ptedge->pnext = psideedges[0];
-	psideedges[0] = ptedge;
-	ptedge->v[0] = pfrontexit;
-	ptedge->v[1] = pfrontenter;
-
-	ptedge = &pbedges[numbedges + 1];
-	ptedge->pnext = psideedges[1];
-	psideedges[1] = ptedge;
-	ptedge->v[0] = pfrontenter;
-	ptedge->v[1] = pfrontexit;
-
-	numbedges += 2;
-    }
-
-    /* draw or recurse further */
-    for (i = 0; i < 2; i++) {
-	if (psideedges[i]) {
-	    /*
-	     * draw if we've reached a non-solid leaf, done if all that's left
-	     * is a solid leaf, and continue down the tree if it's not a leaf
-	     */
-	    pn = pnode->children[i];
-
-	    // we're done with this branch if the node or leaf isn't in the PVS
-	    if (pn->visframe == r_visframecount) {
-		if (pn->contents < 0) {
-		    if (pn->contents != CONTENTS_SOLID) {
-			r_currentbkey = ((mleaf_t *)pn)->key;
-			R_RenderBmodelFace(psideedges[i], psurf);
-		    }
-		} else {
-		    R_RecursiveClipBPoly(psideedges[i], pnode->children[i],
-					 psurf);
-		}
-	    }
-	}
-    }
-}
-
-
-/*
-================
-R_DrawSolidClippedSubmodelPolygons
-================
-*/
-void
-R_DrawSolidClippedSubmodelPolygons(model_t *pmodel)
-{
-    int i, j, lindex;
-    vec_t dot;
-    msurface_t *psurf;
-    int numsurfaces;
-    mplane_t *pplane;
-    mvertex_t bverts[MAX_BMODEL_VERTS];
-    bedge_t bedges[MAX_BMODEL_EDGES], *pbedge;
-    medge_t *pedge, *pedges;
-
-// FIXME: use bounding-box-based frustum clipping info?
-
-    psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
-    numsurfaces = pmodel->nummodelsurfaces;
-    pedges = pmodel->edges;
-
-    for (i = 0; i < numsurfaces; i++, psurf++) {
-	// find which side of the node we are on
-	pplane = psurf->plane;
-
-	dot = DotProduct(modelorg, pplane->normal) - pplane->dist;
-
-	// draw the polygon
-	if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
-	    (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) {
-	    // FIXME: use bounding-box-based frustum clipping info?
-
-	    // copy the edges to bedges, flipping if necessary so always
-	    // clockwise winding
-
-	    /*
-	     * FIXME: if edges and vertices get caches, these assignments must
-	     * move outside the loop, and overflow checking must be done here
-	     */
-	    pbverts = bverts;
-	    pbedges = bedges;
-	    numbverts = numbedges = 0;
-
-	    if (psurf->numedges > 0) {
-		pbedge = &bedges[numbedges];
-		numbedges += psurf->numedges;
-
-		for (j = 0; j < psurf->numedges; j++) {
-		    lindex = pmodel->surfedges[psurf->firstedge + j];
-
-		    if (lindex > 0) {
-			pedge = &pedges[lindex];
-			pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[0]];
-			pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[1]];
-		    } else {
-			lindex = -lindex;
-			pedge = &pedges[lindex];
-			pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[1]];
-			pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[0]];
-		    }
-		    pbedge[j].pnext = &pbedge[j + 1];
-		}
-		pbedge[j - 1].pnext = NULL;	// mark end of edges
-
-		R_RecursiveClipBPoly(pbedge, currententity->topnode, psurf);
-	    } else {
-		Sys_Error("no edges in bmodel");
-	    }
-	}
-    }
-}
-
-
-/*
-================
-R_DrawSubmodelPolygons
-================
-*/
-void
-R_DrawSubmodelPolygons(model_t *pmodel, int clipflags)
-{
-    int i;
-    vec_t dot;
-    msurface_t *psurf;
-    int numsurfaces;
-    mplane_t *pplane;
-
-// FIXME: use bounding-box-based frustum clipping info?
-
-    psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
-    numsurfaces = pmodel->nummodelsurfaces;
-
-    for (i = 0; i < numsurfaces; i++, psurf++) {
-	// find which side of the node we are on
-	pplane = psurf->plane;
-
-	dot = DotProduct(modelorg, pplane->normal) - pplane->dist;
-
-	// draw the polygon
-	if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
-	    (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) {
-	    r_currentkey = ((mleaf_t *)currententity->topnode)->key;
-
-	    // FIXME: use bounding-box-based frustum clipping info?
-	    R_RenderFace(psurf, clipflags);
-	}
-    }
-}
-
-
-/*
-================
-R_RecursiveWorldNode
-================
-*/
-static void
-R_RecursiveWorldNode(mnode_t *node, int clipflags)
-{
-    int i, c, side, *pindex;
-    vec3_t acceptpt, rejectpt;
-    mplane_t *plane;
-    msurface_t *surf, **mark;
-    mleaf_t *pleaf;
-    double d, dot;
-
-    if (node->contents == CONTENTS_SOLID)
-	return;			// solid
-
-    if (node->visframe != r_visframecount)
-	return;
-
-// cull the clipping planes if not trivial accept
-// FIXME: the compiler is doing a lousy job of optimizing here; it could be
-//  twice as fast in ASM
-    if (clipflags) {
-	for (i = 0; i < 4; i++) {
-	    if (!(clipflags & (1 << i)))
-		continue;	// don't need to clip against it
-
-	    // generate accept and reject points
-	    // FIXME: do with fast look-ups or integer tests based on the sign
-	    // bit of the floating point values
-
-	    pindex = pfrustum_indexes[i];
-
-	    rejectpt[0] = (float)node->minmaxs[pindex[0]];
-	    rejectpt[1] = (float)node->minmaxs[pindex[1]];
-	    rejectpt[2] = (float)node->minmaxs[pindex[2]];
-
-	    d = DotProduct(rejectpt, view_clipplanes[i].normal);
-	    d -= view_clipplanes[i].dist;
-
-	    if (d <= 0)
-		return;
-
-	    acceptpt[0] = (float)node->minmaxs[pindex[3 + 0]];
-	    acceptpt[1] = (float)node->minmaxs[pindex[3 + 1]];
-	    acceptpt[2] = (float)node->minmaxs[pindex[3 + 2]];
-
-	    d = DotProduct(acceptpt, view_clipplanes[i].normal);
-	    d -= view_clipplanes[i].dist;
-
-	    if (d >= 0)
-		clipflags &= ~(1 << i);	// node is entirely on screen
-	}
-    }
-
-    /* if a leaf node, draw stuff */
-    if (node->contents < 0) {
-	pleaf = (mleaf_t *)node;
-
-	mark = pleaf->firstmarksurface;
-	c = pleaf->nummarksurfaces;
-
-	if (c) {
-	    do {
-		(*mark)->visframe = r_framecount;
-		mark++;
-	    } while (--c);
-	}
-
-	// deal with model fragments in this leaf
-	if (pleaf->efrags) {
-	    R_StoreEfrags(&pleaf->efrags);
-	}
-
-	pleaf->key = r_currentkey;
-	r_currentkey++;		// all bmodels in a leaf share the same key
-    } else {
-	// node is just a decision point, so go down the apropriate sides
-	// find which side of the node we are on
-	plane = node->plane;
-	switch (plane->type) {
-	case PLANE_X:
-	    dot = modelorg[0] - plane->dist;
-	    break;
-	case PLANE_Y:
-	    dot = modelorg[1] - plane->dist;
-	    break;
-	case PLANE_Z:
-	    dot = modelorg[2] - plane->dist;
-	    break;
-	default:
-	    dot = DotProduct(modelorg, plane->normal) - plane->dist;
-	    break;
-	}
-	side = (dot >= 0) ? 0 : 1;
-
-	// recurse down the children, front side first
-	R_RecursiveWorldNode(node->children[side], clipflags);
-
-	// draw stuff
-	c = node->numsurfaces;
-
-	if (c) {
-	    surf = cl.worldmodel->surfaces + node->firstsurface;
-
-	    if (dot < -BACKFACE_EPSILON) {
-		do {
-		    if ((surf->flags & SURF_PLANEBACK) &&
-			(surf->visframe == r_framecount)) {
-			if (r_drawpolys) {
-			    if (r_worldpolysbacktofront) {
-				if (numbtofpolys < MAX_BTOFPOLYS) {
-				    pbtofpolys[numbtofpolys].clipflags =
-					clipflags;
-				    pbtofpolys[numbtofpolys].psurf = surf;
-				    numbtofpolys++;
-				}
-			    } else {
-				R_RenderPoly(surf, clipflags);
-			    }
-			} else {
-			    R_RenderFace(surf, clipflags);
-			}
-		    }
-		    surf++;
-		} while (--c);
-	    } else if (dot > BACKFACE_EPSILON) {
-		do {
-		    if (!(surf->flags & SURF_PLANEBACK) &&
-			(surf->visframe == r_framecount)) {
-			if (r_drawpolys) {
-			    if (r_worldpolysbacktofront) {
-				if (numbtofpolys < MAX_BTOFPOLYS) {
-				    pbtofpolys[numbtofpolys].clipflags =
-					clipflags;
-				    pbtofpolys[numbtofpolys].psurf = surf;
-				    numbtofpolys++;
-				}
-			    } else {
-				R_RenderPoly(surf, clipflags);
-			    }
-			} else {
-			    R_RenderFace(surf, clipflags);
-			}
-		    }
-		    surf++;
-		} while (--c);
-	    }
-	    // all surfaces on the same node share the same sequence number
-	    r_currentkey++;
-	}
-	// recurse down the back side
-	R_RecursiveWorldNode(node->children[!side], clipflags);
-    }
-}
-
-
-
-/*
-================
-R_RenderWorld
-================
-*/
-void
-R_RenderWorld(void)
-{
-    int i;
-    model_t *clmodel;
-    btofpoly_t btofpolys[MAX_BTOFPOLYS];
-
-    pbtofpolys = btofpolys;
-
-#ifdef NQ_HACK
-    currententity = &cl_entities[0];
-#endif
-#ifdef QW_HACK
-    currententity = &r_worldentity;
-#endif
-    VectorCopy(r_origin, modelorg);
-    clmodel = currententity->model;
-    r_pcurrentvertbase = clmodel->vertexes;
-
-    R_RecursiveWorldNode(clmodel->nodes, 15);
-
-// if the driver wants the polygons back to front, play the visible ones back
-// in that order
-    if (r_worldpolysbacktofront) {
-	for (i = numbtofpolys - 1; i >= 0; i--) {
-	    R_RenderPoly(btofpolys[i].psurf, btofpolys[i].clipflags);
-	}
-    }
-}
diff -urN -X exclude a/common/r_bsp.c head/common/r_bsp.c
--- a/common/r_bsp.c	1970-01-01 09:30:00.000000000 +0930
+++ head/common/r_bsp.c	2006-05-28 14:59:13.000000000 +0930
@@ -0,0 +1,615 @@
+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// r_bsp.c
+
+#include "quakedef.h"
+#include "r_local.h"
+#include "sys.h"
+#include "console.h"
+
+//
+// current entity info
+//
+qboolean insubmodel;
+entity_t *currententity;
+
+// modelorg is the viewpoint reletive to
+// the currently rendering entity
+vec3_t modelorg, base_modelorg;
+
+vec3_t r_entorigin;	// the currently rendering entity in world coordinates
+
+static float entity_rotation[3][3];
+
+vec3_t r_worldmodelorg;
+
+int r_currentbkey;
+
+typedef enum { touchessolid, drawnode, nodrawnode } solidstate_t;
+
+#define MAX_BMODEL_VERTS	500	// 6K
+#define MAX_BMODEL_EDGES	1000	// 12K
+
+static mvertex_t *pbverts;
+static bedge_t *pbedges;
+static int numbverts, numbedges;
+
+static mvertex_t *pfrontenter, *pfrontexit;
+
+static qboolean makeclippededge;
+
+
+//===========================================================================
+
+/*
+================
+R_EntityRotate
+================
+*/
+static void
+R_EntityRotate(vec3_t vec)
+{
+    vec3_t tvec;
+
+    VectorCopy(vec, tvec);
+    vec[0] = DotProduct(entity_rotation[0], tvec);
+    vec[1] = DotProduct(entity_rotation[1], tvec);
+    vec[2] = DotProduct(entity_rotation[2], tvec);
+}
+
+
+/*
+================
+R_RotateBmodel
+================
+*/
+void
+R_RotateBmodel(void)
+{
+    float angle, s, c, temp1[3][3], temp2[3][3], temp3[3][3];
+
+// TODO: should use a look-up table
+// TODO: should really be stored with the entity instead of being reconstructed
+// TODO: could cache lazily, stored in the entity
+// TODO: share work with R_SetUpAliasTransform
+
+// yaw
+    angle = currententity->angles[YAW];
+    angle = angle * M_PI * 2 / 360;
+    s = sin(angle);
+    c = cos(angle);
+
+    temp1[0][0] = c;
+    temp1[0][1] = s;
+    temp1[0][2] = 0;
+    temp1[1][0] = -s;
+    temp1[1][1] = c;
+    temp1[1][2] = 0;
+    temp1[2][0] = 0;
+    temp1[2][1] = 0;
+    temp1[2][2] = 1;
+
+// pitch
+    angle = currententity->angles[PITCH];
+    angle = angle * M_PI * 2 / 360;
+    s = sin(angle);
+    c = cos(angle);
+
+    temp2[0][0] = c;
+    temp2[0][1] = 0;
+    temp2[0][2] = -s;
+    temp2[1][0] = 0;
+    temp2[1][1] = 1;
+    temp2[1][2] = 0;
+    temp2[2][0] = s;
+    temp2[2][1] = 0;
+    temp2[2][2] = c;
+
+    R_ConcatRotations(temp2, temp1, temp3);
+
+// roll
+    angle = currententity->angles[ROLL];
+    angle = angle * M_PI * 2 / 360;
+    s = sin(angle);
+    c = cos(angle);
+
+    temp1[0][0] = 1;
+    temp1[0][1] = 0;
+    temp1[0][2] = 0;
+    temp1[1][0] = 0;
+    temp1[1][1] = c;
+    temp1[1][2] = s;
+    temp1[2][0] = 0;
+    temp1[2][1] = -s;
+    temp1[2][2] = c;
+
+    R_ConcatRotations(temp1, temp3, entity_rotation);
+
+//
+// rotate modelorg and the transformation matrix
+//
+    R_EntityRotate(modelorg);
+    R_EntityRotate(vpn);
+    R_EntityRotate(vright);
+    R_EntityRotate(vup);
+
+    R_TransformFrustum();
+}
+
+
+/*
+================
+R_RecursiveClipBPoly
+================
+*/
+static void
+R_RecursiveClipBPoly(bedge_t *pedges, mnode_t *pnode, msurface_t *psurf)
+{
+    bedge_t *psideedges[2], *pnextedge, *ptedge;
+    int i, side, lastside;
+    float dist, frac, lastdist;
+    mplane_t *splitplane, tplane;
+    mvertex_t *pvert, *plastvert, *ptvert;
+    mnode_t *pn;
+
+    psideedges[0] = psideedges[1] = NULL;
+
+    makeclippededge = false;
+
+// transform the BSP plane into model space
+// FIXME: cache these?
+    splitplane = pnode->plane;
+    tplane.dist = splitplane->dist -
+	DotProduct(r_entorigin, splitplane->normal);
+    tplane.normal[0] = DotProduct(entity_rotation[0], splitplane->normal);
+    tplane.normal[1] = DotProduct(entity_rotation[1], splitplane->normal);
+    tplane.normal[2] = DotProduct(entity_rotation[2], splitplane->normal);
+
+// clip edges to BSP plane
+    for (; pedges; pedges = pnextedge) {
+	pnextedge = pedges->pnext;
+
+	// set the status for the last point as the previous point
+	// FIXME: cache this stuff somehow?
+	plastvert = pedges->v[0];
+	lastdist = DotProduct(plastvert->position, tplane.normal) -
+	    tplane.dist;
+
+	if (lastdist > 0)
+	    lastside = 0;
+	else
+	    lastside = 1;
+
+	pvert = pedges->v[1];
+
+	dist = DotProduct(pvert->position, tplane.normal) - tplane.dist;
+
+	if (dist > 0)
+	    side = 0;
+	else
+	    side = 1;
+
+	if (side != lastside) {
+	    // clipped
+	    if (numbverts >= MAX_BMODEL_VERTS)
+		return;
+
+	    // generate the clipped vertex
+	    frac = lastdist / (lastdist - dist);
+	    ptvert = &pbverts[numbverts++];
+	    ptvert->position[0] = plastvert->position[0] +
+		frac * (pvert->position[0] - plastvert->position[0]);
+	    ptvert->position[1] = plastvert->position[1] +
+		frac * (pvert->position[1] - plastvert->position[1]);
+	    ptvert->position[2] = plastvert->position[2] +
+		frac * (pvert->position[2] - plastvert->position[2]);
+
+	    // split into two edges, one on each side, and remember entering
+	    // and exiting points
+	    // FIXME: share the clip edge by having a winding direction flag?
+	    if (numbedges >= (MAX_BMODEL_EDGES - 1)) {
+		Con_Printf("Out of edges for bmodel\n");
+		return;
+	    }
+
+	    ptedge = &pbedges[numbedges];
+	    ptedge->pnext = psideedges[lastside];
+	    psideedges[lastside] = ptedge;
+	    ptedge->v[0] = plastvert;
+	    ptedge->v[1] = ptvert;
+
+	    ptedge = &pbedges[numbedges + 1];
+	    ptedge->pnext = psideedges[side];
+	    psideedges[side] = ptedge;
+	    ptedge->v[0] = ptvert;
+	    ptedge->v[1] = pvert;
+
+	    numbedges += 2;
+
+	    if (side == 0) {
+		// entering for front, exiting for back
+		pfrontenter = ptvert;
+		makeclippededge = true;
+	    } else {
+		pfrontexit = ptvert;
+		makeclippededge = true;
+	    }
+	} else {
+	    // add the edge to the appropriate side
+	    pedges->pnext = psideedges[side];
+	    psideedges[side] = pedges;
+	}
+    }
+
+// if anything was clipped, reconstitute and add the edges along the clip
+// plane to both sides (but in opposite directions)
+    if (makeclippededge) {
+	if (numbedges >= (MAX_BMODEL_EDGES - 2)) {
+	    Con_Printf("Out of edges for bmodel\n");
+	    return;
+	}
+
+	ptedge = &pbedges[numbedges];
+	ptedge->pnext = psideedges[0];
+	psideedges[0] = ptedge;
+	ptedge->v[0] = pfrontexit;
+	ptedge->v[1] = pfrontenter;
+
+	ptedge = &pbedges[numbedges + 1];
+	ptedge->pnext = psideedges[1];
+	psideedges[1] = ptedge;
+	ptedge->v[0] = pfrontenter;
+	ptedge->v[1] = pfrontexit;
+
+	numbedges += 2;
+    }
+
+    /* draw or recurse further */
+    for (i = 0; i < 2; i++) {
+	if (psideedges[i]) {
+	    /*
+	     * draw if we've reached a non-solid leaf, done if all that's left
+	     * is a solid leaf, and continue down the tree if it's not a leaf
+	     */
+	    pn = pnode->children[i];
+
+	    // we're done with this branch if the node or leaf isn't in the PVS
+	    if (pn->visframe == r_visframecount) {
+		if (pn->contents < 0) {
+		    if (pn->contents != CONTENTS_SOLID) {
+			r_currentbkey = ((mleaf_t *)pn)->key;
+			R_RenderBmodelFace(psideedges[i], psurf);
+		    }
+		} else {
+		    R_RecursiveClipBPoly(psideedges[i], pnode->children[i],
+					 psurf);
+		}
+	    }
+	}
+    }
+}
+
+
+/*
+================
+R_DrawSolidClippedSubmodelPolygons
+================
+*/
+void
+R_DrawSolidClippedSubmodelPolygons(model_t *pmodel)
+{
+    int i, j, lindex;
+    vec_t dot;
+    msurface_t *psurf;
+    int numsurfaces;
+    mplane_t *pplane;
+    mvertex_t bverts[MAX_BMODEL_VERTS];
+    bedge_t bedges[MAX_BMODEL_EDGES], *pbedge;
+    medge_t *pedge, *pedges;
+
+// FIXME: use bounding-box-based frustum clipping info?
+
+    psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
+    numsurfaces = pmodel->nummodelsurfaces;
+    pedges = pmodel->edges;
+
+    for (i = 0; i < numsurfaces; i++, psurf++) {
+	// find which side of the node we are on
+	pplane = psurf->plane;
+
+	dot = DotProduct(modelorg, pplane->normal) - pplane->dist;
+
+	// draw the polygon
+	if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
+	    (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) {
+	    // FIXME: use bounding-box-based frustum clipping info?
+
+	    // copy the edges to bedges, flipping if necessary so always
+	    // clockwise winding
+
+	    /*
+	     * FIXME: if edges and vertices get caches, these assignments must
+	     * move outside the loop, and overflow checking must be done here
+	     */
+	    pbverts = bverts;
+	    pbedges = bedges;
+	    numbverts = numbedges = 0;
+
+	    if (psurf->numedges > 0) {
+		pbedge = &bedges[numbedges];
+		numbedges += psurf->numedges;
+
+		for (j = 0; j < psurf->numedges; j++) {
+		    lindex = pmodel->surfedges[psurf->firstedge + j];
+
+		    if (lindex > 0) {
+			pedge = &pedges[lindex];
+			pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[0]];
+			pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[1]];
+		    } else {
+			lindex = -lindex;
+			pedge = &pedges[lindex];
+			pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[1]];
+			pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[0]];
+		    }
+		    pbedge[j].pnext = &pbedge[j + 1];
+		}
+		pbedge[j - 1].pnext = NULL;	// mark end of edges
+
+		R_RecursiveClipBPoly(pbedge, currententity->topnode, psurf);
+	    } else {
+		Sys_Error("no edges in bmodel");
+	    }
+	}
+    }
+}
+
+
+/*
+================
+R_DrawSubmodelPolygons
+================
+*/
+void
+R_DrawSubmodelPolygons(model_t *pmodel, int clipflags)
+{
+    int i;
+    vec_t dot;
+    msurface_t *psurf;
+    int numsurfaces;
+    mplane_t *pplane;
+
+// FIXME: use bounding-box-based frustum clipping info?
+
+    psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
+    numsurfaces = pmodel->nummodelsurfaces;
+
+    for (i = 0; i < numsurfaces; i++, psurf++) {
+	// find which side of the node we are on
+	pplane = psurf->plane;
+
+	dot = DotProduct(modelorg, pplane->normal) - pplane->dist;
+
+	// draw the polygon
+	if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
+	    (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) {
+	    r_currentkey = ((mleaf_t *)currententity->topnode)->key;
+
+	    // FIXME: use bounding-box-based frustum clipping info?
+	    R_RenderFace(psurf, clipflags);
+	}
+    }
+}
+
+
+/*
+================
+R_RecursiveWorldNode
+================
+*/
+static void
+R_RecursiveWorldNode(mnode_t *node, int clipflags)
+{
+    int i, c, side, *pindex;
+    vec3_t acceptpt, rejectpt;
+    mplane_t *plane;
+    msurface_t *surf, **mark;
+    mleaf_t *pleaf;
+    double d, dot;
+
+    if (node->contents == CONTENTS_SOLID)
+	return;			// solid
+
+    if (node->visframe != r_visframecount)
+	return;
+
+// cull the clipping planes if not trivial accept
+// FIXME: the compiler is doing a lousy job of optimizing here; it could be
+//  twice as fast in ASM
+    if (clipflags) {
+	for (i = 0; i < 4; i++) {
+	    if (!(clipflags & (1 << i)))
+		continue;	// don't need to clip against it
+
+	    // generate accept and reject points
+	    // FIXME: do with fast look-ups or integer tests based on the sign
+	    // bit of the floating point values
+
+	    pindex = pfrustum_indexes[i];
+
+	    rejectpt[0] = (float)node->minmaxs[pindex[0]];
+	    rejectpt[1] = (float)node->minmaxs[pindex[1]];
+	    rejectpt[2] = (float)node->minmaxs[pindex[2]];
+
+	    d = DotProduct(rejectpt, view_clipplanes[i].normal);
+	    d -= view_clipplanes[i].dist;
+
+	    if (d <= 0)
+		return;
+
+	    acceptpt[0] = (float)node->minmaxs[pindex[3 + 0]];
+	    acceptpt[1] = (float)node->minmaxs[pindex[3 + 1]];
+	    acceptpt[2] = (float)node->minmaxs[pindex[3 + 2]];
+
+	    d = DotProduct(acceptpt, view_clipplanes[i].normal);
+	    d -= view_clipplanes[i].dist;
+
+	    if (d >= 0)
+		clipflags &= ~(1 << i);	// node is entirely on screen
+	}
+    }
+
+    /* if a leaf node, draw stuff */
+    if (node->contents < 0) {
+	pleaf = (mleaf_t *)node;
+
+	mark = pleaf->firstmarksurface;
+	c = pleaf->nummarksurfaces;
+
+	if (c) {
+	    do {
+		(*mark)->visframe = r_framecount;
+		mark++;
+	    } while (--c);
+	}
+
+	// deal with model fragments in this leaf
+	if (pleaf->efrags) {
+	    R_StoreEfrags(&pleaf->efrags);
+	}
+
+	pleaf->key = r_currentkey;
+	r_currentkey++;		// all bmodels in a leaf share the same key
+    } else {
+	// node is just a decision point, so go down the apropriate sides
+	// find which side of the node we are on
+	plane = node->plane;
+	switch (plane->type) {
+	case PLANE_X:
+	    dot = modelorg[0] - plane->dist;
+	    break;
+	case PLANE_Y:
+	    dot = modelorg[1] - plane->dist;
+	    break;
+	case PLANE_Z:
+	    dot = modelorg[2] - plane->dist;
+	    break;
+	default:
+	    dot = DotProduct(modelorg, plane->normal) - plane->dist;
+	    break;
+	}
+	side = (dot >= 0) ? 0 : 1;
+
+	// recurse down the children, front side first
+	R_RecursiveWorldNode(node->children[side], clipflags);
+
+	// draw stuff
+	c = node->numsurfaces;
+
+	if (c) {
+	    surf = cl.worldmodel->surfaces + node->firstsurface;
+
+	    if (dot < -BACKFACE_EPSILON) {
+		do {
+		    if ((surf->flags & SURF_PLANEBACK) &&
+			(surf->visframe == r_framecount)) {
+			if (r_drawpolys) {
+			    if (r_worldpolysbacktofront) {
+				if (numbtofpolys < MAX_BTOFPOLYS) {
+				    pbtofpolys[numbtofpolys].clipflags =
+					clipflags;
+				    pbtofpolys[numbtofpolys].psurf = surf;
+				    numbtofpolys++;
+				}
+			    } else {
+				R_RenderPoly(surf, clipflags);
+			    }
+			} else {
+			    R_RenderFace(surf, clipflags);
+			}
+		    }
+		    surf++;
+		} while (--c);
+	    } else if (dot > BACKFACE_EPSILON) {
+		do {
+		    if (!(surf->flags & SURF_PLANEBACK) &&
+			(surf->visframe == r_framecount)) {
+			if (r_drawpolys) {
+			    if (r_worldpolysbacktofront) {
+				if (numbtofpolys < MAX_BTOFPOLYS) {
+				    pbtofpolys[numbtofpolys].clipflags =
+					clipflags;
+				    pbtofpolys[numbtofpolys].psurf = surf;
+				    numbtofpolys++;
+				}
+			    } else {
+				R_RenderPoly(surf, clipflags);
+			    }
+			} else {
+			    R_RenderFace(surf, clipflags);
+			}
+		    }
+		    surf++;
+		} while (--c);
+	    }
+	    // all surfaces on the same node share the same sequence number
+	    r_currentkey++;
+	}
+	// recurse down the back side
+	R_RecursiveWorldNode(node->children[!side], clipflags);
+    }
+}
+
+
+
+/*
+================
+R_RenderWorld
+================
+*/
+void
+R_RenderWorld(void)
+{
+    int i;
+    model_t *clmodel;
+    btofpoly_t btofpolys[MAX_BTOFPOLYS];
+
+    pbtofpolys = btofpolys;
+
+#ifdef NQ_HACK
+    currententity = &cl_entities[0];
+#endif
+#ifdef QW_HACK
+    currententity = &r_worldentity;
+#endif
+    VectorCopy(r_origin, modelorg);
+    clmodel = currententity->model;
+    r_pcurrentvertbase = clmodel->vertexes;
+
+    R_RecursiveWorldNode(clmodel->nodes, 15);
+
+// if the driver wants the polygons back to front, play the visible ones back
+// in that order
+    if (r_worldpolysbacktofront) {
+	for (i = numbtofpolys - 1; i >= 0; i--) {
+	    R_RenderPoly(btofpolys[i].psurf, btofpolys[i].clipflags);
+	}
+    }
+}
