//----------------------------------------------------------------------------- // 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; } } } } } } }
void UnwrapMod::fnAlignAndFit(int axis) { //get our selection Box3 bounds; bounds.Init(); //get the bounding box Point3 pnorm(0.0f,0.0f,0.0f); int ct = 0; TimeValue t = GetCOREInterface()->GetTime(); for (int ldID = 0; ldID < mMeshTopoData.Count(); ldID++) { MeshTopoData *ld = mMeshTopoData[ldID]; Matrix3 tm = mMeshTopoData.GetNodeTM(t,ldID); for (int k = 0; k < ld->GetNumberFaces(); k++) { if (ld->GetFaceSelected(k)) { // Grap the three points, xformed int pcount = 3; // if (gfaces[k].flags & FLAG_QUAD) pcount = 4; pcount = ld->GetFaceDegree(k);//gfaces[k]->count; Point3 temp_point[4]; for (int j=0; j<pcount; j++) { int index = ld->GetFaceGeomVert(k,j);//gfaces[k]->t[j]; bounds += ld->GetGeomVert(index) *tm;//gverts.d[index].p; if (j < 4) temp_point[j] = ld->GetGeomVert(index);//gverts.d[index].p; } pnorm += VectorTransform(Normalize(temp_point[1]-temp_point[0]^temp_point[2]-temp_point[1]),tm); ct++; } } } if (ct == 0) return; theHold.Begin(); SuspendAnimate(); AnimateOff(); pnorm = pnorm / (float) ct; Matrix3 tm(1); //if just a primary axis set the tm; Point3 center = bounds.Center(); // build the scale Point3 scale(bounds.Width().x ,bounds.Width().y , bounds.Width().z); if (scale.x == 0.0f) scale.x = 1.0f; if (scale.y == 0.0f) scale.y = 1.0f; if (scale.z == 0.0f) scale.z = 1.0f; if (axis == 0) // x axi { tm.SetRow(0,Point3(0.0f,-scale.y,0.0f)); tm.SetRow(1,Point3(0.0f,0.0f,scale.z)); tm.SetRow(2,Point3(scale.x,0.0f,0.0f)); if ((fnGetMapMode() == PLANARMAP) || (fnGetMapMode() == PELTMAP) || (fnGetMapMode() == SPHERICALMAP) || (fnGetMapMode() == BOXMAP)) tm.SetRow(3,center); else if (fnGetMapMode() == CYLINDRICALMAP) { center.x = bounds.pmin.x; tm.SetRow(3,center); } Matrix3 ptm(1), id(1); tm = tm ; SetXFormPacket tmpck(tm,ptm); tmControl->SetValue(t,&tmpck,TRUE,CTRL_RELATIVE); } else if (axis == 1) // y axi { tm.SetRow(0,Point3(scale.x,0.0f,0.0f)); tm.SetRow(1,Point3(0.0f,0.0f,scale.z)); tm.SetRow(2,Point3(0.0f,scale.y,0.0f)); if ((fnGetMapMode() == PLANARMAP) || (fnGetMapMode() == PELTMAP)|| (fnGetMapMode() == SPHERICALMAP) || (fnGetMapMode() == BOXMAP)) tm.SetRow(3,center); else if (fnGetMapMode() == CYLINDRICALMAP) { center.y = bounds.pmin.y; tm.SetRow(3,center); } Matrix3 ptm(1), id(1); tm = tm; SetXFormPacket tmpck(tm,ptm); tmControl->SetValue(t,&tmpck,TRUE,CTRL_RELATIVE); } else if (axis == 2) //z axi { tm.SetRow(0,Point3(scale.x,0.0f,0.0f)); tm.SetRow(1,Point3(0.0f,scale.y,0.0f)); tm.SetRow(2,Point3(0.0f,0.0f,scale.z)); if ((fnGetMapMode() == PLANARMAP) || (fnGetMapMode() == PELTMAP)|| (fnGetMapMode() == SPHERICALMAP) || (fnGetMapMode() == BOXMAP)) tm.SetRow(3,center); else if (fnGetMapMode() == CYLINDRICALMAP) { center.z = bounds.pmin.z; tm.SetRow(3,center); } Matrix3 ptm(1), id(1); tm = tm; SetXFormPacket tmpck(tm,ptm); tmControl->SetValue(t,&tmpck,TRUE,CTRL_RELATIVE); } else if (axis == 3) // normal { int numberOfSelectionGroups = 0; for (int ldID = 0; ldID < mMeshTopoData.Count(); ldID++) { MeshTopoData *ld = mMeshTopoData[ldID]; if (ld->GetFaceSelection().NumberSet()) numberOfSelectionGroups++; } if ((fnGetMapMode() == PLANARMAP) || (fnGetMapMode() == PELTMAP) || (numberOfSelectionGroups > 1)) { //get our tm Matrix3 tm; UnwrapMatrixFromNormal(pnorm,tm); Matrix3 itm = Inverse(tm); //find our x and y scale float xmax = 0.0f; float ymax = 0.0f; float zmax = 0.0f; Box3 localBounds; localBounds.Init(); for (int ldID = 0; ldID < mMeshTopoData.Count(); ldID++) { MeshTopoData *ld = mMeshTopoData[ldID]; Matrix3 tm = mMeshTopoData.GetNodeTM(t,ldID); for (int k = 0; k < ld->GetNumberFaces(); k++) { if (ld->GetFaceSelected(k)) { // Grap the three points, xformed int pcount = 3; // if (gfaces[k].flags & FLAG_QUAD) pcount = 4; pcount = ld->GetFaceDegree(k);//gfaces[k]->count; Point3 temp_point[4]; for (int j=0; j<pcount; j++) { int index = ld->GetFaceGeomVert(k,j);//gfaces[k]->t[j]; Point3 p = ld->GetGeomVert(index) * tm * itm;//gverts.d[index].p * itm; localBounds += p; } } } } // center = localBounds.Center(); xmax = localBounds.pmax.x - localBounds.pmin.x; ymax = localBounds.pmax.y - localBounds.pmin.y; zmax = localBounds.pmax.z - localBounds.pmin.z; if (xmax < 0.001f) xmax = 1.0f; if (ymax < 0.001f) ymax = 1.0f; if (zmax < 0.001f) zmax = 1.0f; Point3 vec; vec = Normalize(tm.GetRow(0)) * xmax; tm.SetRow(0,vec); vec = Normalize(tm.GetRow(1)) * ymax; tm.SetRow(1,vec); vec = Normalize(tm.GetRow(2)) * zmax; tm.SetRow(2,vec); tm.SetRow(3,center); Matrix3 ptm(1), id(1); tm = tm ; SetXFormPacket tmpck(tm,ptm); tmControl->SetValue(t,&tmpck,TRUE,CTRL_RELATIVE); } else if ((fnGetMapMode() == CYLINDRICALMAP) || (fnGetMapMode() == SPHERICALMAP)|| (fnGetMapMode() == BOXMAP)) { for (int ldID = 0; ldID < mMeshTopoData.Count(); ldID++) { //get our first 2 rings Tab<int> openEdges; Tab<int> startRing; Tab<int> endRing; MeshTopoData *ld = mMeshTopoData[ldID]; //skip any local data that has no selections if (ld->GetFaceSelection().NumberSet() == 0) continue; Matrix3 nodeTM = mMeshTopoData.GetNodeTM(t,ldID); for (int i = 0; i < ld->GetNumberGeomEdges(); i++)//TVMaps.gePtrList.Count(); i++) { int numberSelectedFaces = 0; int ct = ld->GetGeomEdgeNumberOfConnectedFaces(i);//TVMaps.gePtrList[i]->faceList.Count(); for (int j = 0; j < ct; j++) { int faceIndex = ld->GetGeomEdgeConnectedFace(i,j);//TVMaps.gePtrList[i]->faceList[j]; if (ld->GetFaceSelected(faceIndex))//fsel[faceIndex]) numberSelectedFaces++; } if (numberSelectedFaces == 1) { openEdges.Append(1,&i,1000); } } GetOpenEdges(ld,openEdges, startRing); GetOpenEdges(ld,openEdges, endRing); Point3 zVec = pnorm; Point3 centerS(0.0f,0.0f,0.0f), centerE; if ((startRing.Count() != 0) && (endRing.Count() != 0)) { //get the center start Box3 BoundsS, BoundsE; BoundsS.Init(); BoundsE.Init(); //get the center end for (int i = 0; i < startRing.Count(); i++) { int eIndex = startRing[i]; int a = ld->GetGeomEdgeVert(eIndex,0);//TVMaps.gePtrList[eIndex]->a; int b = ld->GetGeomEdgeVert(eIndex,1);//TVMaps.gePtrList[eIndex]->b; BoundsS += ld->GetGeomVert(a) * nodeTM;//TVMaps.geomPoints[a]; BoundsS += ld->GetGeomVert(b) * nodeTM;//TVMaps.geomPoints[b]; } for (int i = 0; i < endRing.Count(); i++) { int eIndex = endRing[i]; int a = ld->GetGeomEdgeVert(eIndex,0);//TVMaps.gePtrList[eIndex]->a; int b = ld->GetGeomEdgeVert(eIndex,1);//TVMaps.gePtrList[eIndex]->b; BoundsE += ld->GetGeomVert(a) * nodeTM;//TVMaps.geomPoints[a]; BoundsE += ld->GetGeomVert(b) * nodeTM;//TVMaps.geomPoints[b]; } centerS = BoundsS.Center(); centerE = BoundsE.Center(); //create the vec zVec = centerE - centerS; } else if ((startRing.Count() != 0) && (endRing.Count() == 0)) { //get the center start Box3 BoundsS; BoundsS.Init(); //get the center end for (int i = 0; i < startRing.Count(); i++) { int eIndex = startRing[i]; int a = ld->GetGeomEdgeVert(eIndex,0);//TVMaps.gePtrList[eIndex]->a; int b = ld->GetGeomEdgeVert(eIndex,1);//TVMaps.gePtrList[eIndex]->b; BoundsS += ld->GetGeomVert(a) * nodeTM;//TVMaps.geomPoints[a]; BoundsS += ld->GetGeomVert(b) * nodeTM;//TVMaps.geomPoints[b]; } centerS = BoundsS.Center(); int farthestPoint= -1; Point3 fp; float farthestDist= 0.0f; for (int k=0; k < ld->GetNumberFaces(); k++) { if (ld->GetFaceSelected(k)) { // Grap the three points, xformed int pcount = 3; // if (gfaces[k].flags & FLAG_QUAD) pcount = 4; pcount = ld->GetFaceDegree(k);//gfaces[k]->count; for (int j=0; j<pcount; j++) { int index = ld->GetFaceGeomVert(k,j);//gfaces[k]->t[j]; Point3 p = ld->GetGeomVert(index)* nodeTM;//gverts.d[index].p; float d = LengthSquared(p-centerS); if ((d > farthestDist) || (farthestPoint == -1)) { farthestDist = d; farthestPoint = index; fp = p; } } } } centerE = fp; //create the vec zVec = centerE - centerS; } else { zVec = Point3(0.0f,0.0f,1.0f); } //get our tm Matrix3 tm; UnwrapMatrixFromNormal(zVec,tm); tm.SetRow(3,centerS); Matrix3 itm = Inverse(tm); //find our x and y scale float xmax = 0.0f; float ymax = 0.0f; float zmax = 0.0f; Box3 localBounds; localBounds.Init(); for (int k = 0; k < ld->GetNumberFaces(); k++)//gfaces.Count(); k++) { if (ld->GetFaceSelected(k)) { // Grap the three points, xformed int pcount = 3; // if (gfaces[k].flags & FLAG_QUAD) pcount = 4; pcount = ld->GetFaceDegree(k);//gfaces[k]->count; Point3 temp_point[4]; for (int j=0; j<pcount; j++) { int index = ld->GetFaceGeomVert(k,j);//gfaces[k]->t[j]; Point3 p = ld->GetGeomVert(index) * nodeTM * itm;//gverts.d[index].p * itm; localBounds += p; } } } center = localBounds.Center() * tm; if (fnGetMapMode() == CYLINDRICALMAP) { if ((startRing.Count() == 0) && (endRing.Count() == 0)) { centerS = center; centerS.z = localBounds.pmin.z; } else { centerS = centerS * itm; centerS.z = localBounds.pmin.z; centerS = centerS * tm; } } else if ((fnGetMapMode() == SPHERICALMAP) || (fnGetMapMode() == BOXMAP)) { centerS = center; } Point3 bc = localBounds.Center(); bc.z = localBounds.pmin.z; bc = bc * tm; xmax = localBounds.pmax.x - localBounds.pmin.x; ymax = localBounds.pmax.y - localBounds.pmin.y; zmax = localBounds.pmax.z - localBounds.pmin.z; Point3 vec; vec = Normalize(tm.GetRow(0)) * xmax; tm.SetRow(0,vec); vec = Normalize(tm.GetRow(1)) * ymax; tm.SetRow(1,vec); vec = Normalize(tm.GetRow(2)) * zmax; tm.SetRow(2,vec); tm.SetRow(3,centerS); Matrix3 ptm(1), id(1); tm = tm; SetXFormPacket tmpck(tm,ptm); tmControl->SetValue(t,&tmpck,TRUE,CTRL_RELATIVE); } } } ResumeAnimate(); if ((fnGetMapMode() == PLANARMAP) || (fnGetMapMode() == CYLINDRICALMAP) || (fnGetMapMode() == SPHERICALMAP) || (fnGetMapMode() == BOXMAP)) ApplyGizmo(); theHold.Accept(GetString(IDS_MAPPING_ALIGN)); fnGetGizmoTM(); if (ip) ip->RedrawViews(ip->GetTime()); }
void MorphByBone::MirrorMorph(int sourceIndex, int targetIndex, BOOL mirrorData) { //validate the indices if ((sourceIndex < 0) || (sourceIndex >= boneData.Count())) return; if ((targetIndex < 0) || (targetIndex >= boneData.Count())) return; float threshold = 0.0f; pblock->GetValue(pb_mirrorthreshold,0,threshold,FOREVER); //get our mirror tm theHold.Begin(); theHold.Put(new MorphUIRestore(this)); //stupid Hack to handle UI update after redo for (int i = 0; i < localDataList.Count(); i++) { MorphByBoneLocalData *ld = localDataList[i]; if (ld) { //build our vertex look up index ld->tempPoints = ld->preDeform; ld->tempMatchList.SetCount(ld->tempPoints.Count()); for (int j = 0; j < ld->preDeform.Count(); j++) { Matrix3 tm(1); //need to put our original points ld->tempPoints[j] = ld->tempPoints[j] * mirrorTM; ld->tempMatchList[j] = -1; } for (int j = 0; j < ld->tempPoints.Count(); j++) { Point3 sourcePoint = ld->preDeform[j]; float closest = 3.4e+38; int closestID = -1; for (int k = 0; k < ld->tempPoints.Count(); k++) { Point3 mirrorPoint = ld->tempPoints[k]; float dist = Length(sourcePoint-mirrorPoint); if ((dist < threshold) && (dist < closest)) { closest = dist; closestID = k; } } if (closestID != -1) ld->tempMatchList[closestID] = j; } //loop through our targets int numberOfNewMorphs = boneData[sourceIndex]->morphTargets.Count(); int currentSourceMorph = 0; Matrix3 initialDriverTargetTM = GetNode(targetIndex)->GetNodeTM(GetCOREInterface()->GetTime()); // Matrix3 initialDriverTargetTM = boneData[targetIndex]->intialBoneNodeTM; Matrix3 initialDriverSourceTM = GetNode(sourceIndex)->GetNodeTM(GetCOREInterface()->GetTime());// boneData[sourceIndex]->intialBoneNodeTM; Matrix3 tm(1); //from world to local tm = Inverse(ld->selfNodeCurrentTM); //morph tm in local object space and mirrored tm = tm * mirrorTM; //back to world space tm = tm * ld->selfNodeCurrentTM; //now in local space of the target bone // tm = tm * Inverse(boneData[targetIndex]->parentBoneNodeCurrentTM); //now intitial driver tm in world space initialDriverSourceTM *= tm; for (int j = 0; j < numberOfNewMorphs; j++) { //create a new morph MorphTargets *morphTarget = boneData[sourceIndex]->morphTargets[currentSourceMorph]->Clone(); //remap the indices morphTarget->d.ZeroCount(); for (int k = 0; k < boneData[sourceIndex]->morphTargets[currentSourceMorph]->d.Count(); k++) { int vertID = boneData[sourceIndex]->morphTargets[currentSourceMorph]->d[k].vertexID; int index = ld->tempMatchList[vertID]; if (index != -1) { morphTarget->d.Append(1,&boneData[sourceIndex]->morphTargets[currentSourceMorph]->d[k],500); morphTarget->d[morphTarget->d.Count()-1].vertexID = index; morphTarget->d[morphTarget->d.Count()-1].originalPt = morphTarget->d[morphTarget->d.Count()-1].originalPt * mirrorTM; } } if (mirrorData) { morphTarget->parentTM = boneData[targetIndex]->parentBoneNodeCurrentTM; //mirror the source tms Matrix3 morphTM = morphTarget->boneTMInParentSpace; //put in world space morphTM = morphTM * boneData[sourceIndex]->parentBoneNodeCurrentTM; //now in world space morphTM *= tm; //rebuild the tms //put the driver tm in the morph tm space Matrix3 newTM = initialDriverTargetTM; newTM = newTM * Inverse(initialDriverSourceTM); newTM = newTM * morphTM; newTM = newTM * Inverse(boneData[targetIndex]->parentBoneNodeCurrentTM); morphTarget->boneTMInParentSpace = newTM; //mirror the source deltas for (int k = 0; k < morphTarget->d.Count(); k++) { Point3 vec = morphTarget->d[k].vec; // current bone space vec = VectorTransform(vec,boneData[sourceIndex]->intialBoneNodeTM); //world space vec = VectorTransform(vec,tm); //world space after mirror vec = VectorTransform(vec,Inverse(boneData[targetIndex]->intialBoneNodeTM)); //bone space morphTarget->d[k].vec = vec; vec = morphTarget->d[k].vecParentSpace; //parent space vec = VectorTransform(vec,boneData[sourceIndex]->intialParentNodeTM); //world space vec = VectorTransform(vec,tm); //world space after mirror vec = VectorTransform(vec,Inverse(boneData[targetIndex]->intialParentNodeTM)); //bone space morphTarget->d[k].vecParentSpace = vec; } } float angle = 0.0f; Matrix3 currentBoneTM = boneData[targetIndex]->currentBoneNodeTM; Matrix3 currentParentBoneTM = boneData[targetIndex]->parentBoneNodeCurrentTM; currentBoneTM *= Inverse(currentParentBoneTM); angle = AngleBetweenTMs(currentBoneTM,morphTarget->boneTMInParentSpace); float per = 1.0f - angle/morphTarget->influenceAngle; per = GetFalloff(per, morphTarget->falloff,morphTarget->curve); if (per < 0.0f) per = 0.0f; morphTarget->weight = per; boneData[targetIndex]->morphTargets.Append(1,&morphTarget); theHold.Put(new CreateMorphRestore(this,morphTarget)); currentSourceMorph++; } } } theHold.Put(new MorphUIRestore(this)); //stupid Hack to handle UI update after redo theHold.Accept(GetString(IDS_MIRRORMORPHS)); BuildTreeList(); }
//----------------------------------------------------------------------------- // This is called by the base object when it's time to spawn the control panels //----------------------------------------------------------------------------- void CPlantedC4::SpawnControlPanels() { char buf[64]; // FIXME: Deal with dynamically resizing control panels? // If we're attached to an entity, spawn control panels on it instead of use CBaseAnimating *pEntityToSpawnOn = this; char *pOrgLL = "controlpanel%d_ll"; char *pOrgUR = "controlpanel%d_ur"; char *pAttachmentNameLL = pOrgLL; char *pAttachmentNameUR = pOrgUR; Assert( pEntityToSpawnOn ); // Lookup the attachment point... int nPanel; for ( nPanel = 0; true; ++nPanel ) { Q_snprintf( buf, sizeof( buf ), pAttachmentNameLL, nPanel ); int nLLAttachmentIndex = pEntityToSpawnOn->LookupAttachment(buf); if (nLLAttachmentIndex <= 0) { // Try and use my panels then pEntityToSpawnOn = this; Q_snprintf( buf, sizeof( buf ), pOrgLL, nPanel ); nLLAttachmentIndex = pEntityToSpawnOn->LookupAttachment(buf); if (nLLAttachmentIndex <= 0) return; } Q_snprintf( buf, sizeof( buf ), pAttachmentNameUR, nPanel ); int nURAttachmentIndex = pEntityToSpawnOn->LookupAttachment(buf); if (nURAttachmentIndex <= 0) { // Try and use my panels then Q_snprintf( buf, sizeof( buf ), pOrgUR, nPanel ); nURAttachmentIndex = pEntityToSpawnOn->LookupAttachment(buf); if (nURAttachmentIndex <= 0) return; } const char *pScreenName; GetControlPanelInfo( nPanel, pScreenName ); if (!pScreenName) continue; const char *pScreenClassname; GetControlPanelClassName( nPanel, pScreenClassname ); if ( !pScreenClassname ) continue; // Compute the screen size from the attachment points... matrix3x4_t panelToWorld; pEntityToSpawnOn->GetAttachment( nLLAttachmentIndex, panelToWorld ); matrix3x4_t worldToPanel; MatrixInvert( panelToWorld, worldToPanel ); // Now get the lower right position + transform into panel space Vector lr, lrlocal; pEntityToSpawnOn->GetAttachment( nURAttachmentIndex, panelToWorld ); MatrixGetColumn( panelToWorld, 3, lr ); VectorTransform( lr, worldToPanel, lrlocal ); float flWidth = lrlocal.x; float flHeight = lrlocal.y; CVGuiScreen *pScreen = CreateVGuiScreen( pScreenClassname, pScreenName, pEntityToSpawnOn, this, nLLAttachmentIndex ); pScreen->ChangeTeam( GetTeamNumber() ); pScreen->SetActualSize( flWidth, flHeight ); pScreen->SetActive( true ); pScreen->MakeVisibleOnlyToTeammates( false ); int nScreen = m_hScreens.AddToTail( ); m_hScreens[nScreen].Set( pScreen ); } }
// Geometric normal (face normal) Point3 SContext::GNormal(void) { // The face normals are already in camera space return VectorTransform(tmAfterWSM, mesh->getFaceNormal(faceNum)); }
/* ================ ================ */ void StudioModel::DrawPoints ( ) { int i, j; mstudiomesh_t *pmesh; byte *pvertbone; byte *pnormbone; vec3_t *pstudioverts; vec3_t *pstudionorms; mstudiotexture_t *ptexture; float *av; float *lv; float lv_tmp; short *pskinref; pvertbone = ((byte *)m_pstudiohdr + m_pmodel->vertinfoindex); pnormbone = ((byte *)m_pstudiohdr + m_pmodel->norminfoindex); ptexture = (mstudiotexture_t *)((byte *)m_ptexturehdr + m_ptexturehdr->textureindex); pmesh = (mstudiomesh_t *)((byte *)m_pstudiohdr + m_pmodel->meshindex); pstudioverts = (vec3_t *)((byte *)m_pstudiohdr + m_pmodel->vertindex); pstudionorms = (vec3_t *)((byte *)m_pstudiohdr + m_pmodel->normindex); pskinref = (short *)((byte *)m_ptexturehdr + m_ptexturehdr->skinindex); if (m_skinnum != 0 && m_skinnum < m_ptexturehdr->numskinfamilies) pskinref += (m_skinnum * m_ptexturehdr->numskinref); for (i = 0; i < m_pmodel->numverts; i++) { VectorTransform (pstudioverts[i], g_bonetransform[pvertbone[i]], g_pxformverts[i]); } // // clip and draw all triangles // lv = (float *)g_pvlightvalues; for (j = 0; j < m_pmodel->nummesh; j++) { int flags; flags = ptexture[pskinref[pmesh[j].skinref]].flags; for (i = 0; i < pmesh[j].numnorms; i++, lv += 3, pstudionorms++, pnormbone++) { Lighting (&lv_tmp, *pnormbone, flags, (float *)pstudionorms); // FIX: move this check out of the inner loop if (flags & STUDIO_NF_CHROME) Chrome( g_chrome[(float (*)[3])lv - g_pvlightvalues], *pnormbone, (float *)pstudionorms ); lv[0] = lv_tmp * g_lightcolor[0]; lv[1] = lv_tmp * g_lightcolor[1]; lv[2] = lv_tmp * g_lightcolor[2]; } } glCullFace(GL_FRONT); for (j = 0; j < m_pmodel->nummesh; j++) { float s, t; short *ptricmds; pmesh = (mstudiomesh_t *)((byte *)m_pstudiohdr + m_pmodel->meshindex) + j; ptricmds = (short *)((byte *)m_pstudiohdr + pmesh->triindex); s = 1.0/(float)ptexture[pskinref[pmesh->skinref]].width; t = 1.0/(float)ptexture[pskinref[pmesh->skinref]].height; glBindTexture( GL_TEXTURE_2D, ptexture[pskinref[pmesh->skinref]].index ); if (ptexture[pskinref[pmesh->skinref]].flags & STUDIO_NF_CHROME) { while (i = *(ptricmds++)) { if (i < 0) { glBegin( GL_TRIANGLE_FAN ); i = -i; } else { glBegin( GL_TRIANGLE_STRIP ); } for( ; i > 0; i--, ptricmds += 4) { // FIX: put these in as integer coords, not floats glTexCoord2f(g_chrome[ptricmds[1]][0]*s, g_chrome[ptricmds[1]][1]*t); lv = g_pvlightvalues[ptricmds[1]]; glColor4f( lv[0], lv[1], lv[2], 1.0 ); av = g_pxformverts[ptricmds[0]]; glVertex3f(av[0], av[1], av[2]); } glEnd( ); } } else { while (i = *(ptricmds++)) { if (i < 0) { glBegin( GL_TRIANGLE_FAN ); i = -i; } else { glBegin( GL_TRIANGLE_STRIP ); } for( ; i > 0; i--, ptricmds += 4) { // FIX: put these in as integer coords, not floats glTexCoord2f(ptricmds[2]*s, ptricmds[3]*t); lv = g_pvlightvalues[ptricmds[1]]; glColor4f( lv[0], lv[1], lv[2], 1.0 ); av = g_pxformverts[ptricmds[0]]; glVertex3f(av[0], av[1], av[2]); } glEnd( ); } } } }
//----------------------------------------------------------------------------- // Purpose: Attaches fire to the hitboxes of an animating character. The fire // is distributed based on hitbox volumes -- it attaches to the larger // hitboxes first. //----------------------------------------------------------------------------- void C_EntityFlame::AttachToHitBoxes( void ) { m_pCachedModel = NULL; C_BaseCombatCharacter *pAnimating = (C_BaseCombatCharacter *)m_hEntAttached.Get(); if (!pAnimating || !pAnimating->GetModel()) { return; } studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() ); if (!pStudioHdr) { return; } mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->m_nHitboxSet ); if ( !set ) { return; } if ( !set->numhitboxes ) { return; } m_pCachedModel = pAnimating->GetModel(); int boneMask = BONE_USED_BY_HITBOX | BONE_USED_BY_ATTACHMENT; studiocache_t *pcache = Studio_GetBoneCache( pStudioHdr, pAnimating->GetSequence(), pAnimating->m_flAnimTime, pAnimating->GetAbsAngles(), pAnimating->GetAbsOrigin(), boneMask ); if ( !pcache ) { matrix3x4_t bonetoworld[MAXSTUDIOBONES]; pAnimating->SetupBones( bonetoworld, MAXSTUDIOBONES, boneMask, gpGlobals->curtime ); pcache = Studio_SetBoneCache( pStudioHdr, pAnimating->GetSequence(), pAnimating->m_flAnimTime, pAnimating->GetAbsAngles(), pAnimating->GetAbsOrigin(), boneMask, bonetoworld ); } matrix3x4_t *hitboxbones[MAXSTUDIOBONES]; Studio_LinkHitboxCache( hitboxbones, pcache, pStudioHdr, set ); // // Sort the hitboxes by volume. // HitboxVolume_t hitboxvolume[MAXSTUDIOBONES]; for ( int i = 0; i < set->numhitboxes; i++ ) { mstudiobbox_t *pBox = set->pHitbox(i); hitboxvolume[i].nIndex = i; hitboxvolume[i].flVolume = CalcBoxVolume(pBox->bbmin, pBox->bbmax); } qsort(hitboxvolume, set->numhitboxes, sizeof(hitboxvolume[0]), (int (__cdecl *)(const void *, const void *))SortHitboxVolumes); // // Attach fire to the hitboxes. // for ( i = 0; i < NUM_HITBOX_FIRES; i++ ) { // // Pick the 5 biggest hitboxes, or random ones if there are less than 5 hitboxes, // then pick random ones after that. // if (( i < 5 ) && ( i < set->numhitboxes )) { m_nHitbox[i] = hitboxvolume[i].nIndex; } else { m_nHitbox[i] = random->RandomInt( 0, set->numhitboxes - 1 ); } mstudiobbox_t *pBox = set->pHitbox(m_nHitbox[i]); m_pFireSmoke[i] = new C_FireSmoke; // // Calculate a position within the hitbox to place the fire. // m_vecFireOrigin[i] = Vector(random->RandomFloat(pBox->bbmin.x, pBox->bbmax.x), random->RandomFloat(pBox->bbmin.y, pBox->bbmax.y), random->RandomFloat(pBox->bbmin.z, pBox->bbmax.z)); Vector vecAbsOrigin; VectorTransform(m_vecFireOrigin[i], *hitboxbones[m_nHitbox[i]], vecAbsOrigin); m_pFireSmoke[i]->SetLocalOrigin( vecAbsOrigin ); // // The first 2 fires emit smoke, the rest do not. // m_pFireSmoke[i]->m_nFlags = bitsFIRESMOKE_ACTIVE | bitsFIRESMOKE_GLOW; if ( i < 2 ) { m_pFireSmoke[i]->m_nFlags |= bitsFIRESMOKE_SMOKE; } m_pFireSmoke[i]->m_nFlameModelIndex = modelinfo->GetModelIndex("sprites/fire1.vmt"); m_pFireSmoke[i]->m_flScale = 0; m_pFireSmoke[i]->m_flStartScale = 0; m_pFireSmoke[i]->m_flScaleTime = 1.5; m_pFireSmoke[i]->m_flScaleRegister = 0.1; m_pFireSmoke[i]->m_flChildFlameSpread = 20.0; m_pFireSmoke[i]->m_flScaleStart = 0; m_pFireSmoke[i]->m_flScaleEnd = 0.00012f * hitboxvolume[i].flVolume; m_pFireSmoke[i]->m_flScaleTimeStart = Helper_GetTime(); m_pFireSmoke[i]->m_flScaleTimeEnd = Helper_GetTime() + 2.0; m_pFireSmoke[i]->StartClientOnly(); } m_bAttachedToHitboxes = true; }
//----------------------------------------------------------------------------- // Purpose: // Input : flTime - // intermission - //----------------------------------------------------------------------------- int CHudOverview::Draw(float flTime) { #if 0 // only draw in overview mode if (!gEngfuncs.Overview_GetOverviewState()) return 1; // make sure we have player info // gViewPort->GetAllPlayersInfo(); gHUD.m_Scoreboard.GetAllPlayersInfo(); // calculate player size on the overview int x1, y1, x2, y2; float v0[3]={0,0,0}, v1[3]={64,64,0}; gEngfuncs.Overview_WorldToScreen(v0, &x1, &y1); gEngfuncs.Overview_WorldToScreen(v1, &x2, &y2); float scale = abs(x2 - x1); // loop through all the players and draw them on the map for (int i = 1; i < MAX_PLAYERS; i++) { cl_entity_t *pl = gEngfuncs.GetEntityByIndex(i); if (pl && pl->player && pl->curstate.health > 0 && pl->curstate.solid != SOLID_NOT) { int x, y, z = 0; float v[3]={pl->origin[0], pl->origin[1], 0}; gEngfuncs.Overview_WorldToScreen(v, &x, &y); // hack in some team colors float r, g, bc; if (g_PlayerExtraInfo[i].teamnumber == 1) { r = 0.0f; g = 0.0f; bc = 1.0f; } else if (g_PlayerExtraInfo[i].teamnumber == 2) { r = 1.0f; g = 0.0f; bc = 0.0f; } else { // just use the default orange color if the team isn't set r = 1.0f; g = 0.7f; bc = 0.0f; } // set the current texture gEngfuncs.pTriAPI->SpriteTexture((struct model_s *)gEngfuncs.GetSpritePointer(m_hsprPlayer), 0); // additive render mode gEngfuncs.pTriAPI->RenderMode(kRenderTransAdd); // no culling gEngfuncs.pTriAPI->CullFace(TRI_NONE); // draw a square gEngfuncs.pTriAPI->Begin(TRI_QUADS); // set the color to be that of the team gEngfuncs.pTriAPI->Color4f(r, g, bc, 1.0f); // calculate rotational matrix vec3_t a, b, angles; float rmatrix[3][4]; // transformation matrix VectorCopy(pl->angles, angles); angles[0] = 0.0f; angles[1] += 90.f; angles[1] = -angles[1]; angles[2] = 0.0f; AngleMatrix(angles, rmatrix); a[2] = 0; a[0] = -scale; a[1] = -scale; VectorTransform(a, rmatrix , b ); gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); gEngfuncs.pTriAPI->Vertex3f(x + b[0], y + b[1], z); a[0]=-scale; a[1] = scale; VectorTransform(a, rmatrix , b ); gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); gEngfuncs.pTriAPI->Vertex3f (x + b[0], y + b[1], z); a[0]=scale; a[1] = scale; VectorTransform(a, rmatrix , b ); gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); gEngfuncs.pTriAPI->Vertex3f (x + b[0], y + b[1], z); a[0]=scale; a[1] = -scale; VectorTransform(a, rmatrix , b ); gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); gEngfuncs.pTriAPI->Vertex3f (x + b[0], y + b[1], z); // finish up gEngfuncs.pTriAPI->End(); gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); // draw the players name and health underneath char string[256]; sprintf(string, "%s (%i%%)", g_PlayerInfoList[i].name, pl->curstate.health); DrawConsoleString(x, y + (1.1 * scale), string); } } #endif return 1; }
void MeshTopoData::AlignCluster(Tab<ClusterClass*> &clusterList, int baseCluster, int moveCluster, int innerFaceIndex, int outerFaceIndex,int edgeIndex,UnwrapMod *mod) { //get edges that are coincedent int vInner[2]; int vOuter[2]; int vInnerVec[2]; int vOuterVec[2]; int ct = 0; int vct = 0; for (int i = 0; i < TVMaps.f[innerFaceIndex]->count; i++) { int innerIndex = TVMaps.f[innerFaceIndex]->v[i]; for (int j = 0; j < TVMaps.f[outerFaceIndex]->count; j++) { int outerIndex = TVMaps.f[outerFaceIndex]->v[j]; if (innerIndex == outerIndex) { vInner[ct] = TVMaps.f[innerFaceIndex]->t[i]; vOuter[ct] = TVMaps.f[outerFaceIndex]->t[j]; ct++; } } } vInnerVec[0] = -1; vInnerVec[1] = -1; vOuterVec[0] = -1; vOuterVec[1] = -1; ct = 0; if ( (TVMaps.f[innerFaceIndex]->flags & FLAG_CURVEDMAPPING) && (TVMaps.f[innerFaceIndex]->vecs) && (TVMaps.f[outerFaceIndex]->flags & FLAG_CURVEDMAPPING) && (TVMaps.f[outerFaceIndex]->vecs) ) { for (int i = 0; i < TVMaps.f[innerFaceIndex]->count*2; i++) { int innerIndex = TVMaps.f[innerFaceIndex]->vecs->vhandles[i]; for (int j = 0; j < TVMaps.f[outerFaceIndex]->count*2; j++) { int outerIndex = TVMaps.f[outerFaceIndex]->vecs->vhandles[j]; if (innerIndex == outerIndex) { int vec = TVMaps.f[innerFaceIndex]->vecs->handles[i]; vInnerVec[ct] = vec; vec = TVMaps.f[outerFaceIndex]->vecs->handles[j]; vOuterVec[ct] = vec; ct++; } } } } //get align vector Point3 pInner[2]; Point3 pOuter[2]; pInner[0] = TVMaps.v[vInner[0]].GetP(); pInner[1] = TVMaps.v[vInner[1]].GetP(); pOuter[0] = TVMaps.v[vOuter[0]].GetP(); pOuter[1] = TVMaps.v[vOuter[1]].GetP(); Point3 offset = pInner[0] - pOuter[0]; Point3 vecA, vecB; vecA = Normalize(pInner[1] - pInner[0]); vecB = Normalize(pOuter[1] - pOuter[0]); float dot = DotProd(vecA,vecB); float angle = 0.0f; if (dot == -1.0f) angle = PI; else if (dot >= 1.0f) angle = 0.f; else angle = acos(dot); if ((_isnan(angle)) || (!_finite(angle))) angle = 0.0f; Matrix3 tempMat(1); tempMat.RotateZ(angle); Point3 vecC = VectorTransform(tempMat,vecB); float negAngle = -angle; Matrix3 tempMat2(1); tempMat2.RotateZ(negAngle); Point3 vecD = VectorTransform(tempMat2,vecB); float la,lb; la = Length(vecA-vecC); lb = Length(vecA-vecD); if (la > lb) angle = negAngle; clusterList[moveCluster]->newX = offset.x; clusterList[moveCluster]->newY = offset.y; //build vert list //move those verts BitArray processVertList; processVertList.SetSize(TVMaps.v.Count()); processVertList.ClearAll(); for (int i =0; i < clusterList[moveCluster]->faces.Count(); i++) { int faceIndex = clusterList[moveCluster]->faces[i]; for (int j =0; j < TVMaps.f[faceIndex]->count; j++) { int vertexIndex = TVMaps.f[faceIndex]->t[j]; processVertList.Set(vertexIndex); if ( (patch) && (TVMaps.f[faceIndex]->flags & FLAG_CURVEDMAPPING) && (TVMaps.f[faceIndex]->vecs)) { int vertIndex; if (TVMaps.f[faceIndex]->flags & FLAG_INTERIOR) { vertIndex = TVMaps.f[faceIndex]->vecs->interiors[j]; if ((vertIndex >=0) && (vertIndex < processVertList.GetSize())) processVertList.Set(vertIndex); } vertIndex = TVMaps.f[faceIndex]->vecs->handles[j*2]; if ((vertIndex >=0) && (vertIndex < processVertList.GetSize())) processVertList.Set(vertIndex); vertIndex = TVMaps.f[faceIndex]->vecs->handles[j*2+1]; if ((vertIndex >=0) && (vertIndex < processVertList.GetSize())) processVertList.Set(vertIndex); } } } for (int i = 0; i < processVertList.GetSize(); i++) { if (processVertList[i]) { Point3 p = TVMaps.v[i].GetP(); //move to origin p -= pOuter[0]; //rotate Matrix3 mat(1); mat.RotateZ(angle); p = p * mat; //move to anchor point p += pInner[0]; SetTVVert(0,i,p,mod);//TVMaps.v[i].p = p; //if (TVMaps.cont[i]) TVMaps.cont[i]->SetValue(0,&TVMaps.v[i].p); } } if ((vInnerVec[0] != -1) && (vInnerVec[1] != -1) && (vOuterVec[0] != -1) && (vOuterVec[1] != -1)) { SetTVVert(0,vOuterVec[0],TVMaps.v[vInnerVec[0]].GetP(),mod);//TVMaps.v[vOuterVec[0]].p = TVMaps.v[vInnerVec[0]].p; //if (TVMaps.cont[vOuterVec[0]]) TVMaps.cont[vOuterVec[0]]->SetValue(0,&TVMaps.v[vInnerVec[0]].p); SetTVVert(0,vOuterVec[1],TVMaps.v[vInnerVec[1]].GetP(),mod);//TVMaps.v[vOuterVec[1]].p = TVMaps.v[vInnerVec[1]].p; //if (TVMaps.cont[vOuterVec[1]]) TVMaps.cont[vOuterVec[1]]->SetValue(0,&TVMaps.v[vInnerVec[1]].p); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void C_EntityFlame::UpdateHitBoxFlames( void ) { C_BaseCombatCharacter *pAnimating = (C_BaseCombatCharacter *)m_hEntAttached.Get(); if (!pAnimating) { return; } if (pAnimating->GetModel() != m_pCachedModel) { if (m_pCachedModel != NULL) { // The model changed, we must reattach the flames. DeleteHitBoxFlames(); AttachToHitBoxes(); } if (m_pCachedModel == NULL) { // We tried to reattach and failed. return; } } studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() ); if (!pStudioHdr) { return; } mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->m_nHitboxSet ); if ( !set ) { return; } if ( !set->numhitboxes ) { return; } int boneMask = BONE_USED_BY_HITBOX | BONE_USED_BY_ATTACHMENT; studiocache_t *pcache = Studio_GetBoneCache( pStudioHdr, pAnimating->GetSequence(), pAnimating->m_flAnimTime, pAnimating->GetAbsAngles(), pAnimating->GetAbsOrigin(), boneMask ); if ( !pcache ) { matrix3x4_t bonetoworld[MAXSTUDIOBONES]; pAnimating->SetupBones( bonetoworld, MAXSTUDIOBONES, boneMask, gpGlobals->curtime ); pcache = Studio_SetBoneCache( pStudioHdr, pAnimating->GetSequence(), pAnimating->m_flAnimTime, pAnimating->GetAbsAngles(), pAnimating->GetAbsOrigin(), boneMask, bonetoworld ); } matrix3x4_t *hitboxbones[MAXSTUDIOBONES]; Studio_LinkHitboxCache( hitboxbones, pcache, pStudioHdr, set ); for ( int i = 0; i < NUM_HITBOX_FIRES; i++ ) { Vector vecAbsOrigin; VectorTransform(m_vecFireOrigin[i], *hitboxbones[m_nHitbox[i]], vecAbsOrigin); m_pFireSmoke[i]->SetLocalOrigin(vecAbsOrigin); } }
//----------------------------------------------------------------------------- // Debugging methods //----------------------------------------------------------------------------- void CFourWheelVehiclePhysics::DrawDebugGeometryOverlays() { Vector vecRad(m_debugRadius,m_debugRadius,m_debugRadius); for ( int i = 0; i < m_wheelCount; i++ ) { NDebugOverlay::BoxAngles(m_wheelPosition[i], -vecRad, vecRad, m_wheelRotation[i], 0, 255, 45, 0 ,0); } for ( int iWheel = 0; iWheel < m_wheelCount; iWheel++ ) { IPhysicsObject *pWheel = m_pVehicle->GetWheel( iWheel ); Vector vecPos; QAngle vecRot; pWheel->GetPosition( &vecPos, &vecRot ); NDebugOverlay::BoxAngles( vecPos, -vecRad, vecRad, vecRot, 0, 255, 45, 0 ,0 ); } #if 1 // Render vehicle data. IPhysicsObject *pBody = m_pOuter->VPhysicsGetObject(); if ( pBody ) { const vehicleparams_t vehicleParams = m_pVehicle->GetVehicleParams(); // Draw a red cube as the "center" of the vehicle. Vector vecBodyPosition; QAngle angBodyDirection; pBody->GetPosition( &vecBodyPosition, &angBodyDirection ); NDebugOverlay::BoxAngles( vecBodyPosition, Vector( -5, -5, -5 ), Vector( 5, 5, 5 ), angBodyDirection, 255, 0, 0, 0 ,0 ); matrix3x4_t matrix; AngleMatrix( angBodyDirection, vecBodyPosition, matrix ); // Draw green cubes at axle centers. Vector vecAxlePositions[2], vecAxlePositionsHL[2]; vecAxlePositions[0] = vehicleParams.axles[0].offset; vecAxlePositions[1] = vehicleParams.axles[1].offset; VectorTransform( vecAxlePositions[0], matrix, vecAxlePositionsHL[0] ); VectorTransform( vecAxlePositions[1], matrix, vecAxlePositionsHL[1] ); NDebugOverlay::BoxAngles( vecAxlePositionsHL[0], Vector( -3, -3, -3 ), Vector( 3, 3, 3 ), angBodyDirection, 0, 255, 0, 0 ,0 ); NDebugOverlay::BoxAngles( vecAxlePositionsHL[1], Vector( -3, -3, -3 ), Vector( 3, 3, 3 ), angBodyDirection, 0, 255, 0, 0 ,0 ); // Draw blue cubes at wheel centers. Vector vecWheelPositions[4], vecWheelPositionsHL[4]; vecWheelPositions[0] = vehicleParams.axles[0].offset; vecWheelPositions[0] += vehicleParams.axles[0].wheelOffset; vecWheelPositions[1] = vehicleParams.axles[0].offset; vecWheelPositions[1] -= vehicleParams.axles[0].wheelOffset; vecWheelPositions[2] = vehicleParams.axles[1].offset; vecWheelPositions[2] += vehicleParams.axles[1].wheelOffset; vecWheelPositions[3] = vehicleParams.axles[1].offset; vecWheelPositions[3] -= vehicleParams.axles[1].wheelOffset; VectorTransform( vecWheelPositions[0], matrix, vecWheelPositionsHL[0] ); VectorTransform( vecWheelPositions[1], matrix, vecWheelPositionsHL[1] ); VectorTransform( vecWheelPositions[2], matrix, vecWheelPositionsHL[2] ); VectorTransform( vecWheelPositions[3], matrix, vecWheelPositionsHL[3] ); float flWheelRadius = vehicleParams.axles[0].wheels.radius; flWheelRadius = IVP2HL( flWheelRadius ); Vector vecWheelRadius( flWheelRadius, flWheelRadius, flWheelRadius ); NDebugOverlay::BoxAngles( vecWheelPositionsHL[0], -vecWheelRadius, vecWheelRadius, angBodyDirection, 0, 0, 255, 0 ,0 ); NDebugOverlay::BoxAngles( vecWheelPositionsHL[1], -vecWheelRadius, vecWheelRadius, angBodyDirection, 0, 0, 255, 0 ,0 ); NDebugOverlay::BoxAngles( vecWheelPositionsHL[2], -vecWheelRadius, vecWheelRadius, angBodyDirection, 0, 0, 255, 0 ,0 ); NDebugOverlay::BoxAngles( vecWheelPositionsHL[3], -vecWheelRadius, vecWheelRadius, angBodyDirection, 0, 0, 255, 0 ,0 ); // Draw wheel raycasts in yellow vehicle_debugcarsystem_t debugCarSystem; m_pVehicle->GetCarSystemDebugData( debugCarSystem ); for ( int iWheel = 0; iWheel < 4; ++iWheel ) { Vector vecStart, vecEnd, vecImpact; // Hack for now. float tmpY = IVP2HL( debugCarSystem.vecWheelRaycasts[iWheel][0].z ); vecStart.z = -IVP2HL( debugCarSystem.vecWheelRaycasts[iWheel][0].y ); vecStart.y = tmpY; vecStart.x = IVP2HL( debugCarSystem.vecWheelRaycasts[iWheel][0].x ); tmpY = IVP2HL( debugCarSystem.vecWheelRaycasts[iWheel][1].z ); vecEnd.z = -IVP2HL( debugCarSystem.vecWheelRaycasts[iWheel][1].y ); vecEnd.y = tmpY; vecEnd.x = IVP2HL( debugCarSystem.vecWheelRaycasts[iWheel][1].x ); tmpY = IVP2HL( debugCarSystem.vecWheelRaycastImpacts[iWheel].z ); vecImpact.z = -IVP2HL( debugCarSystem.vecWheelRaycastImpacts[iWheel].y ); vecImpact.y = tmpY; vecImpact.x = IVP2HL( debugCarSystem.vecWheelRaycastImpacts[iWheel].x ); NDebugOverlay::BoxAngles( vecStart, Vector( -1 , -1, -1 ), Vector( 1, 1, 1 ), angBodyDirection, 0, 255, 0, 0, 0 ); NDebugOverlay::Line( vecStart, vecEnd, 255, 255, 0, true, 0 ); NDebugOverlay::BoxAngles( vecEnd, Vector( -1, -1, -1 ), Vector( 1, 1, 1 ), angBodyDirection, 255, 0, 0, 0, 0 ); NDebugOverlay::BoxAngles( vecImpact, Vector( -0.5f , -0.5f, -0.5f ), Vector( 0.5f, 0.5f, 0.5f ), angBodyDirection, 0, 0, 255, 0, 0 ); } } #endif }
BOOL BoundsTree::HitQuadTree(IPoint2 m, int &nindex, DWORD &findex, Point3 &p, Point3 &norm, Point3 &bary, float &finalZ, Matrix3 &toWorldTm) { //int nindex = 0; Leaf *l = head; BOOL hit = FALSE; Point3 hitPoint(0.0f,0.0f,0.0f); DWORD smgroup; hitPoint.x = (float) m.x; hitPoint.y = (float) m.y; float z = 0.0f; Point3 bry; if (l == NULL) { z = 0.0f; return FALSE; } int ct = 0; while ( (l!=NULL) && (l->IsBottom() == FALSE)) { int id = l->InWhichQuad(hitPoint); l = l->GetQuad(id); ct++; } if (l) { if (l->faceIndex.Count() == 0) return FALSE; else { for (int i = 0; i < l->faceIndex.Count(); i++) { int faceIndex = l->faceIndex[i].faceIndex; int nodeIndex = l->faceIndex[i].nodeIndex; LightMesh *lmesh = meshList[nodeIndex]; Point3 *tempVerts = lmesh->vertsViewSpace.Addr(0); Face *tempFaces = lmesh->faces.Addr(faceIndex); Box2D b = lmesh->boundingBoxList[faceIndex]; if ( (hitPoint.x >= b.min.x) && (hitPoint.x <= b.max.x) && (hitPoint.y >= b.min.y) && (hitPoint.y <= b.max.y) ) { //now check bary coords Point3 a,b,c; a = tempVerts[tempFaces->v[0]]; b = tempVerts[tempFaces->v[1]]; c = tempVerts[tempFaces->v[2]]; Point3 az,bz,cz,hitPointZ; az = a; bz = b; cz = c; az.z = 0.0f; bz.z = 0.0f; cz.z = 0.0f; hitPointZ = hitPoint; hitPointZ.z = 0.0f; Point3 bry; bry = BaryCoords(az, bz, cz, hitPointZ); //if inside bary find the the z point if (!( (bry.x<0.0f || bry.x>1.0f || bry.y<0.0f || bry.y>1.0f || bry.z<0.0f || bry.z>1.0f) || (fabs(bry.x + bry.y + bry.z - 1.0f) > EPSILON) )) { float tz = a.z * bry.x + b.z * bry.y + c.z * bry.z; if ( (tz > z ) || (hit == FALSE) ) { z = tz; findex = faceIndex; nindex = nodeIndex; bary = bry; finalZ = z; smgroup = tempFaces->getSmGroup(); } hit = TRUE; } } } } } if (hit) { Point3 a,b,c; int ia,ib,ic; LightMesh *lmesh = meshList[nindex]; Point3 *tempVerts = lmesh->vertsWorldSpace.Addr(0); Face *tempFaces = lmesh->faces.Addr(findex); ia = tempFaces->v[0]; ib = tempFaces->v[1]; ic = tempFaces->v[2]; a = tempVerts[ia]; b = tempVerts[ib]; c = tempVerts[ic]; ViewExp *vpt = GetCOREInterface()->GetActiveViewport(); Ray worldRay; // vpt->GetAffineTM(tm); vpt->MapScreenToWorldRay((float) m.x, (float) m.y, worldRay); GetCOREInterface()->ReleaseViewport(vpt); //intersect ray with the hit face // See if the ray intersects the plane (backfaced) norm = Normalize((b-a)^(c-b)); float rn = DotProd(worldRay.dir,norm); // Use a point on the plane to find d float d = DotProd(a,norm); // Find the point on the ray that intersects the plane float ta = (d - DotProd(worldRay.p,norm)) / rn; // The point on the ray and in the plane. p = worldRay.p + ta*worldRay.dir; // Compute barycentric coords. bary = BaryCoords(a, b, c, p); finalZ = ta; // p = a * bary.x + b * bary.y + c * bary.z; p = p * meshList[nindex]->toLocalSpace; norm = VectorTransform(meshList[nindex]->toLocalSpace,norm); toWorldTm = meshList[nindex]->toWorldSpace; } return hit; }
void PropBreakableCreateAll( int modelindex, IPhysicsObject *pPhysics, const breakablepropparams_t ¶ms, CBaseEntity *pEntity, int iPrecomputedBreakableCount, bool bIgnoreGibLimit, bool defaultLocation ) { // Check for prop breakable count reset. int nPropCount = props_break_max_pieces_perframe.GetInt(); if ( nPropCount != -1 ) { if ( nFrameNumber != gpGlobals->framecount ) { nPropBreakablesPerFrameCount = 0; nFrameNumber = gpGlobals->framecount; } // Check for max breakable count for the frame. if ( nPropBreakablesPerFrameCount >= nPropCount ) return; } int iMaxBreakCount = bIgnoreGibLimit ? -1 : props_break_max_pieces.GetInt(); if ( iMaxBreakCount != -1 ) { if ( iPrecomputedBreakableCount != -1 ) { iPrecomputedBreakableCount = MIN( iMaxBreakCount, iPrecomputedBreakableCount ); } else { iPrecomputedBreakableCount = iMaxBreakCount; } } #ifdef GAME_DLL // On server limit break model creation if ( !PropBreakableCapEdictsOnCreateAll(modelindex, pPhysics, params, pEntity, iPrecomputedBreakableCount ) ) { DevMsg( "Failed to create PropBreakable: would exceed MAX_EDICTS\n" ); return; } #endif vcollide_t *pCollide = modelinfo->GetVCollide( modelindex ); if ( !pCollide ) return; int nSkin = 0; CBaseEntity *pOwnerEntity = pEntity; CBaseAnimating *pOwnerAnim = NULL; if ( pPhysics ) { pOwnerEntity = static_cast<CBaseEntity *>(pPhysics->GetGameData()); } if ( pOwnerEntity ) { pOwnerAnim = pOwnerEntity->GetBaseAnimating(); if ( pOwnerAnim ) { nSkin = pOwnerAnim->m_nSkin; } } matrix3x4_t localToWorld; CStudioHdr studioHdr; const model_t *model = modelinfo->GetModel( modelindex ); if ( model ) { studioHdr.Init( modelinfo->GetStudiomodel( model ) ); } Vector parentOrigin = vec3_origin; int parentAttachment = Studio_FindAttachment( &studioHdr, "placementOrigin" ) + 1; if ( parentAttachment > 0 ) { GetAttachmentLocalSpace( &studioHdr, parentAttachment-1, localToWorld ); MatrixGetColumn( localToWorld, 3, parentOrigin ); } else { AngleMatrix( vec3_angle, localToWorld ); } CUtlVector<breakmodel_t> list; BreakModelList( list, modelindex, params.defBurstScale, params.defCollisionGroup ); CUtlVector< CBaseEntity* > spawnedGibs; if ( list.Count() ) { for ( int i = 0; i < list.Count(); i++ ) { int modelIndex = modelinfo->GetModelIndex( list[i].modelName ); if ( modelIndex <= 0 ) continue; // Skip multiplayer pieces that should be spawning on the other dll #ifdef GAME_DLL if ( gpGlobals->maxClients > 1 && breakable_multiplayer.GetBool() ) #else if ( gpGlobals->maxClients > 1 ) #endif { #ifdef GAME_DLL if ( list[i].mpBreakMode == MULTIPLAYER_BREAK_CLIENTSIDE ) continue; #else if ( list[i].mpBreakMode == MULTIPLAYER_BREAK_SERVERSIDE ) continue; #endif if ( !defaultLocation && list[i].mpBreakMode == MULTIPLAYER_BREAK_DEFAULT ) continue; } if ( ( nPropCount != -1 ) && ( nPropBreakablesPerFrameCount > nPropCount ) ) break; if ( ( iPrecomputedBreakableCount != -1 ) && ( i >= iPrecomputedBreakableCount ) ) break; matrix3x4_t matrix; AngleMatrix( params.angles, params.origin, matrix ); CStudioHdr studioHdr; const model_t *model = modelinfo->GetModel( modelIndex ); if ( model ) { studioHdr.Init( modelinfo->GetStudiomodel( model ) ); } // Increment the number of breakable props this frame. ++nPropBreakablesPerFrameCount; const float flModelScale = pOwnerAnim->GetModelScale(); Vector position = vec3_origin; QAngle angles = params.angles; if ( pOwnerAnim && list[i].placementName[0] ) { if ( list[i].placementIsBone ) { int boneIndex = pOwnerAnim->LookupBone( list[i].placementName ); if ( boneIndex >= 0 ) { pOwnerAnim->GetBonePosition( boneIndex, position, angles ); AngleMatrix( angles, position, matrix ); } } else { int attachmentIndex = Studio_FindAttachment( &studioHdr, list[i].placementName ) + 1; if ( attachmentIndex > 0 ) { pOwnerAnim->GetAttachment( attachmentIndex, matrix ); MatrixAngles( matrix, angles ); } } } else { int placementIndex = Studio_FindAttachment( &studioHdr, "placementOrigin" ) + 1; Vector placementOrigin = parentOrigin; if ( placementIndex > 0 ) { GetAttachmentLocalSpace( &studioHdr, placementIndex-1, localToWorld ); MatrixGetColumn( localToWorld, 3, placementOrigin ); placementOrigin -= parentOrigin; } VectorTransform( list[i].offset - placementOrigin * flModelScale, matrix, position ); } Vector objectVelocity = params.velocity; if (pPhysics) { pPhysics->GetVelocityAtPoint( position, &objectVelocity ); } int nActualSkin = nSkin; if ( nActualSkin > studioHdr.numskinfamilies() ) nActualSkin = 0; CBaseEntity *pBreakable = NULL; #ifdef GAME_DLL if ( GetGibManager() == NULL || GetGibManager()->AllowedToSpawnGib() ) #endif { pBreakable = BreakModelCreateSingle( pOwnerEntity, &list[i], position, angles, objectVelocity, params.angularVelocity, nActualSkin, params ); } if ( pBreakable ) { spawnedGibs.AddToTail( pBreakable ); #ifdef GAME_DLL if ( GetGibManager() ) { GetGibManager()->AddGibToLRU( pBreakable->GetBaseAnimating() ); } #endif if ( pOwnerEntity && pOwnerEntity->IsEffectActive( EF_NOSHADOW ) ) { pBreakable->AddEffects( EF_NOSHADOW ); } // If burst scale is set, this piece should 'burst' away from // the origin in addition to travelling in the wished velocity. if ( list[i].burstScale != 0.0 ) { Vector vecBurstDir = position - params.origin; // If $autocenter wasn't used, try the center of the piece if ( vecBurstDir == vec3_origin ) { vecBurstDir = pBreakable->WorldSpaceCenter() - params.origin; } VectorNormalize( vecBurstDir ); pBreakable->ApplyAbsVelocityImpulse( vecBurstDir * list[i].burstScale * flModelScale * params.velocityScale * params.burstScale ); } if ( params.randomAngularVelocity > 0.0f ) { AngularImpulse angRandomImpulse = RandomAngularImpulse( -params.randomAngularVelocity, params.randomAngularVelocity ); pBreakable->ApplyLocalAngularVelocityImpulse( angRandomImpulse * params.velocityScale ); } // If this piece is supposed to be motion disabled, disable it if ( list[i].isMotionDisabled ) { IPhysicsObject *pPhysicsObject = pBreakable->VPhysicsGetObject(); if ( pPhysicsObject != NULL ) { pPhysicsObject->EnableMotion( false ); } } } } } // Then see if the propdata specifies any breakable pieces else if ( pEntity ) { IBreakableWithPropData *pBreakableInterface = dynamic_cast<IBreakableWithPropData*>(pEntity); if ( pBreakableInterface && pBreakableInterface->GetBreakableModel() != NULL_STRING && pBreakableInterface->GetBreakableCount() ) { breakmodel_t breakModel; for ( int i = 0; i < pBreakableInterface->GetBreakableCount(); i++ ) { if ( ( iPrecomputedBreakableCount != -1 ) && ( i >= iPrecomputedBreakableCount ) ) break; Q_strncpy( breakModel.modelName, g_PropDataSystem.GetRandomChunkModel(STRING(pBreakableInterface->GetBreakableModel()), pBreakableInterface->GetMaxBreakableSize()), sizeof(breakModel.modelName) ); breakModel.health = 1; breakModel.fadeTime = RandomFloat(5,10); breakModel.fadeMinDist = 0.0f; breakModel.fadeMaxDist = 0.0f; breakModel.burstScale = params.defBurstScale; breakModel.collisionGroup = COLLISION_GROUP_DEBRIS; breakModel.isRagdoll = false; breakModel.isMotionDisabled = false; breakModel.placementName[0] = 0; breakModel.placementIsBone = false; Vector vecObbSize = pEntity->CollisionProp()->OBBSize(); // Find a random point on the plane of the original's two largest axis int smallestAxis = SmallestAxis( vecObbSize ); Vector vecMins(0,0,0); Vector vecMaxs(1,1,1); vecMins[smallestAxis] = 0.5; vecMaxs[smallestAxis] = 0.5; pEntity->CollisionProp()->RandomPointInBounds( vecMins, vecMaxs, &breakModel.offset ); // Push all chunks away from the center Vector vecBurstDir = breakModel.offset - params.origin; VectorNormalize( vecBurstDir ); Vector vecVelocity = vecBurstDir * params.defBurstScale; QAngle vecAngles = pEntity->GetAbsAngles(); int iSkin = pBreakableInterface->GetBreakableSkin(); CBaseEntity *pBreakable = NULL; #ifdef GAME_DLL if ( GetGibManager() == NULL || GetGibManager()->AllowedToSpawnGib() ) #endif { pBreakable = BreakModelCreateSingle( pOwnerEntity, &breakModel, breakModel.offset, vecAngles, vecVelocity, vec3_origin/*params.angularVelocity*/, iSkin, params ); if ( !pBreakable ) { DevWarning( "PropBreakableCreateAll: Could not create model %s\n", breakModel.modelName ); } } if ( pBreakable ) { #ifdef GAME_DLL if ( GetGibManager() ) { GetGibManager()->AddGibToLRU( pBreakable->GetBaseAnimating() ); } #endif Vector vecBreakableObbSize = pBreakable->CollisionProp()->OBBSize(); // Try to align the gibs along the original axis matrix3x4_t matrix; AngleMatrix( vecAngles, matrix ); AlignBoxes( &matrix, vecObbSize, vecBreakableObbSize ); MatrixAngles( matrix, vecAngles ); if ( pBreakable->VPhysicsGetObject() ) { Vector pos; pBreakable->VPhysicsGetObject()->GetPosition( &pos, NULL ); pBreakable->VPhysicsGetObject()->SetPosition( pos, vecAngles, true ); } pBreakable->SetAbsAngles( vecAngles ); if ( pOwnerEntity->IsEffectActive( EF_NOSHADOW ) ) { pBreakable->AddEffects( EF_NOSHADOW ); } } } } } if ( params.connectingParticleNames.Count() > 0 && spawnedGibs.Count() > 1 ) { const int iGibCount = spawnedGibs.Count(); int iParticlesLeft = iGibCount / 2; int iEntIndex0 = RandomInt( 0, iGibCount - 1 ); while ( iParticlesLeft > 0 ) { iParticlesLeft--; const int iEntIndex1 = ( iEntIndex0 + RandomInt( 1, iGibCount - 1 ) ) % iGibCount; CBaseEntity *pEnt0 = spawnedGibs[ iEntIndex0 ]; CBaseEntity *pEnt1 = spawnedGibs[ iEntIndex1 ]; const int iParticleSystemIndex = RandomInt( 0, params.connectingParticleNames.Count() - 1 ); DispatchParticleEffect( params.connectingParticleNames[ iParticleSystemIndex ], pEnt0, pEnt1 ); iEntIndex0 = ( iEntIndex0 + RandomInt( 1, iGibCount - 1 ) ) % iGibCount; } } }
//================================================================= // Methods for DumpModelTEP // int DumpModelTEP::callback(INode *pnode) { Object* pobj; int fHasMat = TRUE; // clear physique export parameters m_mcExport = NULL; m_phyExport = NULL; m_phyMod = NULL; ASSERT_MBOX(!(pnode)->IsRootNode(), "Encountered a root node!"); if (::FNodeMarkedToSkip(pnode)) return TREE_CONTINUE; int iNode = ::GetIndexOfINode(pnode); TSTR strNodeName(pnode->GetName()); // The Footsteps node apparently MUST have a dummy mesh attached! Ignore it explicitly. if (FStrEq((char*)strNodeName, "Bip01 Footsteps")) return TREE_CONTINUE; // Helper nodes don't have meshes pobj = pnode->GetObjectRef(); if (pobj->SuperClassID() == HELPER_CLASS_ID) return TREE_CONTINUE; // The model's root is a child of the real "scene root" INode *pnodeParent = pnode->GetParentNode(); BOOL fNodeIsRoot = pnodeParent->IsRootNode( ); // Get node's material: should be a multi/sub (if it has a material at all) Mtl *pmtlNode = pnode->GetMtl(); if (pmtlNode == NULL) { return TREE_CONTINUE; fHasMat = FALSE; } else if (!(pmtlNode->ClassID() == Class_ID(MULTI_CLASS_ID, 0) && pmtlNode->IsMultiMtl())) { // sprintf(st_szDBG, "ERROR--Material on node %s isn't a Multi/Sub-Object", (char*)strNodeName); // ASSERT_AND_ABORT(FALSE, st_szDBG); fHasMat = FALSE; } // Get Node's object, convert to a triangle-mesh object, so I can access the Faces ObjectState os = pnode->EvalWorldState(m_tvToDump); pobj = os.obj; TriObject *ptriobj; BOOL fConvertedToTriObject = pobj->CanConvertToType(triObjectClassID) && (ptriobj = (TriObject*)pobj->ConvertToType(m_tvToDump, triObjectClassID)) != NULL; if (!fConvertedToTriObject) return TREE_CONTINUE; Mesh *pmesh = &ptriobj->mesh; // Shouldn't have gotten this far if it's a helper object if (pobj->SuperClassID() == HELPER_CLASS_ID) { sprintf(st_szDBG, "ERROR--Helper node %s has an attached mesh, and it shouldn't.", (char*)strNodeName); ASSERT_AND_ABORT(FALSE, st_szDBG); } // Ensure that the vertex normals are up-to-date pmesh->buildNormals(); // We want the vertex coordinates in World-space, not object-space Matrix3 mat3ObjectTM = pnode->GetObjectTM(m_tvToDump); // initialize physique export parameters m_phyMod = FindPhysiqueModifier(pnode); if (m_phyMod) { // Physique Modifier exists for given Node m_phyExport = (IPhysiqueExport *)m_phyMod->GetInterface(I_PHYINTERFACE); if (m_phyExport) { // create a ModContext Export Interface for the specific node of the Physique Modifier m_mcExport = (IPhyContextExport *)m_phyExport->GetContextInterface(pnode); if (m_mcExport) { // convert all vertices to Rigid m_mcExport->ConvertToRigid(TRUE); } } } // Dump the triangle face info int cFaces = pmesh->getNumFaces(); for (int iFace = 0; iFace < cFaces; iFace++) { Face* pface = &pmesh->faces[iFace]; TVFace* ptvface = &pmesh->tvFace[iFace]; DWORD smGroupFace = pface->getSmGroup(); // Get face's 3 indexes into the Mesh's vertex array(s). DWORD iVertex0 = pface->getVert(0); DWORD iVertex1 = pface->getVert(1); DWORD iVertex2 = pface->getVert(2); ASSERT_AND_ABORT((int)iVertex0 < pmesh->getNumVerts(), "Bogus Vertex 0 index"); ASSERT_AND_ABORT((int)iVertex1 < pmesh->getNumVerts(), "Bogus Vertex 1 index"); ASSERT_AND_ABORT((int)iVertex2 < pmesh->getNumVerts(), "Bogus Vertex 2 index"); // Get the 3 Vertex's for this face Point3 pt3Vertex0 = pmesh->getVert(iVertex0); Point3 pt3Vertex1 = pmesh->getVert(iVertex1); Point3 pt3Vertex2 = pmesh->getVert(iVertex2); // Get the 3 RVertex's for this face // NOTE: I'm using getRVertPtr instead of getRVert to work around a 3DSMax bug RVertex *prvertex0 = pmesh->getRVertPtr(iVertex0); RVertex *prvertex1 = pmesh->getRVertPtr(iVertex1); RVertex *prvertex2 = pmesh->getRVertPtr(iVertex2); // Find appropriate normals for each RVertex // A vertex can be part of multiple faces, so the "smoothing group" // is used to locate the normal for this face's use of the vertex. Point3 pt3Vertex0Normal; Point3 pt3Vertex1Normal; Point3 pt3Vertex2Normal; if (smGroupFace) { pt3Vertex0Normal = Pt3GetRVertexNormal(prvertex0, smGroupFace); pt3Vertex1Normal = Pt3GetRVertexNormal(prvertex1, smGroupFace); pt3Vertex2Normal = Pt3GetRVertexNormal(prvertex2, smGroupFace); } else { pt3Vertex0Normal = pmesh->getFaceNormal( iFace ); pt3Vertex1Normal = pmesh->getFaceNormal( iFace ); pt3Vertex2Normal = pmesh->getFaceNormal( iFace ); } ASSERT_AND_ABORT( Length( pt3Vertex0Normal ) <= 1.1, "bogus orig normal 0" ); ASSERT_AND_ABORT( Length( pt3Vertex1Normal ) <= 1.1, "bogus orig normal 1" ); ASSERT_AND_ABORT( Length( pt3Vertex2Normal ) <= 1.1, "bogus orig normal 2" ); // Get Face's sub-material from node's material, to get the bitmap name. // And no, there isn't a simpler way to get the bitmap name, you have to // dig down through all these levels. TCHAR szBitmapName[256] = "null.bmp"; if (fHasMat) { MtlID mtlidFace = pface->getMatID(); if (mtlidFace >= pmtlNode->NumSubMtls()) { sprintf(st_szDBG, "ERROR--Bogus sub-material index %d in node %s; highest valid index is %d", mtlidFace, (char*)strNodeName, pmtlNode->NumSubMtls()-1); // ASSERT_AND_ABORT(FALSE, st_szDBG); mtlidFace = 0; } Mtl *pmtlFace = pmtlNode->GetSubMtl(mtlidFace); ASSERT_AND_ABORT(pmtlFace != NULL, "NULL Sub-material returned"); if ((pmtlFace->ClassID() == Class_ID(MULTI_CLASS_ID, 0) && pmtlFace->IsMultiMtl())) { // it's a sub-sub material. Gads. pmtlFace = pmtlFace->GetSubMtl(mtlidFace); ASSERT_AND_ABORT(pmtlFace != NULL, "NULL Sub-material returned"); } if (!(pmtlFace->ClassID() == Class_ID(DMTL_CLASS_ID, 0))) { sprintf(st_szDBG, "ERROR--Sub-material with index %d (used in node %s) isn't a 'default/standard' material [%x].", mtlidFace, (char*)strNodeName, pmtlFace->ClassID()); ASSERT_AND_ABORT(FALSE, st_szDBG); } StdMat *pstdmtlFace = (StdMat*)pmtlFace; Texmap *ptexmap = pstdmtlFace->GetSubTexmap(ID_DI); // ASSERT_AND_ABORT(ptexmap != NULL, "NULL diffuse texture") if (ptexmap != NULL) { if (!(ptexmap->ClassID() == Class_ID(BMTEX_CLASS_ID, 0))) { sprintf(st_szDBG, "ERROR--Sub-material with index %d (used in node %s) doesn't have a bitmap as its diffuse texture.", mtlidFace, (char*)strNodeName); ASSERT_AND_ABORT(FALSE, st_szDBG); } BitmapTex *pbmptex = (BitmapTex*)ptexmap; strcpy(szBitmapName, pbmptex->GetMapName()); TSTR strPath, strFile; SplitPathFile(TSTR(szBitmapName), &strPath, &strFile); strcpy(szBitmapName,strFile); } } UVVert UVvertex0( 0, 0, 0 ); UVVert UVvertex1( 1, 0, 0 ); UVVert UVvertex2( 0, 1, 0 ); // All faces must have textures assigned to them if (pface->flags & HAS_TVERTS) { // Get TVface's 3 indexes into the Mesh's TVertex array(s). DWORD iTVertex0 = ptvface->getTVert(0); DWORD iTVertex1 = ptvface->getTVert(1); DWORD iTVertex2 = ptvface->getTVert(2); ASSERT_AND_ABORT((int)iTVertex0 < pmesh->getNumTVerts(), "Bogus TVertex 0 index"); ASSERT_AND_ABORT((int)iTVertex1 < pmesh->getNumTVerts(), "Bogus TVertex 1 index"); ASSERT_AND_ABORT((int)iTVertex2 < pmesh->getNumTVerts(), "Bogus TVertex 2 index"); // Get the 3 TVertex's for this TVFace // NOTE: I'm using getRVertPtr instead of getRVert to work around a 3DSMax bug UVvertex0 = pmesh->getTVert(iTVertex0); UVvertex1 = pmesh->getTVert(iTVertex1); UVvertex2 = pmesh->getTVert(iTVertex2); } else { //sprintf(st_szDBG, "ERROR--Node %s has a textureless face. All faces must have an applied texture.", (char*)strNodeName); //ASSERT_AND_ABORT(FALSE, st_szDBG); } /* const char *szExpectedExtension = ".bmp"; if (stricmp(szBitmapName+strlen(szBitmapName)-strlen(szExpectedExtension), szExpectedExtension) != 0) { sprintf(st_szDBG, "Node %s uses %s, which is not a %s file", (char*)strNodeName, szBitmapName, szExpectedExtension); ASSERT_AND_ABORT(FALSE, st_szDBG); } */ // Determine owning bones for the vertices. int iNodeV0, iNodeV1, iNodeV2; if (m_mcExport) { // The Physique add-in allows vertices to be assigned to bones arbitrarily iNodeV0 = InodeOfPhyVectex( iVertex0 ); iNodeV1 = InodeOfPhyVectex( iVertex1 ); iNodeV2 = InodeOfPhyVectex( iVertex2 ); } else { // Simple 3dsMax model: the vertices are owned by the object, and hence the node iNodeV0 = iNode; iNodeV1 = iNode; iNodeV2 = iNode; } // Rotate the face vertices out of object-space, and into world-space space Point3 v0 = pt3Vertex0 * mat3ObjectTM; Point3 v1 = pt3Vertex1 * mat3ObjectTM; Point3 v2 = pt3Vertex2 * mat3ObjectTM; Matrix3 mat3ObjectNTM = mat3ObjectTM; mat3ObjectNTM.NoScale( ); ASSERT_AND_ABORT( Length( pt3Vertex0Normal ) <= 1.1, "bogus pre normal 0" ); pt3Vertex0Normal = VectorTransform(mat3ObjectNTM, pt3Vertex0Normal); ASSERT_AND_ABORT( Length( pt3Vertex0Normal ) <= 1.1, "bogus post normal 0" ); ASSERT_AND_ABORT( Length( pt3Vertex1Normal ) <= 1.1, "bogus pre normal 1" ); pt3Vertex1Normal = VectorTransform(mat3ObjectNTM, pt3Vertex1Normal); ASSERT_AND_ABORT( Length( pt3Vertex1Normal ) <= 1.1, "bogus post normal 1" ); ASSERT_AND_ABORT( Length( pt3Vertex2Normal ) <= 1.1, "bogus pre normal 2" ); pt3Vertex2Normal = VectorTransform(mat3ObjectNTM, pt3Vertex2Normal); ASSERT_AND_ABORT( Length( pt3Vertex2Normal ) <= 1.1, "bogus post normal 2" ); // Finally dump the bitmap name and 3 lines of face info fprintf(m_pfile, "%s\n", szBitmapName); fprintf(m_pfile, "%3d %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f\n", iNodeV0, v0.x, v0.y, v0.z, pt3Vertex0Normal.x, pt3Vertex0Normal.y, pt3Vertex0Normal.z, UVvertex0.x, UVvertex0.y); fprintf(m_pfile, "%3d %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f\n", iNodeV1, v1.x, v1.y, v1.z, pt3Vertex1Normal.x, pt3Vertex1Normal.y, pt3Vertex1Normal.z, UVvertex1.x, UVvertex1.y); fprintf(m_pfile, "%3d %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f\n", iNodeV2, v2.x, v2.y, v2.z, pt3Vertex2Normal.x, pt3Vertex2Normal.y, pt3Vertex2Normal.z, UVvertex2.x, UVvertex2.y); } cleanup( ); return TREE_CONTINUE; }
void CPhysicsObject::LocalToWorld(Vector* worldPosition, const Vector& localPosition) const { matrix3x4_t matrix; GetPositionMatrix(&matrix); VectorTransform(Vector(localPosition), matrix, *worldPosition); }
//----------------------------------------------------------------------------- // Compute the bounding box's center, size, and basis //----------------------------------------------------------------------------- void ComputeRenderInfo( mstudiobbox_t *pHitBox, const matrix3x4_t &hitboxToWorld, Vector *pVecAbsOrigin, Vector *pXVec, Vector *pYVec ) { // Compute the center of the hitbox in worldspace Vector vecHitboxCenter; VectorAdd( pHitBox->bbmin, pHitBox->bbmax, vecHitboxCenter ); vecHitboxCenter *= 0.5f; VectorTransform( vecHitboxCenter, hitboxToWorld, *pVecAbsOrigin ); // Get the object's basis Vector vec[3]; MatrixGetColumn( hitboxToWorld, 0, vec[0] ); MatrixGetColumn( hitboxToWorld, 1, vec[1] ); MatrixGetColumn( hitboxToWorld, 2, vec[2] ); // vec[1] *= -1.0f; Vector vecViewDir; VectorSubtract( CurrentViewOrigin(), *pVecAbsOrigin, vecViewDir ); VectorNormalize( vecViewDir ); // Project the shadow casting direction into the space of the hitbox Vector localViewDir; localViewDir[0] = DotProduct( vec[0], vecViewDir ); localViewDir[1] = DotProduct( vec[1], vecViewDir ); localViewDir[2] = DotProduct( vec[2], vecViewDir ); // Figure out which vector has the largest component perpendicular // to the view direction... // Sort by how perpendicular it is int vecIdx[3]; SortAbsVectorComponents( localViewDir, vecIdx ); // Here's our hitbox basis vectors; namely the ones that are // most perpendicular to the view direction *pXVec = vec[vecIdx[0]]; *pYVec = vec[vecIdx[1]]; // Project them into a plane perpendicular to the view direction *pXVec -= vecViewDir * DotProduct( vecViewDir, *pXVec ); *pYVec -= vecViewDir * DotProduct( vecViewDir, *pYVec ); VectorNormalize( *pXVec ); VectorNormalize( *pYVec ); // Compute the hitbox size Vector boxSize; VectorSubtract( pHitBox->bbmax, pHitBox->bbmin, boxSize ); // We project the two longest sides into the vectors perpendicular // to the projection direction, then add in the projection of the perp direction Vector2D size( boxSize[vecIdx[0]], boxSize[vecIdx[1]] ); size.x *= fabs( DotProduct( vec[vecIdx[0]], *pXVec ) ); size.y *= fabs( DotProduct( vec[vecIdx[1]], *pYVec ) ); // Add the third component into x and y size.x += boxSize[vecIdx[2]] * fabs( DotProduct( vec[vecIdx[2]], *pXVec ) ); size.y += boxSize[vecIdx[2]] * fabs( DotProduct( vec[vecIdx[2]], *pYVec ) ); // Bloat a bit, since the shadow wants to extend outside the model a bit size *= 2.0f; // Clamp the minimum size Vector2DMax( size, Vector2D(10.0f, 10.0f), size ); // Factor the size into the xvec + yvec (*pXVec) *= size.x * 0.5f; (*pYVec) *= size.y * 0.5f; }
void CRagdollProp::InitRagdoll( const Vector &forceVector, int forceBone, const Vector &forcePos, matrix3x4_t *pPrevBones, matrix3x4_t *pBoneToWorld, float dt, int collisionGroup, bool activateRagdoll ) { SetCollisionGroup( collisionGroup ); // Make sure it's interactive debris for at most 5 seconds if ( collisionGroup == COLLISION_GROUP_INTERACTIVE_DEBRIS ) { SetContextThink( &CRagdollProp::SetDebrisThink, gpGlobals->curtime + 5, s_pDebrisContext ); } SetMoveType( MOVETYPE_VPHYSICS ); SetSolid( SOLID_VPHYSICS ); AddSolidFlags( FSOLID_CUSTOMRAYTEST | FSOLID_CUSTOMBOXTEST ); m_takedamage = DAMAGE_EVENTS_ONLY; ragdollparams_t params; params.pGameData = static_cast<void *>( static_cast<CBaseEntity *>(this) ); params.modelIndex = GetModelIndex(); params.pCollide = modelinfo->GetVCollide( params.modelIndex ); params.pStudioHdr = GetModelPtr(); params.forceVector = forceVector; params.forceBoneIndex = forceBone; params.forcePosition = forcePos; params.pPrevBones = pPrevBones; params.pCurrentBones = pBoneToWorld; params.boneDt = dt; params.jointFrictionScale = 1.0; RagdollCreate( m_ragdoll, params, physenv ); if ( m_anglesOverrideString != NULL_STRING && Q_strlen(m_anglesOverrideString.ToCStr()) > 0 ) { char szToken[2048]; const char *pStr = nexttoken(szToken, STRING(m_anglesOverrideString), ','); // anglesOverride is index,angles,index,angles (e.g. "1, 22.5 123.0 0.0, 2, 0 0 0, 3, 0 0 180.0") while ( szToken[0] != 0 ) { int objectIndex = atoi(szToken); // sanity check to make sure this token is an integer Assert( atof(szToken) == ((float)objectIndex) ); pStr = nexttoken(szToken, pStr, ','); Assert( szToken[0] ); if ( objectIndex >= m_ragdoll.listCount ) { Warning("Bad ragdoll pose in entity %s, model (%s) at %s, model changed?\n", GetDebugName(), GetModelName().ToCStr(), VecToString(GetAbsOrigin()) ); } else if ( szToken[0] != 0 ) { QAngle angles; Assert( objectIndex >= 0 && objectIndex < RAGDOLL_MAX_ELEMENTS ); UTIL_StringToVector( angles.Base(), szToken ); int boneIndex = m_ragdoll.boneIndex[objectIndex]; AngleMatrix( angles, pBoneToWorld[boneIndex] ); const ragdollelement_t &element = m_ragdoll.list[objectIndex]; Vector out; if ( element.parentIndex >= 0 ) { int parentBoneIndex = m_ragdoll.boneIndex[element.parentIndex]; VectorTransform( element.originParentSpace, pBoneToWorld[parentBoneIndex], out ); } else { out = GetAbsOrigin(); } MatrixSetColumn( out, 3, pBoneToWorld[boneIndex] ); element.pObject->SetPositionMatrix( pBoneToWorld[boneIndex], true ); } pStr = nexttoken(szToken, pStr, ','); } } if ( activateRagdoll ) { MEM_ALLOC_CREDIT(); RagdollActivate( m_ragdoll, params.pCollide, GetModelIndex() ); } for ( int i = 0; i < m_ragdoll.listCount; i++ ) { UpdateNetworkDataFromVPhysics( m_ragdoll.list[i].pObject, i ); g_pPhysSaveRestoreManager->AssociateModel( m_ragdoll.list[i].pObject, GetModelIndex() ); physcollision->CollideGetAABB( m_ragdollMins[i], m_ragdollMaxs[i], m_ragdoll.list[i].pObject->GetCollide(), vec3_origin, vec3_angle ); } VPhysicsSetObject( m_ragdoll.list[0].pObject ); CalcRagdollSize(); }
// Returns the derivative of PObj(), relative to the pixel. // TBD Point3 SContext::DPObj(void) { Point3 d = DP(); return VectorTransform(Inverse(tmAfterWSM),d); }
void FetchHitboxes(struct server_studio_api_s *pstudio, float (*bonetransform)[MAXSTUDIOBONES][3][4], struct model_s *pModel, float frame, int sequence, const vec3_t angles, const vec3_t origin, const byte *pcontroller, const byte *pblending, int iBone, const edict_t *pEdict) { /*pEngfuncs->Con_Printf( "FetchHitboxes(0x%08x): 0x%08x,0x%08x,0x%08x,%f,%i,(%f,%f,%f),(%f,%f,%f),0x%08x,0x%08x,%i,0x%08x --> %i\n", &FetchHitboxes, pstudio, bonetransform, pModel, frame, sequence, angles[0],angles[1],angles[2], origin[0],origin[1],origin[2], pcontroller, pblending, iBone, pEdict, g_engfuncs.pfnIndexOfEdict(pEdict) );*/ if(!draw_sv_hitboxes_enable->value) return; studiohdr_t *pstudiohdr = (studiohdr_t *)pstudio->Mod_Extradata(pModel); if(!pstudiohdr) { pEngfuncs->Con_Printf("Error: no model for pEdict (serialnumber=%i)\n",pEdict->serialnumber); return; } mstudiobbox_t *pbbox; vec3_t tmp; temp_box_t p; int i,j; pbbox = (mstudiobbox_t *)((byte *)pstudiohdr+ pstudiohdr->hitboxindex); temp_edictboxes_t & tempEdict = tempEdicts[g_engfuncs.pfnIndexOfEdict(pEdict)]; tempEdict.isFresh = true; tempEdict.tempBoxes.clear(); for (i = 0; i < pstudiohdr->numhitboxes; i++) { /* pEngfuncs->Con_Printf("((%f, %f, %f),(%f, %f, %f))\n", pbbox[i].bbmin[0], pbbox[i].bbmin[1], pbbox[i].bbmin[2], pbbox[i].bbmax[0], pbbox[i].bbmax[1], pbbox[i].bbmax[2] ); */ //get the vector positions of the 8 corners of the bounding box for (j = 0; j < 8; j++) { tmp[0] = (j & 1) ? pbbox[i].bbmin[0] : pbbox[i].bbmax[0]; tmp[1] = (j & 2) ? pbbox[i].bbmin[1] : pbbox[i].bbmax[1]; tmp[2] = (j & 4) ? pbbox[i].bbmin[2] : pbbox[i].bbmax[2]; VectorTransform( tmp, (*bonetransform)[pbbox[i].bone], p.data[j] ); } tempEdict.tempBoxes.push_back(p); } }
//----------------------------------------------------------------------------- // This is called by the base object when it's time to spawn the control panels //----------------------------------------------------------------------------- void CBaseViewModel::SpawnControlPanels() { #if defined( VGUI_CONTROL_PANELS ) char buf[64]; // Destroy existing panels DestroyControlPanels(); CBaseCombatWeapon *weapon = m_hWeapon.Get(); if ( weapon == NULL ) { return; } MDLCACHE_CRITICAL_SECTION(); // FIXME: Deal with dynamically resizing control panels? // If we're attached to an entity, spawn control panels on it instead of use CBaseAnimating *pEntityToSpawnOn = this; char *pOrgLL = "controlpanel%d_ll"; char *pOrgUR = "controlpanel%d_ur"; char *pAttachmentNameLL = pOrgLL; char *pAttachmentNameUR = pOrgUR; /* if ( IsBuiltOnAttachment() ) { pEntityToSpawnOn = dynamic_cast<CBaseAnimating*>((CBaseEntity*)m_hBuiltOnEntity.Get()); if ( pEntityToSpawnOn ) { char sBuildPointLL[64]; char sBuildPointUR[64]; Q_snprintf( sBuildPointLL, sizeof( sBuildPointLL ), "bp%d_controlpanel%%d_ll", m_iBuiltOnPoint ); Q_snprintf( sBuildPointUR, sizeof( sBuildPointUR ), "bp%d_controlpanel%%d_ur", m_iBuiltOnPoint ); pAttachmentNameLL = sBuildPointLL; pAttachmentNameUR = sBuildPointUR; } else { pEntityToSpawnOn = this; } } */ Assert( pEntityToSpawnOn ); // Lookup the attachment point... int nPanel; for ( nPanel = 0; true; ++nPanel ) { Q_snprintf( buf, sizeof( buf ), pAttachmentNameLL, nPanel ); int nLLAttachmentIndex = pEntityToSpawnOn->LookupAttachment(buf); if (nLLAttachmentIndex <= 0) { // Try and use my panels then pEntityToSpawnOn = this; Q_snprintf( buf, sizeof( buf ), pOrgLL, nPanel ); nLLAttachmentIndex = pEntityToSpawnOn->LookupAttachment(buf); if (nLLAttachmentIndex <= 0) return; } Q_snprintf( buf, sizeof( buf ), pAttachmentNameUR, nPanel ); int nURAttachmentIndex = pEntityToSpawnOn->LookupAttachment(buf); if (nURAttachmentIndex <= 0) { // Try and use my panels then Q_snprintf( buf, sizeof( buf ), pOrgUR, nPanel ); nURAttachmentIndex = pEntityToSpawnOn->LookupAttachment(buf); if (nURAttachmentIndex <= 0) return; } const char *pScreenName; weapon->GetControlPanelInfo( nPanel, pScreenName ); if (!pScreenName) continue; const char *pScreenClassname; weapon->GetControlPanelClassName( nPanel, pScreenClassname ); if ( !pScreenClassname ) continue; // Compute the screen size from the attachment points... matrix3x4_t panelToWorld; pEntityToSpawnOn->GetAttachment( nLLAttachmentIndex, panelToWorld ); matrix3x4_t worldToPanel; MatrixInvert( panelToWorld, worldToPanel ); // Now get the lower right position + transform into panel space Vector lr, lrlocal; pEntityToSpawnOn->GetAttachment( nURAttachmentIndex, panelToWorld ); MatrixGetColumn( panelToWorld, 3, lr ); VectorTransform( lr, worldToPanel, lrlocal ); float flWidth = lrlocal.x; float flHeight = lrlocal.y; CVGuiScreen *pScreen = CreateVGuiScreen( pScreenClassname, pScreenName, pEntityToSpawnOn, this, nLLAttachmentIndex ); pScreen->ChangeTeam( GetTeamNumber() ); pScreen->SetActualSize( flWidth, flHeight ); pScreen->SetActive( false ); pScreen->MakeVisibleOnlyToTeammates( false ); #ifdef INVASION_DLL pScreen->SetOverlayMaterial( SCREEN_OVERLAY_MATERIAL ); #endif pScreen->SetAttachedToViewModel( true ); int nScreen = m_hScreens.AddToTail( ); m_hScreens[nScreen].Set( pScreen ); } #endif }
void C_EnvProjectedTexture::UpdateLight( void ) { VPROF("C_EnvProjectedTexture::UpdateLight"); bool bVisible = true; Vector vLinearFloatLightColor( m_LightColor.r, m_LightColor.g, m_LightColor.b ); float flLinearFloatLightAlpha = m_LightColor.a; if ( m_bAlwaysUpdate ) { m_bForceUpdate = true; } if ( m_CurrentLinearFloatLightColor != vLinearFloatLightColor || m_flCurrentLinearFloatLightAlpha != flLinearFloatLightAlpha ) { float flColorTransitionSpeed = gpGlobals->frametime * m_flColorTransitionTime * 255.0f; m_CurrentLinearFloatLightColor.x = Approach( vLinearFloatLightColor.x, m_CurrentLinearFloatLightColor.x, flColorTransitionSpeed ); m_CurrentLinearFloatLightColor.y = Approach( vLinearFloatLightColor.y, m_CurrentLinearFloatLightColor.y, flColorTransitionSpeed ); m_CurrentLinearFloatLightColor.z = Approach( vLinearFloatLightColor.z, m_CurrentLinearFloatLightColor.z, flColorTransitionSpeed ); m_flCurrentLinearFloatLightAlpha = Approach( flLinearFloatLightAlpha, m_flCurrentLinearFloatLightAlpha, flColorTransitionSpeed ); m_bForceUpdate = true; } if ( !m_bForceUpdate ) { bVisible = IsBBoxVisible(); } if ( m_bState == false || !bVisible ) { // Spotlight's extents aren't in view ShutDownLightHandle(); return; } if ( m_LightHandle == CLIENTSHADOW_INVALID_HANDLE || m_hTargetEntity != NULL || m_bForceUpdate ) { Vector vForward, vRight, vUp, vPos = GetAbsOrigin(); FlashlightState_t state; if ( m_hTargetEntity != NULL ) { if ( m_bCameraSpace ) { const QAngle &angles = GetLocalAngles(); C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); if( pPlayer ) { const QAngle playerAngles = pPlayer->GetAbsAngles(); Vector vPlayerForward, vPlayerRight, vPlayerUp; AngleVectors( playerAngles, &vPlayerForward, &vPlayerRight, &vPlayerUp ); matrix3x4_t mRotMatrix; AngleMatrix( angles, mRotMatrix ); VectorITransform( vPlayerForward, mRotMatrix, vForward ); VectorITransform( vPlayerRight, mRotMatrix, vRight ); VectorITransform( vPlayerUp, mRotMatrix, vUp ); float dist = (m_hTargetEntity->GetAbsOrigin() - GetAbsOrigin()).Length(); vPos = m_hTargetEntity->GetAbsOrigin() - vForward*dist; VectorNormalize( vForward ); VectorNormalize( vRight ); VectorNormalize( vUp ); } } else { vForward = m_hTargetEntity->GetAbsOrigin() - GetAbsOrigin(); VectorNormalize( vForward ); // JasonM - unimplemented Assert (0); //Quaternion q = DirectionToOrientation( dir ); // // JasonM - set up vRight, vUp // // VectorNormalize( vRight ); // VectorNormalize( vUp ); } } else { AngleVectors( GetAbsAngles(), &vForward, &vRight, &vUp ); } state.m_fHorizontalFOVDegrees = m_flLightFOV; state.m_fVerticalFOVDegrees = m_flLightFOV; state.m_vecLightOrigin = vPos; BasisToQuaternion( vForward, vRight, vUp, state.m_quatOrientation ); state.m_NearZ = m_flNearZ; state.m_FarZ = m_flFarZ; // quickly check the proposed light's bbox against the view frustum to determine whether we // should bother to create it, if it doesn't exist, or cull it, if it does. if ( m_bSimpleProjection == false ) { #pragma message("OPTIMIZATION: this should be made SIMD") // get the half-widths of the near and far planes, // based on the FOV which is in degrees. Remember that // on planet Valve, x is forward, y left, and z up. const float tanHalfAngle = tan( m_flLightFOV * ( M_PI/180.0f ) * 0.5f ); const float halfWidthNear = tanHalfAngle * m_flNearZ; const float halfWidthFar = tanHalfAngle * m_flFarZ; // now we can build coordinates in local space: the near rectangle is eg // (0, -halfWidthNear, -halfWidthNear), (0, halfWidthNear, -halfWidthNear), // (0, halfWidthNear, halfWidthNear), (0, -halfWidthNear, halfWidthNear) VectorAligned vNearRect[4] = { VectorAligned( m_flNearZ, -halfWidthNear, -halfWidthNear), VectorAligned( m_flNearZ, halfWidthNear, -halfWidthNear), VectorAligned( m_flNearZ, halfWidthNear, halfWidthNear), VectorAligned( m_flNearZ, -halfWidthNear, halfWidthNear) }; VectorAligned vFarRect[4] = { VectorAligned( m_flFarZ, -halfWidthFar, -halfWidthFar), VectorAligned( m_flFarZ, halfWidthFar, -halfWidthFar), VectorAligned( m_flFarZ, halfWidthFar, halfWidthFar), VectorAligned( m_flFarZ, -halfWidthFar, halfWidthFar) }; matrix3x4_t matOrientation( vForward, -vRight, vUp, vPos ); enum { kNEAR = 0, kFAR = 1, }; VectorAligned vOutRects[2][4]; for ( int i = 0 ; i < 4 ; ++i ) { VectorTransform( vNearRect[i].Base(), matOrientation, vOutRects[0][i].Base() ); } for ( int i = 0 ; i < 4 ; ++i ) { VectorTransform( vFarRect[i].Base(), matOrientation, vOutRects[1][i].Base() ); } // now take the min and max extents for the bbox, and see if it is visible. Vector mins = **vOutRects; Vector maxs = **vOutRects; for ( int i = 1; i < 8 ; ++i ) { VectorMin( mins, *(*vOutRects+i), mins ); VectorMax( maxs, *(*vOutRects+i), maxs ); } #if 0 //for debugging the visibility frustum we just calculated NDebugOverlay::Triangle( vOutRects[0][0], vOutRects[0][1], vOutRects[0][2], 255, 0, 0, 100, true, 0.0f ); //first tri NDebugOverlay::Triangle( vOutRects[0][2], vOutRects[0][1], vOutRects[0][0], 255, 0, 0, 100, true, 0.0f ); //make it double sided NDebugOverlay::Triangle( vOutRects[0][2], vOutRects[0][3], vOutRects[0][0], 255, 0, 0, 100, true, 0.0f ); //second tri NDebugOverlay::Triangle( vOutRects[0][0], vOutRects[0][3], vOutRects[0][2], 255, 0, 0, 100, true, 0.0f ); //make it double sided NDebugOverlay::Triangle( vOutRects[1][0], vOutRects[1][1], vOutRects[1][2], 0, 0, 255, 100, true, 0.0f ); //first tri NDebugOverlay::Triangle( vOutRects[1][2], vOutRects[1][1], vOutRects[1][0], 0, 0, 255, 100, true, 0.0f ); //make it double sided NDebugOverlay::Triangle( vOutRects[1][2], vOutRects[1][3], vOutRects[1][0], 0, 0, 255, 100, true, 0.0f ); //second tri NDebugOverlay::Triangle( vOutRects[1][0], vOutRects[1][3], vOutRects[1][2], 0, 0, 255, 100, true, 0.0f ); //make it double sided NDebugOverlay::Box( vec3_origin, mins, maxs, 0, 255, 0, 100, 0.0f ); #endif bool bVisible = IsBBoxVisible( mins, maxs ); if (!bVisible) { // Spotlight's extents aren't in view if ( m_LightHandle != CLIENTSHADOW_INVALID_HANDLE ) { ShutDownLightHandle(); } return; } } float flAlpha = m_flCurrentLinearFloatLightAlpha * ( 1.0f / 255.0f ); state.m_fQuadraticAtten = 0.0; state.m_fLinearAtten = 100; state.m_fConstantAtten = 0.0f; state.m_FarZAtten = m_flFarZ; state.m_fBrightnessScale = m_flBrightnessScale; state.m_Color[0] = m_CurrentLinearFloatLightColor.x * ( 1.0f / 255.0f ) * flAlpha; state.m_Color[1] = m_CurrentLinearFloatLightColor.y * ( 1.0f / 255.0f ) * flAlpha; state.m_Color[2] = m_CurrentLinearFloatLightColor.z * ( 1.0f / 255.0f ) * flAlpha; state.m_Color[3] = 0.0f; // fixme: need to make ambient work m_flAmbient; state.m_flShadowSlopeScaleDepthBias = g_pMaterialSystemHardwareConfig->GetShadowSlopeScaleDepthBias(); state.m_flShadowDepthBias = g_pMaterialSystemHardwareConfig->GetShadowDepthBias(); state.m_bEnableShadows = m_bEnableShadows; state.m_pSpotlightTexture = m_SpotlightTexture; state.m_pProjectedMaterial = NULL; // only complain if we're using material projection state.m_nSpotlightTextureFrame = m_nSpotlightTextureFrame; state.m_flProjectionSize = m_flProjectionSize; state.m_flProjectionRotation = m_flRotation; state.m_nShadowQuality = m_nShadowQuality; // Allow entity to affect shadow quality if ( m_bSimpleProjection == true ) { state.m_bSimpleProjection = true; state.m_bOrtho = true; state.m_fOrthoLeft = -m_flProjectionSize; state.m_fOrthoTop = -m_flProjectionSize; state.m_fOrthoRight = m_flProjectionSize; state.m_fOrthoBottom = m_flProjectionSize; } if( m_LightHandle == CLIENTSHADOW_INVALID_HANDLE ) { // Hack: env projected textures don't work like normal flashlights; they're not assigned to a given splitscreen slot, // but the flashlight code requires this HACK_GETLOCALPLAYER_GUARD( "Env projected texture" ); if ( m_bSimpleProjection == true ) { m_LightHandle = g_pClientShadowMgr->CreateProjection( state ); } else { m_LightHandle = g_pClientShadowMgr->CreateFlashlight( state ); } if ( m_LightHandle != CLIENTSHADOW_INVALID_HANDLE ) { m_bForceUpdate = false; } } else { if ( m_bSimpleProjection == true ) { g_pClientShadowMgr->UpdateProjectionState( m_LightHandle, state ); } else { g_pClientShadowMgr->UpdateFlashlightState( m_LightHandle, state ); } m_bForceUpdate = false; } g_pClientShadowMgr->GetFrustumExtents( m_LightHandle, m_vecExtentsMin, m_vecExtentsMax ); m_vecExtentsMin = m_vecExtentsMin - GetAbsOrigin(); m_vecExtentsMax = m_vecExtentsMax - GetAbsOrigin(); } if( m_bLightOnlyTarget ) { g_pClientShadowMgr->SetFlashlightTarget( m_LightHandle, m_hTargetEntity ); } else { g_pClientShadowMgr->SetFlashlightTarget( m_LightHandle, NULL ); } g_pClientShadowMgr->SetFlashlightLightWorld( m_LightHandle, m_bLightWorld ); if ( !asw_perf_wtf.GetBool() && !m_bForceUpdate ) { g_pClientShadowMgr->UpdateProjectedTexture( m_LightHandle, true ); } }
void CParticleSystemQuery::GetRandomPointsOnControllingObjectHitBox( CParticleCollection *pParticles, int nControlPointNumber, int nNumPtsOut, float flBBoxScale, int nNumTrysToGetAPointInsideTheModel, Vector *pPntsOut, Vector vecDirectionalBias, Vector *pHitBoxRelativeCoordOut, int *pHitBoxIndexOut ) { bool bSucesss = false; #ifndef GAME_DLL EHANDLE *phMoveParent = reinterpret_cast<EHANDLE *> ( pParticles->m_ControlPoints[nControlPointNumber].m_pObject ); CBaseEntity *pMoveParent = NULL; if ( phMoveParent ) { pMoveParent = *( phMoveParent ); } if ( pMoveParent ) { float flRandMax = flBBoxScale; float flRandMin = 1.0 - flBBoxScale; Vector vecBasePos; pParticles->GetControlPointAtTime( nControlPointNumber, pParticles->m_flCurTime, &vecBasePos ); s_BoneMutex.Lock(); C_BaseAnimating *pAnimating = pMoveParent->GetBaseAnimating(); if ( pAnimating ) { matrix3x4_t *hitboxbones[MAXSTUDIOBONES]; if ( pAnimating->HitboxToWorldTransforms( hitboxbones ) ) { studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() ); if ( pStudioHdr ) { mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->GetHitboxSet() ); if ( set ) { bSucesss = true; Vector vecWorldPosition; float u = 0, v = 0, w = 0; int nHitbox = 0; int nNumIters = nNumTrysToGetAPointInsideTheModel; if (! vecDirectionalBias.IsZero( 0.0001 ) ) nNumIters = max( nNumIters, 5 ); for( int i=0 ; i < nNumPtsOut; i++) { int nTryCnt = nNumIters; float flBestPointGoodness = -1.0e20; do { int nTryHitbox = pParticles->RandomInt( 0, set->numhitboxes - 1 ); mstudiobbox_t *pBox = set->pHitbox(nTryHitbox); float flTryU = pParticles->RandomFloat( flRandMin, flRandMax ); float flTryV = pParticles->RandomFloat( flRandMin, flRandMax ); float flTryW = pParticles->RandomFloat( flRandMin, flRandMax ); Vector vecLocalPosition; vecLocalPosition.x = GetSurfaceCoord( flTryU, pBox->bbmin.x, pBox->bbmax.x ); vecLocalPosition.y = GetSurfaceCoord( flTryV, pBox->bbmin.y, pBox->bbmax.y ); vecLocalPosition.z = GetSurfaceCoord( flTryW, pBox->bbmin.z, pBox->bbmax.z ); Vector vecTryWorldPosition; VectorTransform( vecLocalPosition, *hitboxbones[pBox->bone], vecTryWorldPosition ); float flPointGoodness = pParticles->RandomFloat( 0, 72 ) + DotProduct( vecTryWorldPosition - vecBasePos, vecDirectionalBias ); if ( nNumTrysToGetAPointInsideTheModel ) { // do a point in solid test Ray_t ray; trace_t tr; ray.Init( vecTryWorldPosition, vecTryWorldPosition ); enginetrace->ClipRayToEntity( ray, MASK_ALL, pMoveParent, &tr ); if ( tr.startsolid ) flPointGoodness += 1000.; // got a point inside! } if ( flPointGoodness > flBestPointGoodness ) { u = flTryU; v = flTryV; w = flTryW; vecWorldPosition = vecTryWorldPosition; nHitbox = nTryHitbox; flBestPointGoodness = flPointGoodness; } } while ( nTryCnt-- ); *( pPntsOut++ ) = vecWorldPosition; if ( pHitBoxRelativeCoordOut ) ( pHitBoxRelativeCoordOut++ )->Init( u, v, w ); if ( pHitBoxIndexOut ) *( pHitBoxIndexOut++ ) = nHitbox; } } } } } if ( pMoveParent->IsBrushModel() ) { Vector vecMin; Vector vecMax; matrix3x4_t matOrientation; Vector VecOrigin; pMoveParent->GetRenderBounds( vecMin, vecMax ); VecOrigin = pMoveParent->GetRenderOrigin(); matOrientation = pMoveParent->EntityToWorldTransform(); Vector vecWorldPosition; float u = 0, v = 0, w = 0; int nHitbox = 0; int nNumIters = nNumTrysToGetAPointInsideTheModel; if (! vecDirectionalBias.IsZero( 0.0001 ) ) nNumIters = max( nNumIters, 5 ); for( int i=0 ; i < nNumPtsOut; i++) { int nTryCnt = nNumIters; float flBestPointGoodness = -1.0e20; do { float flTryU = pParticles->RandomFloat( flRandMin, flRandMax ); float flTryV = pParticles->RandomFloat( flRandMin, flRandMax ); float flTryW = pParticles->RandomFloat( flRandMin, flRandMax ); Vector vecLocalPosition; vecLocalPosition.x = GetSurfaceCoord( flTryU, vecMin.x, vecMax.x ); vecLocalPosition.y = GetSurfaceCoord( flTryV, vecMin.y, vecMax.y ); vecLocalPosition.z = GetSurfaceCoord( flTryW, vecMin.z, vecMax.z ); Vector vecTryWorldPosition; VectorTransform( vecLocalPosition, matOrientation, vecTryWorldPosition ); float flPointGoodness = pParticles->RandomFloat( 0, 72 ) + DotProduct( vecTryWorldPosition - vecBasePos, vecDirectionalBias ); if ( nNumTrysToGetAPointInsideTheModel ) { // do a point in solid test Ray_t ray; trace_t tr; ray.Init( vecTryWorldPosition, vecTryWorldPosition ); enginetrace->ClipRayToEntity( ray, MASK_ALL, pMoveParent, &tr ); if ( tr.startsolid ) flPointGoodness += 1000.; // got a point inside! } if ( flPointGoodness > flBestPointGoodness ) { u = flTryU; v = flTryV; w = flTryW; vecWorldPosition = vecTryWorldPosition; nHitbox = 0; flBestPointGoodness = flPointGoodness; } } while ( nTryCnt-- ); *( pPntsOut++ ) = vecWorldPosition; if ( pHitBoxRelativeCoordOut ) ( pHitBoxRelativeCoordOut++ )->Init( u, v, w ); if ( pHitBoxIndexOut ) *( pHitBoxIndexOut++ ) = nHitbox; } } s_BoneMutex.Unlock(); } #endif if (! bSucesss ) { // don't have a model or am in editor or something - fill return with control point for( int i=0 ; i < nNumPtsOut; i++) { pPntsOut[i] = pParticles->m_ControlPoints[nControlPointNumber].m_Position; // fallback if anything goes wrong if ( pHitBoxIndexOut ) pHitBoxIndexOut[i] = 0; if ( pHitBoxRelativeCoordOut ) pHitBoxRelativeCoordOut[i].Init(); } } }
void C_EnvProjectedTexture::UpdateLight(void) { VPROF_BUDGET("C_EnvProjectedTexture::UpdateLight", "Projected Textures"); if (CurrentViewID() == VIEW_SHADOW_DEPTH_TEXTURE /*|| CurrentViewID() == VIEW_SUN_SHAFTS*/) return; bool bVisible = true; if (m_bAlwaysUpdate) { m_bForceUpdate = true; } float fHighFOV; if (m_flLightFOV > m_flLightHorFOV) fHighFOV = m_flLightFOV; else fHighFOV = m_flLightHorFOV; if (m_bState == false || !IsWithinFarZ(fHighFOV) || !IsBBoxVisible()) { // Spotlight's extents aren't in view ShutDownLightHandle(); return; } else { bVisible = true; } Vector vLinearFloatLightColor(m_LightColor.r, m_LightColor.g, m_LightColor.b); float flLinearFloatLightAlpha = m_LightColor.a; if (m_CurrentLinearFloatLightColor != vLinearFloatLightColor || m_flCurrentLinearFloatLightAlpha != flLinearFloatLightAlpha) { float flColorTransitionSpeed = gpGlobals->frametime * m_flColorTransitionTime * 255.0f; m_CurrentLinearFloatLightColor.x = Approach(vLinearFloatLightColor.x, m_CurrentLinearFloatLightColor.x, flColorTransitionSpeed); m_CurrentLinearFloatLightColor.y = Approach(vLinearFloatLightColor.y, m_CurrentLinearFloatLightColor.y, flColorTransitionSpeed); m_CurrentLinearFloatLightColor.z = Approach(vLinearFloatLightColor.z, m_CurrentLinearFloatLightColor.z, flColorTransitionSpeed); m_flCurrentLinearFloatLightAlpha = Approach(flLinearFloatLightAlpha, m_flCurrentLinearFloatLightAlpha, flColorTransitionSpeed); m_bForceUpdate = true; } if (m_LightHandle == CLIENTSHADOW_INVALID_HANDLE || m_hTargetEntity != NULL || GetRootMoveParent() != NULL || m_bForceUpdate) { Vector vForward, vRight, vUp, vPos = GetAbsOrigin(); FlashlightState_t state; if (m_hTargetEntity != NULL) { if (m_bCameraSpace) { const QAngle &angles = GetLocalAngles(); C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); if (pPlayer) { const QAngle playerAngles = pPlayer->GetAbsAngles(); Vector vPlayerForward, vPlayerRight, vPlayerUp; AngleVectors(playerAngles, &vPlayerForward, &vPlayerRight, &vPlayerUp); matrix3x4_t mRotMatrix; AngleMatrix(angles, mRotMatrix); VectorITransform(vPlayerForward, mRotMatrix, vForward); VectorITransform(vPlayerRight, mRotMatrix, vRight); VectorITransform(vPlayerUp, mRotMatrix, vUp); float dist = (m_hTargetEntity->GetAbsOrigin() - GetAbsOrigin()).Length(); vPos = m_hTargetEntity->GetAbsOrigin() - vForward*dist; VectorNormalize(vForward); VectorNormalize(vRight); VectorNormalize(vUp); } } else { Vector vecToTarget = m_hTargetEntity->GetAbsOrigin() - GetAbsOrigin(); QAngle vecAngles; VectorAngles(vecToTarget, vecAngles); AngleVectors(vecAngles, &vForward, &vRight, &vUp); } } else { AngleVectors(GetAbsAngles(), &vForward, &vRight, &vUp); } state.m_fHorizontalFOVDegrees = abs(m_flLightHorFOV); state.m_fVerticalFOVDegrees = abs(m_flLightFOV); state.m_vecLightOrigin = vPos; BasisToQuaternion(vForward, vRight, vUp, state.m_quatOrientation); state.m_NearZ = m_flNearZ; state.m_FarZ = m_flFarZ; // quickly check the proposed light's bbox against the view frustum to determine whether we // should bother to create it, if it doesn't exist, or cull it, if it does. // get the half-widths of the near and far planes, // based on the FOV which is in degrees. Remember that // on planet Valve, x is forward, y left, and z up. const float tanHalfAngle = tan(fHighFOV * (M_PI / 180.0f) * 0.5f); const float halfWidthNear = tanHalfAngle * m_flNearZ; const float halfWidthFar = tanHalfAngle * m_flFarZ; // now we can build coordinates in local space: the near rectangle is eg // (0, -halfWidthNear, -halfWidthNear), (0, halfWidthNear, -halfWidthNear), // (0, halfWidthNear, halfWidthNear), (0, -halfWidthNear, halfWidthNear) VectorAligned vNearRect[4] = { VectorAligned(m_flNearZ, -halfWidthNear, -halfWidthNear), VectorAligned(m_flNearZ, halfWidthNear, -halfWidthNear), VectorAligned(m_flNearZ, halfWidthNear, halfWidthNear), VectorAligned(m_flNearZ, -halfWidthNear, halfWidthNear) }; VectorAligned vFarRect[4] = { VectorAligned(m_flFarZ, -halfWidthFar, -halfWidthFar), VectorAligned(m_flFarZ, halfWidthFar, -halfWidthFar), VectorAligned(m_flFarZ, halfWidthFar, halfWidthFar), VectorAligned(m_flFarZ, -halfWidthFar, halfWidthFar) }; matrix3x4_t matOrientation(vForward, -vRight, vUp, vPos); enum { kNEAR = 0, kFAR = 1, }; VectorAligned vOutRects[2][4]; for (int i = 0; i < 4; ++i) { VectorTransform(vNearRect[i].Base(), matOrientation, vOutRects[0][i].Base()); } for (int i = 0; i < 4; ++i) { VectorTransform(vFarRect[i].Base(), matOrientation, vOutRects[1][i].Base()); } // now take the min and max extents for the bbox, and see if it is visible. Vector mins = **vOutRects; Vector maxs = **vOutRects; for (int i = 1; i < 8; ++i) { VectorMin(mins, *(*vOutRects + i), mins); VectorMax(maxs, *(*vOutRects + i), maxs); } #if 0 //for debugging the visibility frustum we just calculated NDebugOverlay::Triangle(vOutRects[0][0], vOutRects[0][1], vOutRects[0][2], 255, 0, 0, 100, true, 0.0f); //first tri NDebugOverlay::Triangle(vOutRects[0][2], vOutRects[0][1], vOutRects[0][0], 255, 0, 0, 100, true, 0.0f); //make it double sided NDebugOverlay::Triangle(vOutRects[0][2], vOutRects[0][3], vOutRects[0][0], 255, 0, 0, 100, true, 0.0f); //second tri NDebugOverlay::Triangle(vOutRects[0][0], vOutRects[0][3], vOutRects[0][2], 255, 0, 0, 100, true, 0.0f); //make it double sided NDebugOverlay::Triangle(vOutRects[1][0], vOutRects[1][1], vOutRects[1][2], 0, 0, 255, 100, true, 0.0f); //first tri NDebugOverlay::Triangle(vOutRects[1][2], vOutRects[1][1], vOutRects[1][0], 0, 0, 255, 100, true, 0.0f); //make it double sided NDebugOverlay::Triangle(vOutRects[1][2], vOutRects[1][3], vOutRects[1][0], 0, 0, 255, 100, true, 0.0f); //second tri NDebugOverlay::Triangle(vOutRects[1][0], vOutRects[1][3], vOutRects[1][2], 0, 0, 255, 100, true, 0.0f); //make it double sided NDebugOverlay::Box(vec3_origin, mins, maxs, 0, 255, 0, 100, 0.0f); #endif bool bVisible = IsBBoxVisible(mins, maxs); if (!bVisible) { // Spotlight's extents aren't in view if (m_LightHandle != CLIENTSHADOW_INVALID_HANDLE) { ShutDownLightHandle(); } return; } float flAlpha = m_flCurrentLinearFloatLightAlpha * (1.0f / 255.0f); state.m_fQuadraticAtten = m_flQuadratic; state.m_fLinearAtten = 100; if (m_bAtten) { state.m_fConstantAtten = 0.0f; } else { state.m_fConstantAtten = 1.0f; } state.m_Color[0] = (m_CurrentLinearFloatLightColor.x * (1.0f / 255.0f) * flAlpha) * m_fBrightness; state.m_Color[1] = (m_CurrentLinearFloatLightColor.y * (1.0f / 255.0f) * flAlpha) * m_fBrightness; state.m_Color[2] = (m_CurrentLinearFloatLightColor.z * (1.0f / 255.0f) * flAlpha) * m_fBrightness; state.m_Color[3] = m_flAmbient; state.m_flShadowSlopeScaleDepthBias = mat_slopescaledepthbias_shadowmap.GetFloat(); state.m_flShadowDepthBias = mat_depthbias_shadowmap.GetFloat(); if (m_bEnableShadows && r_flashlightdepthtexture.GetBool() && m_bClientWantsShadows) { state.m_bEnableShadows = true; } else { state.m_bEnableShadows = false; } state.m_pSpotlightTexture = m_SpotlightTexture; state.m_nSpotlightTextureFrame = m_nSpotlightTextureFrame; if (r_dynamicshadows_use_c17_improvements.GetBool()) { //state.m_flShadowFilterSize = m_flBlur; if (r_flashlightdepthres.GetInt() == 512) { state.m_flShadowFilterSize = 0.8f; } else if (r_flashlightdepthres.GetInt() == 1024) { state.m_flShadowFilterSize = 0.3f; } else if (r_flashlightdepthres.GetInt() == 2048) { state.m_flShadowFilterSize = 0.2f; } else if (r_flashlightdepthres.GetInt() == 4096) { state.m_flShadowFilterSize = 0.08f; } else { state.m_flShadowFilterSize = 1.0f; } state.m_flShadowAtten = m_flAtten; } else { state.m_flShadowFilterSize = 3.0f; state.m_flShadowAtten = 0.35f; } state.m_nShadowQuality = m_nShadowQuality; // Allow entity to affect shadow quality if (m_LightHandle == CLIENTSHADOW_INVALID_HANDLE) { // Hack: env projected textures don't work like normal flashlights; they're not assigned to a given splitscreen slot, // but the flashlight code requires this m_LightHandle = g_pClientShadowMgr->CreateFlashlight(state); if (m_LightHandle != CLIENTSHADOW_INVALID_HANDLE) { m_bForceUpdate = false; } } else { g_pClientShadowMgr->UpdateFlashlightState(m_LightHandle, state); m_bForceUpdate = false; } g_pClientShadowMgr->GetFrustumExtents(m_LightHandle, m_vecExtentsMin, m_vecExtentsMax); m_vecExtentsMin = m_vecExtentsMin - GetAbsOrigin(); m_vecExtentsMax = m_vecExtentsMax - GetAbsOrigin(); } if (m_bLightOnlyTarget) { g_pClientShadowMgr->SetFlashlightTarget(m_LightHandle, m_hTargetEntity); } else { g_pClientShadowMgr->SetFlashlightTarget(m_LightHandle, NULL); } g_pClientShadowMgr->SetFlashlightLightWorld(m_LightHandle, m_bLightWorld); if (!m_bForceUpdate) { g_pClientShadowMgr->UpdateProjectedTexture(m_LightHandle, true); } }
//tm the mirror tm void CopyBuffer::PasteToBuffer(MorphByBone *mod, MorphByBoneData *targ, Matrix3 mirrorTM, float threshold, BOOL flipTM) { if (copyData == NULL) return; if (copyData->morphTargets.Count() == 0) return; if (targ == NULL) return; //delete any existing morphs for (int i = 0; i < targ->morphTargets.Count(); i++) delete targ->morphTargets[i]; targ->morphTargets.ZeroCount(); int realCount= 0; for (int i = 0; i < copyData->morphTargets.Count(); i++) { if (!copyData->morphTargets[i]->IsDead()) realCount++; } targ->morphTargets.SetCount(realCount); for (int i = 0; i < mod->localDataList.Count(); i++) { MorphByBoneLocalData *ld = mod->localDataList[i]; if (ld) { ld->tempPoints = ld->preDeform; ld->tempMatchList.SetCount(ld->tempPoints.Count()); for (int j = 0; j < ld->preDeform.Count(); j++) { Matrix3 tm(1); //need to put our original points ld->tempPoints[j] = ld->tempPoints[j] * mirrorTM; ld->tempMatchList[j] = -1; } } } //now find closest pairs for (int i = 0; i < mod->localDataList.Count(); i++) { MorphByBoneLocalData *ld = mod->localDataList[i]; if (ld) { for (int j = 0; j < ld->tempPoints.Count(); j++) { Point3 sourcePoint = ld->preDeform[j]; float closest = 3.4e+38; int closestID = -1; for (int k = 0; k < ld->tempPoints.Count(); k++) { Point3 mirrorPoint = ld->tempPoints[k]; float dist = Length(sourcePoint-mirrorPoint); if ((dist < threshold) && (dist < closest)) { closest = dist; closestID = k; } } if (closestID != -1) ld->tempMatchList[closestID] = j; } } } //create a blank set of morphs int currentMorph = 0; for (int i = 0; i < copyData->morphTargets.Count(); i++) { if (!copyData->morphTargets[i]->IsDead()) { targ->morphTargets[currentMorph] = new MorphTargets(); int currentVert=0; for (int j = 0; j < mod->localDataList.Count(); j++) { targ->morphTargets[currentMorph]->d.SetCount(mod->localDataList[j]->preDeform.Count()); for (int k =0; k < mod->localDataList[j]->preDeform.Count(); k++) { targ->morphTargets[currentMorph]->d[currentVert].vertexID = k; targ->morphTargets[currentMorph]->d[currentVert].vec = Point3(0.0f,0.0f,0.0f); targ->morphTargets[currentMorph]->d[currentVert].vecParentSpace = Point3(0.0f,0.0f,0.0f); targ->morphTargets[currentMorph]->d[currentVert].originalPt = mod->localDataList[j]->preDeform[k];//*tm; targ->morphTargets[currentMorph]->d[currentVert].localOwner = j; currentVert++; } } currentMorph++; } } //this only works if it is not instanced //loop through morphs currentMorph = 0; for (int i = 0; i < copyData->morphTargets.Count(); i++) { if (!copyData->morphTargets[i]->IsDead()) { //loop through points for (int j = 0; j <targ->morphTargets[currentMorph]->d.Count(); j++) { //get the mirror index if there is one int ldIndex = targ->morphTargets[currentMorph]->d[j].localOwner; MorphByBoneLocalData *ld = mod->localDataList[ldIndex]; Matrix3 boneTM = copyData->currentBoneNodeTM; Matrix3 parentTM = copyData->parentBoneNodeCurrentTM; Matrix3 mirror = Inverse(ld->selfNodeTM) * mirrorTM * ld->selfNodeTM; Matrix3 mirrorBoneTM = targ->currentBoneNodeTM; Matrix3 mirrorParentTM = targ->parentBoneNodeCurrentTM; Matrix3 lTM, pTM; lTM = boneTM * mirror * Inverse(mirrorBoneTM); pTM = parentTM * mirror * Inverse(mirrorParentTM); if (ld) { int mirrorID = targ->morphTargets[currentMorph]->d[j].vertexID; int sourceID = ld->tempMatchList[mirrorID]; //now look though our list and swap the 2 if (sourceID != -1) { ////transform the vec into local space, flip them, then back into bone space // targ->morphTargets[i]->d[j].vec = VectorTransform(copyData->morphTargts[i]->d[sourceID].vec,mirrorTM); if (1)//(flipTM) { Point3 vec = copyData->morphTargets[i]->d[sourceID].vec; // in local bone space targ->morphTargets[currentMorph]->d[j].vec = VectorTransform(lTM,vec); vec = copyData->morphTargets[i]->d[sourceID].vecParentSpace; // in local bone space targ->morphTargets[currentMorph]->d[j].vecParentSpace = VectorTransform(pTM,vec); //current bone tm //current parent tm //invserse of the self //mirror //self tm //inverse of mirror bone //inverse of mirror parent bone } else { targ->morphTargets[currentMorph]->d[j].vec = copyData->morphTargets[i]->d[sourceID].vec; targ->morphTargets[currentMorph]->d[j].vecParentSpace = copyData->morphTargets[i]->d[sourceID].vecParentSpace; } // Point3 pvec = copyData->morphTargets[i]->d[sourceID].vecParentSpace; // Matrix3 selfTM = ld->selfNodeTM; // Matrix3 parentTM = copyData->parentBoneNodeCurrentTM; // Matrix3 tm = parentTM * Inverse(selfTM) * mirrorTM * selfTM * Inverse(parentTM); // pvec = VectorTransform(tm,pvec); //do we need to flip the vecs? targ->morphTargets[currentMorph]->d[j].originalPt = copyData->morphTargets[i]->d[sourceID].originalPt * mirrorTM; } } } //resolve tms if (flipTM) { MorphByBoneLocalData *ld = mod->localDataList[0]; Matrix3 mirror = Inverse(ld->selfNodeTM) * mirrorTM * ld->selfNodeTM; //mirror the initial copy node tm Matrix3 copyTM = copyData->currentBoneNodeTM; copyTM *= mirror; copyTM.SetRow(3,targ->currentBoneNodeTM.GetRow(3)); // targ->morphTargets[currentMorph]->boneTMInParentSpace = copyTM * ; //put our current targ node tm into the copyTM space Matrix3 targTM = targ->currentBoneNodeTM; targTM *= Inverse(copyTM); //put the morph tm in worldspace Matrix3 morphTM = copyData->morphTargets[i]->boneTMInParentSpace * copyData->parentBoneNodeCurrentTM; //mirror it // morphTM *= mirror; // morphTM.SetRow(3,targ->currentBoneNodeTM.GetRow(3)); //now animate it back to world using the morph target tm targTM *= morphTM; //jam it back into our parent space targTM *= Inverse(targ->currentBoneNodeTM); targ->morphTargets[currentMorph]->boneTMInParentSpace = targTM; } else targ->morphTargets[currentMorph]->boneTMInParentSpace = copyData->morphTargets[i]->boneTMInParentSpace; //puts it in world space /* morphTM = copyData->morphTargets[i]->boneTMInParentSpace * copyData->parentBoneNodeCurrentTM; morphTM.SetRow(3,targ->currentBoneNodeTM.GetRow(3)); morphTM = morphTM * mirror; morphTM = morphTM * Inverse(targ->parentBoneNodeCurrentTM); targ->morphTargets[currentMorph]->boneTMInParentSpace = morphTM; */ /* //mirror all the morph tms MorphByBoneLocalData *ld = mod->localDataList[0]; Matrix3 mirror = Inverse(ld->selfNodeTM) * mirrorTM * ld->selfNodeTM; Matrix3 ptm = copyData->parentBoneNodeCurrentTM; Matrix3 mtm = copyData->morphTargets[i]->boneTMInParentSpace; Matrix3 morphWorldSpaceTM = mtm * ptm *mirror; morphWorldSpaceTM.SetRow(3,targ->currentBoneNodeTM.GetRow(3)); //link the target bone initial to the mirrored initial copy node tm //remcompute the mirror tms //but pack into our targ space if (flipTM) { MorphByBoneLocalData *ld = mod->localDataList[0]; Matrix3 mirror = Inverse(ld->selfNodeTM) * mirrorTM * ld->selfNodeTM; //transform the tm into local space //flip it thenback in parent space Matrix3 mtm = copyData->morphTargets[i]->boneTMInParentSpace; mtm = mtm * copyData->parentBoneNodeCurrentTM; //this puts in world space Point3 x,y,z; x = VectorTransform(mirror,mtm.GetRow(0)); y = VectorTransform(mirror,mtm.GetRow(1)); z = VectorTransform(mirror,mtm.GetRow(2)); mtm.SetRow(0,x); mtm.SetRow(1,y); mtm.SetRow(2,z); mtm = mtm * Inverse(copyData->parentBoneNodeCurrentTM); mtm.SetRow(3,copyData->morphTargets[i]->boneTMInParentSpace.GetRow(3)); //put in world space, then by the mirror then back into parent targ->morphTargets[currentMorph]->boneTMInParentSpace = copyData->morphTargets[i]->boneTMInParentSpace; } else targ->morphTargets[currentMorph]->boneTMInParentSpace = copyData->morphTargets[i]->boneTMInParentSpace; */ targ->morphTargets[currentMorph]->influenceAngle = copyData->morphTargets[i]->influenceAngle; targ->morphTargets[currentMorph]->falloff = copyData->morphTargets[i]->falloff; targ->morphTargets[currentMorph]->name = copyData->morphTargets[i]->name; targ->morphTargets[currentMorph]->treeHWND = NULL; targ->morphTargets[currentMorph]->weight = copyData->morphTargets[i]->weight; targ->morphTargets[currentMorph]->flags = copyData->morphTargets[i]->flags; currentMorph++; } } //clean up temp data for (int i = 0; i < mod->localDataList.Count(); i++) { MorphByBoneLocalData *ld = mod->localDataList[i]; if (ld) { ld->tempPoints.Resize(0); ld->tempMatchList.Resize(0); } } }
BOOL TrackMouseCallBack::point_on_obj(ViewExp& vpt, IPoint2 m, Point3& pt, Point3 &norm) { if ( ! vpt.IsAlive() ) { // why are we here DbgAssert(!_T("Invalid viewport!")); return FALSE; } // computes the normal ray at the point of intersection Ray ray, world_ray; float at, best_dist = 0.0f; TimeValue t = MAXScript_time(); Object *obj = NULL; Matrix3 obtm, iobtm; Point3 testNorm; BOOL found_hit = FALSE; vl->face_num_val = vl->face_bary = &undefined; hit_node = NULL; // Calculate a ray from the mouse point vpt.MapScreenToWorldRay(float(m.x), float(m.y), world_ray); for( int i=(nodeTab.Count()-1); i>=0; i-- ) { // Get the object from the node INode* node = nodeTab[i]; ObjectState os = node->EvalWorldState(t); obj = os.obj; // Back transform the ray into object space. obtm = node->GetObjectTM(t); iobtm = Inverse(obtm); ray.p = iobtm * world_ray.p; ray.dir = VectorTransform(iobtm, world_ray.dir); // See if we hit the object if (obj->IsSubClassOf(triObjectClassID)) { TriObject* tobj = (TriObject*)obj; DWORD fi; Point3 bary; if (tobj->mesh.IntersectRay(ray, at, testNorm, fi, bary) && ((!found_hit) || (at<=best_dist)) ) { // Calculate the hit point and transform everything back into world space. // record the face index and bary coord best_dist = at; pt = ray.p + ray.dir * at; pt = pt * obtm; norm = Normalize(VectorTransform(obtm, testNorm)); vl->face_num_val = Integer::intern(fi + 1); vl->face_bary = new Point3Value(bary); hit_node = node; found_hit = TRUE; } } else if (obj->IntersectRay(t, ray, at, testNorm) && ((!found_hit) || (at<=best_dist)) ) { // Calculate the hit point and transform everything back into world space. best_dist = at; pt = ray.p + ray.dir * at; pt = pt * obtm; norm = Normalize(VectorTransform(obtm, testNorm)); hit_node = node; found_hit = TRUE; } } if( found_hit ) return TRUE; // Failed to find a hit on any node, look at the Normal Align Vector for the first node if ((obj!=NULL) && obj->NormalAlignVector(t, pt, testNorm)) // See if a default NA vector is provided { pt = pt * obtm; norm = Normalize(VectorTransform(obtm, testNorm)); return TRUE; } else return FALSE; }
//----------------------------------------------------------------------------- // Draws the mesh //----------------------------------------------------------------------------- void CDmeMDL::Draw( const matrix3x4_t &shapeToWorld, CDmeDrawSettings *pDrawSettings /* = NULL */ ) { if ( !g_pMaterialSystem || !g_pMDLCache || !g_pStudioRender ) return; if ( m_MDLHandle == MDLHANDLE_INVALID ) return; // Color + alpha modulation Vector white( m_Color.r() / 255.0f, m_Color.g() / 255.0f, m_Color.b() / 255.0f ); g_pStudioRender->SetColorModulation( white.Base() ); g_pStudioRender->SetAlphaModulation( m_Color.a() / 255.0f ); DrawModelInfo_t info; info.m_pStudioHdr = g_pMDLCache->GetStudioHdr( m_MDLHandle ); info.m_pHardwareData = g_pMDLCache->GetHardwareData( m_MDLHandle ); info.m_Decals = STUDIORENDER_DECAL_INVALID; info.m_Skin = m_nSkin; info.m_Body = m_nBody; info.m_HitboxSet = 0; info.m_pClientEntity = NULL; info.m_pColorMeshes = NULL; info.m_bStaticLighting = false; info.m_Lod = m_nLOD; // FIXME: Deal with lighting for ( int i = 0; i < 6; ++ i ) { info.m_vecAmbientCube[i].Init( 1, 1, 1 ); } info.m_nLocalLightCount = 0; // info.m_LocalLightDescs; matrix3x4_t *pBoneToWorld = g_pStudioRender->LockBoneMatrices( info.m_pStudioHdr->numbones ); SetUpBones( shapeToWorld, info.m_pStudioHdr->numbones, pBoneToWorld ); g_pStudioRender->UnlockBoneMatrices(); Vector vecWorldViewTarget; if ( m_bWorldSpaceViewTarget ) { vecWorldViewTarget = m_vecViewTarget; } else { VectorTransform( m_vecViewTarget, shapeToWorld, vecWorldViewTarget ); } g_pStudioRender->SetEyeViewTarget( info.m_pStudioHdr, info.m_Body, vecWorldViewTarget ); // FIXME: Why is this necessary!?!?!? CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); if ( !m_bDrawInEngine ) { pRenderContext->CullMode(MATERIAL_CULLMODE_CCW); } // Set default flex values float *pFlexWeights = NULL; const int nFlexDescCount = info.m_pStudioHdr->numflexdesc; if ( nFlexDescCount ) { CStudioHdr cStudioHdr( info.m_pStudioHdr, g_pMDLCache ); float flexDefaults[ MAXSTUDIOFLEXCTRL * 4 ]; memset( flexDefaults, 0, MAXSTUDIOFLEXCTRL * 4 * sizeof( float ) ); g_pStudioRender->LockFlexWeights( info.m_pStudioHdr->numflexdesc, &pFlexWeights ); cStudioHdr.RunFlexRules( flexDefaults, pFlexWeights ); g_pStudioRender->UnlockFlexWeights(); } Vector vecModelOrigin; MatrixGetColumn( shapeToWorld, 3, vecModelOrigin ); g_pStudioRender->DrawModel( NULL, info, pBoneToWorld, pFlexWeights, NULL, vecModelOrigin, STUDIORENDER_DRAW_ENTIRE_MODEL ); // FIXME: Why is this necessary!?!?!? if ( !m_bDrawInEngine ) { pRenderContext->CullMode( MATERIAL_CULLMODE_CW ); } }
//----------------------------------------------------------------------------- // 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; } } } } } } } }