setContext() Limit [RESOLVED]

Hello everybody !

I want to know what’s limit of setContext() function. Because after some call, generated sprites are empty =/

Post some code, please, so we can see what is happening

supportedOrientations(LANDSCAPE_ANY)
displayMode(FULLSCREEN)
    
CURRENT_STATE = nil

function setup()    
    --setCurrentState(MadeWithCodea())
    --setCurrentState(IntroCodea())
    setCurrentState(MainMenu())
end

function draw()
    
    -- States : Intro, MenuPrincipal, NouvellePartie, InGame, Options
    
    background(0, 0, 0, 255)
    noFill()
    stroke(255, 255, 255, 255)
    strokeWidth(5)
    
    if CURRENT_STATE == nil then
        return
    end
    
    CURRENT_STATE:draw()
    if CURRENT_STATE:isEnded() then
        CURRENT_STATE:ended()
    end

end

function setCurrentState(state, start)
    CURRENT_STATE = state
    if start == nil or start then
        state:start()
    end
end

function sleep(time, func)
    tween(time, {}, {}, nil, func)
end

Sprite = class()

function Sprite.makeSprite(func,w,h)
    local img = image(w,h)
    
    setContext(img)
    func()
    setContext()
    
    saveImage("Documents:AAA", img)
    
    return img
end

function Sprite.drawTextSprite(str,args,getCoords)
    local fontA = args.font or "HelveticaNeue-CondensedBold"
    local size = args.fontSize or 80
    local fillA = args.fill or color(255, 255, 255, 255)
    local textModeA = args.textMode or CORNER
    local textWrap = args.textWrapWidth or -1
    local align = args.textAlign or LEFT
    smooth()
    font(fontA)
    fontSize(size)
    fill(fillA)
    textMode(textModeA)
    textWrapWidth(textWrap)
    textAlign(align)
    if not getCoords then text(str,0,0)
    else return textSize(str) end
end

function Sprite.makeTextSprite(str,args)
    local w,h = Sprite.drawTextSprite(str,args,true)
    local f = function() Sprite.drawTextSprite(str,args) end
    return Sprite.makeSprite(f,w,h)
end

Mesh = class()

function Mesh:init(pmesh, args)
    if args == nil then
        args = {}
    end
    
    self.mode = args.mode or CENTER
    self.mesh = pmesh
    self.dim = {}
    self.dim.w, self.dim.h = args.width, args.height
    self.pos = {}
    self.pos.x = args.x or WIDTH/2
    self.pos.y = args.y or HEIGHT/2
    self.pos.z = args.z or 5
    
    self.angle = {}
    self.angle.x = 0
    self.angle.y = 0
    self.angle.z = 0
    
end

function Mesh:draw()
    pushMatrix()
    rotate(self.angle.x, 1,0,0)
    rotate(self.angle.y, 0,1,0)
    rotate(self.angle.z, 0,0,1)
    if self.mode == CENTER then
        translate(self.pos.x - (self.dim.w/2), self.pos.y - (self.dim.h/2), self.pos.z)
    elseif CORNER then
        translate(self.pos.x, self.pos.y, self.pos.z)
    end
    self.mesh:draw()
    popMatrix()
end

function Mesh.makeMesh(spr, args)
    
    if args == nil then
        args = {}
    end
    
    local w,h = spriteSize(spr)
    w = args.width or w
    h = args.height or h
    local myMesh = mesh()
    myMesh.vertices = {vec3(0,0,0),vec3(w,0,0),vec3(w,h,0),vec3(0,0,0),vec3(0,h,0),vec3(w,h,0)}
    myMesh.texCoords = {vec2(0,0),vec2(1,0), vec2(1,1), vec2(0,0),vec2(0,1), vec2(1,1)}
    
    if args.color then
        myMesh:setColors(args.color.r,args.color.g,args.color.b,args.color.a)
    end
    myMesh.texture = spr
    
    return Mesh(myMesh, {width=w, height=h})
end

function Mesh.makeTextMesh(str, args)
    local spr = Sprite.makeTextSprite(str,args)
    
    local w,h = spriteSize(spr)
    local myMesh = mesh()
    myMesh.vertices = {vec3(0,0,0),vec3(w,0,0),vec3(w,h,0),vec3(0,0,0),vec3(0,h,0),vec3(w,h,0)}
    myMesh.texCoords = {vec2(0,0),vec2(1,0), vec2(1,1), vec2(0,0),vec2(0,1), vec2(1,1)}
    
    --local fillA = args.fill or color(255, 255, 255, 255)
    --myMesh:setColors(fillA.r, fillA.g, fillA.b, fillA.a)
    myMesh.texture = spr
    
    return Mesh(myMesh, {width=w, height=h})
