Crate Rotate: an experiment with RotationRate (Codea 1.5)

RotationRate is a new feature in Codea version 1.5, for iPad 2s and above. The code below is based on code where @Andrew_Stacey assisted greatly with the coding of the mathematics of the rotation.


--
-- Crate Rotate
-- For Codea 1.5 (or above)
--

supportedOrientations(LANDSCAPE_LEFT)
function setup()
    if deviceMetrics().platformName == "iPad 1G" then
        print("This code needs a gyroscope."..
            " An iPad 1 does not have one.")
    else
        print("Rotate the Viewer about the crate.")
    end
    local size = math.min(HEIGHT, WIDTH) / 2
    d = size * 3
    m = cubeMesh(size)
    dirz = vec3(0, 0, 1)
    diry = vec3(0, 1, 0)
    dirx = vec3(1, 0, 0)
    fill(255)
end

function draw()
    background(0)
    perspective()
    local mat = matrix()
    local dxa = RotationRate.x
    local dya = RotationRate.y
    local dza = RotationRate.z
    mat = mat:rotate(dza, dirz.x, dirz.y, dirz.z)
    mat = mat:rotate(dya, diry.x, diry.y, diry.z)
    mat = mat:rotate(dxa, dirx.x, dirx.y, dirx.z)
    dirx = mult(mat, dirx)
    diry = mult(mat, diry)
    dirz = mult(mat, dirz)
    local x = dirz.x * d
    local y = dirz.y * d
    local z = dirz.z * d
    camera(x, y, z, 0, 0, 0, diry.x, diry.y, diry.z)
    m:draw()
end

function cubeMesh(size)
    local v = {}
    for i = 0, 7 do
        local x = (i % 2) * 2 - 1
        local y = (math.floor(i / 2) % 2) * 2 - 1
        local z = (math.floor(i / 4) % 2) * 2 - 1
        v[i] = vec3(x, y, z) * size / 2
    end
    local ver = {}
    for v1 = 1, 3 do
        local v2 = v1 * 3 % 7
        local v3 = 7 - v1
        local v4 = 7 - v2
        local vt = {v[0], v[v1], v[v2],
            v[0], v[v3], v[v4], 
            v[7], v[v2], v[v1],
            v[7], v[v4], v[v3]}
        for i = 1, #vt do
            ver[(v1 - 1) * #vt + i] = vt[i]
        end
    end
    local uv = {
        vec2(0.5, 0), vec2(0, 0), vec2(0, 0.5),
        vec2(0.5, 0), vec2(1, 0.5), vec2(1, 0),
        vec2(0.5, 0.5), vec2(1, 0.5), vec2(1, 0),
        vec2(0.5, 0.5), vec2(0, 0), vec2(0, 0.5),            
        vec2(0.5, 0), vec2(0.5, 0.5), vec2(1, 0.5),
        vec2(0.5, 0.5), vec2(1, 1), vec2(1, 0.5),
        vec2(0.5, 0.5), vec2(0, 0.5), vec2(0, 1),
        vec2(0.5, 0.5), vec2(1, 0), vec2(0.5, 0),        
        vec2(0.5, 0), vec2(0, 0.5), vec2(0.5, 0.5),
        vec2(0.5, 0.5), vec2(0.5, 1), vec2(1, 1),
        vec2(0.5, 0.5), vec2(0, 1), vec2(0.5, 1),
        vec2(0.5, 0.5), vec2(0.5, 0), vec2(0, 0)}
    local m = mesh()
    m.texture = texture()
    m.vertices = ver
    m.texCoords = uv
    return m
end

function texture()
    local img = image(214, 214)
    pushStyle()
    pushMatrix()
    resetStyle()
    resetMatrix()
    setContext(img)
    background(45, 11, 23)
    textAlign(CENTER)
    spriteMode(CORNER)
    sprite("Cargo Bot:Title Large Crate 2", 1, 1)
    sprite("Cargo Bot:Title Large Crate 2", 108, 1)
    sprite("Cargo Bot:Title Large Crate 1", 1, 108)
    sprite("Cargo Bot:Title Large Crate 1", 108, 108)
    fill(201, 186, 25)
    text("THIS\
WAY\
UP", 53, 53)
    text("USE\
NO\
HOOKS", 160, 53)
    text("THIS\
SIDE\
UP", 53, 160)
    text("OTHER\
SIDE\
UP", 160, 160)
    setContext()
    popStyle()
    popMatrix()
    return img
end

function mult(mat, vec)
    local v1 = mat[1] * vec.x + mat[5] * vec.y + mat[9]  * vec.z
    local v2 = mat[2] * vec.x + mat[6] * vec.y + mat[10] * vec.z  
    local v3 = mat[3] * vec.x + mat[7] * vec.y + mat[11] * vec.z
    return vec3(v1, v2, v3)    
end

I love the text render-to-texture you’ve done to customise the crate. That’s a really cool demo.