Large circle/ellipse renders slowly

Hi All!

I’ve been using Codea for a little while now, mostly on the train or the front veranda, and loving it. It’s really helping me find the time to tackle those little side projects that always pop up.

Anyway, I’m a little way through my first game. It involves rendering a circle in the middle of the screen representing a sun, which grows as the level progresses, in direct proportion with the player’s proximity to impending doom. I’m finding that once the circle reaches roughly half the height of the iPad display (in landscape) the frame rate dips noticeably. Is this known behaviour, and is there any optimisation I can do to increase the rendering speed of that circle? I have tried setting noSmooth() but it doesn’t seem to have any affect on ellipses which seems in line with the documentation.

Cheers,

Pete.

Circles use the most complex shader, and are the most expensive pixels to render. So drawing a large circle requires the shader be evaluated for each pixel. This will be much slower on iPad 1, which has significantly less fill rate than iPad 2.

Here’s bit of a hack to render a circle into an image and then use that instead. It should be faster, but your circle is limited to a fixed resolution.


function circleImage( size )
    local i = image(size,size)

    setContext(i)

    pushStyle()

    noStroke()
    fill(255) -- fill white, we can tint() the image

    ellipse( size/2, size/2, size )

    popStyle()

    setContext()

    return i
end

function setup()
    circleImg = circleImage( 512 )
end

function draw()
    background(20,20,40)

    tint( 255,255, 0 ) -- make the image yellow

    sprite( circleImg, WIDTH/2, HEIGHT/2 )
end

An even faster alternative is to make a circle from a triangle fan using the mesh() class. I can post sample code for that, if the above doesn’t work for you.

Thanks Simeon. I incorporated your image code and it renders consistently now. I’m glad you used tinting as well, otherwise I might not have realised I could keep my “flickering random shades of yellow” effect :). Later I’ll probably try using a mesh instead of a plain ellipse to give my sun some detail. Cheers!

Hi Simeon. I would be glad to see the circle ( or ellipse) mesh code. Thanks.

Yes, I’m interested in the circle mesh code as well. I would have thought that a mesh for a circle would be very expensive, but I think I might have a skewed impression of meshes.

The circle mesh code is the ellipse shader, which uses quite a bit of math when drawing, I use a circle texture on a mesh to speed things up

Here is a link to the old circle shader from the time when Codea still had an open source runtime. So it might be something similar.

https://github.com/TwoLivesLeft/Codea-Runtime/blob/master/CodeaTemplate/Codify/Resources/Shaders/CircleShader.fsh

or create a mesh with the convenient triangulate function:

local steps, radius, vs = 100, 100, {}
for i=1,steps do
    local a = i/steps * math.pi * 2
    table.insert(vs, vec2(math.cos(a), math.sin(a)) * radius)
end
m = mesh
m.vertices = triangulate(vs)

Here’s an example using the above code. The circle could be a solid color, but I wanted to show how the circle is made up of the different triangular meshes. I have a random color to show the different meshes. You can change the number of edges by sliding your finger up or down the screen. The more edges, the smoother the circle.


displayMode(FULLSCREEN)

function setup()
    radius=math.min(WIDTH,HEIGHT)/2
    dy=10
    h=0
    m=mesh()
    setup1()
end

function setup1()
    count=0
    tot=0
    vs={}
    steps=math.floor(dy)
    if steps~=h then
        h=steps
        for i=1,steps do
            a = i/steps * math.pi * 2
            table.insert(vs, vec2(math.cos(a), math.sin(a)) * radius)
        end
        m.vertices = triangulate(vs)
        m:setColors(255,255,255)
        for z=1,#m.vertices,3 do
            r=math.random(255)
            g=math.random(255)
            b=math.random(255)
            m:color(z,r,g,b)
            m:color(z+1,r,g,b)
            m:color(z+2,r,g,b)
        end
    end
end

function draw()
    background(40, 40, 50)
    fill(255)
    tot=tot+DeltaTime
    count=count+1
    text("Show edges 3 to 100",100,HEIGHT-100)
    text("Outside edges "..steps,100,HEIGHT-150)
    text("vertices "..#m.vertices,100,HEIGHT-200)
    text("Meshes "..#m.vertices/3,100,HEIGHT-250)

    translate(WIDTH/2,HEIGHT/2)
    m.draw(m)
    translate()
end

function touched(t)
    if t.state==BEGAN or t.state==MOVING then
        dy=dy+(t.deltaY/25)
        if dy<3 then
            dy=3
        elseif dy>100 then
            dy=100
        end
        setup1()
    end
end