void Split(rplane &plane) { for(iterator i=begin();i!=end();) { RPortal *pPortal=*i; if(!IS_EQ_PLANE(pPortal->plane,plane)) { RPortal *pFront=new RPortal; pFront->nID=g_nPortalCount++; pFront->pFrom=pPortal->pFrom; pFront->pTo=pPortal->pTo; pFront->pWinding=new RWinding(pPortal->pWinding); pFront->pWinding=ClipWinding(pFront->pWinding,plane); if(pFront->pWinding) { pFront->plane=pPortal->plane; i=insert(i,pFront); i++; }else delete pFront; // 뒷쪽winding 은 있는걸 활용한다.. pPortal->pWinding=ClipWinding(pPortal->pWinding,-plane); if(!pPortal->pWinding) { delete(pPortal); i=erase(i); continue; } } i++; } }
/* ================ MakeHeadnodePortals The created portals will face the global outside_node ================ */ void MakeHeadnodePortals (node_t *node) { vec3_t bounds[2]; int i, j, n; portal_t *p, *portals[6]; plane_t bplanes[6], *pl; int side; Draw_ClearWindow (); // pad with some space so there will never be null volume leafs for (i=0 ; i<3 ; i++) { bounds[0][i] = brushset->mins[i] - SIDESPACE; bounds[1][i] = brushset->maxs[i] + SIDESPACE; } outside_node.contents = CONTENTS_SOLID; outside_node.portals = NULL; for (i=0 ; i<3 ; i++) for (j=0 ; j<2 ; j++) { n = j*3 + i; p = AllocPortal (); portals[n] = p; pl = &bplanes[n]; memset (pl, 0, sizeof(*pl)); if (j) { pl->normal[i] = -1; pl->dist = -bounds[j][i]; } else { pl->normal[i] = 1; pl->dist = bounds[j][i]; } p->planenum = FindPlane (pl, &side); p->winding = BaseWindingForPlane (pl); if (side) AddPortalToNodes (p, &outside_node, node); else AddPortalToNodes (p, node, &outside_node); } // clip the basewindings by all the other planes for (i=0 ; i<6 ; i++) { for (j=0 ; j<6 ; j++) { if (j == i) continue; portals[i]->winding = ClipWinding (portals[i]->winding, &bplanes[j], true); } } }
/* ================= ChopWinding Returns the fragment of in that is on the front side of the cliping plane. The original is freed. ================= */ winding_t *ChopWinding (winding_t *in, normal_t normal, fixed_t dist) { winding_t *f, *b; ClipWinding (in, normal, dist, &f, &b); Z_Free (in); if (b) Z_Free (b); return f; }
/* ================= ChopWinding Returns the fragment of in that is on the front side of the cliping plane. The original is freed. ================= */ winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist) { winding_t *f, *b; ClipWinding (in, normal, dist, &f, &b); free (in); if (b) free (b); return f; }
void DivideWinding (winding_t *in, plane_t *split, winding_t **front, winding_t **back) { int i; int counts[3]; plane_t plane; vec_t dot; winding_t *tmp; counts[0] = counts[1] = counts[2] = 0; // determine sides for each point for (i = 0; i < in->numpoints; i++) { dot = DotProduct (in->points[i], split->normal) - split->dist; if (dot > ON_EPSILON) counts[SIDE_FRONT]++; else if (dot < -ON_EPSILON) counts[SIDE_BACK]++; } *front = *back = NULL; if (!counts[SIDE_FRONT]) { *back = in; return; } if (!counts[SIDE_BACK]) { *front = in; return; } tmp = CopyWinding (in); *front = ClipWinding (tmp, split, 0); plane.dist = -split->dist; VectorNegate (split->normal, plane.normal); tmp = CopyWinding (in); *back = ClipWinding (tmp, &plane, 0); }
/* Returns the visible polygon on a face */ winding_t *MakeFaceWinding(brush_t *b,face_t *face) { winding_t *w; face_t *clip; plane_t plane; BOOL past; // get a poly that covers an effectively infinite area w = BasePolyForPlane (&face->plane); // chop the poly by all of the other faces past = FALSE; for (clip = b->brush_faces ; clip && w ; clip=clip->next) { if (clip == face) { past = TRUE; continue; } if(Math_DotProduct (face->plane.normal, clip->plane.normal) > 0.999 && fabs(face->plane.dist - clip->plane.dist) < 0.01 ) { // identical plane, use the later one if (past) { free (w); return NULL; } continue; } // flip the plane, because we want to keep the back side Math_VectorSubtract(vec3_origin,clip->plane.normal,plane.normal); plane.dist = -clip->plane.dist; w = ClipWinding(w,&plane,FALSE); if (!w) return w; } if (w->numpoints < 3) { free(w); w = NULL; } if (!w) printf ("unused plane\n"); return w; }
/* ================== MakeNodePortal create the new portal by taking the full plane winding for the cutting plane and clipping it by all of the planes from the other portals. Each portal tracks the node that created it, so unused nodes can be removed later. ================== */ void MakeNodePortal (node_t *node) { portal_t *new_portal, *p; dplane_t *plane; dplane_t clipplane; winding_t *w; int side; plane = &dplanes[node->planenum]; w = BaseWindingForPlane (plane); new_portal = AllocPortal (); new_portal->plane = *plane; new_portal->onnode = node; side = 0; // shut up compiler warning for (p = node->portals ; p ; p = p->next[side]) { clipplane = p->plane; if (p->nodes[0] == node) side = 0; else if (p->nodes[1] == node) { clipplane.dist = -clipplane.dist; VectorSubtract (vec3_origin, clipplane.normal, clipplane.normal); side = 1; } else Error ("MakeNodePortal: mislinked portal"); w = ClipWinding (w, &clipplane, true); if (!w) { printf ("WARNING: MakeNodePortal:new portal was clipped away from node@(%.0f,%.0f,%.0f)-(%.0f,%.0f,%.0f)\n", node->mins[0], node->mins[1], node->mins[2], node->maxs[0], node->maxs[1], node->maxs[2]); FreePortal (new_portal); return; } } new_portal->winding = w; AddPortalToNodes (new_portal, node->children[0], node->children[1]); }
/* ================= CheckInside Quick test before running ClipInside; move any faces that are completely outside the brush to the outside list, without splitting them. This saves us time in mergefaces later on (and sometimes a lot of memory) ================= */ static void CheckInside(brush_t *b) { face_t *f, *bf, *next; face_t *insidelist; plane_t clip; winding_t *w; insidelist = NULL; f = inside; while (f) { next = f->next; w = CopyWinding(&f->w); for (bf = b->faces; bf; bf = bf->next) { clip = pPlanes[bf->planenum]; if (!bf->planeside) { VectorSubtract(vec3_origin, clip.normal, clip.normal); clip.dist = -clip.dist; } w = ClipWinding(w, &clip, true); if (!w) break; } if (!w) { /* The face is completely outside this brush */ f->next = outside; outside = f; } else { f->next = insidelist; insidelist = f; FreeMem(w, WINDING, 1); } f = next; } inside = insidelist; }
void CreateBrushFaces (void) { int i,j, k; vec_t r; face_t *f; winding_t *w; plane_t plane; mface_t *mf; brush_mins[0] = brush_mins[1] = brush_mins[2] = 99999; brush_maxs[0] = brush_maxs[1] = brush_maxs[2] = -99999; brush_faces = NULL; for (i=0 ; i<numbrushfaces ; i++) { mf = &faces[i]; w = BaseWindingForPlane (&mf->plane); for (j=0 ; j<numbrushfaces && w ; j++) { if (j == i) continue; // flip the plane, because we want to keep the back side VectorSubtract (vec3_origin,faces[j].plane.normal, plane.normal); plane.dist = -faces[j].plane.dist; w = ClipWinding (w, &plane, false); } if (!w) continue; // overcontrained plane // this face is a keeper f = AllocFace (); f->numpoints = w->numpoints; if (f->numpoints > MAXEDGES) Error ("f->numpoints > MAXEDGES"); for (j=0 ; j<w->numpoints ; j++) { for (k=0 ; k<3 ; k++) { r = Q_rint (w->points[j][k]); if ( fabs(w->points[j][k] - r) < ZERO_EPSILON) f->pts[j][k] = r; else f->pts[j][k] = w->points[j][k]; if (f->pts[j][k] < brush_mins[k]) brush_mins[k] = f->pts[j][k]; if (f->pts[j][k] > brush_maxs[k]) brush_maxs[k] = f->pts[j][k]; } } FreeWinding (w); f->texturenum = mf->texinfo; f->planenum = FindPlane (&mf->plane, &f->planeside); f->next = brush_faces; brush_faces = f; CheckFace (f); } }
/* ============= SubdividePatch ============= */ void SubdividePatch (patch_t *patch) { winding_t *w, *o1, *o2; vec3_t total; vec3_t split; vec_t dist; vec_t widest = -1; int i, j, widest_axis = -1; int subdivide_it = 0; vec_t v; patch_t *newp; w = patch->winding; VectorSubtract (patch->maxs, patch->mins, total); for (i=0 ; i<3 ; i++) { if ( total[i] > widest ) { widest_axis = i; widest = total[i]; } if ( total[i] > patch->chop || (patch->face_maxs[i] == patch->maxs[i] || patch->face_mins[i] == patch->mins[i] ) && total[i] > minchop ) { subdivide_it = 1; } } if ( subdivide_it ) { // // split the winding // VectorCopy (vec3_origin, split); split[widest_axis] = 1; dist = (patch->mins[widest_axis] + patch->maxs[widest_axis])*0.5f; ClipWinding (w, split, dist, &o1, &o2); // // create a new patch // if (num_patches == MAX_PATCHES) Error ("MAX_PATCHES"); newp = &patches[num_patches]; newp->next = patch->next; patch->next = newp; patch->winding = o1; newp->winding = o2; VectorCopy( patch->face_mins, newp->face_mins ); VectorCopy( patch->face_maxs, newp->face_maxs ); VectorCopy( patch->baselight, newp->baselight ); VectorCopy( patch->directlight, newp->directlight ); VectorCopy( patch->totallight, newp->totallight ); VectorCopy( patch->reflectivity, newp->reflectivity ); newp->plane = patch->plane; newp->sky = patch->sky; newp->chop = patch->chop; newp->faceNumber = patch->faceNumber; num_patches++; patch->area = WindingArea (patch->winding); newp->area = WindingArea (newp->winding); WindingCenter (patch->winding, patch->origin); WindingCenter (newp->winding, newp->origin); #ifdef PHONG_NORMAL_PATCHES // This seems to be a bad idea for some reason. Leave it turned off for now. // Set (Copy or Calculate) the synthetic normal for these new patches VectorAdd (patch->origin, patch->plane->normal, patch->origin); VectorAdd (newp->origin, newp->plane->normal, newp->origin); GetPhongNormal( patch->faceNumber, patch->origin, patch->normal ); GetPhongNormal( newp->faceNumber, newp->origin, newp->normal ); VectorSubtract( patch->origin, patch->plane->normal, patch->origin); VectorSubtract( newp->origin, newp->plane->normal, newp->origin); #else VectorCopy( patch->plane->normal, patch->normal ); VectorCopy( newp->plane->normal, newp->normal ); #endif VectorAdd( patch->origin, patch->normal, patch->origin ); VectorAdd( newp->origin, newp->normal, newp->origin ); WindingBounds(patch->winding, patch->mins, patch->maxs); WindingBounds(newp->winding, newp->mins, newp->maxs); // Subdivide patch even more if on the edge of the face; this is a hack! VectorSubtract (patch->maxs, patch->mins, total); if ( total[0] < patch->chop && total[1] < patch->chop && total[2] < patch->chop ) for ( i=0; i<3; i++ ) if ( (patch->face_maxs[i] == patch->maxs[i] || patch->face_mins[i] == patch->mins[i] ) && total[i] > minchop ) { patch->chop = max( minchop, patch->chop / 2 ); break; } SubdividePatch (patch); // Subdivide patch even more if on the edge of the face; this is a hack! VectorSubtract (newp->maxs, newp->mins, total); if ( total[0] < newp->chop && total[1] < newp->chop && total[2] < newp->chop ) for ( i=0; i<3; i++ ) if ( (newp->face_maxs[i] == newp->maxs[i] || newp->face_mins[i] == newp->mins[i] ) && total[i] > minchop ) { newp->chop = max( minchop, newp->chop / 2 ); break; } SubdividePatch (newp); } }
static clipleaf_t * carve_leaf (hull_t *hull, nodeleaf_t *nodeleafs, clipleaf_t *leaf, int num) { mclipnode_t *node; plane_t *plane; winding_t *winding, *fw, *bw; clipport_t *portal; clipport_t *new_portal; clipport_t *next_portal; clipleaf_t *other_leaf; clipleaf_t *new_leaf; plane_t clipplane; int side; if (num < 0) { // we've hit a leaf. all done leaf->contents = num; return leaf; } node = hull->clipnodes + num; plane = hull->planes + node->planenum; winding = BaseWindingForPlane (plane); for (portal = leaf->portals; portal; portal = portal->next[side]) { clipplane = hull->planes[portal->planenum]; side = (portal->leafs[1] == leaf); if (side) PlaneFlip (&clipplane, &clipplane); winding = ClipWinding (winding, &clipplane, true); } new_leaf = alloc_leaf (); portal = leaf->portals; leaf->portals = 0; for (; portal; portal = next_portal) { side = (portal->leafs[1] == leaf); next_portal = portal->next[side]; other_leaf = portal->leafs[!side]; remove_portal (portal, other_leaf); DivideWinding (portal->winding, plane, &fw, &bw); if (!fw) { if (side) add_portal (portal, other_leaf, new_leaf); else add_portal (portal, new_leaf, other_leaf); continue; } if (!bw) { if (side) add_portal (portal, other_leaf, leaf); else add_portal (portal, leaf, other_leaf); continue; } new_portal = alloc_portal (); new_portal->planenum = portal->planenum; new_portal->winding = bw; FreeWinding (portal->winding); portal->winding = fw; if (side) { add_portal (portal, other_leaf, leaf); add_portal (new_portal, other_leaf, new_leaf); } else { add_portal (portal, leaf, other_leaf); add_portal (new_portal, new_leaf, other_leaf); } } new_portal = alloc_portal (); new_portal->planenum = node->planenum; new_portal->winding = winding; add_portal (new_portal, leaf, new_leaf); nodeleafs[num].leafs[0] = carve_leaf (hull, nodeleafs, leaf, node->children[0]); nodeleafs[num].leafs[1] = carve_leaf (hull, nodeleafs, new_leaf, node->children[1]); return 0; }
/* ================ CutNodePortals_r ================ */ static void CutNodePortals_r (node_t *node) { plane_t *plane, clipplane; node_t *f, *b, *other_node; portal_t *p, *new_portal, *next_portal; winding_t *w, *frontwinding, *backwinding; int side; // Vic: properly calculate the bounding box CalcNodeBounds (node); // // separate the portals on node into it's children // if (node->contents) return; // at a leaf, no more dividing plane = &mapplanes[node->planenum]; f = node->children[0]; b = node->children[1]; // // create the new portal by taking the full plane winding for the cutting plane // and clipping it by all of the planes from the other portals // w = BaseWindingForPlane (&mapplanes[node->planenum]); side = 0; // shut up compiler warning for (p = node->portals ; p ; p = p->next[side]) { clipplane = mapplanes[p->planenum]; if (p->nodes[0] == node) side = 0; else if (p->nodes[1] == node) { clipplane.dist = -clipplane.dist; VectorNegate (clipplane.normal, clipplane.normal); side = 1; } else Error ("CutNodePortals_r: mislinked portal"); w = ClipWinding (w, &clipplane, true); if (!w) { printf ("WARNING: CutNodePortals_r:new portal was clipped away\n"); break; } } if (w) { // if the plane was not clipped on all sides, there was an error new_portal = AllocPortal (); new_portal->planenum = node->planenum; new_portal->winding = w; AddPortalToNodes (new_portal, f, b); } // partition the portals for (p = node->portals ; p ; p = next_portal) { if (p->nodes[0] == node) side = 0; else if (p->nodes[1] == node) side = 1; else Error ("CutNodePortals_r: mislinked portal"); next_portal = p->next[side]; other_node = p->nodes[!side]; RemovePortalFromNode (p, p->nodes[0]); RemovePortalFromNode (p, p->nodes[1]); // cut the portal into two portals, one on each side of the cut plane DivideWindingEpsilon( p->winding, plane, &frontwinding, &backwinding, ON_EPSILON ); if (!frontwinding) { if (side == 0) AddPortalToNodes (p, b, other_node); else AddPortalToNodes (p, other_node, b); continue; } if (!backwinding) { if (side == 0) AddPortalToNodes (p, f, other_node); else AddPortalToNodes (p, other_node, f); continue; } // the winding is split new_portal = AllocPortal (); *new_portal = *p; new_portal->winding = backwinding; FreeWinding (p->winding); p->winding = frontwinding; if (side == 0) { AddPortalToNodes (p, f, other_node); AddPortalToNodes (new_portal, b, other_node); } else { AddPortalToNodes (p, other_node, f); AddPortalToNodes (new_portal, other_node, b); } } CutNodePortals_r (f); CutNodePortals_r (b); }
/* ================ CutNodePortals_r ================ */ static void CutNodePortals_r(node_t *node) { plane_t *plane, clipplane; node_t *f, *b, *other_node; portal_t *p, *new_portal, *next_portal; winding_t *w, *frontwinding, *backwinding; int side; #ifdef PARANOID CheckLeafPortalConsistancy (node); #endif // separate the portals on node into it's children if (node->contents) return; // at a leaf, no more dividing plane = &pPlanes[node->planenum]; f = node->children[0]; b = node->children[1]; // create the new portal by taking the full plane winding for the cutting plane // and clipping it by all of the planes from the other portals new_portal = AllocMem(PORTAL, 1, true); new_portal->planenum = node->planenum; w = BaseWindingForPlane(&pPlanes[node->planenum]); side = 0; // shut up compiler warning for (p = node->portals; p; p = p->next[side]) { clipplane = pPlanes[p->planenum]; if (p->nodes[0] == node) side = 0; else if (p->nodes[1] == node) { clipplane.dist = -clipplane.dist; VectorSubtract(vec3_origin, clipplane.normal, clipplane.normal); side = 1; } else Message(msgError, errMislinkedPortal); w = ClipWinding(w, &clipplane, true); if (!w) { Message(msgWarning, warnPortalClippedAway); break; } } if (w) { // if the plane was not clipped on all sides, there was an error new_portal->winding = w; AddPortalToNodes(new_portal, f, b); } // partition the portals for (p = node->portals; p; p = next_portal) { if (p->nodes[0] == node) side = 0; else if (p->nodes[1] == node) side = 1; else Message(msgError, errMislinkedPortal); next_portal = p->next[side]; other_node = p->nodes[!side]; RemovePortalFromNode(p, p->nodes[0]); RemovePortalFromNode(p, p->nodes[1]); // cut the portal into two portals, one on each side of the cut plane DivideWinding(p->winding, plane, &frontwinding, &backwinding); if (!frontwinding) { if (side == 0) AddPortalToNodes(p, b, other_node); else AddPortalToNodes(p, other_node, b); continue; } if (!backwinding) { if (side == 0) AddPortalToNodes(p, f, other_node); else AddPortalToNodes(p, other_node, f); continue; } // the winding is split new_portal = AllocMem(PORTAL, 1, true); *new_portal = *p; new_portal->winding = backwinding; FreeMem(p->winding, WINDING, 1); p->winding = frontwinding; if (side == 0) { AddPortalToNodes(p, f, other_node); AddPortalToNodes(new_portal, b, other_node); } else { AddPortalToNodes(p, other_node, f); AddPortalToNodes(new_portal, other_node, b); } } // Display progress iNodesDone++; Message(msgPercent, iNodesDone, splitnodes); CutNodePortals_r(f); CutNodePortals_r(b); }
void CreateBrushFaces (void) { int i, j, k; vec3_t offset, point; vec_t r, max, min; face_t *f; winding_t *w; plane_t plane; mface_t *mf; qboolean IsRotate; offset[0] = offset[1] = offset[2] = 0; min = brush_mins[0] = brush_mins[1] = brush_mins[2] = 99999; max = brush_maxs[0] = brush_maxs[1] = brush_maxs[2] = -99999; // Hipnotic rotation IsRotate = !strncmp(ValueForKey(CurrEnt, "classname"), "rotate_", 7); if (IsRotate) FixRotateOrigin(CurrEnt, offset); brush_faces = NULL; for (i=0 ; i<numbrushfaces ; i++) { mf = &faces[i]; w = BaseWindingForPlane (&mf->plane); for (j=0 ; j<numbrushfaces && w ; j++) { if (j == i) continue; // flip the plane, because we want to keep the back side VectorSubtract (vec3_origin,faces[j].plane.normal, plane.normal); plane.dist = -faces[j].plane.dist; w = ClipWinding (w, &plane, false); } if (!w) continue; // overcontrained plane // this face is a keeper f = AllocFace (); ResizeFace (f, w->numpoints); if (f->numpoints > MAXEDGES) Message (MSGERR, "f->numpoints (%d) > MAXEDGES (%d)", f->numpoints, MAXEDGES); for (j=0 ; j<w->numpoints ; j++) { for (k=0 ; k<3 ; k++) { point[k] = w->points[j][k] - offset[k]; r = Q_rint(point[k]); if (fabs(point[k] - r) < ZERO_EPSILON) f->pts[j][k] = r; else f->pts[j][k] = point[k]; if (f->pts[j][k] < brush_mins[k]) brush_mins[k] = f->pts[j][k]; if (f->pts[j][k] > brush_maxs[k]) brush_maxs[k] = f->pts[j][k]; if (IsRotate) { if (f->pts[j][k] < min) min = f->pts[j][k]; if (f->pts[j][k] > max) max = f->pts[j][k]; } } } if (!IsRotate) plane = mf->plane; else { VectorCopy(mf->plane.normal, plane.normal); VectorScale(mf->plane.normal, mf->plane.dist, point); VectorSubtract(point, offset, point); plane.dist = DotProduct(plane.normal, point); } FreeWinding (w); f->texturenum = hullnum ? 0 : mf->texinfo; f->planenum = FindPlane (&plane, &f->planeside); f->next = brush_faces; brush_faces = f; CheckFace (f); } // Rotatable objects must have a bounding box big enough to // account for all its rotations if (IsRotate) { vec_t delta; delta = fabs(max); if (fabs(min) > delta) delta = fabs(min); for (k=0; k<3; k++) { brush_mins[k] = -delta; brush_maxs[k] = delta; } } }
RWinding *ClipToSeperators ( RWinding *source, RWinding *pass, RWinding *target, CLIP_SEPERATOR_DIR clipdir ) { long cur_src_point; long next_src_point; long cur_pass_point; rvector v1, v2; rplane plane; long i; float d; float length; long front_count; if( ! source || ! pass ) return target; // source의 모서리와 pass의 한점을 선택하는 모든 조합을 만든다. for (cur_src_point=0 ; cur_src_point<source->nCount; cur_src_point++) { // source 로부터 한 모서리를 선택한다. next_src_point = (cur_src_point+1)%source->nCount; v1 = source->pVertices[next_src_point] - source->pVertices[cur_src_point]; for (cur_pass_point=0 ; cur_pass_point<pass->nCount; cur_pass_point++) { // pass 로부터 한 점을 선택한다. v2 = pass->pVertices[cur_pass_point] - source->pVertices[cur_src_point]; // 선택한 모서리와 점으로 평면(plane)을 만든다. rvector normal; CrossProduct( &normal, v1 ,v2 ); length = DotProduct( normal, normal ); if (length < ON_EPSILON) continue; length = (float)sqrt(length); plane.a = normal.x/length; plane.b = normal.y/length; plane.c = normal.z/length; plane.d = -D3DXPlaneDotNormal(&plane,&pass->pVertices[cur_pass_point]); // plane과 source의위치관계를 조사한다. front_count = 0; for (i=0 ; i<source->nCount ; i++) { if (i == cur_src_point || i == next_src_point) continue; d = D3DXPlaneDotCoord(&plane,&source->pVertices[i]); if (d < -ON_EPSILON) break; if (d > ON_EPSILON) { front_count++; // source는 plane의 양쪽에 걸쳐져 있을 수 없다. // 따라서 한점만 앞에있어도 source가 앞에있다고 판단. break; } } // source가 plane상에 있는경우는 취급하지 않는다. // 이것은 [ 가시성 판단 3 ] 에서 처리한다. // [ 가시성 판단 3 ] 을 수행하지 않고 이 함수를 수행하려 한다면 // 함수가 좀 복잡해진다. if (i == source->nCount) continue; // source가 plane의 뒤쪽에 위치하도록 평면방정식을 조정한다. if ( front_count ) plane=-plane; // plane과 pass의위치관계를 조사한다. // pass가 plane의 앞쪽에 완전히 포함되는 경우, // plane으로 target을 클리핑한다. front_count = 0; for (i=0 ; i<pass->nCount; i++) { if (i==cur_pass_point) continue; d = D3DXPlaneDotCoord(&plane,&pass->pVertices[i]); if (d < -ON_EPSILON) break; if (d > ON_EPSILON) front_count++; } // 한점이라도 plane의 뒤쪽에 있으면 안된다. if (i != pass->nCount) continue; // pass가 평면에 포함되어서도 안된다. if ( ! front_count ) continue; // 입력된 parameter 가 // source -> pass -> target 순이 아니라 // pass -> source -> target 순이라면 plane을 뒤집어야 한다. if ( clipdir == CLIP_SEPERATOR_BACKWARD ) { plane=-plane; } // 여기까지 왔다면 plane은 뷰볼륨을 이루는 평면이다. // target을 잘라낸다. target = ClipWinding (target, plane); if (!target) return NULL; // target is not visible } } return target; }