static __regargs UWORD ClipPolygon(Point3D *S, Point3D *O, UWORD n, UWORD plane) { Point3D *E = S + 1; BOOL S_inside = CheckInside(S, plane); BOOL needClose = TRUE; UWORD m = 0; if (S_inside) { needClose = FALSE; O[m++] = *S; } while (--n) { BOOL E_inside = CheckInside(E, plane); if (S_inside && E_inside) { O[m++] = *E; } else if (S_inside && !E_inside) { ClipEdge(&O[m++], S, E, plane); } else if (!S_inside && E_inside) { ClipEdge(&O[m++], E, S, plane); O[m++] = *E; } S_inside = E_inside; S++; E++; } if (needClose) O[m++] = *O; return m; }
Mth::Vector CEmitterObject::GetClosestPoint(const Mth::Vector &object_pos) const { // Return original position if within the object if (CheckInside(object_pos)) { return object_pos; } Mth::Vector intersect_point; switch (m_shape_type) { case vSHAPE_SPHERE: { // Same for either within or outside sphere Mth::Vector direction = object_pos - m_pos; direction.Normalize(); direction *= m_radius; intersect_point = m_pos + direction; } break; case vSHAPE_BBOX: m_bbox.GetClosestIntersectPoint(object_pos, intersect_point); break; default: Dbg_MsgAssert(0, ("Can't handle EmitterObject type %d", m_shape_type)); break; } #ifdef DEBUG_EMITTER Gfx::AddDebugStar(intersect_point); #endif // DEBUG_EMITTER return intersect_point; }
/* ================== CSGFaces Returns a list of surfaces containing all of the faces ================== */ surface_t * CSGFaces(void) { brush_t *b1, *b2; int i; bool overwrite; face_t *f; surface_t *surfhead; int iBrushes = 0; Message(msgProgress, "CSGFaces"); if (validfaces == NULL) validfaces = AllocMem(OTHER, sizeof(face_t *) * cPlanes, true); else memset(validfaces, 0, sizeof(face_t *) * cPlanes); csgfaces = brushfaces = csgmergefaces = 0; // do the solid faces for (b1 = pCurEnt->pBrushes; b1; b1 = b1->next) { // set outside to a copy of the brush's faces CopyFacesToOutside(b1); // Why is this necessary? overwrite = false; for (b2 = pCurEnt->pBrushes; b2; b2 = b2->next) { // check bounding box first for (i = 0; i < 3; i++) if (b1->mins[i] > b2->maxs[i] || b1->maxs[i] < b2->mins[i]) break; if (i < 3) continue; // see if b2 needs to clip a chunk out of b1 if (b1 == b2) { overwrite = true; continue; } // divide faces by the planes of the new brush inside = outside; outside = NULL; CheckInside(b2); for (f = b2->faces; f; f = f->next) ClipInside(f->planenum, f->planeside, overwrite); // these faces are continued in another brush, so get rid of them if (b1->contents == CONTENTS_SOLID && b2->contents <= CONTENTS_WATER) FreeInside(b2->contents); else FreeInside(CONTENTS_SOLID); } // all of the faces left in outside are real surface faces if (b1->contents != CONTENTS_SOLID) SaveOutside(true); // mirror faces for inside view else SaveOutside(false); iBrushes++; Message(msgPercent, iBrushes, pCurEnt->cBrushes); } surfhead = BuildSurfaces(); Message(msgStat, "%5i brushfaces", brushfaces); Message(msgStat, "%5i csgfaces", csgfaces); Message(msgStat, "%5i mergedfaces", csgmergefaces); return surfhead; }