Hello,
In my program, I’m using setContext to draw into an image, but here’s the problem: When I do that without setting the image variable to a blank image, it retains the previous image. Here’s the other problem: I need to keep the background alpha, so I can’t just draw an opaque rectangle behind it.
This image I’m using is the size of the screen, so when I set it to a blank image (“image(WIDTH,HEIGHT)”), it slows down the performance by about 3 times. I’ve tried to make a template blank image and set it to the image I want to clear every frame, but that doesn’t do anything.
Help would be great.
Thanks!
Maybe a shader will help. What exactly are you doing with the image and the alpha - it isn’t clear to me.
@Ignattz - Here’s my code I made so far:
displayMode(FULLSCREEN) function setup() parameter.watch("1/DeltaTime") fixtures = {} local gSize = vec2(WIDTH,HEIGHT/2) local gScale = 5 local funnleSize = 5 funnle1 = physics.body(CHAIN,false,vec2(-gSize.x,gSize.y), vec2(-funnleSize,-gSize.y/3), vec2(-funnleSize,-gSize.y) ) local funnle2 = physics.body(CHAIN,false,vec2(gSize.x,gSize.y), vec2(funnleSize,-gSize.y/3), vec2(funnleSize,-gSize.y) ) local split = physics.body(CHAIN,false,vec2(-WIDTH/2,-HEIGHT/8), vec2(0,HEIGHT/80), vec2(WIDTH/2,-HEIGHT/8) ) funnle1.x = WIDTH / 2 funnle1.y = HEIGHT - HEIGHT / 4 funnle1.type = STATIC funnle2.x = WIDTH / 2 funnle2.y = HEIGHT - HEIGHT / 4 funnle2.type = STATIC split.x = WIDTH / 2 split.y = HEIGHT/8 split.type = STATIC split.restitution = .3 table.insert(fixtures,funnle1) table.insert(fixtures,funnle2) table.insert(fixtures,split) blankImage = image(WIDTH,HEIGHT) blur = 30 water = {} waterimage = softImage(color(0, 155, 255),5,blur) allWater = blankImage --[[waterMesh = mesh() waterMesh.texture = waterimage]]-- mDisplay = mesh() mDisplay:addRect(WIDTH/2,HEIGHT/2,WIDTH,HEIGHT) mDisplay.shader = shader("Documents:Alpha Threshold") mDisplay.shader.smoothness = 0 mDisplay.shader.threshold = .1 mDisplay.shader.unpremultiply = 1 end function draw() background(0, 0, 0, 255) physics.gravity(Gravity/10) smooth() allWater = image(WIDTH,HEIGHT) print(allWater.data) setContext(allWater) noStroke() smooth() for i,v in ipairs(water) do sprite(waterimage,v.body.x,v.body.y,blur,blur) --waterMesh:addRect(v.body.x,v.body.y,blur*extraSpace,blur*extraSpace) if v.body.x <= 0 or v.body.x >= WIDTH or v.body.y <= 0 or v.body.y >= HEIGHT then v.body:destroy() table.remove(water,i) end end --waterMesh:draw() --waterMesh:clear() setContext() mDisplay.texture = allWater mDisplay:draw() strokeWidth(3) for i,v in ipairs(fixtures) do pushMatrix() translate(v.x,v.y) local points = v.points for j = 1,#points-1 do a = points[j] b = points[(j % #points)+1] line(a.x, a.y, b.x, b.y) end popMatrix() end popMatrix() end function touched(t) addWater(10,t.x,t.y) end function softImage(f,r,s) simg = image(r,r) setContext(simg) pushStyle() noStroke() fill(f) ellipse(simg.width/2,simg.height/2,simg.width) popStyle() setContext() limg = image(s,s) setContext(simg) pushStyle() smooth() sprite(simg,0,0,s,s) popStyle() setContext() return simg end function addWater(amnt,x,y) local posRand = 20 local vRand = 50 for i = 1,amnt do local b = physics.body(CIRCLE,2) b.x = x + math.random(-posRand,posRand) b.y = y + math.random(-posRand,posRand) b.linearVelocity = vec2(math.random(-vRand,vRand),math.random(-vRand,vRand)) b.restitution = .1 table.insert(water,{body = b}) end end ``` Thanks!
I couldnt find a way around this hurdle, i tried to set my image to a screen size image of 0 alpha pixels every way i could imagine but they didnt work, i just stuck with image(WIDTH,HEIGHT)
@Luatee - how about this
Forget about drawing a fullsize image on each draw, that will always be slow. Instead, add your water drops to a mesh (with the shader attached, of course), and on each draw, just update their x,y position, add and remove them, etc. Then just draw the mesh.
This avoids drawing the image twice (once to a hidden image and then to the screen).
PS you forgot to include the shader code, but I found it in another post because I recognised the code.
@Ignatz - The issue is that if I add the droplets to a mesh as rectangles, then the shader will only apply to each drop individually. Then you won’t get the water effect. If I could access the data aspect of the mesh, that’d be great, but I can’t. It returns nil.
@Zoyt - ok, then how about this
Instead of drawing a full screen image, you draw it exactly the size you need, by first looping through the drops and calculating the min and max x and y values. Then you draw to that size image. Below is my draw routine that does this. The drops don’t stay in the funnel for some reason, but it does seem faster
function draw()
background(0, 0, 0, 255)
physics.gravity(Gravity/10)
smooth()
--get min and max values
local minX,minY,maxX,maxY=9999,9999,0,0
for i,v in ipairs(water) do
if v.body.x>maxX then maxX=v.body.x end
if v.body.x<minX then minX=v.body.x end
if v.body.y>maxY then maxY=v.body.y end
if v.body.y<minY then minY=v.body.y end
end
if minX>0 then
--min and max values are at centre of drops, allow space for width of drop
minX,minY=minX-blur/2,minY-blur/2
maxX,maxY=maxX+blur/2,maxY+blur/2
--draw exact size of image required
local w,h=maxX-minX,maxY-minY
allWater = image(w,h)
setContext(allWater)
noStroke()
smooth()
for i,v in ipairs(water) do
--waterMesh:addRect(v.body.x,v.body.y,blur*extraSpace,blur*extraSpace)
if v.body.x <= 0 or v.body.x >= WIDTH or v.body.y <= 0 or v.body.y >= HEIGHT then
v.body:destroy()
table.remove(water,i)
else
--adjust position by minX, minY
sprite(waterimage,v.body.x-minX,v.body.y-minY,blur,blur)
end
end
setContext()
--adjust rectangle to minX, minY
mDisplay:setRect(1,minX-w/2,minY-h/2,w,h)
mDisplay.texture = allWater
mDisplay:draw()
end
strokeWidth(3)
for i,v in ipairs(fixtures) do
pushMatrix()
translate(v.x,v.y)
local points = v.points
for j = 1,#points-1 do
a = points[j]
b = points[(j % #points)+1]
line(a.x, a.y, b.x, b.y)
end
popMatrix()
end
popMatrix()
end
@Ignatz, that works well except for one thing. Change the following:
mDisplay:setRect(1,minX-w/2,minY-h/2,w,h)
To
mDisplay:setRect(1,minX+w/2,minY+h/2,w,h)
Now the water stays where it should.
Edit: something else is a bit funky too. When the first water drop goes off screen, it clears the whole image. Math.min and math.max functions will fix this, also removing the if statement with minx > 0.
function draw()
background(0, 0, 0, 255)
physics.gravity(Gravity/10)
smooth()
--get min and max values
local minX,minY,maxX,maxY=9999,9999,0,0
for i,v in ipairs(water) do
if v.body.x>maxX then maxX=v.body.x end
if v.body.x<minX then minX=v.body.x end
if v.body.y>maxY then maxY=v.body.y end
if v.body.y<minY then minY=v.body.y end
end
--min and max values are at centre of drops, allow space for width of drop
minX,minY=math.max(minX-blur/2,0),math.max(minY-blur/2,0)
maxX,maxY=math.min(maxX+blur/2,WIDTH),math.min(maxY+blur/2,HEIGHT)
--draw exact size of image required
local w,h=maxX-minX,maxY-minY
allWater = image(w,h)
setContext(allWater)
noStroke()
for i,v in ipairs(water) do
--waterMesh:addRect(v.body.x,v.body.y,blur*extraSpace,blur*extraSpace)
if v.body.x <= 0 or v.body.x >= WIDTH or v.body.y <= 0 or v.body.y >= HEIGHT then
v.body:destroy()
table.remove(water,i)
else
--adjust position by minX, minY
sprite(waterimage,v.body.x-minX,v.body.y-minY,blur,blur)
end
end
setContext()
--adjust rectangle to minX, minY
mDisplay:setRect(1,minX+w/2,minY+h/2,w,h)
mDisplay.texture = allWater
mDisplay:draw()
strokeWidth(3)
for i,v in ipairs(fixtures) do
pushMatrix()
translate(v.x,v.y)
local points = v.points
for j = 1,#points-1 do
a = points[j]
b = points[(j % #points)+1]
line(a.x, a.y, b.x, b.y)
end
popMatrix()
end
end
To answer the original question, use background
. This forces everything to the specified colour including alpha. So background(0,0,0,0)
makes the image transparent black.
@Andrew_Stacey I tried using background(0,0) with setContext before but it didn’t work, yours seems to work though
Unless you provide all four values, Codea assumes alpha is 255
Aha, that would be it, even though it comes up with grey,alpha it must ignore the alpha