speedup the refresh-rate of touched()

Hi folks,

i played with Codea last night and made a pixel drawing app. A problem occured! When moving the finger slow, a continuous line gets drawn, but when moving the finger fast over the screen, only a few pixels on that path gets drawn… the line gets broken up… It feels like the touched() function gets not updated fast enough.

Any ideas how to fix this?

@se24vad - perhaps, rather than colouring the actual touch position, you could draw a line between the last touch position and the current touch position, then you should have no gaps

@Ignatz I already thought about using line() but I think it’s faster to use img:set() Also line() is not very precise in this case - thats my biggest doubt!

could I show the code, maybe a better idea comes to your mind?

function math.round(number, decimals)
    decimals = 10^(decimals or 0)
    return math.floor(number * decimals + .5) / decimals
end

function setup()
    parameter.color("rgba", color(155, 0, 155))
    
    local width, height = 124, 124
    
    canvas = {
        x = 0,
        y = 0,
        width = width,
        height = height,
        zoom = 1,
        img = image(width, height),
        touches = {}
    }
end

function draw()
    noSmooth()
    rectMode(CORNER)
    spriteMode(CORNER)
    
    noFill()
    strokeWidth(1)
    stroke(161, 141, 113, 255)
    background(154, 175, 169, 255)
    
    rect(canvas.x, canvas.y, canvas.width * canvas.zoom, canvas.height * canvas.zoom)
    sprite(canvas.img, canvas.x, canvas.y, canvas.width * canvas.zoom, canvas.height * canvas.zoom)
    
    noStroke()
    fill(rgba)
    rect(0, 0, WIDTH, 40)
end

function touched(touch)
    -- Update touches
    if #canvas.touches > 0 then
        for n in ipairs(canvas.touches) do
            if touch.id == canvas.touches[n].id then
                canvas.touches[n].x = touch.x
                canvas.touches[n].y = touch.y
                canvas.touches[n].deltaX = touch.deltaX
                canvas.touches[n].deltaY = touch.deltaY
                canvas.touches[n].tapCount = touch.tapCount
            end
        end
    end
    
    -- Add touch
    if touch.state == BEGAN then
        if #canvas.touches < 2 then -- Max #touches allowed!
            local n = #canvas.touches + 1
            canvas.touches[n] = {
                id = touch.id,
                initX = touch.x,
                initY = touch.y,
                x = touch.x,
                y = touch.y,
                deltaX = touch.deltaX,
                deltaY = touch.deltaY,
                tapCount = touch.tapCount
            }
            
            if #canvas.touches > 1 then
                onHold = true -- Lock drawing mode when using multitouch
            end
        end
        return
    end
    
    -- Handle touches
    if touch.state ~= BEGAN then
        if touch.id == canvas.touches[1].id then
            if #canvas.touches == 1 and not onHold then
                -- Scale down touches from canvas to img bounds
                local factor = vec2(canvas.width / (canvas.width * canvas.zoom), canvas.height / (canvas.height * canvas.zoom))
                local position = vec2(math.round(canvas.touches[1].x * factor.x - canvas.x * factor.x), math.round(canvas.touches[1].y * factor.y - canvas.y * factor.y))
                
                if canvas.touches[1].tapCount == 1 then
                    canvas.img:set(position.x, position.y, rgba) -- Draw pixel
                elseif canvas.touches[1].tapCount == 2 then
                    canvas.img:set(position.x, position.y, color(0, 0, 0, 0)) -- Delete pixel
                end
            elseif #canvas.touches == 2 then
                local pinch = vec2(canvas.touches[1].x, canvas.touches[1].y):dist(vec2(canvas.touches[2].x, canvas.touches[2].y))
                canvas.zoom = canvas.zoom * pinch / (canvas.pinch or pinch)
                canvas.pinch = pinch -- save measurement
                
                canvas.x = canvas.x + canvas.touches[1].deltaX
                canvas.y = canvas.y + canvas.touches[1].deltaY
            end
        end
    end
    
    -- Remove touch
    if touch.state == ENDED then
        for n in ipairs(canvas.touches) do
            if touch.id == canvas.touches[n].id then
                table.remove(canvas.touches, n)
            end
        end
        if #canvas.touches == 0 then
            onHold = nil
            canvas.pinch = nil
        end
    end
