// C++ Implementation: XMLHelper
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "XMLHelper.h"
#include <OgreVector.h>

namespace Ember {
namespace OgreView {

bool XMLHelper::Load(TiXmlDocument& xmlDoc, Ogre::DataStreamPtr stream) {
	size_t length(stream->size());

	if (length) {
		// If we have a file, assume it is all one big XML file, and read it in.
		// The document parser may decide the document ends sooner than the entire file, however.
		std::string data(stream->getAsString());

		xmlDoc.Parse(data.c_str());

		if (xmlDoc.Error()) {
			std::string errorDesc = xmlDoc.ErrorDesc();
			int errorLine = xmlDoc.ErrorRow();
			int errorColumn = xmlDoc.ErrorCol();
			std::stringstream ss;
			ss << "Failed to load xml file '" << stream->getName() << "'! Error at column: " << errorColumn << " line: " << errorLine << ". Error message: " << errorDesc;
			S_LOG_FAILURE(ss.str());
			return false;
		} else {
			return true;
		}
	}
	return false;
}

bool XMLHelper::Load(TiXmlDocument& xmlDoc, std::istream& stream, const boost::filesystem::path& path) {
	stream >> xmlDoc;

	if (xmlDoc.Error()) {
		std::string errorDesc = xmlDoc.ErrorDesc();
		int errorLine = xmlDoc.ErrorRow();
		int errorColumn = xmlDoc.ErrorCol();
		std::stringstream ss;
		ss << "Failed to load xml file '" << path << "'! Error at column: " << errorColumn << " line: " << errorLine << ". Error message: " << errorDesc;
		S_LOG_FAILURE(ss.str());
		return false;
	} else {
		return true;
	}
}

Ogre::Vector3 XMLHelper::fillVector3FromElement(TiXmlElement* elem) {
	Ogre::Real x = 0.0f, y = 0.0f, z = 0.0f;
	if (elem->Attribute("x")) {
		x = std::stof(elem->Attribute("x"));
	}
	if (elem->Attribute("y")) {
		y = std::stof(elem->Attribute("y"));
	}
	if (elem->Attribute("z")) {
		z = std::stof(elem->Attribute("z"));
	}

	return {x, y, z};
}

void XMLHelper::fillElementFromVector3(TiXmlElement& elem, const Ogre::Vector3& vector) {
	elem.SetDoubleAttribute("x", vector.x);
	elem.SetDoubleAttribute("y", vector.y);
	elem.SetDoubleAttribute("z", vector.z);
}

Ogre::Quaternion XMLHelper::fillQuaternionFromElement(TiXmlElement* elem) {
	Ogre::Vector3 vector = fillVector3FromElement(elem);
	vector.normalise();
	Ogre::Degree degrees;
	//first check if degrees is specified, but also allow for radians to be specified
	if (elem->Attribute("degrees")) {
		degrees = std::stof(elem->Attribute("degrees"));
	} else if (elem->Attribute("radians")) {
		degrees = Ogre::Radian(std::stof(elem->Attribute("radians")));
	}
	Ogre::Quaternion q(degr

	if (q.isNaN()) {
		S_LOG_WARNING("Reading rotation resulted in invalid quaternion.");
	}
	return q;

}

void XMLHelper::fillElementFromQuaternion(TiXmlElement& elem, const Ogre::Quaternion& quaternion) {
	//split the quaternion into an axis and a degree (our format allows us to store the angle element as a radian too, but I prefer degrees)
	Ogre::Degree degrees;
	Ogre::Vector3 axis;
	quaternion.ToAngleAxis(degrees, axis);
	fillElementFromVector3(elem, axis);
	elem.SetDoubleAttribute("degrees", degrees.valueDegrees());
}

}
}


float CalculateObjectStress( IPhysicsObject *pObject, CBaseEntity *pInputOwnerEntity, vphysics_objectstress_t *pOutput )

#include "cbase.h"
#include "physics_impact_damage.h"
#include "shareddefs.h"
#include "vphysics/friction.h"
#include "vphysics/player_controller.h"
#include "world.h"

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

// PLAYER PHYSICS DAMAGE TABLE
static impactentry_t playerLinearTable[] =
{
	{ 150*150, 5 },
	{ 250*250, 10 },
	{ 450*450, 20 },
	{ 550*550, 50 },
	{ 700*700, 100 },
	{ 1000*1000, 500 },
};

static impactentry_t playerAngularTable[] =
{
	{ 100*100, 10 },
	{ 150*150, 20 },
	{ 200*200, 50 },
	{ 300*300, 500 },
};

impactdamagetable_t gDefaultPlayerImpactDamageTable =
{
	playerLinearTable,
	playerAngularTable,

	ARRAYSIZE(playerLinearTable),
	ARRAYSIZE(playerAngularTable),

	24*24.0f,	// minimum linear speed
	360*360.0f,	// minimum angular speed
	2.0f,		// can't take damage from anything under 2kg

	5.0f,		// anything less than 5kg is "small"
	5.0f,		// never take more than 5 pts of damage from anything under 5kg
	36*36.0f,	// <5kg objects must go faster than 36 in/s to do damage

	0.0f,		// large mass in kg (no large mass effects)
	1.0f,		// large mass scale
	2.0f,		// large mass falling scale
	320.0f,		// min velocity for player speed to cause damage

};

// PLAYER-IN-VEHICLE PHYSICS DAMAGE TABLE
static impactentry_t playerVehicleLinearTable[] =
{
	{ 450*450, 5 },
	{ 600*600, 10 },
	{ 700*700, 25 },
	{ 1000*1000, 50 },
	{ 1500*1500, 100 },
	{ 2000*2000, 500 },
};

static impactentry_t playerVehicleAngularTable[] =
{
	{ 100*100, 10 },
	{ 150*150, 20 },
	{ 200*200, 50 },
	{ 300*300, 500 },
};

impactdamagetable_t gDefaultPlayerVehicleImpactDamageTable =
{
	playerVehicleLinearTable,
	playerVehicleAngularTable,

	ARRAYSIZE(playerVehicleLinearTable),
	ARRAYSIZE(playerVehicleAngularTable),

	24*24,		// minimum linear speed
	360*360,	// minimum angular speed
	80,			// can't take damage from anything under 80 kg

	150,		// anything less than 150kg is "small"
	5,			// never take more than 5 pts of damage from anything under 150kg
	36*36,		// <150kg objects must go faster than 36 in/s to do damage

	0,			// large mass in kg (no large mass effects)
	1.0f,		// large mass scale
	1.0f,		// large mass falling scale
	0.0f,		// min vel
};

// NPC PHYSICS DAMAGE TABLE
static impactentry_t npcLinearTable[] =
{
	{ 150*150, 5 },
	{ 250*250, 10 },
	{ 350*350, 50 },
	{ 500*500, 100 },
	{ 1000*1000, 500 },
};

static impactentry_t npcAngularTable[] =
{
	{ 100*100, 10 },
	{ 150*150, 25 },
	{ 200*200, 50 },
	{ 250*250, 500 },
};

impactdamagetable_t gDefaultNPCImpactDamageTable =
{
	npcLinearTable,
	npcAngularTable,

	ARRAYSIZE(npcLinearTable),
	ARRAYSIZE(npcAngularTable),

	24*24,		// minimum linear speed squared
	360*360,	// minimum angular speed squared (360 deg/s to cause spin/slice damage)
	2,			// can't take damage from anything under 2kg

	5,			// anything less than 5kg is "small"
	5,			// never take more than 5 pts of damage from anything under 5kg
	36*36,		// <5kg objects must go faster than 36 in/s to do damage

	VPHYSICS_LARGE_OBJECT_MASS,		// large mass in kg
	4,			// large mass scale (anything over 500kg does 4X as much energy to read from damage table)
	5,			// large mass falling scale (emphasize falling/crushing damage over sideways impacts since the stress will kill you anyway)
	0.0f,		// min vel
};

// GLASS DAMAGE TABLE
static impactentry_t glassLinearTable[] =
{
	{ 25*25, 10 },
	{ 50*50, 20 },
	{ 100*100, 50 },
	{ 200*200, 75 },
	{ 500*500, 100 },
	{ 250*250, 500 },
};

static impactentry_t glassAngularTable[] =
{
	{ 50*50, 25 },
	{ 100*100, 50 },
	{ 200*200, 100 },
	{ 250*250, 500 },
};

impactdamagetable_t gGlassImpactDamageTable =
{
	glassLinearTable,
	glassAngularTable,

	ARRAYSIZE(glassLinearTable),
	ARRAYSIZE(glassAngularTable),

	8*8,		// minimum linear speed squared
	360*360,	// minimum angular speed squared (360 deg/s to cause spin/slice damage)
	2,			// can't take damage from anything under 2kg

	1,			// anything less than 1kg is "small"
	10,			// never take more than 10 pts of damage from anything under 1kg
	8*8,		// <1kg objects must go faster than 8 in/s to do damage

	50,			// large mass in kg
	4,			// large mass scale (anything over 50kg does 4X as much energy to read from damage table)
	0.0f,		// min vel
};

// PHYSICS TABLE NAMES
struct damagetable_t
{
	const char			*pszTableName;
	impactdamagetable_t	*pTable;
};

static damagetable_t gDamageTableRegistry[] =
{
	{
		"player",
		&gDefaultPlayerImpactDamageTable,
	},
	{
		"player_vehicle",
		&gDefaultPlayerVehicleImpactDamageTable,
	},
	{
		"npc",
		&gDefaultNPCImpactDamageTable,
	},
	{
		"glass",
		&gGlassImpactDamageTable,
	},
};

float ReadDamageTable( impactentry_t *pTable, int tableCount, float impulse, bool bDebug )
{
	if ( pTable )
	{
		int i;
		for ( i = 0; i < tableCount; i++ )
		{
			if ( impulse < pTable[i].impulse )
				break;
		}
		if ( i > 0 )
		{
			i--;
			if ( bDebug )
			{
				Msg("Damage %.0f, energy %.0f\n", pTable[i].damage, FastSqrt(impulse) );
			}
			return pTable[i].damage;
		}
	}
	return 0;
}

float CalculatePhysicsImpactDamage( int index, gamevcollisionevent_t *pEvent, const impactdamagetable_t &table, float energyScale, bool allowStaticDamage, int &damageType, bool bDamageFromHeldObjects )
{
	damageType = DMG_CRUSH;
	int otherIndex = !index;

	// UNDONE: Expose a flag for self-inflicted damage?  Can't think of a valid case so far.
	if ( pEvent->pEntities[0] == pEvent->pEntities[1] )
		return 0;

	if ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_NO_NPC_IMPACT_DMG )
	{
		if( pEvent->pEntities[index]->IsNPC() || pEvent->pEntities[index]->IsPlayer() )
		{
			return 0;
		}
	}

	// use implicit velocities on ragdolls since they may have high constraint velocities that aren't actually executed, just pushed through contacts
	if (( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_PART_OF_RAGDOLL) && pEvent->pEntities[index]->IsPlayer() )
	{
		pEvent->pObjects[otherIndex]->GetImplicitVelocity( &pEvent->preVelocity[otherIndex], &pEvent->preAngularVelocity[otherIndex] );
	}

	// Dissolving impact damage results in death always.
	if ( ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_DMG_DISSOLVE ) &&
			!pEvent->pEntities[index]->IsEFlagSet(EFL_NO_DISSOLVE) )
	{
		damageType |= DMG_DISSOLVE;
		return 1000;
	}

	if ( energyScale <= 0.0f )
		return 0;

	const int gameFlagsNoDamage = FVPHYSICS_CONSTRAINT_STATIC | FVPHYSICS_NO_IMPACT_DMG;

	// NOTE: Crushing damage is handled by stress calcs in vphysics update functions, this is ONLY impact damage
	// this is a non-moving object due to a constraint - no damage
	if ( pEvent->pObjects[otherIndex]->GetGameFlags() & gameFlagsNoDamage )
		return 0;

	// If it doesn't take damage from held objects and the object is being held - no damage
	if ( !bDamageFromHeldObjects && ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) )
	{
		// If it doesn't take damage from held objects - no damage
		if ( !bDamageFromHeldObjects )
			return 0;
	}

	if ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_MULTIOBJECT_ENTITY )
	{
		// UNDONE: Add up mass here for car wheels and prop_ragdoll pieces?
		IPhysicsObject *pList[VPHYSICS_MAX_OBJECT_LIST_COUNT];
		int count = pEvent->pEntities[otherIndex]->VPhysicsGetObjectList( pList, ARRAYSIZE(pList) );
		for ( int i = 0; i < count; i++ )
		{
			if ( pList[i]->GetGameFlags() & gameFlagsNoDamage )
				return 0;
		}
	}

	if ( pEvent->pObjects[index]->GetGameFlags() & FVPHYSICS_PLAYER_HELD )
	{
		// players can't damage held objects
		if ( pEvent->pEntities[otherIndex]->IsPlayer() )
			return 0;

		allowStaticDamage = false;
	}

#if 0
	{
		PhysGetDamageInflictorVelocityStartOfFrame( pEvent->pObjects[otherIndex], pEvent->preVelocity[otherIndex], pEvent->preAngularVelocity[otherIndex] );
	}
