/*
=====================
R_PolytopeSurface

Generate vertexes and indexes for a polytope, and optionally returns the polygon windings.
The positive sides of the planes will be visible.
=====================
*/
srfTriangles_t *R_PolytopeSurface( int numPlanes, const idPlane *planes, idWinding **windings ) {
	int i, j;
	srfTriangles_t *tri;
	idFixedWinding planeWindings[MAX_POLYTOPE_PLANES];
	int numVerts, numIndexes;
	if( numPlanes > MAX_POLYTOPE_PLANES ) {
		common->Error( "R_PolytopeSurface: more than %d planes", MAX_POLYTOPE_PLANES );
	}
	numVerts = 0;
	numIndexes = 0;
	for( i = 0; i < numPlanes; i++ ) {
		const idPlane &plane = planes[i];
		idFixedWinding &w = planeWindings[i];
		w.BaseForPlane( plane );
		for( j = 0; j < numPlanes; j++ ) {
			const idPlane &plane2 = planes[j];
			if( j == i ) {
				continue;
			} else if( !w.ClipInPlace( -plane2, ON_EPSILON ) ) {
				break;
			}
		}
		if( w.GetNumPoints() <= 2 ) {
			continue;
		}
		numVerts += w.GetNumPoints();
		numIndexes += ( w.GetNumPoints() - 2 ) * 3;
	}
	// allocate the surface
	tri = R_AllocStaticTriSurf();
	R_AllocStaticTriSurfVerts( tri, numVerts );
	R_AllocStaticTriSurfIndexes( tri, numIndexes );
	// copy the data from the windings
	for( i = 0; i < numPlanes; i++ ) {
		idFixedWinding &w = planeWindings[i];
		if( !w.GetNumPoints() ) {
			continue;
		}
		for( j = 0 ; j < w.GetNumPoints() ; j++ ) {
			tri->verts[tri->numVerts + j ].Clear();
			tri->verts[tri->numVerts + j ].xyz = w[j].ToVec3();
		}
		for( j = 1 ; j < w.GetNumPoints() - 1 ; j++ ) {
			tri->indexes[ tri->numIndexes + 0 ] = tri->numVerts;
			tri->indexes[ tri->numIndexes + 1 ] = tri->numVerts + j;
			tri->indexes[ tri->numIndexes + 2 ] = tri->numVerts + j + 1;
			tri->numIndexes += 3;
		}
		tri->numVerts += w.GetNumPoints();
		// optionally save the winding
		if( windings ) {
			windings[i] = new idWinding( w.GetNumPoints() );
			*windings[i] = w;
		}
	}
	R_BoundTriSurf( tri );
	return tri;
}
Exemple #2
0
/*
================
CombineModelSurfaces

Frees the model and returns a new model with all triangles combined
into one surface
================
*/
static idRenderModel *CombineModelSurfaces( idRenderModel *model ) {
	int		totalVerts;
	int		totalIndexes;
	int		numIndexes;
	int		numVerts;
	int		i, j;

	totalVerts = 0;
	totalIndexes = 0;

	for ( i = 0 ; i < model->NumSurfaces() ; i++ ) {
		const modelSurface_t	*surf = model->Surface(i);

		totalVerts += surf->geometry->numVerts;
		totalIndexes += surf->geometry->numIndexes;
	}

	srfTriangles_t *newTri = R_AllocStaticTriSurf();
	R_AllocStaticTriSurfVerts( newTri, totalVerts );
	R_AllocStaticTriSurfIndexes( newTri, totalIndexes );

	newTri->numVerts = totalVerts;
	newTri->numIndexes = totalIndexes;

	newTri->bounds.Clear();

	idDrawVert *verts = newTri->verts;
	glIndex_t *indexes = newTri->indexes;
	numIndexes = 0;
	numVerts = 0;
	for ( i = 0 ; i < model->NumSurfaces() ; i++ ) {
		const modelSurface_t *surf = model->Surface(i);
		const srfTriangles_t *tri = surf->geometry;

		memcpy( verts + numVerts, tri->verts, tri->numVerts * sizeof( tri->verts[0] ) );
		for ( j = 0 ; j < tri->numIndexes ; j++ ) {
			indexes[numIndexes+j] = numVerts + tri->indexes[j];
		}
		newTri->bounds.AddBounds( tri->bounds );
		numIndexes += tri->numIndexes;
		numVerts += tri->numVerts;
	}

	modelSurface_t surf;

	surf.id = 0;
	surf.geometry = newTri;
	surf.shader = tr.defaultMaterial;

	idRenderModel *newModel = renderModelManager->AllocModel();
	newModel->AddSurface( surf );

	renderModelManager->FreeModel( model );

	return newModel;
}
/*
================
idRenderWorldLocal::ParseShadowModel
================
*/
idRenderModel *idRenderWorldLocal::ParseShadowModel( idLexer *src ) {
	idRenderModel	*model;
	idToken			token;
	int				j;
	srfTriangles_t	*tri;
	modelSurface_t	surf;

	src->ExpectTokenString( "{" );

	// parse the name
	src->ExpectAnyToken( &token );

	model = renderModelManager->AllocModel();
	model->InitEmpty( token );

	surf.shader = tr.defaultMaterial;

	tri = R_AllocStaticTriSurf();
	surf.geometry = tri;

	tri->numVerts = src->ParseInt();
	tri->numShadowIndexesNoCaps = src->ParseInt();
	tri->numShadowIndexesNoFrontCaps = src->ParseInt();
	tri->numIndexes = src->ParseInt();
	tri->shadowCapPlaneBits = src->ParseInt();

	R_AllocStaticTriSurfShadowVerts( tri, tri->numVerts );
	tri->bounds.Clear();
	for ( j = 0 ; j < tri->numVerts ; j++ ) {
		float	vec[8];

		src->Parse1DMatrix( 3, vec );
		tri->shadowVertexes[j].xyz[0] = vec[0];
		tri->shadowVertexes[j].xyz[1] = vec[1];
		tri->shadowVertexes[j].xyz[2] = vec[2];
		tri->shadowVertexes[j].xyz[3] = 1;		// no homogenous value

		tri->bounds.AddPoint( tri->shadowVertexes[j].xyz.ToVec3() );
	}

	R_AllocStaticTriSurfIndexes( tri, tri->numIndexes );
	for ( j = 0 ; j < tri->numIndexes ; j++ ) {
		tri->indexes[j] = src->ParseInt();
	}

	// add the completed surface to the model
	model->AddSurface( surf );

	src->ExpectTokenString( "}" );

	// we do NOT do a model->FinishSurfaceces, because we don't need sil edges, planes, tangents, etc.
//	model->FinishSurfaces();

	return model;
}
Exemple #4
0
/*
====================
ShareMapTriVerts

Converts independent triangles to shared vertex triangles
====================
*/
srfTriangles_t	*ShareMapTriVerts( const mapTri_t *tris )
{
    const mapTri_t	*step;
    int			count;
    int			i, j;
    int			numVerts;
    int			numIndexes;
    srfTriangles_t	*uTri;

    // unique the vertexes
    count = CountTriList( tris );

    uTri = R_AllocStaticTriSurf();
    R_AllocStaticTriSurfVerts( uTri, count * 3 );
    R_AllocStaticTriSurfIndexes( uTri, count * 3 );

    numVerts = 0;
    numIndexes = 0;

    for ( step = tris ; step ; step = step->next )
    {
        for ( i = 0 ; i < 3 ; i++ )
        {
            const idDrawVert	*dv;

            dv = &step->v[i];

            // search for a match
            for ( j = 0 ; j < numVerts ; j++ )
            {
                if ( MatchVert( &uTri->verts[j], dv ) )
                {
                    break;
                }
            }
            if ( j == numVerts )
            {
                numVerts++;
                uTri->verts[j].xyz = dv->xyz;
                uTri->verts[j].normal = dv->normal;
                uTri->verts[j].st[0] = dv->st[0];
                uTri->verts[j].st[1] = dv->st[1];
            }

            uTri->indexes[numIndexes++] = j;
        }
    }

    uTri->numVerts = numVerts;
    uTri->numIndexes = numIndexes;

    return uTri;
}
/*
================
idRenderWorldLocal::ParseShadowModel
================
*/
idRenderModel* idRenderWorldLocal::ParseShadowModel( idLexer* src, idFile* fileOut )
{
	idToken token;
	
	src->ExpectTokenString( "{" );
	
	// parse the name
	src->ExpectAnyToken( &token );
	
	idRenderModel* model = renderModelManager->AllocModel();
	model->InitEmpty( token );
	
	if( fileOut != NULL )
	{
		// write out the type so the binary reader knows what to instantiate
		fileOut->WriteString( "shadowmodel" );
		fileOut->WriteString( token );
	}
	
	srfTriangles_t* tri = R_AllocStaticTriSurf();
	
	tri->numVerts = src->ParseInt();
	tri->numShadowIndexesNoCaps = src->ParseInt();
	tri->numShadowIndexesNoFrontCaps = src->ParseInt();
	tri->numIndexes = src->ParseInt();
	tri->shadowCapPlaneBits = src->ParseInt();
	
	assert( ( tri->numVerts & 1 ) == 0 );
	
	R_AllocStaticTriSurfPreLightShadowVerts( tri, ALIGN( tri->numVerts, 2 ) );
	tri->bounds.Clear();
	for( int j = 0; j < tri->numVerts; j++ )
	{
		float vec[8];
		
		src->Parse1DMatrix( 3, vec );
		tri->preLightShadowVertexes[j].xyzw[0] = vec[0];
		tri->preLightShadowVertexes[j].xyzw[1] = vec[1];
		tri->preLightShadowVertexes[j].xyzw[2] = vec[2];
		tri->preLightShadowVertexes[j].xyzw[3] = 1.0f;		// no homogenous value
		
		tri->bounds.AddPoint( tri->preLightShadowVertexes[j].xyzw.ToVec3() );
	}
	// clear the last vertex if it wasn't stored
	if( ( tri->numVerts & 1 ) != 0 )
	{
		tri->preLightShadowVertexes[ALIGN( tri->numVerts, 2 ) - 1].xyzw.Zero();
	}
	
	// to be consistent set the number of vertices to half the number of shadow vertices
	tri->numVerts = ALIGN( tri->numVerts, 2 ) / 2;
	
	R_AllocStaticTriSurfIndexes( tri, tri->numIndexes );
	for( int j = 0; j < tri->numIndexes; j++ )
	{
		tri->indexes[j] = src->ParseInt();
	}
	
	// add the completed surface to the model
	modelSurface_t surf;
	surf.id = 0;
	surf.shader = tr.defaultMaterial;
	surf.geometry = tri;
	
	model->AddSurface( surf );
	
	src->ExpectTokenString( "}" );
	
	// NOTE: we do NOT do a model->FinishSurfaceces, because we don't need sil edges, planes, tangents, etc.
	
	if( fileOut != NULL && model->SupportsBinaryModel() && r_binaryLoadRenderModels.GetBool() )
	{
		model->WriteBinaryModel( fileOut, &mapTimeStamp );
	}
	
	return model;
}
/*
================
idRenderWorldLocal::ParseModel
================
*/
idRenderModel* idRenderWorldLocal::ParseModel( idLexer* src, const char* mapName, ID_TIME_T mapTimeStamp, idFile* fileOut )
{
	idToken token;
	
	src->ExpectTokenString( "{" );
	
	// parse the name
	src->ExpectAnyToken( &token );
	
	idRenderModel* model = renderModelManager->AllocModel();
	model->InitEmpty( token );
	
	if( fileOut != NULL )
	{
		// write out the type so the binary reader knows what to instantiate
		fileOut->WriteString( "shadowmodel" );
		fileOut->WriteString( token );
	}
	
	int numSurfaces = src->ParseInt();
	if( numSurfaces < 0 )
	{
		src->Error( "R_ParseModel: bad numSurfaces" );
	}
	
	for( int i = 0; i < numSurfaces; i++ )
	{
		src->ExpectTokenString( "{" );
		
		src->ExpectAnyToken( &token );
		
		modelSurface_t surf;
		surf.shader = declManager->FindMaterial( token );
		
		( ( idMaterial* )surf.shader )->AddReference();
		
		srfTriangles_t* tri = R_AllocStaticTriSurf();
		surf.geometry = tri;
		
		tri->numVerts = src->ParseInt();
		tri->numIndexes = src->ParseInt();
		
		// parse the vertices
		idTempArray<float> verts( tri->numVerts * 8 );
		for( int j = 0; j < tri->numVerts; j++ )
		{
			src->Parse1DMatrix( 8, &verts[j * 8] );
		}
		
		// parse the indices
		idTempArray<triIndex_t> indexes( tri->numIndexes );
		for( int j = 0; j < tri->numIndexes; j++ )
		{
			indexes[j] = src->ParseInt();
		}
		
#if 1
		// find the island that each vertex belongs to
		idTempArray<int> vertIslands( tri->numVerts );
		idTempArray<bool> trisVisited( tri->numIndexes );
		vertIslands.Zero();
		trisVisited.Zero();
		int numIslands = 0;
		for( int j = 0; j < tri->numIndexes; j += 3 )
		{
			if( trisVisited[j] )
			{
				continue;
			}
			
			int islandNum = ++numIslands;
			vertIslands[indexes[j + 0]] = islandNum;
			vertIslands[indexes[j + 1]] = islandNum;
			vertIslands[indexes[j + 2]] = islandNum;
			trisVisited[j] = true;
			
			idList<int> queue;
			queue.Append( j );
			for( int n = 0; n < queue.Num(); n++ )
			{
				int t = queue[n];
				for( int k = 0; k < tri->numIndexes; k += 3 )
				{
					if( trisVisited[k] )
					{
						continue;
					}
					bool connected =	indexes[t + 0] == indexes[k + 0] || indexes[t + 0] == indexes[k + 1] || indexes[t + 0] == indexes[k + 2] ||
										indexes[t + 1] == indexes[k + 0] || indexes[t + 1] == indexes[k + 1] || indexes[t + 1] == indexes[k + 2] ||
										indexes[t + 2] == indexes[k + 0] || indexes[t + 2] == indexes[k + 1] || indexes[t + 2] == indexes[k + 2];
					if( connected )
					{
						vertIslands[indexes[k + 0]] = islandNum;
						vertIslands[indexes[k + 1]] = islandNum;
						vertIslands[indexes[k + 2]] = islandNum;
						trisVisited[k] = true;
						queue.Append( k );
					}
				}
			}
		}
		
		// center the texture coordinates for each island for maximum 16-bit precision
		for( int j = 1; j <= numIslands; j++ )
		{
			float minS = idMath::INFINITY;
			float minT = idMath::INFINITY;
			float maxS = -idMath::INFINITY;
			float maxT = -idMath::INFINITY;
			for( int k = 0; k < tri->numVerts; k++ )
			{
				if( vertIslands[k] == j )
				{
					minS = Min( minS, verts[k * 8 + 3] );
					maxS = Max( maxS, verts[k * 8 + 3] );
					minT = Min( minT, verts[k * 8 + 4] );
					maxT = Max( maxT, verts[k * 8 + 4] );
				}
			}
			const float averageS = idMath::Ftoi( ( minS + maxS ) * 0.5f );
			const float averageT = idMath::Ftoi( ( minT + maxT ) * 0.5f );
			for( int k = 0; k < tri->numVerts; k++ )
			{
				if( vertIslands[k] == j )
				{
					verts[k * 8 + 3] -= averageS;
					verts[k * 8 + 4] -= averageT;
				}
			}
		}
#endif
		
		R_AllocStaticTriSurfVerts( tri, tri->numVerts );
		for( int j = 0; j < tri->numVerts; j++ )
		{
			tri->verts[j].xyz[0] = verts[j * 8 + 0];
			tri->verts[j].xyz[1] = verts[j * 8 + 1];
			tri->verts[j].xyz[2] = verts[j * 8 + 2];
			tri->verts[j].SetTexCoord( verts[j * 8 + 3], verts[j * 8 + 4] );
			tri->verts[j].SetNormal( verts[j * 8 + 5], verts[j * 8 + 6], verts[j * 8 + 7] );
		}
		
		R_AllocStaticTriSurfIndexes( tri, tri->numIndexes );
		for( int j = 0; j < tri->numIndexes; j++ )
		{
			tri->indexes[j] = indexes[j];
		}
		src->ExpectTokenString( "}" );
		
		// add the completed surface to the model
		model->AddSurface( surf );
	}
	
	src->ExpectTokenString( "}" );
	
	model->FinishSurfaces();
	
	if( fileOut != NULL && model->SupportsBinaryModel() && r_binaryLoadRenderModels.GetBool() )
	{
		model->WriteBinaryModel( fileOut, &mapTimeStamp );
	}
	
	return model;
}
/*
====================
R_CreateLightTris

The resulting surface will be a subset of the original triangles,
it will never clip triangles, but it may cull on a per-triangle basis.
====================
*/
static srfTriangles_t *R_CreateLightTris( const idRenderEntityLocal *ent, 
									 const srfTriangles_t *tri, const idRenderLightLocal *light,
									 const idMaterial *shader, srfCullInfo_t &cullInfo ) {
	int			i;
	int			numIndexes;
	glIndex_t	*indexes;
	srfTriangles_t	*newTri;
	int			c_backfaced;
	int			c_distance;
	idBounds	bounds;
	bool		includeBackFaces;
	int			faceNum;

	tr.pc.c_createLightTris++;
	c_backfaced = 0;
	c_distance = 0;

	numIndexes = 0;
	indexes = NULL;

	// it is debatable if non-shadowing lights should light back faces. we aren't at the moment
	if ( r_lightAllBackFaces.GetBool() || light->lightShader->LightEffectsBackSides()
			|| shader->ReceivesLightingOnBackSides()
				|| ent->parms.noSelfShadow || ent->parms.noShadow  ) {
		includeBackFaces = true;
	} else {
		includeBackFaces = false;
	}

	// allocate a new surface for the lit triangles
	newTri = R_AllocStaticTriSurf();

	// save a reference to the original surface
	newTri->ambientSurface = const_cast<srfTriangles_t *>(tri);

	// the light surface references the verts of the ambient surface
	newTri->numVerts = tri->numVerts;
	R_ReferenceStaticTriSurfVerts( newTri, tri );

	// calculate cull information
	if ( !includeBackFaces ) {
		R_CalcInteractionFacing( ent, tri, light, cullInfo );
	}
	R_CalcInteractionCullBits( ent, tri, light, cullInfo );

	// if the surface is completely inside the light frustum
	if ( cullInfo.cullBits == LIGHT_CULL_ALL_FRONT ) {

		// if we aren't self shadowing, let back facing triangles get
		// through so the smooth shaded bump maps light all the way around
		if ( includeBackFaces ) {

			// the whole surface is lit so the light surface just references the indexes of the ambient surface
			R_ReferenceStaticTriSurfIndexes( newTri, tri );
			numIndexes = tri->numIndexes;
			bounds = tri->bounds;

		} else {

			// the light tris indexes are going to be a subset of the original indexes so we generally
			// allocate too much memory here but we decrease the memory block when the number of indexes is known
			R_AllocStaticTriSurfIndexes( newTri, tri->numIndexes );

			// back face cull the individual triangles
			indexes = newTri->indexes;
			const byte *facing = cullInfo.facing;
			for ( faceNum = i = 0; i < tri->numIndexes; i += 3, faceNum++ ) {
				if ( !facing[ faceNum ] ) {
					c_backfaced++;
					continue;
				}
				indexes[numIndexes+0] = tri->indexes[i+0];
				indexes[numIndexes+1] = tri->indexes[i+1];
				indexes[numIndexes+2] = tri->indexes[i+2];
				numIndexes += 3;
			}

			// get bounds for the surface
			SIMDProcessor->MinMax( bounds[0], bounds[1], tri->verts, indexes, numIndexes );

			// decrease the size of the memory block to the size of the number of used indexes
			R_ResizeStaticTriSurfIndexes( newTri, numIndexes );
		}

	} else {

		// the light tris indexes are going to be a subset of the original indexes so we generally
		// allocate too much memory here but we decrease the memory block when the number of indexes is known
		R_AllocStaticTriSurfIndexes( newTri, tri->numIndexes );

		// cull individual triangles
		indexes = newTri->indexes;
		const byte *facing = cullInfo.facing;
		const byte *cullBits = cullInfo.cullBits;
		for ( faceNum = i = 0; i < tri->numIndexes; i += 3, faceNum++ ) {
			int i1, i2, i3;

			// if we aren't self shadowing, let back facing triangles get
			// through so the smooth shaded bump maps light all the way around
			if ( !includeBackFaces ) {
				// back face cull
				if ( !facing[ faceNum ] ) {
					c_backfaced++;
					continue;
				}
			}

			i1 = tri->indexes[i+0];
			i2 = tri->indexes[i+1];
			i3 = tri->indexes[i+2];

			// fast cull outside the frustum
			// if all three points are off one plane side, it definately isn't visible
			if ( cullBits[i1] & cullBits[i2] & cullBits[i3] ) {
				c_distance++;
				continue;
			}

			if ( r_usePreciseTriangleInteractions.GetBool() ) {
				// do a precise clipped cull if none of the points is completely inside the frustum
				// note that we do not actually use the clipped triangle, which would have Z fighting issues.
				if ( cullBits[i1] && cullBits[i2] && cullBits[i3] ) {
					int cull = cullBits[i1] | cullBits[i2] | cullBits[i3];
					if ( !R_ClipTriangleToLight( tri->verts[i1].xyz, tri->verts[i2].xyz, tri->verts[i3].xyz, cull, cullInfo.localClipPlanes ) ) {
						continue;
					}
				}
			}

			// add to the list
			indexes[numIndexes+0] = i1;
			indexes[numIndexes+1] = i2;
			indexes[numIndexes+2] = i3;
			numIndexes += 3;
		}

		// get bounds for the surface
		SIMDProcessor->MinMax( bounds[0], bounds[1], tri->verts, indexes, numIndexes );

		// decrease the size of the memory block to the size of the number of used indexes
		R_ResizeStaticTriSurfIndexes( newTri, numIndexes );
	}

	if ( !numIndexes ) {
		R_ReallyFreeStaticTriSurf( newTri );
		return NULL;
	}

	newTri->numIndexes = numIndexes;

	newTri->bounds = bounds;

	return newTri;
}
/*
====================
idRenderModelOverlay::AddOverlaySurfacesToModel
====================
*/
void idRenderModelOverlay::AddOverlaySurfacesToModel( idRenderModel *baseModel ) {
	int i, j, k, numVerts, numIndexes, surfaceNum;
	const modelSurface_t *baseSurf;
	idRenderModelStatic *staticModel;
	overlaySurface_t *surf;
	srfTriangles_t *newTri;
	modelSurface_t *newSurf;

	if ( baseModel == NULL || baseModel->IsDefaultModel() ) {
		return;
	}

	// md5 models won't have any surfaces when r_showSkel is set
	if ( !baseModel->NumSurfaces() ) {
		return;
	}

	if ( baseModel->IsDynamicModel() != DM_STATIC ) {
		common->Error( "idRenderModelOverlay::AddOverlaySurfacesToModel: baseModel is not a static model" );
	}

	assert( dynamic_cast<idRenderModelStatic *>(baseModel) != NULL );
	staticModel = static_cast<idRenderModelStatic *>(baseModel);

	staticModel->overlaysAdded = 0;

	if ( !materials.Num() ) {
		staticModel->DeleteSurfacesWithNegativeId();
		return;
	}

	for ( k = 0; k < materials.Num(); k++ ) {

		numVerts = numIndexes = 0;
		for ( i = 0; i < materials[k]->surfaces.Num(); i++ ) {
			numVerts += materials[k]->surfaces[i]->numVerts;
			numIndexes += materials[k]->surfaces[i]->numIndexes;
		}

		if ( staticModel->FindSurfaceWithId( -1 - k, surfaceNum ) ) {
			newSurf = &staticModel->surfaces[surfaceNum];
		} else {
			newSurf = &staticModel->surfaces.Alloc();
			newSurf->geometry = NULL;
			newSurf->shader = materials[k]->material;
			newSurf->id = -1 - k;
		}

		if ( newSurf->geometry == NULL || newSurf->geometry->numVerts < numVerts || newSurf->geometry->numIndexes < numIndexes ) {
			R_FreeStaticTriSurf( newSurf->geometry );
			newSurf->geometry = R_AllocStaticTriSurf();
			R_AllocStaticTriSurfVerts( newSurf->geometry, numVerts );
			R_AllocStaticTriSurfIndexes( newSurf->geometry, numIndexes );
			SIMDProcessor->Memset( newSurf->geometry->verts, 0, numVerts * sizeof( newTri->verts[0] ) );
		} else {
			R_FreeStaticTriSurfVertexCaches( newSurf->geometry );
		}

		newTri = newSurf->geometry;
		numVerts = numIndexes = 0;

		for ( i = 0; i < materials[k]->surfaces.Num(); i++ ) {
			surf = materials[k]->surfaces[i];

			// get the model surface for this overlay surface
			if ( surf->surfaceNum < staticModel->NumSurfaces() ) {
				baseSurf = staticModel->Surface( surf->surfaceNum );
			} else {
				baseSurf = NULL;
			}

			// if the surface ids no longer match
			if ( !baseSurf || baseSurf->id != surf->surfaceId ) {
				// find the surface with the correct id
				if ( staticModel->FindSurfaceWithId( surf->surfaceId, surf->surfaceNum ) ) {
					baseSurf = staticModel->Surface( surf->surfaceNum );
				} else {
					// the surface with this id no longer exists
					FreeSurface( surf );
					materials[k]->surfaces.RemoveIndex( i );
					i--;
					continue;
				}
			}

			// copy indexes;
			for ( j = 0; j < surf->numIndexes; j++ ) {
				newTri->indexes[numIndexes + j] = numVerts + surf->indexes[j];
			}
			numIndexes += surf->numIndexes;

			// copy vertices
			for ( j = 0; j < surf->numVerts; j++ ) {
				overlayVertex_t *overlayVert = &surf->verts[j];

				newTri->verts[numVerts].st[0] = overlayVert->st[0];
				newTri->verts[numVerts].st[1] = overlayVert->st[1];

				if ( overlayVert->vertexNum >= baseSurf->geometry->numVerts ) {
					// This can happen when playing a demofile and a model has been changed since it was recorded, so just issue a warning and go on.
					common->Warning( "idRenderModelOverlay::AddOverlaySurfacesToModel: overlay vertex out of range.  Model has probably changed since generating the overlay." );
					FreeSurface( surf );
					materials[k]->surfaces.RemoveIndex( i );
					staticModel->DeleteSurfaceWithId( newSurf->id );
					return;
				}
				newTri->verts[numVerts].xyz = baseSurf->geometry->verts[overlayVert->vertexNum].xyz;
				numVerts++;
			}
		}

		newTri->numVerts = numVerts;
		newTri->numIndexes = numIndexes;
		R_BoundTriSurf( newTri );

		staticModel->overlaysAdded++;	// so we don't create an overlay on an overlay surface
	}
}
Exemple #9
0
/*
====================
R_CreateInteractionLightTris

This is only used for the static interaction case, dynamic interactions
just draw everything and let the GPU deal with it.

The resulting surface will be a subset of the original triangles,
it will never clip triangles, but it may cull on a per-triangle basis.
====================
*/
static srfTriangles_t* R_CreateInteractionLightTris( const idRenderEntityLocal* ent,
		const srfTriangles_t* tri, const idRenderLightLocal* light,
		const idMaterial* shader )
{

	SCOPED_PROFILE_EVENT( "R_CreateInteractionLightTris" );
	
	int			i;
	int			numIndexes;
	triIndex_t*	indexes;
	srfTriangles_t*	newTri;
	int			c_backfaced;
	int			c_distance;
	idBounds	bounds;
	bool		includeBackFaces;
	int			faceNum;
	
	c_backfaced = 0;
	c_distance = 0;
	
	numIndexes = 0;
	indexes = NULL;
	
	// it is debatable if non-shadowing lights should light back faces. we aren't at the moment
	// RB: now we do with r_useHalfLambert, so don't cull back faces if we have smooth shadowing enabled
	if( r_lightAllBackFaces.GetBool() || light->lightShader->LightEffectsBackSides()
			|| shader->ReceivesLightingOnBackSides() || ent->parms.noSelfShadow || ent->parms.noShadow || ( r_useHalfLambertLighting.GetInteger() && r_useShadowMapping.GetBool() ) )
	{
		includeBackFaces = true;
	}
	else
	{
		includeBackFaces = false;
	}
	
	// allocate a new surface for the lit triangles
	newTri = R_AllocStaticTriSurf();
	
	// save a reference to the original surface
	newTri->ambientSurface = const_cast<srfTriangles_t*>( tri );
	
	// the light surface references the verts of the ambient surface
	newTri->numVerts = tri->numVerts;
	R_ReferenceStaticTriSurfVerts( newTri, tri );
	
	// calculate cull information
	srfCullInfo_t cullInfo = {};
	
	if( !includeBackFaces )
	{
		R_CalcInteractionFacing( ent, tri, light, cullInfo );
	}
	R_CalcInteractionCullBits( ent, tri, light, cullInfo );
	
	// if the surface is completely inside the light frustum
	if( cullInfo.cullBits == LIGHT_CULL_ALL_FRONT )
	{
	
		// if we aren't self shadowing, let back facing triangles get
		// through so the smooth shaded bump maps light all the way around
		if( includeBackFaces )
		{
		
			// the whole surface is lit so the light surface just references the indexes of the ambient surface
			newTri->indexes = tri->indexes;
			newTri->indexCache = tri->indexCache;
//			R_ReferenceStaticTriSurfIndexes( newTri, tri );

			numIndexes = tri->numIndexes;
			bounds = tri->bounds;
			
		}
		else
		{
		
			// the light tris indexes are going to be a subset of the original indexes so we generally
			// allocate too much memory here but we decrease the memory block when the number of indexes is known
			R_AllocStaticTriSurfIndexes( newTri, tri->numIndexes );
			
			// back face cull the individual triangles
			indexes = newTri->indexes;
			const byte* facing = cullInfo.facing;
			for( faceNum = i = 0; i < tri->numIndexes; i += 3, faceNum++ )
			{
				if( !facing[ faceNum ] )
				{
					c_backfaced++;
					continue;
				}
				indexes[numIndexes + 0] = tri->indexes[i + 0];
				indexes[numIndexes + 1] = tri->indexes[i + 1];
				indexes[numIndexes + 2] = tri->indexes[i + 2];
				numIndexes += 3;
			}
			
			// get bounds for the surface
			SIMDProcessor->MinMax( bounds[0], bounds[1], tri->verts, indexes, numIndexes );
			
			// decrease the size of the memory block to the size of the number of used indexes
			newTri->numIndexes = numIndexes;
			R_ResizeStaticTriSurfIndexes( newTri, numIndexes );
		}
		
	}
	else
	{
	
		// the light tris indexes are going to be a subset of the original indexes so we generally
		// allocate too much memory here but we decrease the memory block when the number of indexes is known
		R_AllocStaticTriSurfIndexes( newTri, tri->numIndexes );
		
		// cull individual triangles
		indexes = newTri->indexes;
		const byte* facing = cullInfo.facing;
		const byte* cullBits = cullInfo.cullBits;
		for( faceNum = i = 0; i < tri->numIndexes; i += 3, faceNum++ )
		{
			int i1, i2, i3;
			
			// if we aren't self shadowing, let back facing triangles get
			// through so the smooth shaded bump maps light all the way around
			if( !includeBackFaces )
			{
				// back face cull
				if( !facing[ faceNum ] )
				{
					c_backfaced++;
					continue;
				}
			}
			
			i1 = tri->indexes[i + 0];
			i2 = tri->indexes[i + 1];
			i3 = tri->indexes[i + 2];
			
			// fast cull outside the frustum
			// if all three points are off one plane side, it definately isn't visible
			if( cullBits[i1] & cullBits[i2] & cullBits[i3] )
			{
				c_distance++;
				continue;
			}
			
			// add to the list
			indexes[numIndexes + 0] = i1;
			indexes[numIndexes + 1] = i2;
			indexes[numIndexes + 2] = i3;
			numIndexes += 3;
		}
		
		// get bounds for the surface
		SIMDProcessor->MinMax( bounds[0], bounds[1], tri->verts, indexes, numIndexes );
		
		// decrease the size of the memory block to the size of the number of used indexes
		newTri->numIndexes = numIndexes;
		R_ResizeStaticTriSurfIndexes( newTri, numIndexes );
	}
	
	// free the cull information when it's no longer needed
	R_FreeInteractionCullInfo( cullInfo );
	
	if( !numIndexes )
	{
		R_FreeStaticTriSurf( newTri );
		return NULL;
	}
	
	newTri->numIndexes = numIndexes;
	
	newTri->bounds = bounds;
	
	return newTri;
}
/*
========================
idRenderModelMD5::LoadBinaryModel
========================
*/
bool idRenderModelMD5::LoadBinaryModel( idFile* file, const ID_TIME_T sourceTimeStamp )
{

	if( !idRenderModelStatic::LoadBinaryModel( file, sourceTimeStamp ) )
	{
		return false;
	}
	
	unsigned int magic = 0;
	file->ReadBig( magic );
	if( magic != MD5B_MAGIC )
	{
		return false;
	}
	
	int tempNum;
	file->ReadBig( tempNum );
	joints.SetNum( tempNum );
	for( int i = 0; i < joints.Num(); i++ )
	{
		file->ReadString( joints[i].name );
		int offset;
		file->ReadBig( offset );
		if( offset >= 0 )
		{
			joints[i].parent = joints.Ptr() + offset;
		}
		else
		{
			joints[i].parent = NULL;
		}
	}
	
	file->ReadBig( tempNum );
	defaultPose.SetNum( tempNum );
	for( int i = 0; i < defaultPose.Num(); i++ )
	{
		file->ReadBig( defaultPose[i].q.x );
		file->ReadBig( defaultPose[i].q.y );
		file->ReadBig( defaultPose[i].q.z );
		file->ReadBig( defaultPose[i].q.w );
		file->ReadVec3( defaultPose[i].t );
	}
	
	file->ReadBig( tempNum );
	invertedDefaultPose.SetNum( tempNum );
	for( int i = 0; i < invertedDefaultPose.Num(); i++ )
	{
		file->ReadBigArray( invertedDefaultPose[ i ].ToFloatPtr(), JOINTMAT_TYPESIZE );
	}
	SIMD_INIT_LAST_JOINT( invertedDefaultPose.Ptr(), joints.Num() );
	
	file->ReadBig( tempNum );
	meshes.SetNum( tempNum );
	for( int i = 0; i < meshes.Num(); i++ )
	{
	
		idStr materialName;
		file->ReadString( materialName );
		if( materialName.IsEmpty() )
		{
			meshes[i].shader = NULL;
		}
		else
		{
			meshes[i].shader = declManager->FindMaterial( materialName );
		}
		
		file->ReadBig( meshes[i].numVerts );
		file->ReadBig( meshes[i].numTris );
		
		file->ReadBig( meshes[i].numMeshJoints );
		meshes[i].meshJoints = ( byte* ) Mem_Alloc( meshes[i].numMeshJoints * sizeof( meshes[i].meshJoints[0] ), TAG_MODEL );
		file->ReadBigArray( meshes[i].meshJoints, meshes[i].numMeshJoints );
		file->ReadBig( meshes[i].maxJointVertDist );
		
		meshes[i].deformInfo = ( deformInfo_t* )R_ClearedStaticAlloc( sizeof( deformInfo_t ) );
		deformInfo_t& deform = *meshes[i].deformInfo;
		
		file->ReadBig( deform.numSourceVerts );
		file->ReadBig( deform.numOutputVerts );
		file->ReadBig( deform.numIndexes );
		file->ReadBig( deform.numMirroredVerts );
		file->ReadBig( deform.numDupVerts );
		file->ReadBig( deform.numSilEdges );
		
		srfTriangles_t	tri;
		memset( &tri, 0, sizeof( srfTriangles_t ) );
		
		if( deform.numOutputVerts > 0 )
		{
			R_AllocStaticTriSurfVerts( &tri, deform.numOutputVerts );
			deform.verts = tri.verts;
			file->ReadBigArray( deform.verts, deform.numOutputVerts );
		}
		
		if( deform.numIndexes > 0 )
		{
			R_AllocStaticTriSurfIndexes( &tri, deform.numIndexes );
			R_AllocStaticTriSurfSilIndexes( &tri, deform.numIndexes );
			deform.indexes = tri.indexes;
			deform.silIndexes = tri.silIndexes;
			file->ReadBigArray( deform.indexes, deform.numIndexes );
			file->ReadBigArray( deform.silIndexes, deform.numIndexes );
		}
		
		if( deform.numMirroredVerts > 0 )
		{
			R_AllocStaticTriSurfMirroredVerts( &tri, deform.numMirroredVerts );
			deform.mirroredVerts = tri.mirroredVerts;
			file->ReadBigArray( deform.mirroredVerts, deform.numMirroredVerts );
		}
		
		if( deform.numDupVerts > 0 )
		{
			R_AllocStaticTriSurfDupVerts( &tri, deform.numDupVerts );
			deform.dupVerts = tri.dupVerts;
			file->ReadBigArray( deform.dupVerts, deform.numDupVerts * 2 );
		}
		
		if( deform.numSilEdges > 0 )
		{
			R_AllocStaticTriSurfSilEdges( &tri, deform.numSilEdges );
			deform.silEdges = tri.silEdges;
			assert( deform.silEdges != NULL );
			for( int j = 0; j < deform.numSilEdges; j++ )
			{
				file->ReadBig( deform.silEdges[j].p1 );
				file->ReadBig( deform.silEdges[j].p2 );
				file->ReadBig( deform.silEdges[j].v1 );
				file->ReadBig( deform.silEdges[j].v2 );
			}
		}
		
		idShadowVertSkinned* shadowVerts = ( idShadowVertSkinned* ) Mem_Alloc( ALIGN( deform.numOutputVerts * 2 * sizeof( idShadowVertSkinned ), 16 ), TAG_MODEL );
		idShadowVertSkinned::CreateShadowCache( shadowVerts, deform.verts, deform.numOutputVerts );
		
		deform.staticAmbientCache = vertexCache.AllocStaticVertex( deform.verts, ALIGN( deform.numOutputVerts * sizeof( idDrawVert ), VERTEX_CACHE_ALIGN ) );
		deform.staticIndexCache = vertexCache.AllocStaticIndex( deform.indexes, ALIGN( deform.numIndexes * sizeof( triIndex_t ), INDEX_CACHE_ALIGN ) );
		deform.staticShadowCache = vertexCache.AllocStaticVertex( shadowVerts, ALIGN( deform.numOutputVerts * 2 * sizeof( idShadowVertSkinned ), VERTEX_CACHE_ALIGN ) );
		
		Mem_Free( shadowVerts );
		
		file->ReadBig( meshes[i].surfaceNum );
	}
	
	return true;
}
Exemple #11
0
/*
=====================
R_CreateVertexProgramTurboShadowVolume

are dangling edges that are outside the light frustum still making planes?
=====================
*/
srfTriangles_t *R_CreateVertexProgramTurboShadowVolume( const idRenderEntityLocal *ent, 
														const srfTriangles_t *tri, const idRenderLightLocal *light,
														srfCullInfo_t &cullInfo ) {
	int		i, j;
	srfTriangles_t	*newTri;
	silEdge_t	*sil;
	const glIndex_t *indexes;
	const byte *facing;

	R_CalcInteractionFacing( ent, tri, light, cullInfo );
	if ( r_useShadowProjectedCull.GetBool() ) {
		R_CalcInteractionCullBits( ent, tri, light, cullInfo );
	}

	int numFaces = tri->numIndexes / 3;
	int	numShadowingFaces = 0;
	facing = cullInfo.facing;

	// if all the triangles are inside the light frustum
	if ( cullInfo.cullBits == LIGHT_CULL_ALL_FRONT || !r_useShadowProjectedCull.GetBool() ) {

		// count the number of shadowing faces
		for ( i = 0; i < numFaces; i++ ) {
			numShadowingFaces += facing[i];
		}
		numShadowingFaces = numFaces - numShadowingFaces;

	} else {

		// make all triangles that are outside the light frustum "facing", so they won't cast shadows
		indexes = tri->indexes;
		byte *modifyFacing = cullInfo.facing;
		const byte *cullBits = cullInfo.cullBits;
		for ( j = i = 0; i < tri->numIndexes; i += 3, j++ ) {
			if ( !modifyFacing[j] ) {
				int	i1 = indexes[i+0];
				int	i2 = indexes[i+1];
				int	i3 = indexes[i+2];
				if ( cullBits[i1] & cullBits[i2] & cullBits[i3] ) {
					modifyFacing[j] = 1;
				} else {
					numShadowingFaces++;
				}
			}
		}
	}

	if ( !numShadowingFaces ) {
		// no faces are inside the light frustum and still facing the right way
		return NULL;
	}

	// shadowVerts will be NULL on these surfaces, so the shadowVerts will be taken from the ambient surface
	newTri = R_AllocStaticTriSurf();

	newTri->numVerts = tri->numVerts * 2;

	// alloc the max possible size
#ifdef USE_TRI_DATA_ALLOCATOR
	R_AllocStaticTriSurfIndexes( newTri, ( numShadowingFaces + tri->numSilEdges ) * 6 );
	glIndex_t *tempIndexes = newTri->indexes;
	glIndex_t *shadowIndexes = newTri->indexes;
#else
	glIndex_t *tempIndexes = (glIndex_t *)_alloca16( tri->numSilEdges * 6 * sizeof( tempIndexes[0] ) );
	glIndex_t *shadowIndexes = tempIndexes;
#endif

	// create new triangles along sil planes
	for ( sil = tri->silEdges, i = tri->numSilEdges; i > 0; i--, sil++ ) {

		int f1 = facing[sil->p1];
		int f2 = facing[sil->p2];

		if ( !( f1 ^ f2 ) ) {
			continue;
		}

		int v1 = sil->v1 << 1;
		int v2 = sil->v2 << 1;

		// set the two triangle winding orders based on facing
		// without using a poorly-predictable branch

		shadowIndexes[0] = v1;
		shadowIndexes[1] = v2 ^ f1;
		shadowIndexes[2] = v2 ^ f2;
		shadowIndexes[3] = v1 ^ f2;
		shadowIndexes[4] = v1 ^ f1;
		shadowIndexes[5] = v2 ^ 1;

		shadowIndexes += 6;
	}

	int	numShadowIndexes = shadowIndexes - tempIndexes;

	// we aren't bothering to separate front and back caps on these
	newTri->numIndexes = newTri->numShadowIndexesNoFrontCaps = numShadowIndexes + numShadowingFaces * 6;
	newTri->numShadowIndexesNoCaps = numShadowIndexes;
	newTri->shadowCapPlaneBits = SHADOW_CAP_INFINITE;

#ifdef USE_TRI_DATA_ALLOCATOR
	// decrease the size of the memory block to only store the used indexes
	R_ResizeStaticTriSurfIndexes( newTri, newTri->numIndexes );
#else
	// allocate memory for the indexes
	R_AllocStaticTriSurfIndexes( newTri, newTri->numIndexes );
	// copy the indexes we created for the sil planes
	SIMDProcessor->Memcpy( newTri->indexes, tempIndexes, numShadowIndexes * sizeof( tempIndexes[0] ) );
#endif

	// these have no effect, because they extend to infinity
	newTri->bounds.Clear();

	// put some faces on the model and some on the distant projection
	indexes = tri->indexes;
	shadowIndexes = newTri->indexes + numShadowIndexes;
	for ( i = 0, j = 0; i < tri->numIndexes; i += 3, j++ ) {
		if ( facing[j] ) {
			continue;
		}

		int i0 = indexes[i+0] << 1;
		shadowIndexes[2] = i0;
		shadowIndexes[3] = i0 ^ 1;
		int i1 = indexes[i+1] << 1;
		shadowIndexes[1] = i1;
		shadowIndexes[4] = i1 ^ 1;
		int i2 = indexes[i+2] << 1;
		shadowIndexes[0] = i2;
		shadowIndexes[5] = i2 ^ 1;

		shadowIndexes += 6;
	}

	return newTri;
}
/*
===============
idRenderModelSprite::InstantiateDynamicModel
===============
*/
idRenderModel *	idRenderModelSprite::InstantiateDynamicModel( const struct renderEntity_s *renderEntity, const struct viewDef_s *viewDef, idRenderModel *cachedModel ) {
	idRenderModelStatic *staticModel;
	srfTriangles_t *tri;
	modelSurface_t surf;

	if ( cachedModel && !r_useCachedDynamicModels.GetBool() ) {
		delete cachedModel;
		cachedModel = NULL;
	}

	if ( renderEntity == NULL || viewDef == NULL ) {
		delete cachedModel;
		return NULL;
	}

	if ( cachedModel != NULL ) {

		assert( dynamic_cast<idRenderModelStatic *>( cachedModel ) != NULL );
		assert( idStr::Icmp( cachedModel->Name(), sprite_SnapshotName ) == 0 );

		staticModel = static_cast<idRenderModelStatic *>( cachedModel );
		surf = *staticModel->Surface( 0 );
		tri = surf.geometry;

	} else {

		staticModel = new idRenderModelStatic;
		staticModel->InitEmpty( sprite_SnapshotName );

		tri = R_AllocStaticTriSurf();
		R_AllocStaticTriSurfVerts( tri, 4 );
		R_AllocStaticTriSurfIndexes( tri, 6 );

		tri->verts[ 0 ].Clear();
		tri->verts[ 0 ].normal.Set( 1.0f, 0.0f, 0.0f );
		tri->verts[ 0 ].tangents[0].Set( 0.0f, 1.0f, 0.0f );
		tri->verts[ 0 ].tangents[1].Set( 0.0f, 0.0f, 1.0f );
		tri->verts[ 0 ].st[ 0 ] = 0.0f;
		tri->verts[ 0 ].st[ 1 ] = 0.0f;

		tri->verts[ 1 ].Clear();
		tri->verts[ 1 ].normal.Set( 1.0f, 0.0f, 0.0f );
		tri->verts[ 1 ].tangents[0].Set( 0.0f, 1.0f, 0.0f );
		tri->verts[ 1 ].tangents[1].Set( 0.0f, 0.0f, 1.0f );
		tri->verts[ 1 ].st[ 0 ] = 1.0f;
		tri->verts[ 1 ].st[ 1 ] = 0.0f;

		tri->verts[ 2 ].Clear();
		tri->verts[ 2 ].normal.Set( 1.0f, 0.0f, 0.0f );
		tri->verts[ 2 ].tangents[0].Set( 0.0f, 1.0f, 0.0f );
		tri->verts[ 2 ].tangents[1].Set( 0.0f, 0.0f, 1.0f );
		tri->verts[ 2 ].st[ 0 ] = 1.0f;
		tri->verts[ 2 ].st[ 1 ] = 1.0f;

		tri->verts[ 3 ].Clear();
		tri->verts[ 3 ].normal.Set( 1.0f, 0.0f, 0.0f );
		tri->verts[ 3 ].tangents[0].Set( 0.0f, 1.0f, 0.0f );
		tri->verts[ 3 ].tangents[1].Set( 0.0f, 0.0f, 1.0f );
		tri->verts[ 3 ].st[ 0 ] = 0.0f;
		tri->verts[ 3 ].st[ 1 ] = 1.0f;

		tri->indexes[ 0 ] = 0;
		tri->indexes[ 1 ] = 1;
		tri->indexes[ 2 ] = 3;
		tri->indexes[ 3 ] = 1;
		tri->indexes[ 4 ] = 2;
		tri->indexes[ 5 ] = 3;

		tri->numVerts = 4;
		tri->numIndexes = 6;

		surf.geometry = tri;
		surf.id = 0;
		surf.shader = tr.defaultMaterial;
		staticModel->AddSurface( surf );
	}

	int	red			= idMath::FtoiFast( renderEntity->shaderParms[ SHADERPARM_RED ] * 255.0f );
	int green		= idMath::FtoiFast( renderEntity->shaderParms[ SHADERPARM_GREEN ] * 255.0f );
	int	blue		= idMath::FtoiFast( renderEntity->shaderParms[ SHADERPARM_BLUE ] * 255.0f );
	int	alpha		= idMath::FtoiFast( renderEntity->shaderParms[ SHADERPARM_ALPHA ] * 255.0f );

	idVec3 right	= idVec3( 0.0f, renderEntity->shaderParms[ SHADERPARM_SPRITE_WIDTH ] * 0.5f, 0.0f );
	idVec3 up		= idVec3( 0.0f, 0.0f, renderEntity->shaderParms[ SHADERPARM_SPRITE_HEIGHT ] * 0.5f );

	tri->verts[ 0 ].xyz = up + right;
	tri->verts[ 0 ].color[ 0 ] = red;
	tri->verts[ 0 ].color[ 1 ] = green;
	tri->verts[ 0 ].color[ 2 ] = blue;
	tri->verts[ 0 ].color[ 3 ] = alpha;

	tri->verts[ 1 ].xyz = up - right;
	tri->verts[ 1 ].color[ 0 ] = red;
	tri->verts[ 1 ].color[ 1 ] = green;
	tri->verts[ 1 ].color[ 2 ] = blue;
	tri->verts[ 1 ].color[ 3 ] = alpha;

	tri->verts[ 2 ].xyz = - right - up;
	tri->verts[ 2 ].color[ 0 ] = red;
	tri->verts[ 2 ].color[ 1 ] = green;
	tri->verts[ 2 ].color[ 2 ] = blue;
	tri->verts[ 2 ].color[ 3 ] = alpha;

	tri->verts[ 3 ].xyz = right - up;
	tri->verts[ 3 ].color[ 0 ] = red;
	tri->verts[ 3 ].color[ 1 ] = green;
	tri->verts[ 3 ].color[ 2 ] = blue;
	tri->verts[ 3 ].color[ 3 ] = alpha;

	R_BoundTriSurf( tri );

	staticModel->bounds = tri->bounds;

	return staticModel;
}
/*
================
idRenderWorldLocal::ParseModel
================
*/
idRenderModel *idRenderWorldLocal::ParseModel( idLexer *src ) {
	idRenderModel	*model;
	idToken			token;
	int				i, j;
	srfTriangles_t	*tri;
	modelSurface_t	surf;

	src->ExpectTokenString( "{" );

	// parse the name
	src->ExpectAnyToken( &token );

	model = renderModelManager->AllocModel();
	model->InitEmpty( token );

	int numSurfaces = src->ParseInt();
	if ( numSurfaces < 0 ) {
		src->Error( "R_ParseModel: bad numSurfaces" );
	}

	for ( i = 0 ; i < numSurfaces ; i++ ) {
		src->ExpectTokenString( "{" );

		src->ExpectAnyToken( &token );

		surf.shader = declManager->FindMaterial( token );

		((idMaterial*)surf.shader)->AddReference();

		tri = R_AllocStaticTriSurf();
		surf.geometry = tri;

		tri->numVerts = src->ParseInt();
		tri->numIndexes = src->ParseInt();

		R_AllocStaticTriSurfVerts( tri, tri->numVerts );
		for ( j = 0 ; j < tri->numVerts ; j++ ) {
			float	vec[8];

			src->Parse1DMatrix( 8, vec );

			tri->verts[j].xyz[0] = vec[0];
			tri->verts[j].xyz[1] = vec[1];
			tri->verts[j].xyz[2] = vec[2];
			tri->verts[j].st[0] = vec[3];
			tri->verts[j].st[1] = vec[4];
			tri->verts[j].normal[0] = vec[5];
			tri->verts[j].normal[1] = vec[6];
			tri->verts[j].normal[2] = vec[7];
		}

		R_AllocStaticTriSurfIndexes( tri, tri->numIndexes );
		for ( j = 0 ; j < tri->numIndexes ; j++ ) {
			tri->indexes[j] = src->ParseInt();
		}
		src->ExpectTokenString( "}" );

		// add the completed surface to the model
		model->AddSurface( surf );
	}

	src->ExpectTokenString( "}" );

	model->FinishSurfaces();

	return model;
}
/*
====================
idRenderModelPrt::InstantiateDynamicModel
====================
*/
idRenderModel* idRenderModelPrt::InstantiateDynamicModel( const struct renderEntity_s* renderEntity, const viewDef_t* viewDef, idRenderModel* cachedModel )
{
	idRenderModelStatic*	staticModel;
	
	if( cachedModel && !r_useCachedDynamicModels.GetBool() )
	{
		delete cachedModel;
		cachedModel = NULL;
	}
	
	// this may be triggered by a model trace or other non-view related source, to which we should look like an empty model
	if( renderEntity == NULL || viewDef == NULL )
	{
		delete cachedModel;
		return NULL;
	}
	
	if( r_skipParticles.GetBool() )
	{
		delete cachedModel;
		return NULL;
	}
	
	/*
	// if the entire system has faded out
	if ( renderEntity->shaderParms[SHADERPARM_PARTICLE_STOPTIME] && viewDef->renderView.time * 0.001f >= renderEntity->shaderParms[SHADERPARM_PARTICLE_STOPTIME] ) {
		delete cachedModel;
		return NULL;
	}
	*/
	
	if( cachedModel != NULL )
	{
	
		assert( dynamic_cast<idRenderModelStatic*>( cachedModel ) != NULL );
		assert( idStr::Icmp( cachedModel->Name(), parametricParticle_SnapshotName ) == 0 );
		
		staticModel = static_cast<idRenderModelStatic*>( cachedModel );
		
	}
	else
	{
	
		staticModel = new( TAG_MODEL ) idRenderModelStatic;
		staticModel->InitEmpty( parametricParticle_SnapshotName );
	}
	
	particleGen_t g;
	
	g.renderEnt = renderEntity;
	g.renderView = &viewDef->renderView;
	g.origin.Zero();
	g.axis.Identity();
	
	for( int stageNum = 0; stageNum < particleSystem->stages.Num(); stageNum++ )
	{
		idParticleStage* stage = particleSystem->stages[stageNum];
		
		if( !stage->material )
		{
			continue;
		}
		if( !stage->cycleMsec )
		{
			continue;
		}
		if( stage->hidden )  		// just for gui particle editor use
		{
			staticModel->DeleteSurfaceWithId( stageNum );
			continue;
		}
		
		idRandom steppingRandom, steppingRandom2;
		
		int stageAge = g.renderView->time[renderEntity->timeGroup] + renderEntity->shaderParms[SHADERPARM_TIMEOFFSET] * 1000 - stage->timeOffset * 1000;
		int	stageCycle = stageAge / stage->cycleMsec;
		
		// some particles will be in this cycle, some will be in the previous cycle
		steppingRandom.SetSeed( ( ( stageCycle << 10 ) & idRandom::MAX_RAND ) ^ ( int )( renderEntity->shaderParms[SHADERPARM_DIVERSITY] * idRandom::MAX_RAND ) );
		steppingRandom2.SetSeed( ( ( ( stageCycle - 1 ) << 10 ) & idRandom::MAX_RAND ) ^ ( int )( renderEntity->shaderParms[SHADERPARM_DIVERSITY] * idRandom::MAX_RAND ) );
		
		int	count = stage->totalParticles * stage->NumQuadsPerParticle();
		
		int surfaceNum;
		modelSurface_t* surf;
		
		if( staticModel->FindSurfaceWithId( stageNum, surfaceNum ) )
		{
			surf = &staticModel->surfaces[surfaceNum];
			R_FreeStaticTriSurfVertexCaches( surf->geometry );
		}
		else
		{
			surf = &staticModel->surfaces.Alloc();
			surf->id = stageNum;
			surf->shader = stage->material;
			surf->geometry = R_AllocStaticTriSurf();
			R_AllocStaticTriSurfVerts( surf->geometry, 4 * count );
			R_AllocStaticTriSurfIndexes( surf->geometry, 6 * count );
		}
		
		int numVerts = 0;
		idDrawVert* verts = surf->geometry->verts;
		
		for( int index = 0; index < stage->totalParticles; index++ )
		{
			g.index = index;
			
			// bump the random
			steppingRandom.RandomInt();
			steppingRandom2.RandomInt();
			
			// calculate local age for this index
			int	bunchOffset = stage->particleLife * 1000 * stage->spawnBunching * index / stage->totalParticles;
			
			int particleAge = stageAge - bunchOffset;
			int	particleCycle = particleAge / stage->cycleMsec;
			if( particleCycle < 0 )
			{
				// before the particleSystem spawned
				continue;
			}
			if( stage->cycles && particleCycle >= stage->cycles )
			{
				// cycled systems will only run cycle times
				continue;
			}
			
			if( particleCycle == stageCycle )
			{
				g.random = steppingRandom;
			}
			else
			{
				g.random = steppingRandom2;
			}
			
			int	inCycleTime = particleAge - particleCycle * stage->cycleMsec;
			
			if( renderEntity->shaderParms[SHADERPARM_PARTICLE_STOPTIME] &&
					g.renderView->time[renderEntity->timeGroup] - inCycleTime >= renderEntity->shaderParms[SHADERPARM_PARTICLE_STOPTIME] * 1000 )
			{
				// don't fire any more particles
				continue;
			}
			
			// supress particles before or after the age clamp
			g.frac = ( float )inCycleTime / ( stage->particleLife * 1000 );
			if( g.frac < 0.0f )
			{
				// yet to be spawned
				continue;
			}
			if( g.frac > 1.0f )
			{
				// this particle is in the deadTime band
				continue;
			}
			
			// this is needed so aimed particles can calculate origins at different times
			g.originalRandom = g.random;
			
			g.age = g.frac * stage->particleLife;
			
			// if the particle doesn't get drawn because it is faded out or beyond a kill region, don't increment the verts
			numVerts += stage->CreateParticle( &g, verts + numVerts );
		}
		
		// numVerts must be a multiple of 4
		assert( ( numVerts & 3 ) == 0 && numVerts <= 4 * count );
		
		// build the indexes
		int	numIndexes = 0;
		triIndex_t* indexes = surf->geometry->indexes;
		for( int i = 0; i < numVerts; i += 4 )
		{
			indexes[numIndexes + 0] = i + 0;
			indexes[numIndexes + 1] = i + 2;
			indexes[numIndexes + 2] = i + 3;
			indexes[numIndexes + 3] = i + 0;
			indexes[numIndexes + 4] = i + 3;
			indexes[numIndexes + 5] = i + 1;
			numIndexes += 6;
		}
		
		surf->geometry->tangentsCalculated = false;
		surf->geometry->numVerts = numVerts;
		surf->geometry->numIndexes = numIndexes;
		surf->geometry->bounds = stage->bounds;		// just always draw the particles
	}
	
	return staticModel;
}
/*
===============
idRenderModelBeam::InstantiateDynamicModel
===============
*/
idRenderModel *idRenderModelBeam::InstantiateDynamicModel(const struct renderEntity_s *renderEntity, const struct viewDef_s *viewDef, idRenderModel *cachedModel)
{
	idRenderModelStatic *staticModel;
	srfTriangles_t *tri;
	modelSurface_t surf;

	if (cachedModel) {
		delete cachedModel;
		cachedModel = NULL;
	}

	if (renderEntity == NULL || viewDef == NULL) {
		delete cachedModel;
		return NULL;
	}

	if (cachedModel != NULL) {

		assert(dynamic_cast<idRenderModelStatic *>(cachedModel) != NULL);
		assert(idStr::Icmp(cachedModel->Name(), beam_SnapshotName) == 0);

		staticModel = static_cast<idRenderModelStatic *>(cachedModel);
		surf = *staticModel->Surface(0);
		tri = surf.geometry;

	} else {

		staticModel = new idRenderModelStatic;
		staticModel->InitEmpty(beam_SnapshotName);

		tri = R_AllocStaticTriSurf();
		R_AllocStaticTriSurfVerts(tri, 4);
		R_AllocStaticTriSurfIndexes(tri, 6);

		tri->verts[0].Clear();
		tri->verts[0].st[0] = 0;
		tri->verts[0].st[1] = 0;

		tri->verts[1].Clear();
		tri->verts[1].st[0] = 0;
		tri->verts[1].st[1] = 1;

		tri->verts[2].Clear();
		tri->verts[2].st[0] = 1;
		tri->verts[2].st[1] = 0;

		tri->verts[3].Clear();
		tri->verts[3].st[0] = 1;
		tri->verts[3].st[1] = 1;

		tri->indexes[0] = 0;
		tri->indexes[1] = 2;
		tri->indexes[2] = 1;
		tri->indexes[3] = 2;
		tri->indexes[4] = 3;
		tri->indexes[5] = 1;

		tri->numVerts = 4;
		tri->numIndexes = 6;

		surf.geometry = tri;
		surf.id = 0;
		surf.shader = tr.defaultMaterial;
		staticModel->AddSurface(surf);
	}

	idVec3	target = *reinterpret_cast<const idVec3 *>(&renderEntity->shaderParms[SHADERPARM_BEAM_END_X]);

	// we need the view direction to project the minor axis of the tube
	// as the view changes
	idVec3	localView, localTarget;
	float	modelMatrix[16];
	R_AxisToModelMatrix(renderEntity->axis, renderEntity->origin, modelMatrix);
	R_GlobalPointToLocal(modelMatrix, viewDef->renderView.vieworg, localView);
	R_GlobalPointToLocal(modelMatrix, target, localTarget);

	idVec3	major = localTarget;
	idVec3	minor;

	idVec3	mid = 0.5f * localTarget;
	idVec3	dir = mid - localView;
	minor.Cross(major, dir);
	minor.Normalize();

	if (renderEntity->shaderParms[SHADERPARM_BEAM_WIDTH] != 0.0f) {
		minor *= renderEntity->shaderParms[SHADERPARM_BEAM_WIDTH] * 0.5f;
	}

	int red		= idMath::FtoiFast(renderEntity->shaderParms[SHADERPARM_RED] * 255.0f);
	int green	= idMath::FtoiFast(renderEntity->shaderParms[SHADERPARM_GREEN] * 255.0f);
	int blue	= idMath::FtoiFast(renderEntity->shaderParms[SHADERPARM_BLUE] * 255.0f);
	int alpha	= idMath::FtoiFast(renderEntity->shaderParms[SHADERPARM_ALPHA] * 255.0f);

	tri->verts[0].xyz = minor;
	tri->verts[0].color[0] = red;
	tri->verts[0].color[1] = green;
	tri->verts[0].color[2] = blue;
	tri->verts[0].color[3] = alpha;

	tri->verts[1].xyz = -minor;
	tri->verts[1].color[0] = red;
	tri->verts[1].color[1] = green;
	tri->verts[1].color[2] = blue;
	tri->verts[1].color[3] = alpha;

	tri->verts[2].xyz = localTarget + minor;
	tri->verts[2].color[0] = red;
	tri->verts[2].color[1] = green;
	tri->verts[2].color[2] = blue;
	tri->verts[2].color[3] = alpha;

	tri->verts[3].xyz = localTarget - minor;
	tri->verts[3].color[0] = red;
	tri->verts[3].color[1] = green;
	tri->verts[3].color[2] = blue;
	tri->verts[3].color[3] = alpha;

	R_BoundTriSurf(tri);

	staticModel->bounds = tri->bounds;

	return staticModel;
}
Exemple #16
0
/*
=============
idRenderModelMD3::InstantiateDynamicModel
=============
*/
idRenderModel *idRenderModelMD3::InstantiateDynamicModel( const struct renderEntity_s *ent, const struct viewDef_s *view, idRenderModel *cachedModel ) {
    int				i, j;
    float			backlerp;
    int *			triangles;
    float *			texCoords;
    int				indexes;
    int				numVerts;
    md3Surface_t *	surface;
    int				frame, oldframe;
    idRenderModelStatic	*staticModel;

    if ( cachedModel ) {
        delete cachedModel;
        cachedModel = NULL;
    }

    staticModel = new idRenderModelStatic;
    staticModel->bounds.Clear();

    surface = (md3Surface_t *) ((byte *)md3 + md3->ofsSurfaces);

    // TODO: these need set by an entity
    frame = ent->shaderParms[SHADERPARM_MD3_FRAME];			// probably want to keep frames < 1000 or so
    oldframe = ent->shaderParms[SHADERPARM_MD3_LASTFRAME];
    backlerp = ent->shaderParms[SHADERPARM_MD3_BACKLERP];

    for( i = 0; i < md3->numSurfaces; i++ ) {

        srfTriangles_t *tri = R_AllocStaticTriSurf();
        R_AllocStaticTriSurfVerts( tri, surface->numVerts );
        R_AllocStaticTriSurfIndexes( tri, surface->numTriangles * 3 );
        tri->bounds.Clear();

        modelSurface_t	surf;

        surf.geometry = tri;

        md3Shader_t* shaders = (md3Shader_t *) ((byte *)surface + surface->ofsShaders);
        surf.shader = shaders->shader;

        LerpMeshVertexes( tri, surface, backlerp, frame, oldframe );

        triangles = (int *) ((byte *)surface + surface->ofsTriangles);
        indexes = surface->numTriangles * 3;
        for (j = 0 ; j < indexes ; j++) {
            tri->indexes[j] = triangles[j];
        }
        tri->numIndexes += indexes;

        texCoords = (float *) ((byte *)surface + surface->ofsSt);

        numVerts = surface->numVerts;
        for ( j = 0; j < numVerts; j++ ) {
            idDrawVert *stri = &tri->verts[j];
            stri->st[0] = texCoords[j*2+0];
            stri->st[1] = texCoords[j*2+1];
        }

        R_BoundTriSurf( tri );

        staticModel->AddSurface( surf );
        staticModel->bounds.AddPoint( surf.geometry->bounds[0] );
        staticModel->bounds.AddPoint( surf.geometry->bounds[1] );

        // find the next surface
        surface = (md3Surface_t *)( (byte *)surface + surface->ofsEnd );
    }

    return staticModel;
}
Exemple #17
0
/*
=====================
R_CreateInteractionShadowVolume

Note that dangling edges outside the light frustum don't make silhouette planes because
a triangle outside the light frustum is considered facing and the "fake triangle" on
the outside of the dangling edge is also set to facing: cullInfo.facing[numFaces] = 1;
=====================
*/
static srfTriangles_t *R_CreateInteractionShadowVolume( const idRenderEntityLocal * ent, 
														const srfTriangles_t * tri, const idRenderLightLocal * light ) {
	SCOPED_PROFILE_EVENT( "R_CreateInteractionShadowVolume" );

	srfCullInfo_t cullInfo = {};

	R_CalcInteractionFacing( ent, tri, light, cullInfo );
	R_CalcInteractionCullBits( ent, tri, light, cullInfo );

	int numFaces = tri->numIndexes / 3;
	int	numShadowingFaces = 0;
	const byte * facing = cullInfo.facing;

	// if all the triangles are inside the light frustum
	if ( cullInfo.cullBits == LIGHT_CULL_ALL_FRONT ) {

		// count the number of shadowing faces
		for ( int i = 0; i < numFaces; i++ ) {
			numShadowingFaces += facing[i];
		}
		numShadowingFaces = numFaces - numShadowingFaces;

	} else {

		// make all triangles that are outside the light frustum "facing", so they won't cast shadows
		const triIndex_t * indexes = tri->indexes;
		byte *modifyFacing = cullInfo.facing;
		const byte *cullBits = cullInfo.cullBits;
		for ( int i = 0, j = 0; i < tri->numIndexes; i += 3, j++ ) {
			if ( !modifyFacing[j] ) {
				int	i1 = indexes[i+0];
				int	i2 = indexes[i+1];
				int	i3 = indexes[i+2];
				if ( cullBits[i1] & cullBits[i2] & cullBits[i3] ) {
					modifyFacing[j] = 1;
				} else {
					numShadowingFaces++;
				}
			}
		}
	}

	if ( !numShadowingFaces ) {
		// no faces are inside the light frustum and still facing the right way
		R_FreeInteractionCullInfo( cullInfo );
		return NULL;
	}

	// shadowVerts will be NULL on these surfaces, so the shadowVerts will be taken from the ambient surface
	srfTriangles_t * newTri = R_AllocStaticTriSurf();

	newTri->numVerts = tri->numVerts * 2;

	// alloc the max possible size
	R_AllocStaticTriSurfIndexes( newTri, ( numShadowingFaces + tri->numSilEdges ) * 6 );
	triIndex_t * tempIndexes = newTri->indexes;
	triIndex_t * shadowIndexes = newTri->indexes;

	// create new triangles along sil planes
	const silEdge_t * sil = tri->silEdges;
	for ( int i = tri->numSilEdges; i > 0; i--, sil++ ) {

		int f1 = facing[sil->p1];
		int f2 = facing[sil->p2];

		if ( !( f1 ^ f2 ) ) {
			continue;
		}

		int v1 = sil->v1 << 1;
		int v2 = sil->v2 << 1;

		// set the two triangle winding orders based on facing
		// without using a poorly-predictable branch

		shadowIndexes[0] = v1;
		shadowIndexes[1] = v2 ^ f1;
		shadowIndexes[2] = v2 ^ f2;
		shadowIndexes[3] = v1 ^ f2;
		shadowIndexes[4] = v1 ^ f1;
		shadowIndexes[5] = v2 ^ 1;

		shadowIndexes += 6;
	}

	int	numShadowIndexes = shadowIndexes - tempIndexes;

	// we aren't bothering to separate front and back caps on these
	newTri->numIndexes = newTri->numShadowIndexesNoFrontCaps = numShadowIndexes + numShadowingFaces * 6;
	newTri->numShadowIndexesNoCaps = numShadowIndexes;
	newTri->shadowCapPlaneBits = SHADOW_CAP_INFINITE;

	// decrease the size of the memory block to only store the used indexes
	// R_ResizeStaticTriSurfIndexes( newTri, newTri->numIndexes );

	// these have no effect, because they extend to infinity
	newTri->bounds.Clear();

	// put some faces on the model and some on the distant projection
	const triIndex_t * indexes = tri->indexes;
	shadowIndexes = newTri->indexes + numShadowIndexes;
	for ( int i = 0, j = 0; i < tri->numIndexes; i += 3, j++ ) {
		if ( facing[j] ) {
			continue;
		}

		int i0 = indexes[i+0] << 1;
		int i1 = indexes[i+1] << 1;
		int i2 = indexes[i+2] << 1;

		shadowIndexes[0] = i2;
		shadowIndexes[1] = i1;
		shadowIndexes[2] = i0;
		shadowIndexes[3] = i0 ^ 1;
		shadowIndexes[4] = i1 ^ 1;
		shadowIndexes[5] = i2 ^ 1;

		shadowIndexes += 6;
	}

	R_FreeInteractionCullInfo( cullInfo );

	return newTri;
}