void VMPI_ReceiveDetailPropWU( int iWorkUnit, MessageBuffer *pBuf, int iWorker ) { CUtlVector<DetailPropLightstylesLump_t> *pDetailPropLump = s_pDetailPropLightStyleLump; DetailObjectLump_t& prop = g_pMPIDetailProps[iWorkUnit]; pBuf->read( &prop.m_Lighting, sizeof( prop.m_Lighting ) ); pBuf->read( &prop.m_LightStyleCount, sizeof( prop.m_LightStyleCount ) ); pBuf->read( &prop.m_LightStyles, sizeof( prop.m_LightStyles ) ); pDetailPropLump->EnsureCount( prop.m_LightStyles + prop.m_LightStyleCount ); for ( int i=0; i < prop.m_LightStyleCount; i++ ) { DetailPropLightstylesLump_t *l = &pDetailPropLump->Element( i + prop.m_LightStyles ); pBuf->read( &l->m_Lighting, sizeof( l->m_Lighting ) ); pBuf->read( &l->m_Style, sizeof( l->m_Style ) ); } }
void Disp_BuildVirtualMesh( int contentsMask ) { CUtlVector<CPhysCollide *> virtualMeshes; virtualMeshes.EnsureCount( g_CoreDispInfos.Count() ); for ( int i = 0; i < g_CoreDispInfos.Count(); i++ ) { CCoreDispInfo *pDispInfo = g_CoreDispInfos[ i ]; mapdispinfo_t *pMapDisp = &mapdispinfo[ i ]; virtualMeshes[i] = NULL; // not solid for this pass if ( !(pMapDisp->contents & contentsMask) ) continue; // Build a triangle list. This shares the tesselation code with the engine. CUtlVector<unsigned short> indices; CVBSPTesselateHelper helper; helper.m_pIndices = &indices; helper.m_pActiveVerts = pDispInfo->GetAllowedVerts().Base(); helper.m_pPowerInfo = pDispInfo->GetPowerInfo(); ::TesselateDisplacement( &helper ); // validate the collision data if ( 1 ) { int triCount = indices.Count() / 3; for ( int j = 0; j < triCount; j++ ) { int index = j * 3; Vector v0 = pDispInfo->GetVert( indices[index+0] ); Vector v1 = pDispInfo->GetVert( indices[index+1] ); Vector v2 = pDispInfo->GetVert( indices[index+2] ); if ( v0 == v1 || v1 == v2 || v2 == v0 ) { Warning( "Displacement %d has bad geometry near %.2f %.2f %.2f\n", i, v0.x, v0.y, v0.z ); texinfo_t *pTexInfo = &texinfo[pMapDisp->face.texinfo]; dtexdata_t *pTexData = GetTexData( pTexInfo->texdata ); const char *pMatName = TexDataStringTable_GetString( pTexData->nameStringTableID ); Error( "Can't compile displacement physics, exiting. Texture is %s\n", pMatName ); } } } CDispMeshEvent meshHandler( indices.Base(), indices.Count(), pDispInfo ); virtualmeshparams_t params; params.buildOuterHull = true; params.pMeshEventHandler = &meshHandler; params.userData = &meshHandler; virtualMeshes[i] = physcollision->CreateVirtualMesh( params ); } unsigned int totalSize = 0; CUtlBuffer buf; dphysdisp_t header; header.numDisplacements = g_CoreDispInfos.Count(); buf.PutObjects( &header ); CUtlVector<char> dispBuf; for ( int i = 0; i < header.numDisplacements; i++ ) { if ( virtualMeshes[i] ) { unsigned int testSize = physcollision->CollideSize( virtualMeshes[i] ); totalSize += testSize; buf.PutShort( testSize ); } else { buf.PutShort( -1 ); } } for ( int i = 0; i < header.numDisplacements; i++ ) { if ( virtualMeshes[i] ) { unsigned int testSize = physcollision->CollideSize( virtualMeshes[i] ); dispBuf.RemoveAll(); dispBuf.EnsureCount(testSize); unsigned int outSize = physcollision->CollideWrite( dispBuf.Base(), virtualMeshes[i], false ); Assert( outSize == testSize ); buf.Put( dispBuf.Base(), outSize ); } } g_PhysDispSize = totalSize + sizeof(dphysdisp_t) + (sizeof(unsigned short) * header.numDisplacements); Assert( buf.TellMaxPut() == g_PhysDispSize ); g_PhysDispSize = buf.TellMaxPut(); g_pPhysDisp = new byte[g_PhysDispSize]; Q_memcpy( g_pPhysDisp, buf.Base(), g_PhysDispSize ); }
//----------------------------------------------------------------------------- // Purpose: Copy a string into a CUtlVector of characters //----------------------------------------------------------------------------- void UtlStrcpy( CUtlVector<char> &dest, const char *pSrc ) { dest.EnsureCount( (int) (strlen( pSrc ) + 1) ); Q_strncpy( dest.Base(), pSrc, dest.Count() ); }
//----------------------------------------------------------------------------- // 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; } } } } } } }