Fast grid drawing

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.
Post Reply
User avatar
MicroMacro
Citizen
Posts: 92
Joined: Fri May 30, 2014 2:30 am
Location: Boston, MA, USA
Contact:

Fast grid drawing

Post by MicroMacro »

Hi!

I'm making a tile based world editor, and I want the user to be able to toggle a grid. My algorithm works, but I'm constantly drawing a 1000x1000 area of squares. Is there a way I could draw the grid once, and then not draw it again, or just have it draw more efficiently?

Here's my current grid algorithm:

Code: Select all

if editor.grid then
	for i=-500,500 do
		local precolor = love.graphics.getColor()
		love.graphics.setColor(255,255,255,50)
		for i2=-500,500 do
			love.graphics.rectangle("line",i*40,i2*40,editor.defaultTileSize,editor.defaultTileSize)
		end
	end
end
Any and all help is appreciated. Thank you so much!
https://github.com/ebernerd- where you can find all my work.
User avatar
s-ol
Party member
Posts: 1077
Joined: Mon Sep 15, 2014 7:41 pm
Location: Cologne, Germany
Contact:

Re: Fast grid drawing

Post by s-ol »

MicroMacro wrote:Hi!

I'm making a tile based world editor, and I want the user to be able to toggle a grid. My algorithm works, but I'm constantly drawing a 1000x1000 area of squares. Is there a way I could draw the grid once, and then not draw it again, or just have it draw more efficiently?

Here's my current grid algorithm:

Code: Select all

if editor.grid then
	for i=-500,500 do
		local precolor = love.graphics.getColor()
		love.graphics.setColor(255,255,255,50)
		for i2=-500,500 do
			love.graphics.rectangle("line",i*40,i2*40,editor.defaultTileSize,editor.defaultTileSize)
		end
	end
end
Any and all help is appreciated. Thank you so much!
Just draw it onto a canvas once, then draw the canvas instead.

Code: Select all

-- somewhere where it only happens once
gridcanvas = love.graphics.newCanvas()for i=-500,500 do
love.graphics.setCanvas(gridcanvas)
		local precolor = love.graphics.getColor()
		love.graphics.setColor(255,255,255,50)
		for i2=-500,500 do
			love.graphics.rectangle("line",i*40,i2*40,editor.defaultTileSize,editor.defaultTileSize)
		end
	end
love.graphics.setCanvas()

-- every frane
if editor.grid then
  love.graphics.draw(gridcanvas)
end

s-ol.nu /blog  -  p.s-ol.be /st8.lua  -  g.s-ol.be /gtglg /curcur

Code: Select all

print( type(love) )
if false then
  baby:hurt(me)
end
DataBrain
Prole
Posts: 5
Joined: Fri Jul 03, 2015 5:37 pm

Re: Fast grid drawing

Post by DataBrain »

love.draw will always clear the render every time at the beginning of its call. I'm not sure what you can do to optimize all of this if it's on-screen.

If most squares are off-screen (Which appears to be the case), I would recommend that you simply procedurally generating these squares in the grid rather than keeping 1000000 squares of data.

It should looking something along the lines of this:

Code: Select all

-- Assume StartX and StartY are the current positions that the camera is at, with the default being 0, 0.
for x = 1, math.floor(love.graphics.getWidth() / 40) do
	local precolor = love.graphics.getColor()
	love.graphics.setColor(255,255,255,50)
	for y = 1, math.floor(love.graphics.getWidth() / 40) do
		love.graphics.rectangle("line", StartX % 40 + x * 40, StartY % 40 + y * 40, editor.defaultTileSize, editor.defaultTileSize)
	end
end
This is all untested, but in theory, it should work.
User avatar
MicroMacro
Citizen
Posts: 92
Joined: Fri May 30, 2014 2:30 am
Location: Boston, MA, USA
Contact:

Re: Fast grid drawing

Post by MicroMacro »

Oh, thank you! I've never used canvases before.

Edit: works like a charm, just increases the loading time. I might not render a whole 1000x1000 grid structure, but instead render a grid only for what the camera can see.

Is there any way you can move canvases? Like translate them across x and y?
https://github.com/ebernerd- where you can find all my work.
User avatar
Jasoco
Inner party member
Posts: 3725
Joined: Mon Jun 22, 2009 9:35 am
Location: Pennsylvania, USA
Contact:

Re: Fast grid drawing

Post by Jasoco »

Canvases are just images of a sort. You can do anything with a canvas that you can do with an image. With the benefit being you can draw stuff onto it easily.
User avatar
micha
Inner party member
Posts: 1083
Joined: Wed Sep 26, 2012 5:13 pm

