| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711 |
- // Purposely not including Base.h here, or any other gameplay dependencies
- // so this class can be reused between gameplay and gameplay-encoder.
- #include "Curve.h"
- #include <assert.h>
- #include <math.h>
- #include <memory.h>
- #ifndef NULL
- #define NULL 0
- #endif
- namespace gameplay
- {
- Curve::Curve(unsigned int pointCount, unsigned int componentCount)
- : _pointCount(pointCount), _componentCount(componentCount), _componentSize(0), _quaternionOffsets(NULL), _quaternionOffsetsCount(0), _points(NULL)
- {
- assert(pointCount > 1 && componentCount > 0);
- _componentSize = sizeof(float)*componentCount;
- _points = new Point[_pointCount];
- for (unsigned int i = 0; i < _pointCount; i++)
- {
- _points[i].time = 0.0f;
- _points[i].value = new float[_componentCount];
- _points[i].inValue = new float[_componentCount];
- _points[i].outValue = new float[_componentCount];
- _points[i].type = LINEAR;
- }
- _points[_pointCount - 1].time = 1.0f;
- }
- Curve::~Curve()
- {
- delete[] _points;
- delete[] _quaternionOffsets;
- }
- Curve::Point::Point()
- : time(0.0f), value(NULL), inValue(NULL), outValue(NULL)
- {
- }
- Curve::Point::~Point()
- {
- delete[] value;
- delete[] inValue;
- delete[] outValue;
- }
- unsigned int Curve::getPointCount() const
- {
- return _pointCount;
- }
- unsigned int Curve::getComponentCount() const
- {
- return _componentCount;
- }
- float Curve::getStartTime() const
- {
- return _points[0].time;
- }
- float Curve::getEndTime() const
- {
- return _points[_pointCount-1].time;
- }
- void Curve::setPoint(unsigned int index, float time, float* value, InterpolationType type)
- {
- setPoint(index, time, value, type, NULL, NULL);
- }
- void Curve::setPoint(unsigned int index, float time, float* value, InterpolationType type, float* inValue, float* outValue)
- {
- assert(index < _pointCount && time >= 0.0f && time <= 1.0f && !(index == 0 && time != 0.0f) && !(index == _pointCount - 1 && time != 1.0f));
- _points[index].time = time;
- _points[index].type = type;
- if (value)
- memcpy(_points[index].value, value, _componentSize);
- if (inValue)
- memcpy(_points[index].inValue, inValue, _componentSize);
- if (outValue)
- memcpy(_points[index].outValue, outValue, _componentSize);
- }
- void Curve::setTangent(unsigned int index, InterpolationType type, float* inValue, float* outValue)
- {
- assert(index < _pointCount);
- _points[index].type = type;
- if (inValue)
- memcpy(_points[index].inValue, inValue, _componentSize);
- if (outValue)
- memcpy(_points[index].outValue, outValue, _componentSize);
- }
- void Curve::evaluate(float time, float* dst) const
- {
- assert(dst && time >= 0 && time <= 1.0f);
- // Check if we are at or beyond the bounds of the curve.
- if (time <= _points[0].time)
- {
- memcpy(dst, _points[0].value, _componentSize);
- return;
- }
- else if (time >= _points[_pointCount - 1].time)
- {
- memcpy(dst, _points[_pointCount - 1].value, _componentSize);
- return;
- }
- // Locate the points we are interpolating between using a binary search.
- unsigned int index = determineIndex(time);
-
- Point* from = _points + index;
- Point* to = _points + (index + 1);
- // Calculate the fractional time between the two points.
- float scale = (to->time - from->time);
- float t = (time - from->time) / scale;
- // Calculate the value of the curve discretely if appropriate.
- switch (from->type)
- {
- case BEZIER:
- {
- interpolateBezier(t, from, to, dst);
- break;
- }
- case BSPLINE:
- {
- Point* c0;
- Point* c1;
- if (index == 0)
- {
- c0 = from;
- }
- else
- {
- c0 = (_points + index - 1);
- }
-
- if (index == _pointCount - 2)
- {
- c1 = to;
- }
- else
- {
- c1 = (_points + index + 2);
- }
- interpolateBSpline(t, c0, from, to, c1, dst);
- break;
- }
- case FLAT:
- {
- interpolateHermiteFlat(t, from, to, dst);
- break;
- }
- case HERMITE:
- {
- interpolateHermite(t, from, to, dst);
- break;
- }
- case LINEAR:
- {
- interpolateLinear(t, from, to, dst);
- break;
- }
- case SMOOTH:
- {
- interpolateHermiteSmooth(t, index, from, to, dst);
- break;
- }
- case STEP:
- {
- memcpy(dst, from->value, _componentSize);
- break;
- }
- }
- }
- void Curve::addQuaternionOffset(unsigned int offset)
- {
- if (!_quaternionOffsets)
- {
- _quaternionOffsetsCount = 1;
- _quaternionOffsets = new unsigned int[_quaternionOffsetsCount];
- _quaternionOffsets[0] = offset;
- }
- else
- {
- assert((offset >= _componentCount - 4) && (offset > (_quaternionOffsets[_quaternionOffsetsCount - 1] + 3)));
- unsigned int oldSize = _quaternionOffsetsCount;
- _quaternionOffsetsCount++;
-
- unsigned int* newArray = new unsigned int[_quaternionOffsetsCount];
- memcpy(newArray, _quaternionOffsets, sizeof(unsigned int) * oldSize);
-
- // set new offset.
- newArray[oldSize] = offset;
- delete[] _quaternionOffsets; // delete old array
- _quaternionOffsets = newArray; // point to new array.
- }
- }
- void Curve::interpolateBezier(float s, Point* from, Point* to, float* dst) const
- {
- float s_2 = s * s;
- float eq0 = 1 - s;
- float eq0_2 = eq0 * eq0;
- float eq1 = eq0_2 * eq0;
- float eq2 = 3 * s * eq0_2;
- float eq3 = 3 * s_2 * eq0;
- float eq4 = s_2 * s;
- if (!_quaternionOffsets)
- {
- for (unsigned int i = 0; i < _componentCount; i++)
- {
- dst[i] = from->value[i] * eq1 + from->outValue[i] * eq2 + to->inValue[i] * eq3 + to->value[i] * eq4;
- }
- }
- else
- {
- // Interpolate values as scalars up to first quaternion offset.
- unsigned int quaternionOffsetIndex = 0;
- unsigned int quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
- unsigned int i = 0;
-
- do {
- while (i < quaternionOffset)
- {
- dst[i] = from->value[i] * eq1 + from->outValue[i] * eq2 + to->inValue[i] * eq3 + to->value[i] * eq4;
- i++;
- }
- // Handle quaternion component.
- interpolateQuaternion(s, (from->value + i), (to->value + i), (dst + i));
- i += 4;
- quaternionOffsetIndex++;
- quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
- } while (quaternionOffsetIndex < _quaternionOffsetsCount);
- while (i < _componentCount)
- {
- dst[i] = from->value[i] * eq1 + from->outValue[i] * eq2 + to->inValue[i] * eq3 + to->value[i] * eq4;
- i++;
- }
- }
- }
- void Curve::interpolateBSpline(float s, Point* c0, Point* c1, Point* c2, Point* c3, float* dst) const
- {
- float s_2 = s * s;
- float s_3 = s_2 * s;
- float eq0 = (-s_3 + 3 * s_2 - 3 * s + 1) / 6.0f;
- float eq1 = (3 * s_3 - 6 * s_2 + 4) / 6.0f;
- float eq2 = (-3 * s_3 + 3 * s_2 + 3 * s + 1) / 6.0f;
- float eq3 = s_3 / 6.0f;
- if (!_quaternionOffsets)
- {
- for (unsigned int i = 0; i < _componentCount; i++)
- {
- dst[i] = c0->value[i] * eq0 + c1->value[i] * eq1 + c2->value[i] * eq2 + c3->value[i] * eq3;
- }
- }
- else
- {
- // Interpolate values as scalars up to first quaternion offset.
- unsigned int quaternionOffsetIndex = 0;
- unsigned int quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
- unsigned int i = 0;
- do {
- while (i < quaternionOffset)
- {
- dst[i] = c0->value[i] * eq0 + c1->value[i] * eq1 + c2->value[i] * eq2 + c3->value[i] * eq3;
- i++;
- }
- // Handle quaternion component.
- float interpTime;
- if (c0->time == c1->time)
- interpTime = -c0->time * eq0 + c1->time * eq1 + c2->time * eq2 + c3->time * eq3;
- else if (c2->time == c3->time)
- interpTime = c0->time * eq0 + c1->time * eq1 + c2->time * eq2 - c3->time * eq3;
- else
- interpTime = c0->time * eq0 + c1->time * eq1 + c2->time * eq2 + c3->time * eq3;
-
- interpolateQuaternion(s, (c1->value + quaternionOffset) , (c2->value + quaternionOffset), (dst + quaternionOffset));
- i += 4;
- quaternionOffsetIndex++;
- quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
- } while (quaternionOffsetIndex < _quaternionOffsetsCount);
-
- // Handle remaining scalar values.
- while (i < _componentCount)
- {
- dst[i] = c0->value[i] * eq0 + c1->value[i] * eq1 + c2->value[i] * eq2 + c3->value[i] * eq3;
- i++;
- }
- }
- }
- void Curve::interpolateHermite(float s, Point* from, Point* to, float* dst) const
- {
- // Calculate the hermite basis functions.
- float s_2 = s * s; // t^2
- float s_3 = s_2 * s; // t^3
- float h00 = 2 * s_3 - 3 * s_2 + 1; // basis function 0
- float h01 = -2 * s_3 + 3 * s_2; // basis function 1
- float h10 = s_3 - 2 * s_2 + s; // basis function 2
- float h11 = s_3 - s_2; // basis function 3
- if (!_quaternionOffsets)
- {
- for (unsigned int i = 0; i < _componentCount; i++)
- {
- dst[i] = h00 * from->value[i] + h01 * to->value[i] + h10 * from->outValue[i] + h11 * to->inValue[i];
- }
- }
- else
- {
- // Interpolate values as scalars up to first quaternion offset.
- unsigned int quaternionOffsetIndex = 0;
- unsigned int quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
- unsigned int i = 0;
- do {
- while (i < quaternionOffset)
- {
- dst[i] = h00 * from->value[i] + h01 * to->value[i] + h10 * from->outValue[i] + h11 * to->inValue[i];
- i++;
- }
- // Handle quaternion component.
- float interpTime = h01 * 1.0f + h10 * from->outValue[quaternionOffset] + h11 * to->inValue[quaternionOffset];
- interpolateQuaternion(interpTime, (from->value + quaternionOffset), (to->value + quaternionOffset), (dst + quaternionOffset));
- i += 4;
- quaternionOffsetIndex++;
- quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
-
- } while (quaternionOffsetIndex < _quaternionOffsetsCount);
-
- // Handle remaining scalar values.
- while (i < _componentCount)
- {
- dst[i] = h00 * from->value[i] + h01 * to->value[i] + h10 * from->outValue[i] + h11 * to->inValue[i];
- i++;
- }
- }
- }
- void Curve::interpolateHermiteFlat(float s, Point* from, Point* to, float* dst) const
- {
- // Calculate the hermite basis functions.
- float s_2 = s * s; // t^2
- float s_3 = s_2 * s; // t^3
- float h00 = 2 * s_3 - 3 * s_2 + 1; // basis function 0
- float h01 = -2 * s_3 + 3 * s_2; // basis function 1
- if (!_quaternionOffsets)
- {
- for (unsigned int i = 0; i < _componentCount; i++)
- {
- dst[i] = h00 * from->value[i] + h01 * to->value[i];
- }
- }
- else
- {
- // Interpolate values as scalars up to first quaternion offset.
- unsigned int quaternionOffsetIndex = 0;
- unsigned int quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
- unsigned int i = 0;
- float interpTime = h01 * 1.0f; // Can drop all other terms because they will compute to 0. Only need to compute once.
- do {
- while (i < quaternionOffset)
- {
- dst[i] = h00 * from->value[i] + h01 * to->value[i];
- i++;
- }
- // We've hit a quaternion component, so handle it. increase the component counter by 4, and increase quaternionOffsetIndex
- interpolateQuaternion(interpTime, (from->value + quaternionOffset), (to->value + quaternionOffset), (dst + quaternionOffset));
- i += 4;
- quaternionOffsetIndex++;
- quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
- } while (quaternionOffsetIndex < _quaternionOffsetsCount);
- // Handle remaining scalar values.
- while (i < _componentCount)
- {
- dst[i] = h00 * from->value[i] + h01 * to->value[i];
- i++;
- }
- }
- }
- void Curve::interpolateHermiteSmooth(float s, unsigned int index, Point* from, Point* to, float* dst) const
- {
- // Calculate the hermite basis functions.
- float s_2 = s * s; // t^2
- float s_3 = s_2 * s; // t^3
- float h00 = 2 * s_3 - 3 * s_2 + 1; // basis function 0
- float h01 = -2 * s_3 + 3 * s_2; // basis function 1
- float h10 = s_3 - 2 * s_2 + s; // basis function 2
- float h11 = s_3 - s_2; // basis function 3
- float inValue;
- float outValue;
- if (!_quaternionOffsets)
- {
- for (unsigned int i = 0; i < _componentCount; i++)
- {
- if (index == 0)
- {
- outValue = to->value[i] - from->value[i];
- }
- else
- {
- outValue = (to->value[i] - (from - 1)->value[i]) * ((from->time - (from - 1)->time) / (to->time - (from - 1)->time));
- }
- if (index == _pointCount - 2)
- {
- inValue = to->value[i] - from->value[i];
- }
- else
- {
- inValue = ((to + 1)->value[i] - from->value[i]) * ((to->time - from->time) / ((to + 1)->time - from->time));
- }
- dst[i] = h00 * from->value[i] + h01 * to->value[i] + h10 * outValue + h11 * inValue;
- }
- }
- else
- {
- // Calculates in/out values for interpolating the time for the quaternion component.
- // Only need to calculate this once.
- if (index == 0)
- {
- outValue = to->time - from->time;
- }
- else
- {
- outValue = (to->time - (from - 1)->time) * ((from->time - (from - 1)->time) / (to->time - (from - 1)->time));
- }
- if (index == _pointCount - 2)
- {
- inValue = to->time - from->time;
- }
- else
- {
- inValue = ((to + 1)->time - from->time) * ((to->time - from->time) / ((to + 1)->time - from->time));
- }
- // Interpolate values as scalars up to first quaternion offset.
- unsigned int quaternionOffsetIndex = 0;
- unsigned int quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
- unsigned int i = 0;
- do {
- // Handle scalar values up to the quaternion offset.
- while (i < quaternionOffset)
- {
- // Interpolate as scalar.
- if (index == 0)
- {
- outValue = to->value[i] - from->value[i];
- }
- else
- {
- outValue = (to->value[i] - (from - 1)->value[i]) * ((from->time - (from - 1)->time) / (to->time - (from - 1)->time));
- }
- if (index == _pointCount - 2)
- {
- inValue = to->value[i] - from->value[i];
- }
- else
- {
- inValue = ((to + 1)->value[i] - from->value[i]) * ((to->time - from->time) / ((to + 1)->time - from->time));
- }
- dst[i] = h00 * from->value[i] + h01 * to->value[i] + h10 * outValue + h11 * inValue;
- i++;
- }
-
- float interpTime = h01 * 1.0f + h10 * outValue + h11 * inValue;
- interpolateQuaternion(interpTime, (from->value + quaternionOffset), (to->value + quaternionOffset), (dst + quaternionOffset));
- i+=4;
- quaternionOffsetIndex++;
- quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
- } while (quaternionOffsetIndex < _quaternionOffsetsCount);
-
- // Handle remaining scalar values.
- while (i < _componentCount)
- {
- // Interpolate as scalar.
- if (index == 0)
- {
- outValue = to->value[i] - from->value[i];
- }
- else
- {
- outValue = (to->value[i] - (from - 1)->value[i]) * ((from->time - (from - 1)->time) / (to->time - (from - 1)->time));
- }
- if (index == _pointCount - 2)
- {
- inValue = to->value[i] - from->value[i];
- }
- else
- {
- inValue = ((to + 1)->value[i] - from->value[i]) * ((to->time - from->time) / ((to + 1)->time - from->time));
- }
- dst[i] = h00 * from->value[i] + h01 * to->value[i] + h10 * outValue + h11 * inValue;
- i++;
- }
- }
- }
- void Curve::interpolateLinear(float s, Point* from, Point* to, float* dst) const
- {
- if (!_quaternionOffsets)
- {
- for (unsigned int i = 0; i < _componentCount; i++)
- {
- dst[i] = from->value[i] + (to->value[i] - from->value[i]) * s;
- }
- }
- else
- {
- // Interpolate values as scalars up to first quaternion offset.
- unsigned int quaternionOffsetIndex = 0;
- unsigned int quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
- unsigned int i = 0;
- do {
- // Loop through values until you hit the next quaternion offset.
- while (i < quaternionOffset)
- {
- dst[i] = from->value[i] + (to->value[i] - from->value[i]) * s;
- i++;
- }
- // Handle quaternion component.
- interpolateQuaternion(s, (from->value + quaternionOffset), (to->value + quaternionOffset), (dst + quaternionOffset));
- i += 4;
- quaternionOffsetIndex++;
- quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
- } while (quaternionOffsetIndex < _quaternionOffsetsCount);
- // Loop through the last remaining values, if any.
- while (i < _componentCount)
- {
- dst[i] = from->value[i] + (to->value[i] - from->value[i]) * s;
- i++;
- }
- }
- }
- void slerpQuat(float* q1, float* q2, float t, float* dst)
- {
- // Fast slerp implementation by kwhatmough:
- // It contains no division operations, no trig, no inverse trig
- // and no sqrt. Not only does this code tolerate small constraint
- // errors in the input quaternions, it actually corrects for them.
- assert(dst);
- assert(!(t < 0.0f || t > 1.0f));
- if (t == 0.0f)
- {
- memcpy(dst, q1, sizeof(float) * 4);
- return;
- }
- else if (t == 1.0f)
- {
- memcpy(dst, q2, sizeof(float) * 4);
- return;
- }
- float halfY, alpha, beta;
- float u, f1, f2a, f2b;
- float ratio1, ratio2;
- float halfSecHalfTheta, versHalfTheta;
- float sqNotU, sqU;
- float cosTheta = q1[3] * q2[3] + q1[0] * q2[0] + q1[1] * q2[1] + q1[2] * q2[2];
- // As usual in all slerp implementations, we fold theta.
- alpha = cosTheta >= 0 ? 1.0f : -1.0f;
- halfY = 1.0f + alpha * cosTheta;
- // Here we bisect the interval, so we need to fold t as well.
- f2b = t - 0.5f;
- u = f2b >= 0 ? f2b : -f2b;
- f2a = u - f2b;
- f2b += u;
- u += u;
- f1 = 1.0f - u;
- // One iteration of Newton to get 1-cos(theta / 2) to good accuracy.
- halfSecHalfTheta = 1.09f - (0.476537f - 0.0903321f * halfY) * halfY;
- halfSecHalfTheta *= 1.5f - halfY * halfSecHalfTheta * halfSecHalfTheta;
- versHalfTheta = 1.0f - halfY * halfSecHalfTheta;
- // Evaluate series expansions of the coefficients.
- sqNotU = f1 * f1;
- ratio2 = 0.0000440917108f * versHalfTheta;
- ratio1 = -0.00158730159f + (sqNotU - 16.0f) * ratio2;
- ratio1 = 0.0333333333f + ratio1 * (sqNotU - 9.0f) * versHalfTheta;
- ratio1 = -0.333333333f + ratio1 * (sqNotU - 4.0f) * versHalfTheta;
- ratio1 = 1.0f + ratio1 * (sqNotU - 1.0f) * versHalfTheta;
- sqU = u * u;
- ratio2 = -0.00158730159f + (sqU - 16.0f) * ratio2;
- ratio2 = 0.0333333333f + ratio2 * (sqU - 9.0f) * versHalfTheta;
- ratio2 = -0.333333333f + ratio2 * (sqU - 4.0f) * versHalfTheta;
- ratio2 = 1.0f + ratio2 * (sqU - 1.0f) * versHalfTheta;
- // Perform the bisection and resolve the folding done earlier.
- f1 *= ratio1 * halfSecHalfTheta;
- f2a *= ratio2;
- f2b *= ratio2;
- alpha *= f1 + f2a;
- beta = f1 + f2b;
- // Apply final coefficients to a and b as usual.
- float w = alpha * q1[3] + beta * q2[3];
- float x = alpha * q1[0] + beta * q2[0];
- float y = alpha * q1[1] + beta * q2[1];
- float z = alpha * q1[2] + beta * q2[2];
- // This final adjustment to the quaternion's length corrects for
- // any small constraint error in the inputs q1 and q2. But as you
- // can see, it comes at the cost of 9 additional multiplication
- // operations. If this error-correcting feature is not required,
- // the following code may be removed.
- f1 = 1.5f - 0.5f * (w * w + x * x + y * y + z * z);
- dst[3] = w * f1;
- dst[0] = x * f1;
- dst[1] = y * f1;
- dst[2] = z * f1;
- }
- void normalizeQuat(float* q)
- {
- float n = q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3];
- // Do we need to normalize?
- if (fabs(n) > 0.00001f && fabs(n - 1.0f) > 0.00001f)
- {
- n = sqrtf(n);
- q[0] /= n;
- q[1] /= n;
- q[2] /= n;
- q[3] /= n;
- }
- }
- void Curve::interpolateQuaternion(float s, float* from, float* to, float* dst) const
- {
- float quatFrom[4] = { from[0], from[1], from[2], from[3] };
- float quatTo[4] = { to[0], to[1], to[2], to[3] };
- // Normalize the quaternions.
- normalizeQuat(quatFrom);
- normalizeQuat(quatTo);
-
- // Evaluate.
- if (s >= 0)
- slerpQuat(quatFrom, quatTo, s, dst);
- else
- slerpQuat(quatTo, quatFrom, -s, dst);
- }
- int Curve::determineIndex(float time) const
- {
- unsigned int min = 0;
- unsigned int max = _pointCount - 1;
- unsigned int mid = 0;
- // Do a binary search to determine the index.
- do
- {
- mid = (min + max) >> 1;
- if (time >= _points[mid].time && time <= _points[mid + 1].time)
- return mid;
- else if (time < _points[mid].time)
- max = mid - 1;
- else
- min = mid + 1;
- } while (min <= max);
-
- // We should never hit this!
- return -1;
- }
- }
|