Page 1 of 1
Fast grid drawing
Posted: Sat Jul 04, 2015 1:29 am
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!
Re: Fast grid drawing
Posted: Sat Jul 04, 2015 1:39 am
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
Re: Fast grid drawing
Posted: Sat Jul 04, 2015 1:43 am
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.
Re: Fast grid drawing
Posted: Sat Jul 04, 2015 1:48 am
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?
Re: Fast grid drawing
Posted: Sat Jul 04, 2015 5:49 am
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.
Re: Fast grid drawing
Posted: Sat Jul 04, 2015 7:58 am
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 200 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).
Re: Fast grid drawing
Posted: Tue Jul 28, 2015 11:11 pm
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
Re: Fast grid drawing
Posted: Sun Aug 02, 2015 8:44 am
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