/* ** All the three given vectors span only a 2D space, and this finds ** the normal to that plane. Simply sums up all the pair-wise ** cross-products to get a good estimate. Trick is getting the cross ** products to line up before summing. */ void nullspace1(double ret[3], const double r0[3], const double r1[3], const double r2[3]) { double crs[3]; /* ret = r0 x r1 */ VEC_CROSS(ret, r0, r1); /* crs = r1 x r2 */ VEC_CROSS(crs, r1, r2); /* ret += crs or ret -= crs; whichever makes ret longer */ if (VEC_DOT(ret, crs) > 0) { VEC_ADD(ret, crs); } else { VEC_SUB(ret, crs); } /* crs = r0 x r2 */ VEC_CROSS(crs, r0, r2); /* ret += crs or ret -= crs; whichever makes ret longer */ if (VEC_DOT(ret, crs) > 0) { VEC_ADD(ret, crs); } else { VEC_SUB(ret, crs); } return; }
BOOL hit_geo_sphere (GEO *Generic, RAY *Ray, HIT *Hit, PAIR *Bound, void *Info) { GEO_SPHERE *Geo; VECTOR Point; REAL a, b, Distance, Delta; Geo = (GEO_SPHERE *) Generic; VEC_SUB (Point, Ray->Point, Geo->Point); a = - VEC_DOT (Point, Ray->Vector); b = VEC_DOT (Point, Point); Delta = a * a - b + Geo->Radius * Geo->Radius; if (Delta < 0.0) return (FALSE); Delta = sqrt (Delta); Distance = a - Delta; /* - Epsilon;*/ if (Distance < Bound->u || Distance > Bound->v) return (FALSE); if (Hit) { Ray->Distance = Distance; VEC_LIN (Point, Ray->Point, Distance, Ray->Vector); VEC_SUB (Hit->Normal, Point, Geo->Point); if (VEC_DOT (Ray->Vector, Hit->Normal) > 0.0) VEC_NEG (Hit->Normal); VEC_UNIT (Hit->Normal, Distance); VEC_LIN (Hit->Point, Point, Epsilon, Hit->Normal); xyz2uv_geo_sphere (Geo, Hit); } return (TRUE); }
BOOL IsPolyInsideSurface(CTempSurface *pSurface, CPrePoly *pPoly) { DWORD i, j; CEditPoly *pEditPoly; CPrePlane edgePlane; PVector vTemp, testPt; pEditPoly = pSurface->m_pPoly; for(i=0; i < pEditPoly->NumVerts(); i++) { VEC_SUB(vTemp, pEditPoly->NextPt(i), pEditPoly->Pt(i)); VEC_CROSS(edgePlane.m_Normal, vTemp, pEditPoly->Normal()); edgePlane.m_Normal.Norm(); edgePlane.m_Dist = VEC_DOT(edgePlane.m_Normal, pEditPoly->Pt(i)); for(j=0; j < pPoly->NumVerts(); j++) { testPt = pPoly->Pt(j); if(DIST_TO_PLANE(testPt, edgePlane) < -0.1f) { return FALSE; } } } return TRUE; }
DBOOL BounceMovingObject(PhysicsState *pUserState, MovingObject *pObject, DVector *pNewPos, ClientIntersectInfo* pInfo, SurfaceType *eType) { if (!pObject || !pNewPos || !pInfo) return DFALSE; PhysicsState* pState = pUserState ? pUserState : GetCurPhysicsState(pObject); if (!pState) return DFALSE; ClientIntersectQuery query; float dot; // Only do an intersection test if the line is long enough (sometimes the // intersection test will fail on really short lines). memset(&query, 0, sizeof(query)); VEC_COPY(query.m_From, pObject->m_Pos); VEC_COPY(query.m_To, *pNewPos); if (eType) query.m_Flags = INTERSECT_HPOLY; if (pState->m_pClientDE->IntersectSegment(&query, pInfo)) { // get the surface type if (eType) *eType = GetSurfaceType(pInfo->m_hObject, pInfo->m_hPoly); // Reflect the velocity. dot = VEC_DOT(pObject->m_Velocity, pInfo->m_Plane.m_Normal); dot *= -2.0f; VEC_ADDSCALED(pObject->m_Velocity, pObject->m_Velocity, pInfo->m_Plane.m_Normal, dot); // If the plane hit is in the opposite direction of travel, then move back a little... if( dot > 0.0f ) { // Move the dest point a little in front of the plane. VEC_ADDSCALED(*pNewPos, pInfo->m_Point, pInfo->m_Plane.m_Normal, 0.3f); } // Dampen it. VEC_MULSCALAR(pObject->m_Velocity, pObject->m_Velocity, pState->m_VelocityDampen); // (250 is the max squared magnitude). if(pInfo->m_Plane.m_Normal.y > 0.6f && (VEC_MAGSQR(pObject->m_Velocity) < (250.0f))) { pObject->m_PhysicsFlags |= MO_RESTING; } return DTRUE; } return DFALSE; }
/* ** All vectors are in the same 1D space, we have to find two ** mutually vectors perpendicular to that span */ void nullspace2(double reta[3], double retb[3], const double r0[3], const double r1[3], const double r2[3]) { double sqr[3], sum[3]; int idx; VEC_COPY(sum, r0); if (VEC_DOT(sum, r1) > 0) { VEC_ADD(sum, r1); } else { VEC_SUB(sum, r1); } if (VEC_DOT(sum, r2) > 0) { VEC_ADD(sum, r2); } else { VEC_SUB(sum, r2); } /* find largest component, to get most stable expression for a perpendicular vector */ sqr[0] = sum[0]*sum[0]; sqr[1] = sum[1]*sum[1]; sqr[2] = sum[2]*sum[2]; idx = 0; if (sqr[0] < sqr[1]) idx = 1; if (sqr[idx] < sqr[2]) idx = 2; /* reta will be perpendicular to sum */ if (0 == idx) { VEC_SET(reta, sum[1] - sum[2], -sum[0], sum[0]); } else if (1 == idx) { VEC_SET(reta, -sum[1], sum[0] - sum[2], sum[1]); } else { VEC_SET(reta, -sum[2], sum[2], sum[0] - sum[1]); } /* and now retb will be perpendicular to both reta and sum */ VEC_CROSS(retb, reta, sum); return; }
inline bool d3d_ClipSprite(SpriteInstance *pInstance, HPOLY hPoly, T **ppPoints, uint32 *pnPoints, T *pOut) { LTPlane thePlane; float dot, d1, d2; SPolyVertex *pPrevPoint, *pCurPoint, *pEndPoint; LTVector vecTo; T *pVerts; uint32 nVerts; WorldPoly *pPoly; if(g_have_world == false) return false; // Get the correct poly. pPoly = world_bsp_client->GetPolyFromHPoly(hPoly); if(!pPoly) return false; // First see if the viewer is on the frontside of the poly. dot = pPoly->GetPlane()->DistTo(g_ViewParams.m_Pos); if(dot <= 0.01f) return false; pVerts = *ppPoints; nVerts = *pnPoints; // Clip on each edge plane. pEndPoint = &pPoly->GetVertices()[pPoly->GetNumVertices()]; pPrevPoint = pEndPoint - 1; for(pCurPoint=pPoly->GetVertices(); pCurPoint != pEndPoint; ) { VEC_SUB(vecTo, pCurPoint->m_Vertex->m_Vec, pPrevPoint->m_Vertex->m_Vec); VEC_CROSS(thePlane.m_Normal, vecTo, pPoly->GetPlane()->m_Normal); VEC_NORM(thePlane.m_Normal); thePlane.m_Dist = VEC_DOT(thePlane.m_Normal, pCurPoint->m_Vertex->m_Vec); #define CLIPTEST PLANETEST #define DOCLIP DOPLANECLIP #include "polyclip.h" #undef CLIPTEST #undef DOCLIP pPrevPoint = pCurPoint; ++pCurPoint; } *ppPoints = pVerts; *pnPoints = nVerts; return true; }
void gim_merge_contacts_unique(GDYNAMIC_ARRAY * source_contacts, GDYNAMIC_ARRAY * dest_contacts) { dest_contacts->m_size = 0; //Traverse the source contacts GUINT32 source_count = source_contacts->m_size; if(source_count==0) return; GIM_CONTACT * psource_contacts = GIM_DYNARRAY_POINTER(GIM_CONTACT,(*source_contacts)); //add the unique contact GIM_CONTACT * pcontact = 0; GIM_DYNARRAY_PUSH_EMPTY(GIM_CONTACT,(*dest_contacts)); pcontact = GIM_DYNARRAY_POINTER_LAST(GIM_CONTACT,(*dest_contacts)); //set the first contact GIM_COPY_CONTACTS(pcontact, psource_contacts); if(source_count==1) return; //scale the first contact VEC_SCALE(pcontact->m_normal,pcontact->m_depth,pcontact->m_normal); psource_contacts++; //Average the contacts GUINT32 i; for(i=1;i<source_count;i++) { VEC_SUM(pcontact->m_point,pcontact->m_point,psource_contacts->m_point); VEC_ACCUM(pcontact->m_normal,psource_contacts->m_depth,psource_contacts->m_normal); psource_contacts++; } GREAL divide_average = 1.0f/((GREAL)source_count); VEC_SCALE(pcontact->m_point,divide_average,pcontact->m_point); pcontact->m_depth = VEC_DOT(pcontact->m_normal,pcontact->m_normal)*divide_average; GIM_SQRT(pcontact->m_depth,pcontact->m_depth); VEC_NORMALIZE(pcontact->m_normal); /*GREAL normal_len; VEC_INV_LENGTH(pcontact->m_normal,normal_len); VEC_SCALE(pcontact->m_normal,normal_len,pcontact->m_normal); //Deep = LEN(normal)/SQRT(source_count) GIM_SQRT(divide_average,divide_average); pcontact->m_depth = divide_average/normal_len; */ }
void gr_GetPerpendicularVector(LTVector *pVec, LTVector *pRef, LTVector *pPerp) { float dot, t; LTVector temp, tempRef; if(!pRef) { tempRef.Init(0, 1, 0); pRef = &tempRef; } *pPerp = *pRef; // Are pRef and pVec the same? If not, we can exit. dot = pVec->Dot(*pPerp); if(dot > 0.99f || dot < -0.99f) { // Try to modify it as little as possible. pPerp->z += 5.0f; pPerp->Norm(); dot = VEC_DOT(*pVec, *pPerp); if(dot > 0.99f || dot < -0.99f) { pPerp->x += 5.0f; pPerp->y += 5.0f; pPerp->Norm(); dot = pVec->Dot(*pPerp); if(dot > 0.99f || dot < -0.99f) { pPerp->x += 5.0f; pPerp->y -= 2.0f; pPerp->z -= 5.0f; pPerp->Norm(); } } } // Make pVec and pPerp linear independent. t = -pVec->Dot(*pPerp); temp = *pVec * t; *pPerp += temp; pPerp->Norm(); }
LTBOOL CGibFX::OkToRemoveGib(HLOCALOBJ hGib) { if (!m_pClientDE || !g_pGameClientShell || !hGib) return LTTRUE; // The only constraint is that the client isn't currently looking // at the model... HLOCALOBJ hCamera = g_pGameClientShell->GetCamera(); if (!hCamera) return LTTRUE; LTVector vPos, vCamPos; m_pClientDE->GetObjectPos(hGib, &vPos); m_pClientDE->GetObjectPos(hCamera, &vCamPos); // Determine if the client can see us... LTVector vDir; VEC_SUB(vDir, vPos, vCamPos); LTRotation rRot; LTVector vU, vR, vF; m_pClientDE->GetObjectRotation(hCamera, &rRot); m_pClientDE->GetRotationVectors(&rRot, &vU, &vR, &vF); VEC_NORM(vDir); VEC_NORM(vF); LTFLOAT fMul = VEC_DOT(vDir, vF); if (fMul <= 0.0f) return LTTRUE; // Client is looking our way, don't remove it yet... return LTFALSE; }
void CSpear::HandleImpact(HOBJECT hObj) { if (!g_vtSpearStickPercentage.IsInitted()) { g_vtSpearStickPercentage.Init(g_pLTServer, "SpearStickPercent", LTNULL, 0.9f); } if (!m_pAmmoData || !m_pAmmoData->pProjectileFX) { CProjectile::HandleImpact(hObj); return; } CollisionInfo info; g_pLTServer->GetLastCollision(&info); LTVector vPos, vVel, vCurVel, vP0, vP1; g_pLTServer->GetObjectPos(m_hObject, &vPos); LTRotation rRot; g_pLTServer->GetObjectRotation(m_hObject, &rRot); // Should we break the spear? enum SpearAction { eSpearActionBreak, eSpearActionStickWorld, eSpearActionStickAI, eSpearActionStickPlayer, eSpearActionStickBody }; SpearAction eSpearAction = eSpearActionBreak; // Randomly break even if we could sometimes stick... if (GetRandom(0.0, 1.0f) > g_vtSpearStickPercentage.GetFloat()) { eSpearAction = eSpearActionBreak; } else if (IsMainWorld(hObj)) { // Calculate where we really hit the world... g_pLTServer->GetVelocity(m_hObject, &vVel); vP1 = vPos; vCurVel = vVel * g_pLTServer->GetFrameTime(); vP0 = vP1 - vCurVel; vP1 += vCurVel; LTFLOAT fDot1 = VEC_DOT(info.m_Plane.m_Normal, vP0) - info.m_Plane.m_Dist; LTFLOAT fDot2 = VEC_DOT(info.m_Plane.m_Normal, vP1) - info.m_Plane.m_Dist; if (fDot1 < 0.0f && fDot2 < 0.0f || fDot1 > 0.0f && fDot2 > 0.0f) { vPos = vP1; } else { LTFLOAT fPercent = -fDot1 / (fDot2 - fDot1); VEC_LERP(vPos, vP0, vP1, fPercent); } // Set our new "real" pos... g_pLTServer->SetObjectPos(m_hObject, &vPos); eSpearAction = eSpearActionStickWorld; } else if (IsMoveable(hObj)) { if (IsAI(hObj)) { // Attach to a AI eSpearAction = eSpearActionStickAI; } else if (IsPlayer(hObj)) { // Attach to a Player eSpearAction = eSpearActionStickPlayer; } else if (IsBody(hObj)) { // Attach to a body eSpearAction = eSpearActionStickBody; } else { // Could probably come up with a way to attach to moveable // non-character objects (like doors), but it is much easier // to just break it ;)... eSpearAction = eSpearActionBreak; } } // If the surface is too hard, the spear will just break when // it hits it... SurfaceType eSurf = GetSurfaceType(info); SURFACE* pSurf = g_pSurfaceMgr->GetSurface(eSurf); if ((eSpearActionBreak == eSpearAction) || ((eSpearActionStickWorld == eSpearAction) && pSurf && pSurf->fHardness > 0.5)) { // Create spear debris... DEBRIS* pDebris = g_pDebrisMgr->GetDebris(m_pAmmoData->szName); if (pDebris) { vVel.Norm(); LTVector vNegVel = -vVel; CreatePropDebris(vPos, vNegVel, pDebris->nId); } CProjectile::HandleImpact(hObj); return; } // Create the Spear powerup... char szSpawn[512]; sprintf(szSpawn, "AmmoBox AmmoType1 %s;AmmoCount1 1;Filename %s;Skin %s", m_pAmmoData->szName, m_pAmmoData->pProjectileFX->szModel, m_pAmmoData->pProjectileFX->szSkin); LTVector vScale = m_pAmmoData->pProjectileFX->vModelScale; // Make sure the spear sticks out a little ways... vVel.Norm(); vPos -= (vVel * vScale.z/2.0f); if (eSpearActionStickWorld == eSpearAction) { g_pLTServer->AlignRotation(&rRot, &vVel, LTNULL); } BaseClass* pClass = SpawnObject(szSpawn, LTVector(-10000,-10000,-10000), rRot); if (pClass) { g_pLTServer->ScaleObject(pClass->m_hObject, &vScale); LTVector vDims; g_pLTServer->GetObjectDims(pClass->m_hObject, &vDims); vDims.x *= vScale.x; vDims.y *= vScale.y; vDims.z *= vScale.z; g_pLTServer->SetObjectDims(pClass->m_hObject, &vDims); // We don't want other projectiles to impact on us... //uint32 dwUsrFlags = g_pLTServer->GetObjectUserFlags(pClass->m_hObject); //dwUsrFlags |= USRFLG_IGNORE_PROJECTILES; //g_pLTServer->SetObjectUserFlags(pClass->m_hObject, dwUsrFlags); if ( eSpearActionStickAI == eSpearAction || eSpearActionStickPlayer == eSpearAction ) { g_pLTServer->SetObjectUserFlags(pClass->m_hObject, g_pLTServer->GetObjectUserFlags(pClass->m_hObject) & ~USRFLG_GLOW); g_pLTServer->SetObjectFlags(pClass->m_hObject, g_pLTServer->GetObjectFlags(pClass->m_hObject) & ~FLAG_TOUCH_NOTIFY); if ( eSpearActionStickPlayer == eSpearAction ) { g_pLTServer->SetObjectUserFlags(pClass->m_hObject, g_pLTServer->GetObjectUserFlags(pClass->m_hObject) | USRFLG_ATTACH_HIDE1SHOW3); } // Attach it to the character CCharacter* pCharacter = (CCharacter*)g_pLTServer->HandleToObject(hObj); pCharacter->AddSpear(pClass->m_hObject, pCharacter->GetModelNodeLastHit(), rRot); } else if ( eSpearActionStickBody == eSpearAction ) { g_pLTServer->SetObjectUserFlags(pClass->m_hObject, g_pLTServer->GetObjectUserFlags(pClass->m_hObject) & ~USRFLG_GLOW); g_pLTServer->SetObjectFlags(pClass->m_hObject, g_pLTServer->GetObjectFlags(pClass->m_hObject) & ~FLAG_TOUCH_NOTIFY); // Attach it to the body Body* pBody = (Body*)g_pLTServer->HandleToObject(hObj); pBody->AddSpear(pClass->m_hObject, rRot); } else // ( eSpearActionStickWorld == eSpearAction ) { // Move it to the right position in the world g_pLTServer->SetObjectPos(pClass->m_hObject, &vPos); } } CProjectile::HandleImpact(hObj); }
void CProjectileFX::Detonate(CollisionInfo* pInfo) { if (!m_pClientDE || m_bDetonated) return; m_bDetonated = LTTRUE; SurfaceType eType = ST_UNKNOWN; LTVector vPos; g_pLTClient->GetObjectPos(m_hServerObject, &vPos); // Determine the normal of the surface we are impacting on... LTVector vNormal; VEC_SET(vNormal, 0.0f, 1.0f, 0.0f); if (pInfo) { if (pInfo->m_hObject) { eType = GetSurfaceType(pInfo->m_hObject); } else if (pInfo->m_hPoly != INVALID_HPOLY) { eType = GetSurfaceType(pInfo->m_hPoly); VEC_COPY(vNormal, pInfo->m_Plane.m_Normal); LTRotation rRot(vNormal, LTVector(0.0f, 1.0f, 0.0f)); m_pClientDE->SetObjectRotation(m_hServerObject, &rRot); // Calculate where we really hit the plane... LTVector vVel, vP0, vP1; g_pPhysicsLT->GetVelocity(m_hServerObject, &vVel); VEC_COPY(vP1, vPos); VEC_MULSCALAR(vVel, vVel, g_pGameClientShell->GetFrameTime()); VEC_SUB(vP0, vP1, vVel); LTFLOAT fDot1 = VEC_DOT(pInfo->m_Plane.m_Normal, vP0) - pInfo->m_Plane.m_Dist; LTFLOAT fDot2 = VEC_DOT(pInfo->m_Plane.m_Normal, vP1) - pInfo->m_Plane.m_Dist; if (fDot1 < 0.0f && fDot2 < 0.0f || fDot1 > 0.0f && fDot2 > 0.0f) { VEC_COPY(vPos, vP1); } else { LTFLOAT fPercent = -fDot1 / (fDot2 - fDot1); VEC_LERP(vPos, vP0, vP1, fPercent); } } } else { // Since pInfo was null, this means the projectile's lifetime was up, // so we just blow-up in the air. eType = ST_AIR; } HOBJECT hObj = !!pInfo ? pInfo->m_hObject : LTNULL; ::AddLocalImpactFX(hObj, m_vFirePos, vPos, vNormal, eType, m_vPath, m_nWeaponId, m_nAmmoId, 0); m_bWantRemove = LTTRUE; }
void Prop::HandleAttachmentTouch( HOBJECT hToucher ) { if( !hToucher || !m_bAttachmentShotOff ) return; // Don't touch the owner... if( hToucher == m_hAttachmentOwner ) return; // Or any non-solid objects... uint32 dwToucherFlags; g_pCommonLT->GetObjectFlags( hToucher, OFT_Flags, dwToucherFlags ); if( !(dwToucherFlags & FLAG_SOLID) ) return; CollisionInfo info; g_pLTServer->GetLastCollision( &info ); LTVector vVel; g_pPhysicsLT->GetVelocity( m_hObject, &vVel ); // Calculate where we really hit the world... if( IsMainWorld( hToucher )) { LTVector vPos, vCurVel, vP0, vP1; g_pLTServer->GetObjectPos( m_hObject, &vPos ); vP1 = vPos; vCurVel = vVel * g_pLTServer->GetFrameTime(); vP0 = vP1 - vCurVel; vP1 += vCurVel; LTFLOAT fDot1 = VEC_DOT( info.m_Plane.m_Normal, vP0 ) - info.m_Plane.m_Dist; LTFLOAT fDot2 = VEC_DOT( info.m_Plane.m_Normal, vP1 ) - info.m_Plane.m_Dist; if( fDot1 < 0.0f && fDot2 < 0.0f || fDot1 > 0.0f && fDot2 > 0.0f ) { vPos = vP1; } else { LTFLOAT fPercent = -fDot1 / (fDot2 - fDot1); VEC_LERP( vPos, vP0, vP1, fPercent); } // Set our new "real" pos... g_pLTServer->SetObjectPos( m_hObject, &vPos ); } // If we're on the ground (or an object), stop movement... CollisionInfo standingInfo; g_pLTServer->GetStandingOn( m_hObject, &standingInfo ); CollisionInfo* pInfo = standingInfo.m_hObject ? &standingInfo : &info; if( pInfo->m_hObject ) { // Don't stop on walls... if( pInfo->m_Plane.m_Normal.y > 0.75f ) { vVel.Init(); // Turn off gravity, solid, and touch notify.... uint32 dwFlags = FLAG_POINTCOLLIDE | FLAG_NOSLIDING | FLAG_TOUCH_NOTIFY | FLAG_GRAVITY; g_pCommonLT->SetObjectFlags( m_hObject, OFT_Flags, 0, dwFlags ); // Rotate to rest... if( m_bRotating ) { LTRotation rRot( 0.0f, m_fYaw, 0.0f ); g_pLTServer->SetObjectRotation( m_hObject, &rRot ); m_bRotating = false; StartFade( s_vtAttachmentFadeDuration.GetFloat(), s_vtAttachmentFadeDelay.GetFloat() ); } } } // Remove the stoping velocity... vVel = -info.m_vStopVel; g_pPhysicsLT->SetVelocity( m_hObject, &vVel ); }
void CProjectile::Detonate(HOBJECT hObj) { if (m_bDetonated) return; // Make sure we don't detonate if a cinematic is playing (i.e., // make sure the user doesn't disrupt the cinematic)... if (Camera::IsActive()) { RemoveObject(); return; } m_bDetonated = LTTRUE; SurfaceType eType = ST_UNKNOWN; LTVector vPos; g_pLTServer->GetObjectPos(m_hObject, &vPos); // Determine the normal of the surface we are impacting on... LTVector vNormal(0.0f, 1.0f, 0.0f); if (hObj) { if (IsMainWorld(hObj) || g_pLTServer->GetObjectType(hObj) == OT_WORLDMODEL) { CollisionInfo info; g_pLTServer->GetLastCollision(&info); if (info.m_hPoly) { eType = GetSurfaceType(info.m_hPoly); } LTPlane plane = info.m_Plane; vNormal = plane.m_Normal; // Calculate where we really hit the plane... LTVector vVel, vP0, vP1, vDir; g_pLTServer->GetVelocity(m_hObject, &vVel); vDir = vVel; vDir.Norm(); vP1 = vPos; vVel *= g_pLTServer->GetFrameTime(); vP0 = vP1 - vVel; vP1 += vVel; // Make sure we don't tunnel through an object... IntersectInfo iInfo; IntersectQuery qInfo; qInfo.m_Flags = INTERSECT_HPOLY | INTERSECT_OBJECTS | IGNORE_NONSOLID; qInfo.m_From = vP0; qInfo.m_To = vPos; qInfo.m_FilterFn = SpecificObjectFilterFn; qInfo.m_pUserData = m_hObject; if (g_pLTServer->IntersectSegment(&qInfo, &iInfo)) { vPos = iInfo.m_Point - vDir; eType = GetSurfaceType(iInfo); vNormal = iInfo.m_Plane.m_Normal; } else { //g_pLTServer->CPrint("P0 = %.2f, %.2f, %.2f", VEC_EXPAND(vP0)); //g_pLTServer->CPrint("P1 = %.2f, %.2f, %.2f", VEC_EXPAND(vP1)); //LTVector vDist = vP1 - vP0; //g_pLTServer->CPrint("Distance from P0 to P1: %.2f", vDist.Mag()); LTFLOAT fDot1 = VEC_DOT(vNormal, vP0) - info.m_Plane.m_Dist; LTFLOAT fDot2 = VEC_DOT(vNormal, vP1) - info.m_Plane.m_Dist; if (fDot1 < 0.0f && fDot2 < 0.0f || fDot1 > 0.0f && fDot2 > 0.0f) { vPos = vP1; } else { LTFLOAT fPercent = -fDot1 / (fDot2 - fDot1); //g_pLTServer->CPrint("Percent: %.2f", fPercent); VEC_LERP(vPos, vP0, vP1, fPercent); } } LTRotation rRot; g_pLTServer->AlignRotation(&rRot, &vNormal, LTNULL); g_pLTServer->SetObjectRotation(m_hObject, &rRot); // g_pLTServer->CPrint("Pos = %.2f, %.2f, %.2f", VEC_EXPAND(vPos)); } } else { // Since hObj was null, this means the projectile's lifetime was up, // so we just blew-up in the air. eType = ST_AIR; } if (eType == ST_UNKNOWN) { eType = GetSurfaceType(hObj); } AddImpact(hObj, m_vFlashPos, vPos, vNormal, eType); // Handle impact damage... if (hObj) { HOBJECT hDamager = m_hFiredFrom ? m_hFiredFrom : m_hObject; ImpactDamageObject(hDamager, hObj); } //g_pLTServer->CPrint("Server end pos (%.2f, %.2f, %.2f)", vPos.x, vPos.y, vPos.z); //g_pLTServer->CPrint("Server fly time %.2f", g_pLTServer->GetTime() - m_fStartTime); // Remove projectile from world... RemoveObject(); }
LTBOOL CWeaponFX::CreateObject(ILTClient* pClientDE) { if (!CSpecialFX::CreateObject(pClientDE) || !g_pWeaponMgr) return LTFALSE; CGameSettings* pSettings = g_pInterfaceMgr->GetSettings(); if (!pSettings) return LTFALSE; // Set up our data members... // Set the local client id... uint32 dwId; g_pLTClient->GetLocalClientID(&dwId); m_nLocalId = (uint8)dwId; m_nDetailLevel = pSettings->SpecialFXSetting(); // Fire pos may get tweaked a little... m_vFirePos = CalcFirePos(m_vFirePos); m_vDir = m_vPos - m_vFirePos; m_fFireDistance = m_vDir.Mag(); m_vDir.Norm(); g_pLTClient->AlignRotation(&m_rSurfaceRot, &m_vSurfaceNormal, LTNULL); g_pLTClient->AlignRotation(&m_rDirRot, &m_vDir, LTNULL); SetupExitInfo(); // Calculate if the camera can see the fire position and the impact // position... g_bCanSeeImpactPos = LTTRUE; g_bCanSeeFirePos = LTTRUE; g_bDistantImpactPos = LTFALSE; g_bDistantFirePos = LTFALSE; if (g_vtWeaponFXUseFOVPerformance.GetFloat()) { HOBJECT hCamera = g_pGameClientShell->GetCamera(); LTVector vCameraPos, vU, vR, vF, vDir; LTRotation rCameraRot; g_pLTClient->GetObjectPos(hCamera, &vCameraPos); g_pLTClient->GetObjectRotation(hCamera, &rCameraRot); g_pLTClient->GetRotationVectors(&rCameraRot, &vU, &vR, &vF); vDir = m_vPos - vCameraPos; LTFLOAT fImpactDist = vDir.Mag(); if (fImpactDist > g_vtWeaponFXMaxImpactDist.GetFloat()) { g_bDistantImpactPos = LTTRUE; } vDir.Norm(); LTFLOAT fMul = VEC_DOT(vDir, vF); g_bCanSeeImpactPos = (fMul < g_vtWeaponFXMinImpactDot.GetFloat() ? LTFALSE : LTTRUE); // In multiplayer we need to account for impacts that occur around // our camera that we didn't cause (this is also an issue in single // player, but due to the singler player gameplay dynamics it isn't // as noticeable)... if (!g_bCanSeeImpactPos && IsMultiplayerGame()) { // Somebody else shot this...if the impact is close enough, we // "saw" it... if (m_nLocalId != m_nShooterId && fImpactDist <= g_vtWeaponFXMaxMultiImpactDist.GetFloat()) { g_bCanSeeImpactPos = LTTRUE; } } vDir = m_vFirePos - vCameraPos; if (vDir.Mag() > g_vtWeaponFXMaxFireDist.GetFloat()) { g_bDistantFirePos = LTTRUE; } vDir.Norm(); fMul = VEC_DOT(vDir, vF); g_bCanSeeFirePos = (fMul < g_vtWeaponFXMinFireDot.GetFloat() ? LTFALSE : LTTRUE); } // Determine what container the sfx is in... HLOCALOBJ objList[1]; LTVector vTestPos = m_vPos + m_vSurfaceNormal; // Test a little closer... uint32 dwNum = g_pLTClient->GetPointContainers(&vTestPos, objList, 1); if (dwNum > 0 && objList[0]) { uint32 dwUserFlags; g_pLTClient->GetObjectUserFlags(objList[0], &dwUserFlags); if (dwUserFlags & USRFLG_VISIBLE) { uint16 dwCode; if (g_pLTClient->GetContainerCode(objList[0], &dwCode)) { m_eCode = (ContainerCode)dwCode; } } } // Determine if the fire point is in liquid vTestPos = m_vFirePos + m_vDir; // Test a little further in... dwNum = g_pLTClient->GetPointContainers(&vTestPos, objList, 1); if (dwNum > 0 && objList[0]) { uint32 dwUserFlags; g_pLTClient->GetObjectUserFlags(objList[0], &dwUserFlags); if (dwUserFlags & USRFLG_VISIBLE) { uint16 dwCode; if (g_pLTClient->GetContainerCode(objList[0], &dwCode)) { m_eFirePosCode = (ContainerCode)dwCode; } } } if (IsLiquid(m_eCode)) { m_wImpactFX = m_pAmmo->pUWImpactFX ? m_pAmmo->pUWImpactFX->nFlags : 0; } else { m_wImpactFX = m_pAmmo->pImpactFX ? m_pAmmo->pImpactFX->nFlags : 0; } m_wFireFX = m_pAmmo->pFireFX ? m_pAmmo->pFireFX->nFlags : 0; // Assume alt-fire, silenced, and tracer...these will be cleared by // IgnoreFX if not used... m_wFireFX |= WFX_ALTFIRESND | WFX_SILENCED | WFX_TRACER; // Assume impact ding, it will be cleared if not used... m_wImpactFX |= WFX_IMPACTDING; // Clear all the fire fx we want to ignore... m_wFireFX &= ~m_wIgnoreFX; m_wImpactFX &= ~m_wIgnoreFX; // See if this is a redundant weapon fx (i.e., this client shot the // weapon so they've already seen this fx)... if (g_pGameClientShell->IsMultiplayerGame()) { if (m_pAmmo->eType != PROJECTILE) { if (!m_bLocal && m_nLocalId >= 0 && m_nLocalId == m_nShooterId) { if (m_wImpactFX & WFX_IMPACTDING) { if (g_vtMultiDing.GetFloat()) { PlayImpactDing(); } } return LTFALSE; } } } // Show the fire path...(debugging...) if (g_cvarShowFirePath.GetFloat() > 0) { PLFXCREATESTRUCT pls; pls.vStartPos = m_vFirePos; pls.vEndPos = m_vPos; pls.vInnerColorStart = LTVector(GetRandom(127.0f, 255.0f), GetRandom(127.0f, 255.0f), GetRandom(127.0f, 255.0f)); pls.vInnerColorEnd = pls.vInnerColorStart; pls.vOuterColorStart = LTVector(0, 0, 0); pls.vOuterColorEnd = LTVector(0, 0, 0); pls.fAlphaStart = 1.0f; pls.fAlphaEnd = 1.0f; pls.fMinWidth = 0; pls.fMaxWidth = 10; pls.fMinDistMult = 1.0f; pls.fMaxDistMult = 1.0f; pls.fLifeTime = 10.0f; pls.fAlphaLifeTime = 10.0f; pls.fPerturb = 0.0f; pls.bAdditive = LTFALSE; pls.nWidthStyle = PLWS_CONSTANT; pls.nNumSegments = 2; CSpecialFX* pFX = g_pGameClientShell->GetSFXMgr()->CreateSFX(SFX_POLYLINE_ID, &pls); if (pFX) pFX->Update(); } // If the surface is the sky, don't create any impact related fx... if (m_eSurfaceType != ST_SKY || (m_wImpactFX & WFX_IMPACTONSKY)) { CreateWeaponSpecificFX(); if (g_bCanSeeImpactPos) { if ((m_wImpactFX & WFX_MARK) && ShowsMark(m_eSurfaceType) && (LTBOOL)GetConsoleInt("MarkShow", 1)) { LTBOOL bCreateMark = LTTRUE; if (g_bDistantImpactPos && m_nLocalId == m_nShooterId) { // Assume we'll see the mark if we're zoomed in ;) bCreateMark = g_pGameClientShell->IsZoomed(); } if (bCreateMark) { CreateMark(m_vPos, m_vSurfaceNormal, m_rSurfaceRot, m_eSurfaceType); } } CreateSurfaceSpecificFX(); } PlayImpactSound(); } if (IsBulletTrailWeapon()) { if (IsLiquid(m_eFirePosCode)) { if (m_nDetailLevel != RS_LOW) { CreateBulletTrail(&m_vFirePos); } } } // No tracers under water... if ((LTBOOL)GetConsoleInt("Tracers", 1) && (m_wFireFX & WFX_TRACER) && !IsLiquid(m_eCode)) { CreateTracer(); } if (g_bCanSeeFirePos) { // Only do muzzle fx for the client (not for AIs)... if ((m_wFireFX & WFX_MUZZLE) && (m_nLocalId == m_nShooterId)) { CreateMuzzleFX(); } if (!g_bDistantFirePos && (LTBOOL)GetConsoleInt("ShellCasings", 1) && (m_wFireFX & WFX_SHELL)) { CreateShell(); } if ((m_wFireFX & WFX_LIGHT)) { CreateMuzzleLight(); } } if ((m_wFireFX & WFX_FIRESOUND) || (m_wFireFX & WFX_ALTFIRESND) || (m_wFireFX & WFX_SILENCED)) { PlayFireSound(); } // Only do fly-by sounds for weapons that leave bullet trails... if (IsBulletTrailWeapon()) { PlayBulletFlyBySound(); } return LTFALSE; // Just delete me, I'm done :) }
void CNodeController::UpdateHeadFollowPosControl(NCSTRUCT *pNodeControl) { LTVector vPos; LTRotation rRot; LTransform transform; LTVector vU, vR, vF; //---------------------------------------------------------------------- // Get information about the control node... // *** NOTE: On the head node... vU faces forward, vR faces down, vF faces right *** // Get access to the controls... ILTMath *pMathLT = g_pLTClient->GetMathLT(); ILTModel *pModelLT = g_pLTClient->GetModelLT(); ILTTransform *pTransformLT = g_pLTClient->GetTransformLT(); // Get the transform of the node we're controlling pModelLT->GetNodeTransform(GetCFX()->GetServerObj(), m_aNodes[pNodeControl->eModelNode].hModelNode, transform, LTTRUE); // Decompose the transform into the position and rotation pTransformLT->Get(transform, vPos, rRot); pMathLT->GetRotationVectors(rRot, vR, vU, vF); // Get information about the follow position... LTVector vObjPos = pNodeControl->vFollowPos; // Turn the follow control off if the expire time has past if(pNodeControl->fFollowExpireTime <= 0.0f) { pNodeControl->fFollowExpireTime = 0.0f; pNodeControl->bFollowOn = LTFALSE; } else pNodeControl->fFollowExpireTime -= g_pGameClientShell->GetFrameTime(); //---------------------------------------------------------------------- // Setup the rotation matrix to directly follow the destination position // Get the direction that we're going to face... LTVector vDir = vObjPos - vPos; // Setup some temp vectors that are on the x/z plane... LTVector vTempU, vTempF, vTempDir; vTempU = vU; vTempU.y = 0.0f; vTempF = vF; vTempF.y = 0.0f; vTempDir = vDir; vTempDir.y = 0.0f; VEC_NORM(vTempU); VEC_NORM(vTempF); VEC_NORM(vTempDir); // Get the dot products between the dir vector and the up and forward to determine the rotation angles LTFLOAT fDotUDir = VEC_DOT(vTempU, vTempDir); LTFLOAT fDotFDir = VEC_DOT(vTempF, vTempDir); LTFLOAT fDotRDir = 0.0f; // Init the vectors to get a rotation matrix from... LTVector vRotAxisR(1.0f, 0.0f, 0.0f); // Get the first rotation angle LTFLOAT fAngle1 = pNodeControl->bFollowOn ? fDotUDir : 1.0f; if(fAngle1 < -0.1f) fAngle1 = -0.1f; // HACK! Limit the head rotation fAngle1 = (1.0f - fAngle1) * MATH_HALFPI; if(fDotFDir < 0.0f) fAngle1 *= -1.0f; // Do a full rotation around the first axis so we can get an angle for the second axis LTFLOAT fTempAngle = pNodeControl->bFollowOn ? ((1.0f - fDotUDir) * MATH_HALFPI) : 0.0f; pMathLT->RotateAroundAxis(rRot, vR, (fDotFDir < 0.0f) ? -fTempAngle : fTempAngle); pMathLT->GetRotationVectors(rRot, vR, vU, vF); VEC_NORM(vDir); fDotUDir = VEC_DOT(vU, vDir); fDotRDir = VEC_DOT(vR, vDir); // Get the second rotation angle LTFLOAT fAngle2 = pNodeControl->bFollowOn ? fDotUDir : 1.0f; if(fAngle2 < 0.25f) fAngle2 = 0.25f; // HACK! Limit the head rotation fAngle2 = (1.0f - fAngle2) * MATH_HALFPI; if(fDotRDir > 0.0f) fAngle2 *= -1.0f; // Calculate a max rotation value LTFLOAT fRotMax = (pNodeControl->fFollowRate * g_pGameClientShell->GetFrameTime() / 180.0f) * MATH_PI; // Interpolate the angles based off the previous angle if(fAngle1 > pNodeControl->vFollowAngles.y + fRotMax) fAngle1 = pNodeControl->vFollowAngles.y + fRotMax; else if(fAngle1 < pNodeControl->vFollowAngles.y - fRotMax) fAngle1 = pNodeControl->vFollowAngles.y - fRotMax; if(fAngle2 > pNodeControl->vFollowAngles.x + fRotMax) fAngle2 = pNodeControl->vFollowAngles.x + fRotMax; else if(fAngle2 < pNodeControl->vFollowAngles.x - fRotMax) fAngle2 = pNodeControl->vFollowAngles.x - fRotMax; // Create a new rotation and rotate around each controlled axis LTRotation rNewRot; rNewRot.Init(); pMathLT->RotateAroundAxis(rNewRot, vRotAxisR, fAngle1); pNodeControl->vFollowAngles.y = fAngle1; pMathLT->GetRotationVectors(rNewRot, vR, vU, vF); pMathLT->RotateAroundAxis(rNewRot, vF, fAngle2); pNodeControl->vFollowAngles.x = fAngle2; // If we're turned off and back at the start rotation... make the control invalid if(!pNodeControl->bFollowOn && pNodeControl->vFollowAngles.x == 0.0f && pNodeControl->vFollowAngles.y == 0.0f) { pNodeControl->bValid = LTFALSE; return; } // Create a rotation matrix and apply it to the current offset matrix LTMatrix m1; pMathLT->SetupRotationMatrix(m1, rNewRot); m_aNodes[pNodeControl->eModelNode].matTransform = m_aNodes[pNodeControl->eModelNode].matTransform * m1; }
/*! \param triangle \param s1 \param s2 \param contacts Contains the closest points on the segment (1,2), and the normal points to segment, and m_depth contains the distance \post The contacts array is not set to 0. It adds aditional contacts */ void gim_closest_point_triangle_segment(GIM_TRIANGLE_DATA * triangle, vec3f s1,vec3f s2, GDYNAMIC_ARRAY * contacts) { vec3f segment_points[4]; vec3f closest_points[2]; GUINT intersection_type, out_edge= 10; GREAL dis, dis_temp,perpend; vec4f sdiff; dis = DISTANCE_PLANE_POINT(triangle->m_planes.m_planes[0],s1); dis_temp = DISTANCE_PLANE_POINT(triangle->m_planes.m_planes[0],s2); if(dis<=0.0f && dis_temp<=0.0f) return; VEC_DIFF(sdiff,s2,s1); perpend = VEC_DOT(sdiff,triangle->m_planes.m_planes[0]); if(!IS_ZERO(perpend)) // Not perpendicular { if(dis<dis_temp) { VEC_COPY(closest_points[0],s1); } else { dis = dis_temp; VEC_COPY(closest_points[0],s2); } //Testing segment vertices over triangle if(dis>=0.0f && dis_temp>=0.0f) { POINT_IN_HULL(closest_points[0],(&triangle->m_planes.m_planes[1]),3,out_edge); if(out_edge==0)//Point over face { GIM_PUSH_CONTACT((*contacts),closest_points[0] ,triangle->m_planes.m_planes[0] ,dis,0, 0, 0,0); return; } } else { PLANE_CLIP_SEGMENT(s1,s2,triangle->m_planes.m_planes[0],closest_points[1]); POINT_IN_HULL(closest_points[1],(&triangle->m_planes.m_planes[1]),3,out_edge); if(out_edge==0)//Point over face { GIM_PUSH_CONTACT((*contacts),closest_points[0] ,triangle->m_planes.m_planes[0] ,dis,0, 0, 0,0); return; } } } else // Perpendicular Face { //out_edge=10 //Clip segment by triangle // Edge1 PLANE_CLIP_SEGMENT_CLOSEST(s1,s2,triangle->m_planes.m_planes[1],segment_points[0],segment_points[1],intersection_type); if(intersection_type==0||intersection_type==1) { out_edge = 0; VEC_COPY(closest_points[0],segment_points[0]); } else { //Edge2 PLANE_CLIP_SEGMENT_CLOSEST(segment_points[0],segment_points[1],triangle->m_planes.m_planes[2],segment_points[2],segment_points[3],intersection_type); if(intersection_type==0||intersection_type==1) { out_edge = 1; VEC_COPY(closest_points[0],segment_points[3]); } else { //Edge3 PLANE_CLIP_SEGMENT_CLOSEST(segment_points[2],segment_points[3],triangle->m_planes.m_planes[3],closest_points[0],closest_points[1],intersection_type); if(intersection_type==0||intersection_type==1) { out_edge = 2; } } } //POST closest_points[0] and closest_points[1] are inside the triangle, if out_edge>2 if(out_edge>2) // Over triangle { dis = VEC_DOT(closest_points[0],triangle->m_planes.m_planes[0]); GIM_PUSH_CONTACT((*contacts),closest_points[0] ,triangle->m_planes.m_planes[0] ,dis,0, 0, 0,0); GIM_PUSH_CONTACT((*contacts),closest_points[1] ,triangle->m_planes.m_planes[0] ,dis,0, 0, 0,0); return; } } //Find closest edges out_edge = 10; dis = G_REAL_INFINITY; GUINT i; for(i=0;i<3;i++) { SEGMENT_COLLISION(s1,s2,triangle->m_vertices[i],triangle->m_vertices[(i+1)%3],segment_points[0],segment_points[1]); VEC_DIFF(sdiff,segment_points[0],segment_points[1]); dis_temp = VEC_DOT(sdiff,sdiff); if(dis_temp< dis) { dis = dis_temp; out_edge = i; VEC_COPY(closest_points[0],segment_points[0]); VEC_COPY(closest_points[1],sdiff);//normal } } if(out_edge>2) return ;// ???? ASSERT this please if(IS_ZERO(dis)) { //Set face plane GIM_PUSH_CONTACT((*contacts),closest_points[0] ,triangle->m_planes.m_planes[0] ,0.0f,0, 0, 0,0); } else { GIM_SQRT(dis,dis); VEC_SCALE(closest_points[1],(1.0f/dis),closest_points[1]);//normal GIM_PUSH_CONTACT((*contacts),closest_points[0] ,closest_points[1],dis,0, 0, 0,0); } }
void SoccerGoal::OnTouchNotify( HOBJECT hObj ) { CollisionInfo colInfo; DVector vBallVel; DBOOL bGoal; SoccerBall *pSoccerBall; DVector vPos, vDir, vDims; HOBJECT hPlayer; LMessage *pMsg; if( g_pServerDE->IsKindOf( g_pServerDE->GetObjectClass(hObj), m_hSoccerBall )) { pSoccerBall = ( SoccerBall * )g_pServerDE->HandleToObject( hObj ); if( !pSoccerBall ) return; // Already recorded this goal. Ball should delete itself soon. if( pSoccerBall->IsMadeGoal( )) return; // Ball has to enter from correct side for directional goals if( m_bDirectional ) { // Assume no goal bGoal = DFALSE; g_pServerDE->GetVelocity( hObj, &vBallVel ); // Check if going in the right direction if( VEC_DOT( vBallVel, m_vGoalDirection ) > 0.0f ) { bGoal = DTRUE; } } else bGoal = DTRUE; if( bGoal ) { if(( hPlayer = pSoccerBall->GetLastPlayerTouched( )) == DNULL ) return; // Send message to player and ball if( g_pServerDE->Common( )->CreateMessage( pMsg ) != LT_OK ) return; pMsg->WriteByte( m_nTeamID ); g_pServerDE->SendToObject( *pMsg, MID_GOAL, m_hObject, hPlayer, 0 ); g_pServerDE->SendToObject( *pMsg, MID_GOAL, m_hObject, hObj, 0 ); pMsg->Release(); // Create special effects g_pServerDE->GetObjectPos( hObj, &vPos ); g_pServerDE->GetVelocity( hObj, &vDir ); VEC_MULSCALAR( vDir, vDir, -1.0f ); VEC_SET( vDims, 25.0f, 25.0f, 25.0f ); SetupClientGibFX( &vPos, &vDir, &vDims, ( SURFTYPE_FLESH/10 ) | SIZE_SMALL | TRAIL_BLOOD, 1.0f, 5 ); // Play the sound if( m_hstrScoreSound ) { g_pServerDE->GetObjectPos( m_hObject, &vPos ); PlaySoundFromPos( &vPos, g_pServerDE->GetStringData( m_hstrScoreSound ), m_fRadius, SOUNDPRIORITY_MISC_MEDIUM ); } SendTrigger( ); } } }
/******************************************************** * Search for an intersection between a nappe and a ray * *******************************************************/ BOOL hit_geo_nappe (GEO *Generic, RAY *Ray, HIT *Hit, PAIR *Bound, void *Info) { GEO_NAPPE *Geo; FCT *Fct; PNT *Pnt, *PntA, *PntB; VECTOR Normal; VECTOR Point; REAL a, b, c, u, v, uA, vA, uB, vB, Distance, Real; Geo = (GEO_NAPPE *) Generic; Fct = (FCT *) Info; Distance = VEC_DOT (Ray->Vector, Fct->Normal); if (ABS(Distance) < EPSILON) return (FALSE); Pnt = Geo->TabPnt + Fct->i; VEC_SUB (Point, Pnt->Point, Ray->Point); Distance = VEC_DOT (Point, Fct->Normal) / Distance ; /*-Epsilon est vire*/ if (Distance < Bound->u || Distance > Bound->v) return (FALSE); VEC_LIN (Point, Ray->Point, Distance, Ray->Vector); if ((ABS(Fct->Normal.z) > ABS(Fct->Normal.x)) && (ABS(Fct->Normal.z) > ABS(Fct->Normal.y))) { u = Point.x - Pnt->Point.x; v = Point.y - Pnt->Point.y; PntA = Geo->TabPnt + Fct->j; PntB = Geo->TabPnt + Fct->k; uA = PntA->Point.x - Pnt->Point.x; vA = PntA->Point.y - Pnt->Point.y; uB = PntB->Point.x - Pnt->Point.x; vB = PntB->Point.y - Pnt->Point.y; a = uA*vB - vA*uB; b = (u*vB - v*uB)/a; c = (v*uA-u*vA) / a; a = 1.0-b-c; if (a > -EPSILON && b > -EPSILON && c > -EPSILON) { VEC_INTER (Normal, a, Pnt->Normal, b, PntA->Normal, c, PntB->Normal); Real = VEC_DOT (Ray->Vector, Normal); if (Real > 0.0) return (FALSE); if (Hit) { Real = VEC_LEN (Normal); VEC_UNIT (Normal, Real); Ray->Distance = Distance; Hit->Point = Point; Hit->Normal = Normal; xyz2uv_geo_nappe (Geo, Hit, Fct); } return (TRUE); } if (Fct->l == Fct->i) return (FALSE); PntA = Geo->TabPnt + Fct->l; uA = PntA->Point.x - Pnt->Point.x; vA = PntA->Point.y - Pnt->Point.y; a = uA*vB - vA*uB; b = (u*vB - v*uB)/a; c = (v*uA - u*vA)/a; a = 1.0-b-c; if (a > -EPSILON && b > -EPSILON && c > -EPSILON) { VEC_INTER (Normal, a, Pnt->Normal, b, PntA->Normal, c, PntB->Normal); Real = VEC_DOT (Ray->Vector, Normal); if (Real > 0.0) return (FALSE); if (Hit) { Real = VEC_LEN (Normal); VEC_UNIT (Normal, Real); Ray->Distance = Distance; Hit->Point = Point; Hit->Normal = Normal; xyz2uv_geo_nappe (Geo, Hit, Fct); } return (TRUE); } return (FALSE); } else if (ABS(Fct->Normal.y) > ABS(Fct->Normal.x)) { u = Point.z - Pnt->Point.z; v = Point.x - Pnt->Point.x; PntA = Geo->TabPnt + Fct->j; PntB = Geo->TabPnt + Fct->k; uA = PntA->Point.z - Pnt->Point.z; vA = PntA->Point.x - Pnt->Point.x; uB = PntB->Point.z - Pnt->Point.z; vB = PntB->Point.x - Pnt->Point.x; a = uA*vB - vA*uB; b = (u*vB - v*uB)/a; c = (v*uA - u*vA)/a; a = 1.0-b-c; if (a > -EPSILON && b > -EPSILON && c > -EPSILON) { VEC_INTER (Normal, a, Pnt->Normal, b, PntA->Normal, c, PntB->Normal); Real = VEC_DOT (Ray->Vector, Normal); if (Real > 0.0) return (FALSE); if (Hit) { Real = VEC_LEN (Normal); VEC_UNIT (Normal, Real); Ray->Distance = Distance; Hit->Point = Point; Hit->Normal = Normal; xyz2uv_geo_nappe (Geo, Hit, Fct); } return (TRUE); } if (Fct->l == Fct->i) return (FALSE); PntA = Geo->TabPnt + Fct->l; uA = PntA->Point.z - Pnt->Point.z; vA = PntA->Point.x - Pnt->Point.x; a = uA*vB - vA*uB; b = (u*vB - v*uB)/a; c = (v*uA - u*vA)/a; a = 1.0-b-c; if (a > -EPSILON && b > -EPSILON && c > -EPSILON) { VEC_INTER (Normal, a, Pnt->Normal, b, PntA->Normal, c, PntB->Normal); Real = VEC_DOT (Ray->Vector, Normal); if (Real > 0.0) return (FALSE); if (Hit) { Real = VEC_LEN (Normal); VEC_UNIT (Normal, Real); Ray->Distance = Distance; Hit->Point = Point; Hit->Normal = Normal; xyz2uv_geo_nappe (Geo, Hit, Fct); } return (TRUE); } return (FALSE); } else if (ABS(Fct->Normal.x) > EPSILON) { u = Point.y - Pnt->Point.y; v = Point.z - Pnt->Point.z; PntA = Geo->TabPnt + Fct->j; PntB = Geo->TabPnt + Fct->k; uA = PntA->Point.y - Pnt->Point.y; vA = PntA->Point.z - Pnt->Point.z; uB = PntB->Point.y - Pnt->Point.y; vB = PntB->Point.z - Pnt->Point.z; a = uA*vB - vA*uB; b = (u*vB - v*uB)/a; c = (v*uA - u*vA)/a; a = 1.0-b-c; if (a > -EPSILON && b > -EPSILON && c > -EPSILON) { VEC_INTER (Normal, a, Pnt->Normal, b, PntA->Normal, c, PntB->Normal); Real = VEC_DOT (Ray->Vector, Normal); if (Real > 0.0) return (FALSE); if (Hit) { Real = VEC_LEN (Normal); VEC_UNIT (Normal, Real); Ray->Distance = Distance; Hit->Point = Point; Hit->Normal = Normal; xyz2uv_geo_nappe (Geo, Hit, Fct); } return (TRUE); } if (Fct->l == Fct->i) return (FALSE); PntA = Geo->TabPnt + Fct->l; uA = PntA->Point.y - Pnt->Point.y; vA = PntA->Point.z - Pnt->Point.z; a = uA*vB - vA*uB; b = (u*vB - v*uB)/a; c = (v*uA - u*vA)/a; a = 1.0-b-c; if (a > -EPSILON && b > -EPSILON && c > -EPSILON) { VEC_INTER (Normal, a, Pnt->Normal, b, PntA->Normal, c, PntB->Normal); Real = VEC_DOT (Ray->Vector, Normal); if (Real > 0.0) return (FALSE); if (Hit) { Real = VEC_LEN (Normal); VEC_UNIT (Normal, Real); Ray->Distance = Distance; Hit->Point = Point; Hit->Normal = Normal; xyz2uv_geo_nappe (Geo, Hit, Fct); } return (TRUE); } return (FALSE); } return (FALSE); }
int CDestructable::CalculateHitLimb(DVector vDir, DVector vPos, DFLOAT fDamage) { CServerDE* pServerDE = BaseClass::GetServerDE(); if (!pServerDE || !m_hObject || !m_pInventoryMgr || !m_pAnim_Sound) return -1; int nNode = -1; DFLOAT fNodeDist = 0.0f, fDist = 999.0f, fTemp = 0.0f; DVector vShot, vNewShot, vTemp, vObjDims, vNodePos, vZ; DFLOAT fX, fY, ft; DBOOL bStatus = DFALSE; DRotation rRot; if(pServerDE->GetModelAnimUserDims(m_hObject, &vObjDims, pServerDE->GetModelAnimation(m_hObject)) == DE_INVALIDPARAMS) pServerDE->DebugOut("CalculateHitLimb() f****d up\r\n"); vTemp.x = (float)fabs(vDir.x); vTemp.y = (float)fabs(vDir.y); vTemp.z = (float)fabs(vDir.z); if(vTemp.x > vTemp.y && vTemp.x > vTemp.z) { fTemp = vObjDims.x / vTemp.x; } else if(vTemp.y > vTemp.x && vTemp.y > vTemp.z) { fTemp = vObjDims.y / vTemp.y; } else if(vTemp.z > vTemp.x && vTemp.z > vTemp.y) { fTemp = vObjDims.z / vTemp.z; } VEC_MULSCALAR(vNewShot,vDir,fTemp); VEC_ADD(vShot,vPos,vNewShot); DVector vC; VEC_SUB(vC,vShot,vPos); fX = 1 / VEC_DOT(vC,vC); fY = fX * -(VEC_DOT(vC,vPos)); for(int i = 0; i < NUM_STD_NODES; i++) { pServerDE->GetModelNodeHideStatus(m_hObject, szNodes[i], &bStatus); if(!bStatus) { DBOOL bRet = pServerDE->GetModelNodeTransform(m_hObject, szNodes[i], &vNodePos, &rRot); ft = VEC_DOT(vC,vNodePos) * fX + fY; if(ft >= 0.0f && ft <= 1.0f) { VEC_ADDSCALED(vZ,vPos,vC, ft); fNodeDist = VEC_DIST(vNodePos, vZ); if(fNodeDist < fDist && fNodeDist <= m_pAnim_Sound->m_fHitSpheres[i]) { fDist = fNodeDist; nNode = i; } } } } /* //Do we leave a pass through mark behind us? if(nNode != -1) { CWeapon *pW = m_pInventoryMgr->GetCurrentWeapon(); if(pW) { VEC_MULSCALAR(vTemp,vDir,-1.0f); // TODO: combine sparks with weaponFX GK 8/27 // pW->AddSparks(vPos, vTemp, fDamage * 2.0f, m_hObject, SURFTYPE_FLESH); // pW->AddBloodSpurt(vPos, vTemp, fDamage * 2.0f, m_hObject, SURFTYPE_FLESH); // Took this out - more efficient to send one message. GK 8/27 // vTemp.x *= -1.0f; // vTemp.z *= -1.0f; // pW->AddBloodSpurt(vPos, vTemp, fDamage * 2.0f, m_hObject, SURFTYPE_FLESH); IntersectQuery iq; IntersectInfo ii; // Set the intersection query values iq.m_Flags = INTERSECT_OBJECTS | IGNORE_NONSOLID; iq.m_FilterFn = DNULL; iq.m_pUserData = DNULL; VEC_COPY(iq.m_From, vPos); VEC_ADDSCALED(iq.m_To, vPos, vDir, 75.0f); // Apply a blood splat to the wall if(pServerDE->IntersectSegment(&iq, &ii) && (ii.m_hObject == pServerDE->GetWorldObject())) { // pW->AddImpact(WFX_BLOODSPLAT, ii.m_Point, vDir, ii.m_Plane.m_Normal, fDamage * 2.0f, // ii.m_hObject, SURFTYPE_FLESH); // pW->AddSparks(ii.m_Point, ii.m_Plane.m_Normal, fDamage * 2.0f, ii.m_hObject, SURFTYPE_FLESH); } } } */ return nNode; }
int evals_evecs(double eval[3], double evec[9], const double _M00, const double _M01, const double _M02, const double _M11, const double _M12, const double _M22) { double r0[3], r1[3], r2[3], crs[3], len, dot; double mean, norm, rnorm, Q, R, QQQ, D, theta, M00, M01, M02, M11, M12, M22; double epsilon = 1.0E-12; int roots; /* copy the given matrix elements */ M00 = _M00; M01 = _M01; M02 = _M02; M11 = _M11; M12 = _M12; M22 = _M22; /* ** subtract out the eigenvalue mean (will add back to evals later); ** helps with numerical stability */ mean = (M00 + M11 + M22)/3.0; M00 -= mean; M11 -= mean; M22 -= mean; /* ** divide out L2 norm of eigenvalues (will multiply back later); ** this too seems to help with stability */ norm = sqrt(M00*M00 + 2*M01*M01 + 2*M02*M02 + M11*M11 + 2*M12*M12 + M22*M22); rnorm = norm ? 1.0/norm : 1.0; M00 *= rnorm; M01 *= rnorm; M02 *= rnorm; M11 *= rnorm; M12 *= rnorm; M22 *= rnorm; /* this code is a mix of prior Teem code and ideas from Eberly's "Eigensystems for 3 x 3 Symmetric Matrices (Revisited)" */ Q = (M01*M01 + M02*M02 + M12*M12 - M00*M11 - M00*M22 - M11*M22)/3.0; QQQ = Q*Q*Q; R = (M00*M11*M22 + M02*(2*M01*M12 - M02*M11) - M00*M12*M12 - M01*M01*M22)/2.0; D = QQQ - R*R; if (D > epsilon) { /* three distinct roots- this is the most common case */ double mm, ss, cc; theta = atan2(sqrt(D), R)/3.0; mm = sqrt(Q); ss = sin(theta); cc = cos(theta); eval[0] = 2*mm*cc; eval[1] = mm*(-cc + sqrt(3.0)*ss); eval[2] = mm*(-cc - sqrt(3.0)*ss); roots = ROOT_THREE; /* else D is near enough to zero */ } else if (R < -epsilon || epsilon < R) { double U; /* one double root and one single root */ U = airCbrt(R); /* cube root function */ if (U > 0) { eval[0] = 2*U; eval[1] = -U; eval[2] = -U; } else { eval[0] = -U; eval[1] = -U; eval[2] = 2*U; } roots = ROOT_SINGLE_DOUBLE; } else { /* a triple root! */ eval[0] = eval[1] = eval[2] = 0.0; roots = ROOT_TRIPLE; } /* r0, r1, r2 are the vectors we manipulate to find the nullspaces of M - lambda*I */ VEC_SET(r0, 0.0, M01, M02); VEC_SET(r1, M01, 0.0, M12); VEC_SET(r2, M02, M12, 0.0); if (ROOT_THREE == roots) { r0[0] = M00 - eval[0]; r1[1] = M11 - eval[0]; r2[2] = M22 - eval[0]; nullspace1(evec+0, r0, r1, r2); r0[0] = M00 - eval[1]; r1[1] = M11 - eval[1]; r2[2] = M22 - eval[1]; nullspace1(evec+3, r0, r1, r2); r0[0] = M00 - eval[2]; r1[1] = M11 - eval[2]; r2[2] = M22 - eval[2]; nullspace1(evec+6, r0, r1, r2); } else if (ROOT_SINGLE_DOUBLE == roots) { if (eval[1] == eval[2]) { /* one big (eval[0]) , two small (eval[1,2]) */ r0[0] = M00 - eval[0]; r1[1] = M11 - eval[0]; r2[2] = M22 - eval[0]; nullspace1(evec+0, r0, r1, r2); r0[0] = M00 - eval[1]; r1[1] = M11 - eval[1]; r2[2] = M22 - eval[1]; nullspace2(evec+3, evec+6, r0, r1, r2); } else { /* two big (eval[0,1]), one small (eval[2]) */ r0[0] = M00 - eval[0]; r1[1] = M11 - eval[0]; r2[2] = M22 - eval[0]; nullspace2(evec+0, evec+3, r0, r1, r2); r0[0] = M00 - eval[2]; r1[1] = M11 - eval[2]; r2[2] = M22 - eval[2]; nullspace1(evec+6, r0, r1, r2); } } else { /* ROOT_TRIPLE == roots; use any basis for eigenvectors */ VEC_SET(evec+0, 1, 0, 0); VEC_SET(evec+3, 0, 1, 0); VEC_SET(evec+6, 0, 0, 1); } /* we always make sure its really orthonormal; keeping fixed the eigenvector associated with the largest-magnitude eigenvalue */ if (ABS(eval[0]) > ABS(eval[2])) { /* normalize evec+0 but don't move it */ VEC_NORM(evec+0, len); dot = VEC_DOT(evec+0, evec+3); VEC_SCL_SUB(evec+3, dot, evec+0); VEC_NORM(evec+3, len); dot = VEC_DOT(evec+0, evec+6); VEC_SCL_SUB(evec+6, dot, evec+0); dot = VEC_DOT(evec+3, evec+6); VEC_SCL_SUB(evec+6, dot, evec+3); VEC_NORM(evec+6, len); } else { /* normalize evec+6 but don't move it */ VEC_NORM(evec+6, len); dot = VEC_DOT(evec+6, evec+3); VEC_SCL_SUB(evec+3, dot, evec+6); VEC_NORM(evec+3, len); dot = VEC_DOT(evec+3, evec+0); VEC_SCL_SUB(evec+0, dot, evec+3); dot = VEC_DOT(evec+6, evec+0); VEC_SCL_SUB(evec+0, dot, evec+6); VEC_NORM(evec+0, len); } /* to be nice, make it right-handed */ VEC_CROSS(crs, evec+0, evec+3); if (0 > VEC_DOT(crs, evec+6)) { VEC_SCL(evec+6, -1); } /* multiply back by eigenvalue L2 norm */ eval[0] /= rnorm; eval[1] /= rnorm; eval[2] /= rnorm; /* add back in the eigenvalue mean */ eval[0] += mean; eval[1] += mean; eval[2] += mean; return roots; }