//Returns the hill of a specific bounce, working backwards and excluding the final half-bounce.
//0 = the last bounce, excluding the final half-bounce.
//1 = the second-to-last bounce.
float priv_Bounce_GetBounceWidth(unsigned bounce)
{
//Each bounce is half the width of the previous bounce.
//The first bounce (excluding the half-bounce) is 1.0f,
//The second bounce is 0.5f, the third is 0.25f, and so on.
return std::pow(0.5f, float(bounce));
}
//Returns the height of a specific bounce, working backwards and excluding the final half-bounce.
//0 = the last bounce, excluding the final half-bounce.
//1 = the second-to-last bounce.
//
//'bounciness' is a value from 0.0 to 1.0, describing how (from the half-bounce on down)
//small the size of each bounce becomes, relative to the previous.
float priv_Bounce_GetBounceHeight(unsigned bounce, float bounciness)
{
return std::pow(bounciness, float(bounce+1));
}
float priv_Bounce_GetBouncePosition(unsigned bounce)
{
float position = 1.0f; //The final half-bounce.
for(unsigned i = 0; i < bounce; i++)
{
//Add up the width of all the bounces before this one.
position += priv_Bounce_GetBounceWidth(i);
}
return position;
}
float priv_Bounce_GetBounceHalfwayPoint(unsigned bounce)
{
return (priv_Bounce_GetBouncePosition(bounce) + (priv_Bounce_GetBounceWidth(bounce) * 0.5f));
}
//Gets the amount we need to offset the bounces by, to make them be at the 'bottom' of the ease.
float priv_Bounce_GetVerticalBounceOffset(unsigned bounce, float bounciness)
{
const float inverseBounciness = (1.0f - bounciness);
float offset = 0.0f;
for(unsigned i = 0; i <= bounce; i++)
{
//For each bounce, add 0.75f (or whatever (1.0f - bounciness) is) of the remaining height. (Since Each bounce is 0.25f of the previous).
offset += (inverseBounciness * (1.0f - offset));
}
return offset;
}
//Returns the total width of all the bounces, plus the final half-bounce.
float priv_Bounce_TotalWidth(unsigned bounces)
{
float totalWidth = 1.0f; //The final half-bounce.
for(unsigned bounce = 0; bounce < bounces; bounce++)
{
//The First bounce added, adds '1.0f'. Second bounce adds '0.5f', the next adds '0.25f', and so on.
totalWidth += priv_Bounce_GetBounceWidth(bounce);
}
return totalWidth;
}
float CustomBounceEase(float position, int bounces, float bounciness)
{
//Optimization for end points, which are the most common spots.
if(position == 0.0f || position == 1.0f)
{
return position;
}
//I don't know the purpose this constant serves in the original ease equation.
const float UnknownVar = 7.5625f;
//Calculate the total width needed for all the bounces.
const float TotalWidth = priv_Bounce_TotalWidth(bounces);
for(unsigned int bounce = bounces; bounce-- > 0; )
{
float bouncePos = priv_Bounce_GetBouncePosition(bounce);
if(position > (bouncePos / TotalWidth))
{
position -= (priv_Bounce_GetBounceHalfwayPoint(bounce) / TotalWidth);
float verticalOffset = priv_Bounce_GetVerticalBounceOffset(bounce, bounciness);
return ((UnknownVar * position * position) + verticalOffset);
}
}
//The final half-bounce:
return (UnknownVar * position * position);
}