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 = -PlaneDiff(r_entorigin, splitplane); tplane.normal[0] = PlaneDist (entity_rotation[0], splitplane); tplane.normal[1] = PlaneDist (entity_rotation[1], splitplane); tplane.normal[2] = PlaneDist (entity_rotation[2], splitplane); // 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; lastside = (lastdist <= 0); pvert = pedges->v[1]; dist = DotProduct (pvert->position, tplane.normal) - tplane.dist; side = (dist <= 0); 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)) { 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 = 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)) { Com_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); } } } } }
static void ddDrawPlane(const Plane& plane, const AABB& bounds, const Color& color) { vec3 points[6]; struct edge_t { int start; int end; }; static const edge_t edges[12] = { // bottom {0, 1}, {1, 3}, {3, 2}, {2, 0}, // top {4, 5}, {5, 7}, {7, 6}, {6, 4}, // top to bottom sides {0, 4}, {1, 5}, {2, 6}, {3, 7}, }; // clip plane to bounds and render a quad vec3 corners[8]; const vec3 *minmax[2] = { &bounds.m_min, &bounds.m_max }; for(int j = 0; j < 8; ++j) { int iz = j & 1; int ix = (j >> 1) & 1; int iy = (j >> 2) & 1; corners[j].Set(minmax[ix]->x, minmax[iy]->y, minmax[iz]->z); } int numPoints = 0; // add corners as points if they are close to the plane for(int j = 0; j < 8; ++j) { float planeDist = PlaneDist(plane, corners[j]); if(fabs(planeDist) < EPSILON) points[numPoints++] = corners[j]; } // add edge intersections for(int j = 0; j < 12; ++j) { vec3 a = corners[edges[j].start], b = corners[edges[j].end], ab = b - a; // intersect edge with plane float t = (-plane.m_d - Dot(plane.m_n, a)) / Dot(plane.m_n, ab); if(t >= 0.f && t <= 1.f) { vec3 pt = a + t * ab, ptA = a - pt, ptB = b - pt; float distSqA = LengthSq(ptA); float distSqB = LengthSq(ptB); if(distSqA > EPSILON_SQ && distSqB > EPSILON_SQ) { points[numPoints++] = pt; if(numPoints == 6) break; } } } if(numPoints < 3) return; // Sort results const float inv_num = 1.f / numPoints; vec3 center = {0,0,0}; for(int j = 0; j < numPoints; ++j) center += inv_num * points[j]; vec3 sideVec = Normalize(points[0] - center); vec3 upVec = Normalize(Cross(plane.m_n, sideVec)); for(int j = 1; j < numPoints; ++j) { vec3 toPointJ = points[j] - center; float angleJ = AngleWrap(atan2(Dot(upVec, toPointJ), Dot(sideVec, toPointJ))); for(int k = j+1; k < numPoints; ++k) { vec3 toPointK = points[k] - center; float angleK = AngleWrap(atan2(Dot(upVec, toPointK), Dot(sideVec, toPointK))); if(angleK < angleJ) { angleJ = angleK; std::swap(points[j], points[k]); } } } // Draw outline const ShaderInfo* shader = g_dbgdrawShader.get(); GLint posLoc = shader->m_attrs[GEOM_Pos]; GLint colorLoc = shader->m_attrs[GEOM_Color]; glVertexAttrib3fv(colorLoc, &color.r); glLineWidth(2.f); glBegin(GL_LINES); for(int j = 0; j < numPoints; ++j) { int next = (j + 1) % numPoints; glVertexAttrib3fv(posLoc, &points[j].x); glVertexAttrib3fv(posLoc, &points[next].x); } glEnd(); glLineWidth(1.f); // Draw triangles glVertexAttrib3fv(colorLoc, &color.r); glBegin(GL_TRIANGLE_FAN); glVertexAttrib3fv(posLoc, ¢er.x); for(int j = 0; j < numPoints; ++j) glVertexAttrib3fv(posLoc, &points[j].x); glVertexAttrib3fv(posLoc, &points[0].x); glEnd(); glBegin(GL_TRIANGLE_FAN); glVertexAttrib3fv(posLoc, ¢er.x); for(int j = numPoints-1; j >= 0; --j) glVertexAttrib3fv(posLoc, &points[j].x); glVertexAttrib3fv(posLoc, &points[numPoints-1].x); glEnd(); }