Example #1
0
void idSimpleWindow::SetupTransforms( float x, float y )
{
	static idMat3 trans;
	static idVec3 org;
	
	trans.Identity();
	org.Set( origin.x + x, origin.y + y, 0 );
	if( rotate )
	{
		static idRotation rot;
		static idVec3 vec( 0, 0, 1 );
		rot.Set( org, vec, rotate );
		trans = rot.ToMat3();
	}
	
	static idMat3 smat;
	smat.Identity();
	if( shear.x() || shear.y() )
	{
		smat[0][1] = shear.x();
		smat[1][0] = shear.y();
		trans *= smat;
	}
	
	if( !trans.IsIdentity() )
	{
		dc->SetTransformInfo( org, trans );
	}
}
/*
================
idPhysics_Static::Rotate
================
*/
void idPhysics_Static::Rotate( const idRotation& rotation, int id )
{
	idVec3 masterOrigin;
	idMat3 masterAxis;
	
	current.origin *= rotation;
	current.axis *= rotation.ToMat3();
	
	if( hasMaster )
	{
		self->GetMasterPosition( masterOrigin, masterAxis );
		current.localAxis *= rotation.ToMat3();
		current.localOrigin = ( current.origin - masterOrigin ) * masterAxis.Transpose();
	}
	else
	{
		current.localAxis = current.axis;
		current.localOrigin = current.origin;
	}
	
	if( clipModel )
	{
		clipModel->Link( gameLocal.clip, self, 0, current.origin, current.axis );
	}
}
/*
================
idPhysics_StaticMulti::Rotate
================
*/
void idPhysics_StaticMulti::Rotate( const idRotation& rotation, int id )
{
	int i;
	idVec3 masterOrigin;
	idMat3 masterAxis;
	
	if( id >= 0 && id < clipModels.Num() )
	{
		current[id].origin *= rotation;
		current[id].axis *= rotation.ToMat3();
		
		if( hasMaster )
		{
			self->GetMasterPosition( masterOrigin, masterAxis );
			current[id].localAxis *= rotation.ToMat3();
			current[id].localOrigin = ( current[id].origin - masterOrigin ) * masterAxis.Transpose();
		}
		else
		{
			current[id].localAxis = current[id].axis;
			current[id].localOrigin = current[id].origin;
		}
		
		if( clipModels[id] )
		{
			clipModels[id]->Link( gameLocal.clip, self, id, current[id].origin, current[id].axis );
		}
	}
	else if( id == -1 )
	{
		for( i = 0; i < clipModels.Num(); i++ )
		{
			current[i].origin *= rotation;
			current[i].axis *= rotation.ToMat3();
			
			if( hasMaster )
			{
				self->GetMasterPosition( masterOrigin, masterAxis );
				current[i].localAxis *= rotation.ToMat3();
				current[i].localOrigin = ( current[i].origin - masterOrigin ) * masterAxis.Transpose();
			}
			else
			{
				current[i].localAxis = current[i].axis;
				current[i].localOrigin = current[i].origin;
			}
			
			if( clipModels[i] )
			{
				clipModels[i]->Link( gameLocal.clip, self, i, current[i].origin, current[i].axis );
			}
		}
	}
}
Example #4
0
/*
============
idBounds::FromPointRotation

  Most tight bounds for the rotational movement of the given point.
============
*/
void idBounds::FromPointRotation( const idVec3 &point, const idRotation &rotation ) {
	float radius;

	if ( idMath::Fabs( rotation.GetAngle() ) < 180.0f ) {
		(*this) = BoundsForPointRotation( point, rotation );
	}
	else {

		radius = ( point - rotation.GetOrigin() ).Length();

		// FIXME: these bounds are usually way larger
		b[0].Set( -radius, -radius, -radius );
		b[1].Set( radius, radius, radius );
	}
}
/*
================
idPhysics::Rotate
================
*/
void idPhysics_RigidBody::Rotate( const idRotation &rotation, int id ) {
	idVec3 masterOrigin;
	idMat3 masterAxis;
	current.i.orientation *= rotation.ToMat3();
	current.i.position *= rotation;
	if( hasMaster ) {
		self->GetMasterPosition( masterOrigin, masterAxis );
		current.localAxis *= rotation.ToMat3();
		current.localOrigin = ( current.i.position - masterOrigin ) * masterAxis.Transpose();
	} else {
		current.localAxis = current.i.orientation;
		current.localOrigin = current.i.position;
	}
	clipModel->Link( gameLocal.clip, self, clipModel->GetId(), current.i.position, current.i.orientation );
	Activate();
}
Example #6
0
/*
================
idPhysics_Monster::Rotate
================
*/
void idPhysics_Monster::Rotate( const idRotation &rotation, int id ) {
	idVec3 masterOrigin;
	idMat3 masterAxis;
	current.origin *= rotation;
	if( masterEntity ) {
		self->GetMasterPosition( masterOrigin, masterAxis );
		current.localOrigin = ( current.origin - masterOrigin ) * masterAxis.Transpose();
	} else {
		current.localOrigin = current.origin;
	}
	clipModel->Link( gameLocal.clip, self, 0, current.origin, clipModel->GetAxis() * rotation.ToMat3() );
	Activate();
}
Example #7
0
/*
============
idClip::Rotation
============
*/
bool idClip::Rotation( trace_t &results, const idVec3 &start, const idRotation &rotation,
					   const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity ) {
	int i, num;
	idClipModel *touch, *clipModelList[MAX_GENTITIES];
	idBounds traceBounds;
	trace_t trace;
	const idTraceModel *trm;
	trm = TraceModelForClipModel( mdl );
	if( !passEntity || passEntity->entityNumber != ENTITYNUM_WORLD ) {
		// test world
		idClip::numRotations++;
		collisionModelManager->Rotation( &results, start, rotation, trm, trmAxis, contentMask, 0, vec3_origin, mat3_default );
		results.c.entityNum = results.fraction != 1.0f ? ENTITYNUM_WORLD : ENTITYNUM_NONE;
		if( results.fraction == 0.0f ) {
			return true;		// blocked immediately by the world
		}
	} else {
		memset( &results, 0, sizeof( results ) );
		results.fraction = 1.0f;
		results.endpos = start;
		results.endAxis = trmAxis * rotation.ToMat3();
	}
	if( !trm ) {
		traceBounds.FromPointRotation( start, rotation );
	} else {
		traceBounds.FromBoundsRotation( trm->bounds, start, trmAxis, rotation );
	}
	num = GetTraceClipModels( traceBounds, contentMask, passEntity, clipModelList );
	for( i = 0; i < num; i++ ) {
		touch = clipModelList[i];
		if( !touch ) {
			continue;
		}
		// no rotational collision with render models
		if( touch->renderModelHandle != -1 ) {
			continue;
		}
		idClip::numRotations++;
		collisionModelManager->Rotation( &trace, start, rotation, trm, trmAxis, contentMask,
										 touch->Handle(), touch->origin, touch->axis );
		if( trace.fraction < results.fraction ) {
			results = trace;
			results.c.entityNum = touch->entity->entityNumber;
			results.c.id = touch->id;
			if( results.fraction == 0.0f ) {
				break;
			}
		}
	}
	return ( results.fraction < 1.0f );
}
Example #8
0
/*
================
BoundsForPointRotation

  only for rotations < 180 degrees
================
*/
idBounds BoundsForPointRotation( const idVec3 &start, const idRotation &rotation ) {
	int i;
	float radiusSqr;
	idVec3 v1, v2;
	idVec3 origin, axis, end;
	idBounds bounds;

	end = start * rotation;
	axis = rotation.GetVec();
	origin = rotation.GetOrigin() + axis * ( axis * ( start - rotation.GetOrigin() ) );
	radiusSqr = ( start - origin ).LengthSqr();
	v1 = ( start - origin ).Cross( axis );
	v2 = ( end - origin ).Cross( axis );

	for ( i = 0; i < 3; i++ ) {
		// if the derivative changes sign along this axis during the rotation from start to end
		if ( ( v1[i] > 0.0f && v2[i] < 0.0f ) || ( v1[i] < 0.0f && v2[i] > 0.0f ) ) {
			if ( ( 0.5f * (start[i] + end[i]) - origin[i] ) > 0.0f ) {
				bounds[0][i] = Min( start[i], end[i] );
				bounds[1][i] = origin[i] + idMath::Sqrt( radiusSqr * ( 1.0f - axis[i] * axis[i] ) );
			}
			else {
				bounds[0][i] = origin[i] - idMath::Sqrt( radiusSqr * ( 1.0f - axis[i] * axis[i] ) );
				bounds[1][i] = Max( start[i], end[i] );
			}
		}
		else if ( start[i] > end[i] ) {
			bounds[0][i] = end[i];
			bounds[1][i] = start[i];
		}
		else {
			bounds[0][i] = start[i];
			bounds[1][i] = end[i];
		}
	}

	return bounds;
}
Example #9
0
/*
============
idBounds::FromBoundsRotation

  Most tight bounds for the rotational movement of the given bounds.
============
*/
void idBounds::FromBoundsRotation( const idBounds &bounds, const idVec3 &origin, const idMat3 &axis, const idRotation &rotation ) {
	int i;
	float radius;
	idVec3 point;
	idBounds rBounds;

	if ( idMath::Fabs( rotation.GetAngle() ) < 180.0f ) {

		(*this) = BoundsForPointRotation( bounds[0] * axis + origin, rotation );
		for ( i = 1; i < 8; i++ ) {
			point[0] = bounds[(i^(i>>1))&1][0];
			point[1] = bounds[(i>>1)&1][1];
			point[2] = bounds[(i>>2)&1][2];
			(*this) += BoundsForPointRotation( point * axis + origin, rotation );
		}
	}
Example #10
0
/*
================
rvPhysics_Particle::Rotate(
================
*/
void rvPhysics_Particle::Rotate( const idRotation &rotation, int id ) {
	idVec3 masterOrigin;
	idMat3 masterAxis;

	current.origin *= rotation;
	if ( hasMaster ) {
		self->GetMasterPosition( masterOrigin, masterAxis );
		current.localOrigin = ( current.origin - masterOrigin ) * masterAxis.Transpose();
	}
	else {
		current.localOrigin = current.origin;
	}
// RAVEN BEGIN
// ddynerman: multiple clip worlds
	clipModel->Link( self, 0, current.origin, clipModel->GetAxis() * rotation.ToMat3() );
// RAVEN END
	Activate();
}
Example #11
0
/*
============
idClip::Motion
============
*/
bool idClip::Motion( trace_t &results, const idVec3 &start, const idVec3 &end, const idRotation &rotation,
					const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity ) {
	int i, num;
	idClipModel *touch, *clipModelList[MAX_GENTITIES];
	idVec3 dir, endPosition;
	idBounds traceBounds;
	float radius;
	trace_t translationalTrace, rotationalTrace, trace;
	idRotation endRotation;
	const idTraceModel *trm;

	assert( rotation.GetOrigin() == start );

	if ( TestHugeTranslation( results, mdl, start, end, trmAxis ) ) {
		return true;
	}

	if ( mdl != NULL && rotation.GetAngle() != 0.0f && rotation.GetVec() != vec3_origin ) {
		// if no translation
		if ( start == end ) {
			// pure rotation
			return Rotation( results, start, rotation, mdl, trmAxis, contentMask, passEntity );
		}
	} else if ( start != end ) {
		// pure translation
		return Translation( results, start, end, mdl, trmAxis, contentMask, passEntity );
	} else {
		// no motion
		results.fraction = 1.0f;
		results.endpos = start;
		results.endAxis = trmAxis;
		return false;
	}

	trm = TraceModelForClipModel( mdl );

	radius = trm->bounds.GetRadius();

	if ( !passEntity || passEntity->entityNumber != ENTITYNUM_WORLD ) {
		// translational collision with world
		idClip::numTranslations++;
		collisionModelManager->Translation( &translationalTrace, start, end, trm, trmAxis, contentMask, 0, vec3_origin, mat3_default );
		translationalTrace.c.entityNum = translationalTrace.fraction != 1.0f ? ENTITYNUM_WORLD : ENTITYNUM_NONE;
	} else {
		memset( &translationalTrace, 0, sizeof( translationalTrace ) );
		translationalTrace.fraction = 1.0f;
		translationalTrace.endpos = end;
		translationalTrace.endAxis = trmAxis;
	}

	if ( translationalTrace.fraction != 0.0f ) {

		traceBounds.FromBoundsRotation( trm->bounds, start, trmAxis, rotation );
		dir = translationalTrace.endpos - start;
		for ( i = 0; i < 3; i++ ) {
			if ( dir[i] < 0.0f ) {
				traceBounds[0][i] += dir[i];
			}
			else {
				traceBounds[1][i] += dir[i];
			}
		}

		num = GetTraceClipModels( traceBounds, contentMask, passEntity, clipModelList );

		for ( i = 0; i < num; i++ ) {
			touch = clipModelList[i];

			if ( !touch ) {
				continue;
			}

			if ( touch->renderModelHandle != -1 ) {
				idClip::numRenderModelTraces++;
				TraceRenderModel( trace, start, end, radius, trmAxis, touch );
			} else {
				idClip::numTranslations++;
				collisionModelManager->Translation( &trace, start, end, trm, trmAxis, contentMask,
										touch->Handle(), touch->origin, touch->axis );
			}

			if ( trace.fraction < translationalTrace.fraction ) {
				translationalTrace = trace;
				translationalTrace.c.entityNum = touch->entity->entityNumber;
				translationalTrace.c.id = touch->id;
				if ( translationalTrace.fraction == 0.0f ) {
					break;
				}
			}
		}
	} else {
		num = -1;
	}

	endPosition = translationalTrace.endpos;
	endRotation = rotation;
	endRotation.SetOrigin( endPosition );

	if ( !passEntity || passEntity->entityNumber != ENTITYNUM_WORLD ) {
		// rotational collision with world
		idClip::numRotations++;
		collisionModelManager->Rotation( &rotationalTrace, endPosition, endRotation, trm, trmAxis, contentMask, 0, vec3_origin, mat3_default );
		rotationalTrace.c.entityNum = rotationalTrace.fraction != 1.0f ? ENTITYNUM_WORLD : ENTITYNUM_NONE;
	} else {
		memset( &rotationalTrace, 0, sizeof( rotationalTrace ) );
		rotationalTrace.fraction = 1.0f;
		rotationalTrace.endpos = endPosition;
		rotationalTrace.endAxis = trmAxis * rotation.ToMat3();
	}

	if ( rotationalTrace.fraction != 0.0f ) {

		if ( num == -1 ) {
			traceBounds.FromBoundsRotation( trm->bounds, endPosition, trmAxis, endRotation );
			num = GetTraceClipModels( traceBounds, contentMask, passEntity, clipModelList );
		}

		for ( i = 0; i < num; i++ ) {
			touch = clipModelList[i];

			if ( !touch ) {
				continue;
			}

			// no rotational collision detection with render models
			if ( touch->renderModelHandle != -1 ) {
				continue;
			}

			idClip::numRotations++;
			collisionModelManager->Rotation( &trace, endPosition, endRotation, trm, trmAxis, contentMask,
								touch->Handle(), touch->origin, touch->axis );

			if ( trace.fraction < rotationalTrace.fraction ) {
				rotationalTrace = trace;
				rotationalTrace.c.entityNum = touch->entity->entityNumber;
				rotationalTrace.c.id = touch->id;
				if ( rotationalTrace.fraction == 0.0f ) {
					break;
				}
			}
		}
	}

	if ( rotationalTrace.fraction < 1.0f ) {
		results = rotationalTrace;
	} else {
		results = translationalTrace;
		results.endAxis = rotationalTrace.endAxis;
	}

	results.fraction = Max( translationalTrace.fraction, rotationalTrace.fraction );

	return ( translationalTrace.fraction < 1.0f || rotationalTrace.fraction < 1.0f );
}
Example #12
0
int idPush::TryRotatePushEntity( trace_t &results, idEntity *check, idClipModel *clipModel, const int flags,
											 const idMat3 &newAxis, const idRotation &rotation ) {
	trace_t trace;
	idVec3 rotationPoint;
	idRotation newRotation;
	float checkAngle;
	idPhysics *physics;

	physics = check->GetPhysics();

#ifdef ROTATIONAL_PUSH_DEBUG
	bool startsolid = false;
	if ( physics->ClipContents( clipModel ) ) {
		startsolid = true;
	}
#endif

	results.fraction = 1.0f;
	results.endpos = clipModel->GetOrigin();
	results.endAxis = newAxis;
	memset( &results.c, 0, sizeof( results.c ) );

	// always pushed when standing on the pusher
	if ( physics->IsGroundClipModel( clipModel->GetEntity()->entityNumber, clipModel->GetId() ) ) {
		// rotate the entity colliding with all other entities except the pusher itself
		ClipEntityRotation( trace, check, NULL, clipModel, rotation );
		// if there is a collision
		if ( trace.fraction < 1.0f ) {
			// angle along which the entity is pushed
			checkAngle = rotation.GetAngle() * trace.fraction;
			// test if the entity can stay at it's partly pushed position by rotating
			// the entity in reverse only colliding with pusher
			newRotation.Set( rotation.GetOrigin(), rotation.GetVec(), -(rotation.GetAngle() - checkAngle) );
			ClipEntityRotation( results, check, clipModel, NULL, newRotation );
			// if there is a collision
			if ( results.fraction < 1.0f ) {

				// FIXME: try to push the blocking entity as well or try to slide along collision plane(s)?

				results.c.normal = -results.c.normal;
				results.c.dist = -results.c.dist;

				// the entity will be crushed between the pusher and some other entity
				return PUSH_BLOCKED;
			}
		}
		else {
			// angle along which the entity is pushed
			checkAngle = rotation.GetAngle();
		}
		// point to rotate entity bbox around back to axial
		rotationPoint = physics->GetOrigin();
	}
	else {
		// rotate entity in reverse only colliding with pusher
		newRotation = rotation;
		newRotation.Scale( -1 );
		//
		ClipEntityRotation( results, check, clipModel, NULL, newRotation );
		// if no collision with the pusher then the entity is not pushed by the pusher
		if ( results.fraction >= 1.0f ) {
#ifdef ROTATIONAL_PUSH_DEBUG
			// set pusher into final position
			clipModel->Link( gameLocal.clip, clipModel->GetEntity(), clipModel->GetId(), clipModel->GetOrigin(), newAxis );
			if ( physics->ClipContents( clipModel ) ) {
				if ( !startsolid ) {
					int bah = 1;
				}
			}
#endif
			return PUSH_NO;
		}
		// get point to rotate bbox around back to axial
		rotationPoint = results.c.point;
		// angle along which the entity will be pushed
		checkAngle = rotation.GetAngle() * (1.0f - results.fraction);
		// rotate the entity colliding with all other entities except the pusher itself
		newRotation.Set( rotation.GetOrigin(), rotation.GetVec(), checkAngle );
		ClipEntityRotation( trace, check, NULL, clipModel, newRotation );
		// if there is a collision
		if ( trace.fraction < 1.0f ) {

			// FIXME: try to push the blocking entity as well or try to slide along collision plane(s)?

			results.c.normal = -results.c.normal;
			results.c.dist = -results.c.dist;

			// the entity will be crushed between the pusher and some other entity
			return PUSH_BLOCKED;
		}
	}

	SaveEntityPosition( check );

	newRotation.Set( rotation.GetOrigin(), rotation.GetVec(), checkAngle );
	// NOTE:	this code prevents msvc 6.0 & 7.0 from screwing up the above code in
	//			release builds moving less floats than it should
	static float shit = checkAngle;
	#pragma unused(shit)

	newRotation.RotatePoint( rotationPoint );

	// rotate the entity
	physics->Rotate( newRotation );

	// set pusher into final position
	clipModel->Link( gameLocal.clip, clipModel->GetEntity(), clipModel->GetId(), clipModel->GetOrigin(), newAxis );

#ifdef ROTATIONAL_PUSH_DEBUG
	if ( physics->ClipContents( clipModel ) ) {
		if ( !startsolid ) {
			int bah = 1;
		}
	}
#endif

	// if the entity uses actor physics
	if ( physics->IsType( idPhysics_Actor::Type ) ) {

		// rotate the collision model back to axial
		if ( !RotateEntityToAxial( check, rotationPoint ) ) {
			// don't allow rotation if the bbox is no longer axial
			return PUSH_BLOCKED;
		}
	}

#ifdef ROTATIONAL_PUSH_DEBUG
	if ( physics->ClipContents( clipModel ) ) {
		if ( !startsolid ) {
			int bah = 1;
		}
	}
#endif

	// if the entity is an actor using actor physics
	if ( check->IsType( idActor::Type ) && physics->IsType( idPhysics_Actor::Type ) ) {

		// if the entity is standing ontop of the pusher
		if ( physics->IsGroundClipModel( clipModel->GetEntity()->entityNumber, clipModel->GetId() ) ) {
			// rotate actor view
			idActor *actor = static_cast<idActor *>(check);
			idAngles delta = actor->GetDeltaViewAngles();
			delta.yaw += newRotation.ToMat3()[0].ToYaw();
			actor->SetDeltaViewAngles( delta );
		}
	}

	return PUSH_OK;
}
Example #13
0
/*
============
idPush::ClipRotationalPush

  Try to push other entities by rotating the given entity.
============
*/
float idPush::ClipRotationalPush( trace_t &results, idEntity *pusher, const int flags,
									const idMat3 &newAxis, const idRotation &rotation ) {
	int i, j, numListedEntities;
	idEntity *curPusher, *ent, *entityList[ MAX_GENTITIES ];
	float fraction;
	bool groundContact, blocked = false;
	float totalMass;
	trace_t trace;
	idRotation realRotation, partialRotation;
	idMat3 oldAxis;

	totalMass = 0.0f;

	results.fraction = 1.0f;
	results.endpos = pusher->GetPhysics()->GetOrigin();
	results.endAxis = newAxis;
	memset( results.c, 0, sizeof( results.c ) );

	if ( !rotation.GetAngle() ) {
		return totalMass;
	}

	// clip against all non-pushable physics objects
	if ( flags & PUSHFL_CLIP ) {

		numListedEntities = GetPushableEntitiesForRotation( pusher, pusher, flags, rotation, entityList, MAX_GENTITIES );
		// disable pushable entities for collision detection
		for ( i = 0; i < numListedEntities; i++ ) {
			entityList[i]->GetPhysics()->DisableClip();
		}
		// clip rotation
		pusher->GetPhysics()->ClipRotation( results, rotation, NULL );
		// enable pushable entities
		for ( i = 0; i < numListedEntities; i++ ) {
			entityList[i]->GetPhysics()->EnableClip();
		}
		if ( results.fraction == 0.0f ) {
			return totalMass;
		}
		realRotation = results.fraction * rotation;
	}
	else {
		realRotation = rotation;
	}

	// put the pusher in the group of pushed physics objects
	pushedGroup[0].ent = pusher;
	pushedGroup[0].fraction = 1.0f;
	pushedGroup[0].groundContact = true;
	pushedGroup[0].test = true;
	pushedGroupSize = 1;

	// get all physics objects that need to be pushed
	for ( i = 0; i < pushedGroupSize; ) {
		if ( !pushedGroup[i].test ) {
			i++;
			continue;
		}
		pushedGroup[i].test = false;
		curPusher = pushedGroup[i].ent;
		fraction = pushedGroup[i].fraction;
		groundContact = pushedGroup[i].groundContact;
		i = 0;

		numListedEntities = GetPushableEntitiesForRotation( curPusher, pusher, flags, realRotation, entityList, MAX_GENTITIES );

		for ( j = 0; j < numListedEntities; j++ ) {
			ent = entityList[ j ];

			if ( IsFullyPushed( ent ) ) {
				continue;
			}

			if ( ent->GetPhysics()->IsGroundEntity( curPusher->entityNumber ) ) {
				AddEntityToPushedGroup( ent, 1.0f * fraction, false );
			}
			else if ( ClipRotationAgainstPusher( trace, ent, curPusher, -fraction * realRotation ) ) {
				AddEntityToPushedGroup( ent, ( 1.0f - trace.fraction ) * fraction, groundContact );
			}
		}
	}

	// save physics states and disable physics objects for collision detection
	for ( i = 1; i < pushedGroupSize; i++ ) {
		SaveEntityPosition( pushedGroup[i].ent );
		pushedGroup[i].ent->GetPhysics()->DisableClip();
	}

	// clip all pushed physics objects
	for ( i = 1; i < pushedGroupSize; i++ ) {
		partialRotation = realRotation * pushedGroup[i].fraction;

		pushedGroup[i].ent->GetPhysics()->ClipRotation( trace, partialRotation, NULL );

		if ( trace.fraction < 1.0f ) {
			blocked = true;
			break;
		}
	}

	// enable all physics objects for collision detection
	for ( i = 1; i < pushedGroupSize; i++ ) {
		pushedGroup[i].ent->GetPhysics()->EnableClip();
	}

	// push all or nothing
	if ( blocked ) {
		if ( flags & PUSHFL_CLIP ) {
			pusher->GetPhysics()->ClipRotation( results, realRotation, NULL );
		}
		else {
			results.fraction = 0.0f;
			results.endpos = pusher->GetPhysics()->GetOrigin();
			results.endAxis = pusher->GetPhysics()->GetAxis();
		}
	}
	else {
		// rotate all pushed physics objects
		for ( i = 1; i < pushedGroupSize; i++ ) {
			partialRotation = realRotation * pushedGroup[i].fraction;
			pushedGroup[i].ent->GetPhysics()->Rotate( partialRotation );
			totalMass += pushedGroup[i].ent->GetPhysics()->GetMass();
		}
		// rotate the clip models of the pusher
		for ( i = 0; i < pusher->GetPhysics()->GetNumClipModels(); i++ ) {
			pusher->GetPhysics()->GetClipModel(i)->Rotate( realRotation );
			pusher->GetPhysics()->GetClipModel(i)->Link( gameLocal.clip );
			pusher->GetPhysics()->GetClipModel(i)->Enable();
		}
		// rotate any actors back to axial
		for ( i = 1; i < pushedGroupSize; i++ ) {
			// if the entity is using actor physics
			if ( pushedGroup[i].ent->GetPhysics()->IsType( idPhysics_Actor::Type ) ) {

				// rotate the collision model back to axial
				if ( !RotateEntityToAxial( pushedGroup[i].ent, pushedGroup[i].ent->GetPhysics()->GetOrigin() ) ) {
					// don't allow rotation if the bbox is no longer axial
					results.fraction = 0.0f;
					results.endpos = pusher->GetPhysics()->GetOrigin();
					results.endAxis = pusher->GetPhysics()->GetAxis();
				}
			}
		}
	}

	return totalMass;
}
Example #14
0
/*
============
idPush::ClipRotationalPush

  Try to push other entities by moving the given entity.
============
*/
float idPush::ClipRotationalPush( trace_t &results, idEntity *pusher, const int flags,
									const idMat3 &newAxis, const idRotation &rotation ) {
	int			i, listedEntities, res;
	idEntity	*check, *entityList[ MAX_GENTITIES ];
	idBounds	bounds, pushBounds;
	idRotation	clipRotation;
	idMat3		clipAxis, oldAxis;
	trace_t		pushResults;
	bool		wasEnabled;
	float		totalMass;
	idClipModel *clipModel;

	clipModel = pusher->GetPhysics()->GetClipModel();

	totalMass = 0.0f;

	results.fraction = 1.0f;
	results.endpos = clipModel->GetOrigin();
	results.endAxis = newAxis;
	memset( &results.c, 0, sizeof( results.c ) );

	if ( !rotation.GetAngle() ) {
		return totalMass;
	}

	// get bounds for the whole movement
	bounds = clipModel->GetBounds();
	if ( bounds[0].x >= bounds[1].x ) {
		return totalMass;
	}
	pushBounds.FromBoundsRotation( bounds, clipModel->GetOrigin(), clipModel->GetAxis(), rotation );

	wasEnabled = clipModel->IsEnabled();

	// make sure we don't get the pushing clip model in the list
	clipModel->Disable();

	listedEntities = gameLocal.clip.EntitiesTouchingBounds( pushBounds, -1, entityList, MAX_GENTITIES );

	// discard entities we cannot or should not push
	listedEntities = DiscardEntities( entityList, listedEntities, flags, pusher );

	if ( flags & PUSHFL_CLIP ) {

		// can only clip movement of a trace model
		assert( clipModel->IsTraceModel() );

		// disable to be pushed entities for collision detection
		for ( i = 0; i < listedEntities; i++ ) {
			entityList[i]->GetPhysics()->DisableClip();
		}

		gameLocal.clip.Rotation( results, clipModel->GetOrigin(), rotation, clipModel, clipModel->GetAxis(), pusher->GetPhysics()->GetClipMask(), NULL );

		// enable to be pushed entities for collision detection
		for ( i = 0; i < listedEntities; i++ ) {
			entityList[i]->GetPhysics()->EnableClip();
		}

		if ( results.fraction == 0.0f ) {
			if ( wasEnabled ) {
				clipModel->Enable();
			}
			return totalMass;
		}

		clipRotation = rotation * results.fraction;
		clipAxis = results.endAxis;
	}
	else {

		clipRotation = rotation;
		clipAxis = newAxis;
	}

	// we have to enable the clip model because we use it during pushing
	clipModel->Enable();

	// save pusher old position
	oldAxis = clipModel->GetAxis();

	// try to push all the entities
	for ( i = 0; i < listedEntities; i++ ) {

		check = entityList[ i ];

		idPhysics *physics = check->GetPhysics();

		// disable the entity for collision detection
		physics->DisableClip();

		res = TryRotatePushEntity( pushResults, check, clipModel, flags, clipAxis, clipRotation );

		// enable the entity for collision detection
		physics->EnableClip();

		// if the entity is pushed
		if ( res == PUSH_OK ) {
			// set the pusher in the rotated position
			clipModel->Link( gameLocal.clip, clipModel->GetEntity(), clipModel->GetId(), clipModel->GetOrigin(), newAxis );
			// the entity might be pushed off the ground
			physics->EvaluateContacts();
			// put pusher back in old position
			clipModel->Link( gameLocal.clip, clipModel->GetEntity(), clipModel->GetId(), clipModel->GetOrigin(), oldAxis );

			// wake up this object
			check->ApplyImpulse( clipModel->GetEntity(), clipModel->GetId(), clipModel->GetOrigin(), vec3_origin );

			// add mass of pushed entity
			totalMass += physics->GetMass();
		}

		// if the entity is not blocking
		if ( res != PUSH_BLOCKED ) {
			continue;
		}

		// if the blocking entity is a projectile
		if ( check->IsType( idProjectile::Type ) ) {
			check->ProcessEvent( &EV_Explode );
			continue;
		}

		// if blocking entities should be crushed
		if ( flags & PUSHFL_CRUSH ) {
			check->Damage( clipModel->GetEntity(), clipModel->GetEntity(), vec3_origin, "damage_crush", 1.0f, CLIPMODEL_ID_TO_JOINT_HANDLE( pushResults.c.id ) );
			continue;
		}

		// if the entity is an active articulated figure and gibs
		if ( check->IsType( idAFEntity_Base::Type ) && check->spawnArgs.GetBool( "gib" ) ) {
			if ( static_cast<idAFEntity_Base *>(check)->IsActiveAF() ) {
				check->ProcessEvent( &EV_Gib, "damage_Gib" );
			}
		}

		// blocked
		results = pushResults;
		results.fraction = 0.0f;
		results.endAxis = clipModel->GetAxis();
		results.endpos = clipModel->GetOrigin();
		results.c.entityNum = check->entityNumber;
		results.c.id = 0;

		if ( !wasEnabled ) {
			clipModel->Disable();
		}

		return totalMass;
	}

	if ( !wasEnabled ) {
		clipModel->Disable();
	}

	return totalMass;
}
void idCollisionModelManagerLocal::Rotation( trace_t *results, const idVec3 &start, const idRotation &rotation,
										const idTraceModel *trm, const idMat3 &trmAxis, int contentMask,
										cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis ) {
	idVec3 tmp;
	float maxa, stepa, a, lasta;

	assert( ((byte *)&start) < ((byte *)results) || ((byte *)&start) > (((byte *)results) + sizeof( trace_t )) );
	assert( ((byte *)&trmAxis) < ((byte *)results) || ((byte *)&trmAxis) > (((byte *)results) + sizeof( trace_t )) );

	memset( results, 0, sizeof( *results ) );

	// if special position test
	if ( rotation.GetAngle() == 0.0f ) {
		idCollisionModelManagerLocal::ContentsTrm( results, start, trm, trmAxis, contentMask, model, modelOrigin, modelAxis );
		return;
	}

#ifdef _DEBUG
	bool startsolid = false;
	// test whether or not stuck to begin with
	if ( cm_debugCollision.GetBool() ) {
		if ( !entered ) {
			entered = 1;
			// if already messed up to begin with
			if ( idCollisionModelManagerLocal::Contents( start, trm, trmAxis, -1, model, modelOrigin, modelAxis ) & contentMask ) {
				startsolid = true;
			}
			entered = 0;
		}
	}
#endif

	if ( rotation.GetAngle() >= 180.0f || rotation.GetAngle() <= -180.0f) {
		if ( rotation.GetAngle() >= 360.0f ) {
			maxa = 360.0f;
			stepa = 120.0f;			// three steps strictly < 180 degrees
		} else if ( rotation.GetAngle() <= -360.0f ) {
			maxa = -360.0f;
			stepa = -120.0f;		// three steps strictly < 180 degrees
		} else {
			maxa = rotation.GetAngle();
			stepa = rotation.GetAngle() * 0.5f;	// two steps strictly < 180 degrees
		}
		for ( lasta = 0.0f, a = stepa; fabs( a ) < fabs( maxa ) + 1.0f; lasta = a, a += stepa ) {
			// partial rotation
			idCollisionModelManagerLocal::Rotation180( results, rotation.GetOrigin(), rotation.GetVec(), lasta, a, start, trm, trmAxis, contentMask, model, modelOrigin, modelAxis );
			// if there is a collision
			if ( results->fraction < 1.0f ) {
				// fraction of total rotation
				results->fraction = (lasta + stepa * results->fraction) / rotation.GetAngle();
				return;
			}
		}
		results->fraction = 1.0f;
		return;
	}

	idCollisionModelManagerLocal::Rotation180( results, rotation.GetOrigin(), rotation.GetVec(), 0.0f, rotation.GetAngle(), start, trm, trmAxis, contentMask, model, modelOrigin, modelAxis );

#ifdef _DEBUG
	// test for missed collisions
	if ( cm_debugCollision.GetBool() ) {
		if ( !entered ) {
			entered = 1;
			// if the trm is stuck in the model
			if ( idCollisionModelManagerLocal::Contents( results->endpos, trm, results->endAxis, -1, model, modelOrigin, modelAxis ) & contentMask ) {
				trace_t tr;

				// test where the trm is stuck in the model
				idCollisionModelManagerLocal::Contents( results->endpos, trm, results->endAxis, -1, model, modelOrigin, modelAxis );
				// re-run collision detection to find out where it failed
				idCollisionModelManagerLocal::Rotation( &tr, start, rotation, trm, trmAxis, contentMask, model, modelOrigin, modelAxis );
			}
			entered = 0;
		}
	}
#endif
}
Example #16
0
/*
============
idPush::ClipRotationalPush

  Try to push other entities by moving the given entity.
============
*/
float idPush::ClipRotationalPush( trace_t &results, idEntity *pusher, const int flags,
									const idMat3 &newAxis, const idRotation &rotation, idClipModel * clipModel ) {
	int			i, listedEntities, res;
	idEntity	*check, *entityList[ MAX_GENTITIES ];
	idBounds	bounds, pushBounds;
	idRotation	clipRotation;
	idMat3		clipAxis, oldAxis;
	trace_t		pushResults;
	bool		wasEnabled;
	float		totalMass;

	totalMass = 0.0f;

	results.fraction = 1.0f;
	results.endpos = clipModel->GetOrigin();
	results.endAxis = newAxis;
	memset( &results.c, 0, sizeof( results.c ) );

	if ( !rotation.GetAngle() ) {
		return totalMass;
	}

	// get bounds for the whole movement
	bounds = clipModel->GetBounds();
	if ( bounds[0].x >= bounds[1].x ) {
		return totalMass;
	}
	pushBounds.FromBoundsRotation( bounds, clipModel->GetOrigin(), clipModel->GetAxis(), rotation );

	wasEnabled = clipModel->GetContents() != 0;

	// make sure we don't get the pushing clip model in the list
	clipModel->Disable();

	listedEntities = gameLocal.clip.EntitiesTouchingBounds( pushBounds, -1, entityList, MAX_GENTITIES );

	// discard entities we cannot or should not push
	listedEntities = DiscardEntities( entityList, listedEntities, flags, pusher, clipModel->GetRealContents() );

	if ( flags & PUSHFL_CLIP ) {

		// can only clip movement of a trace model
		assert( clipModel->IsTraceModel() );

		// disable to be pushed entities for collision detection
		for ( i = 0; i < listedEntities; i++ ) {
			entityList[ i ]->DisableClip( false );
		}

		gameLocal.clip.Rotation( CLIP_DEBUG_PARMS results, clipModel->GetOrigin(), rotation, clipModel, clipModel->GetAxis(), pusher->GetPhysics()->GetClipMask(), NULL );

		// enable to be pushed entities for collision detection
		for ( i = 0; i < listedEntities; i++ ) {
			entityList[ i ]->EnableClip();
		}

		if ( results.fraction == 0.0f ) {
			if ( wasEnabled ) {
				clipModel->Enable();
			}
			return totalMass;
		}

		clipRotation = rotation * results.fraction;
		clipAxis = results.endAxis;
	}
	else {

		clipRotation = rotation;
		clipAxis = newAxis;
	}

	// we have to enable the clip model because we use it during pushing
	clipModel->Link( gameLocal.clip );

	// save pusher old position
	oldAxis = clipModel->GetAxis();

	// try to push all the entities
	for ( i = 0; i < listedEntities; i++ ) {

		check = entityList[ i ];

		idPhysics *physics = check->GetPhysics();

		// disable the entity for collision detection
		check->DisableClip( false );

		res = TryRotatePushEntity( pushResults, check, clipModel, flags, clipAxis, clipRotation );

		// enable the entity for collision detection
		check->EnableClip();

		// if the entity is pushed
		if ( res == PUSH_OK ) {
			// set the pusher in the rotated position
			clipModel->Link( gameLocal.clip, clipModel->GetEntity(), clipModel->GetId(), clipModel->GetOrigin(), newAxis );
			// the entity might be pushed off the ground
			physics->EvaluateContacts( CLIP_DEBUG_PARMS_ONLY );
			// put pusher back in old position
			clipModel->Link( gameLocal.clip, clipModel->GetEntity(), clipModel->GetId(), clipModel->GetOrigin(), oldAxis );

			// wake up this object
			check->ApplyImpulse( clipModel->GetEntity(), clipModel->GetId(), clipModel->GetOrigin(), vec3_origin );

			// add mass of pushed entity
			totalMass += physics->GetMass();
		}

		// if the entity is not blocking
		if ( res != PUSH_BLOCKED ) {
			continue;
		}

		// if blocking entities should be crushed
		if ( flags & PUSHFL_CRUSH ) {
			check->Damage( clipModel->GetEntity(), clipModel->GetEntity(), vec3_origin, DAMAGE_FOR_NAME( "damage_crush" ), 1.0f, &pushResults );
			continue;
		}

		// blocked
		results = pushResults;
		results.fraction = 0.0f;
		results.endAxis = clipModel->GetAxis();
		results.endpos = clipModel->GetOrigin();
		results.c.entityNum = check->entityNumber;
		results.c.id = 0;

		if ( !wasEnabled ) {
			clipModel->Disable();
		}

		return totalMass;
	}

	if ( !wasEnabled ) {
		clipModel->Disable();
	}

	return totalMass;
}