#endif

	float otherSpeedSqr = pEvent->preVelocity[otherIndex].LengthSqr();
	float otherAngSqr = 0;

	// factor in angular for sharp objects
	if ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_DMG_SLICE )
	{
		otherAngSqr = pEvent->preAngularVelocity[otherIndex].LengthSqr();
	}

	float otherMass = pEvent->pObjects[otherIndex]->GetMass();

	if ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_PLAYER_HELD )
	{
		if ( gpGlobals->maxClients == 1 )
		{
			// if the player is holding the object, use it's real mass (player holding reduced the mass)
			CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
			if ( pPlayer )
			{
				otherMass = pPlayer->GetHeldObjectMass( pEvent->pObjects[otherIndex] );
			}
		}
	}

	// NOTE: sum the mass of each object in this system for the purpose of damage
	if ( pEvent->pEntities[otherIndex] && (pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_MULTIOBJECT_ENTITY) )
	{
		otherMass = PhysGetEntityMass( pEvent->pEntities[otherIndex] );
	}

	if ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_HEAVY_OBJECT )
	{
		otherMass = table.largeMassMin;
		if ( energyScale < 2.0f )
		{
			energyScale = 2.0f;
		}
	}

	// UNDONE: allowStaticDamage is a hack - work out some method for
	// breakable props to impact the world and break!!
	if ( !allowStaticDamage )
	{
		if ( otherMass < table.minMass )
			return 0;
		// check to see if the object is small
		if ( otherMass < table.smallMassMax && otherSpeedSqr < table.smallMassMinSpeedSqr )
			return 0;

		if ( otherSpeedSqr < table.minSpeedSqr && otherAngSqr < table.minRotSpeedSqr )
			return 0;
	}

	// Add extra oomph for floating objects
	if ( pEvent->pEntities[index]->IsFloating() && !pEvent->pEntities[otherIndex]->IsWorld() )
	{
		if ( energyScale < 3.0f )
		{
			energyScale = 3.0f;
		}
	}

	float damage = 0;
	bool bDebug = false;//(&table == &gDefaultPlayerImpactDamageTable);

	// don't ever take spin damage from slowly spinning objects
	if ( otherAngSqr > table.minRotSpeedSqr )
	{
		Vector otherInertia = pEvent->pObjects[otherIndex]->GetInertia();
		float angularMom = DotProductAbs( otherInertia, pEvent->preAngularVelocity[otherIndex] );
		damage = ReadDamageTable( table.angularTable, table.angularCount, angularMom * energyScale, bDebug );
		if ( damage > 0 )
		{
			damageType |= DMG_SLASH;
		}
	}

	float deltaV = pEvent->preVelocity[index].Length() - pEvent->postVelocity[index].Length();
	float mass = pEvent->pObjects[index]->GetMass();

	// If I lost speed, and I lost less than min velocity, then filter out this energy
	if ( deltaV > 0 && deltaV < table.myMinVelocity )
	{
		deltaV = 0;
	}
	float eliminatedEnergy = deltaV * deltaV * mass;

	deltaV = pEvent->preVelocity[otherIndex].Length() - pEvent->postVelocity[otherIndex].Length();
	float otherEliminatedEnergy = deltaV * deltaV * otherMass;

	// exaggerate the effects of really large objects
	if ( otherMass >= table.largeMassMin )
	{
		otherEliminatedEnergy *= table.largeMassScale;
		float dz = pEvent->preVelocity[otherIndex].z - pEvent->postVelocity[otherIndex].z;

		if ( deltaV > 0 && dz < 0 && pEvent->preVelocity[otherIndex].z < 0 )
		{
			float factor = fabs(dz / deltaV);
			otherEliminatedEnergy *= (1 + factor * (table.largeMassFallingScale - 1.0f));
		}
	}

	eliminatedEnergy += otherEliminatedEnergy;

	// now in units of this character's speed squared
	float invMass = pEvent->pObjects[index]->GetInvMass();
	if ( !pEvent->pObjects[index]->IsMoveable() )
	{
		// inv mass is zero, but impact damage is enabled on this
		// prop, so recompute:
		invMass = 1.0f / pEvent->pObjects[index]->GetMass();
	}
	else if ( pEvent->pObjects[index]->GetGameFlags() & FVPHYSICS_PLAYER_HELD )
	{
		if ( gpGlobals->maxClients == 1 )
		{
			// if the player is holding the object, use it's real mass (player holding reduced the mass)
			CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
			if ( pPlayer )
			{
				float mass = pPlayer->GetHeldObjectMass( pEvent->pObjects[index] );
				if ( mass > 0 )
				{
					invMass = 1.0f / mass;
				}
			}
		}
	}

	eliminatedEnergy *= invMass * energyScale;

	damage += ReadDamageTable( table.linearTable, table.linearCount, eliminatedEnergy, bDebug );

	if ( !pEvent->pObjects[otherIndex]->IsStatic() && otherMass < table.smallMassMax && table.smallMassCap > 0 )
	{
		damage = clamp( damage, 0.f, table.smallMassCap );
	}

	return damage;
}

float CalculateDefaultPhysicsDamage( int index, gamevcollisionevent_t *pEvent, float energyScale, bool allowStaticDamage, int &damageType, string_t iszDamageTableName, bool bDamageFromHeldObjects )
{
	// If we have a specified damage table, find it and use it instead
	if ( iszDamageTableName != NULL_STRING )
	{
		for ( int i = 0; i < ARRAYSIZE(gDamageTableRegistry); i++ )
		{
			if ( !Q_strcmp( gDamageTableRegistry[i].pszTableName, STRING(iszDamageTableName) ) )
				return CalculatePhysicsImpactDamage( index, pEvent, *(gDamageTableRegistry[i].pTable), energyScale, allowStaticDamage, damageType, bDamageFromHeldObjects );
		}

		Warning("Failed to find custom physics damage table name: %s\n", STRING(iszDamageTableName) );
	}

	return CalculatePhysicsImpactDamage( index, pEvent, gDefaultNPCImpactDamageTable, energyScale, allowStaticDamage, damageType, bDamageFromHeldObjects );
}

static bool IsPhysicallyControlled( CBaseEntity *pEntity, IPhysicsObject *pPhysics )
{
	bool isPhysical = false;
	if ( pEntity->GetMoveType() == MOVETYPE_VPHYSICS )
	{
		isPhysical = true;
	}
	else
	{
		if ( pPhysics->GetShadowController() )
		{
			isPhysical = pPhysics->GetShadowController()->IsPhysicallyControlled();
		}
	}
	return isPhysical;
}

{
	CUtlVector< CBaseEntity * > pObjectList;
	CUtlVector< Vector >		objectForce;
	bool hasLargeObject = false;

	// add a slot for static objects
	pObjectList.AddToTail( NULL );
	objectForce.AddToTail( vec3_origin );
	// add a slot for friendly objects
	pObjectList.AddToTail( NULL );
	objectForce.AddToTail( vec3_origin );

	CBaseCombatCharacter *pBCC = pInputOwnerEntity->MyCombatCharacterPointer();

	IPhysicsFrictionSnapshot *pSnapshot = pObject->CreateFrictionSnapshot();
	float objMass = pObject->GetMass();
	while ( pSnapshot->IsValid() )
	{
		float force = pSnapshot->GetNormalForce();
		if ( force > 0.0f )
		{
			IPhysicsObject *pOther = pSnapshot->GetObject(1);
			CBaseEntity *pOtherEntity = static_cast<CBaseEntity *>(pOther->GetGameData());
			if ( !pOtherEntity )
			{
				// object was just deleted, but we still have a contact point this frame...
				// just assume it came from the world.
				pOtherEntity = GetWorldEntity();
			}
			CBaseEntity *pOtherOwner = pOtherEntity;
			if ( pOtherEntity->GetOwnerEntity() )
			{
				pOtherOwner = pOtherEntity->GetOwnerEntity();
			}

			int outIndex = 0;
			if ( !pOther->IsMoveable() )
			{
				outIndex = 0;
			}
			// NavIgnored objects are often being pushed by a friendly
			else if ( pBCC && (pBCC->IRelationType( pOtherOwner ) == D_LI || pOtherEntity->IsNavIgnored()) )
			{
				outIndex = 1;
			}
			// player held objects do no stress
			else if ( pOther->GetGameFlags() & FVPHYSICS_PLAYER_HELD )
			{
				outIndex = 1;
			}
			else
			{
				if ( pOther->GetMass() >= VPHYSICS_LARGE_OBJECT_MASS )
				{
					if ( pInputOwnerEntity->GetGroundEntity() != pOtherEntity)
					{
						hasLargeObject = true;
					}
				}
				// moveable, non-friendly

				// aggregate contacts over each object to avoid greater stress in multiple contact cases
				// NOTE: Contacts should be in order, so this shouldn't ever search, but just in case
				outIndex = pObjectList.Count();
				for ( int i = pObjectList.Count()-1; i >= 2; --i )
				{
					if ( pObjectList[i] == pOtherOwner )
					{
						outIndex = i;
						break;
					}
				}
				if ( outIndex == pObjectList.Count() )
				{
					pObjectList.AddToTail( pOtherOwner );
					objectForce.AddToTail( vec3_origin );
				}
			}

			if ( outIndex != 0 && pInputOwnerEntity->GetMoveType() != MOVETYPE_VPHYSICS && !IsPhysicallyControlled(pOtherEntity, pOther) )
			{
				// UNDONE: Test this!  This is to remove any shadow/shadow stress.  The game should handle this with blocked/damage
				force = 0.0f;
			}

			Vector normal;
			pSnapshot->GetSurfaceNormal( normal );
			objectForce[outIndex] += normal * force;
		}
		pSnapshot->NextFrictionData();
	}
	pObject->DestroyFrictionSnapshot( pSnapshot );
	pSnapshot = NULL;

	// clear out all friendly force
	objectForce[1].Init();

	float sum = 0;
	Vector negativeForce = vec3_origin;
	Vector positiveForce = vec3_origin;

	Assert( pObjectList.Count() == objectForce.Count() );
	for ( int objectIndex = pObjectList.Count()-1; objectIndex >= 0; --objectIndex )
	{
		sum += objectForce[objectIndex].Length();
		for ( int i = 0; i < 3; i++ )
		{
			if ( objectForce[objectIndex][i] < 0 )
			{
				negativeForce[i] -= objectForce[objectIndex][i];
			}
			else
			{
				positiveForce[i] += objectForce[objectIndex][i];
			}
		}
	}

	// "external" stress is two way (something pushes on the object and something else pushes back)
	// so the set of minimum values per component are the projections of the two-way force
	// "internal" stress is one way (the object is pushing against something OR something pushing back)
	// the momentum must have come from inside the object (gravity, controller, etc)
	Vector internalForce = vec3_origin;
	Vector externalForce = vec3_origin;

	for ( int i = 0; i < 3; i++ )
	{
		if ( negativeForce[i] < positiveForce[i] )
		{
			internalForce[i] = positiveForce[i] - negativeForce[i];
			externalForce[i] = negativeForce[i];
		}
		else
		{
			internalForce[i] = negativeForce[i] - positiveForce[i];
			externalForce[i] = positiveForce[i];
		}
	}

	// sum is kg in / s
	Vector gravVector;
	physenv->GetGravity( &gravVector );
	float gravity = gravVector.Length();
	if ( pInputOwnerEntity->GetMoveType() != MOVETYPE_VPHYSICS && pObject->IsMoveable() )
	{
		Vector lastVel;
		lastVel.Init();
		if ( pObject->GetShadowController() )
		{
			pObject->GetShadowController()->GetLastImpulse( &lastVel );
		}
		else
		{
			if ( ( pObject->GetCallbackFlags() & CALLBACK_IS_PLAYER_CONTROLLER ) )
			{
				CBasePlayer *pPlayer = ToBasePlayer( pInputOwnerEntity );
				IPhysicsPlayerController *pController = pPlayer ? pPlayer->GetPhysicsController() : NULL;
				if ( pController )
				{
					pController->GetLastImpulse( &lastVel );
				}
			}
		}

		// Work in progress...

		// Peek into the controller for this object.  Look at the input velocity and make sure it's all
		// accounted for in the computed stress.  If not, redistribute external to internal as it's
		// probably being reflected in a way we can't measure here.
		float inputLen = lastVel.Length() * (1.0f / physenv->GetSimulationTimestep()) * objMass;
		if ( inputLen > 0.0f )
		{
			float internalLen = internalForce.Length();
			if ( internalLen < inputLen )
			{
				float ratio = internalLen / inputLen;
				Vector delta = internalForce * (1.0f - ratio);
				internalForce += delta;
				float deltaLen = delta.Length();
				sum -= deltaLen;
				float extLen = VectorNormalize(externalForce) - deltaLen;
				if ( extLen < 0 )
				{
					extLen = 0;
				}
				externalForce *= extLen;
			}
		}
	}

	float invGravity = gravity;
	if ( invGravity <= 0 )
	{
		invGravity = 1.0f;
	}
	else
	{
		invGravity = 1.0f / invGravity;
	}
	sum *= invGravity;
	internalForce *= invGravity;
	externalForce *= invGravity;
	if ( !pObject->IsMoveable() )
	{
		// the above algorithm will see almost all force as internal if the object is not moveable
		// (it doesn't push on anything else, so nothing is reciprocated)
		// exceptions for friction of a single other object with multiple contact points on this object

		// But the game wants to see it all as external because obviously the object can't move, so it can't have
		// internal stress
		externalForce = internalForce;
		internalForce.Init();

		if ( !pObject->IsStatic() )
		{
			sum += objMass;
		}
	}
	else
	{
		// assume object is at rest
		if ( sum > objMass )
		{
			sum = objMass + (sum-objMass) * 0.5;
		}
	}

	if ( pOutput )
	{
		pOutput->exertedStress = internalForce.Length();
		pOutput->receivedStress = externalForce.Length();
		pOutput->hasNonStaticStress = pObjectList.Count() > 2 ? true : false;
		pOutput->hasLargeObjectContact = hasLargeObject;
	}

	// sum is now kg
	return sum;
}


{
	bool isPhysical = false;
	if ( pEntity->GetMoveType() == MOVETYPE_VPHYSICS )
	{
		isPhysical = true;
	}
	else
	{
		if ( pPhysics->GetShadowController() )
		{
			isPhysical = pPhysics->GetShadowController()->IsPhysicallyControlled();
		}
	}
	return isPhysical;
}

#include "cbase.h"
#include "physics_impact_damage.h"
#include "shareddefs.h"
#include "vphysics/friction.h"
#include "vphysics/player_controller.h"
#include "world.h"

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

// PLAYER PHYSICS DAMAGE TABLE
static impactentry_t playerLinearTable[] =
{
	{ 150*150, 5 },
	{ 250*250, 10 },
	{ 450*450, 20 },
	{ 550*550, 50 },
	{ 700*700, 100 },
	{ 1000*1000, 500 },
};

static impactentry_t playerAngularTable[] =
{
	{ 100*100, 10 },
	{ 150*150, 20 },
	{ 200*200, 50 },
	{ 300*300, 500 },
};

impactdamagetable_t gDefaultPlayerImpactDamageTable =
{
	playerLinearTable,
	playerAngularTable,

	ARRAYSIZE(playerLinearTable),
	ARRAYSIZE(playerAngularTable),

	24*24.0f,	// minimum linear speed
	360*360.0f,	// minimum angular speed
	2.0f,		// can't take damage from anything under 2kg

	5.0f,		// anything less than 5kg is "small"
	5.0f,		// never take more than 5 pts of damage from anything under 5kg
	36*36.0f,	// <5kg objects must go faster than 36 in/s to do damage

	0.0f,		// large mass in kg (no large mass effects)
	1.0f,		// large mass scale
	2.0f,		// large mass falling scale
	320.0f,		// min velocity for player speed to cause damage

};

