Using love.draw

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
laperen
Prole
Posts: 27
Joined: Tue Jul 26, 2016 1:15 am

Using love.draw

Post by laperen »

I'm intending to use love.draw only in my main.lua
A list of information will be sent to main.lua and it will be iterated through for each object to be drawn
Each element in the list will contain its position, rotation, scale, image, quad(using atlases), and offsets

all in all its going to look something like this

Code: Select all

--in main.lua
function love.draw()
	for count = 1, table.getn(list),1 do
		love.graphics.draw(list[count][1], list[count][2]--image,quad
			, list[count][3],list[count][4],list[count][5]--x,y,r
			,list[count][6],list[count][7]--sx,sy
			,list[count][8],list[count][9])--offsets
	end
end
--in main.lua
so my main question is if this is a good idea.
drunken_munki
Party member
Posts: 134
Joined: Tue Mar 29, 2011 11:05 pm

Re: Using love.draw

Post by drunken_munki »

I have done something similar as I am sure many others have, I don't see how it could be a problem!

I think however that in terms of execution you will get a pretty large performance increase if you create a local var of your indexed list:

Code: Select all

function love.draw()
   for count = 1, table.getn(list),1 do
      local item = list[count]
      love.graphics.draw(item[1], item[2]--image,quad
         ,item[3],item[4],item[5]--x,y,r
         ,item[6],item[7]--sx,sy
         ,item[8],item[9])--offsets
   end
end
Especially anything running inside a loop would benefit from this with a caveat. From my research I believe if you access a variable inside a table more than 3 times then you will see a speed boost, in your case you access 9 fields of list[count] per iteration.

The other thing, having your drawable stuff in an array means you can sort it by y position (for depth ordering) and other some such.

Also, during update you could iterate your objects and test which objects are in view of the screen and add those to your draw list. Draw will pick up the list and get on with it. Or alternatively by adding a .draw (as item[10]?) flag which you set True or False; which might be more efficient.
User avatar
zorg
Party member
Posts: 3444
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: Using love.draw

Post by zorg »

table.getn is outdated, use #table instead, also you can leave off the third 1 parameter, since that's the default anyway;
other than that, and the optimizations drunken_munki wrote, your code snippet is viable. :3
Me and my stuff :3True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
User avatar
Nixola
Inner party member
Posts: 1949
Joined: Tue Dec 06, 2011 7:11 pm
Location: Italy

Re: Using love.draw

Post by Nixola »

Can't you use unpack(list[count]) instead of indexing a table 9 times?
lf = love.filesystem
ls = love.sound
la = love.audio
lp = love.physics
lt = love.thread
li = love.image
lg = love.graphics
laperen
Prole
Posts: 27
Joined: Tue Jul 26, 2016 1:15 am

Re: Using love.draw

Post by laperen »

thank you all
drunken_munki, those suggestions sound fabulous, I'll give them a try when my project reaches a point when I have objects outside my screen.
zorg, great to know theres a better way to get the table element count, was rather annoying to use getn constantly.
I'm learning as i go with my project so didnt know of unpack until it was mentioned here, thanks Nixola
Last edited by laperen on Sun Jul 31, 2016 4:38 pm, edited 1 time in total.
User avatar
pgimeno
Party member
Posts: 3550
Joined: Sun Oct 18, 2015 2:58 pm

Re: Using love.draw

Post by pgimeno »

drunken_munki wrote:I think however that in terms of execution you will get a pretty large performance increase if you create a local var of your indexed list:

[...]

Especially anything running inside a loop would benefit from this with a caveat. From my research I believe if you access a variable inside a table more than 3 times then you will see a speed boost, in your case you access 9 fields of list[count] per iteration.
I'm pretty sure that's the case for Lua, but are you sure it holds for LuaJIT? The performance guide in the LuaJIT wiki suggests otherwise:

http://wiki.luajit.org/Numerical-Comput ... ance-Guide
  • Do not try to second-guess the JIT compiler.
    • [...]
    • It's perfectly ok to write 'a[j] = a[j] * a[j+1]'.
      • Do not try to cache partial FFI struct/array references (e.g. a) unless they are long-lived (e.g. in a big loop).


And indeed, I've made a quick benchmark and couldn't measure any difference.
drunken_munki
Party member
Posts: 134
Joined: Tue Mar 29, 2011 11:05 pm

Re: Using love.draw

Post by drunken_munki »

pgimeno wrote:I'm pretty sure that's the case for Lua, but are you sure it holds for LuaJIT? .
Does love 0.10.1 use LuaJit? I just use love 0.10.1 out of the box with no changes; if so here is my benchmark:

DATA:

Code: Select all

      local TABL_TEST = { }
      for i = 1, 10000 do
        TABL_TEST[i] = { math.random(),
                         math.random(),
                         math.random(),
                         math.random(),
                         math.random(),
                         math.random(),
                         math.random(),
                         math.random(),
                         math.random()
                        }
      end
The same test data is sent to both computation methods as below:

Code: Select all


local function methodA(TABL_TEST)
  for i = 1, #TABL_TEST do
    local test = TABL_TEST[i][1] + TABL_TEST[i][2] + TABL_TEST[i][3] + TABL_TEST[i][4] + TABL_TEST[i][5] + TABL_TEST[i][5] + TABL_TEST[i][6] + TABL_TEST[i][7] + TABL_TEST[i][8] + TABL_TEST[i][9]
  end