end



Screen = class()

function Screen:init(name)
    
    self.name = name
    
    self.x = 0
    self.y = 0
    self.z = -900
    self.eyeX = WIDTH/2
    self.eyeY = HEIGHT/2
    self.eyeZ = 150
    self.lookAtX = WIDTH/2
    self.lookAtY = HEIGHT/2
    self.lookAtZ = 0
    self.angle = 0
    self.fieldOfView = 40
    
    --[[
    parameter.number("X",-500,1000,self.x)
    parameter.number("Y",-500,500,self.y)
    parameter.number("Z",-500,1000,self.z)
    
    parameter.number("EyeX", -1000, 1000, self.eyeX)
    parameter.number("EyeY", -1000, 1000, self.eyeY)
    parameter.number("EyeZ", -1000, 1000, self.eyeZ)
    
    parameter.number("LookAtX", -1000, 1000, self.lookAtX)
    parameter.number("LookAtY", -1000, 1000, self.lookAtY)
    parameter.number("LookAtZ", -1000, 1000, self.lookAtZ)
    
    parameter.number("Angle",-360, 360, self.angle)
    parameter.number("FieldOfView", -140, 140, self.fieldOfView)
    ]]--
    
    self.meshes = {}
    self.backgroundColor = color(255, 255, 255, 255)
end

function Screen:start() end

function Screen:draw()
    
    table.sort(self.meshes, function(a, b)
        return a.pos.z < b.pos.z
    end)
    
    pushMatrix()
    pushStyle()
    
    perspective(self.fieldOfView, WIDTH/HEIGHT)
    camera(self.eyeX,self.eyeY,self.eyeZ, self.lookAtX,self.lookAtY,self.lookAtZ, 0,1,0)
    
    translate(self.x, self.y, self.z)
    rotate(self.angle, 0, 1, 0)
    
    fill(self.backgroundColor)
    rect(0,0,WIDTH,HEIGHT)
    
    for k,v in pairs(self.meshes) do
        v:draw()
    end
    
    popStyle()
    popMatrix()
end


function Screen:isEnded()
    return false
end
function Screen:ended() end

function Screen:touched(touch) end

ScreenTransition = class(Screen)

function ScreenTransition:init(name, screenFrom, screenTo)
    Screen.init(self, name)
    self.screenFrom = screenFrom
    self.screenTo = screenTo
end
function ScreenTransition:start() end
function ScreenTransition:draw()
    self.screenFrom:draw()
    self.screenTo:draw()
    if self:isEnded() then
        self:ended()
    end
end
function ScreenTransition:isEnded() end
function ScreenTransition:ended()
    setCurrentState(self.screenTo)
end

MiniatureToRight = class(ScreenTransition)

function MiniatureToRight:init(screenFrom, screenTo)
    ScreenTransition.init(self, "MiniatureToRight", screenFrom, screenTo)
    self.isended = false
end

function MiniatureToRight:start()
    self.screenTo.x = WIDTH
    self.screenTo.z = -1200
    
    sleep(2, function()
        tween(2, self.screenFrom, {z=-1200}, tween.easing.bounceOut,
        function()
            local easing = tween.easing.quadInOut
            tween(2, self.screenFrom, {x=-WIDTH}, easing)
            tween(2, self.screenTo, {x=0}, easing,
            function()
                tween(2, self.screenTo, {z=-900}, nil,
                function()
                    self.isended = true
                end)
            end)
        end)
    end)
end

function MiniatureToRight:isEnded()
    return self.isended
end


MadeWithCodea = class(Screen)

function MadeWithCodea:init()
    Screen.init(self, "MadeWithCodea")
    self.background = Mesh.makeMesh(readImage("Documents:madeWithCodea"))
    self.meshes = {self.background}
end

function MadeWithCodea:start()
    setCurrentState(MiniatureToRight(self, IntroCodea()))
end


IntroCodea = class(Screen)

