New version after 16 days


This version is mostly cleaning up and tightening the radical rewrite of the previous version. There's one major bugfix: searching for text using ctrl+f now works again. (This is inaccessible in common phone configurations, but useful on computers.)

Here's a really cool program inspired by Roni Kaufman. Give it an image filename on the first line (unfortunately only possible on a computer) and it will approximate it using just circles. Circles of different sizes, circles of different colors, but just circles.

local Fudge, filename = 0.3, ___
local imgdata = love.image.newImageData(filename)
local w, h = imgdata:getDimensions()
local show_image = false
circles = {}
nFrames, maxFrames = 1, 1000
function scale(a)
    local w2, h2 = Safe_width-60, Safe_height-Menu_height
    if w/h < w2/h2 then
        return a * h2/h
    else
        return a * w2/w
    end
end
function draw_image()
    for x=0,w-1 do
        for y=0,h-1 do
            local r,g,b, _ = imgdata:getPixel(x, y)
            color(r, g, b, 0.5)
            pt(30+scale(x),Menu_height+scale(y))
        end
    end
end
function car.draw()
    color(0,0,0)
    rect('fill', 30, Menu_height, scale(w), scale(h))
    assert(scale(w) < Safe_width)
    assert(scale(h) < Safe_height)
    if show_image then draw_image() end
    for _, c in ipairs(circles) do
        color(c.col.r, c.col.g, c.col.b, show_image and 0.5 or 1)
        circle('fill', 30+scale(c.x), Menu_height+scale(c.y), scale(c.r))
    end
end
function car.update(dt)
    nFrames = nFrames + 1
    if nFrames > maxFrames then return end
    for i=1,100 do
        local x, y = rand(w)-1, rand(h)-1
        local r,g,b,a = imgdata:getPixel(x,y)
        local col={r=r, g=g, b=b, a=a}
        local r = 1
        while canAddCircle(x,y, r, col) do
            r = r+1
        end
        if r > 2 then
            table.insert(circles, {x=x, y=y, r=r-1, col=col})
        end
    end
end
function canAddCircle(x,y, r, col)
    for _,c in ipairs(circles) do
        if dist(x,y, c.x,c.y) < c.r+r then
            return false  -- overlaps with existing circle
        end
    end
    for theta = 0, 2*pi, pi/16 do
        local x1 = floor(x + r*cos(theta))
        if x1 < 0 or x1 >= w then return false end
        local y1 = floor(y + r*sin(theta))
        if y1 < 0 or y1 >= h then return false end
        if not similar_shade(x1,y1, col) then
            return false
        end
    end
    return true
end
function similar_shade(x,y, c)
    local r,g,b,a = imgdata:getPixel(x,y)
    return Fudge > abs(r-c.r) + abs(g-c.g) + abs(b-c.b)
end
function car.keypressed()
    show_image = not show_image
end
function dist(x1,y1, x2,y2)
    return math.sqrt((x2-x1)^2 + (y2-y1)^2)
end

Unfortunately you can't run this on a phone because you need a way to make an image file accessible to Lua Carousel. On a computer you'll need to put the image file into the save directory of Lua Carousel. Then put the filename in the first line.

You'll also need the abbreviations on one of the example screens. Or if you've deleted that screen, here are the abbreviations I used in this post:

g = love.graphics
pt = g.points
rect = g.rectangle
circle = g.circle
color = g.setColor
floor, ceil = math.floor, math.ceil
abs, rand = math.abs, math.random
pi, cos, sin = math.pi, math.cos, math.sin

Get Lua Carousel

Leave a comment

Log in with itch.io to leave a comment.