end

local function methodB(TABL_TEST)
  for i = 1, #TABL_TEST do
    local item = TABL_TEST[i]
    local test = item[1] + item[2] + item[3] + item[4] + item[5] + item[5] + item[6] + item[7] + item[8] + item[9]
  end
end
Reports --


Method A:

Code: Select all

  TOTAL TIME   = 0.001000 s
---------------------------------------------------------------------------------------------------------------
| FILE                             : FUNCTION                         : LINE    : TIME    : %       : #       |
---------------------------------------------------------------------------------------------------------------
| main.lua                         : methodA                          :    398  : 0.0010  : 100.00  :       1 |
---------------------------------------------------------------------------------------------------------------
| monkey_bay/engine.lua            : profileEnd                       :   1373  : ~       : ~       :       1 |
---------------------------------------------------------------------------------------------------------------

Method B:

Code: Select all

  TOTAL TIME   = 0.000000 s
---------------------------------------------------------------------------------------------------------------
| FILE                             : FUNCTION                         : LINE    : TIME    : %       : #       |
---------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------
| monkey_bay/engine.lua            : profileEnd                       :   1373  : ~       : ~       :       1 |
| main.lua                         : methodB                          :    404  : ~       : ~       :       1 |
---------------------------------------------------------------------------------------------------------------


I'm profiling with my own modifications to ProFi which reports as above. When the timing is less than "0.0001" I replace it with '~' in the time column of the report. Method A is timing at 0.001 and B is less than 0.0001 seconds... so I would assume Method B is at least is 10x faster?

So I know with a ridiculously large sample the overall delay is small, but the performance increase is high and a real change and still useful to practice.
User avatar
pgimeno
Party member
Posts: 3550
Joined: Sun Oct 18, 2015 2:58 pm

Re: Using love.draw

Post by pgimeno »

Yes, LÖVE 0.10.1 uses LuaJIT.

I can't reproduce your results without using a profiler. Maybe the profiler is disabling optimization or forcing some extra calls.

Here's my test program (yours with a few changes):

Code: Select all

require 'socket'

      local TABL_TEST = { }
      for i = 1, 10000 do
        TABL_TEST[i] = { math.random(),
                         math.random(),
                         math.random(),
                         math.random(),
                         math.random(),
                         math.random(),
                         math.random(),
                         math.random(),
                         math.random()
                        }
      end


local function methodA(TABL_TEST)
  for i = 1, #TABL_TEST do
    TABL_TEST[i][1] = TABL_TEST[i][1] + TABL_TEST[i][2] + TABL_TEST[i][3] + TABL_TEST[i][4] + TABL_TEST[i][5] + TABL_TEST[i][5] + TABL_TEST[i][6] + TABL_TEST[i][7] + TABL_TEST[i][8] + TABL_TEST[i][9]
  end
end

local function methodB(TABL_TEST)
  for i = 1, #TABL_TEST do
    local item = TABL_TEST[i]
    item[1] = item[1] + item[2] + item[3] + item[4] + item[5] + item[5] + item[6] + item[7] + item[8] + item[9]
  end
end


local startTime = socket.gettime()

for i = 1, 10000 do
  methodA(TABL_TEST)
end

print(socket.gettime() - startTime)
(change methodA to methodB to test the other)

Run with either 'luajit main.lua' or 'love .'

Results of 10 runs of each:

Code: Select all

methodA           methodB
0.87791299819946  0.87835216522217
0.8876838684082   0.87647485733032
0.88603281974792  0.88520693778992
0.89042115211487  0.89626216888428
0.90008997917175  0.88968300819397
0.89558506011963  0.88830399513245
0.89924907684326  0.88235592842102
0.87286520004272  0.89468812942505
0.86974000930786  0.88487601280212
0.87221884727478  0.88938403129578
The differences are not distinguishable from noise.

I changed the assignment to prevent LuaJIT from realizing that the value is not used, and discard the whole operation. Making the result visible from outside the function should stop that.
drunken_munki
Party member
Posts: 134
Joined: Tue Mar 29, 2011 11:05 pm

Re: Using love.draw

Post by drunken_munki »

pgimeno wrote:Yes, LÖVE 0.10.1 uses LuaJIT.
...
I changed the assignment to prevent LuaJIT from realizing that the value is not used, and discard the whole operation. Making the result visible from outside the function should stop that.
Thanks for that, it's very interesting indeed -- maybe I'll run it several times later on.

*Edit* I'm thinking though, why did you change the test code, it makes it very hard for me to interpret your results?
Last edited by drunken_munki on Sat Aug 27, 2016 8:16 am, edited 1 time in total.
laperen
Prole
Posts: 27
Joined: Tue Jul 26, 2016 1:15 am

Re: Using love.draw

Post by laperen »

How different would it have been to do it like this?
Object.lua

Code: Select all

function Object.draw()
	love.graphics.draw(...)
end
Main.lua

Code: Select all

function love.draw()
	for i = 1,#objectList,1 do
		objectList[i].draw()
	end
end
Last edited by laperen on Tue Aug 02, 2016 3:14 pm, edited 1 time in total.
Post Reply

Who is online

Users browsing this forum: Google [Bot] and 49 guests