// PLAYER-IN-VEHICLE PHYSICS DAMAGE TABLE
static impactentry_t playerVehicleLinearTable[] =
{
	{ 450*450, 5 },
	{ 600*600, 10 },
	{ 700*700, 25 },
	{ 1000*1000, 50 },
	{ 1500*1500, 100 },
	{ 2000*2000, 500 },
};

static impactentry_t playerVehicleAngularTable[] =
{
	{ 100*100, 10 },
	{ 150*150, 20 },
	{ 200*200, 50 },
	{ 300*300, 500 },
};

impactdamagetable_t gDefaultPlayerVehicleImpactDamageTable =
{
	playerVehicleLinearTable,
	playerVehicleAngularTable,

	ARRAYSIZE(playerVehicleLinearTable),
	ARRAYSIZE(playerVehicleAngularTable),

	24*24,		// minimum linear speed
	360*360,	// minimum angular speed
	80,			// can't take damage from anything under 80 kg

	150,		// anything less than 150kg is "small"
	5,			// never take more than 5 pts of damage from anything under 150kg
	36*36,		// <150kg objects must go faster than 36 in/s to do damage

	0,			// large mass in kg (no large mass effects)
	1.0f,		// large mass scale
	1.0f,		// large mass falling scale
	0.0f,		// min vel
};

// NPC PHYSICS DAMAGE TABLE
static impactentry_t npcLinearTable[] =
{
	{ 150*150, 5 },
	{ 250*250, 10 },
	{ 350*350, 50 },
	{ 500*500, 100 },
	{ 1000*1000, 500 },
};

static impactentry_t npcAngularTable[] =
{
	{ 100*100, 10 },
	{ 150*150, 25 },
	{ 200*200, 50 },
	{ 250*250, 500 },
};

impactdamagetable_t gDefaultNPCImpactDamageTable =
{
	npcLinearTable,
	npcAngularTable,

	ARRAYSIZE(npcLinearTable),
	ARRAYSIZE(npcAngularTable),

	24*24,		// minimum linear speed squared
	360*360,	// minimum angular speed squared (360 deg/s to cause spin/slice damage)
	2,			// can't take damage from anything under 2kg

	5,			// anything less than 5kg is "small"
	5,			// never take more than 5 pts of damage from anything under 5kg
	36*36,		// <5kg objects must go faster than 36 in/s to do damage

	VPHYSICS_LARGE_OBJECT_MASS,		// large mass in kg
	4,			// large mass scale (anything over 500kg does 4X as much energy to read from damage table)
	5,			// large mass falling scale (emphasize falling/crushing damage over sideways impacts since the stress will kill you anyway)
	0.0f,		// min vel
};

// GLASS DAMAGE TABLE
static impactentry_t glassLinearTable[] =
{
	{ 25*25, 10 },
	{ 50*50, 20 },
	{ 100*100, 50 },
	{ 200*200, 75 },
	{ 500*500, 100 },
	{ 250*250, 500 },
};

static impactentry_t glassAngularTable[] =
{
	{ 50*50, 25 },
	{ 100*100, 50 },
	{ 200*200, 100 },
	{ 250*250, 500 },
};

impactdamagetable_t gGlassImpactDamageTable =
{
	glassLinearTable,
	glassAngularTable,

	ARRAYSIZE(glassLinearTable),
	ARRAYSIZE(glassAngularTable),

	8*8,		// minimum linear speed squared
	360*360,	// minimum angular speed squared (360 deg/s to cause spin/slice damage)
	2,			// can't take damage from anything under 2kg

	1,			// anything less than 1kg is "small"
	10,			// never take more than 10 pts of damage from anything under 1kg
	8*8,		// <1kg objects must go faster than 8 in/s to do damage

	50,			// large mass in kg
	4,			// large mass scale (anything over 50kg does 4X as much energy to read from damage table)
	0.0f,		// min vel
};

// PHYSICS TABLE NAMES
struct damagetable_t
{
	const char			*pszTableName;
	impactdamagetable_t	*pTable;
};

static damagetable_t gDamageTableRegistry[] =
{
	{
		"player",
		&gDefaultPlayerImpactDamageTable,
	},
	{
		"player_vehicle",
		&gDefaultPlayerVehicleImpactDamageTable,
	},
	{
		"npc",
		&gDefaultNPCImpactDamageTable,
	},
	{
		"glass",
		&gGlassImpactDamageTable,
	},
};

float ReadDamageTable( impactentry_t *pTable, int tableCount, float impulse, bool bDebug )
{
	if ( pTable )
	{
		int i;
		for ( i = 0; i < tableCount; i++ )
		{
			if ( impulse < pTable[i].impulse )
				break;
		}
		if ( i > 0 )
		{
			i--;
			if ( bDebug )
			{
				Msg("Damage %.0f, energy %.0f\n", pTable[i].damage, FastSqrt(impulse) );
			}
			return pTable[i].damage;
		}
	}
	return 0;
}

float CalculatePhysicsImpactDamage( int index, gamevcollisionevent_t *pEvent, const impactdamagetable_t &table, float energyScale, bool allowStaticDamage, int &damageType, bool bDamageFromHeldObjects )
{
	damageType = DMG_CRUSH;
	int otherIndex = !index;

	// UNDONE: Expose a flag for self-inflicted damage?  Can't think of a valid case so far.
	if ( pEvent->pEntities[0] == pEvent->pEntities[1] )
		return 0;

	if ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_NO_NPC_IMPACT_DMG )
	{
		if( pEvent->pEntities[index]->IsNPC() || pEvent->pEntities[index]->IsPlayer() )
		{
			return 0;
		}
	}

	// use implicit velocities on ragdolls since they may have high constraint velocities that aren't actually executed, just pushed through contacts
	if (( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_PART_OF_RAGDOLL) && pEvent->pEntities[index]->IsPlayer() )
	{
		pEvent->pObjects[otherIndex]->GetImplicitVelocity( &pEvent->preVelocity[otherIndex], &pEvent->preAngularVelocity[otherIndex] );
	}

	// Dissolving impact damage results in death always.
	if ( ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_DMG_DISSOLVE ) &&
			!pEvent->pEntities[index]->IsEFlagSet(EFL_NO_DISSOLVE) )
	{
		damageType |= DMG_DISSOLVE;
		return 1000;
	}

	if ( energyScale <= 0.0f )
		return 0;

	const int gameFlagsNoDamage = FVPHYSICS_CONSTRAINT_STATIC | FVPHYSICS_NO_IMPACT_DMG;

	// NOTE: Crushing damage is handled by stress calcs in vphysics update functions, this is ONLY impact damage
	// this is a non-moving object due to a constraint - no damage
	if ( pEvent->pObjects[otherIndex]->GetGameFlags() & gameFlagsNoDamage )
		return 0;

	// If it doesn't take damage from held objects and the object is being held - no damage
	if ( !bDamageFromHeldObjects && ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) )
	{
		// If it doesn't take damage from held objects - no damage
		if ( !bDamageFromHeldObjects )
			return 0;
	}

	if ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_MULTIOBJECT_ENTITY )
	{
		// UNDONE: Add up mass here for car wheels and prop_ragdoll pieces?
		IPhysicsObject *pList[VPHYSICS_MAX_OBJECT_LIST_COUNT];
		int count = pEvent->pEntities[otherIndex]->VPhysicsGetObjectList( pList, ARRAYSIZE(pList) );
		for ( int i = 0; i < count; i++ )
		{
			if ( pList[i]->GetGameFlags() & gameFlagsNoDamage )
				return 0;
		}
	}

	if ( pEvent->pObjects[index]->GetGameFlags() & FVPHYSICS_PLAYER_HELD )
	{
		// players can't damage held objects
		if ( pEvent->pEntities[otherIndex]->IsPlayer() )
			return 0;

		allowStaticDamage = false;
	}

#if 0
	{
		PhysGetDamageInflictorVelocityStartOfFrame( pEvent->pObjects[otherIndex], pEvent->preVelocity[otherIndex], pEvent->preAngularVelocity[otherIndex] );
	}
#endif

	float otherSpeedSqr = pEvent->preVelocity[otherIndex].LengthSqr();
	float otherAngSqr = 0;

	// factor in angular for sharp objects
	if ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_DMG_SLICE )
	{
		otherAngSqr = pEvent->preAngularVelocity[otherIndex].LengthSqr();
	}

	float otherMass = pEvent->pObjects[otherIndex]->GetMass();

	if ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_PLAYER_HELD )
	{
		if ( gpGlobals->maxClients == 1 )
		{
			// if the player is holding the object, use it's real mass (player holding reduced the mass)
			CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
			if ( pPlayer )
			{
				otherMass = pPlayer->GetHeldObjectMass( pEvent->pObjects[otherIndex] );
			}
		}
	}

	// NOTE: sum the mass of each object in this system for the purpose of damage
	if ( pEvent->pEntities[otherIndex] && (pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_MULTIOBJECT_ENTITY) )
	{
		otherMass = PhysGetEntityMass( pEvent->pEntities[otherIndex] );
	}

	if ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_HEAVY_OBJECT )
	{
		otherMass = table.largeMassMin;
		if ( energyScale < 2.0f )
		{
			energyScale = 2.0f;
		}
	}

	// UNDONE: allowStaticDamage is a hack - work out some method for
	// breakable props to impact the world and break!!
	if ( !allowStaticDamage )
	{
		if ( otherMass < table.minMass )
			return 0;
		// check to see if the object is small
		if ( otherMass < table.smallMassMax && otherSpeedSqr < table.smallMassMinSpeedSqr )
			return 0;

		if ( otherSpeedSqr < table.minSpeedSqr && otherAngSqr < table.minRotSpeedSqr )
			return 0;
	}

	// Add extra oomph for floating objects
	if ( pEvent->pEntities[index]->IsFloating() && !pEvent->pEntities[otherIndex]->IsWorld() )
	{
		if ( energyScale < 3.0f )
		{
			energyScale = 3.0f;
		}
	}

	float damage = 0;
	bool bDebug = false;//(&table == &gDefaultPlayerImpactDamageTable);

	// don't ever take spin damage from slowly spinning objects
	if ( otherAngSqr > table.minRotSpeedSqr )
	{
		Vector otherInertia = pEvent->pObjects[otherIndex]->GetInertia();
		float angularMom = DotProductAbs( otherInertia, pEvent->preAngularVelocity[otherIndex] );
		damage = ReadDamageTable( table.angularTable, table.angularCount, angularMom * energyScale, bDebug );
		if ( damage > 0 )
		{
			damageType |= DMG_SLASH;
		}
	}

	float deltaV = pEvent->preVelocity[index].Length() - pEvent->postVelocity[index].Length();
	float mass = pEvent->pObjects[index]->GetMass();

	// If I lost speed, and I lost less than min velocity, then filter out this energy
	if ( deltaV > 0 && deltaV < table.myMinVelocity )
	{
		deltaV = 0;
	}
	float eliminatedEnergy = deltaV * deltaV * mass;

	deltaV = pEvent->preVelocity[otherIndex].Length() - pEvent->postVelocity[otherIndex].Length();
	float otherEliminatedEnergy = deltaV * deltaV * otherMass;

	// exaggerate the effects of really large objects
	if ( otherMass >= table.largeMassMin )
	{
		otherEliminatedEnergy *= table.largeMassScale;
		float dz = pEvent->preVelocity[otherIndex].z - pEvent->postVelocity[otherIndex].z;

		if ( deltaV > 0 && dz < 0 && pEvent->preVelocity[otherIndex].z < 0 )
		{
			float factor = fabs(dz / deltaV);
			otherEliminatedEnergy *= (1 + factor * (table.largeMassFallingScale - 1.0f));
		}
	}

	eliminatedEnergy += otherEliminatedEnergy;

	// now in units of this character's speed squared
	float invMass = pEvent->pObjects[index]->GetInvMass();
	if ( !pEvent->pObjects[index]->IsMoveable() )
	{
		// inv mass is zero, but impact damage is enabled on this
		// prop, so recompute:
		invMass = 1.0f / pEvent->pObjects[index]->GetMass();
	}
	else if ( pEvent->pObjects[index]->GetGameFlags() & FVPHYSICS_PLAYER_HELD )
	{
		if ( gpGlobals->maxClients == 1 )
		{
			// if the player is holding the object, use it's real mass (player holding reduced the mass)
			CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
			if ( pPlayer )
			{
				float mass = pPlayer->GetHeldObjectMass( pEvent->pObjects[index] );
				if ( mass > 0 )
				{
					invMass = 1.0f / mass;
				}
			}
		}
	}

	eliminatedEnergy *= invMass * energyScale;

	damage += ReadDamageTable( table.linearTable, table.linearCount, eliminatedEnergy, bDebug );

	if ( !pEvent->pObjects[otherIndex]->IsStatic() && otherMass < table.smallMassMax && table.smallMassCap > 0 )
	{
		damage = clamp( damage, 0.f, table.smallMassCap );
	}

	return damage;
}

float CalculateDefaultPhysicsDamage( int index, gamevcollisionevent_t *pEvent, float energyScale, bool allowStaticDamage, int &damageType, string_t iszDamageTableName, bool bDamageFromHeldObjects )
{
	// If we have a specified damage table, find it and use it instead
	if ( iszDamageTableName != NULL_STRING )
	{
		for ( int i = 0; i < ARRAYSIZE(gDamageTableRegistry); i++ )
		{
			if ( !Q_strcmp( gDamageTableRegistry[i].pszTableName, STRING(iszDamageTableName) ) )
				return CalculatePhysicsImpactDamage( index, pEvent, *(gDamageTableRegistry[i].pTable), energyScale, allowStaticDamage, damageType, bDamageFromHeldObjects );
		}

		Warning("Failed to find custom physics damage table name: %s\n", STRING(iszDamageTableName) );
	}

	return CalculatePhysicsImpactDamage( index, pEvent, gDefaultNPCImpactDamageTable, energyScale, allowStaticDamage, damageType, bDamageFromHeldObjects );
}

static bool IsPhysicallyControlled( CBaseEntity *pEntity, IPhysicsObject *pPhysics )

