SneakySquid icon

Ellipses!

SneakySquid | PRO | 07/17/24 12:38:40 PM UTC (Edited) | 0 ⭐ | 850 👁️ | Never ⏰ | []
Lua |

2.9 KB

|

None

|

0 👍

/

0 👎

local _R = debug.getregistry()
_R.EllipseCache = {}
 
local VMatrix = _R.VMatrix
local VMatrix_SetUnpacked = VMatrix.SetUnpacked
 
local IMesh = _R.IMesh
local IMesh_Draw = IMesh.Draw
local IMesh_Destroy = IMesh.Destroy
local IMesh_IsValid = IMesh.IsValid
local IMesh_BuildFromTriangles = IMesh.BuildFromTriangles
 
local Ellipse do
    local ellipse_matrix = Matrix()
 
    local anchor_vertex = {
        pos = Vector(0, 0),
        u = 0.5, v = 0.5,
    }
 
    local function RenderEllipse(ellipse_mesh, scale_x, scale_y)
        return function(self, x, y, rotation)
            if not self:IsValid() then return false end
 
            x, y = tonumber(x) or 0, tonumber(y) or 0
            rotation = tonumber(rotation) or 0
 
            if rotation ~= 0 then
                local rotation = math.rad(rotation)
                local cos, sin = math.cos(rotation), math.sin(rotation)
 
                VMatrix_SetUnpacked(ellipse_matrix,
                    cos * scale_x, -sin * scale_y, 0, x,
                    sin * scale_x,  cos * scale_y, 0, y,
                    0, 0, 1, 0,
                    0, 0, 0, 1
                )
            else
                VMatrix_SetUnpacked(ellipse_matrix,
                    scale_x, 0, 0, x,
                    0, scale_y, 0, y,
                    0, 0, 1, 0,
                    0, 0, 0, 1
                )
            end
 
            cam.PushModelMatrix(ellipse_matrix)
                IMesh_Draw(ellipse_mesh)
            cam.PopModelMatrix()
 
            return true
        end
    end
 
    function Ellipse(width, height, start_angle, end_angle, distance, color)
        local width, height = width / 2, height / 2
        local radius = math.max(width, height)
        local start_angle, end_angle = math.Clamp(start_angle, 0, 360), math.Clamp(end_angle, 0, 360)
 
        local id = string.format("%i-%i-%i-%.2f-%s", radius, start_angle, end_angle, distance, color or color_white)
 
        if not _R.EllipseCache[id] then
            local vertices = {}
            local vertex_count = 0
            local step = distance / radius
            local start_angle, end_angle = math.rad(start_angle), math.rad(end_angle)
 
            for angle = start_angle, end_angle, step do
                local a, b = angle, angle + step
                b = math.min(b, end_angle)
 
                local a_cos, a_sin = math.cos(a), math.sin(a)
                local b_cos, b_sin = math.cos(b), math.sin(b)
 
                vertices[vertex_count + 1] = anchor_vertex
 
                vertices[vertex_count + 2] = {
                    pos = Vector(a_cos * radius, a_sin * radius),
                    u = 0.5 + a_cos / 2, v = 0.5 + a_sin / 2,
                }
 
                vertices[vertex_count + 3] = {
                    pos = Vector(b_cos * radius, b_sin * radius),
                    u = 0.5 + b_cos / 2, v = 0.5 + b_sin / 2,
                }
 
                vertex_count = vertex_count + 3
            end
 
            local ellipse_mesh = Mesh()
            IMesh_BuildFromTriangles(ellipse_mesh, vertices)
 
            _R.EllipseCache[id] = setmetatable(
                {
                    Destroy = function()
                        _R.EllipseCache[id] = nil
                        return IMesh_Destroy(ellipse_mesh)
                    end,
 
                    IsValid = function()
                        return IMesh_IsValid(ellipse_mesh)
                    end,
                },
 
                {
                    __call = RenderEllipse(ellipse_mesh, width / radius, height / radius),
                }
            )
        end
 
        return _R.EllipseCache[id]
    end
end
 
return Ellipse
 

Comments

  • SneakySquid icon
    06/05/24 11:59:06 AM UTC
    Lua |

    0 B

    |

    0 👍

    /

    0 👎

    local Ellipse = include("ellipse.lua")
     
    local x, y = ScrW() / 2, ScrH() / 2
    local ellipse_test = Ellipse(600, 400, 0, 360, 1, color_white)
     
    hook.Add("PostRender", ellipse_test, function()
        cam.Start2D()
            render.SetMaterial(Material("vgui/white"))
            ellipse_test(x, y, (1 + math.sin(CurTime())) / 2 * 360)
        cam.End2D()
    end)
     
    timer.Simple(1, function()
        ellipse_test:Destroy()
        print("Removed ellipse.")
    end)