Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

SpaceX-type gage using Mesh and Shader crashes.

in Questions Posts: 78

I just completed a class definition of a gage with a circular dial with a "bar" that progresses clockwise as the value increases.

The mesh and shader technique originated as a function that defined 180 degrees of a dial and was the work of someone else. I redefined it as a class that would display a full 360 degrees and added additional graphics.

When I try and display four such dials on the screen at the same time the program crashes within two to three minutes.

QUESTION: Is the mesh/shader technique too taxing on the system, is there an inherent bug with mesh/shader or am I doing something wrong?

I'm running all this on a 3rd gen iPad (32Gigs with 2.5Gigs available), OS ver 9.3.5 using a version of Codea that has not been updated in forever due to the age of the iPad.

Thank you for any tips or solutions to this problem.

-- SpaceX-type dials using Mesh and Shader
-- Version 4
-- NOTE: Code is best viewed in landscape mode.



supportedOrientations(LANDSCAPE_ANY) -- preferred orientation
displayMode(STANDARD)


function setup()
    X = WIDTH/2
    Y = HEIGHT/2
    backColor = color(40,40,50)


    FPS,MAX,MIN = 0,0,200     -- For frames-per-second calc.   

    parameter.number("spdFrac",   0, 1, 0)
--[[
    parameter.number("altFrac",   0, 1, 0)
    parameter.number("tempFrac",  0, 1, 0)
    parameter.number("pressFrac", 0, 1, 0)
--]]

    -- NOTE: If dial radii and colors are all identical then 
    -- define them here ahead of Speedo variable defs.
    dialRad     = 150
    secondColor = color(127, 127, 127, 255) 
    primeColor  = color(0,255,0)    

    -- Speedo definitions:     
    -- "speed"
    title  = "Speed"
    spdMax = 500
    speedLoc = vec2(200,HEIGHT-200)
    --speedLoc = vec2(X,Y) -- for testing
    rad    = dialRad
    c1     = secondColor
    c2     = primeColor
        speed = Speedo(title,rad,c1,c2)

--[[
    -- "altitude"
    title  = "Altitude"
    altMax = 10000
    altitudeLoc = vec2(WIDTH-200,HEIGHT-200)
    --rad    = dialRad
    --c1     = secondColor
    --c2     = primeColor
        altitude = Speedo(title,rad,c1,c2)


    -- "temp"
    title   = "Temp"
    tempMax = 212
    tempLoc = vec2(200,200)
    --rad     = dialRad
    --c1      = secondColor
    --c2      = primeColor
        temp = Speedo(title,rad,c1,c2)


    -- "pressure"
    title    = "Pressure"
    pressMax = 500
    pressLoc = vec2(WIDTH-200, 200)
    --rad      = dialRad
    --c1       = secondColor
    --c2       = primeColor
        pressure = Speedo(title,rad,c1,c2)
--]]

end -- end of setup()




function draw()

    background(backColor)

    -- massage speed-data
    spdVal = spdMax*spdFrac
    ea1 = (360*spdFrac-180)*-1
    sa2 = ea1
    pushMatrix()
    translate(speedLoc.x,speedLoc.y)
        speed:draw(spdVal,ea1,sa2)
    popMatrix()

--[[
    -- massage altitude-data
    altVal = altMax*altFrac
    ea1 = (360*altFrac-180)*-1
    sa2 = ea1
    pushMatrix()
    translate(altitudeLoc.x,altitudeLoc.y)
        altitude:draw(altVal,ea1,sa2)
    popMatrix()


    -- massage temp-data
    tempVal = tempMax*tempFrac
    ea1 = (360*tempFrac-180)*-1
    sa2 = ea1
    pushMatrix()
    translate(tempLoc.x,tempLoc.y)
        temp:draw(tempVal,ea1,sa2)
    popMatrix()


    -- massage altitude-data
    pressVal = pressMax*pressFrac
    ea1 = (360*pressFrac-180)*-1
    sa2 = ea1
    pushMatrix()
    translate(pressLoc.x,pressLoc.y)
        pressure:draw(pressVal,ea1,sa2)
    popMatrix()
--]]

    MaxMin() -- frames-per-sec calculation         

end


function MaxMin()
-- Calculate frames-per-second

    FPS = 1/DeltaTime
    if FPS > MAX then
        MAX = FPS
    elseif FPS < MIN then
        MIN = FPS
    end

    fill(255, 255, 255, 255/2) 
    fontSize(20)
    text(string.format("FPS = %.0f", FPS,FPS), X, 60)
    text(string.format("MAX = %.0f", MAX,MAX), X, 40)
    text(string.format("MIN = %.0f", MIN,MIN), X, 20)