float CalculateObjectStress( IPhysicsObject *pObject, CBaseEntity *pInputOwnerEntity, vphysics_objectstress_t *pOutput )
{
	CUtlVector< CBaseEntity * > pObjectList;
	CUtlVector< Vector >		objectForce;
	bool hasLargeObject = false;

	// add a slot for static objects
	pObjectList.AddToTail( NULL );
	objectForce.AddToTail( vec3_origin );
	// add a slot for friendly objects
	pObjectList.AddToTail( NULL );
	objectForce.AddToTail( vec3_origin );

	CBaseCombatCharacter *pBCC = pInputOwnerEntity->MyCombatCharacterPointer();

	IPhysicsFrictionSnapshot *pSnapshot = pObject->CreateFrictionSnapshot();
	float objMass = pObject->GetMass();
	while ( pSnapshot->IsValid() )
	{
		float force = pSnapshot->GetNormalForce();
		if ( force > 0.0f )
		{
			IPhysicsObject *pOther = pSnapshot->GetObject(1);
			CBaseEntity *pOtherEntity = static_cast<CBaseEntity *>(pOther->GetGameData());
			if ( !pOtherEntity )
			{
				// object was just deleted, but we still have a contact point this frame...
				// just assume it came from the world.
				pOtherEntity = GetWorldEntity();
			}
			CBaseEntity *pOtherOwner = pOtherEntity;
			if ( pOtherEntity->GetOwnerEntity() )
			{
				pOtherOwner = pOtherEntity->GetOwnerEntity();
			}

			int outIndex = 0;
			if ( !pOther->IsMoveable() )
			{
				outIndex = 0;
			}
			// NavIgnored objects are often being pushed by a friendly
			else if ( pBCC && (pBCC->IRelationType( pOtherOwner ) == D_LI || pOtherEntity->IsNavIgnored()) )
			{
				outIndex = 1;
			}
			// player held objects do no stress
			else if ( pOther->GetGameFlags() & FVPHYSICS_PLAYER_HELD )
			{
				outIndex = 1;
			}
			else
			{
				if ( pOther->GetMass() >= VPHYSICS_LARGE_OBJECT_MASS )
				{
					if ( pInputOwnerEntity->GetGroundEntity() != pOtherEntity)
					{
						hasLargeObject = true;
					}
				}
				// moveable, non-friendly

				// aggregate contacts over each object to avoid greater stress in multiple contact cases
				// NOTE: Contacts should be in order, so this shouldn't ever search, but just in case
				outIndex = pObjectList.Count();
				for ( int i = pObjectList.Count()-1; i >= 2; --i )
				{
					if ( pObjectList[i] == pOtherOwner )
					{
						outIndex = i;
						break;
					}
				}
				if ( outIndex == pObjectList.Count() )
				{
					pObjectList.AddToTail( pOtherOwner );
					objectForce.AddToTail( vec3_origin );
				}
			}

			if ( outIndex != 0 && pInputOwnerEntity->GetMoveType() != MOVETYPE_VPHYSICS && !IsPhysicallyControlled(pOtherEntity, pOther) )
			{
				// UNDONE: Test this!  This is to remove any shadow/shadow stress.  The game should handle this with blocked/damage
				force = 0.0f;
			}

			Vector normal;
			pSnapshot->GetSurfaceNormal( normal );
			objectForce[outIndex] += normal * force;
		}
		pSnapshot->NextFrictionData();
	}
	pObject->DestroyFrictionSnapshot( pSnapshot );
	pSnapshot = NULL;

	// clear out all friendly force
	objectForce[1].Init();

	float sum = 0;
	Vector negativeForce = vec3_origin;
	Vector positiveForce = vec3_origin;

	Assert( pObjectList.Count() == objectForce.Count() );
	for ( int objectIndex = pObjectList.Count()-1; objectIndex >= 0; --objectIndex )
	{
		sum += objectForce[objectIndex].Length();
		for ( int i = 0; i < 3; i++ )
		{
			if ( objectForce[objectIndex][i] < 0 )
			{
				negativeForce[i] -= objectForce[objectIndex][i];
			}
			else
			{
				positiveForce[i] += objectForce[objectIndex][i];
			}
		}
	}

	// "external" stress is two way (something pushes on the object and something else pushes back)
	// so the set of minimum values per component are the projections of the two-way force
	// "internal" stress is one way (the object is pushing against something OR something pushing back)
	// the momentum must have come from inside the object (gravity, controller, etc)
	Vector internalForce = vec3_origin;
	Vector externalForce = vec3_origin;

	for ( int i = 0; i < 3; i++ )
	{
		if ( negativeForce[i] < positiveForce[i] )
		{
			internalForce[i] = positiveForce[i] - negativeForce[i];
			externalForce[i] = negativeForce[i];
		}
		else
		{
			internalForce[i] = negativeForce[i] - positiveForce[i];
			externalForce[i] = positiveForce[i];
		}
	}

	// sum is kg in / s
	Vector gravVector;
	physenv->GetGravity( &gravVector );
	float gravity = gravVector.Length();
	if ( pInputOwnerEntity->GetMoveType() != MOVETYPE_VPHYSICS && pObject->IsMoveable() )
	{
		Vector lastVel;
		lastVel.Init();
		if ( pObject->GetShadowController() )
		{
			pObject->GetShadowController()->GetLastImpulse( &lastVel );
		}
		else
		{
			if ( ( pObject->GetCallbackFlags() & CALLBACK_IS_PLAYER_CONTROLLER ) )
			{
				CBasePlayer *pPlayer = ToBasePlayer( pInputOwnerEntity );
				IPhysicsPlayerController *pController = pPlayer ? pPlayer->GetPhysicsController() : NULL;
				if ( pController )
				{
					pController->GetLastImpulse( &lastVel );
				}
			}
		}

		// Work in progress...

		// Peek into the controller for this object.  Look at the input velocity and make sure it's all
		// accounted for in the computed stress.  If not, redistribute external to internal as it's
		// probably being reflected in a way we can't measure here.
		float inputLen = lastVel.Length() * (1.0f / physenv->GetSimulationTimestep()) * objMass;
		if ( inputLen > 0.0f )
		{
			float internalLen = internalForce.Length();
			if ( internalLen < inputLen )
			{
				float ratio = internalLen / inputLen;
				Vector delta = internalForce * (1.0f - ratio);
				internalForce += delta;
				float deltaLen = delta.Length();
				sum -= deltaLen;
				float extLen = VectorNormalize(externalForce) - deltaLen;
				if ( extLen < 0 )
				{
					extLen = 0;
				}
				externalForce *= extLen;
			}
		}
	}

	float invGravity = gravity;
	if ( invGravity <= 0 )
	{
		invGravity = 1.0f;
	}
	else
	{
		invGravity = 1.0f / invGravity;
	}
	sum *= invGravity;
	internalForce *= invGravity;
	externalForce *= invGravity;
	if ( !pObject->IsMoveable() )
	{
		// the above algorithm will see almost all force as internal if the object is not moveable
		// (it doesn't push on anything else, so nothing is reciprocated)
		// exceptions for friction of a single other object with multiple contact points on this object

		// But the game wants to see it all as external because obviously the object can't move, so it can't have
		// internal stress
		externalForce = internalForce;
		internalForce.Init();

		if ( !pObject->IsStatic() )
		{
			sum += objMass;
		}
	}
	else
	{
		// assume object is at rest
		if ( sum > objMass )
		{
			sum = objMass + (sum-objMass) * 0.5;
		}
	}

	if ( pOutput )
	{
		pOutput->exertedStress = internalForce.Length();
		pOutput->receivedStress = externalForce.Length();
		pOutput->hasNonStaticStress = pObjectList.Count() > 2 ? true : false;
		pOutput->hasLargeObjectContact = hasLargeObject;
	}

	// sum is now kg
	return sum;
}


#include "cbase.h"
#include "physics_impact_damage.h"
#include "shareddefs.h"
#include "vphysics/friction.h"
#include "vphysics/player_controller.h"
#include "world.h"

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

// PLAYER PHYSICS DAMAGE TABLE
static impactentry_t playerLinearTable[] =
{
	{ 150*150, 5 },
	{ 250*250, 10 },
	{ 450*450, 20 },
	{ 550*550, 50 },
	{ 700*700, 100 },
	{ 1000*1000, 500 },
};

static impactentry_t playerAngularTable[] =
{
	{ 100*100, 10 },
	{ 150*150, 20 },
	{ 200*200, 50 },
	{ 300*300, 500 },
};

impactdamagetable_t gDefaultPlayerImpactDamageTable =
{
	playerLinearTable,
	playerAngularTable,

	ARRAYSIZE(playerLinearTable),
	ARRAYSIZE(playerAngularTable),

	24*24.0f,	// minimum linear speed
	360*360.0f,	// minimum angular speed
	2.0f,		// can't take damage from anything under 2kg

	5.0f,		// anything less than 5kg is "small"
	5.0f,		// never take more than 5 pts of damage from anything under 5kg
	36*36.0f,	// <5kg objects must go faster than 36 in/s to do damage

	0.0f,		// large mass in kg (no large mass effects)
	1.0f,		// large mass scale
	2.0f,		// large mass falling scale
	320.0f,		// min velocity for player speed to cause damage

};

// PLAYER-IN-VEHICLE PHYSICS DAMAGE TABLE
static impactentry_t playerVehicleLinearTable[] =
{
	{ 450*450, 5 },
	{ 600*600, 10 },
	{ 700*700, 25 },
	{ 1000*1000, 50 },
	{ 1500*1500, 100 },
	{ 2000*2000, 500 },
};

static impactentry_t playerVehicleAngularTable[] =
{
	{ 100*100, 10 },
	{ 150*150, 20 },
	{ 200*200, 50 },
	{ 300*300, 500 },
};

impactdamagetable_t gDefaultPlayerVehicleImpactDamageTable =
{
	playerVehicleLinearTable,
	playerVehicleAngularTable,

	ARRAYSIZE(playerVehicleLinearTable),
	ARRAYSIZE(playerVehicleAngularTable),

	24*24,		// minimum linear speed
	360*360,	// minimum angular speed
	80,			// can't take damage from anything under 80 kg

	150,		// anything less than 150kg is "small"
	5,			// never take more than 5 pts of damage from anything under 150kg
	36*36,		// <150kg objects must go faster than 36 in/s to do damage

	0,			// large mass in kg (no large mass effects)
	1.0f,		// large mass scale
	1.0f,		// large mass falling scale
	0.0f,		// min vel
};

// NPC PHYSICS DAMAGE TABLE
static impactentry_t npcLinearTable[] =
{
	{ 150*150, 5 },
	{ 250*250, 10 },
	{ 350*350, 50 },
	{ 500*500, 100 },
	{ 1000*1000, 500 },
};

static impactentry_t npcAngularTable[] =
{
	{ 100*100, 10 },
	{ 150*150, 25 },
	{ 200*200, 50 },
	{ 250*250, 500 },
};

impactdamagetable_t gDefaultNPCImpactDamageTable =
{
	npcLinearTable,
	npcAngularTable,

	ARRAYSIZE(npcLinearTable),
	ARRAYSIZE(npcAngularTable),

	24*24,		// minimum linear speed squared
	360*360,	// minimum angular speed squared (360 deg/s to cause spin/slice damage)
	2,			// can't take damage from anything under 2kg

	5,			// anything less than 5kg is "small"
	5,			// never take more than 5 pts of damage from anything under 5kg
	36*36,		// <5kg objects must go faster than 36 in/s to do damage

	VPHYSICS_LARGE_OBJECT_MASS,		// large mass in kg
	4,			// large mass scale (anything over 500kg does 4X as much energy to read from damage table)
	5,			// large mass falling scale (emphasize falling/crushing damage over sideways impacts since the stress will kill you anyway)
	0.0f,		// min vel
};

// GLASS DAMAGE TABLE
static impactentry_t glassLinearTable[] =
{
	{ 25*25, 10 },
	{ 50*50, 20 },
	{ 100*100, 50 },
	{ 200*200, 75 },
	{ 500*500, 100 },
	{ 250*250, 500 },
};

static impactentry_t glassAngularTable[] =
{
	{ 50*50, 25 },
	{ 100*100, 50 },
	{ 200*200, 100 },
	{ 250*250, 500 },
};

impactdamagetable_t gGlassImpactDamageTable =
{
	glassLinearTable,
	glassAngularTable,

	ARRAYSIZE(glassLinearTable),
	ARRAYSIZE(glassAngularTable),

	8*8,		// minimum linear speed squared
	360*360,	// minimum angular speed squared (360 deg/s to cause spin/slice damage)
	2,			// can't take damage from anything under 2kg

	1,			// anything less than 1kg is "small"
	10,			// never take more than 10 pts of damage from anything under 1kg
	8*8,		// <1kg objects must go faster than 8 in/s to do damage

	50,			// large mass in kg
	4,			// large mass scale (anything over 50kg does 4X as much energy to read from damage table)
	0.0f,		// min vel
};

// PHYSICS TABLE NAMES
struct damagetable_t
{
	const char			*pszTableName;
	impactdamagetable_t	*pTable;
};

static damagetable_t gDamageTableRegistry[] =
{
	{
		"player",
		&gDefaultPlayerImpactDamageTable,
	},
	{
		"player_vehicle",
		&gDefaultPlayerVehicleImpactDamageTable,
	},
	{
		"npc",
		&gDefaultNPCImpactDamageTable,
	},
	{
		"glass",
		&gGlassImpactDamageTable,
	},
};

float ReadDamageTable( impactentry_t *pTable, int tableCount, float impulse, bool bDebug )
{
	if ( pTable )
	{
		int i;
		for ( i = 0; i < tableCount; i++ )
		{
			if ( impulse < pTable[i].impulse )
				break;
		}
		if ( i > 0 )
		{
			i--;
			if ( bDebug )
			{
				Msg("Damage %.0f, energy %.0f\n", pTable[i].damage, FastSqrt(impulse) );
			}
			return pTable[i].damage;
		}
	}
	return 0;
}

