Page 1 of 1
problem using stencil function
Posted: Thu Mar 17, 2022 8:29 am
by DebasishDatta
Code: Select all
function love.draw()
push:start()
love.graphics.setCanvas({canvas,stencil=true})
love.graphics.stencil(function()
love.graphics.rectangle('fill',VIRTUAL_WIDTH/2 - 40,VIRTUAL_HEIGHT/2 - 10, 30,30)
end,'replace',1,false)
love.graphics.setStencilTest('less',1)
love.graphics.draw(Ctexture,Cquads[1],posX,posY)
love.graphics.setStencilTest()
love.graphics.setCanvas()
push:finish()
end
Here I am trying to use stencil and my target is, when the character is inside the stencil area he should not be visible and for rest area normal screen display will take place, i.e character will be displayed in the screen normally, but the result of above code is something different, it is drawing the character in the stencil area. As a result small display is taking place with the character that to the area drawn by the rectangle inside stencil function. kindly help.
Re: problem using stencil function
Posted: Fri Mar 18, 2022 12:14 am
by pgimeno
You can use other compare mode instead of 'less', check
CompareMode. If you want the opposite of what you currently have, you can try 'gequal'.
Re: problem using stencil function
Posted: Fri Mar 18, 2022 5:09 am
by DebasishDatta
Thank you for your reply, I have tried with 'gequal', but it does not work, I thing the problem is that the stencil buffer is not getting synchronized with canvas, is there any other way to set stencil = true other than using setCanvas? or other way to use the stencil?
Re: problem using stencil function
Posted: Sat Mar 19, 2022 2:02 am
by pgimeno
Can you post a complete runnable example? It doesn't need to be your full project, just enough code to be able to run it and see the problem. It might be easy from the code above, but I don't have time right now to try, and after all you're the one who wants help
Re: problem using stencil function
Posted: Sat Mar 19, 2022 2:59 pm
by DebasishDatta
Code: Select all
push = require 'push'
VIRTUAL_WIDTH = 384
VIRTUAL_HEIGHT = 216
WINDOW_HEIGHT = 720
WINDOW_WIDTH = 1280
WALK_SPEED = 40
function love.load()
push:setupScreen(VIRTUAL_WIDTH,VIRTUAL_HEIGHT,WINDOW_WIDTH,WINDOW_HEIGHT,{
fullscreen = false,
vsync = true,
resizable = true
})
Ctexture = love.graphics.newImage('entities.png')
Cquads = GenerateQuads(Ctexture,16,16)
posX = VIRTUAL_WIDTH/2
posY = VIRTUAL_HEIGHT/2
love.keyboard.keyPressed = {}
canvas = love.graphics.newCanvas()
end
function love.keypressed(key)
love.keyboard.keyPressed[key] = true
end
function love.keyboard.wasPressed(key)
return love.keyboard.keyPressed[key]
end
function love.update(dt)
if love.keyboard.wasPressed('escape') then
love.event.quit()
end
if love.keyboard.isDown('up') then
posY = posY - WALK_SPEED * dt
end
if love.keyboard.isDown('down') then
posY = posY + WALK_SPEED * dt
end
if love.keyboard.isDown('left') then
posX = posX - WALK_SPEED * dt
end
if love.keyboard.isDown('right') then
posX = posX + WALK_SPEED * dt
end
love.keyboard.keyPressed = {}
end
function love.draw()
push:start()
love.graphics.setCanvas{canvas,stencil = true}
--love.graphics.setCanvas(canvas)
love.graphics.stencil(function()
love.graphics.rectangle('fill',VIRTUAL_WIDTH/2 - 40,VIRTUAL_HEIGHT/2 - 10, 60,60)
end,'replace',1,false)
love.graphics.setStencilTest('gequal',0)
love.graphics.draw(Ctexture,Cquads[1],posX,posY)
love.graphics.setStencilTest()
love.graphics.setCanvas()
--love.graphics.draw(Ctexture,Cquads[1],posX,posY)
push:finish()
end
function GenerateQuads(atlas,tileWidth,tileHeight)
local sheetWidth = atlas:getWidth()/tileWidth
local sheetHeight = atlas:getHeight()/tileHeight
local sheetCounter = 1
local spriteSheet = {}
for y = 0, sheetHeight - 1 do
for x = 0, sheetWidth - 1 do
spriteSheet[sheetCounter] = love.graphics.newQuad(x * tileWidth, y * tileHeight,
tileWidth, tileHeight, atlas:getDimensions())
sheetCounter = sheetCounter + 1
end
end
return spriteSheet
end
In the above code I have tried to do exactly what I want, I want that when character enters the area defined by the rectangular area inside stencil function does not render to the screen. I have other alternative, in program I can set a flag for this, but I want to use stencil for this. Can you please help.
Re: problem using stencil function
Posted: Sat Mar 19, 2022 9:05 pm
by ReFreezed
Your original code with love.graphics.setStencilTest('less',1) is correct if you want to draw everywhere except in that rectangle. However, you draw Ctexture to a canvas but you don't draw the canvas anywhere after that (which makes your wording confusing because you shouldn't be able to see anything at all ever).
Also note that push:start() sets its own canvas, and when you call love.graphics.setCanvas() you potentially ruin whatever the push library is doing. You can solve this by calling love.graphics.push("all") before you call love.graphics.setCanvas(canvas), and call love.graphics.pop() instead of love.graphics.setCanvas(). However, it's not clear from the given code if you need your own canvas here at all as, by looking at the push library code, stencils are enabled by default when calling push:start().
(Also, next time you post your code, please post a runnable example - e.g. a .love file that includes libraries and images being used. It just wastes everyone's time trying to guess what is needed to get the code to run.)
Edit: Added correction to error pointed out by pgimeno.
Re: problem using stencil function
Posted: Sat Mar 19, 2022 10:26 pm
by pgimeno
ReFreezed wrote: ↑Sat Mar 19, 2022 9:05 pmYou can solve this by calling love.graphics.push()
Correction:
love.graphics.push("all")
before you call love.graphics.setCanvas(canvas), and call love.graphics.pop() instead of love.graphics.setCanvas().
But I recommend saving the canvas and restoring it instead of using push/pop:
Code: Select all
local saveCanvas = love.graphics.getCanvas()
love.graphics.setCanvas(myCanvas)
-- draw stuff, then:
love.graphics.setCanvas(saveCanvas)
I haven't looked into the code to be sure, but love.graphics.push("all") is probably somewhat overkill when only a handful of things have changed.
Re: problem using stencil function :) Problem resolved
Posted: Tue Mar 22, 2022 4:34 am
by DebasishDatta
Thank you pgimeno and ReFreezed , your suggestions were very helpful, restoring the canvas solved my problem and my program has started behaving the way I wanted. I understand that, I have wasted your time by not posing .love file along with the .png files. In future post I will certainly do that. I have a little doubt here, By using getCanvas() whether we are getting the reference of the canvas set by push? and after I draw the graphics again I am restoring the canvas initiated by push function? Is my understanding correct? if not can you please explain which canvas we are getting by using getCanvas() function. In this context I want to mention that, I have not used push:start("all")
Re: problem using stencil function
Posted: Tue Mar 22, 2022 5:24 pm
by ReFreezed
If we look at the definition of push:start() we see that it calls love.graphics.setCanvas(), so when you call love.graphics.getCanvas() after calling push:start() you get the canvas that push:start() set. So yes, you understand correctly.
push:start("all") is not a thing - the push:start() function does not take any arguments. I'm assuming you meant love.graphics.push("all").