///applyDamping damps the velocity, using the given m_linearDamping and m_angularDamping
void btRigidBody::applyDamping(btScalar timeStep)
{
	//On new damping: see discussion/issue report here: http://code.google.com/p/bullet/issues/detail?id=74
	//todo: do some performance comparisons (but other parts of the engine are probably bottleneck anyway

//#define USE_OLD_DAMPING_METHOD 1
#ifdef USE_OLD_DAMPING_METHOD
	m_linearVelocity *= GEN_clamped((btScalar(1.) - timeStep * m_linearDamping), (btScalar)btScalar(0.0), (btScalar)btScalar(1.0));
	m_angularVelocity *= GEN_clamped((btScalar(1.) - timeStep * m_angularDamping), (btScalar)btScalar(0.0), (btScalar)btScalar(1.0));
#else
	m_linearVelocity *= btPow(btScalar(1)-m_linearDamping, timeStep);
	m_angularVelocity *= btPow(btScalar(1)-m_angularDamping, timeStep);
#endif

	if (m_additionalDamping)
	{
		//Additional damping can help avoiding lowpass jitter motion, help stability for ragdolls etc.
		//Such damping is undesirable, so once the overall simulation quality of the rigid body dynamics system has improved, this should become obsolete
		if ((m_angularVelocity.length2() < m_additionalAngularDampingThresholdSqr) &&
			(m_linearVelocity.length2() < m_additionalLinearDampingThresholdSqr))
		{
			m_angularVelocity *= m_additionalDampingFactor;
			m_linearVelocity *= m_additionalDampingFactor;
		}


		btScalar speed = m_linearVelocity.length();
		if (speed < m_linearDamping)
		{
			btScalar dampVel = btScalar(0.005);
			if (speed > dampVel)
			{
				btVector3 dir = m_linearVelocity.normalized();
				m_linearVelocity -=  dir * dampVel;
			} else
			{
				m_linearVelocity.setValue(btScalar(0.),btScalar(0.),btScalar(0.));
			}
		}

		btScalar angSpeed = m_angularVelocity.length();
		if (angSpeed < m_angularDamping)
		{
			btScalar angDampVel = btScalar(0.005);
			if (angSpeed > angDampVel)
			{
				btVector3 dir = m_angularVelocity.normalized();
				m_angularVelocity -=  dir * angDampVel;
			} else
			{
				m_angularVelocity.setValue(btScalar(0.),btScalar(0.),btScalar(0.));
			}
		}
	}
    }
