I wrote a little class that takes a drawing function and renders it into a circular mesh, creating a masked circle.
Here’s how it looks drawing random circles every frame into the masked area:

Edit: You can lower the number of sides to get a regular polygon mask, e.g:

Here’s the code:
CircleMask
CircleMask = class()
function CircleMask:init(rad, sides)
-- you can accept and set parameters here
self.mesh = mesh()
local verts = {}
local tex = {}
for i=1,sides do
local r1 = (i-1)/sides * math.pi * 2
local r2 = i/sides * math.pi * 2
local p1 = vec2( math.cos(r1), math.sin(r1) )
local p2 = vec2( math.cos(r2), math.sin(r2) )
-- Verts
table.insert(verts, p1 * rad)
table.insert(verts, p2 * rad)
table.insert(verts, vec2(0,0)) -- center
-- Tex Coords
table.insert(tex, (p1 + vec2(1,1)) * 0.5)
table.insert(tex, (p2 + vec2(1,1)) * 0.5)
table.insert(tex, vec2(0.5,0.5))
end
self.mesh.vertices = verts
self.mesh.texCoords = tex
self.mesh:setColors( 255,255,255 )
end
function CircleMask:setDrawFunction(func, w, h)
self.mesh.texture = image(w,h)
self.drawFunction = func
end
function CircleMask:setTexture(tex)
self.mesh.texture = tex
self.drawFunction = nil
end
function CircleMask:draw()
if self.drawFunction ~= nil then
setContext( self.mesh.texture )
pushMatrix()
resetMatrix()
self.drawFunction()
popMatrix()
setContext()
end
self.mesh:draw()
end
Main
function drawRandomCircles(w,h)
local minSize = w/10
local maxSize = w/4
pushStyle()
noStroke()
for i = 1,30 do
local s = math.random(minSize,maxSize)
fill( math.random(255),
math.random(255),
math.random(255), 255 )
ellipse( math.random(w), math.random(h), s )
end
popStyle()
end
function setup()
cm = CircleMask( 200, 30 )
cm:setDrawFunction( function ()
drawRandomCircles(200,200)
end, 200, 200 )
end
function draw()
background(40, 40, 50)
-- Do your drawing here
translate(WIDTH/2, HEIGHT/2)
cm:draw()
end