//-----------------------------------------------------------------------------
// Computes a convex hull from a studio mesh
//-----------------------------------------------------------------------------
static void AddMeshToPolysoup( CPhysPolysoup* pSoup, mstudiomesh_t* pMesh, OptimizedModel::MeshHeader_t* pVtxMesh )
{
	Vector v[3];

	for (int i = 0; i < pVtxMesh->numStripGroups; ++i )
	{
		OptimizedModel::StripGroupHeader_t* pStripGroup = pVtxMesh->pStripGroup(i);

		if (pStripGroup->flags & OptimizedModel::STRIP_IS_TRILIST)
		{
			for (int j = 0; j < pStripGroup->numStrips; ++j )
			{
				OptimizedModel::StripHeader_t* pStrip = pStripGroup->pStrip(i);

				int numTri = pStrip->numIndices / 3;
				unsigned short* pIdx = pStripGroup->pIndex(pStrip->indexOffset);
				for (int k = 0; k < numTri; ++k)
				{
					v[0] = *PositionFromIndex( pMesh, pStripGroup, pIdx[3*k] );
					v[1] = *PositionFromIndex( pMesh, pStripGroup, pIdx[3*k+1] );
					v[2] = *PositionFromIndex( pMesh, pStripGroup, pIdx[3*k+2] );
					s_pPhysCollision->PolysoupAddTriangle( pSoup, v[0], v[1], v[2], 0 );
				}
			}
		}
		else
		{
			for (int j = 0; j < pStripGroup->numStrips; ++j )
			{
				OptimizedModel::StripHeader_t* pStrip = pStripGroup->pStrip(i);

				int numTri = pStrip->numIndices - 2;
				unsigned short* pIdx = pStripGroup->pIndex(pStrip->indexOffset);
				for (int k = 0; k < numTri; ++k)
				{
					v[0] = *PositionFromIndex( pMesh, pStripGroup, pIdx[k] );
					bool winding = ( (k & 0x1) == 0 );
					v[2 - winding] = *PositionFromIndex( pMesh, pStripGroup, pIdx[k+1] );
					v[1 + winding] = *PositionFromIndex( pMesh, pStripGroup, pIdx[k+2] );
					s_pPhysCollision->PolysoupAddTriangle( pSoup, v[0], v[1], v[2], 0 );
				}
			}
		}
	}
}
Exemple #2
0
//-----------------------------------------------------------------------------
// Trace rays from each unique vertex, accumulating direct and indirect
// sources at each ray termination. Use the winding data to distribute the unique vertexes
// into the rendering layout.
//-----------------------------------------------------------------------------
void CVradStaticPropMgr::ComputeLighting( CStaticProp &prop, int iThread, int prop_index )
{
	Vector						samplePosition;
	Vector						sampleNormal;
	CUtlVector<colorVertex_t>	colorVerts; 
	CUtlVector<badVertex_t>		badVerts;

	StaticPropDict_t &dict = m_StaticPropDict[prop.m_ModelIdx];
	studiohdr_t	*pStudioHdr = dict.m_pStudioHdr;
	OptimizedModel::FileHeader_t *pVtxHdr = (OptimizedModel::FileHeader_t *)dict.m_VtxBuf.Base();
	if ( !pStudioHdr || !pVtxHdr )
	{
		// must have model and its verts for lighting computation
		// game will fallback to fullbright
		return;
	}

	// for access to this model's vertexes
	SetCurrentModel( pStudioHdr );

	for ( int bodyID = 0; bodyID < pStudioHdr->numbodyparts; ++bodyID )
	{
		OptimizedModel::BodyPartHeader_t* pVtxBodyPart = pVtxHdr->pBodyPart( bodyID );
		mstudiobodyparts_t *pBodyPart = pStudioHdr->pBodypart( bodyID );

		for ( int modelID = 0; modelID < pBodyPart->nummodels; ++modelID )
		{
			OptimizedModel::ModelHeader_t* pVtxModel = pVtxBodyPart->pModel( modelID );
			mstudiomodel_t *pStudioModel = pBodyPart->pModel( modelID );

			// light all unique vertexes
			colorVerts.EnsureCount( pStudioModel->numvertices );
			memset( colorVerts.Base(), 0, colorVerts.Count() * sizeof(colorVertex_t) );

			int numVertexes = 0;
			for ( int meshID = 0; meshID < pStudioModel->nummeshes; ++meshID )
			{
				mstudiomesh_t *pStudioMesh = pStudioModel->pMesh( meshID );
				const mstudio_meshvertexdata_t *vertData = pStudioMesh->GetVertexData();
				for ( int vertexID = 0; vertexID < pStudioMesh->numvertices; ++vertexID )
				{
					// transform position and normal into world coordinate system
					matrix3x4_t	matrix;
					AngleMatrix( prop.m_Angles, prop.m_Origin, matrix );
					VectorTransform( *vertData->Position( vertexID ), matrix, samplePosition );
					AngleMatrix( prop.m_Angles, matrix );
					VectorTransform( *vertData->Normal( vertexID ), matrix, sampleNormal );

					if ( (! (prop.m_Flags & STATIC_PROP_NO_PER_VERTEX_LIGHTING ) ) &&
						 PositionInSolid( samplePosition ) )
					{
						// vertex is in solid, add to the bad list, and recover later
						badVertex_t badVertex;
						badVertex.m_ColorVertex = numVertexes;
						badVertex.m_Position = samplePosition;
						badVertex.m_Normal = sampleNormal;
						badVerts.AddToTail( badVertex );			
					}
					else
					{
						Vector direct_pos=samplePosition;
						int skip_prop=-1;

						Vector directColor(0,0,0);
						if (prop.m_Flags & STATIC_PROP_NO_PER_VERTEX_LIGHTING )
						{
							if (prop.m_bLightingOriginValid)
								VectorCopy( prop.m_LightingOrigin, direct_pos );
							else
								VectorCopy( prop.m_Origin, direct_pos );
							skip_prop = prop_index;
						}
						if ( prop.m_Flags & STATIC_PROP_NO_SELF_SHADOWING )
							skip_prop = prop_index;

						
						ComputeDirectLightingAtPoint( direct_pos,
													  sampleNormal, directColor, iThread,
													  skip_prop );
						Vector indirectColor(0,0,0);

						if (g_bShowStaticPropNormals)
						{
							directColor= sampleNormal;
							directColor += Vector(1.0,1.0,1.0);
							directColor *= 50.0;
						}
						else
							if (numbounce >= 1)
								ComputeIndirectLightingAtPoint( samplePosition, sampleNormal, 
																indirectColor, iThread, true );

						colorVerts[numVertexes].m_bValid = true;
						colorVerts[numVertexes].m_Position = samplePosition;
						VectorAdd( directColor, indirectColor, colorVerts[numVertexes].m_Color );
					}

					numVertexes++;
				}
			}

			// color in the bad vertexes
			// when entire model has no lighting origin and no valid neighbors
			// must punt, leave black coloring
			if ( badVerts.Count() && ( prop.m_bLightingOriginValid || badVerts.Count() != numVertexes ) )
			{
				for ( int nBadVertex = 0; nBadVertex < badVerts.Count(); nBadVertex++ )
				{		
					Vector bestPosition;
					if ( prop.m_bLightingOriginValid )
					{
						// use the specified lighting origin
						VectorCopy( prop.m_LightingOrigin, bestPosition );
					}
					else
					{
						// find the closest valid neighbor
						int best = 0;
						float closest = FLT_MAX;
						for ( int nColorVertex = 0; nColorVertex < numVertexes; nColorVertex++ )
						{
							if ( !colorVerts[nColorVertex].m_bValid )
							{
								// skip invalid neighbors
								continue;
							}
							Vector delta;
							VectorSubtract( colorVerts[nColorVertex].m_Position, badVerts[nBadVertex].m_Position, delta );
							float distance = VectorLength( delta );
							if ( distance < closest )
							{
								closest = distance;
								best    = nColorVertex;
							}
						}

						// use the best neighbor as the direction to crawl
						VectorCopy( colorVerts[best].m_Position, bestPosition );
					}

					// crawl toward best position
					// sudivide to determine a closer valid point to the bad vertex, and re-light
					Vector midPosition;
					int numIterations = 20;
					while ( --numIterations > 0 )
					{
						VectorAdd( bestPosition, badVerts[nBadVertex].m_Position, midPosition );
						VectorScale( midPosition, 0.5f, midPosition );
						if ( PositionInSolid( midPosition ) )
							break;
						bestPosition = midPosition;
					}

					// re-light from better position
					Vector directColor;
					ComputeDirectLightingAtPoint( bestPosition, badVerts[nBadVertex].m_Normal, directColor, iThread );

					Vector indirectColor;
					ComputeIndirectLightingAtPoint( bestPosition, badVerts[nBadVertex].m_Normal,
													indirectColor, iThread, true );

					// save results, not changing valid status
					// to ensure this offset position is not considered as a viable candidate
					colorVerts[badVerts[nBadVertex].m_ColorVertex].m_Position = bestPosition;
					VectorAdd( directColor, indirectColor, colorVerts[badVerts[nBadVertex].m_ColorVertex].m_Color );
				}
			}
			
			// discard bad verts
			badVerts.Purge();

			// distribute the lighting results
			for ( int nLod = 0; nLod < pVtxHdr->numLODs; nLod++ )
			{
				OptimizedModel::ModelLODHeader_t *pVtxLOD = pVtxModel->pLOD( nLod );

				for ( int nMesh = 0; nMesh < pStudioModel->nummeshes; ++nMesh )
				{
					mstudiomesh_t* pMesh = pStudioModel->pMesh( nMesh );
					OptimizedModel::MeshHeader_t* pVtxMesh = pVtxLOD->pMesh( nMesh );

					for ( int nGroup = 0; nGroup < pVtxMesh->numStripGroups; ++nGroup )
					{
						OptimizedModel::StripGroupHeader_t* pStripGroup = pVtxMesh->pStripGroup( nGroup );
						int nMeshIdx = prop.m_MeshData.AddToTail();
						prop.m_MeshData[nMeshIdx].m_Verts.AddMultipleToTail( pStripGroup->numVerts );
						prop.m_MeshData[nMeshIdx].m_nLod = nLod;

						for ( int nVertex = 0; nVertex < pStripGroup->numVerts; ++nVertex )
						{
							int nIndex = pMesh->vertexoffset + pStripGroup->pVertex( nVertex )->origMeshVertID;

							Assert( nIndex < pStudioModel->numvertices );
							prop.m_MeshData[nMeshIdx].m_Verts[nVertex] = colorVerts[nIndex].m_Color;
						}
					}
				}
			}
		}
	}
}
Exemple #3
0
//-----------------------------------------------------------------------------
// Adds all static prop polys to the ray trace store.
//-----------------------------------------------------------------------------
void CVradStaticPropMgr::AddPolysForRayTrace( void )
{
	int count = m_StaticProps.Count();
	if ( !count )
	{
		// nothing to do
		return;
	}

	for ( int nProp = 0; nProp < count; ++nProp )
	{
		CStaticProp &prop = m_StaticProps[nProp];
		if ( prop.m_Flags & STATIC_PROP_NO_SHADOW )
			continue;

		StaticPropDict_t &dict = m_StaticPropDict[prop.m_ModelIdx];
		studiohdr_t	*pStudioHdr = dict.m_pStudioHdr;
		OptimizedModel::FileHeader_t *pVtxHdr = (OptimizedModel::FileHeader_t *)dict.m_VtxBuf.Base();
		if ( !pStudioHdr || !pVtxHdr )
		{
			// must have model and its verts for decoding triangles
			return;
		}

		// for access to this model's vertexes
		SetCurrentModel( pStudioHdr );
	
		// meshes are deeply hierarchial, divided between three stores, follow the white rabbit
		// body parts -> models -> lod meshes -> strip groups -> strips
		// the vertices and indices are pooled, the trick is knowing the offset to determine your indexed base 
		for ( int bodyID = 0; bodyID < pStudioHdr->numbodyparts; ++bodyID )
		{
			OptimizedModel::BodyPartHeader_t* pVtxBodyPart = pVtxHdr->pBodyPart( bodyID );
			mstudiobodyparts_t *pBodyPart = pStudioHdr->pBodypart( bodyID );

			for ( int modelID = 0; modelID < pBodyPart->nummodels; ++modelID )
			{
				OptimizedModel::ModelHeader_t* pVtxModel = pVtxBodyPart->pModel( modelID );
				mstudiomodel_t *pStudioModel = pBodyPart->pModel( modelID );

				// assuming lod 0, could iterate if required
				int nLod = 0;
				OptimizedModel::ModelLODHeader_t *pVtxLOD = pVtxModel->pLOD( nLod );

				for ( int nMesh = 0; nMesh < pStudioModel->nummeshes; ++nMesh )
				{
					mstudiomesh_t* pMesh = pStudioModel->pMesh( nMesh );
					OptimizedModel::MeshHeader_t* pVtxMesh = pVtxLOD->pMesh( nMesh );
					const mstudio_meshvertexdata_t *vertData = pMesh->GetVertexData();

					for ( int nGroup = 0; nGroup < pVtxMesh->numStripGroups; ++nGroup )
					{
						OptimizedModel::StripGroupHeader_t* pStripGroup = pVtxMesh->pStripGroup( nGroup );

						int nStrip;
						for ( nStrip = 0; nStrip < pStripGroup->numStrips; nStrip++ )
						{
							OptimizedModel::StripHeader_t *pStrip = pStripGroup->pStrip( nStrip );

							if ( pStrip->flags & OptimizedModel::STRIP_IS_TRILIST )
							{
								for ( int i = 0; i < pStrip->numIndices; i += 3 )
								{
									int idx = pStrip->indexOffset + i;

									unsigned short i1 = *pStripGroup->pIndex( idx );
									unsigned short i2 = *pStripGroup->pIndex( idx + 1 );
									unsigned short i3 = *pStripGroup->pIndex( idx + 2 );

									int vertex1 = pStripGroup->pVertex( i1 )->origMeshVertID;
									int vertex2 = pStripGroup->pVertex( i2 )->origMeshVertID;
									int vertex3 = pStripGroup->pVertex( i3 )->origMeshVertID;

									// transform position into world coordinate system
									matrix3x4_t	matrix;
									AngleMatrix( prop.m_Angles, prop.m_Origin, matrix );

									Vector position1;
									Vector position2;
									Vector position3;
									VectorTransform( *vertData->Position( vertex1 ), matrix, position1 );
									VectorTransform( *vertData->Position( vertex2 ), matrix, position2 );
									VectorTransform( *vertData->Position( vertex3 ), matrix, position3 );
// 		printf( "\ngl 3\n" );
// 		printf( "gl %6.3f %6.3f %6.3f 1 0 0\n", XYZ(position1));
// 		printf( "gl %6.3f %6.3f %6.3f 0 1 0\n", XYZ(position2));
// 		printf( "gl %6.3f %6.3f %6.3f 0 0 1\n", XYZ(position3));
									g_RtEnv.AddTriangle( nProp,
														 position1, position2, position3,
														 Vector(0,0,0));
								}
							}
							else
							{
								// all tris expected to be discrete tri lists
								// must fixme if stripping ever occurs
								printf("unexpected strips found\n");
								Assert( 0 );
								return;
							}
						}
					}
				}
			}
		}
	}
}