Skip to content

Instantly share code, notes, and snippets.

@ZakBlystone
Last active December 23, 2020 09:17
Show Gist options
  • Save ZakBlystone/49ab52dd92326f83f861884289333f3d to your computer and use it in GitHub Desktop.
Save ZakBlystone/49ab52dd92326f83f861884289333f3d to your computer and use it in GitHub Desktop.
GLua code for drawing circles and arcs with thickness
-- Circles and Arcs (CC0 Public Domain, free to use in whatever you want)
-- Created by: Zachary Blystone ( [email protected] )
-- Vertex cache to prevent table allocations during draw operations
local vertCache = {}
for i=1, 256 do vertCache[i] = { x = 0, y = 0, u = 0, v = 0, } end
-- Localized functions
local math_rad = math.rad
local math_pi = math.pi
local math_cos = math.cos
local math_sin = math.sin
local math_min = math.min
local math_max = math.max
local surface_DrawPoly = surface.DrawPoly
-- surface.DrawCircle
-- centerX, centerY the center of the circle
-- radius the size of the circle
-- angle [0] the rotation of the circle (noticable if you have a small number of vertices)
-- numVerts [50] the number of vertices (corners) on the circle
function surface.DrawCircle(centerX,centerY,radius,angle,numVerts)
numVerts = math_min(numVerts or 50, 256)
local temp = nil
-- Setup angles and rotation
local increment = 2 * math_pi / numVerts
local angle = math_rad(angle or 0)
local cos = math_cos(increment)
local sin = math_sin(increment)
local x = math_cos(angle)
local y = math_sin(angle)
for i=1, numVerts do
-- Set the vertex
local v = vertCache[i]
v.x = centerX + x * radius
v.y = centerY + y * radius
v.u = (x + 1) * .5
v.v = (y + 1) * .5
-- Rotate the current frame by increment
temp = x * cos - y * sin
y = x * sin + y * cos
x = temp
end
-- Put a 'notch' in the vertex cache so only these vertices are drawn
temp = vertCache[numVerts+1]
vertCache[numVerts+1] = nil
surface_DrawPoly( vertCache )
-- Restore vertex cache
vertCache[numVerts+1] = temp
end
-- surface.DrawArc
-- centerX, centerY the center of the arc
-- radius the inner boundary of the arc
-- thickness [10] defines how thick the arc is
-- startAngle [0] the angle the arc should start from
-- endAngle [360] the angle the arc should end up at
-- numSegments [50] the number of segments (corners) the arc should have
function surface.DrawArc(centerX,centerY,radius,thickness,startAngle,endAngle,numSegments)
numSegments = math_max(numSegments or 50, 1)
local temp = nil
-- Setup angles and rotation
local angle = math_rad(startAngle or 0)
local sweep = math_rad(endAngle or 360) - angle
local increment = sweep / numSegments
local cos = math_cos(increment)
local sin = math_sin(increment)
local x = math_cos(angle)
local y = math_sin(angle)
local invSegments = 1 / numSegments
-- Gather vertices from cache
local v0 = vertCache[1]
local v1 = vertCache[2]
local v2 = vertCache[3]
local v3 = vertCache[4]
-- Negative thickness pushes the radius inward
if thickness < 0 then
radius = radius + thickness
thickness = -thickness
end
local outer = radius + (thickness or 10)
-- Put a 'notch' in the cache so only these vertices are drawn
local prevCache = vertCache[5]
vertCache[5] = nil
-- Each segment is 4 vertices
for i=1, numSegments do
-- Set vertices for this segment
v0.x = centerX + x * outer
v0.y = centerY + y * outer
v0.u = (i-1) * invSegments
v0.v = 0
v3.x = centerX + x * radius
v3.y = centerY + y * radius
v3.u = (i-1) * invSegments
v3.v = 1
-- Rotate the current frame by increment
temp = x * cos - y * sin
y = x * sin + y * cos
x = temp
-- Set vertices for the next segment
v1.x = centerX + x * outer
v1.y = centerY + y * outer
v1.u = i * invSegments
v1.v = 0
v2.x = centerX + x * radius
v2.y = centerY + y * radius
v2.u = i * invSegments
v2.v = 1
surface_DrawPoly( vertCache )
end
-- Restore vertex cache
vertCache[5] = prevCache
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment