Beispiel #1
0
/*
** 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;
}
Beispiel #2
0
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);
}
Beispiel #3
0
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;
}
Beispiel #4
0
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;
}
Beispiel #5
0
/*
** 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;
}
Beispiel #6
0
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;
	*/
}
Beispiel #8
0
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;
}
Beispiel #10
0
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);
}
Beispiel #11
0
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;
}
Beispiel #12
0
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();
}
Beispiel #14
0
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 :)
}
Beispiel #15
0
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);
    }
}
Beispiel #17
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( );
		}
	}
}
Beispiel #18
0
/********************************************************
 * 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);
}
Beispiel #19
0
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;
}
Beispiel #20
0
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;
}