[rshapes] Add implementations
This commit is contained in:
parent
cb3168a048
commit
51d849571d
408
src/rshapes.c
408
src/rshapes.c
|
|
@ -2107,6 +2107,66 @@ void DrawSplineSegmentBezierCubic(Vector2 p1, Vector2 c2, Vector2 c3, Vector2 p4
|
||||||
DrawTriangleStrip(points, 2*SPLINE_SEGMENT_DIVISIONS + 2, color);
|
DrawTriangleStrip(points, 2*SPLINE_SEGMENT_DIVISIONS + 2, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Draw spline segment with variable thickness: Cubic Bezier, 2 points, 2 control points, 1 or more thickness
|
||||||
|
void DrawSplineSegmentBezierCubicVar(Vector2 p1, Vector2 c2, Vector2 c3, Vector2 p4, const float* thicks, int thickCount, Color color)
|
||||||
|
{
|
||||||
|
if (thickCount >= 1)
|
||||||
|
{
|
||||||
|
const float step = 1.0f/SPLINE_SEGMENT_DIVISIONS;
|
||||||
|
|
||||||
|
Vector2 previous = p1;
|
||||||
|
Vector2 current = { 0 };
|
||||||
|
float t = 0.0f;
|
||||||
|
|
||||||
|
Vector2 points[2*SPLINE_SEGMENT_DIVISIONS + 2] = { 0 };
|
||||||
|
|
||||||
|
for (int i = 1; i <= SPLINE_SEGMENT_DIVISIONS; i++)
|
||||||
|
{
|
||||||
|
t = step*(float)i;
|
||||||
|
|
||||||
|
float thick;
|
||||||
|
if (thickCount > 1) {
|
||||||
|
float tMajor = t*(float)thickCount;
|
||||||
|
int tIndex = (int)tMajor;
|
||||||
|
if (tIndex >= thickCount) tIndex = thickCount - 1;
|
||||||
|
float tMinor = tMajor - (float)tIndex;
|
||||||
|
thick = thicks[tIndex];
|
||||||
|
} else {
|
||||||
|
thick = thicks[0]; // constant thickness
|
||||||
|
}
|
||||||
|
|
||||||
|
float a = powf(1.0f - t, 3);
|
||||||
|
float b = 3.0f*powf(1.0f - t, 2)*t;
|
||||||
|
float c = 3.0f*(1.0f - t)*powf(t, 2);
|
||||||
|
float d = powf(t, 3);
|
||||||
|
|
||||||
|
current.y = a*p1.y + b*c2.y + c*c3.y + d*p4.y;
|
||||||
|
current.x = a*p1.x + b*c2.x + c*c3.x + d*p4.x;
|
||||||
|
|
||||||
|
float dy = current.y - previous.y;
|
||||||
|
float dx = current.x - previous.x;
|
||||||
|
float size = 0.5f*thick/sqrtf(dx*dx+dy*dy);
|
||||||
|
|
||||||
|
if (i == 1)
|
||||||
|
{
|
||||||
|
points[0].x = previous.x + dy*size;
|
||||||
|
points[0].y = previous.y - dx*size;
|
||||||
|
points[1].x = previous.x - dy*size;
|
||||||
|
points[1].y = previous.y + dx*size;
|
||||||
|
}
|
||||||
|
|
||||||
|
points[2*i + 1].x = current.x - dy*size;
|
||||||
|
points[2*i + 1].y = current.y + dx*size;
|
||||||
|
points[2*i].x = current.x + dy*size;
|
||||||
|
points[2*i].y = current.y - dx*size;
|
||||||
|
|
||||||
|
previous = current;
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawTriangleStrip(points, 2*SPLINE_SEGMENT_DIVISIONS + 2, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get spline point for a given t [0.0f .. 1.0f], Linear
|
// Get spline point for a given t [0.0f .. 1.0f], Linear
|
||||||
Vector2 GetSplinePointLinear(Vector2 startPos, Vector2 endPos, float t)
|
Vector2 GetSplinePointLinear(Vector2 startPos, Vector2 endPos, float t)
|
||||||
{
|
{
|
||||||
|
|
@ -2189,6 +2249,354 @@ Vector2 GetSplinePointBezierCubic(Vector2 startPos, Vector2 startControlPos, Vec
|
||||||
return point;
|
return point;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get spline direction and speed, Linear Bezier
|
||||||
|
//
|
||||||
|
// Normalize to get the "forward" direction of the curve
|
||||||
|
Vector2 GetSplineVelocityLinear(Vector2 startPos, Vector2 endPos)
|
||||||
|
{
|
||||||
|
Vector2 velocity = { 0 };
|
||||||
|
|
||||||
|
velocity.x = endPos.x - startPos.x;
|
||||||
|
velocity.y = endPos.y - startPos.y;
|
||||||
|
|
||||||
|
return velocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get spline direction and speed for a given t [0.0f .. 1.0f], Quadratic Bezier
|
||||||
|
//
|
||||||
|
// Normalize to get the "forward" direction of the curve at t
|
||||||
|
Vector2 GetSplineVelocityBezierQuad(Vector2 startPos, Vector2 controlPos, Vector2 endPos, float t)
|
||||||
|
{
|
||||||
|
Vector2 velocity = { 0 };
|
||||||
|
|
||||||
|
float a = 2.0f*(1.0f - t);
|
||||||
|
float b = 2.0f*t;
|
||||||
|
|
||||||
|
velocity.x = a*(controlPos.x - startPos.x) + b*(endPos.x - controlPos.x);
|
||||||
|
velocity.y = a*(controlPos.y - startPos.y) + b*(endPos.y - controlPos.y);
|
||||||
|
|
||||||
|
return velocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get spline direction and speed for a given t [0.0f .. 1.0f], Cubic Bezier
|
||||||
|
//
|
||||||
|
// Normalize to get the "forward" direction of the curve at t
|
||||||
|
Vector2 GetSplineVelocityBezierCubic(Vector2 startPos, Vector2 startControlPos, Vector2 endControlPos, Vector2 endPos, float t)
|
||||||
|
{
|
||||||
|
Vector2 velocity = { 0 };
|
||||||
|
|
||||||
|
float a = 3.0f*powf(1.0f - t, 2);
|
||||||
|
float b = 6.0f*(1.0f - t)*t;
|
||||||
|
float c = 3.0f*t*t;
|
||||||
|
|
||||||
|
velocity.x = a*(startControlPos.x - startPos.x) + b*(endControlPos.x - startControlPos.x) + c*(endPos.x - endControlPos.x);
|
||||||
|
velocity.y = a*(startControlPos.y - startPos.y) + b*(endControlPos.y - startControlPos.y) + c*(endPos.y - endControlPos.y);
|
||||||
|
|
||||||
|
return velocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get spline rate of change, Quadratic Bezier
|
||||||
|
Vector2 GetSplineAccelerationBezierQuad(Vector2 startPos, Vector2 controlPos, Vector2 endPos)
|
||||||
|
{
|
||||||
|
Vector2 acceleration = { 0 };
|
||||||
|
|
||||||
|
acceleration.x = 2.0f*(endPos.x - 2.0f*controlPos.x - startPos.x);
|
||||||
|
acceleration.y = 2.0f*(endPos.y - 2.0f*controlPos.y - startPos.y);
|
||||||
|
|
||||||
|
return acceleration;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get spline rate of change for a given t [0.0f .. 1.0f], Cubic Bezier
|
||||||
|
Vector2 GetSplineAccelerationBezierCubic(Vector2 startPos, Vector2 startControlPos, Vector2 endControlPos, Vector2 endPos, float t)
|
||||||
|
{
|
||||||
|
Vector2 acceleration = { 0 };
|
||||||
|
|
||||||
|
float a = 2.0f*(1.0f - t);
|
||||||
|
float b = 2.0f*t;
|
||||||
|
|
||||||
|
acceleration.x = a*(endControlPos.x - 2.0f*startControlPos.x + startPos.x) + b*(endPos.x - 2.0f*endControlPos.x + startControlPos.x);
|
||||||
|
acceleration.y = a*(endControlPos.y - 2.0f*startControlPos.y + startPos.y) + b*(endPos.y - 2.0f*endControlPos.y + startControlPos.y);
|
||||||
|
|
||||||
|
return acceleration;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get spline rate of acceleration, Cubic Bezier
|
||||||
|
Vector2 GetSplineJoltBezierCubic(Vector2 startPos, Vector2 startControlPos, Vector2 endControlPos, Vector2 endPos)
|
||||||
|
{
|
||||||
|
Vector2 jolt = { 0 };
|
||||||
|
|
||||||
|
jolt.x = 6.0f*(endPos.x + 3.0f*(startControlPos.x - endControlPos.x) - startPos.x);
|
||||||
|
jolt.y = 6.0f*(endPos.y + 3.0f*(startControlPos.y - endControlPos.y) - startPos.y);
|
||||||
|
|
||||||
|
return jolt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute spline curve bounding rectangle, Linear Bezier
|
||||||
|
Rectangle GetSplineBoundsBezierLinear(Vector2 startPos, Vector2 endPos)
|
||||||
|
{
|
||||||
|
float xMin;
|
||||||
|
float yMin;
|
||||||
|
float xMax;
|
||||||
|
float yMax;
|
||||||
|
|
||||||
|
if (startPos.x < endPos.x)
|
||||||
|
{
|
||||||
|
xMin = startPos.x;
|
||||||
|
xMax = endPos.x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xMin = endPos.x;
|
||||||
|
xMax = startPos.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startPos.y < endPos.y)
|
||||||
|
{
|
||||||
|
yMin = startPos.y;
|
||||||
|
yMax = endPos.y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
yMin = endPos.y;
|
||||||
|
yMax = startPos.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// straight line will never escape bounds
|
||||||
|
|
||||||
|
Rectangle bounds = { xMin, yMin, xMax - xMin, yMax - yMin };
|
||||||
|
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute spline curve bounding rectangle, Quadratic Bezier
|
||||||
|
Rectangle GetSplineBoundsBezierQuad(Vector2 startPos, Vector2 controlPos, Vector2 endPos)
|
||||||
|
{
|
||||||
|
float xMin;
|
||||||
|
float yMin;
|
||||||
|
float xMax;
|
||||||
|
float yMax;
|
||||||
|
|
||||||
|
if (startPos.x < endPos.x)
|
||||||
|
{
|
||||||
|
xMin = startPos.x;
|
||||||
|
xMax = endPos.x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xMin = endPos.x;
|
||||||
|
xMax = startPos.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startPos.y < endPos.y)
|
||||||
|
{
|
||||||
|
yMin = startPos.y;
|
||||||
|
yMax = endPos.y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
yMin = endPos.y;
|
||||||
|
yMax = startPos.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// curve velocity, rearranged to solve for t
|
||||||
|
// at^2 + bt + c
|
||||||
|
// local min/max occur where derivative (velocity) is zero,
|
||||||
|
// so we use quadratic formula to find values of t at zeros
|
||||||
|
|
||||||
|
float a = startPos.x - 2.0f*controlPos.x + endPos.x;
|
||||||
|
float b = 2.0f*(controlPos.x - startPos.x);
|
||||||
|
float c = startPos.x;
|
||||||
|
|
||||||
|
bool dejavu = false;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (a != 0)
|
||||||
|
{
|
||||||
|
float bSqrMinus4ac = b*b - 4.0f*a*c;
|
||||||
|
float t[2] = { 0 };
|
||||||
|
int tCount = 0;
|
||||||
|
if (bSqrMinus4ac > 0)
|
||||||
|
{
|
||||||
|
float denominator = 1.0f/(2.0f*a);
|
||||||
|
|
||||||
|
float term0 = -b*denominator;
|
||||||
|
float term1 = sqrtf(bSqrMinus4ac)*denominator;
|
||||||
|
|
||||||
|
t[0] = term0 + term1;
|
||||||
|
if (0.0f < t[0] && t[0] < 1.0f) ++tCount;
|
||||||
|
|
||||||
|
t[tCount] = term0 - term1;
|
||||||
|
if (0.0f < t[tCount] && t[tCount] < 1.0f) ++tCount;
|
||||||
|
}
|
||||||
|
else if (bSqrMinus4ac == 0)
|
||||||
|
{
|
||||||
|
t[0] = -b/(2.0f*a);
|
||||||
|
if (0.0f < t[0] && t[0] < 1.0f) ++tCount;
|
||||||
|
}
|
||||||
|
// ignore imaginary solution
|
||||||
|
|
||||||
|
for (int i = 0; i < tCount; ++i)
|
||||||
|
{
|
||||||
|
Vector2 point = GetSplinePointBezierQuad(startPos, controlPos, endPos, t[i]);
|
||||||
|
|
||||||
|
if (point.x < xMin) xMin = point.x;
|
||||||
|
if (point.x > xMax) xMax = point.x;
|
||||||
|
if (point.y < yMin) yMin = point.y;
|
||||||
|
if (point.y > yMax) yMax = point.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// straight line will never escape bounds
|
||||||
|
|
||||||
|
if (dejavu) break;
|
||||||
|
dejavu = true;
|
||||||
|
|
||||||
|
a = startPos.y - 2.0f*controlPos.y + endPos.y;
|
||||||
|
b = 2.0f*(controlPos.y - startPos.y);
|
||||||
|
c = startPos.y;
|
||||||
|
}
|
||||||
|
while (true);
|
||||||
|
|
||||||
|
Rectangle bounds = { xMin, yMin, xMax - xMin, yMax - yMin };
|
||||||
|
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute spline curve bounding rectangle, Cubic Bezier
|
||||||
|
Rectangle GetSplineBoundsBezierCubic(Vector2 startPos, Vector2 startControlPos, Vector2 endControlPos, Vector2 endPos)
|
||||||
|
{
|
||||||
|
float xMin;
|
||||||
|
float yMin;
|
||||||
|
float xMax;
|
||||||
|
float yMax;
|
||||||
|
|
||||||
|
if (startPos.x < endPos.x)
|
||||||
|
{
|
||||||
|
xMin = startPos.x;
|
||||||
|
xMax = endPos.x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xMin = endPos.x;
|
||||||
|
xMax = startPos.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startPos.y < endPos.y)
|
||||||
|
{
|
||||||
|
yMin = startPos.y;
|
||||||
|
yMax = endPos.y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
yMin = endPos.y;
|
||||||
|
yMax = startPos.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// curve velocity, rearranged to solve for t
|
||||||
|
// at^2 + bt + c
|
||||||
|
// local min/max occur where derivative (velocity) is zero,
|
||||||
|
// so we use quadratic formula to find values of t at zeros
|
||||||
|
|
||||||
|
float a = -3.0f*startPos.x + 9.0f*startControlPos.x - 9.0f*endControlPos.x + 3.0f*endPos.x;
|
||||||
|
float b = 6.0f*startPos.x - 12.0f*startControlPos.x + 6.0f*endControlPos.x;
|
||||||
|
float c = -3.0f*startPos.x + 3.0f*startControlPos.x;
|
||||||
|
|
||||||
|
bool dejavu = false;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (a != 0)
|
||||||
|
{
|
||||||
|
float bSqrMinus4ac = b*b - 4.0f*a*c;
|
||||||
|
float t[2] = { 0 };
|
||||||
|
int tCount = 0;
|
||||||
|
if (bSqrMinus4ac > 0)
|
||||||
|
{
|
||||||
|
float denominator = 1.0f/(2.0f*a);
|
||||||
|
|
||||||
|
float term0 = -b*denominator;
|
||||||
|
float term1 = sqrtf(bSqrMinus4ac)*denominator;
|
||||||
|
|
||||||
|
t[0] = term0 + term1;
|
||||||
|
if (0.0f < t[0] && t[0] < 1.0f) ++tCount;
|
||||||
|
|
||||||
|
t[tCount] = term0 - term1;
|
||||||
|
if (0.0f < t[tCount] && t[tCount] < 1.0f) ++tCount;
|
||||||
|
}
|
||||||
|
else if (bSqrMinus4ac == 0)
|
||||||
|
{
|
||||||
|
t[0] = -b/(2.0f*a);
|
||||||
|
if (0.0f < t[0] && t[0] < 1.0f) ++tCount;
|
||||||
|
}
|
||||||
|
// ignore imaginary solution
|
||||||
|
|
||||||
|
for (int i = 0; i < tCount; ++i)
|
||||||
|
{
|
||||||
|
Vector2 point = GetSplinePointBezierCubic(startPos, startControlPos, endControlPos, endPos, t[i]);
|
||||||
|
|
||||||
|
if (point.x < xMin) xMin = point.x;
|
||||||
|
if (point.x > xMax) xMax = point.x;
|
||||||
|
if (point.y < yMin) yMin = point.y;
|
||||||
|
if (point.y > yMax) yMax = point.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// straight line will never escape bounds
|
||||||
|
|
||||||
|
if (dejavu) break;
|
||||||
|
dejavu = true;
|
||||||
|
|
||||||
|
a = -3.0f*startPos.x + 9.0f*startControlPos.x - 9.0f*endControlPos.x + 3.0f*endPos.x;
|
||||||
|
b = 6.0f*startPos.x - 12.0f*startControlPos.x + 6.0f*endControlPos.x;
|
||||||
|
c = -3.0f*startPos.x + 3.0f*startControlPos.x;
|
||||||
|
}
|
||||||
|
while (true);
|
||||||
|
|
||||||
|
Rectangle bounds = { xMin, yMin, xMax - xMin, yMax - yMin };
|
||||||
|
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reciprocal radius (or "radians per meter") for a given t [0.0f .. 1.0f], Cubic Bezier
|
||||||
|
float GetSplineCurvatureBezierCubic(Vector2 startPos, Vector2 startControlPos, Vector2 endControlPos, Vector2 endPos, float t)
|
||||||
|
{
|
||||||
|
float curvature = 0.0f;
|
||||||
|
|
||||||
|
float a = 3.0f*powf(1.0f - t, 2);
|
||||||
|
float b = 6.0f*(1.0f - t)*t;
|
||||||
|
float c = 3.0f*t*t;
|
||||||
|
|
||||||
|
Vector2 velocity = { 0 };
|
||||||
|
|
||||||
|
velocity.x = a*(startControlPos.x - startPos.x) + b*(endControlPos.x - startControlPos.x) + c*(endPos.x - endControlPos.x);
|
||||||
|
velocity.y = a*(startControlPos.y - startPos.y) + b*(endControlPos.y - startControlPos.y) + c*(endPos.y - endControlPos.y);
|
||||||
|
|
||||||
|
a = 2.0f*(1.0f - t);
|
||||||
|
b = 2.0f*t;
|
||||||
|
|
||||||
|
Vector2 acceleration = { 0 };
|
||||||
|
|
||||||
|
acceleration.x = a*(endControlPos.x - 2.0f*startControlPos.x + startPos.x) + b*(endPos.x - 2.0f*endControlPos.x + startControlPos.x);
|
||||||
|
acceleration.y = a*(endControlPos.y - 2.0f*startControlPos.y + startPos.y) + b*(endPos.y - 2.0f*endControlPos.y + startControlPos.y);
|
||||||
|
|
||||||
|
float curvature = (velocity.x*acceleration.y - velocity.y*acceleration.x)/powf(sqrtf(velocity.x*velocity.x + velocity.y*velocity.y), 3);
|
||||||
|
|
||||||
|
return curvature;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get value of t (unbounded) for the point on the line closest to a given position
|
||||||
|
float GetSplineNearestTLinear(Vector2 startPos, Vector2 endPos, Vector2 point)
|
||||||
|
{
|
||||||
|
Vector2 edge = { 0 };
|
||||||
|
edge.x = endPos.x - startPos.x;
|
||||||
|
edge.y = endPos.y - startPos.y;
|
||||||
|
|
||||||
|
Vector2 diff = { 0 };
|
||||||
|
diff.x = point.x - startPos.x;
|
||||||
|
diff.y = point.y - startPos.y;
|
||||||
|
|
||||||
|
float t = (edge.x*diff.x + edge.y*diff.y)/(edge.x*edge.x + edge.y*edge.y);
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Module Functions Definition - Collision Detection functions
|
// Module Functions Definition - Collision Detection functions
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user