Advise me, please. zLevel does odd things.

I have a function that draws a bunch of objects. Looks like this:

function DungeonContentsCollection:draw()
    pushMatrix()
    pushStyle()
    for tile,entries in pairs(self:drawingOrder()) do
        if tile:isVisible() then
            local gc = tile:graphicCenter()
            for i,object in ipairs(entries) do
                zLevel(5) -- breaks visibility??
                spriteMode(CENTER)
                object:draw(false, gc)
            end
        end
    end
    popStyle()
    popMatrix()
end

When the zLevel is in there, objects drawn in the loop sometimes show up and sometimes do not, depending on how the Player moves around near them. There is no obvious pattern, but it seems that if it ever appears while player is on a given tile, it will always appear, and vice versa. So it’s not random with moves, but dependent on where you move.

There is no other call to zLevel in the whole program.

I can do without the call, because I am (finally) drawing in increasing z-level order, but what the heck could possibly be going on that could do this? Unless zLevel is well and truly borked?

Ideas solicited. Thanks!

@RonJeffries okay I’m a little bit majorly out of my depth here, but I do know that the draw() function has some pecadilloes when it comes to combining 2D concepts and 3D concepts, and if I remember correctly it actually renders one before the other, so if you call something that requires 3D rendering (which I guess would be mesh rendering?) at the wrong time, it won’t interact properly with your 2D renders. Maybe partial and badly-remembered information is worse than no information at all, but at least it may be a hint that the anatomy of a draw cycle is not as straightforward as it might seem…

this is all 2d, sprites mostly.

@RonJeffries its not related to the alpha bug? https://codea.io/talk/discussion/11281/zlevel-limit-is-10

i don’t see how it could be. i think zlevel is screwy somehow

maybe try putting your pop and push inside the for loop

@RonJeffries Is this something like what you’re running into. Move the ship slider so the space ship overlays the other objects. The ship has the yellow square around it covering up the other 2. If you slide the others one around, those don’t have the square background.

Then uncomment the second setup and draw code. I reversed the ship and ufo. Now the ufo has the square background covering the others as you slide the parameter and the others don’t. So I’m not sure what’s causing this.

function setup()
    img = {}
    img[1] = readImage(asset.builtin.Space_Art.Red_Ship)
    img[2] = readImage(asset.builtin.Space_Art.Asteroid_Large)
    img[3] = readImage(asset.builtin.Space_Art.UFO)
    parameter.integer("ship", -10, 10, -3)
    parameter.integer("asteroid", -10, 10, 0)
    parameter.integer("ufo", -10, 10, 3)
    rectMode(CENTER)
end

function draw()
    background(255, 230, 0,0)
    translate(WIDTH/2, HEIGHT/2)
    zLevel(0)
    z = 0 -- Keep track of z level
    fill(37, 235, 22)
    imgZ = {ship, asteroid, ufo}
    scale(3, 3)
    for i = 1, #img do
        local dz = imgZ[i] - z
        zLevel(dz)
        z = z + dz -- Keep track of z level
        sprite(img[i], i * 20 - 40, 0)
    end
end

--[[
function setup()
    img = {}
    img[1] = readImage(asset.builtin.Space_Art.UFO)
    img[2] = readImage(asset.builtin.Space_Art.Asteroid_Large)
    img[3] = readImage(asset.builtin.Space_Art.Red_Ship)
    parameter.integer("ufo", -10, 10, -3)
    parameter.integer("asteroid", -10, 10, 0)
    parameter.integer("ship", -10, 10, 3)
    rectMode(CENTER)
end

function draw()
    background(255, 230, 0,0)
    translate(WIDTH/2, HEIGHT/2)
    zLevel(0)
    z = 0 -- Keep track of z level
    fill(37, 235, 22)
    imgZ = {ufo, asteroid, ship}
    scale(3, 3)
    for i = 1, #img do
        local dz = imgZ[i] - z
        zLevel(dz)
        z = z + dz -- Keep track of z level
        sprite(img[i], i * 20 - 40, 0)
    end
end
--]]

hi dave … mine is not a coverage thing. objects disappear when there’s nothing near them. and it’s the only zlevel call anywhere.

@skar can’t hurt, might try it.

