graphicsluadrawinglove2d

Clipping a polygon to only draw within a circle in Love2D


I'm trying to draw a circle with filled, randomly generated polygons drawn on top of it, but I can't work out how to make it so that the polygons are only drawn on top of the circle.

Here's a mockup as an example:

enter image description here

I have a achieved the random polygons drawn on a circle, using the love.graphics.polygon() function with a set of randomly generated points, but I'm looking for a way of clipping them when they're drawn so that they're only filled in on top of the circle.

Here's what I've actually got so far:

enter image description here

So, my question is: is there a function that I can call in the love.draw function that clips parts of the polygon drawn outside of a range, or is it going to be harder to fix than that?

Thanks in advance!


Solution

  • It turns out that I could have just spent a minute looking at the love.graphics documentation. Anyway, the love.graphics.stencil() function and its counterpart love.graphics.setStencilTest() are just what I needed.

    You can pass the draw function for the circle to the love.graphics.stencil() function, and the using the setStencilTest(), you can make it not draw pixels outside that circle function. The documentation has some good examples.

    Here is a simple example with a camera centered on the screen with a mask only allowing the background grid to be drawn within the circle. Use motion keys to move the camera.

    function love.load()
      camera_x = 0
      camera_y = 0
    end
    
    function love.draw()
      local width, height = love.graphics.getDimensions()
    
      love.graphics.stencil(function()
        love.graphics.circle("fill", width / 2, height / 2, math.min(width*2/3, height*2/3) / 2)
      end, "replace", 1)
    
      love.graphics.setStencilTest("greater", 0)
    
      -- draw a grid to see the camera movement
      for x = 0, width, 50 do
        local x = x - camera_x % 50
        love.graphics.line(x, 0, x, height)
    
        for y = 0, height, 50 do
          local y = y - camera_y % 50
          love.graphics.line(0, y, width, y)
        end
      end
    end
    
    function love.update(dt)
      if love.keyboard.isDown("up") then
        camera_y = camera_y - 100 * dt * 2
      end
      if love.keyboard.isDown("down") then
        camera_y = camera_y + 100 * dt * 2
      end
      if love.keyboard.isDown("left") then
        camera_x = camera_x - 100 * dt * 2
      end
      if love.keyboard.isDown("right") then
        camera_x = camera_x + 100 * dt * 2
      end
    end