float CalculatePhysicsImpactDamage( int index, gamevcollisionevent_t *pEvent, const impactdamagetable_t &table, float energyScale, bool allowStaticDamage, int &damageType, bool bDamageFromHeldObjects )
{
	damageType = DMG_CRUSH;
	int otherIndex = !index;

	// UNDONE: Expose a flag for self-inflicted damage?  Can't think of a valid case so far.
	if ( pEvent->pEntities[0] == pEvent->pEntities[1] )
		return 0;

	if ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_NO_NPC_IMPACT_DMG )
	{
		if( pEvent->pEntities[index]->IsNPC() || pEvent->pEntities[index]->IsPlayer() )
		{
			return 0;
		}
	}

	// use implicit velocities on ragdolls since they may have high constraint velocities that aren't actually executed, just pushed through contacts
	if (( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_PART_OF_RAGDOLL) && pEvent->pEntities[index]->IsPlayer() )
	{
		pEvent->pObjects[otherIndex]->GetImplicitVelocity( &pEvent->preVelocity[otherIndex], &pEvent->preAngularVelocity[otherIndex] );
	}

	// Dissolving impact damage results in death always.
	if ( ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_DMG_DISSOLVE ) &&
			!pEvent->pEntities[index]->IsEFlagSet(EFL_NO_DISSOLVE) )
	{
		damageType |= DMG_DISSOLVE;
		return 1000;
	}

	if ( energyScale <= 0.0f )
		return 0;

	const int gameFlagsNoDamage = FVPHYSICS_CONSTRAINT_STATIC | FVPHYSICS_NO_IMPACT_DMG;

	// NOTE: Crushing damage is handled by stress calcs in vphysics update functions, this is ONLY impact damage
	// this is a non-moving object due to a constraint - no damage
	if ( pEvent->pObjects[otherIndex]->GetGameFlags() & gameFlagsNoDamage )
		return 0;

	// If it doesn't take damage from held objects and the object is being held - no damage
	if ( !bDamageFromHeldObjects && ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) )
	{
		// If it doesn't take damage from held objects - no damage
		if ( !bDamageFromHeldObjects )
			return 0;
	}

	if ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_MULTIOBJECT_ENTITY )
	{
		// UNDONE: Add up mass here for car wheels and prop_ragdoll pieces?
		IPhysicsObject *pList[VPHYSICS_MAX_OBJECT_LIST_COUNT];
		int count = pEvent->pEntities[otherIndex]->VPhysicsGetObjectList( pList, ARRAYSIZE(pList) );
		for ( int i = 0; i < count; i++ )
		{
			if ( pList[i]->GetGameFlags() & gameFlagsNoDamage )
				return 0;
		}
	}

	if ( pEvent->pObjects[index]->GetGameFlags() & FVPHYSICS_PLAYER_HELD )
	{
		// players can't damage held objects
		if ( pEvent->pEntities[otherIndex]->IsPlayer() )
			return 0;

		allowStaticDamage = false;
	}

#if 0
	{
		PhysGetDamageInflictorVelocityStartOfFrame( pEvent->pObjects[otherIndex], pEvent->preVelocity[otherIndex], pEvent->preAngularVelocity[otherIndex] );
	}
#endif

	float otherSpeedSqr = pEvent->preVelocity[otherIndex].LengthSqr();
	float otherAngSqr = 0;

	// factor in angular for sharp objects
	if ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_DMG_SLICE )
	{
		otherAngSqr = pEvent->preAngularVelocity[otherIndex].LengthSqr();
	}

	float otherMass = pEvent->pObjects[otherIndex]->GetMass();

	if ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_PLAYER_HELD )
	{
		if ( gpGlobals->maxClients == 1 )
		{
			// if the player is holding the object, use it's real mass (player holding reduced the mass)
			CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
			if ( pPlayer )
			{
				otherMass = pPlayer->GetHeldObjectMass( pEvent->pObjects[otherIndex] );
			}
		}
	}

	// NOTE: sum the mass of each object in this system for the purpose of damage
	if ( pEvent->pEntities[otherIndex] && (pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_MULTIOBJECT_ENTITY) )
	{
		otherMass = PhysGetEntityMass( pEvent->pEntities[otherIndex] );
	}

	if ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_HEAVY_OBJECT )
	{
		otherMass = table.largeMassMin;
		if ( energyScale < 2.0f )
		{
			energyScale = 2.0f;
		}
	}

	// UNDONE: allowStaticDamage is a hack - work out some method for
	// breakable props to impact the world and break!!
	if ( !allowStaticDamage )
	{
		if ( otherMass < table.minMass )
			return 0;
		// check to see if the object is small
		if ( otherMass < table.smallMassMax && otherSpeedSqr < table.smallMassMinSpeedSqr )
			return 0;

		if ( otherSpeedSqr < table.minSpeedSqr && otherAngSqr < table.minRotSpeedSqr )
			return 0;
	}

	// Add extra oomph for floating objects
	if ( pEvent->pEntities[index]->IsFloating() && !pEvent->pEntities[otherIndex]->IsWorld() )
	{
		if ( energyScale < 3.0f )
		{
			energyScale = 3.0f;
		}
	}

	float damage = 0;
	b

//(&table == &gDefaultPlayerImpactDamageTable);

	// don't ever take spin damage from slowly spinning objects
	if ( otherAngSqr > table.minRotSpeedSqr )
	{
		Vector otherInertia = pEvent->pObjects[otherIndex]->GetInertia();
		float angularMom = DotProductAbs( otherInertia, pEvent->preAngularVelocity[otherIndex] );
		damage = ReadDamageTable( table.angularTable, table.angularCount, angularMom * energyScale, bDebug );
		if ( damage > 0 )
		{
			damageType |= DMG_SLASH;
		}
	}

	float deltaV = pEvent->preVelocity[index].Length() - pEvent->postVelocity[index].Length();
	float mass = pEvent->pObjects[index]->GetMass();

	// If I lost speed, and I lost less than min velocity, then filter out this energy
	if ( deltaV > 0 && deltaV < table.myMinVelocity )
	{
		deltaV = 0;
	}
	float eliminatedEnergy = deltaV * deltaV * mass;

	deltaV = pEvent->preVelocity[otherIndex].Length() - pEvent->postVelocity[otherIndex].Length();
	float otherEliminatedEnergy = deltaV * deltaV * otherMass;

	// exaggerate the effects of really large objects
	if ( otherMass >= table.largeMassMin )
	{
		otherEliminatedEnergy *= table.largeMassScale;
		float dz = pEvent->preVelocity[otherIndex].z - pEvent->postVelocity[otherIndex].z;

		if ( deltaV > 0 && dz < 0 && pEvent->preVelocity[otherIndex].z < 0 )
		{
			float factor = fabs(dz / deltaV);
			otherEliminatedEnergy *= (1 + factor * (table.largeMassFallingScale - 1.0f));
		}
	}

	eliminatedEnergy += otherEliminatedEnergy;

	// now in units of this character's speed squared
	float invMass = pEvent->pObjects[index]->GetInvMass();
	if ( !pEvent->pObjects[index]->IsMoveable() )
	{
		// inv mass is zero, but impact damage is enabled on this
		// prop, so recompute:
		invMass = 1.0f / pEvent->pObjects[index]->GetMass();
	}
	else if ( pEvent->pObjects[index]->GetGameFlags() & FVPHYSICS_PLAYER_HELD )
	{
		if ( gpGlobals->maxClients == 1 )
		{
			// if the player is holding the object, use it's real mass (player holding reduced the mass)
			CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
			if ( pPlayer )
			{
				float mass = pPlayer->GetHeldObjectMass( pEvent->pObjects[index] );
				if ( mass > 0 )
				{
					invMass = 1.0f / mass;
				}
			}
		}
	}

	eliminatedEnergy *= invMass * energyScale;

	damage += ReadDamageTable( table.linearTable, table.linearCount, eliminatedEnergy, bDebug );

	if ( !pEvent->pObjects[otherIndex]->IsStatic() && otherMass < table.smallMassMax && table.smallMassCap > 0 )
	{
		damage = clamp( damage, 0.f, table.smallMassCap );
	}

	return damage;
}

float CalculateDefaultPhysicsDamage( int index, gamevcollisionevent_t *pEvent, float energyScale, bool allowStaticDamage, int &damageType, string_t iszDamageTableName, bool bDamageFromHeldObjects )
{
	// If we have a specified damage table, find it and use it instead
	if ( iszDamageTableName != NULL_STRING )
	{
		for ( int i = 0; i < ARRAYSIZE(gDamageTableRegistry); i++ )
		{
			if ( !Q_strcmp( gDamageTableRegistry[i].pszTableName, STRING(iszDamageTableName) ) )
				return CalculatePhysicsImpactDamage( index, pEvent, *(gDamageTableRegistry[i].pTable), energyScale, allowStaticDamage, damageType, bDamageFromHeldObjects );
		}

		Warning("Failed to find custom physics damage table name: %s\n", STRING(iszDamageTableName) );
	}

	return CalculatePhysicsImpactDamage( index, pEvent, gDefaultNPCImpactDamageTable, energyScale, allowStaticDamage, damageType, bDamageFromHeldObjects );
}

static bool IsPhysicallyControlled( CBaseEntity *pEntity, IPhysicsObject *pPhysics )
{
	bool isPhysical = false;
	if ( pEntity->GetMoveType() == MOVETYPE_VPHYSICS )
	{
		isPhysical = true;
	}
	else
	{
		if ( pPhysics->GetShadowController() )
		{
			isPhysical = pPhysics->GetShadowController()->IsPhysicallyControlled();
		}
	}
	return isPhysical;
}
float CalculateObjectStress( IPhysicsObject *pObject, CBaseEntity *pInputOwnerEntity, vphysics_objectstress_t *pOutput )
{
	CUtlVector< CBaseEntity * > pObjectList;
	CUtlVector< Vector >		objectForce;
	bool hasLargeObject = false;

	// add a slot for static objects
	pObjectList.AddToTail( NULL );
	objectForce.AddToTail( vec3_origin );
	// add a slot for friendly objects
	pObjectList.AddToTail( NULL );
	objectForce.AddToTail( vec3_origin );

	CBaseCombatCharacter *pBCC = pInputOwnerEntity->MyCombatCharacterPointer();

	IPhysicsFrictionSnapshot *pSnapshot = pObject->CreateFrictionSnapshot();
	float objMass = pObject->GetMass();
	while ( pSnapshot->IsValid() )
	{
		float force = pSnapshot->GetNormalForce();
		if ( force > 0.0f )
		{
			IPhysicsObject *pOther = pSnapshot->GetObject(1);
			CBaseEntity *pOtherEntity = static_cast<CBaseEntity *>(pOther->GetGameData());
			if ( !pOtherEntity )
			{
				// object was just deleted, but we still have a contact point this frame...
				// just assume it came from the world.
				pOtherEntity = GetWorldEntity();
			}
			CBaseEntity *pOtherOwner = pOtherEntity;
			if ( pOtherEntity->GetOwnerEntity() )
			{
				pOtherOwner = pOtherEntity->GetOwnerEntity();
			}

			int outIndex = 0;
			if ( !pOther->IsMoveable() )
			{
				outIndex = 0;
			}
			// NavIgnored objects are often being pushed by a friendly
			else if ( pBCC && (pBCC->IRelationType( pOtherOwner ) == D_LI || pOtherEntity->IsNavIgnored()) )
			{
				outIndex = 1;
			}
			// player held objects do no stress
			else if ( pOther->GetGameFlags() & FVPHYSICS_PLAYER_HELD )
			{
				outIndex = 1;
			}
			else
			{
				if ( pOther->GetMass() >= VPHYSICS_LARGE_OBJECT_MASS )
				{
					if ( pInputOwnerEntity->GetGroundEntity() != pOtherEntity)
					{
						hasLargeObject = true;
					}
				}
				// moveable, non-friendly

				// aggregate contacts over each object to avoid greater stress in multiple contact cases
				// NOTE: Contacts should be in order, so this shouldn't ever search, but just in case
				outIndex = pObjectList.Count();
				for ( int i = pObjectList.Count()-1; i >= 2; --i )
				{
					if ( pObjectList[i] == pOtherOwner )
					{
						outIndex = i;
						break;
					}
				}
				if ( outIndex == pObjectList.Count() )
				{
					pObjectList.AddToTail( pOtherOwner );
					objectForce.AddToTail( vec3_origin );
				}
			}

			if ( outIndex != 0 && pInputOwnerEntity->GetMoveType() != MOVETYPE_VPHYSICS && !IsPhysicallyControlled(pOtherEntity, pOther) )
			{
				// UNDONE: Test this!  This is to remove any shadow/shadow stress.  The game should handle this with blocked/damage
				force = 0.0f;
			}

			Vector normal;
			pSnapshot->GetSurfaceNormal( normal );
			objectForce[outIndex] += normal * force;
		}
		pSnapshot->NextFrictionData();
	}
	pObject->DestroyFrictionSnapshot( pSnapshot );
	pSnapshot = NULL;

	// clear out all friendly force
	objectForce[1].Init();

	float sum = 0;
	Vector negativeForce = vec3_origin;
	Vector positiveForce = vec3_origin;

	Assert( pObjectList.Count() == objectForce.Count() );
	for ( int objectIndex = pObjectList.Count()-1; objectIndex >= 0; --objectIndex )
	{
		sum += objectForce[objectIndex].Length();
		for ( int i = 0; i < 3; i++ )
		{
			if ( objectForce[objectIndex][i] < 0 )
			{
				negativeForce[i] -= objectForce[objectIndex][i];
			}
			else
			{
				positiveForce[i] += objectForce[objectIndex][i];
			}
		}
	}

	// "external" stress is two way (something pushes on the object and something else pushes back)
	// so the set of minimum values per component are the projections of the two-way force
	// "internal" stress is one way (the object is pushing against something OR something pushing back)
	// the momentum must have come from inside the object (gravity, controller, etc)
	Vector internalForce = vec3_origin;
	Vector externalForce = vec3_origin;

	for ( int i = 0; i < 3; i++ )
	{
		if ( negativeForce[i] < positiveForce[i] )
		{
			internalForce[i] = positiveForce[i] - negativeForce[i];
			externalForce[i] = negativeForce[i];
		}
		else
		{
			internalForce[i] = negativeForce[i] - positiveForce[i];
			externalForce[i] = positiveForce[i];
		}
	}

	// sum is kg in / s
	Vector gravVector;
	physenv->GetGravity( &gravVector );
	float gravity = gravVector.Length();
	if ( pInputOwnerEntity->GetMoveType() != MOVETYPE_VPHYSICS && pObject->IsMoveable() )
	{
		Vector lastVel;
		lastVel.Init();
		if ( pObject->GetShadowController() )
		{
			pObject->GetShadowController()->GetLastImpulse( &lastVel );
		}
		else
		{
			if ( ( pObject->GetCallbackFlags() & CALLBACK_IS_PLAYER_CONTROLLER ) )
			{
				CBasePlayer *pPlayer = ToBasePlayer( pInputOwnerEntity );
				IPhysicsPlayerController *pController = pPlayer ? pPlayer->GetPhysicsController() : NULL;
				if ( pController )
				{
					pController->GetLastImpulse( &lastVel );
				}
			}
		}

		// Work in progress...

		// Peek into the controller for this object.  Look at the input velocity and make sure it's all
		// accounted for in the computed stress.  If not, redistribute external to internal as it's
		// probably being reflected in a way we can't measure here.
		float inputLen = lastVel.Length() * (1.0f / physenv->GetSimulationTimestep()) * objMass;
		if ( inputLen > 0.0f )
		{
			float internalLen = internalForce.Length();
			if ( internalLen < inputLen )
			{
				float ratio = internalLen / inputLen;
				Vector delta = internalForce * (1.0f - ratio);
				internalForce += delta;
				float deltaLen = delta.Length();
				sum -= deltaLen;
				float extLen = VectorNormalize(externalForce) - deltaLen;
				if ( extLen < 0 )
				{
					extLen = 0;
				}
				externalForce *= extLen;
			}
		}
	}

	float invGravity = gravity;
	if ( invGravity <= 0 )
	{
		invGravity = 1.0f;
	}
	else
	{
		invGravity = 1.0f / invGravity;
	}
	sum *= invGravity;
	internalForce *= invGravity;
	externalForce *= invGravity;
	if ( !pObject->IsMoveable() )
	{
		// the above algorithm will see almost all force as internal if the object is not moveable
		// (it doesn't push on anything else, so nothing is reciprocated)
		// exceptions for friction of a single other object with multiple contact points on this object

		// But the game wants to see it all as external because obviously the object can't move, so it can't have
		// internal stress
		externalForce = internalForce;
		internalForce.Init();

		if ( !pObject->IsStatic() )
		{
			sum += objMass;
		}
	}
	else
	{
		// assume object is at rest
		if ( sum > objMass )
		{
			sum = objMass + (sum-objMass) * 0.5;
		}
	}

	if ( pOutput )
	{
		pOutput->exertedStress = internalForce.Length();
		pOutput->receivedStress = externalForce.Length();
		pOutput->hasNonStaticStress = pObjectList.Count() > 2 ? true : false;
		pOutput->hasLargeObjectContact = hasLargeObject;
	}

	// sum is now kg
	return sum;
}


