Anyone know how to do an "iris"?

BlitzPlus Forums/BlitzPlus Programming/Anyone know how to do an "iris"?

WoeIsMe(Posted 2003) [#1]
You know in cartoons, where at the end, a black ring closes in on the screen (called an iris if you didn't know), showing a smaller and smaller ring of the screen until the screen is completely black. I want to do one of these for when you die in Alf the Elf II. I already have a rectangular one that looks quite good, but does anyone know how to do a circular one that doesn't slow down the game much? Here's my code for the rectangle, should anyone be interested:

;death\dietime=death\dietime+1 is somewhere earlier in the code
Color 0,0,0
Rect 0,0,800,(death\dietime)-100
Rect 0,600-(death\dietime)+100,800,death\dietime
Rect 0,0,(death\dietime*1.25)-100,600
Rect 800+100-(death\dietime*1.25),0,(death\dietime*1.25),600



Binary_Moon(Posted 2003) [#2]
I'd create an image the same size as the screen in a nice bright colour (255,0,255) - let's call it mask_image. I'd then draw a circle onto mask_image (the iris) in green say.

Set the mask colour for mask_image to the same green you drew the iris as.

Grab a copy of the image you want to 'iris out' (the screen) which I will call screen_image. Set screen_image to use the magenta colour for its mask colour then draw the mask_image onto screen_image. The magenta will obscure the border but the circle should still be visible since it has been made transparent.

Draw screen_image to the screen and you should get a circle of the image visible. You can then just repeat the steps above (only need to get screen_image once) making the circle smaller each time.

Does that make sense?

Haven't got a clue how fast this will be but I suspect it will actually work quite fast and I may just use it myself :) since it will probably be the only thing running you shouldnn't have a problem


sswift(Posted 2003) [#3]
There's a ton of ways you could do this.

None of them are super easy to do though. It will take some optimization to make it fast.

You've basically got two equations you can use to draw a circle, plus the bresenham circle algorithm, but I'm not gonna explain that. :-)

The first is to use the cartesian to polar coordinates equations:

X = Radius * Cos(Angle)
Y = Radius * Sin(Angle)

For a circle of a specific radius, you can use that to find all points around the border of the circle.

Or, you can rearrange the equation to find the two X coordinates for the edges of the circle at a particular Y coordinate. Which is what you would want to do to "rasterize" a circle so you can draw it with a series of horizontal lines on the screen. Or as an outline.


Another way to calculate a circle is to use the distance equation:

RadiusSquared = Radius*Radius
DistanceSquared = ((CX-X)*(CX-X) + (CY-Y)*(CY-Y))
If (DistanceSquared < RadiusSquared) Then this pixel is inside the circle.

CX, CY is the location of the center of the screen.

You can do that for each pixel of the screen, decreasing the radius each time, and if the radius is greater than a certain value, or between a set of values, you can set the pixel black.

This might be the easiest method for you to implment.

If you want to do this, then what you'd do is first find the distance from the center of the screen to the pixel in the corner of the screen. This is the largest you need to draw your circle.

You only need the square of the distance, so just go:

CornerDistanceSquared = ((GraphicsWidth()/2)^2 + (GraphicsHeight/2)^2)

You'll note this is a ltitle diffrent from the distance equation above. That's cause I decideed to get the location of the 0,0 corner pixel, which allowed me to simplify the equation.

Once you have that corner distance, you know the largest you need to draw your circle. This is the radius at which you start drawing an outline circle.

So what you do then is you set Radius to this value. Then for each pixel in the screen, do this:

InnerRadiusSquared# = (Radius#-0.5)*(Radius#-0.5)
OuterRadiusSquared# = (Radius#+0.5)*(Radius#+0.5)
DistanceSquared# = ((CX-X)*(CX-X) + (CY-Y)*(CY-Y))

If (DistanceSquared# > InnerRadiusSquared#) and (DistanceSquared# < OuterRadiusSquared) Then set this pixel to be black.


And then you just keep decreasing the radius one unit at a time.

What this does is it fills pixels which are between an inner radius and an outer radius. You need to fill pixels within two radiuses rather than just at the radius because if you just fill at the radius some pixels will be missed. This will ensure that as you draw circles of decreasing size that the circles will fill all the pixels. You may even be able to use a value of less than 0.5 for the radius size. If you can then you will fill fewer pixels extra times and the algorithm will go faster.

This isn't the fastest way to do it, but it should be fast enough for your needs.


sswift(Posted 2003) [#4]
Oh and I almost forgot, there's a bunch of code on BlitzCoder which does screen transitions. And some of them are circles, and some are squares and some are checkerboards. It's really cool and fast, and it's exaclty the sort of thing you need. All you need to do is specify that the destination image is black.


Floyd(Posted 2003) [#5]
Instead of drawing pixels I would just draw circles.
It's inefficient in the sense that each pixel is drawn many times.
But who cares?
Graphics 800, 600

dot = CreateImage(20,20)
SetBuffer ImageBuffer(dot)
Color 0, 0, 255
Oval 0,0, 20,20

r# = Sqr(400*400 + 300*300)
phase# = 1
SetBuffer BackBuffer()

While r > 0
	
	For angle# = 0 To 358 Step 2

		a# = angle + phase
		x# = 400+r*Cos(a)
		y# = 300+r*Sin(a)	

		DrawImage dot,  x-10, y-10

	Next
	Flip	

	phase = 1 - phase
	r = r - 2.5
	
	CopyRect 0,0, 800,600, FrontBuffer(), BackBuffer()

Wend
WaitKey
End

The phase is just a trick for alternately drawing even and odd angles.
It makes things look a little smoother.


cyberseth(Posted 2003) [#6]
Here is a link to my code for realtime full-screen transitions like iris, checkerboard, etc...

http://www.christianaupairs.com/seth/transitions.zip


Oldefoxx(Posted 2003) [#7]
Since you are considering creating an "iris" effect, you can create a more mechanical approach by considering the nature of a mechanical iris. It is not a perfect circle, but rather a apperature that uses overlapping segments to close of more and more of the opening. Suppose you created a six-sided figure at the extreme limits of the screen. Each segment would enclose an angle of 120 degrees. You then rotate the figure by say, five degreesm and make it slightly smaller so that each point touches a line segment on the first. You do a fill to each triangle produced, then rotate another five degrees, and create another figure inside the second, again just touching at a point on the second figure. Then a fourth figure rotated another five degrees and reduced to fit at the points inside the third. You get a spiral effect, and each fill makes the iris smaller and blends it with the previous figures thus created.