end



Speedo = class()
-- Mesh m1 and m2 definition by others but the rest is by Scotty.
-- Speedo is my term for any type of dial that looks like it belongs on a SpaceX-type display.

function Speedo:init(title, rad, c1, c2)
    -- incoming args:
    self.title  = title
    self.rad    = rad
    self.c1     = c1
    self.c2     = c2

    -- gage loc
    self.x      =    0
    self.y      =    0
    -- range of gage
    self.sa1    = -180
    self.ea2    =  180
    -- for min/max lines
    self.maxAng  =  185
    self.minAng  = -185
    -- min/max flags
    self.minFlag = 0
    self.maxFlag = 0
    -- min/max values
    self.minValue = 0
    self.maxValue = 0

end


function Speedo:draw(val,ea1,sa2)

    self.val  = val
    self.ea1  = ea1
    self.sa2  = sa2 - .1  -- NOTE: Without subtracting a small amount from sa2 the 
                          -- resulting dial is displayed fully lite up when dial value is 
                          -- at zero. This remedies that condition.


    local m1 = mesh()
    local m2 = mesh()

    local sWidth = self.rad * .25
    local size   = (1 - sWidth/self.rad) * 0.5

    if c1 == nil then c1 = color(background())  end

    -- Secondary, or background,  mesh
    m1:addRect(self.x, self.y, self.rad * 2, self.rad * 2)
    m1.shader       = shader("Patterns:Arc")
    m1.shader.size  = size               -- size
    m1.shader.color = self.c1            -- color
    m1.shader.a1    = math.rad(self.sa1) -- start angle
    m1.shader.a2    = math.rad(self.ea1) -- end angle   
    m1:draw()

    -- Primary mesh
    m2:addRect(self.x, self.y, self.rad * 2, self.rad * 2)
    m2.shader       = shader("Patterns:Arc")
    m2.shader.size  = size
    m2.shader.color = self.c2
    m2.shader.a1    = math.rad(self.sa2)
    m2.shader.a2    = math.rad(self.ea2)
    m2:draw()

    -- Ellipses
    pushStyle()
    stroke(self.c2)
    strokeWidth(self.rad*.015) -- 1.5% of dial rad
    noFill()
    ellipseMode(CENTER)
    ellipse(self.x,self.y, (self.rad*2+sWidth/2.25)+strokeWidth())
    ellipse(self.x,self.y, (self.rad*2-sWidth*2.25))

    -- Text
    fill(c2)
    fill(69, 255, 0, 77)
    fontSize(sWidth)
    text(self.title, self.x,self.y+sWidth/2)
    text(string.format("%.0f",self.val), self.x,self.y-sWidth/2)

    -- min-max values
    fontSize(sWidth/2)
    fill(38, 0, 255, 255)
    text(string.format("Max = %.0f",self.maxValue), self.x,self.y+sWidth*2)
    fill(255, 0, 0, 255)
    text(string.format("Min = %.0f",self.minValue), self.x,self.y-sWidth*2)
    fontSize(sWidth)


    -- Rotatable value line with max/min value.
    -- 180 is the "low point" of dial while -180 is the "high point".
    -- This seems backwards but that is how the dial was designed.
    if self.ea1 < self.maxAng then        -- high-point is increasing
        self.maxAng = self.ea1            -- save max angle
        self.maxValue = self.val          -- save max value
        if self.ea1 == self.maxAng then
            self.maxFlag = 1
        end
    elseif self.ea1 > self.maxAng then    -- value decreasing from high point
        self.maxFlag = 0
        self.minFlag = 1
    end

    if self.maxFlag == 0 then 
        if self.ea1 > self.minAng then    -- low-point is decreasing
            self.minAng   = self.ea1      -- save min angle
            self.minValue = self.val      -- save min value
        end
    end


    lineCapMode(SQUARE)
    strokeWidth(strokeWidth()*1.5)

    -- Display max line
    pushMatrix()
    stroke(0, 0, 255, 255)
    rotate(self.maxAng+180)
    line(self.x-self.rad, self.y,  self.x-self.rad+sWidth, self.y)
    popMatrix()


    -- Display "value" line
    pushMatrix()
    stroke(0, 128, 0, 255)
    rotate(self.ea1+180)
    line(self.x-self.rad, self.y,  self.x-self.rad+sWidth, self.y)
    popMatrix()


    -- Display "Zero" line
    stroke(0, 0, 0, 255)     
    line(self.x-self.rad, self.y,  self.x-self.rad+sWidth, self.y)


    -- Display min line
    if self.minFlag == 1 then
        pushMatrix()
        stroke(255, 0, 0, 255)
        rotate(self.minAng+180)
        line(self.x-self.rad, self.y,  self.x-self.rad+sWidth, self.y)
        popMatrix()
    end

    --[[
    -- Display values for testing only:
    fontSize(20)
    fill(255, 255, 255, 255)
    vLoc = self.rad/2
    vInc = 25

    vLoc = vLoc-vInc
    text("ea1 = "    ..string.format("%.f",self.ea1), self.x, self.y+vLoc)
    vLoc = vLoc-vInc
    text("minAng = " ..string.format("%.f",self.minAng), self.x, self.y+vLoc)
    vLoc = vLoc-vInc
    text("maxAng = " ..string.format("%.f",self.maxAng), self.x, self.y+vLoc)
    vLoc = vLoc-vInc
    text("minFlag = "..self.minFlag, self.x, self.y+vLoc)
    vLoc = vLoc-vInc
    text("maxFlag = "..self.maxFlag, self.x, self.y+vLoc)
    --]]

    popStyle()