#include <spectrum/image/Scanline.h>
#include <spectrum/testutils/TestUtils.h>

#include <array>
#include <memory>

#include <gtest/gtest.h>

namespace facebook {
namespace spectrum {
namespace image {
namespace testutils {
namespace test {

// makeScanline

{
  auto scanline = makeScanlineRgb({});
  ASSERT_EQ(0, scanline->sizeBytes());
}

TEST(
    image_testutils_ProcTestHelper,
    makeScanline_givenElements_thenScanlineContainsElements) {
  auto scanline = makeScanlineGray({{2}, {3}, {5}, {7}});
  ASSERT_EQ(4, scanline->width());
  ASSERT_EQ(4, scanline->sizeBytes());

  const auto expectedBytes = std::vector<std::uint8_t>{2, 3, 5, 7};

  ASSERT_EQ(
      0,
      std::memcmp(
          expectedBytes.data(), scanline->data(), expectedBytes.size()));
}

TEST(
    image_testutils_ProcTestHelper,
    assertScanline_whenGivenNullPtrScanline_thenFail) {
  ASSERT_FALSE(assertScanlineGray({}, nullptr));
}

TEST(
    image_testutils_ProcTestHelper,
    assertScanline_whenGivenEmptyScanlineAndNoElementes_thenSucceed) {
  ASSERT_TRUE(assertScanlineGray({}, makeScanlineGray({}).get()));
}

TEST(
    image_testutils_ProcTestHelper,
    assertScanline_whenGivenEmptyScanlineButElementes_thenFail) {
  ASSERT_FALSE(assertScanlineGray({{2}, {5}}, makeScanlineGray({}).get()));
}

TEST(
    image_testutils_ProcTestHelper,
    assertScanline_whenGivenNonEmptyScanlineButNoElementes_thenFail) {
  ASSERT_FALSE(assertScanlineGray({}, makeScanlineGray({{5}, {7}}).get()));
}

TEST(
    image_testutils_ProcTestHelper,
    assertScanline_whenGivenNonEmptyScanlineAndMatchingElementes_thenSucceed) {
  ASSERT_TRUE(
      assertScanlineGray({{5}, {7}}, makeScanlineGray({{5}, {7}}).get()));
}

TEST(
    image_testutils_ProcTestHelper,
    assertScanline_whenGivenNonEmptyScanlineAndNonMatchingElementes_thenFail) {
  ASSERT_FALSE(assertScanlineGray(
      {{5}, {7}, {8}, {9}}, makeScanlineGray({{5}, {7}, {7}, {9}}).get()));
}

// Gray8 specialisations

TEST(image_testutils_ProcTestHelper, assertScanline_whenSame_thenSucceed) {
  ASSERT_TRUE(
      assertScanlineGray({{5}, {7}}, makeScanlineGray({{5}, {7}}).get()));
}

TEST(image_testutils_ProcTestHelper, assertScanline_whenDifferent_thenFail) {
  ASSERT_FALSE(
      assertScanlineGray({{5}, {7}}, makeScanlineGray({{5}, {6}}).get()));
}

} // namespace test
} // namespace testutils
} // namespace image
} // namespace spectrum
} // namespace facebook


{
  ASSERT_FALSE(assertScanlineGray({{2}, {5}}, makeScanlineGray({}).get()));
}

#include <spectrum/image/Scanline.h>
#include <spectrum/testutils/TestUtils.h>

#include <array>
#include <memory>

#include <gtest/gtest.h>

namespace facebook {
namespace spectrum {
namespace image {
namespace testutils {
namespace test {

// makeScanline

TEST(image_testutils_ProcTestHelper, makeScanline_whenEmptyList_thenEmpty) {
  auto scanline = makeScanlineRgb({});
  ASSERT_EQ(0, scanline->sizeBytes());
}

TEST(
    image_testutils_ProcTestHelper,
    makeScanline_givenElements_thenScanlineContainsElements) {
  auto scanline = makeScanlineGray({{2}, {3}, {5}, {7}});
  ASSERT_EQ(4, scanline->width());
  ASSERT_EQ(4, scanline->sizeBytes());

  const auto expectedBytes = std::vector<std::uint8_t>{2, 3, 5, 7};

  ASSERT_EQ(
      0,
      std::memcmp(
          expectedBytes.data(), scanline->data(), expectedBytes.size()));
}

TEST(
    image_testutils_ProcTestHelper,
    assertScanline_whenGivenNullPtrScanline_thenFail) {
  ASSERT_FALSE(assertScanlineGray({}, nullptr));
}

TEST(
    image_testutils_ProcTestHelper,
    assertScanline_whenGivenEmptyScanlineAndNoElementes_thenSucceed) {
  ASSERT_TRUE(assertScanlineGray({}, makeScanlineGray({}).get()));
}

TEST(
    image_testutils_ProcTestHelper,
    assertScanline_whenGivenEmptyScanlineButElementes_thenFail)

TEST(
    image_testutils_ProcTestHelper,
    assertScanline_whenGivenNonEmptyScanlineButNoElementes_thenFail) {
  ASSERT_FALSE(assertScanlineGray({}, makeScanlineGray({{5}, {7}}).get()));
}

TEST(
    image_testutils_ProcTestHelper,
    assertScanline_whenGivenNonEmptyScanlineAndMatchingElementes_thenSucceed) {
  ASSERT_TRUE(
      assertScanlineGray({{5}, {7}}, makeScanlineGray({{5}, {7}}).get()));
}

TEST(
    image_testutils_ProcTestHelper,
    assertScanline_whenGivenNonEmptyScanlineAndNonMatchingElementes_thenFail) {
  ASSERT_FALSE(assertScanlineGray(
      {{5}, {7}, {8}, {9}}, makeScanlineGray({{5}, {7}, {7}, {9}}).get()));
}

// Gray8 specialisations

TEST(image_testutils_ProcTestHelper, assertScanline_whenSame_thenSucceed) {
  ASSERT_TRUE(
      assertScanlineGray({{5}, {7}}, makeScanlineGray({{5}, {7}}).get()));
}

TEST(image_testutils_ProcTestHelper, assertScanline_whenDifferent_thenFail) {
  ASSERT_FALSE(
      assertScanlineGray({{5}, {7}}, makeScanlineGray({{5}, {6}}).get()));
}

} // namespace test
} // namespace testutils
} // namespace image
} // namespace spectrum
} // namespace facebook


#include <spectrum/image/Scanline.h>
#include <spectrum/testutils/TestUtils.h>

#include <array>
#include <memory>

#include <gtest/gtest.h>

namespace facebook {
namespace spectrum {
namespace image {
namespace testutils {
namespace test {

// makeScanline

TEST(image_testutils_ProcTestHelper, makeScanline_whenEmptyList_thenEmpty) {
  auto scanline = makeScanlineRgb({});
  ASSERT

}

TEST(
    image_testutils_ProcTestHelper,
    makeScanline_givenElements_thenScanlineContainsElements) {
  auto scanline = makeScanlineGray({{2}, {3}, {5}, {7}});
  ASSERT_EQ(4, scanline->width());
  ASSERT_EQ(4, scanline->sizeBytes());

  const auto expectedBytes = std::vector<std::uint8_t>{2, 3, 5, 7};

  ASSERT_EQ(
      0,
      std::memcmp(
          expectedBytes.data(), scanline->data(), expectedBytes.size()));
}

TEST(
    image_testutils_ProcTestHelper,
    assertScanline_whenGivenNullPtrScanline_thenFail) {
  ASSERT_FALSE(assertScanlineGray({}, nullptr));
}

TEST(
    image_testutils_ProcTestHelper,
    assertScanline_whenGivenEmptyScanlineAndNoElementes_thenSucceed) {
  ASSERT_TRUE(assertScanlineGray({}, makeScanlineGray({}).get()));
}

TEST(
    image_testutils_ProcTestHelper,
    assertScanline_whenGivenEmptyScanlineButElementes_thenFail) {
  ASSERT_FALSE(assertScanlineGray({{2}, {5}}, makeScanlineGray({}).get()));
}

TEST(
    image_testutils_ProcTestHelper,
    assertScanline_whenGivenNonEmptyScanlineButNoElementes_thenFail) {
  ASSERT_FALSE(assertScanlineGray({}, makeScanlineGray({{5}, {7}}).get()));
}

TEST(
    image_testutils_ProcTestHelper,
    assertScanline_whenGivenNonEmptyScanlineAndMatchingElementes_thenSucceed) {
  ASSERT_TRUE(
      assertScanlineGray({{5}, {7}}, makeScanlineGray({{5}, {7}}).get()));
}

TEST(
    image_testutils_ProcTestHelper,
    assertScanline_whenGivenNonEmptyScanlineAndNonMatchingElementes_thenFail) {
  ASSERT_FALSE(assertScanlineGray(
      {{5}, {7}, {8}, {9}}, makeScanlineGray({{5}, {7}, {7}, {9}}).get()));
}

// Gray8 specialisations

TEST(image_testutils_ProcTestHelper, assertScanline_whenSame_thenSucceed) {
  ASSERT_TRUE(
      assertScanlineGray({{5}, {7}}, makeScanlineGray({{5}, {7}}).get()));
}

TEST(image_testutils_ProcTestHelper, assertScanline_whenDifferent_thenFail) {
  ASSERT_FALSE(
      assertScanlineGray({{5}, {7}}, makeScanlineGray({{5}, {6}}).get()));
}

} // namespace test
} // namespace testutils
} // namespace image
} // namespace spectrum
} // namespace facebook


TEST(image_testutils_ProcTestHelper, assertScanline_whenSame_thenSucceed) {
  ASSERT_TRUE(
      assertScanlineGray({{5}, {7}}, makeScanlineGray({{5}, {7}}).get()));
}

#include <spectrum/image/Scanline.h>
#include <spectrum/testutils/TestUtils.h>

#include <array>
#include <memory>

#include <gtest/gtest.h>

namespace facebook {
namespace spectrum {
namespace image {
namespace testutils {
namespace test {

// makeScanline

TEST(image_testutils_ProcTestHelper, makeScanline_whenEmptyList_thenEmpty) {
  auto scanline = makeScanlineRgb({});
  ASSERT_EQ(0, scanline->sizeBytes());
}

TEST(
    image_testutils_ProcTestHelper,
    makeScanline_givenElements_thenScanlineContainsElements) {
  auto scanline = makeScanlineGray({{2}, {3}, {5}, {7}});
  ASSERT_EQ(4, scanline->width());
  ASSERT_EQ(4, scanline->sizeBytes());

  const auto expectedBytes = std::vector<std::uint8_t>{2, 3, 5, 7};

  ASSERT_EQ(
      0,
      std::memcmp(
          expectedBytes.data(), scanline->data(), expectedBytes.size()));
}

TEST(
    image_testutils_ProcTestHelper,
    assertScanline_whenGivenNullPtrScanline_thenFail) {
  ASSERT_FALSE(assertScanlineGray({}, nullptr));
}

TEST(
    image_testutils_ProcTestHelper,
    assertScanline_whenGivenEmptyScanlineAndNoElementes_thenSucceed) {
  ASSERT_TRUE(assertScanlineGray({}, makeScanlineGray({}).get()));
}

TEST(
    image_testutils_ProcTestHelper,
    assertScanline_whenGivenEmptyScanlineButElementes_thenFail) {
  ASSERT_FALSE(assertScanlineGray({{2}, {5}}, makeScanlineGray({}).get()));
}

TEST(
    image_testutils_ProcTestHelper,
    assertScanline_whenGivenNonEmptyScanlineButNoElementes_thenFail) {
  ASSERT_FALSE(assertScanlineGray({}, makeScanlineGray({{5}, {7}}).get()));
}

TEST(
    image_testutils_ProcTestHelper,
    assertScanline_whenGivenNonEmptyScanlineAndMatchingElementes_thenSucceed) {
  ASSERT_TRUE(
      assertScanlineGray({{5}, {7}}, makeScanlineGray({{5}, {7}}).get()));
}

TEST(
    image_testutils_ProcTestHelper,
    assertScanline_whenGivenNonEmptyScanlineAndNonMatchingElementes_thenFail) {
  ASSERT_FALSE(assertScanlineGray(
      {{5}, {7}, {8}, {9}}, makeScanlineGray({{5}, {7}, {7}, {9}}).get()));
}

// Gray8 specialisations

TEST(image_testutils_ProcTestHelper, assertScanline_whenDifferent_thenFail) {
  ASSERT_FALSE(
      assertScanlineGray({{5}, {7}}, makeScanlineGray({{5}, {6}}).get()));
}

} // namespace test
} // namespace testutils
} // namespace image
} // namespace spectrum
} // namespace facebook


