/* ================ R_DrawSolidClippedSubmodelPolygons Bmodel crosses multiple leafs ================ */ void R_DrawSolidClippedSubmodelPolygons(mmodel_t *pmodel, mnode_t *topnode) { int i, j; vec_t dot; mface_t *psurf; int numsurfaces; cplane_t *pplane; mvertex_t bverts[MAX_BMODEL_VERTS]; bedge_t bedges[MAX_BMODEL_EDGES], *pbedge; msurfedge_t *surfedge; // FIXME: use bounding-box-based frustum clipping info? psurf = pmodel->firstface; numsurfaces = pmodel->numfaces; for (i = 0; i < numsurfaces; i++, psurf++) { // find which side of the node we are on pplane = psurf->plane; dot = PlaneDiff(modelorg, pplane); // draw the polygon if ((!(psurf->drawflags & DSURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || ((psurf->drawflags & DSURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) continue; // 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; pbedge = &bedges[numbedges]; numbedges += psurf->numsurfedges; if (numbedges >= MAX_BMODEL_EDGES) { Com_Printf("Out of edges for bmodel\n"); return; } surfedge = psurf->firstsurfedge; for (j = 0; j < psurf->numsurfedges; j++, surfedge++) { pbedge[j].v[0] = surfedge->edge->v[surfedge->vert ]; pbedge[j].v[1] = surfedge->edge->v[surfedge->vert ^ 1]; pbedge[j].pnext = &pbedge[j + 1]; } pbedge[j - 1].pnext = NULL; // mark end of edges if (!(psurf->texinfo->c.flags & SURF_TRANS_MASK)) R_RecursiveClipBPoly(pbedge, topnode, psurf); else R_RenderBmodelFace(pbedge, psurf); } }
/* ================ R_DrawSolidClippedSubmodelPolygons ================ */ void R_DrawSolidClippedSubmodelPolygons(const entity_t *e, model_t *pmodel) { int i, j, lindex; msurface_t *psurf; int numsurfaces; mvertex_t bverts[MAX_BMODEL_VERTS]; bedge_t bedges[MAX_BMODEL_EDGES], *pbedge; medge_t *pedge, *pedges; psurf = &pmodel->surfaces[pmodel->firstmodelsurface]; numsurfaces = pmodel->nummodelsurfaces; pedges = pmodel->edges; for (i = 0; i < numsurfaces; i++, psurf++) { if (psurf->clipflags == BMODEL_FULLY_CLIPPED) continue; // draw the polygon // 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; 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(e, pbedge, e->topnode, psurf); } }
/* ================ R_RecursiveClipBPoly Clip a bmodel poly down the world bsp tree ================ */ static void R_RecursiveClipBPoly(bedge_t *pedges, mnode_t *pnode, mface_t *psurf) { bedge_t *psideedges[2], *pnextedge, *ptedge; int i, side, lastside; float dist, frac, lastdist; cplane_t *splitplane, tplane; mvertex_t *pvert, *plastvert, *ptvert; mnode_t *pn; int area; psideedges[0] = psideedges[1] = NULL; makeclippededge = qfalse; // transform the BSP plane into model space // FIXME: cache these? splitplane = pnode->plane; tplane.dist = -PlaneDiff(r_entorigin, splitplane); 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 = PlaneDiff(plastvert->point, &tplane); if (lastdist > 0) lastside = 0; else lastside = 1; pvert = pedges->v[1]; dist = PlaneDiff(pvert->point, &tplane); 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++]; LerpVector(plastvert->point, pvert->point, frac, ptvert->point); // 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)) { Com_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 = qtrue; } else { pfrontexit = ptvert; makeclippededge = qtrue; } } 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)) { Com_Error(ERR_DROP, "Out of edges for bmodel"); } 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->plane) { mleaf_t *pl = (mleaf_t *)pn; if (pl->contents != CONTENTS_SOLID) { if (r_newrefdef.areabits) { area = pl->area; if (!Q_IsBitSet(r_newrefdef.areabits, area)) continue; // not visible } r_currentbkey = pl->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"); } } } }