@skar push pop changes it but weirdly. i find that setting zlevel in lots of places an make it work, but so does setting it nowhere,

@Simeon are you sure zlevel is saved / restored properly by push/popmatrix? this almost looks like it’s sticky, or additive or something.

not urgent: i’m just curious to figure out how a single zlevel call could make things appear/disappear when nothing else is near them.

Hi all,
Off the wall a bit but could this be related to blending mode, something in the depths of my cranium says I’ve seen something similar - but, as usual I can’t find it.

not doing anything with blending mode.

@RonJeffries I was playing around with the below code similar to yours above. What I see is that zLevel looks like it’s additive. Each time thru the loop, the value for zLevel gets added to itself. Once the zLevel is above 10 or below -10, anything drawn at the level disappears. Slide the level slider and watch the tot value that is displayed. When a tot value corresponding to a zLevel vale exceeds 10 or below -10 that draw doesn’t show.

function setup()
    fill(255)
    parameter.integer("level",-11,11,0)
    tab={   asset.builtin.Space_Art.UFO,
            asset.builtin.Space_Art.Red_Ship,
            asset.builtin.Space_Art.Asteroid_Large,
            asset.builtin.Space_Art.Icon
        }
end

function draw()
    background(0)
    tot=0
    for a,b in pairs(tab) do
        zLevel(level)
        sprite(b,WIDTH/2+a*50,HEIGHT/2)
        tot=tot+level
        text(tot,WIDTH/2,HEIGHT-100-a*20)
    end
end

@RonJeffries Apparently you can control the zLevel by subtracting the value in the loop.
So you can subtract values to keep sprites from disappearing.

function setup()
    fill(255)
    parameter.integer("level",-11,11,0)
    tab={   asset.builtin.Space_Art.UFO,
        asset.builtin.Space_Art.Red_Ship,
        asset.builtin.Space_Art.Asteroid_Large,
        asset.builtin.Space_Art.Icon
    }
end

function draw()
    background(0)
    for a,b in pairs(tab) do
        zLevel(level)
        sprite(b,WIDTH/2+a*50,HEIGHT/2)
        zLevel(-level)
    end
end

You’re right, zLevel adds rather than setting. i think this version of your demo shows it better.

@Simeon i think this is a clear bug: subsequent calls to zLevel add to the level rather than replace it.

well spotted, @dave1707 !

function setup()
    fill(255)
    parameter.integer("level",-11,11,0)
    tab={   asset.builtin.Space_Art.UFO,
        asset.builtin.Space_Art.Red_Ship,
        asset.builtin.Space_Art.Asteroid_Large,
        asset.builtin.Space_Art.Icon
    }
end

function draw()
    background(0)
    tot=0
    pushMatrix()
    for a,b in pairs(tab) do
        zLevel(level)
        --sprite(b,WIDTH/2+a*50,HEIGHT/2)
        text(""..a, WIDTH/2+a*50, HEIGHT/2)
        tot=tot+level
        text(tot,WIDTH/2,HEIGHT-100-a*20)
    end
    popMatrix()
end


yes, the subtract should work. still a bug.

i can imagine concern that fixing this bug would break things, but i think that’s unlikely. if i were to use it now i’d be like:

zLevel(n)
draw ...
zLevel(-n)
zLevel(0)

that should work, and would survive the correction.

@RonJeffries @Simeon - wouldn’t it be better to make it more explicit by adding z-level to the sprite command. Are vector drawings also z-level dependent, if so you could retain z-level as a command to specify it. Also, if you can specify z-level you could add it to setContext() call to restrict output.

@RonJeffries The zLevel(0) you show above doesn’t do anything. It just adds 0 to whatever value zLevel currently is. It seems like zLevel is 0 when draw starts and changes by whatever value you set zLevel to until you exit draw. That means any functions called from within draw that use zLevel will add to or subtract from the zLevel value.

@RonJeffries You can use a function like the one below to set your zlevel values. Put currZlevel=0 at the beginning of draw() and then call setZlevel(zLevel) any time you want to change the zLevel. It determines what value it needs to add or subtract so you get the correct zLevel. I haven’t tried it, but I think it should work.

function setZlevel(z)
    zLevel(z-currZlevel)
    currZlevel=z
end