예제 #1
0
/*
=======================
FlowViewThroughPortals

Finds viewLights and viewEntities by flowing from an origin through the visible portals.
origin point can see into.  The planes array defines a volume (positive
sides facing in) that should contain the origin, such as a view frustum or a point light box.
Zero planes assumes an unbounded volume.
=======================
*/
void idRenderWorldLocal::FlowViewThroughPortals( const idVec3 origin, int numPlanes, const idPlane *planes ) {
	portalStack_t	ps;
	int				i;

	ps.next = NULL;
	ps.p = NULL;

	for ( i = 0 ; i < numPlanes ; i++ ) {
		ps.portalPlanes[i] = planes[i];
	}

	ps.numPortalPlanes = numPlanes;
	ps.rect = tr.viewDef->scissor;

	if ( tr.viewDef->areaNum < 0 ){

		for ( i = 0; i < numPortalAreas; i++ ) {
			areaScreenRect[i] = tr.viewDef->scissor;
		}

		// if outside the world, mark everything
		for ( i = 0 ; i < numPortalAreas ; i++ ) {
			AddAreaRefs( i, &ps );
		}
	} else {

		for ( i = 0; i < numPortalAreas; i++ ) {
			areaScreenRect[i].Clear();
		}

		// flood out through portals, setting area viewCount
		FloodViewThroughArea_r( origin, tr.viewDef->areaNum, &ps );
	}
}
예제 #2
0
/*
=======================
idRenderWorldLocal::FlowViewThroughPortals

Finds viewLights and viewEntities by flowing from an origin through the visible
portals that the origin point can see into. The planes array defines a volume with
the planes pointing outside the volume. Zero planes assumes an unbounded volume.
=======================
*/
void idRenderWorldLocal::FlowViewThroughPortals( const idVec3& origin, int numPlanes, const idPlane* planes )
{
	portalStack_t ps;
	ps.next = NULL;
	ps.p = NULL;
	
	assert( numPlanes <= MAX_PORTAL_PLANES );
	for( int i = 0; i < numPlanes; i++ )
	{
		ps.portalPlanes[i] = planes[i];
	}
	
	ps.numPortalPlanes = numPlanes;
	ps.rect = tr.viewDef->scissor;
	
	// if outside the world, mark everything
	if( tr.viewDef->areaNum < 0 )
	{
		for( int i = 0; i < numPortalAreas; i++ )
		{
			areaScreenRect[i] = tr.viewDef->scissor;
			AddAreaToView( i, &ps );
		}
	}
	else
	{
		// flood out through portals, setting area viewCount
		FloodViewThroughArea_r( origin, tr.viewDef->areaNum, &ps );
	}
}
예제 #3
0
/*
===================
FloodViewThroughArea_r
===================
*/
void idRenderWorldLocal::FloodViewThroughArea_r( const idVec3 origin, int areaNum, 
								 const struct portalStack_s *ps ) {
	portal_t*		p;
	float			d;
	portalArea_t *	area;
	const portalStack_t	*check;
	portalStack_t	newStack;
	int				i, j;
	idVec3			v1, v2;
	int				addPlanes;
	idFixedWinding	w;		// we won't overflow because MAX_PORTAL_PLANES = 20

	area = &portalAreas[ areaNum ];

	// cull models and lights to the current collection of planes
	AddAreaRefs( areaNum, ps );

	if ( areaScreenRect[areaNum].IsEmpty() ) {
		areaScreenRect[areaNum] = ps->rect;
	} else {
		areaScreenRect[areaNum].Union( ps->rect );
	}

	// go through all the portals
	for ( p = area->portals; p; p = p->next ) {
		// an enclosing door may have sealed the portal off
		if ( p->doublePortal->blockingBits & PS_BLOCK_VIEW ) {
			continue;
		}

		// make sure this portal is facing away from the view
		d = p->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 = ps; check; check = check->next ) {
			if ( check->p == p ) {
				break;		// don't recursively enter a stack
			}
		}
		if ( check ) {
			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 = *ps;
			newStack.p = p;
			newStack.next = ps;
			FloodViewThroughArea_r( origin, p->intoArea, &newStack );
			continue;
		}

		// clip the portal winding to all of the planes
		w = *p->w;
		for ( j = 0; j < ps->numPortalPlanes; j++ ) {
			if ( !w.ClipInPlace( -ps->portalPlanes[j], 0 ) ) {
				break;
			}
		}
		if ( !w.GetNumPoints() ) {
			continue;	// portal not visible
		}

		// see if it is fogged out
		if ( PortalIsFoggedOut( p ) ) {
			continue;
		}

		// go through this portal
		newStack.p = p;
		newStack.next = ps;

		// find the screen pixel bounding box of the remaining portal
		// so we can scissor things outside it
		newStack.rect = ScreenRectFromWinding( &w, &tr.identitySpace );
		
		// slop might have spread it a pixel outside, so trim it back
		newStack.rect.Intersect( ps->rect );

		// generate a set of clipping planes that will further restrict
		// the visible view beyond just the scissor rect

		addPlanes = w.GetNumPoints();
		if ( addPlanes > MAX_PORTAL_PLANES ) {
			addPlanes = MAX_PORTAL_PLANES;
		}

		newStack.numPortalPlanes = 0;
		for ( i = 0; i < addPlanes; i++ ) {
			j = i+1;
			if ( j == w.GetNumPoints() ) {
				j = 0;
			}

			v1 = origin - w[i].ToVec3();
			v2 = origin - w[j].ToVec3();

			newStack.portalPlanes[newStack.numPortalPlanes].Normal().Cross( v2, v1 );

			// if it is degenerate, skip the plane
			if ( newStack.portalPlanes[newStack.numPortalPlanes].Normalize() < 0.01f ) {
				continue;
			}
			newStack.portalPlanes[newStack.numPortalPlanes].FitThroughPoint( origin );

			newStack.numPortalPlanes++;
		}

		// the last stack plane is the portal plane
		newStack.portalPlanes[newStack.numPortalPlanes] = p->plane;
		newStack.numPortalPlanes++;

		FloodViewThroughArea_r( origin, p->intoArea, &newStack );
	}
}