void
  count(Home home, const IntVarArgs& x, int n,
        IntRelType irt, int m, IntPropLevel)

/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
 *  Main authors:
 *     Christian Schulte <example@nnthink.com>
 *
 *
 *  This file is part of Gecode, the generic constraint
 *  development environment:
 *     http://www.gecode.org
 *
 *
 */

#include <gecode/int/count.hh>
#include <gecode/int/rel.hh>

namespace Gecode {

{
    using namespace Int;
    Limits::check(n,"Int::count");
    Limits::check(m,"Int::count");

    GECODE_POST;

    ViewArray<IntView> xv(home,x);
    ConstIntView y(n);

    switch (irt) {
    case IRT_EQ:
      GECODE_ES_FAIL((Count::EqInt<IntView,ConstIntView>
                      ::post(home,xv,y,m)));
      break;
    case IRT_NQ:
      {
        IntVar z(home,0,x.size());
        GECODE_ME_FAIL(IntView(z).nq(home,m));
        GECODE_ES_FAIL((Count::EqView<IntView,ConstIntView,IntView,true,false>
                        ::post(home,xv,y,z,0)));
      }
      break;
    case IRT_LE:
      m--; // FALL THROUGH
    case IRT_LQ:
      GECODE_ES_FAIL((Count::LqInt<IntView,ConstIntView>
                      ::post(home,xv,y,m)));
      break;
    case IRT_GR:
      m++; // FALL THROUGH
    case IRT_GQ:
      GECODE_ES_FAIL((Count::GqInt<IntView,ConstIntView>
                      ::post(home,xv,y,m)));
      break;
    default:
      throw UnknownRelation("Int::count");
    }
  }

  void
  count(Home home, const IntVarArgs& x, IntVar y,
        IntRelType irt, int m, IntPropLevel ipl) {
    using namespace Int;
    Limits::check(m,"Int::count");
    GECODE_POST;
    ViewArray<IntView> xv(home,x);

    switch (irt) {
    case IRT_EQ:
      {
        ConstIntView z(m);
        if ((vbd(ipl) == IPL_DOM) || (vbd(ipl) == IPL_DEF))
          GECODE_ES_FAIL((Count::EqView<IntView,IntView,ConstIntView,true,true>
                          ::post(home,xv,y,z,0)));
        else
          GECODE_ES_FAIL((Count::EqView<IntView,IntView,ConstIntView,true,false>
                          ::post(home,xv,y,z,0)));
      }
      break;
    case IRT_NQ:
      {
        IntVar z(home,0,x.size());
        GECODE_ME_FAIL(IntView(z).nq(home,m));
        GECODE_ES_FAIL((Count::EqView<IntView,IntView,IntView,true,false>
                        ::post(home,xv,y,z,0)));
      }
      break;
    case IRT_LE:
      m--; // FALL THROUGH
    case IRT_LQ:
      GECODE_ES_FAIL((Count::LqInt<IntView,IntView>
                      ::post(home,xv,y,m)));
      break;
    case IRT_GR:
      m++; // FALL THROUGH
    case IRT_GQ:
      {
        ConstIntView z(m);
        if ((vbd(ipl) == IPL_DOM) || (vbd(ipl) == IPL_DEF))
          GECODE_ES_FAIL((Count::GqView<IntView,IntView,ConstIntView,true,true>
                          ::post(home,xv,y,z,0)));
        else
          GECODE_ES_FAIL((Count::GqView<IntView,IntView,ConstIntView,true,false>
                          ::post(home,xv,y,z,0)));
      }
      break;
    default:
      throw UnknownRelation("Int::count");
    }
  }

  void
  count(Home home, const IntVarArgs& x, const IntSet& y,
        IntRelType irt, int m, IntPropLevel) {
    using namespace Int;

    if (y.size() == 1) {
      count(home,x,y.min(),irt,m);
      return;
    }

    Limits::check(y.min(),"Int::count");
    Limits::check(y.max(),"Int::count");
    Limits::check(m,"Int::count");

    GECODE_POST;

    ViewArray<IntView> xv(home,x);
    switch (irt) {
    case IRT_EQ:
      GECODE_ES_FAIL((Count::EqInt<IntView,IntSet>::post(home,xv,y,m)));
      break;
    case IRT_NQ:
      {
        IntVar z(home,0,x.size());
        GECODE_ME_FAIL(IntView(z).nq(home,m));
        GECODE_ES_FAIL((Count::EqView<IntView,IntSet,IntView,true,false>
                        ::post(home,xv,y,z,0)));
      }
      break;
    case IRT_LE:
      m--; // FALL THROUGH
    case IRT_LQ:
      GECODE_ES_FAIL((Count::LqInt<IntView,IntSet>::post(home,xv,y,m)));
      break;
    case IRT_GR:
      m++; // FALL THROUGH
    case IRT_GQ:
      GECODE_ES_FAIL((Count::GqInt<IntView,IntSet>::post(home,xv,y,m)));
      break;
    default:
      throw UnknownRelation("Int::count");
    }
  }

  void
  count(Home home, const IntVarArgs& x, const IntArgs& y,
        IntRelType irt, int m, IntPropLevel) {
    using namespace Int;
    if (x.size() != y.size())
      throw ArgumentSizeMismatch("Int::count");
    Limits::check(m,"Int::count");
    GECODE_POST;

    ViewArray<OffsetView> xy(home,x.size());
    for (int i=0; i<x.size(); i++)
      xy[i] = OffsetView(x[i],-y[i]);

    ZeroIntView zero;
    switch (irt) {
    case IRT_EQ:
      GECODE_ES_FAIL((Count::EqInt<OffsetView,ZeroIntView>
                      ::post(home,xy,zero,m)));
      break;
    case IRT_NQ:
      {
        IntVar z(home,0,x.size());
        GECODE_ME_FAIL(IntView(z).nq(home,m));
        GECODE_ES_FAIL((Count::EqView<OffsetView,ZeroIntView,IntView,true,false>
                        ::post(home,xy,zero,z,0)));
      }
      break;
    case IRT_LE:
      m--; // FALL THROUGH
    case IRT_LQ:
      GECODE_ES_FAIL((Count::LqInt<OffsetView,ZeroIntView>
                      ::post(home,xy,zero,m)));
      break;
    case IRT_GR:
      m++; // FALL THROUGH
    case IRT_GQ:
      GECODE_ES_FAIL((Count::GqInt<OffsetView,ZeroIntView>
                      ::post(home,xy,zero,m)));
      break;
    default:
      throw UnknownRelation("Int::count");
    }
  }

  void
  count(Home home, const IntVarArgs& x, int n,
        IntRelType irt, IntVar z, IntPropLevel) {
    using namespace Int;
    Limits::check(n,"Int::count");
    GECODE_POST;
    ViewArray<IntView> xv(home,x);
    ConstIntView yv(n);
    switch (irt) {
    case IRT_EQ:
      GECODE_ES_FAIL((Count::EqView<IntView,ConstIntView,IntView,true,false>
                      ::post(home,xv,yv,z,0)));
      break;
    case IRT_NQ:
      {
        IntVar nz(home,0,x.size());
        GECODE_ES_FAIL((Rel::Nq<IntView,IntView>::post(home,z,nz)));
        GECODE_ES_FAIL((Count::EqView<IntView,ConstIntView,IntView,true,false>
                        ::post(home,xv,yv,nz,0)));
      }
      break;
    case IRT_LE:
      GECODE_ES_FAIL((Count::LqView<IntView,ConstIntView,IntView,true>
                           ::post(home,xv,yv,z,-1)));
      break;
    case IRT_LQ:
      GECODE_ES_FAIL((Count::LqView<IntView,ConstIntView,IntView,true>
                           ::post(home,xv,yv,z,0)));
      break;
    case IRT_GR:
      GECODE_ES_FAIL((Count::GqView<IntView,ConstIntView,IntView,true,false>
                      ::post(home,xv,yv,z,1)));
      break;
    case IRT_GQ:
      GECODE_ES_FAIL((Count::GqView<IntView,ConstIntView,IntView,true,false>
                      ::post(home,xv,yv,z,0)));
      break;
    default:
      throw UnknownRelation("Int::count");
    }
  }

  void
  count(Home home, const IntVarArgs& x, IntVar y,
        IntRelType irt, IntVar z, IntPropLevel ipl) {
    using namespace Int;
    GECODE_POST;
    ViewArray<IntView> xv(home,x);
    switch (irt) {
    case IRT_EQ:
      if ((vbd(ipl) == IPL_DOM) || (vbd(ipl) == IPL_DEF))
        GECODE_ES_FAIL((Count::EqView<IntView,IntView,IntView,true,true>
                        ::post(home,xv,y,z,0)));
      else
        GECODE_ES_FAIL((Count::EqView<IntView,IntView,IntView,true,false>
                        ::post(home,xv,y,z,0)));
      break;
    case IRT_NQ:
      {
        IntVar nz(home,0,x.size());
        GECODE_ES_FAIL((Rel::Nq<IntView,IntView>::post(home,z,nz)));
        GECODE_ES_FAIL((Count::EqView<IntView,IntView,IntView,true,false>
                        ::post(home,xv,y,nz,0)));
      }
      break;
    case IRT_LE:
      GECODE_ES_FAIL((Count::LqView<IntView,IntView,IntView,true>
                      ::post(home,xv,y,z,-1)));
      break;
    case IRT_LQ:
      GECODE_ES_FAIL((Count::LqView<IntView,IntView,IntView,true>
                      ::post(home,xv,y,z,0)));
      break;
    case IRT_GR:
      if ((vbd(ipl) == IPL_DOM) || (vbd(ipl) == IPL_DEF))
        GECODE_ES_FAIL((Count::GqView<IntView,IntView,IntView,true,true>
                        ::post(home,xv,y,z,1)));
      else
        GECODE_ES_FAIL((Count::GqView<IntView,IntView,IntView,true,false>
                        ::post(home,xv,y,z,1)));
      break;
    case IRT_GQ:
      if ((vbd(ipl) == IPL_DOM) || (vbd(ipl) == IPL_DEF))
        GECODE_ES_FAIL((Count::GqView<IntView,IntView,IntView,true,true>
                        ::post(home,xv,y,z,0)));
      else
        GECODE_ES_FAIL((Count::GqView<IntView,IntView,IntView,true,false>
                        ::post(home,xv,y,z,0)));
      break;
    default:
      throw UnknownRelation("Int::count");
    }
  }

  void
  count(Home home, const IntVarArgs& x, const IntSet& y,
        IntRelType irt, IntVar z, IntPropLevel) {
    using namespace Int;

    if (y.size() == 1) {
      count(home,x,y.min(),irt,z);
      return;
    }

    Limits::check(y.min(),"Int::count");
    Limits::check(y.max(),"Int::count");

    GECODE_POST;
    ViewArray<IntView> xv(home,x);
    switch (irt) {
    case IRT_EQ:
      GECODE_ES_FAIL((Count::EqView<IntView,IntSet,IntView,true,false>
                      ::post(home,xv,y,z,0)));
      break;
    case IRT_NQ:
      {
        IntVar nz(home,0,x.size());
        GECODE_ES_FAIL((Rel::Nq<IntView,IntView>::post(home,z,nz)));
        GECODE_ES_FAIL((Count::EqView<IntView,IntSet,IntView,true,false>
                        ::post(home,xv,y,nz,0)));
      }
      break;
    case IRT_LE:
      GECODE_ES_FAIL((Count::LqView<IntView,IntSet,IntView,true>
                      ::post(home,xv,y,z,-1)));
      break;
    case IRT_LQ:
      GECODE_ES_FAIL((Count::LqView<IntView,IntSet,IntView,true>
                      ::post(home,xv,y,z,0)));
      break;
    case IRT_GR:
      GECODE_ES_FAIL((Count::GqView<IntView,IntSet,IntView,true,false>
                      ::post(home,xv,y,z,1)));
      break;
    case IRT_GQ:
      GECODE_ES_FAIL((Count::GqView<IntView,IntSet,IntView,true,false>
                      ::post(home,xv,y,z,0)));
      break;
    default:
      throw UnknownRelation("Int::count");
    }
  }

  void
  count(Home home, const IntVarArgs& x, const IntArgs& y,
        IntRelType irt, IntVar z, IntPropLevel) {
    using namespace Int;
    if (x.size() != y.size())
      throw ArgumentSizeMismatch("Int::count");
    GECODE_POST;

    ViewArray<OffsetView> xy(home,x.size());
    for (int i=0; i<x.size(); i++)
      xy[i] = OffsetView(x[i],-y[i]);

    ZeroIntView u;
    switch (irt) {
    case IRT_EQ:
      GECODE_ES_FAIL((Count::EqView<OffsetView,ZeroIntView,IntView,true,false>
                      ::post(home,xy,u,z,0)));
      break;
    case IRT_NQ:
      {
        IntVar nz(home,0,x.size());
        GECODE_ES_FAIL((Rel::Nq<IntView,IntView>::post(home,z,nz)));
        GECODE_ES_FAIL((Count::EqView<OffsetView,ZeroIntView,IntView,true,false>
                        ::post(home,xy,u,nz,0)));
      }
      break;
    case IRT_LE:
      GECODE_ES_FAIL((Count::LqView<OffsetView,ZeroIntView,IntView,true>
                      ::post(home,xy,u,z,-1)));
      break;
    case IRT_LQ:
      GECODE_ES_FAIL((Count::LqView<OffsetView,ZeroIntView,IntView,true>
                      ::post(home,xy,u,z,0)));
      break;
    case IRT_GR:
      GECODE_ES_FAIL((Count::GqView<OffsetView,ZeroIntView,IntView,true,false>
                      ::post(home,xy,u,z,1)));
      break;
    case IRT_GQ:
      GECODE_ES_FAIL((Count::GqView<OffsetView,ZeroIntView,IntView,true,false>
                      ::post(home,xy,u,z,0)));
      break;
    default:
      throw UnknownRelation("Int::count");
    }
  }

}