end

Maybe you simply do a loop from the last touch to the current touch, and fill in pixels as you go…

For greater speed, maybe a good idea is to avoid the need to draw to an image in memory by making the screen persistent, ie it remembers previous drawing and doesn’t clear, so you don’t need to keep redrawing previously placed pixels. Then you can simply keep drawing to the screen all the time. You put this line in setup

backingMode(RETAINED)

and you remove the background command from draw…

I need to do it with the image, because I plan to add stuff like animation. Good idea! but what if the user makes a circular motion? then last.touch->current.touch would result in a straight line, which ist just a line() … or am I wrong?

Please, don’t get me wrong! I VERY appreciate your help. I just want not to accept, that there is no other way :slight_smile:

@se24vad - all you have is the touch positions that Codea registers. It tries to do that 60 times a second, but it may slow down if you keep writing to an image in memory, and especially if you add animation, and then your touch positions will be further apart than ever.

Codea can’t tell you which path the finger took between one touch position and the next, so as long as you are getting 60 frames a second, the touches will be close together, and you can probably draw straight lines between them and they will be so close together that it looks like a curve.

So I think speed is very important.

This problem has arisen before, and solutions have been suggested. Try the searchbox above with words like drawing, stuff like that, I’m sure you’ll find some good ideas.

I think there’s a problem with touch that I’ve mentioned before. Run this program and draw a steep sine wave across the screen. Sometimes there will be points missing in the wave. If you do a restart and draw the wave, it’s fine. It doesn’t do it every time so you might have to exit and restart the program to see the missing points.


displayMode(FULLSCREEN)

function setup()
    tab={}
end

function draw()
    background(40, 40, 50)
    fill(255)
    for a,b in pairs(tab) do
        ellipse(b.x,b.y,5)
    end
end

function touched(t)
    if t.state==BEGAN or t.state==MOVING then
        table.insert(tab,vec2(t.x,t.y))
    end
end

@Dave1707 yes there is a tiny glitch in it I’ve noticed but never had it show as clear as it does with your code.

displayMode(FULLSCREEN)

function setup()
    tab={}
    n = 0
end

function draw()
    background(40, 40, 50)
    fill(255)
    for a,b in pairs(tab) do
        ellipse(b.x,b.y,5)
    end
end

function touched(t)
    n = n + 1
    if t.state==BEGAN or t.state==MOVING then
        tab[n] = vec2(t.x,t.y)
    end
end

I tried that and it still happened

@Luatee There are times when I run the program and no points show as I move my finger. If I move a second finger on the screen at the same time, the points will show for the second finger but still not for the first finger. Also,if there are points missing for the first finger, the second finger will also miss points. If the first finger doesn’t miss points, the second one doesn’t either.

Hi Guys,

Just putting a little finding into the mix. I know this is not totally Codea related but, apart from a few minor changes the code is identical. I am playing with loveCodea in Love2D and have a problem with the touch.state in some of my code. When I saw se24vad’s program (top) decided to see if the problem could be replicated with his program. Short answer yes. This may have some bearing on your own observations.

I added three lines to the code:

Hittype = “STARTED”
watch(“Hittype”)

Both above in the setup. Then

Hittype = touch.state

Latter in the function touched(touch). What I see is a number returned for the Hittype of 2 for the MOVING touch state and 4 for the ENDED. This is repeatable.

However it depends on the code involved - some code operates as expected and other code does not respond to touch at all. My other code operates with a class touched function. What I wondered is if the touch.state is held in a global variable i.e. MOVING = 2 and if the code can sometimes look at the value rather than the variable itself. IF you test for “MOVING” it will fail with “2”.

loveCodea is a wrapper written in Lua, my problem is most likely to do with the Touch code in the wrapper itself - just throwing in the idea that the touch.state may not always be in the MOVING/BEGIN/ENDED states we usually expect.

Oh, and if there is anyone familiar with loveCodea that has encountered this problem - how do you resolve it?

Thanks.

Bri_G

:smiley: