Rotating Rectangles

Based on a seminar I went to yesterday.

displayMode(FULLSCREEN)
function setup()

    local n = {2,3}
    local picture = "Documents:Snowman" -- REPLACE THIS LINE
    meshes = {}
    pics = {}
    nmeshes = 0
    local w = math.min(WIDTH,HEIGHT)
    if w == WIDTH then
        ox,oy = 0,(HEIGHT-WIDTH)/2
    else
        ox,oy = (WIDTH-HEIGHT)/2,0
    end
    local ver,tex,l,img,m
    for _,v in ipairs(n) do
        m = mesh()
        table.insert(meshes,m)
        local img = image(w,w)
        table.insert(pics,img)
        m.texture = img
        nmeshes = nmeshes + 1
        ver = {}
        tex = {}
        l = w/v
        for i=1,v do
            for j=1,v do
                for _,u in ipairs({
                        {1,1,1,0},
                        {1,0,0,0},
                        {0,0,0,1},
                        {1,1,1,0},
                        {0,0,0,1},
                        {0,1,1,1}
                        }) do
                    table.insert(ver,vec2((i-u[1])*l,(j-u[2])*l))
                    table.insert(tex,vec2((i-u[3])/v,(j-u[4])/v))
                end
            end
        end
        m.vertices = ver
        m.texCoords = tex
        m:setColors(255,255,255,255)
    end
    cmesh = 0
    m = mesh()
    img = image(w,w)
    m.texture = img
    m:addRect(w/2,w/2,w,w)
    m:setRectTex(1,0,0,1,1)
    meshes[0] = m
    setContext(img)
        background(255, 255, 255, 255)
        noSmooth()
        sprite(picture,w/2,w/2)
    setContext()
    stime = ElapsedTime
end

function draw()
    background(51, 51, 51, 255)
    pushMatrix()
    translate(ox,oy)
    meshes[cmesh]:draw()
    popMatrix()
    if auto then
        if ElapsedTime - stime > 1 then
            nextmesh()
        end
    end
end

function touched(touch)
    if touch.state == ENDED then
        if touch.tapCount == 2 then
            auto = not auto
        else
            nextmesh()
        end
    end
end

function nextmesh()
    local n = cmesh
    cmesh = cmesh%nmeshes + 1
    setContext(pics[cmesh])
        resetMatrix()
        noSmooth()
        background(255, 255, 255, 255)
        meshes[n]:draw()
    setContext()
    stime = ElapsedTime
end

The image is chopped up into a grid of squares which are then rotated 90 degrees anticlockwise (I think!). This process repeats itself, but as it does so then it cycles through a list of different sized grids. The default is to alternate between a grid of size 2 and of size 3. You can manually advance the process by tapping the screen, or set it to auto by double tapping.

It works by setting the texture of each mesh to the result of rendering the previous one. But then the rectangles in each mesh are pre-rotated so when a mesh is drawn it does the necessary rotation.

http://www.youtube.com/watch?v=1HH8SBS4ZbE

Interesting. In working through how your code worked, I simplified parts of it, as follows. (Update) I have added the slices array to reintroduce the flexibility in Andrew’s original code. (Further update) I have applied the edge effects correction.


displayMode(FULLSCREEN)
function setup()
    slices = {1, 3, 5}
    local picture = myPict(slices) -- Replace with code for image
    noSmooth()
    meshes, pics = {}, {}
    local dim = math.min(WIDTH, HEIGHT)
    -- Edge effects correction to dim:
    local sn = slices[2] * slices[3]
    dim = math.floor(dim / sn) * sn
    ox, oy = (WIDTH - dim) / 2, (HEIGHT - dim) / 2
    for mn = 1, 3 do
        local m = mesh()
        local img = image(dim, dim)
        meshes[mn - 1] = m
        pics[mn - 1] = img
        m.texture = img
        local n = slices[mn]
        local l = dim / n
        local r = math.pi / 2
        if mn == 1 then
            r = 0
            setContext(img)
            background(255)
            sprite(picture, dim / 2, dim / 2)
            setContext()
        end
        for i = 0, n - 1 do
            for j = 0, n - 1 do
                local cx, cy = (i + 0.5) * l, (j + 0.5) * l
                local idx = m:addRect(cx, cy, l, l, r)
                local tx, ty = i / n, j / n
                m:setRectTex(idx, tx, ty, 1 / n, 1 / n)
            end
        end
    end
    nmeshes = #meshes
    cmesh = 0
    stime = ElapsedTime
end

function draw()
    background(0)
    translate(ox, oy)
    meshes[cmesh]:draw()
    if auto and ElapsedTime - stime > 1 then nextmesh() end
end

function touched(touch)
    if touch.state == ENDED then
        if touch.tapCount == 2 then
            auto = not auto
        else
            nextmesh()
        end
    end
end

function nextmesh()
    local n = cmesh
    cmesh = cmesh % nmeshes + 1
    setContext(pics[cmesh])
    resetMatrix()
    background(255)
    meshes[n]:draw()
    setContext()
    stime = ElapsedTime
end

and I used the following image to follow the movement of the parts of the image. (Update) Faster version.


function myPict(slices)
    local n = slices[2] * slices[3]
    local dim = math.min(WIDTH, HEIGHT)
    -- Edge effects correction to dim:
    dim = math.floor(dim / n) * n
    local img = image(dim, dim)
    local w = dim / n
    -- Improved sizing of numbering:
    fontSize(1152 / n / (math.floor(math.log10(n * n)) + 1))
    rectMode(CORNER)
    setContext(img)
    for j = 0, n - 1 do
        for i = 0, n - 1 do
            local rn = n * j + i + 1
            local c = H2RGB(rn / (n * n))
            fill(c)
            rect(i * w + 1, j * w + 1, w, w)
            fill(255)
            text(rn, i * w + w/2, j * w + w/2)
        end
    end
    setContext()
    return img
end

-- Hue (nil or [0, 1)) to RGB; (S = 1, V = 1)
function H2RGB(h)
    local r, g, b = 0, 0, 0
    local i = h * 6
    local x = (1 - math.abs(i % 2 - 1))
    if i < 1 then r, g = 1, x
    elseif i < 2 then r, g = x, 1
    elseif i < 3 then g, b = 1, x
    elseif i < 4 then g, b = x, 1
    elseif i < 5 then r, b = x, 1
    else r, b = 1, x end
    return color(255 * r, 255 * g, 255 * b)
end

Ah, I forgot about rotations in addRect. Useful.

The choice of pairs 2,3 was arbitrary. I’m told that successive Fibonnacci numbers make good choices. Also, there are edge effects - I’ll post an update that fixes those soon.

I think I see what you mean by edge effects - when I cycle through {3, 5} something is lost by the time the end state returns to the origin. (Update) I solved it by forcing the dimension of the picture and the mesh to be an integral multiple of the product of the size of the two ‘slices’.

That was my solution too.