function IntroCodea:init()
    Screen.init(self, "IntroCodea")
    
    --[[
    local txt = "Connect4_3D_3P is a game of french students.\
"..
    "It's a connect four in a line in 3D for 3 players.\
"..
    "The concept is : \"Help the player who want to watch you lose\""
    ]]--
    --[[
    local txt = "Ce jeu a été entierement developpé avec Codea par Hyro Vitaly Protago.\
" ..
    "Les concepteurs sont : \
\\t- Robin Lasne, \
\\t- Léo ..., \
\\t-..."
    ]]--
    
    local txt = "Ce jeu a été entierement developpé avec Codea : un IDE sur Ipad pour programmer en lua.\
" ..
        ""
    
    self.infoPanel = Mesh.makeMesh(readImage("Cargo Bot:About Info Panel"), {color=color(0,0,0,255), width=WIDTH})
    self.infoPanel.pos.x = WIDTH/2
    self.infoPanel.pos.y = HEIGHT + self.infoPanel.dim.h/2
    self.infoPanel.pos.z = 5
    
    self.meshIntroText = Mesh.makeTextMesh(txt,{fontSize=25, textWrapWidth=WIDTH/1.1, textAlign=CENTER})
    self.meshIntroText.pos.x = WIDTH/2
    self.meshIntroText.pos.y = HEIGHT - self.infoPanel.dim.h/1.25 + self.meshIntroText.dim.h/2
    self.meshIntroText.pos.z = 10
    
    self.codeaIcon = Mesh.makeMesh(readImage("Cargo Bot:Codea Icon"))
    self.codeaIcon.pos.x = WIDTH/2
    self.codeaIcon.pos.y = HEIGHT/3
    self.codeaIcon.pos.z = 5
    
    self.madeWithCodea = Mesh.makeMesh(readImage("Cargo Bot:Made With Codea"), {color=color(0,0,0,255)})
    self.madeWithCodea.pos.x = WIDTH - self.madeWithCodea.dim.w/1.8
    self.madeWithCodea.pos.y = self.madeWithCodea.dim.h/1.25
    self.madeWithCodea.pos.z = 5
    
    self.meshes = {self.infoPanel, self.meshIntroText, self.codeaIcon, self.madeWithCodea}
    --[[
    table.sort(self.meshes, function(a, b)
        return a.pos.z < b.pos.z
    end)
    ]]--
    --self.infoPanel.mesh.shader = shader("Effects:Ripple")
    --self.infoPanel.mesh.shader.freq = 0.4
end

function IntroCodea:start()
    --box = { x = -150}
    --id = tween(2, self, {ycache = HEIGHT, alpha = 0})
    --local h = 
    --tween(4, self.madeWithCodea.angle, {z=360})
    id = tween(2, self.infoPanel.pos, {y = HEIGHT - self.infoPanel.dim.h/1.25}, tween.easing.bounceOut,
    function()
        sleep(3, function()
            setCurrentState(MiniatureToRight(self, MainMenu()))
        end)
    end)
    
    --tween.stop(id)
    
    -- 10 - 15s
end

function IntroCodea:draw()
    --meshIntroText = self.meshIntroText
    --self.infoPanel.mesh.shader.time = ElapsedTime
    Screen.draw(self)
end

function IntroCodea:isEnded()
end

function IntroCodea:ended()
end


MainMenu = class(Screen)

function MainMenu:init()
    Screen.init(self, "MainMenu")
    
    local txt = "Nouvelle Partie"
    self.newGame = Mesh.makeTextMesh(txt,{fill=color(0,0,0,255), fontSize=50, textWrapWidth=WIDTH/1.1, textAlign=CENTER})
    self.newGame.pos.x = WIDTH/2
    self.newGame.pos.y = HEIGHT/2 -- - self.newGame.dim.h*3
    --self.newGame.pos.z = 100
    table.insert(self.meshes, self.newGame)

end

function MainMenu:start()
    sleep(3, function()
        setCurrentState(MiniatureToRight(self, IntroCodea()))
    end)
end

@Ignatz, i expect you could help me, thanks before :wink:

The issue isn’t setContext, the issue is you construct your screen effectively after the draw loop for subsequent screens. The reason this doesn’t work is that when you are building the sprite your camera and perspective have already been applied and break it.

Modify your Screen:draw() function adding viewMatrix(matrix()) and ortho() as below and it works.


function Screen:draw()

    table.sort(self.meshes, function(a, b)
        return a.pos.z < b.pos.z
    end)

    pushMatrix()
    pushStyle()

    perspective(self.fieldOfView, WIDTH/HEIGHT)
    camera(self.eyeX,self.eyeY,self.eyeZ, self.lookAtX,self.lookAtY,self.lookAtZ, 0,1,0)

    translate(self.x, self.y, self.z)
    rotate(self.angle, 0, 1, 0)

    fill(self.backgroundColor)
    rect(0,0,WIDTH,HEIGHT)

    for k,v in pairs(self.meshes) do
        v:draw()
    end

    viewMatrix(matrix())
    ortho()
    popStyle()
    popMatrix()
end

PS. Really nice effect

@spacemonkey thanks a lot :wink:

Yes, very nice!