void btFluidSphSurfaceTensionForce::computeColorFieldGradient(const btFluidSphParametersGlobal& FG, btFluidSph* fluid, 
														const btAlignedObjectArray<btFluidSphNeighbors>& neighborTables, 
														const btAlignedObjectArray<btScalar>& invDensity)
{
	BT_PROFILE("btFluidSphSolverDefault::computeColorFieldGradient()");
	
	int numParticles = fluid->numParticles();
	const btFluidSphParametersLocal& FL = fluid->getLocalParameters();
	const btFluidSortingGrid& grid = fluid->getGrid();
	btFluidParticles& particles = fluid->internalGetParticles();
	
	for(int i = 0; i < numParticles; ++i) m_colorFieldGradient[i].setValue(0, 0, 0);
	
	for(int group = 0; group < btFluidSortingGrid::NUM_MULTITHREADING_GROUPS; ++group)
	{
		const btAlignedObjectArray<int>& multithreadingGroup = grid.internalGetMultithreadingGroup(group);
		if( !multithreadingGroup.size() ) continue;
		
		//If using multiple threads, this needs to be moved to a separate function
		{
			for(int cell = 0; cell < multithreadingGroup.size(); ++cell)
				computeColorFieldGradientInCellSymmetric(FG, multithreadingGroup[cell], grid, particles, 
														neighborTables, invDensity, m_colorFieldGradient);
		}
	}
	
	
#ifdef USE_SPIKY_KERNEL_GRADIENT
	for(int i = 0; i < numParticles; ++i) m_colorFieldGradient[i] *= FG.m_sphSmoothRadius * FL.m_sphParticleMass * FG.m_spikyKernGradCoeff;
#else
	const btScalar poly6KernGradCoeff = btScalar(-945.0) / ( btScalar(32.0) * SIMD_PI * btPow(FG.m_sphSmoothRadius, 9) );
	for(int i = 0; i < numParticles; ++i) m_colorFieldGradient[i] *= FG.m_sphSmoothRadius * FL.m_sphParticleMass * poly6KernGradCoeff;
#endif
}
//need to make a proper evaluation function
//get the best CPG function, delete the rest of CPGs and clear the m_birdCPGs array
void BirdOptimizer::evaluateCurrentGenerationBirds() {

    m_perturb_scaler = btExp(-btPow(((m_numGeneration - 1) * 2.8f/50.f + 1.5f), 1.2f));

    if (m_numGeneration == 0)
        return;

    //choose the best CPG
    float minEnergy = FLT_MAX;
    int minIndex = -1;
    for (int ii = 0; ii < m_birdTrajectoryData.size(); ++ii) {
        float energy =
            calculateTimeToHitGround(m_birdTrajectoryData[ii])
            + calculateTotalUpTime(m_birdTrajectoryData[ii])
            + calculateEnergy(m_birdTrajectoryData[ii])/1500.0;
        std::cout << "\tenergy: " << energy << std::endl;
        if (energy < minEnergy)
        {
            minEnergy = energy;
            minIndex = ii;
        }
    }
    std::cout << "---GENERATION: " << m_numGeneration << " :: "
              << "min_energy: " << minEnergy
              << ", index: " << minIndex
              << ", scaler: " << m_perturb_scaler
              << std::endl;
    m_currentBestInfo = m_birdInfos[minIndex];

    // Save bird configuration.

    proto::BirdOptimizerResult* result = m_result_data.add_result();
    result->set_cum_energy(minEnergy);
    result->mutable_bird()->CopyFrom(*m_birdInfos[minIndex]);


    {
        std::ofstream ofs("C:\\Users\\k\\bird_data.pbdata", std::ios::out | std::ios::trunc | std::ios::binary);
        ofs << m_result_data.SerializeAsString();
    }
    {
        std::ofstream ofs("C:\\Users\\k\\bird_data.txt", std::ios::out | std::ios::trunc);
        ofs << m_result_data.DebugString();
    }



    for (int ii = 0; ii < m_birdTrajectoryData.size(); ++ii) {
        delete m_birdTrajectoryData[ii];
    }
    m_birdTrajectoryData.clear();

    for (int ii = 0; ii < m_birdInfos.size(); ii++) {
        if (m_birdInfos[ii] == m_currentBestInfo) continue;
        delete m_birdInfos[ii];
    }
    m_birdInfos.clear();

}
unsigned int btPolarDecomposition::decompose(const btMatrix3x3& a, btMatrix3x3& u, btMatrix3x3& h) const
{
  // Use the 'u' and 'h' matrices for intermediate calculations
  u = a;
  h = a.inverse();

  for (unsigned int i = 0; i < m_maxIterations; ++i)
  {
    const btScalar h_1 = p1_norm(h);
    const btScalar h_inf = pinf_norm(h);
    const btScalar u_1 = p1_norm(u);
    const btScalar u_inf = pinf_norm(u);

    const btScalar h_norm = h_1 * h_inf;
    const btScalar u_norm = u_1 * u_inf;

    // The matrix is effectively singular so we cannot invert it
    if (btFuzzyZero(h_norm) || btFuzzyZero(u_norm))
      break;

    const btScalar gamma = btPow(h_norm / u_norm, 0.25f);
    const btScalar inv_gamma = 1.0 / gamma;

    // Determine the delta to 'u'
    const btMatrix3x3 delta = (u * (gamma - 2.0) + h.transpose() * inv_gamma) * 0.5;

    // Update the matrices
    u += delta;
    h = u.inverse();

    // Check for convergence
    if (p1_norm(delta) <= m_tolerance * u_1)
    {
      h = u.transpose() * a;
      h = (h + h.transpose()) * 0.5;
      return i;
    }
  }

  // The algorithm has failed to converge to the specified tolerance, but we
  // want to make sure that the matrices returned are in the right form.
  h = u.transpose() * a;
  h = (h + h.transpose()) * 0.5;

  return m_maxIterations;
}
void btFluidHfBuoyantConvexShape::generateShape(btScalar collisionRadius, btScalar volumeEstimationRadius)
{
	m_voxelPositions.resize(0);
	
	btVoronoiSimplexSolver simplexSolver;
	btTransform voxelTransform = btTransform::getIdentity();
	
	btVector3 aabbMin, aabbMax;
	getAabb( btTransform::getIdentity(), aabbMin, aabbMax );	//AABB of the convex shape
	
	//Generate voxels for collision
	{
		btSphereShape collisionShape(collisionRadius);
	
		const btScalar collisionDiameter = btScalar(2.0) * collisionRadius;
		btVector3 numVoxels = (aabbMax - aabbMin) / collisionDiameter;
		for(int i = 0; i < ceil( numVoxels.x() ); i++)
		{
			for(int j = 0; j < ceil( numVoxels.y() ); j++)
			{
				for(int k = 0; k < ceil( numVoxels.z() ); k++)
				{
					btVector3 voxelPosition = aabbMin + btVector3(i * collisionDiameter, j * collisionDiameter, k * collisionDiameter);
					voxelTransform.setOrigin(voxelPosition);

					if( intersect(&simplexSolver, btTransform::getIdentity(), voxelTransform, m_convexShape, &collisionShape) ) 
						m_voxelPositions.push_back(voxelPosition);
				}
			}
		}
		
		const bool CENTER_VOXELS_AABB_ON_ORIGIN = true;
		if(CENTER_VOXELS_AABB_ON_ORIGIN)
		{
			btVector3 diameter(collisionDiameter, collisionDiameter, collisionDiameter);
		
			btVector3 voxelAabbMin(BT_LARGE_FLOAT, BT_LARGE_FLOAT, BT_LARGE_FLOAT); 
			btVector3 voxelAabbMax(-BT_LARGE_FLOAT, -BT_LARGE_FLOAT, -BT_LARGE_FLOAT);
			for(int i = 0; i < m_voxelPositions.size(); ++i)
			{
				voxelAabbMin.setMin(m_voxelPositions[i] - diameter);
				voxelAabbMax.setMax(m_voxelPositions[i] + diameter);
			}
		
			btVector3 offset = (voxelAabbMax - voxelAabbMin)*btScalar(0.5) - voxelAabbMax;
		
			for(int i = 0; i < m_voxelPositions.size(); ++i) m_voxelPositions[i] += offset;
		}
	}
	
	//Estimate volume with smaller spheres
	btScalar estimatedVolume;
	{
		btSphereShape volumeEstimationShape(volumeEstimationRadius);	
		
		int numCollidingVoxels = 0;
		const btScalar estimationDiameter = btScalar(2.0) * volumeEstimationRadius;
		btVector3 numEstimationVoxels = (aabbMax - aabbMin) / estimationDiameter;
		
		for(int i = 0; i < ceil( numEstimationVoxels.x() ); i++)
		{
			for(int j = 0; j < ceil( numEstimationVoxels.y() ); j++)
			{
				for(int k = 0; k < ceil( numEstimationVoxels.z() ); k++)
				{
					btVector3 voxelPosition = aabbMin + btVector3(i * estimationDiameter, j * estimationDiameter, k * estimationDiameter);
					voxelTransform.setOrigin(voxelPosition);

					if( intersect(&simplexSolver, btTransform::getIdentity(), voxelTransform, m_convexShape, &volumeEstimationShape) ) 
						++numCollidingVoxels;
				}
			}
		}
		

		
		//Although the voxels are spherical, it is better to use the volume of a cube
		//for volume estimation. Since convex shapes are completely solid and the voxels
		//are generated by moving along a cubic lattice, using the volume of a sphere
		//would result in gaps. Comparing the volume of a cube with edge length 2(8 m^3) 
		//and the volume of a sphere with diameter 2(~4 m^3), the estimated volume would
		//be off by about 1/2.
		btScalar volumePerEstimationVoxel = btPow( estimationDiameter, btScalar(3.0) );
		//btScalar volumePerEstimationVoxel =  btScalar(4.0/3.0) * SIMD_PI * btPow( volumeEstimationRadius, btScalar(3.0) );
		
		estimatedVolume = static_cast<btScalar>(numCollidingVoxels) * volumePerEstimationVoxel;
	}
	
	m_volumePerVoxel = estimatedVolume / static_cast<btScalar>( getNumVoxels() );
	m_totalVolume = estimatedVolume;
	
	m_collisionRadius = collisionRadius;
}
   void CDynamics3DMagnetismPlugin::Update() {
      if(m_vecDipoles.size() < 2) {
         /* Nothing to do */
         return;
      }
      for(std::vector<SMagneticDipole>::iterator itDipole0 = std::begin(m_vecDipoles);
          itDipole0 != (std::end(m_vecDipoles) - 1);
          ++itDipole0) {
         for(std::vector<SMagneticDipole>::iterator itDipole1 = std::next(itDipole0, 1);
             itDipole1 != std::end(m_vecDipoles);
             ++itDipole1) {
            const btTransform& cTransformDipole0 = itDipole0->Offset * itDipole0->Body->GetTransform();
            const btTransform& cTransformDipole1 = itDipole1->Offset * itDipole1->Body->GetTransform();
            const btVector3& cPositionDipole0 = cTransformDipole0.getOrigin();
            const btVector3& cPositionDipole1 = cTransformDipole1.getOrigin();
            /* calculate the distance between the two magnetic bodies */
            btScalar fDistance = cPositionDipole0.distance(cPositionDipole1);
            /* optimization - don't calculate magnetism for dipoles more than m_fMaxDistance apart */
            if(fDistance > m_fMaxDistance) {
               continue;
            }
            /* perform Barnes-hut algorithm */
            /* calculate the normalized seperation between the two dipoles, pointing from Dipole1 to Dipole0*/
            const btVector3& cNormalizedSeparation =
               btVector3(cPositionDipole0 - cPositionDipole1) / fDistance;
            /* calculate the rotated field of dipole 0 */
            const btVector3& cRotatedFieldDipole0 =
               itDipole0->Body->GetTransform().getBasis() * itDipole0->GetField();
            /* calculate the rotated field of dipole 1 */
            const btVector3& cRotatedFieldDipole1 =
               itDipole1->Body->GetTransform().getBasis() * itDipole1->GetField();
            /* We now have cRotatedFieldDipole0 and cRotatedFieldDipole1 as the magnetic moments
               (i.e., m0, m1), cNormalizedSeparation as the direction unit vector from Dipole 1
               to Dipole 0 (i.e., n), fDistance is the scalar distance between the dipoles (i.e.,
               d), and B0 is the magnetic flux density at Dipole 0.
                  B0 = u0/4pi * [3n(n.m1) - m1] / d^3
                  T0 = m0 * B0
                     = u0.4pi/d^3 * [3 (m1.n)(m0 * n) - m0 * m1]

                  F0 = grad(m0.B0)
                     = u0.4pi/d^4 * [-15n(m0.n)(m1.n) + 3n(m0.m1) + 3(m0(m1.n)+m1(m0.n))]
            */
            /* calculate the intermediate cross and dot products */
            const btVector3& cCrossProduct01 = cRotatedFieldDipole0.cross(cRotatedFieldDipole1);
            const btVector3& cCrossProduct0 = cRotatedFieldDipole0.cross(cNormalizedSeparation);
            const btVector3& cCrossProduct1 = cRotatedFieldDipole1.cross(cNormalizedSeparation);
            btScalar fDotProduct01 = cRotatedFieldDipole0.dot(cRotatedFieldDipole1);
            btScalar fDotProduct0 = cRotatedFieldDipole0.dot(cNormalizedSeparation);
            btScalar fDotProduct1 = cRotatedFieldDipole1.dot(cNormalizedSeparation);
            /* calculate the magnetic force and torque */
            const btVector3& cTorque0 =
               ((3 * fDotProduct1 * cCrossProduct0) - cCrossProduct01) *
               m_fForceConstant / btPow(fDistance, 3);
            const btVector3& cTorque1 =
               ((3 * fDotProduct0 * cCrossProduct1) + cCrossProduct01) *
               m_fForceConstant / btPow(fDistance, 3);
            const btVector3& cForce = (m_fForceConstant / btPow(fDistance, 4)) *
               ((-15 * cNormalizedSeparation * fDotProduct1 * fDotProduct0) +
                (3 * cNormalizedSeparation * fDotProduct01) +
                (3 * (fDotProduct1 * cRotatedFieldDipole0 + fDotProduct0 * cRotatedFieldDipole1)));
            /* apply torques and forces to the bodies */
            itDipole0->Body->ApplyForce(cForce, (itDipole0->Offset).getOrigin());
            itDipole0->Body->ApplyTorque(cTorque0);
            itDipole1->Body->ApplyForce(-cForce, (itDipole1->Offset).getOrigin());
            itDipole1->Body->ApplyTorque(cTorque1);
         }
      }
   }