/* ============= Brush_MergeList Tries to merge all brushes in the list into one new brush. The input brush list stays intact. Returns NULL if no merged brush can be created. To create a new brush the brushes in the list may not overlap and the outer faces of the brushes together should make a new convex brush. if onlyshape is true then the merge is allowed based on the shape only otherwise the texture references of faces in the same plane have to be the same as well. ============= */ brush_t *Brush_MergeList(brush_t *brushlist, int onlyshape) { brush_t *brush1, *brush2, *brush3, *newbrush; face_t *face1, *face2, *face3, *newface, *f; if (!brushlist) return NULL; for (brush1 = brushlist; brush1; brush1 = brush1->next) { // check if the new brush would be convex... flipped planes make a brush concave for (face1 = brush1->brush_faces; face1; face1 = face1->next) { // don't check face1 if it touches another brush for (brush2 = brushlist; brush2; brush2 = brush2->next) { if (brush2 == brush1) continue; for (face2 = brush2->brush_faces; face2; face2 = face2->next) { if (Plane_Equal(&face1->plane, &face2->plane, true)) { break; } } if (face2) break; } // if face1 touches another brush if (brush2) continue; // for (brush2 = brush1->next; brush2; brush2 = brush2->next) { // don't check the faces of brush 2 touching another brush for (face2 = brush2->brush_faces; face2; face2 = face2->next) { for (brush3 = brushlist; brush3; brush3 = brush3->next) { if (brush3 == brush2) continue; for (face3 = brush3->brush_faces; face3; face3 = face3->next) { if (Plane_Equal(&face2->plane, &face3->plane, true)) break; } if (face3) break; } // if face2 touches another brush if (brush3) continue; // if (Plane_Equal(&face1->plane, &face2->plane, false)) { //if the texture references should be the same but are not if (!onlyshape && stricmp(face1->texdef.name, face2->texdef.name) != 0) return NULL; continue; } // if (Winding_PlanesConcave(face1->face_winding, face2->face_winding, face1->plane.normal, face2->plane.normal, face1->plane.dist, face2->plane.dist)) { return NULL; } } } } } // newbrush = Brush_Alloc(); // for (brush1 = brushlist; brush1; brush1 = brush1->next) { for (face1 = brush1->brush_faces; face1; face1 = face1->next) { // don't add face1 to the new brush if it touches another brush for (brush2 = brushlist; brush2; brush2 = brush2->next) { if (brush2 == brush1) continue; for (face2 = brush2->brush_faces; face2; face2 = face2->next) { if (Plane_Equal(&face1->plane, &face2->plane, true)) { break; } } if (face2) break; } if (brush2) continue; // don't add faces with the same plane twice for (f = newbrush->brush_faces; f; f = f->next) { if (Plane_Equal(&face1->plane, &f->plane, false)) break; if (Plane_Equal(&face1->plane, &f->plane, true)) break; } if (f) continue; // newface = Face_Alloc(); newface->texdef = face1->texdef; VectorCopy(face1->planepts[0], newface->planepts[0]); VectorCopy(face1->planepts[1], newface->planepts[1]); VectorCopy(face1->planepts[2], newface->planepts[2]); newface->plane = face1->plane; newface->next = newbrush->brush_faces; newbrush->brush_faces = newface; } } // link the new brush to an entity Entity_LinkBrush (brushlist->owner, newbrush); // build windings for the faces Brush_BuildWindings( newbrush); return newbrush; }
/* ============ TryMergeLeaves ============ */ int TryMergeLeaves(int l1num, int l2num) { int i, j, k, n, numportals; visPlane_t plane1, plane2; leaf_t *l1, *l2; vportal_t *p1, *p2; vportal_t *portals[MAX_PORTALS_ON_LEAF]; for(k = 0; k < 2; k++) { if(k) l1 = &leafs[l1num]; else l1 = &faceleafs[l1num]; for(i = 0; i < l1->numportals; i++) { p1 = l1->portals[i]; if(p1->leaf == l2num) continue; for(n = 0; n < 2; n++) { if(n) l2 = &leafs[l2num]; else l2 = &faceleafs[l2num]; for(j = 0; j < l2->numportals; j++) { p2 = l2->portals[j]; if(p2->leaf == l1num) continue; // plane1 = p1->plane; plane2 = p2->plane; if(Winding_PlanesConcave(p1->winding, p2->winding, plane1.normal, plane2.normal, plane1.dist, plane2.dist)) return qfalse; } } } } for(k = 0; k < 2; k++) { if(k) { l1 = &leafs[l1num]; l2 = &leafs[l2num]; } else { l1 = &faceleafs[l1num]; l2 = &faceleafs[l2num]; } numportals = 0; //the leaves can be merged now for(i = 0; i < l1->numportals; i++) { p1 = l1->portals[i]; if(p1->leaf == l2num) { p1->removed = qtrue; continue; } portals[numportals++] = p1; } for(j = 0; j < l2->numportals; j++) { p2 = l2->portals[j]; if(p2->leaf == l1num) { p2->removed = qtrue; continue; } portals[numportals++] = p2; } for(i = 0; i < numportals; i++) { l2->portals[i] = portals[i]; } l2->numportals = numportals; l1->merged = l2num; } return qtrue; }
/* ============= Brush_Merge Returns a new brush that is created by merging brush1 and brush2. May return NULL if brush1 and brush2 do not create a convex brush when merged. The input brushes brush1 and brush2 stay intact. if onlyshape is true then the merge is allowed based on the shape only otherwise the texture references of faces in the same plane have to be the same as well. ============= */ brush_t *Brush_Merge(brush_t *brush1, brush_t *brush2, int onlyshape) { int i, shared; brush_t *newbrush; face_t *face1, *face2, *newface, *f; // check for bounding box overlapp for (i = 0; i < 3; i++) { if (brush1->mins[i] > brush2->maxs[i] + ON_EPSILON || brush1->maxs[i] < brush2->mins[i] - ON_EPSILON) { // never merge if the brushes overlap return NULL; } } // shared = 0; // check if the new brush would be convex... flipped planes make a brush non-convex for (face1 = brush1->brush_faces; face1; face1 = face1->next) { // don't check the faces of brush 1 and 2 touching each other for (face2 = brush2->brush_faces; face2; face2 = face2->next) { if (Plane_Equal(&face1->plane, &face2->plane, true)) { shared++; // there may only be ONE shared side if (shared > 1) return NULL; break; } } // if this face plane is shared if (face2) continue; // for (face2 = brush2->brush_faces; face2; face2 = face2->next) { // don't check the faces of brush 1 and 2 touching each other for (f = brush1->brush_faces; f; f = f->next) { if (Plane_Equal(&face2->plane, &f->plane, true)) break; } if (f) continue; // if (Plane_Equal(&face1->plane, &face2->plane, false)) { //if the texture references should be the same but are not if (!onlyshape && stricmp(face1->texdef.name, face2->texdef.name) != 0) return NULL; continue; } // if (Winding_PlanesConcave(face1->face_winding, face2->face_winding, face1->plane.normal, face2->plane.normal, face1->plane.dist, face2->plane.dist)) { return NULL; } //end if } //end for } //end for // newbrush = Brush_Alloc(); // for (face1 = brush1->brush_faces; face1; face1 = face1->next) { // don't add the faces of brush 1 and 2 touching each other for (face2 = brush2->brush_faces; face2; face2 = face2->next) { if (Plane_Equal(&face1->plane, &face2->plane, true)) break; } if (face2) continue; // don't add faces with the same plane twice for (f = newbrush->brush_faces; f; f = f->next) { if (Plane_Equal(&face1->plane, &f->plane, false)) break; if (Plane_Equal(&face1->plane, &f->plane, true)) break; } if (f) continue; // newface = Face_Alloc(); newface->texdef = face1->texdef; VectorCopy(face1->planepts[0], newface->planepts[0]); VectorCopy(face1->planepts[1], newface->planepts[1]); VectorCopy(face1->planepts[2], newface->planepts[2]); newface->plane = face1->plane; newface->next = newbrush->brush_faces; newbrush->brush_faces = newface; } // for (face2 = brush2->brush_faces; face2; face2 = face2->next) { // don't add the faces of brush 1 and 2 touching each other for (face1 = brush1->brush_faces; face1; face1 = face1->next) { if (Plane_Equal(&face2->plane, &face1->plane, true)) break; } if (face1) continue; // don't add faces with the same plane twice for (f = newbrush->brush_faces; f; f = f->next) { if (Plane_Equal(&face2->plane, &f->plane, false)) break; if (Plane_Equal(&face2->plane, &f->plane, true)) break; } if (f) continue; // newface = Face_Alloc(); newface->texdef = face2->texdef; VectorCopy(face2->planepts[0], newface->planepts[0]); VectorCopy(face2->planepts[1], newface->planepts[1]); VectorCopy(face2->planepts[2], newface->planepts[2]); newface->plane = face2->plane; newface->next = newbrush->brush_faces; newbrush->brush_faces = newface; } // link the new brush to an entity Entity_LinkBrush (brush1->owner, newbrush); // build windings for the faces Brush_BuildWindings(newbrush); return newbrush; }