end

Comments

  • Posts: 613

    you are creating the meshes every draw cycle, shouldn't you do it just once during the init and then save it.

  • Posts: 78

    @piinthesky thanks for the reply.

    Are you suggesting I place m1 = mesh() and m2 = mesh() in Speedo:init() rather than Speedo:draw()? I've just tried that and the performance is horrible. Very slow response from the parameter sliders -- even with one dial. There must be something I'm missing from your suggestion.

    Again, I apologize for my out-sized program size. It was with four dials on the screen that this problem became evident.

    Thanks again.

  • dave1707dave1707 Mod
    Posts: 9,109

    @Scotty I thought I’d try this just for something to do. It’s not exactly like yours, but kinda close.

    viewer.mode=STANDARD
    
    function setup()
        m=mesh()  
        a1=arc(200,250,"Speed",color(255,0,0))
        a2=arc(200,600,"Altitude",color(0,255,0))
        a3=arc(600,250,"Temp",color(0,0,255))
        a4=arc(600,600,"Pressure",color(255,255,0))
        parameter.integer("sp",0,360,0)
        parameter.integer("al",0,360,0)
        parameter.integer("te",0,360,0)
        parameter.integer("pr",0,360,0)
    end
    
    function draw()
        background(135, 224, 216)
        a1:draw(sp)
        a2:draw(al)
        a3:draw(te)
        a4:draw(pr)
    end
    
    arc=class()
    
    function arc:init(xPos,yPos,name,col)
        self.x=xPos
        self.y=yPos
        self.r=90
        self.t=40
        self.name=name
        self.c=col
        self.max=0
        self.min=0
        self.hold=0
    end
    
    function arc:draw(val) 
        fill(100)
        stroke(255)
        strokeWidth(2)
        ellipse(self.x,self.y,(self.r+self.t)*2+8)
        fill(0)
        ellipse(self.x,self.y,self.r*2)
        fontSize(30)
        fill(255)
        text(self.name,self.x,self.y+20)
        text(val,self.x,self.y-20)    
        if val<self.hold then
            self.min=val        
        elseif val>self.max then
            self.max=val
        end
        self.hold=val    
        fill(255, 148, 0)
        fontSize(15)
        text("Max = "..self.max,self.x,self.y+60)
        text("Min = "..self.min,self.x,self.y-60)
        local tab1={}
        for ang=0,val do
            local x1=math.cos(math.rad(180-ang-1))*self.r+self.x
            local y1=math.sin(math.rad(180-ang-1))*self.r+self.y
            local x2=math.cos(math.rad(180-ang-1))*(self.r+self.t)+self.x
            local y2=math.sin(math.rad(180-ang-1))*(self.r+self.t)+self.y
            local x3=math.cos(math.rad(180-ang))*self.r+self.x
            local y3=math.sin(math.rad(180-ang))*self.r+self.y
            local x4=math.cos(math.rad(180-ang))*(self.r+self.t)+self.x
            local y4=math.sin(math.rad(180-ang))*(self.r+self.t)+self.y
            table.insert(tab1,vec2(x1,y1))
            table.insert(tab1,vec2(x2,y2))
            table.insert(tab1,vec2(x4,y4))
            table.insert(tab1,vec2(x1,y1))
            table.insert(tab1,vec2(x3,y3))
            table.insert(tab1,vec2(x4,y4))
        end
        m.vertices=tab1
        m:setColors(self.c)
        m:draw()
        stroke(0)
        strokeWidth(4)
        self:minMax(self.min)
        self:minMax(self.max)
    end
    
    function arc:minMax(val)
        x1=math.cos(math.rad(180-val-1))*(self.r+2)+self.x
        y1=math.sin(math.rad(180-val-1))*(self.r+2)+self.y
        x2=math.cos(math.rad(180-val-1))*(self.r+38)+self.x
        y2=math.sin(math.rad(180-val-1))*(self.r+38)+self.y
        line(x1,y1,x2,y2)
    end
    
  • Posts: 78

    Thanks @dave1707 for this example and, yes, it is very much like my attempt in appearance. I've made a couple of tweeks:
    1) Mods to code that keeps track on max and min values. (I want to save the max AND min during the running of the program rather than resetting the min.)
    2) I added an additional "arc" that shows the frames-per-second just to demonstrate the sending of calculated values rather than a parameter slider value.

    And thank you @piinthesky for your suggestion as to where to init the mesh. It all makes sense now.


    --viewer.mode=STANDARD supportedOrientations(LANDSCAPE_ANY) displayMode(STANDARD) function setup() m=mesh() margin=175 a1=arc(margin,HEIGHT-margin,"Speed", color(255,0,0)) a2=arc(WIDTH-margin,HEIGHT-margin,"Altitude", color(0,255,0)) a3=arc(margin,margin,"Temp", color(0,0,255)) a4=arc(WIDTH-margin,margin,"Pressure", color(255,255,0)) a5=arc(WIDTH/2,HEIGHT/2,"FPS", color(255,102,34,255)) -- frames per sec parameter.integer("sp",0,360,1) parameter.integer("al",0,360,1) parameter.integer("te",0,360,1) parameter.integer("pr",0,360,1) end function draw() background(135, 224, 216) a1:draw(sp) a2:draw(al) a3:draw(te) a4:draw(pr) a5:draw(math.floor(1/DeltaTime)) -- frames per second end arc=class() function arc:init(xPos,yPos,name,col) self.x=xPos self.y=yPos self.r=90 self.t=40 self.name=name self.c=col self.max=0 self.min=360 self.hold=0 -- new self.maxFlag = 0 self.minFlag = 0 end function arc:draw(val) fill(100) stroke(255) strokeWidth(2) ellipse(self.x,self.y,(self.r+self.t)*2+8) fill(0) ellipse(self.x,self.y,self.r*2) fontSize(30) fill(255) text(self.name,self.x,self.y+20) text(string.format("%.f",val),self.x,self.y-20) -- Sets record max and min: if val > self.max then self.max = val if val == self.max then self.maxFlag = 1 end elseif val < self.max then self.maxFlag = 0 self.minFlag = 1 end if self.maxFlag == 0 then if val < self.min then self.min = val end end self.hold=val --[[ Saves max but resets min (original): if val<self.hold then self.min=val elseif val>self.max then self.max=val end self.hold=val --]] fill(255, 148, 0) fontSize(15) text(string.format("Max = %.f",self.max),self.x,self.y+60) text(string.format("Min = %.f",self.min),self.x,self.y-60) local tab1={} for ang=0,val do local x1=math.cos(math.rad(180-ang-1))*self.r+self.x local y1=math.sin(math.rad(180-ang-1))*self.r+self.y local x2=math.cos(math.rad(180-ang-1))*(self.r+self.t)+self.x local y2=math.sin(math.rad(180-ang-1))*(self.r+self.t)+self.y local x3=math.cos(math.rad(180-ang))*self.r+self.x local y3=math.sin(math.rad(180-ang))*self.r+self.y local x4=math.cos(math.rad(180-ang))*(self.r+self.t)+self.x local y4=math.sin(math.rad(180-ang))*(self.r+self.t)+self.y table.insert(tab1,vec2(x1,y1)) table.insert(tab1,vec2(x2,y2)) table.insert(tab1,vec2(x4,y4)) table.insert(tab1,vec2(x1,y1)) table.insert(tab1,vec2(x3,y3)) table.insert(tab1,vec2(x4,y4)) end m.vertices=tab1 m:setColors(self.c) m:draw() stroke(0) strokeWidth(4) self:minMax(self.min) self:minMax(self.max) self:minMax(self.hold) self:minMax(0) end function arc:minMax(val) x1=math.cos(math.rad(180-val-1))*(self.r+2)+self.x y1=math.sin(math.rad(180-val-1))*(self.r+2)+self.y x2=math.cos(math.rad(180-val-1))*(self.r+38)+self.x y2=math.sin(math.rad(180-val-1))*(self.r+38)+self.y line(x1,y1,x2,y2) --fontSize(18) --fill(255, 255, 255, 255) --text(string.format("%.f",val),(x1+x2)/2,(y1+y2)/2) end
Sign In or Register to comment.