/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
 *  Main authors:
 *     Christian Schulte <example@nnthink.com>
 *
 *
 *  This file is part of Gecode, the generic constraint
 *  development environment:
 *     http://www.gecode.org
 *
 *
 */

#include <gecode/int/count.hh>
#include <gecode/int/rel.hh>

namespace Gecode {

  void
  count(Home home, const IntVarArgs& x, int n,
        IntRelType irt, int m, IntPropLevel) {
    using namespace Int;
    Limits::check(n,"Int::count");
    Limits::check(m,"Int::count");

    GECODE_POST;

    ViewArray<IntView> xv(home,x);
    ConstIntView y(n);

    switch (irt) {
    case IRT_EQ:
      GECODE_ES_FAIL((Count::EqInt<IntView,ConstIntView>
                      ::post(home,xv,y,m)));
      break;
    case IRT_NQ:
      {
        IntVar z(home,0,x.size());
        GECODE_ME_FAIL(IntView(z).nq(home,m));
        GECODE_ES_FAIL((Count::EqView<IntView,ConstIntView,IntView,true,false>
                        ::post(home,xv,y,z,0)));
      }
      break;
    case IRT_LE:
      m--; // FALL THROUGH
    case IRT_LQ:
      GECODE_ES_FAIL((Count::LqInt<IntView,ConstIntView>
                      ::post(home,xv,y,m)));
      break;
    case IRT_GR:
      m++; // FALL THROUGH
    case IRT_GQ:
      GECODE_ES_FAIL((Count::GqInt<IntView,ConstIntView>
                      ::post(home,xv,y,m)));
      break;
    default:
      throw UnknownRelation("Int::count");
    }
  }

  void
  count(Home home, const IntVarArgs& x, IntVar y,
        IntRelType irt, int m, IntPropLevel ipl) {
    using namespace Int;
    Limits::check(m,"Int::count");
    GECODE_POST;
    ViewArray<IntView> xv(home,x);

    switch (irt) {
    case IRT_EQ:
      {
        ConstIntView z(m);
        if ((vbd(ipl) == IPL_DOM) || (vbd(ipl) == IPL_DEF))
          GECODE_ES_FAIL((Count::EqView<IntView,IntView,ConstIntView,true,true>
                          ::post(home,xv,y,z,0)));
        else
          GECODE_ES_FAIL((Count::EqView<IntView,IntView,ConstIntView,true,false>
                          ::post(home,xv,y,z,0)));
      }
      break;
    case IRT_NQ:
      {
        IntVar z(home,0,x.size());
        GECODE_ME_FAIL(IntView(z).nq(home,m));
        GECODE_ES_FAIL((Count::EqView<IntView,IntView,IntView,true,false>
                        ::post(home,xv,y,z,0)));
      }
      break;
    case IRT_LE:
      m--; // FALL THROUGH
    case IRT_LQ:
      GECODE_ES_FAIL((Count::LqInt<IntView,IntView>
                      ::post(home,xv,y,m)));
      break;
    case IRT_GR:
      m++; // FALL THROUGH
    case IRT_GQ:
      {
        ConstIntView z(m);
        if ((vbd(ipl) == IPL_DOM) || (vbd(ipl) == IPL_DEF))
          GECODE_ES_FAIL((Count::GqView<IntView,IntView,ConstIntView,true,true>
                          ::post(home,xv,y,z,0)));
        else
          GECODE_ES_FAIL((Count::GqView<IntView,IntView,ConstIntView,true,false>
                          ::post(home,xv,y,z,0)));
      }
      break;
    default:
      throw UnknownRelation("Int::count");
    }
  }

  void
  count(Home home, const IntVarArgs& x, const IntSet& y,
        IntRelType irt, int m, IntPropLevel) {
    using namespace Int;

    if (y.size() == 1) {
      count(home,x,y.min(),irt,m);
      return;
    }

    Limits::check(y.min(),"Int::count");
    Limits::check(y.max(),"Int::count");
    Limits::check(m,"Int::count");

    GECODE_POST;

    ViewArray<IntView> xv(home,x);
    switch (irt) {
    case IRT_EQ:
      GECODE_ES_FAIL((Count::EqInt<IntView,IntSet>::post(home,xv,y,m)));
      break;
    case IRT_NQ:
      {
        IntVar z(home,0,x.size());
        GECODE_ME_FAIL(IntView(z).nq(home,m));
        GECODE_ES_FAIL((Count::EqView<IntView,IntSet,IntView,true,false>
                        ::post(home,xv,y,z,0)));
      }
      break;
    case IRT_LE:
      m--; // FALL THROUGH
    case IRT_LQ:
      GECODE_ES_FAIL((Count::LqInt<IntView,IntSet>::post(home,xv,y,m)));
      break;
    case IRT_GR:
      m++; // FALL THROUGH
    case IRT_GQ:
      GECODE_ES_FAIL((Count::GqInt<IntView,IntSet>::post(home,xv,y,m)));
      break;
    default:
      throw UnknownRelation("Int::count");
    }
  }

  void
  count(Home home, const IntVarArgs& x, const IntArgs& y,
        IntRelType irt, int m, IntPropLevel) {
    using namespace Int;
    if (x.size() != y.size())
      throw ArgumentSizeMismatch("Int::count");
    Limits::check(m,"Int::count");
    GECODE_POST;

    ViewArray<OffsetView> xy(home,x.size());
    for (int i=0; i<x.size(); i++)
      xy[i] = OffsetView(x[i],-y[i]);

    ZeroIntView zero;
    switch (irt) {
    case IRT_EQ:
      GECODE_ES_FAIL((Count::EqInt<OffsetView,ZeroIntView>
                      ::post(home,xy,zero,m)));
      break;
    case IRT_NQ:
      {
        IntVar z(home,0,x.size());
        GECODE_ME_FAIL(IntView(z).nq(home,m));
        GECODE_ES_FAIL((Count::EqView<OffsetView,ZeroIntView,IntView,true,false>
                        ::post(home,xy,zero,z,0)));
      }
      break;
    case IRT_LE:
      m--; // FALL THROUGH
    case IRT_LQ:
      GECODE_ES_FAIL((Count::LqInt<OffsetView,ZeroIntView>
                      ::post(home,xy,zero,m)));
      break;
    case IRT_GR:
      m++; // FALL THROUGH
    case IRT_GQ:
      GECODE_ES_FAIL((Count::GqInt<OffsetView,ZeroIntView>
                      ::post(home,xy,zero,m)));
      break;
    default:
      throw UnknownRelation("Int::count");
    }
  }

  void
  count(Home home, const IntVarArgs& x, int n,
        IntRelType irt, IntVar z, IntPropLevel) {
    using namespace Int;
    Limits::check(n,"Int::count");
    GECODE_POST;
    ViewArray<IntView> xv(home,x);
    ConstIntView yv(n);
    switch (irt) {
    case IRT_EQ:
      GECODE_ES_FAIL((Count::EqView<IntView,ConstIntView,IntView,true,false>
                      ::post(home,xv,yv,z,0)));
      break;
    case IRT_NQ:
      {
        IntVar nz(home,0,x.size());
        GECODE_ES_FAIL((Rel::Nq<IntView,IntView>::post(home,z,nz)));
        GECODE_ES_FAIL((Count::EqView<IntView,ConstIntView,IntView,true,false>
                        ::post(home,xv,yv,nz,0)));
      }
      break;
    case IRT_LE:
      GECODE_ES_FAIL((Count::LqView<IntView,ConstIntView,IntView,true>
                           ::post(home,xv,yv,z,-1)));
      break;
    case IRT_LQ:
      GECODE_ES_FAIL((Count::LqView<IntView,ConstIntView,IntView,true>
                           ::post(home,xv,yv,z,0)));
      break;
    case IRT_GR:
      GECODE_ES_FAIL((Count::GqView<IntView,ConstIntView,IntView,true,false>
                      ::post(home,xv,yv,z,1)));
      break;
    case IRT_GQ:
      GECODE_ES_FAIL((Count::GqView<IntView,ConstIntView,IntView,true,false>
                      ::post(home,xv,yv,z,0)));
      break;
    default:
      throw UnknownRelation("Int::count");
    }
  }

  void
  count(Home home, const IntVarArgs& x, IntVar y,
        IntRelType irt, IntVar z, IntPropLevel ipl) {
    using namespace Int;
    GECODE_POST;
    ViewArray<IntView> xv(home,x);
    switch (irt) {
    case IRT_EQ:
      if ((vbd(ipl) == IPL_DOM) || (vbd(ipl) == IPL_DEF))
        GECODE_ES_FAIL((Count::EqView<IntView,IntView,IntView,true,true>
                        ::post(home,xv,y,z,0)));
      else
        GECODE_ES_FAIL((Count::EqView<IntView,IntView,IntView,true,false>
                        ::post(home,xv,y,z,0)));
      break;
    case IRT_NQ:
      {
        IntVar nz(home,0,x.size());
        GECODE_ES_FAIL((Rel::Nq<IntView,IntView>::post(home,z,nz)));
        GECODE_ES_FAIL((Count::EqView<IntView,IntView,IntView,true,false>
                        ::post(home,xv,y,nz,0)));
      }
      break;
    case IRT_LE:
      GECODE_ES_FAIL((Count::LqView<IntView,IntView,IntView,true>
                      ::post(home,xv,y,z,-1)));
      break;
    case IRT_LQ:
      GECODE_ES_FAIL((Count::LqView<IntView,IntView,IntView,true>
                      ::post(home,xv,y,z,0)));
      break;
    case IRT_GR:
      if ((vbd(ipl) == IPL_DOM) || (vbd(ipl) == IPL_DEF))
        GECODE_ES_FAIL((Count::GqView<IntView,IntView,IntView,true,true>
                        ::post(home,xv,y,z,1)));
      else
        GECODE_ES_FAIL((Count::GqView<IntView,IntView,IntView,true,false>
                        ::post(home,xv,y,z,1)));
      break;
    case IRT_GQ:
      if ((vbd(ipl) == IPL_DOM) || (vbd(ipl) == IPL_DEF))
        GECODE_ES_FAIL((Count::GqView<IntView,IntView,IntView,true,true>
                        ::post(home,xv,y,z,0)));
      else
        GECODE_ES_FAIL((Count::GqView<IntView,IntView,IntView,true,false>
                        ::post(home,xv,y,z,0)));
      break;
    default:
      throw UnknownRelation("Int::count");
    }
  }

  void
  count(Home home, const IntVarArgs& x, const IntSet& y,
        IntRelType irt, IntVar z, IntPropLevel) {
    using namespace Int;

    if (y.size() == 1) {
      count(home,x,y.min(),irt,z);
      return;
    }

    Limits::check(y.min(),"Int::count");
    Limits::check(y.max(),"Int::count");

    GECODE_POST;
    ViewArray<IntView> xv(home,x);
    switch (irt) {
    case IRT_EQ:
      GECODE_ES_FAIL((Count::EqView<IntView,IntSet,IntView,true,false>
                      ::post(home,xv,y,z,0)));
      break;
    case IRT_NQ:
      {
        IntVar nz(home,0,x.size());
        GECODE_ES_FAIL((Rel::Nq<IntView,IntView>::post(home,z,nz)));
        GECODE_ES_FAIL((Count::EqView<IntView,IntSet,IntView,true,false>
                        ::post(home,xv,y,nz,0)));
      }
      break;
    case IRT_LE:
      GECODE_ES_FAIL((Count::LqView<IntView,IntSet,IntView,true>
                      ::post(home,xv,y,z,-1)));
      break;
    case IRT_LQ:
      GECODE_ES_FAIL((Count::LqView<IntView,IntSet,IntView,true>
                      ::post(home,xv,y,z,0)));
      break;
    case IRT_GR:
      GECODE_ES_FAIL((Count::GqView<IntView,IntSet,IntView,true,false>
                      ::post(home,xv,y,z,1)));
      break;
    case IRT_GQ:
      GECODE_ES_FAIL((Count::GqView<IntView,IntSet,IntView,true,false>
                      ::post(home,xv,y,z,0)));
      break;
    default:
      throw UnknownRelation("Int::count");
    }
  }

  void
  count(Home home, const IntVarArgs& x, const IntArgs& y,
        IntRelType irt, IntVar z, IntPropLevel) {
    using namespace Int;
    if (x.size() != y.size())
      throw ArgumentSizeMismatch("Int::count");
    GECO

    ViewArray<OffsetView> xy(home,x.size());
    for (int i=0; i<x.size(); i++)
      xy[i] = OffsetView(x[i],-y[i]);

    ZeroIntView u;
    switch (irt) {
    case IRT_EQ:
      GECODE_ES_FAIL((Count::EqView<OffsetView,ZeroIntView,IntView,true,false>
                      ::post(home,xy,u,z,0)));
      break;
    case IRT_NQ:
      {
        IntVar nz(home,0,x.size());
        GECODE_ES_FAIL((Rel::Nq<IntView,IntView>::post(home,z,nz)));
        GECODE_ES_FAIL((Count::EqView<OffsetView,ZeroIntView,IntView,true,false>
                        ::post(home,xy,u,nz,0)));
      }
      break;
    case IRT_LE:
      GECODE_ES_FAIL((Count::LqView<OffsetView,ZeroIntView,IntView,true>
                      ::post(home,xy,u,z,-1)));
      break;
    case IRT_LQ:
      GECODE_ES_FAIL((Count::LqView<OffsetView,ZeroIntView,IntView,true>
                      ::post(home,xy,u,z,0)));
      break;
    case IRT_GR:
      GECODE_ES_FAIL((Count::GqView<OffsetView,ZeroIntView,IntView,true,false>
                      ::post(home,xy,u,z,1)));
      break;
    case IRT_GQ:
      GECODE_ES_FAIL((Count::GqView<OffsetView,ZeroIntView,IntView,true,false>
                      ::post(home,xy,u,z,0)));
      break;
    default:
      throw UnknownRelation("Int::count");
    }
  }

}