1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | //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); } |
Ly9SZXR1cm5zIHRoZSBoaWxsIG9mIGEgc3BlY2lmaWMgYm91bmNlLCB3b3JraW5nIGJhY2t3YXJkcyBhbmQgZXhjbHVkaW5nIHRoZSBmaW5hbCBoYWxmLWJvdW5jZS4KLy8wID0gdGhlIGxhc3QgYm91bmNlLCBleGNsdWRpbmcgdGhlIGZpbmFsIGhhbGYtYm91bmNlLgovLzEgPSB0aGUgc2Vjb25kLXRvLWxhc3QgYm91bmNlLgpmbG9hdCBwcml2X0JvdW5jZV9HZXRCb3VuY2VXaWR0aCh1bnNpZ25lZCBib3VuY2UpCnsKICAgIC8vRWFjaCBib3VuY2UgaXMgaGFsZiB0aGUgd2lkdGggb2YgdGhlIHByZXZpb3VzIGJvdW5jZS4KICAgIC8vVGhlIGZpcnN0IGJvdW5jZSAoZXhjbHVkaW5nIHRoZSBoYWxmLWJvdW5jZSkgaXMgMS4wZiwKICAgIC8vVGhlIHNlY29uZCBib3VuY2UgaXMgMC41ZiwgdGhlIHRoaXJkIGlzIDAuMjVmLCBhbmQgc28gb24uCiAgICByZXR1cm4gc3RkOjpwb3coMC41ZiwgZmxvYXQoYm91bmNlKSk7Cn0KCi8vUmV0dXJucyB0aGUgaGVpZ2h0IG9mIGEgc3BlY2lmaWMgYm91bmNlLCB3b3JraW5nIGJhY2t3YXJkcyBhbmQgZXhjbHVkaW5nIHRoZSBmaW5hbCBoYWxmLWJvdW5jZS4KLy8wID0gdGhlIGxhc3QgYm91bmNlLCBleGNsdWRpbmcgdGhlIGZpbmFsIGhhbGYtYm91bmNlLgovLzEgPSB0aGUgc2Vjb25kLXRvLWxhc3QgYm91bmNlLgovLwovLydib3VuY2luZXNzJyBpcyBhIHZhbHVlIGZyb20gMC4wIHRvIDEuMCwgZGVzY3JpYmluZyBob3cgKGZyb20gdGhlIGhhbGYtYm91bmNlIG9uIGRvd24pCi8vc21hbGwgdGhlIHNpemUgb2YgZWFjaCBib3VuY2UgYmVjb21lcywgcmVsYXRpdmUgdG8gdGhlIHByZXZpb3VzLgpmbG9hdCBwcml2X0JvdW5jZV9HZXRCb3VuY2VIZWlnaHQodW5zaWduZWQgYm91bmNlLCBmbG9hdCBib3VuY2luZXNzKQp7CiAgICByZXR1cm4gc3RkOjpwb3coYm91bmNpbmVzcywgZmxvYXQoYm91bmNlKzEpKTsKfQoKZmxvYXQgcHJpdl9Cb3VuY2VfR2V0Qm91bmNlUG9zaXRpb24odW5zaWduZWQgYm91bmNlKQp7CiAgICBmbG9hdCBwb3NpdGlvbiA9IDEuMGY7IC8vVGhlIGZpbmFsIGhhbGYtYm91bmNlLgogICAgZm9yKHVuc2lnbmVkIGkgPSAwOyBpIDwgYm91bmNlOyBpKyspCiAgICB7CiAgICAgICAgLy9BZGQgdXAgdGhlIHdpZHRoIG9mIGFsbCB0aGUgYm91bmNlcyBiZWZvcmUgdGhpcyBvbmUuCiAgICAgICAgcG9zaXRpb24gKz0gcHJpdl9Cb3VuY2VfR2V0Qm91bmNlV2lkdGgoaSk7CiAgICB9CgogICAgcmV0dXJuIHBvc2l0aW9uOwp9CgpmbG9hdCBwcml2X0JvdW5jZV9HZXRCb3VuY2VIYWxmd2F5UG9pbnQodW5zaWduZWQgYm91bmNlKQp7CiAgICByZXR1cm4gKHByaXZfQm91bmNlX0dldEJvdW5jZVBvc2l0aW9uKGJvdW5jZSkgKyAocHJpdl9Cb3VuY2VfR2V0Qm91bmNlV2lkdGgoYm91bmNlKSAqIDAuNWYpKTsKfQoKLy9HZXRzIHRoZSBhbW91bnQgd2UgbmVlZCB0byBvZmZzZXQgdGhlIGJvdW5jZXMgYnksIHRvIG1ha2UgdGhlbSBiZSBhdCB0aGUgJ2JvdHRvbScgb2YgdGhlIGVhc2UuCmZsb2F0IHByaXZfQm91bmNlX0dldFZlcnRpY2FsQm91bmNlT2Zmc2V0KHVuc2lnbmVkIGJvdW5jZSwgZmxvYXQgYm91bmNpbmVzcykKewogICAgY29uc3QgZmxvYXQgaW52ZXJzZUJvdW5jaW5lc3MgPSAoMS4wZiAtIGJvdW5jaW5lc3MpOwogICAgZmxvYXQgb2Zmc2V0ID0gMC4wZjsKICAgIAogICAgZm9yKHVuc2lnbmVkIGkgPSAwOyBpIDw9IGJvdW5jZTsgaSsrKQogICAgewogICAgICAgIC8vRm9yIGVhY2ggYm91bmNlLCBhZGQgMC43NWYgKG9yIHdoYXRldmVyICgxLjBmIC0gYm91bmNpbmVzcykgaXMpIG9mIHRoZSByZW1haW5pbmcgaGVpZ2h0LiAoU2luY2UgRWFjaCBib3VuY2UgaXMgMC4yNWYgb2YgdGhlIHByZXZpb3VzKS4KICAgICAgICBvZmZzZXQgKz0gKGludmVyc2VCb3VuY2luZXNzICogKDEuMGYgLSBvZmZzZXQpKTsKICAgIH0KCiAgICByZXR1cm4gb2Zmc2V0Owp9CgovL1JldHVybnMgdGhlIHRvdGFsIHdpZHRoIG9mIGFsbCB0aGUgYm91bmNlcywgcGx1cyB0aGUgZmluYWwgaGFsZi1ib3VuY2UuCmZsb2F0IHByaXZfQm91bmNlX1RvdGFsV2lkdGgodW5zaWduZWQgYm91bmNlcykKewogICAgZmxvYXQgdG90YWxXaWR0aCA9IDEuMGY7IC8vVGhlIGZpbmFsIGhhbGYtYm91bmNlLgogICAgZm9yKHVuc2lnbmVkIGJvdW5jZSA9IDA7IGJvdW5jZSA8IGJvdW5jZXM7IGJvdW5jZSsrKQogICAgewogICAgICAgIC8vVGhlIEZpcnN0IGJvdW5jZSBhZGRlZCwgYWRkcyAnMS4wZicuIFNlY29uZCBib3VuY2UgYWRkcyAnMC41ZicsIHRoZSBuZXh0IGFkZHMgJzAuMjVmJywgYW5kIHNvIG9uLgogICAgICAgIHRvdGFsV2lkdGggKz0gcHJpdl9Cb3VuY2VfR2V0Qm91bmNlV2lkdGgoYm91bmNlKTsKICAgIH0KCiAgICByZXR1cm4gdG90YWxXaWR0aDsKfQoKZmxvYXQgQ3VzdG9tQm91bmNlRWFzZShmbG9hdCBwb3NpdGlvbiwgaW50IGJvdW5jZXMsIGZsb2F0IGJvdW5jaW5lc3MpCnsKICAgIC8vT3B0aW1pemF0aW9uIGZvciBlbmQgcG9pbnRzLCB3aGljaCBhcmUgdGhlIG1vc3QgY29tbW9uIHNwb3RzLgogICAgaWYocG9zaXRpb24gPT0gMC4wZiB8fCBwb3NpdGlvbiA9PSAxLjBmKQogICAgewogICAgICAgIHJldHVybiBwb3NpdGlvbjsKICAgIH0KICAgIAogICAgLy9JIGRvbid0IGtub3cgdGhlIHB1cnBvc2UgdGhpcyBjb25zdGFudCBzZXJ2ZXMgaW4gdGhlIG9yaWdpbmFsIGVhc2UgZXF1YXRpb24uCiAgICBjb25zdCBmbG9hdCBVbmtub3duVmFyID0gNy41NjI1ZjsKICAgIAogICAgLy9DYWxjdWxhdGUgdGhlIHRvdGFsIHdpZHRoIG5lZWRlZCBmb3IgYWxsIHRoZSBib3VuY2VzLgogICAgY29uc3QgZmxvYXQgVG90YWxXaWR0aCA9IHByaXZfQm91bmNlX1RvdGFsV2lkdGgoYm91bmNlcyk7CiAgICAKICAgIGZvcih1bnNpZ25lZCBpbnQgYm91bmNlID0gYm91bmNlczsgYm91bmNlLS0gPiAwOyApCiAgICB7CiAgICAgICAgZmxvYXQgYm91bmNlUG9zID0gcHJpdl9Cb3VuY2VfR2V0Qm91bmNlUG9zaXRpb24oYm91bmNlKTsKICAgICAgICAKICAgICAgICBpZihwb3NpdGlvbiA+IChib3VuY2VQb3MgLyBUb3RhbFdpZHRoKSkKICAgICAgICB7CiAgICAgICAgICAgIHBvc2l0aW9uIC09IChwcml2X0JvdW5jZV9HZXRCb3VuY2VIYWxmd2F5UG9pbnQoYm91bmNlKSAvIFRvdGFsV2lkdGgpOwogICAgICAgICAgICBmbG9hdCB2ZXJ0aWNhbE9mZnNldCA9IHByaXZfQm91bmNlX0dldFZlcnRpY2FsQm91bmNlT2Zmc2V0KGJvdW5jZSwgYm91bmNpbmVzcyk7CiAgICAgICAgICAgIAogICAgICAgICAgICByZXR1cm4gKChVbmtub3duVmFyICogcG9zaXRpb24gKiBwb3NpdGlvbikgKyB2ZXJ0aWNhbE9mZnNldCk7CiAgICAgICAgfQogICAgfQogICAgCiAgICAvL1RoZSBmaW5hbCBoYWxmLWJvdW5jZToKICAgIHJldHVybiAoVW5rbm93blZhciAqIHBvc2l0aW9uICogcG9zaXRpb24pOwp9


