Example #1
0
/*
================
FreeDMapFile
================
*/
void FreeDMapFile( void )
{
    int		i, j;

    FreeBrush( buildBrush );
    buildBrush = NULL;

    // free the entities and brushes
    for( i = 0; i < dmapGlobals.num_entities; i++ )
    {
        uEntity_t	*ent;
        primitive_t	*prim, *nextPrim;

        ent = &dmapGlobals.uEntities[i];

        FreeTree( ent->tree );

        // free primitives
        for( prim = ent->primitives; prim; prim = nextPrim )
        {
            nextPrim = prim->next;

            if( prim->brush )
            {
                FreeBrush( prim->brush );
            }

            if( prim->tris )
            {
                FreeTriList( prim->tris );
            }
            Mem_Free( prim );
        }

        // free area surfaces
        if( ent->areas )
        {
            for( j = 0; j < ent->numAreas; j++ )
            {
                uArea_t	*area;

                area = &ent->areas[j];
                FreeOptimizeGroupList( area->groups );

            }
            Mem_Free( ent->areas );
        }
    }
    Mem_Free( dmapGlobals.uEntities );

    dmapGlobals.num_entities = 0;

    // free the map lights
    for( i = 0; i < dmapGlobals.mapLights.Num(); i++ )
    {
        R_FreeLightDefDerivedData( &dmapGlobals.mapLights[i]->def );
    }
    dmapGlobals.mapLights.DeleteContents( true );
}
/*
====================
CarveGroupsByLight

Divide each group into an inside group and an outside group, based
on which fragments are illuminated by the light's beam tree
====================
*/
static void CarveGroupsByLight( uEntity_t *e, mapLight_t *light ) {
	int			i;
	optimizeGroup_t	*group, *newGroup, *carvedGroups, *nextGroup;
	mapTri_t	*tri, *inside, *outside;
	uArea_t		*area;

	for ( i = 0 ; i < e->numAreas ; i++ ) {
		area = &e->areas[i];
		carvedGroups = NULL;

		// we will be either freeing or reassigning the groups as we go
		for ( group = area->groups ; group ; group = nextGroup ) {
			nextGroup = group->nextGroup;
			// if the surface doesn't get lit, don't carve it up
			if ( ( light->def.lightShader->IsFogLight() && !group->material->ReceivesFog() )
				|| ( !light->def.lightShader->IsFogLight() && !group->material->ReceivesLighting() )
				|| !group->bounds.IntersectsBounds( light->def.frustumTris->bounds ) ) {

				group->nextGroup = carvedGroups;
				carvedGroups = group;
				continue;
			}

			if ( group->numGroupLights == MAX_GROUP_LIGHTS ) {
				common->Error( "MAX_GROUP_LIGHTS around %f %f %f",
					 group->triList->v[0].xyz[0], group->triList->v[0].xyz[1], group->triList->v[0].xyz[2] );
			}

			// if the group doesn't face the light,
			// it won't get carved at all
			if ( !light->def.lightShader->LightEffectsBackSides() &&
				!group->material->ReceivesLightingOnBackSides() &&
				dmapGlobals.mapPlanes[ group->planeNum ].Distance( light->def.parms.origin ) <= 0  ) {

				group->nextGroup = carvedGroups;
				carvedGroups = group;
				continue;
			}

			// split into lists for hit-by-light, and not-hit-by-light
			inside = NULL;
			outside = NULL;

			for ( tri = group->triList ; tri ; tri = tri->next ) {
				mapTri_t	*in, *out;

				ClipTriByLight( light, tri, &in, &out );
				inside = MergeTriLists( inside, in );
				outside = MergeTriLists( outside, out );
			}

			if ( inside ) {
				newGroup = (optimizeGroup_t *)Mem_Alloc( sizeof( *newGroup ) );
				*newGroup = *group;
				newGroup->groupLights[newGroup->numGroupLights] = light;
				newGroup->numGroupLights++;
				newGroup->triList = inside;
				newGroup->nextGroup = carvedGroups;
				carvedGroups = newGroup;
			}

			if ( outside ) {
				newGroup = (optimizeGroup_t *)Mem_Alloc( sizeof( *newGroup ) );
				*newGroup = *group;
				newGroup->triList = outside;
				newGroup->nextGroup = carvedGroups;
				carvedGroups = newGroup;
			}

			// free the original
			group->nextGroup = NULL;
			FreeOptimizeGroupList( group );
		}

		// replace this area's group list with the new one
		area->groups = carvedGroups;
	}
}
/*
====================
BuildLightShadows

Build the beam tree and shadow volume surface for a light
====================
*/
static void BuildLightShadows( uEntity_t *e, mapLight_t *light ) {
	int			i;
	optimizeGroup_t	*group;
	mapTri_t	*tri;
	mapTri_t	*shadowers;
	optimizeGroup_t		*shadowerGroups;
	idVec3		lightOrigin;
	bool		hasPerforatedSurface = false;

	//
	// build a group list of all the triangles that will contribute to
	// the optimized shadow volume, leaving the original triangles alone
	//


	// shadowers will contain all the triangles that will contribute to the
	// shadow volume
	shadowerGroups = NULL;
	lightOrigin = light->def.globalLightOrigin;

	// if the light is no-shadows, don't add any surfaces
	// to the beam tree at all
	if ( !light->def.parms.noShadows
		&& light->def.lightShader->LightCastsShadows() ) {
		for ( i = 0 ; i < e->numAreas ; i++ ) {
			for ( group = e->areas[i].groups ; group ; group = group->nextGroup ) {
				// if the surface doesn't cast shadows, skip it
				if ( !group->material->SurfaceCastsShadow() ) {
					continue;
				}

				// if the group doesn't face away from the light, it
				// won't contribute to the shadow volume
				if ( dmapGlobals.mapPlanes[ group->planeNum ].Distance( lightOrigin ) > 0 ) {
					continue;
				}

				// if the group bounds doesn't intersect the light bounds,
				// skip it
				if ( !group->bounds.IntersectsBounds( light->def.frustumTris->bounds ) ) {
					continue;
				}

				// build up a list of the triangle fragments inside the
				// light frustum
				shadowers = NULL;
				for ( tri = group->triList ; tri ; tri = tri->next ) {
					mapTri_t	*in, *out;

					// clip it to the light frustum
					ClipTriByLight( light, tri, &in, &out );
					FreeTriList( out );
					shadowers = MergeTriLists( shadowers, in );
				}

				// if we didn't get any out of this group, we don't
				// need to create a new group in the shadower list
				if ( !shadowers ) {
					continue;
				}

				// find a group in shadowerGroups to add these to
				// we will ignore everything but planenum, and we
				// can merge across areas
				optimizeGroup_t	*check;

				for ( check = shadowerGroups ; check ; check = check->nextGroup ) {
					if ( check->planeNum == group->planeNum ) {
						break;
					}
				}
				if ( !check ) {
					check = (optimizeGroup_t *)Mem_Alloc( sizeof( *check ) );
					*check = *group;
					check->triList = NULL;
					check->nextGroup = shadowerGroups;
					shadowerGroups = check;
				}

				// if any surface is a shadow-casting perforated or translucent surface, we
				// can't use the face removal optimizations because we can see through
				// some of the faces
				if ( group->material->Coverage() != MC_OPAQUE ) {
					hasPerforatedSurface = true;
				}

				check->triList = MergeTriLists( check->triList, shadowers );
			}
		}
	}

	// take the shadower group list and create a beam tree and shadow volume
	light->shadowTris = CreateLightShadow( shadowerGroups, light );

	if ( light->shadowTris && hasPerforatedSurface ) {
		// can't ever remove front faces, because we can see through some of them
		light->shadowTris->numShadowIndexesNoCaps = light->shadowTris->numShadowIndexesNoFrontCaps =
			light->shadowTris->numIndexes;
	}

	// we don't need the original shadower triangles for anything else
	FreeOptimizeGroupList( shadowerGroups );
}