Code archives/Graphics/Fast Fading

This code has been declared by its author to be Public Domain code.

Download source code

Fast Fading by Koriolis2003
Doing effect such as fade to black (or fade to another image) is not very efficient if done in pure 2D, as it requires for each frame of the fading to modifye each pixel. Here is an alternative way of doing cool fading effects that is on my computer 320 times faster than brute force alpha blending!
The idea is to have a gray bitmap that drives the way the two images are merged. In this example I have put 3 methods:
1) the brute force alpha blended fading
2) the brute force "new" fading method
3) the optimized "new" fading method
Also the the gray bitmap here is procedural (it's a spiral pattern, with random paramaters giving different results each time), but the intent is really to use a bitmap that you have created in your favorite 2D tool. Try to mess with the filters of Photoshop, you can get interesting results.

The functions of interest here are CreateFastFadingPattern that preprocesses the gray level image (the "fading pattern") and creates a bank holding the data, and DrawFastFading that actually draws a frame of the fading sequence (there are 256 frames, one for each level of gray).
Last word: to see how fast this really is, deactivate vertical sync when asked.
Enough of boring talking, you'll see by yourself.

NB: don't forget to modify the lines
img1% = LoadImage("adobe.jpg")
img2% = LoadImage("MossyGround.bmp")
to point tou your own images.
; === Fast Fading by Koriolis ===

; Brute force alpha blended fading
; Could still be enhanced a bit by storing the image information in an array
Function DrawAlphaFading(alpha%, img1%, img2)
	; NB: img1 and img2 must have the same dimensions
	alpha_inv% = 255 - alpha
	SetBuffer(BackBuffer())
	w% = ImageWidth(img1)-1
	h% = ImageHeight(img1)-1
	img1Buf% = ImageBuffer(img1)
	img2Buf% = ImageBuffer(img2)
	LockBuffer(BackBuffer())
	LockBuffer(img1Buf)
	LockBuffer(img2Buf)
	For i = 0 To w
		For j = 0 To h
			c1% = ReadPixelFast(i, j, img1Buf)
			c2% = ReadPixelFast(i, j, img2Buf)
			r% = (((c1 And 255) * alpha) + ((c2 And 255) * alpha_inv)) Shr 8
			g% = ((((c1 Shr 8) And 255) * alpha) + (((c2 Shr 8) And 255) * alpha_inv)) Shr 8
			b% = ((((c1 Shr 16) And 255) * alpha) + (((c2 Shr 16) And 255) * alpha_inv)) Shr 8
			WritePixel(i, j, r Or (g Shl 8) Or (b Shl 16))
		Next
	Next
	UnlockBuffer(img1Buf)
	UnlockBuffer(img2Buf)
	UnlockBuffer(BackBuffer())
End Function

; brute force "new" fading
Function DrawSlowFading(grayLevel%, img%, mixMap%)
	SetBuffer(BackBuffer())
	w% = ImageWidth(img)-1
	h% = ImageHeight(img)-1
	imgBuf% = ImageBuffer(img)
	mixMapBuf% = ImageBuffer(mixMap)
	LockBuffer(BackBuffer())
	LockBuffer(imgBuf)
	LockBuffer(mixMapBuf)
	For i = 0 To w
		For j = 0 To h
			a% = ReadPixelFast(i, j, mixMapBuf) And 255
			If a = grayLevel Then				
				WritePixelFast(i, j, ReadPixelFast(i, j, imgBuf))
			EndIf
		Next
	Next
	UnlockBuffer(mixMapBuf)
	UnlockBuffer(imgBuf)
	UnlockBuffer(BackBuffer())
End Function


Dim CFFP_counts%(256)
Function CreateFastFadingPattern%(fadingImg%)
	w% = ImageWidth(fadingImg)
	h% = ImageHeight(fadingImg)
	bank% = CreateBank(w*h*4 + 1028)
	For layer = 0 To 256
		CFFP_counts(layer) = 0
	Next
	fadingImgBuf% = ImageBuffer(fadingImg)
	w = w - 1
	h = h - 1
	LockBuffer(fadingImgBuf)
	For i = 0 To w
		For j = 0 To h
			a% = (ReadPixelFast(i, j, fadingImgBuf) And 255) + 1
			CFFP_counts(a) = CFFP_counts(a) + 4
		Next
	Next
	PokeInt(bank, 0, CFFP_counts(0))
	For layer = 1 To 256
		CFFP_counts(layer) = CFFP_counts(layer) + CFFP_counts(layer-1)
		CFFP_counts(layer-1) = CFFP_counts(layer-1) + 1028
		PokeInt(bank, layer Shl 2, CFFP_counts(layer))
	Next
	CFFP_counts(256) = CFFP_counts(256) + 1028
	For i = 0 To w
		For j = 0 To h
			a% = ReadPixelFast(i, j, fadingImgBuf) And 255
			PokeShort(bank, CFFP_counts(a), i)
			PokeShort(bank, CFFP_counts(a)+2, j)
			CFFP_counts(a) = CFFP_counts(a) + 4
		Next
	Next
	UnlockBuffer(fadingImgBuf)
	Return bank
End Function

; optimized "new" fading
Function DrawFastFading(grayLevel%, img%, fadingPattern%)
	SetBuffer(BackBuffer())
	st% = PeekInt(fadingPattern, grayLevel Shl 2)
	en% = PeekInt(fadingPattern, (grayLevel+1) Shl 2) - 1
	imgBuf% = ImageBuffer(img)
	LockBuffer(BackBuffer())
	LockBuffer(imgBuf)
	For ofs = st To en Step 4
		i% = PeekShort(fadingPattern, ofs)
		j% = PeekShort(fadingPattern, ofs + 2)
		WritePixel(i, j, ReadPixelFast(i, j, imgBuf))
	Next
	UnlockBuffer(imgBuf)
	UnlockBuffer(BackBuffer())
End Function


;============================ little test ===============================

Graphics 256,256,16,2

; TODO: replace these images by two 256x256 images of your own
img1% = LoadImage("adobe.jpg")
img2% = LoadImage("MossyGround.bmp")

frame% = 0

vsync% = Lower(Input("VSync ? (y/n) "))="y"
Print("")
Print("1) Alpha blended fading, slooow")
Print("2) Slow fading (almost as slow)")
Print("3) Fast fading (really fast)")
Select Input("Select method ")
	Case 1
		Color 0,0,255
		While Not KeyHit(1)
			If (frame And 255) = 0 Then
				DrawImage(img1, 0, 0)
				startMS% = MilliSecs()
			EndIf
			DrawAlphaFading(frame And 255, img1, img2)
			Flip(vsync)
			frame = frame + 1
			If (frame And 255) = 255
				Cls
				Print "Duration : " + (MilliSecs() - startMS) + " ms"
			EndIf
			Wend

	Case 2
		Color 0,0,255
		While Not KeyHit(1)
			If (frame And 255) = 0 Then
				If mixMap <> 0 Then FreeImage(mixMap)
				mixMap% = CreateTestFadingImage(2*Rand(-3,3), Rnd(0, 20))
				DrawImage(mixMap, 0, 0)
				Text 128, 5, "Press a key", True
				Flip()
				WaitKey()
				startMS% = MilliSecs()
			EndIf
			DrawSlowFading(frame And 255, img2, mixMap)
			Flip(vsync)
			frame = frame + 1
			If (frame And 255) = 255
				Cls
				Print "Duration : " + (MilliSecs() - startMS) + " ms"
			EndIf
			Wend

	Case 3
		Color 0,0,255
		While Not KeyHit(1)
			If (frame And 255) = 0 Then
				If mixMap <> 0 Then FreeImage(mixMap)
				mixMap% = CreateTestFadingImage(2*Rand(-3,3), Rnd(0, 20))
				fadingPattern% = CreateFastFadingPattern(mixMap)
				DrawImage(mixMap, 0, 0)
				Text 128, 5, "Press a key", True
				Flip()
				WaitKey()
				DrawImage(img1, 0, 0)
				startMS% = MilliSecs()
			EndIf
			DrawFastFading(frame And 255, img2, fadingPattern)
			Flip(vsync)
			frame = frame + 1
			If (frame And 255) = 255
				Cls
				Print "Duration : " + (MilliSecs() - startMS) + " ms"
			EndIf
		Wend
		FreeBank(fadingPattern)

		Default Print "Invalid option, quiting..."
				Delay(2000)
				End
	End Select
End


Function CreateTestFadingImage%(coeff#, swirlStrength#)
	coeff = coeff*255.0/360.0
	img% = CreateImage(256,256)
	imgBuf% = ImageBuffer(img)
	LockBuffer(imgBuf)
	For i = 0 To 255
		For j = 0 To 255
			c% = ((ATan((i-128)/(j-128.5))*coeff) + swirlStrength*Sqr((i-128)*(i-128)+(j-128)*(j-128))) And 255
			WritePixelFast(i, j, c * $010101, imgBuf)
		Next
	Next
	UnlockBuffer(imgBuf)
	Return img
End Function

Comments

None.

Code Archives Forum