Circle in & circle out effect

BlitzMax Forums/BlitzMax Programming/Circle in & circle out effect

Hi all,

I'm trying to create a transition effect where the screen is wiped to black by a circle that zooms to the center. To clarify, when the effect starts, the circle is larger than the screen and keeps reducing in size to the point where there is a single pixel in the middle. At the 1/2 way point you would have 1/2 the screen in the middle still visible within the circle, everything outside the circle would be black.

I hope I've been clear in trying to explain the effect, it if helps I think batman (the TV series had a similar effect except the circle was the batman logo?

My problems are:

1) Pixmaps are too slow to draw a circle mask each frame
2) How does one draw an 'inverse circle' quickly ? i.e. a rect with a circle punched out of the middle

Can anyone think of an easy way to achieve this effect keeping in mind that I would like to keep the game animating while the transition is in progress (i.e. the effect should make minimal use of resources)

Anyhow - I look forward to any help that you can provide.

It seems that writing the above question helped me answer it, in particular - the description of 'circle punched out of the middle of a rect' gave me an idea.

How I've achieved the effect is quite simple in the end; I make a masked image with a circle punched out of the middle, draw this image over the everything (scaled) and then draw rects on all sides of it - I've included the code for anyone that's interested.


' circle mask effect

Graphics 640,480,0
AutoMidHandle True
'create the mask image
Local timask=CreateImage(640,480,1,MASKEDIMAGE | DYNAMICIMAGE | FILTEREDIMAGE)
'set mask color to white
SetMaskColor 255,255,255
'draw white circle on black b/g
SetColor 255,255,255
DrawOval 0,0,640,480
'grab background into timask
GrabImage timask,0,0

Local done:Int=False
Local sc:Float=2

Repeat
	Cls
	For a=1 To 5000
		SetColor Rand(1,255),Rand(1,255),Rand(1,255)
		Plot Rand(1,640),Rand(1,480)
	Next

		'reduce scale of mask
	sc=sc-.01

	'draw boxes on either side of circle mask
	SetScale 1,1
	SetColor 0,0,0
	DrawRect 0,0,640,ImageHeight(timask)/2-(ImageHeight(timask)/2*sc)
	DrawRect 0,ImageHeight(timask)/2+(ImageHeight(timask)/2*sc),640,480
	DrawRect 0,0,ImageWidth(timask)/2-(ImageWidth(timask)/2*sc),480
	DrawRect ImageWidth(timask)/2+(ImageWidth(timask)/2*sc),0,640,480
	


	'draw circle mask
	SetScale sc,sc
	SetColor 255,255,255
	DrawImage timask,ImageWidth(timask)/2,ImageHeight(timask)/2
	
	Flip
	If KeyDown(key_escape) Then done=True
Until done=True



Clever!

Or you can use DrawPoly, like this:
' circle fade out effect
Graphics 640,480,0

Local done:Int=False
Local size:Float = 800

Repeat
	Cls
	For a=1 To 5000
		SetColor Rand(1,255),Rand(1,255),Rand(1,255)
		DrawRect Rand(1,640),Rand(1,480),4,4
	Next

	' reduce scale of mask
	size :- 4

	' draw boxes on either side of circle mask
	SetColor 0,0,0
	DrawCircleBox(0,0,GraphicsWidth(),GraphicsHeight(),size,size)
	
	Flip
	If KeyDown(key_escape) Then done=True
Until done=True


Function DrawCircleBox(x:Float,y:Float,w:Float,h:Float,radiusx:Float,radiusy:Float,stp:Int = 8)

	Local xy:Float[6]

	Local cx:Float = x+w*0.5
	Local cy:Float = y+h*0.5

	For Local quad:Int = 0 To 3
		Local offset:Int = 0
		
	 	Select quad
			Case 0
				xy[0] = x
				xy[1] = y
				offset = 0
			Case 1
				xy[0] = x+w
				xy[1] = y
				offset = -90
			Case 2
				xy[0] = x+w
				xy[1] = y+h
				offset = 180			
			Case 3
				xy[0] = x
				xy[1] = y+h
				offset = 90
		EndSelect
	
		For Local i:Int = 0 To 90/stp
			Local j:Int = i*stp + offset
		
			xy[2] = cx - Sin(j)*radiusx
			xy[3] = cy - Cos(j)*radiusy

			xy[4] = cx - Sin(j+stp)*radiusx
			xy[5] = cy - Cos(j+stp)*radiusy
		
			DrawPoly(xy)
		Next
	Next

	Local dy:Float = (h*0.5)-radiusy
	Local dx:Float = (w*0.5)-radiusx

	DrawPoly([x,y,cx,y+dy,x+w,y])
	DrawPoly([x,y+h,cx,y+h-dy,x+w,y+h])
	DrawPoly([x,y,x+dx,cy,x,y+h])
	DrawPoly([x+w,y,x+w-dx,cy,x+w,y+h])

End Function


The way I do this in OpenGL is pre-draw a screen full of circles, starting with the biggest diameter and working down, changing the color value by 1 for each circle, and only drawing 256 circles in total. I save this as an alpha pixmap and upload it as a GL_ALPHA texture. Then I switch off drawing to alpha, but draw a textured quad over the screen with the alpha texture map, set up so that bits greater than a given value are drawn to the stencil buffer. Then I draw the `game screen`, taking the stencil into account so that only pixels not stencilled are drawn. This way you can do per-pixel wipes (hint: distort the image containing the circles).