SetCanvas() breaks drawing when using Tiled/STI

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
BathtubAmbassador
Prole
Posts: 7
Joined: Thu Jul 07, 2016 8:11 pm

SetCanvas() breaks drawing when using Tiled/STI

Post by BathtubAmbassador »

Hi, I've been working on a math demo using Tiled and the Simple Tiled Implementation library. I've got an issue where when I use setCanvas() to return to drawing the main screen, no graphics calls work until the end of the function setCanvas() is in. I'm trying to draw a 16th size canvas onto the main screen, but nothing appears except for the background. Commenting out the setCanvas calls makes the character draw normally, with the points I want to draw to the "visibleImage" canvas appearing at the top left of the world. Excuse how slow the program is, it iterates over a lot of lists and I'm working on optimizing it.

Here's the code causing the issue, and after that is the .love file, which has a bunch of stuff in it including STI, bump, anim8, an implementation of A* i'm not currently using, etc. Just head to main.lua in the main folder.

Code: Select all

function slayer:draw()

		local dx,dy = 0,0
		local qx,qy = math.floor((self.player.x - (love.graphics.getWidth() / 2))/16),math.floor((self.player.y - (love.graphics.getHeight() / 2))/16)
		local hx, hy = math.floor((self.player.x + (love.graphics.getWidth() / 2)) / 16), math.floor((self.player.y + (love.graphics.getHeight() / 2)) / 16)

		love.graphics.setCanvas(self.visibleImage)

		repeat
			if has_val(self.player.visible,{['x'] = qx, ['y'] = qy}) then
				love.graphics.setColor(255,255,255,0)
				love.graphics.points(dx,dy)
			else
				love.graphics.setColor(0,0,0,128)
				love.graphics.points(dx,dy)
			end

			qy = qy + 1
			dy = dy + 1
			if qy > hy then
				qy = 1
				dy = 1
				qx = qx + 1
				dx = dx + 1
			end
		until qx == hx and qy == hy

		love.graphics.setColor(255,255,255,255)
		love.graphics.setCanvas()
		love.graphics.draw(self.visibleImage,(self.player.x - (love.graphics.getWidth() / 2)),(self.player.y - (love.graphics.getHeight() / 2)),0,16,16)

		self.player.anims[self.player.currentAnim]:draw(
			plsprite,
			math.floor(self.player.x),
			math.floor(self.player.y),
			0,2,2,
			self.player.ox,
			self.player.oy)
	end
EDIT: I've gotten my drawing stuff working! ...mostly. I managed to get things working first with the method that cvai posted. Then I moved stuff around till the drawing order was correct. Now i'm dealing with translation funny business. Right now everything draws, but the points that are supposed to match the tiles are misaligned. It looks like the screenshot below. The "halo" should be centered around the player, but it's off somehow. If anyone wants to take a shot at fixing it, it'd help a lot. I've updated the .love file.
Attachments
sndbug.png
sndbug.png (191.01 KiB) Viewed 2553 times
SND.love
(1.21 MiB) Downloaded 96 times
Last edited by BathtubAmbassador on Fri Jul 08, 2016 12:41 am, edited 1 time in total.
cval
Citizen
Posts: 58
Joined: Sun Apr 20, 2014 2:15 pm
Location: Ukraine

Re: SetCanvas() breaks drawing when using Tiled/STI

Post by cval »

It's way more reliable to store current canvas into local variable before your new setCanvas call and at the end set it as current after all draw procedures.

Code: Select all

local prevcanvas = love.graphics.getCanvas()
love.graphics.setCanvas(mycanvas)
-- draw my stuff on my other canvas
love.graphics.setCanvas(prevcanvas)
And boom, you have code that safely does what it does and doesn't break anything. Basically same applies to any color changes in draw calls - first you store current and at the end restore it. Not sure if shaders require that too, since there arent many cases where you have lots and lots of shader passes in one draw loop.. So in your case just put getCanvas just after the slayer:draw() line, and call setCanvas at the end of the function. Hope it helps.
BathtubAmbassador
Prole
Posts: 7
Joined: Thu Jul 07, 2016 8:11 pm

Re: SetCanvas() breaks drawing when using Tiled/STI

Post by BathtubAmbassador »

I just tried it and the character shows up again. Thanks a bunch, I was thinking I was gonna have to move all that code out of the layer draw function and make a bunch of variables global and such and such. Still working on making the canvas draw in the right position. I will upload a corrected version as soon as I finish so people have an example to look at.
User avatar
zorg
Party member
Posts: 3468
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: SetCanvas() breaks drawing when using Tiled/STI

Post by zorg »

Alternate, and frankly, less error-prone way:
[wiki]love.graphics.push[/wiki]('all') stores graphics state, including color, bgcolor, blendmode, active shader, active canvas;
[wiki]love.graphics.pop[/wiki]() will restore everything back to what it was so there's no need to get/set these properities by hand...

Unless one wants to prematurely optimize things, that is. :3

Also, to address the OP, it's a bit murky to me what you want to accomplish, but this line is sticking out to me a bit:

Code: Select all

love.graphics.draw(self.visibleImage,(self.player.x - (love.graphics.getWidth() / 2)),(self.player.y - (love.graphics.getHeight() / 2)),0,16,16)
right after you set the active canvas to be the screen; those 16,16 values in the scale make it 16 times bigger, so if you wanted 1/16th size, then you'd need to put 1/16 in there.
Also, if your canvas is the same size as the window, you'd want to draw it to 0,0. If not, then you'd want to draw anything -to- the canvas at 0,0. Either or works, both will not give you what you might expect... that said, i am only guessing at this time.
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.
BathtubAmbassador
Prole
Posts: 7
Joined: Thu Jul 07, 2016 8:11 pm

Re: SetCanvas() breaks drawing when using Tiled/STI

Post by BathtubAmbassador »

To clarify, the canvas is defined as being 1/16th the screen size. I then stretch it to fill the rest of the screen after I draw one pixel per tile. I'm trying to create a dimming effect for areas not within the "line of sight" of the object.

Anyway, still trying to figure out what's going on with my canvas rendering location.

EDIT: Also, the new, less clunky version of the code zorg quoted is:

Code: Select all

love.graphics.setBlendMode("alpha","premultiplied")
love.graphics.draw(map1.layers["Sprites"].visibleImage,0,0,0,16,16)
love.graphics.setBlendMode("alpha")
I think I can just have the location be 0,0 now because the statement is before I use love.graphics.translate() to scroll around. The canvas still isn't showing up though, even though the code executes. Any ideas?
Post Reply

Who is online

Users browsing this forum: Bing [Bot] and 7 guests