Last active
August 1, 2023 21:26
-
-
Save Be1zebub/a2d1383a6ba09a2c5d71888dbeedf284 to your computer and use it in GitHub Desktop.
bezier.lua
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[--------------------------------------------------------- | |
Name: BezierLerp( frac, points ) | |
Desc: Lerp point between points with bezier algorithms | |
-----------------------------------------------------------]] | |
function math.BezierLerp( frac, points ) | |
local mu = frac * frac | |
local mum = 1 - frac | |
local mum2 = mum * mum | |
if ( points[4] ) then -- Cubic | |
return mum2 * mum * points[1] + 3 * mum2 * frac * points[2] + 3 * mum * mu * points[3] + mu * frac * points[4] | |
elseif ( points[3] ) then -- Quadratic | |
return mum2 * points[1] + 2 * mum * frac * points[2] + mu * points[3] | |
else -- Linear | |
return mum * points[1] + frac * points[2] | |
end | |
end | |
--[[--------------------------------------------------------- | |
Name: BezierSpline( points, steps, spline ) | |
Desc: Calc spline between points with bezier algorithms | |
-----------------------------------------------------------]] | |
do | |
local function GetDistance( p1, p2 ) | |
return math.sqrt( ( p2.x - p1.x ) ^ 2 + ( p2.y - p1.y ) ^ 2 ) | |
end | |
local bezierStepSize = 1 / ( math.pi * 10 ) | |
function math.BezierSpline( points, steps, spline ) | |
if steps == nil then | |
local distance = GetDistance( points[1], points[2] ) | |
if points[3] then | |
distance = distance + GetDistance( points[2], points[3] ) | |
end | |
if points[4] then | |
distance = distance + GetDistance( points[3], points[4] ) | |
end | |
steps = math.max( 1, math.floor( distance * bezierStepSize ) ) | |
end | |
spline = spline or {} | |
local i = 1 | |
for frac = 0, 1, 1 / steps do | |
spline[ i ] = math.BezierLerp( frac, points ) | |
i = i + 1 | |
end | |
return spline | |
end | |
end | |
local function bbox(points) | |
local mins, maxs = Vector(math.huge, math.huge), Vector() | |
for _, point in ipairs(points) do | |
mins.x, mins.y = math.min(mins.x, point.x), math.min(mins.y, point.y) | |
maxs.x, maxs.y = math.max(maxs.x, point.x), math.max(maxs.y, point.y) | |
end | |
return mins, maxs - mins | |
end | |
local function test(name, points) | |
local spline = math.BezierSpline(points) | |
return function() | |
local mins, maxs = bbox(points) | |
draw.SimpleText(name, "DermaDefault", mins.x + maxs.x * 0.5, mins.y, nil, TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM) | |
-- draw bbox | |
surface.SetDrawColor(0, 0, 0, 150) | |
surface.DrawRect(mins.x, mins.y, maxs.x, maxs.y) | |
-- draw points | |
surface.SetDrawColor(0, 255, 0) | |
for i, point in ipairs(points) do | |
surface.DrawRect(point.x - 4, point.y - 4, 8, 8) | |
draw.SimpleText(i, "DermaDefault", point.x + 4, point.y + 4) | |
end | |
-- draw spline | |
surface.SetDrawColor(255, 0, 0) | |
for _, point in ipairs(spline) do | |
surface.DrawRect(point.x - 2, point.y - 2, 4, 4) | |
end | |
-- draw moving point | |
local frac = RealTime() % 1 | |
local point = math.BezierLerp(frac, points) | |
surface.SetDrawColor(255, 255, 0) | |
surface.DrawRect(point.x - 4, point.y - 4, 8, 8) | |
end | |
end | |
do -- tests | |
local x, y = 32, 32 | |
local Cubic = test("Cubic", { | |
Vector(x, y), | |
Vector(x + 256, y), | |
Vector(x + 256, y + 256), | |
Vector(x, y + 256), | |
}) | |
x = x + 320 | |
local Quadratic = test("Quadratic", { | |
Vector(x, y), | |
Vector(x + 256, y), | |
Vector(x, y + 256) | |
}) | |
x = x + 320 | |
local Linear = test("Linear", { | |
Vector(x, y), | |
Vector(x + 256, y + 256) | |
}) | |
hook.Add("HUDPaint", "bezier tests", function() | |
Cubic() | |
Quadratic() | |
Linear() | |
end) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment