Low FPS with Vega's Button Class

does any one else experience low fps when using @Vega’s mesh button class. If I have six buttons the fps drop by 10. Any fix to this?
it drops even more when I add in a physics object.

I need to work on a fix. The problem is with calling recolor() every frame, which was not a brilliant plan. It actually should only be called once initially, then when touch begins, then when touch ends. I will work on it later today when I have time. Thanks for reminding me.

Ok, that was actually an easy fix. I just added a few recolor() calls and killed the one in the draw function. Here is the updated source:

--Much faster version of button class by Vega
button = class()
function button:init(text,location,width,height)
    self.state = "normal"
    self.text = text
    self.textColor = color(255,255,255,192)
    self.location = location
    self.width = width
    self.height = height
    self.visible = true
    self.fontSize = 28
    self.font = "ArialRoundedMTBold"
    self.color1 = color(255, 255, 255, 96)
    self.color2 = color(128,128,128,32)
    self.presscolor1 = color(192, 224, 224, 128)
    self.presscolor2 = color(96, 192, 224, 128)
    self.verts = self:createVerts(self.width, self.height)
    self.myMesh = mesh()
    self.myMesh.vertices = triangulate(self.verts)
    self.vertColor = {}
    self:recolor()
end
function button:setColors(c1,c2,p1,p2)
    self.color1 = c1
    self.color2 = c2
    self.presscolor1 = p1
    self.presscolor2 = p2
    self:recolor()
end
function button:textOptions(fn, sz, col)
    self.font = fn
    self.fontSize = sz
    self.textColor = col
end
function button:draw()
    if self.visible == true then
        pushMatrix()
        translate(self.location.x,self.location.y)
        self.myMesh:draw()
        fill(self.textColor)
        fontSize(self.fontSize)
        font(self.font)
        text(self.text, self.width/2,self.height/2)
        self:drawLines(self.verts)
        popMatrix()
    end
end
function button:touched(touch)
    if self.visible then
        if touch.x >= self.location.x and touch.x <= self.location.x + self.width and touch.y >= self.location.y and touch.y <= self.location.y + self.height then
            if touch.state == BEGAN then
                self.state = "pressing"
                self:recolor()
            elseif touch.state == ENDED then
                if self.state == "pressing" then
                    self.state = "normal"
                    self:recolor()
                    print "pressed."
                end
            end
        else
            self.state = "normal"
            self:recolor()
        end
    end
end
function button:createVerts(w,h)
    local r
    local v = {}
    if w > 100 or h > 100 then
        if w>=h then r = round(h/100) else r = round(w/100) end
    else
        r = 1
    end
    v[1] = vec2(w,6*r)
    v[2] = vec2(w-r,4*r)
    v[3] = vec2(w-2*r,2*r)
    v[4] = vec2(w-4*r,r)
    v[5] = vec2(w-6*r,0)
    v[6] = vec2(6*r,0)
    v[7] = vec2(4*r,r)
    v[8] = vec2(2*r,2*r)
    v[9] = vec2(r,4*r)
    v[10] = vec2(0,6*r)
    v[11] = vec2(0,h-6*r)
    v[12] = vec2(r,h-4*r)
    v[13] = vec2(2*r,h-2*r)
    v[14] = vec2(4*r,h-r)
    v[15] = vec2(6*r,h)
    v[16] = vec2(w-6*r,h)
    v[17] = vec2(w-4*r,h-r)
    v[18] = vec2(w-2*r,h-2*r)
    v[19] = vec2(w-r,h-4*r)
    v[20] = vec2(w,h-6*r)
    return v
end
function button:drawLines(v)
    noSmooth()
    strokeWidth(1)
    stroke(0, 0, 0, 192)
    for i=1, #v-1 do
        line(v[i].x,v[i].y,v[i+1].x,v[i+1].y)
    end
    line(v[#v].x,v[#v].y,v[1].x,v[1].y)   
end
function button:recolor()
    local lt, dk
    if self.state == "normal" then 
        lt = self.color1
        dk = self.color2
    else
        lt = self.presscolor1
        dk = self.presscolor2
    end
    for i=1,3 * #self.verts - 6 do
        if self.myMesh.vertices[i].y > self.height/2 then
            self.vertColor[i] = lt
        else
            self.vertColor[i] = dk
        end
    end
    self.myMesh.colors = self.vertColor
end
function round(v)
    return math.floor(v + 0.5)
end

I used your updated button class but I noticed a bug. while it did up the FPS to 60 instead of 20, the quality of my physics injects and sprites diminished. I’ll post two pictures for further detail.
http://d.pr/i/aFB4
http://d.pr/i/3BVQ

I am guessing that it is because of the noSmooth call I make in the draw lines function. Try adding a pushStyle and PopStyle to that function, so that it becomes:

function button:drawLines(v)
    pushStyle()
    noSmooth()
    strokeWidth(1)
    stroke(0, 0, 0, 192)
    for i=1, #v-1 do
        line(v[i].x,v[i].y,v[i+1].x,v[i+1].y)
    end
    line(v[#v].x,v[#v].y,v[1].x,v[1].y)   
    popStyle()
end

I believe that should do it, but I’m not completely sure.

yeah that’s it. thankss

Nice - I will update the tute with the new @Vega class button (sounds like a Destroyer). The low frame rates hadn’t been an issue for me since I only had 3 buttons and not much happening on the screen.

Are the changes that @Vega made here also in github?
I want to add a link in a “buttons” aside I’m doing for my site.

If you add an array of actions, the button can be made generic so that multiple instances can be made to fire, but call seperate functions. This way I can create many buttons and have all their code seperated away from the Vega class. I haven’t seen any way to do this before, so I thought I’d mention it here.

Adds to the Button class: (uppercased it as a preference)
Init (last line)

self.action = {} 

touched(), last line after self:recolor in ENDED.

if (table.getn(self.action) == 0) then print ('No action defined') else self.action[1]() end

Main class:
My button declaration in setup() now has a second line;

mybtn.action ={mybtnclicked}  ---call the mybtnclicked code when clicked!

Finally, I have the payload function in main. We can put this in another file and have all our payloads in a different location.

function mybtnclicked()
  print("clicked")
end

Surely you just create multiple instances of the class, each with their own callback. Or maybe I’m misunderstanding what you’re trying to do.

no, that’s what this code was doing - making multiple instances of a class each with a seperate callback. the problem was the callback; without creating a new class file for each function. Maybe there is a better way to do this, but my goal is to:

In Setup:

1.  dynamically create any buttons that I need, and set the visible state;
2.  write the code that I need each button to do as a function (for convienence, in a master "business logic" file of sorts);
3.  tie the button to the function with some intelligent function name

What I do NOT want to do is create a new class each time I need button functionality and hardcode into the button class the possible derivations of what a button press is doing.

I was unable to fathom how to do what I wanted without writing all this funky callback code myself; was there a better way?

So then you pass the callback function as one of the initialisation arguments. Change the following lines:

function button:init(text,location,width,height,callback)

add to the init function

self.callback = callback

and change button:touched so that instead of print("pressed.") it reads self.callback()

Then you initialse it something like:

bttn = button("press me",vec2(WIDTH/2,HEIGHT/2),20,30, function () print ("I'm a speckled hen.") end)

OIC - after doing some additional research (into class.lua, actually) and reading this, it looks like anything that can be a function IS a function, even though it looks like a variable. So, “callback” is a function. I noticed that since you are passing the function on instantiation (last line above). Seems that if I wrote the function as

function cb()
print("speckled...")
end

I’d instantiate with

bttn = button("press me",vec2(WIDTH/2,HEIGHT/2),20,30, cb) 

This also explains that mysterious doNothing I keep seeing peppered through peoples’ code!