private void FloodViewThroughArea(Vector3 origin, int areaNumber, PortalStack portalStack)
{
int i, j;
idWinding winding; // we won't overflow because MAX_PORTAL_PLANES = 20
PortalStack check;
PortalStack newStack;
PortalArea area = _portalAreas[areaNumber];
// cull models and lights to the current collection of planes
AddAreaReferences(areaNumber, portalStack);
if(_areaScreenRect[areaNumber].IsEmpty == true)
{
_areaScreenRect[areaNumber] = portalStack.Rectangle;
}
else
{
_areaScreenRect[areaNumber].Union(portalStack.Rectangle);
}
// go through all the portals
Portal portal;
for(portal = area.Portals; portal != null; portal = portal.Next)
{
// an enclosing door may have sealed the portal off
if((portal.DoublePortal.BlockingBits & PortalConnection.BlockView) == PortalConnection.BlockView)
{
continue;
}
// make sure this portal is facing away from the view
float d = portal.Plane.Distance(origin);
if(d < -0.1f)
{
continue;
}
// make sure the portal isn't in our stack trace,
// which would cause an infinite loop
for(check = portalStack; check != null; check = check.Next)
{
if(check.Portal == portal)
{
break; // don't recursively enter a stack
}
}
if(check != null)
{
continue; // already in stack
}
// if we are very close to the portal surface, don't bother clipping
// it, which tends to give epsilon problems that make the area vanish
if(d < 1.0f)
{
// go through this portal
newStack = portalStack;
newStack.Portal = portal;
newStack.Next = portalStack;
FloodViewThroughArea(origin, portal.IntoArea, newStack);
continue;
}
// clip the portal winding to all of the planes
winding = portal.Winding;
for(j = 0; j < portalStack.PortalPlaneCount; j++)
{
Plane neg = new Plane(-portalStack.PortalPlanes[j].Normal, -portalStack.PortalPlanes[j].D);
if(winding.ClipInPlace(neg, 0) == false)
{
break;
}
}
if(winding.PointCount == 0)
{
continue; // portal not visible
}
// see if it is fogged out
if(PortalIsFoggedOut(portal) == true)
{
continue;
}
// go through this portal
newStack = new PortalStack();
newStack.Portal = portal;
newStack.Next = portalStack;
// find the screen pixel bounding box of the remaining portal
// so we can scissor things outside it
newStack.Rectangle = ScreenRectangleFromWinding(winding, idE.RenderSystem.IdentitySpace);
// slop might have spread it a pixel outside, so trim it back
newStack.Rectangle.Intersect(portalStack.Rectangle);
// generate a set of clipping planes that will further restrict
// the visible view beyond just the scissor rect
int addPlanes = winding.PointCount;
if(addPlanes > idE.MaxPortalPlanes)
{
addPlanes = idE.MaxPortalPlanes;
}
newStack.PortalPlaneCount = 0;
for(i = 0; i < addPlanes; i++)
{
j = i + 1;
if(j == winding.PointCount)
{
j = 0;
}
Vector3 v1 = origin - winding[i];
Vector3 v2 = origin - winding[j];
newStack.PortalPlanes[newStack.PortalPlaneCount].Normal = Vector3.Cross( v2, v1 );
// if it is degenerate, skip the plane
newStack.PortalPlanes[newStack.PortalPlaneCount].Normalize();
if(newStack.PortalPlanes[newStack.PortalPlaneCount].Normal.Length() < 0.01f)
{
continue;
}
newStack.PortalPlanes[newStack.PortalPlaneCount].FitThroughPoint(origin);
newStack.PortalPlaneCount++;
}
// the last stack plane is the portal plane
newStack.PortalPlanes[newStack.PortalPlaneCount] = portal.Plane;
newStack.PortalPlaneCount++;
FloodViewThroughArea(origin, portal.IntoArea, newStack);
}
}