/** * @return @c true if the ray passes @a bspLeaf; otherwise @c false. */ bool crossBspLeaf(BspLeaf const &bspLeaf) { if(!bspLeaf.hasSubspace()) return false; ConvexSubspace const &subspace = bspLeaf.subspace(); // Check polyobj lines. LoopResult blocked = subspace.forAllPolyobjs([this] (Polyobj &pob) { for(Line *line : pob.lines()) { if(!crossLine(line->front())) return LoopAbort; } return LoopContinue; }); if(blocked) return false; // Check lines for the edges of the subspace geometry. HEdge *base = subspace.poly().hedge(); HEdge *hedge = base; do { if(hedge->hasMapElement()) { if(!crossLine(hedge->mapElementAs<LineSideSegment>().lineSide())) return false; } } while((hedge = &hedge->next()) != base); // Check lines for the extra meshes. blocked = subspace.forAllExtraMeshes([this] (Mesh &mesh) { for(HEdge *hedge : mesh.hedges()) { // Is this on the back of a one-sided line? if(!hedge->hasMapElement()) continue; if(!crossLine(hedge->mapElementAs<LineSideSegment>().lineSide())) return LoopAbort; } return LoopContinue; }); return !blocked; }
/** * Interpret vlights from glowing planes at the @a origin in the specfified * @a bspleaf and add them to the identified list. */ static void lightWithPlaneGlows(Vector3d const &origin, BspLeaf &bspLeaf, uint listIdx) { SectorCluster &cluster = bspLeaf.cluster(); for(int i = 0; i < cluster.sector().planeCount(); ++i) { Plane &plane = cluster.visPlane(i); Surface &surface = plane.surface(); // Glowing at this moment? Vector3f glowColor; float intensity = surface.glow(glowColor); if(intensity < .05f) continue; coord_t glowHeight = Rend_PlaneGlowHeight(intensity); if(glowHeight < 2) continue; // Not too small! // In front of the plane? Vector3d pointOnPlane = Vector3d(cluster.center(), plane.heightSmoothed()); double dist = (origin - pointOnPlane).dot(surface.normal()); if(dist < 0) continue; intensity *= 1 - dist / glowHeight; if(intensity < .05f) continue; Vector3f color = Rend_LuminousColor(glowColor, intensity); if(color != Vector3f(0, 0, 0)) { ListNode *node = newVLight(); VectorLight *vlight = &node->vlight; vlight->direction = Vector3f(surface.normal().x, surface.normal().y, -surface.normal().z); vlight->color = color; vlight->affectedByAmbient = true; vlight->approxDist = dist; vlight->lightSide = 1; vlight->darkSide = 0; vlight->offset = .3f; linkNodeInList(node, listIdx); } } }
void addNeighborIntercepts(coord_t bottom, coord_t top) { ClockDirection const direction = edge? Clockwise : Anticlockwise; HEdge *hedge = wallHEdge; while((hedge = &SectorClusterCirculator::findBackNeighbor(*hedge, direction)) != wallHEdge) { // Stop if there is no back cluster. BspLeaf *backLeaf = hedge->hasFace()? &hedge->face().mapElementAs<BspLeaf>() : 0; if(!backLeaf || !backLeaf->hasCluster()) break; SectorCluster &cluster = backLeaf->cluster(); if(cluster.hasWorldVolume()) { for(int i = 0; i < cluster.visPlaneCount(); ++i) { Plane const &plane = cluster.visPlane(i); if(plane.heightSmoothed() > bottom && plane.heightSmoothed() < top) { ddouble distance = distanceTo(plane.heightSmoothed()); if(!haveEvent(distance)) { createEvent(distance); // Have we reached the div limit? if(interceptCount() == WALLEDGE_MAX_INTERCEPTS) return; } } // Clip a range bound to this height? if(plane.isSectorFloor() && plane.heightSmoothed() > bottom) bottom = plane.heightSmoothed(); else if(plane.isSectorCeiling() && plane.heightSmoothed() < top) top = plane.heightSmoothed(); // All clipped away? if(bottom >= top) return; } } else { /* * A neighbor with zero volume is a special case -- the potential * division is at the height of the back ceiling. This is because * elsewhere we automatically fix the case of a floor above a * ceiling by lowering the floor. */ coord_t z = cluster.visCeiling().heightSmoothed(); if(z > bottom && z < top) { ddouble distance = distanceTo(z); if(!haveEvent(distance)) { createEvent(distance); // All clipped away. return; } } } } }