Re: Fast grid drawing

Post by micha »

I would try to avoid a 1000x1000 tile-sized canvas. The grid itself is very much repetitive and that would be a waste of memory.

There are two elegant methods.
1) Like S0lll0s already suggested, do not draw all 1000 by 1000 rectangles, but only those, that are inside the screen. Do this by running the for-loops (for i and i2) over only a smaller interval. The interval has to be adapted to what tile is the left most tile on the screen, the right most, top most and bottom most.

2) Use a quad that is larger than an image and set the wrap-mode to repeat. You can also combine this with a canvas. The see attached .love file. This approach again has the advantage that only pixels are drawn that are actually visible on screen.
efficientGrid.love
Grid by Canvas + Wrapping. Use arrow-keys for moving the grid.
(662 Bytes) Downloaded 193 times

Edit: And if you stick to the for-loop solution, you can make it also faster by replacing the rectangles by lines (one for loop for the vertical lines and one for the horizontal ones). That way, the grid size in x- and y- direction will not multiply (no nested loops needed).
User avatar
Positive07
Party member
Posts: 1014
Joined: Sun Aug 12, 2012 4:34 pm
Location: Argentina

Re: Fast grid drawing

Post by Positive07 »

micha wrote: 2) Use a quad that is larger than an image and set the wrap-mode to repeat. You can also combine this with a canvas. The see attached .love file. This approach again has the advantage that only pixels are drawn that are actually visible on screen.
Tried to use this with a 10x10px image but had some weird transparent lines between each repetition, the issue was solver when I resized the image to 8x8px so probably a PO2 issue. Anyway I could still use it as a 10x10px one by passing 10 in the sixth and seventh arguments to newQuad
for i, person in ipairs(everybody) do
[tab]if not person.obey then person:setObey(true) end
end
love.system.openURL(github.com/pablomayobre)
User avatar
AntonioModer
Party member
Posts: 202
Joined: Fri Jun 15, 2012 5:31 pm
Location: Belarus
Contact:

Re: Fast grid drawing

Post by AntonioModer »

Method from my game-engine, draw grid with image. I use hump.camera module.

Code: Select all

--[[
version 0.1.0
--]]
thisModule.grid = {}
thisModule.grid.on = config.gameEditor.on
thisModule.grid.image = love.graphics.newImage(love.image.newCompressedData([[resources/images/other/grid.dds]]))
thisModule.grid.image:setMipmapFilter("linear", 0)
thisModule.grid.imageSize = thisModule.grid.image:getWidth()
local sBSizeX = math.ceil((config.window.width/thisModule.grid.imageSize)/0.5)		-- 0.5 - maximum camera.scale when grid draw
local sBSizeY = math.ceil((config.window.height/thisModule.grid.imageSize)/0.5)
local sBSize = (sBSizeX*sBSizeY)+(sBSizeX+sBSizeY)*2
--print(sBSize)														-- debug
thisModule.grid.spriteBatch = love.graphics.newSpriteBatch(thisModule.grid.image, sBSize, "dynamic")
local _count = 0
--[[
drawMethod: 1=image, 2=spriteBatch
--]]
function thisModule.grid:draw(drawMethod)
	if not thisModule.grid.on or camera.scale < 0.5 then return false end
	love.graphics.setColor(255,255,255,255)
	local floor, ceil, camera = math.floor, math.ceil, camera
--	local Xlast, Ylast, count = 0, 0, 0								-- debug
	if drawMethod == 2 then
		self.spriteBatch:clear()
	end
	for x = floor((camera.x-((config.window.width/camera.scale)/2)+0)/self.imageSize), 
                   ceil((camera.x+((config.window.width/camera.scale)/2)-0)/self.imageSize) do
		for y = floor((camera.y-((config.window.height/camera.scale)/2)+0)/self.imageSize), 
                           ceil((camera.y+((config.window.height/camera.scale)/2)-0)/self.imageSize) do
			if drawMethod == 1 then
				love.graphics.draw(self.image, x*self.imageSize, y*self.imageSize)
			elseif drawMethod == 2 then
				self.spriteBatch:add(x*self.imageSize, y*self.imageSize)
			end
--			Xlast, Ylast =  x*backgr.imageSize, y*backgr.imageSize							-- debug
--			count = count+1
		end
	end
	if drawMethod == 2 then
		love.graphics.draw(self.spriteBatch, 0, 0)
	end
--	print(count)																-- debug
end

Post Reply

Who is online

Users browsing this forum: No registered users and 70 guests