Quick Links: Download Gideros Studio | Gideros Documentation | Gideros Development Center | Gideros community chat | DONATE
Performance Issues drawing lines with touch — Gideros Forum

Performance Issues drawing lines with touch

drewfgdrewfg Member
edited July 2013 in General questions
I am having issues keeping consistent performance with a drawing app.

First attempt: When I reach a certain number of lines drawn (sprites created) around 30 - 40, the app lags and creates jagged lines (skips drawing on all move events), I thought this might be a memory issue.

Second attempt: I added a 10 line limit to the line table and what is rendered on stage. I used Render to Texture to merge all sprites together with the exception of the last 10 lines drawn (so I can provide an undo function). The performance doing it this way is very inconsistent drawing smooth and then jagged and back to smooth lines regardless of how many lines have been drawn.

Any ideas on what I am doing wrong would be greatly appreciated!
-- set constants
local lineTable  = {} 
local lineWidth  = 12 
local lineColor  = 0x0a8eea
local lineBitmap = nil
 
-- set up sprite groups
local canvas = Sprite.new()
self:addChild(canvas)
 
local bitmapGroup = Sprite.new()
canvas:addChild(bitmapGroup)
 
local lineGroup  = Sprite.new()
canvas:addChild(lineGroup)
 
-- draw line function
local newLine = function(event)
 
	local function drawLine()	
		local line = Shape.new()	
		line:setLineStyle(lineWidth, lineColor, 1)
		line:beginPath()
		line:moveTo(linePoints[#linePoints-1].x, linePoints[#linePoints-1].y)
		line:lineTo(linePoints[#linePoints].x, linePoints[#linePoints].y)
		line:endPath()
		lineTable[i]:addChild(line)	
	end
 
	if event:getType() == "mouseDown" then
		i = #lineTable+1
 
		lineTable[i] = Sprite.new()		
		lineGroup:addChild(lineTable[i])
 
		linePoints = nil
		linePoints = {};
 
		local pt = {}
			pt.x = event.x;
			pt.y = event.y;
			table.insert(linePoints,pt);						
	elseif event:getType() == "mouseMove" then
		local pt = {}
			pt.x = event.x;
			pt.y = event.y;			
		if not (pt.x==linePoints[#linePoints].x and pt.y==linePoints[#linePoints].y) then
			table.insert(linePoints,pt)
			drawLine()
		end	
	elseif event:getType() == "mouseUp" then
 
		if i >= 10 then
			local lineTexture = nil
			local lineMerge   = nil
			local lineTexture = RenderTarget.new(cwidth, cheight)
			local lineMerge   = Sprite.new()
 
			if lineBitmap then
				lineMerge:addChild(lineBitmap)
			end
 
			lineMerge:addChild(lineTable[1])
 
			lineTexture:clear(0x000000,0)
			lineTexture:draw(lineMerge)
 
			if lineBitmap then
				lineMerge:removeChild(lineBitmap, true)
				lineBitmap:removeFromParent()
				lineBitmap = nil
			end
 
			lineMerge:removeChild(lineTable[1])
 
			lineBitmap = Bitmap.new(lineTexture)
			bitmapGroup:addChild(lineBitmap)
 
			lineTexture = nil
			lineMerge   = nil
 
			lineTable[1]:removeFromParent()
			table.remove(lineTable, 1)
		end
 
		i = nil
	end
return true
end
 
-- add paint event listeners
self:addEventListener("mouseDown", newLine)
self:addEventListener("mouseUp", newLine)
self:addEventListener("mouseMove", newLine)

Comments

  • ar2rsawseenar2rsawseen Maintainer
    @drewfg thats interesting, just tested on my old Android 2.3 LG P500 and well, yes it does not too run smoothly and drawing is maybe a little behind, but no jagged lines and I basically can color my screen full.

    But still how about something like this:
    scene1 = Core.class(Sprite)
     
    function scene1:init()
    -- set constants
    local lineTable  = {} 
    local lineWidth  = 12 
    local lineColor  = 0x0a8eea
    local lineBitmap = nil
     
    -- set up sprite groups
    local canvas = Sprite.new()
    self.canvas = canvas
    --let's not add canvas
    --self:addChild(canvas)
     
    --but render it
    self.target = RenderTarget.new(application:getContentWidth(), application:getContentHeight())
    self:addChild(Bitmap.new(self.target))
     
     
    local bitmapGroup = Sprite.new()
    canvas:addChild(bitmapGroup)
     
    local lineGroup  = Sprite.new()
    canvas:addChild(lineGroup)
     
    --we don't want to redeclare function on every mouse move
    local function drawLine()	
    	local line = Shape.new()	
    	line:setLineStyle(lineWidth, lineColor, 1)
    	line:beginPath()
    	line:moveTo(linePoints[#linePoints-1].x, linePoints[#linePoints-1].y)
    	line:lineTo(linePoints[#linePoints].x, linePoints[#linePoints].y)
    	line:endPath()
    	lineTable[i]:addChild(line)	
    end
     
    -- lets create separate events
    local mouseDown = function(event)
    		i = #lineTable+1
     
    		lineTable[i] = Sprite.new()		
    		lineGroup:addChild(lineTable[i])
     
    		linePoints = nil
    		linePoints = {};
     
    		local pt = {}
    			pt.x = event.x;
    			pt.y = event.y;
    			table.insert(linePoints,pt);
    end
     
    local mouseMove = function(event)
    		local pt = {}
    			pt.x = event.x;
    			pt.y = event.y;			
    		if not (pt.x==linePoints[#linePoints].x and pt.y==linePoints[#linePoints].y) then
    			table.insert(linePoints,pt)
    			drawLine()
    		end	
    end
     
    -- add paint event listeners
    self:addEventListener("mouseDown", mouseDown)
    self:addEventListener("mouseMove", mouseMove)
    self:addEventListener(Event.ENTER_FRAME, self.onEnterFrame, self)
    end
     
    function scene1:onEnterFrame()
    	self.target:clear(0xffffff)
    	self.target:draw(self.canvas)
    end
    And here on canvas which no one can see, you can again implement optimizations of storing only 10 last values, etc.
  • keszeghkeszegh Member
    edited July 2013
    in my drawing app 'fragmenter' i use meshes to draw lines, and it can handle tons of lines without much of an issue, the lines are a bit jagged but not much (it is due to the fact that touch events are received only 30/60 fps only, to get rid of these jags i would need splines instead of segments), and it is consistent, i.e. it doesn't get worse after 1000 segments or whatever bigger number, i did not test it exhaustively but it never became slow for me.
    http://www.amazon.com/gp/product/B009IVLQ6Y

    Likes: ndoss

    +1 -1 (+1 / -0 )Share on Facebook
  • drewfgdrewfg Member
    @keszegh Are you creating a square with 2 triangles using mesh, and creating a new square mesh on every touch move to draw your line?
  • keszeghkeszegh Member
    edited July 2013
    @drewfg, exactly. even i add 4 additional triangles at the two sides with alpha gradient decreasing outside.
    here is my code (the 8 coordinates needed are computed beforehand and sent to this function) - i do some rounding, but this is mostly as i store it later in a json file and this way the file is smaller; so you can skip that.

    ps: in this code it seems that all segments are in one mesh (which is preferable, also doing an undo is quite easy this way, using self:resizeIndexArray), which is true for one 'frame', but because i make a new 'frame' for all frames of the animation, actually i have also many of these 'frames' (meshes), all with many 'segments' (triangles), and it still runs fast.
    Frame = Core.class(Mesh)
     
    function Frame:renderSegment(a1x,a1y, a2x,a2y, b1x,b1y, b2x,b2y, a3x,a3y, b3x,b3y, a4x,a4y, b4x,b4y,color_curr)
      local i=self.i
     
      a1x=math.floor(a1x*10)/10
      a1y=math.floor(a1y*10)/10
      a2x=math.floor(a2x*10)/10
      a2y=math.floor(a2y*10)/10
      b1x=math.floor(b1x*10)/10
      b1y=math.floor(b1y*10)/10
      b2x=math.floor(b2x*10)/10
      b2y=math.floor(b2y*10)/10
     
      self:setVertices(i*8+1, a1x, a1y, i*8+2, a2x, a2y)
    	self:setVertices(i*8+3, b1x, b1y, i*8+4, b2x, b2y) 
      self:setVertices(i*8+5, a3x, a3y, i*8+6, b3x, b3y) 
      self:setVertices(i*8+7, a4x, a4y, i*8+8, b4x, b4y)     
     
    	self:setColors(i*8+1, color_curr, 1, i*8+2, color_curr, 1)
    	self:setColors(i*8+3, color_curr, 1, i*8+4, color_curr, 1)	
      self:setColors(i*8+5, color_curr, 0, i*8+6, color_curr, 0)
      self:setColors(i*8+7, color_curr, 0, i*8+8, color_curr, 0)	  
     
    	self:setIndices(i*18+1, i*8+1, i*18+2, i*8+3, i*18+3, i*8+4)
    	self:setIndices(i*18+4, i*8+1, i*18+5, i*8+4, i*18+6, i*8+2)
     
      self:setIndices(i*18+7, i*8+5, i*18+8, i*8+6, i*18+9, i*8+3)
      self:setIndices(i*18+10, i*8+5, i*18+11, i*8+3, i*18+12, i*8+1)  
     
      self:setIndices(i*18+13, i*8+2, i*18+14, i*8+4, i*18+15, i*8+8)
      self:setIndices(i*18+16, i*8+2, i*18+17, i*8+8, i*18+18, i*8+7)
      self.i=self.i+1
    end
  • keszeghkeszegh Member
    edited February 2014
    So to make it more visual, with this class/function:
    Frame = Core.class(Mesh)
     
    function Frame:renderSegment(a1x,a1y, a2x,a2y, b1x,b1y, b2x,b2y, a3x,a3y, b3x,b3y, a4x,a4y, b4x,b4y,color_curr)
      local i=self.i
        --adding vertices:
      self:setVertices(i*8+1, a1x, a1y, i*8+2, a2x, a2y)
      self:setVertices(i*8+3, b1x, b1y, i*8+4, b2x, b2y) 
      self:setVertices(i*8+5, a3x, a3y, i*8+6, b3x, b3y) 
      self:setVertices(i*8+7, a4x, a4y, i*8+8, b4x, b4y)     
     
        --setting vertex colors and transparencies:
      self:setColors(i*8+1, color_curr, 1, i*8+2, color_curr, 1)
      self:setColors(i*8+3, color_curr, 1, i*8+4, color_curr, 1)	
      self:setColors(i*8+5, color_curr, 0, i*8+6, color_curr, 0)
      self:setColors(i*8+7, color_curr, 0, i*8+8, color_curr, 0)	  
     
        --adding the 3x2 triangles (we need 3 quadrangles and each has two triangles):
      self:setIndices(i*18+1, i*8+1, i*18+2, i*8+3, i*18+3, i*8+4)
      self:setIndices(i*18+4, i*8+1, i*18+5, i*8+4, i*18+6, i*8+2)
     
      self:setIndices(i*18+7, i*8+5, i*18+8, i*8+6, i*18+9, i*8+3)
      self:setIndices(i*18+10, i*8+5, i*18+11, i*8+3, i*18+12, i*8+1)  
     
      self:setIndices(i*18+13, i*8+2, i*18+14, i*8+4, i*18+15, i*8+8)
      self:setIndices(i*18+16, i*8+2, i*18+17, i*8+8, i*18+18, i*8+7)
     
      self.i=self.i+1
    end
    you can draw something like this:
    image
    smooth line.png
    473 x 91 - 6K

    Likes: uncleking

    +1 -1 (+1 / -0 )Share on Facebook
Sign In or Register to comment.