Dynamic dropshadow

BlitzMax Forums/BlitzMax Beginners Area/Dynamic dropshadow

I want to create a (non windows-like) popup menu with a drop shadow. The size of the popup can vary so it's no option of having a fixed size drop shadow png-file.
Furthermore, I want to have the blur amount of this drop shadow to be variable.
Any ideas?

O, and I'm happy to have a solution for rectangular popups, but it would be great to have a 'createDropShadow()' based on the alpha-channel of an image (for instance a rounded rectangle popup menu).

You can "blur" a second instance of your image...(if the menus are statically generated - grabimage/grabpixmap) and then use the blurimage-code out of the 'code archives' here on bm.com

This blurred image is then drawn before the menu ... set ShadeBlend - or how it is called - before. Setting Color to 50,50,50 and alpha 0.5 or so would do the same.

Just take attention of the image generated by the blur-function - it should use alpha-channel.


bye
MB

Set the drawing color to black, draw the window 8 pixels down and to the right, then set the drawing color back to white and draw it again at the normal location.

To make it blur, if you want it to be 3d accelerated, I don't think there is a way you can do a perfect gaussian or box blur without pixel shaders, but you can do a sort of approximation if you draw the shadow multiple times in different locations with a certain amount of alpha.

This code shows how to do this in Blitz3D:
http://www.blitzmax.com/codearcs/codearcs.php?code=754

Basically, just look at that to figure out what alpha you need to set and how to offset it.

The drawback of this method is you will tend to see circular indentations at the corners of the object.

Is it worth using this for the blur? (the function should really be 'cheapblur' rather than createbloom)?

I'd have initially suggested what sswift did, i.e. draw shadow several times with different alpha but I'm interest to see these other functions. Be nice if BMax had some of these built in.

Thanks for the replies.
It seems there is no 'out of the box' solution for this. Based on your suggestions, I will try to make a drop shadow code myself. If it's successful I'll post a demo.

Hint:

Draw a box with an alpha of 0.5 in the same place twice and it will draw the equivalent of 0.75.

You do not even need to change the alpha value!

How about something like this (Pseudocode)

For rounded corners:
setalpha 0.5
for Dist:int=36 to 0 step -5
   drawimage Image,x+(sin(dist*10)*angle),y+(cos(dist*10)*angle)
next


For a basic alpha'd edge:
Setalpha 0.1
For add#=10 to 0 step -2
   drawimage image,x+add,y+add
next


Write these in proper Max code and you should be able to do those shadows pretty easily.

Here is my blurred drop shadow demo:
If any of you can make this routine run (much) faster, please let me know!
I tried to make a pixmap with PF_A8 format for the alphachannel only. But that did not work because readpixel returns a 32 bit integer.
Anyway, here is the code (don't know how to include source code in a seperate scrollable text field).
Strict

Graphics 800, 600
AutoMidHandle(1)
SetClsColor 255,255,255

Const margin = 10
Local argbBlack:Int = (255 Shl 24)
Local argbWhite:Int = (255 Shl 24) + (255 Shl 16) + (255 Shl 8) + 255

Global rocket:Timage = LoadImage("gfx\blobship.png", DYNAMICIMAGE) 'or any other png file with alpha channel
Global rocketAlpha:TPixmap = CreatePixmap(rocket.width + margin * 2, rocket.height + margin * 2, PF_RGBA8888)
ClearPixels(rocketAlpha, 0)

Global shadow:TImage = CreateImage(rocketAlpha.width, rocketAlpha.height, DYNAMICIMAGE)


Global PixMap:TPixmap
pixmap = LockImage(rocket)
'copy alphaChannel from original image
For Local x:Int = 0 To rocket.width - 1
	For Local y:Int = 0 To rocket.height - 1
		Local a:Int = ReadPixel(pixmap, x, y)
		a = (a Shr 24) Shl 24   'remove RGB values
		WritePixel(rocketAlpha, x + margin, y + margin, a)
	Next
Next
UnlockImage(rocket)

SetAlpha 1
SetBlend ALPHABLEND
Local r:Int = 0 
Local fr:Float = 0
Local cx = 400
Local cy = 300
Local radius = 200

	pixmap = LockImage(shadow)
	blurImage(0.2 + fr * 0.8)
	UnlockImage(shadow)

While Not KeyHit(KEY_ESCAPE)

	Cls
	SetRotation 0
	SetColor 255, 0, 0
	DrawRect 150, 150, 300, 200
	SetRotation r + 180
   SetColor 255, 255, 255
	SetAlpha 0.4

Rem ******** remove rem to dynamically change the blur amount based on the altitude of the ship
	pixmap = LockImage(shadow)
	blurImage(0.2 + fr * 0.8)
	UnlockImage(shadow)
End Rem

	DrawImage shadow, cx+Cos(r) * radius + margin * (1-fr), cy + Sin(r) * radius + margin * (1-fr)
	SetAlpha 1
	DrawImage rocket, cx + Cos(r) * radius, cy + Sin(r) * radius
	r = (r+1) Mod 360
	fr = (Sin(r) + 1) / 2  'rotation between 0..1

	Flip
Wend

End


'*************** modified blurring functions *******************
Function blurImage(k:Float = 0.5)
	'k - blurring amount. Value between 0.0 and 1.0
	'	 0.1 = Extreme, 0.9 = Minimal 
	Local pm:TPixmap = CopyPixmap(rocketAlpha)

	For Local x:Int = 1 To (pm.Width - 1)
    	For Local z:Int = 0 To (pm.Height - 1)
			WritePixel(pm, x, z, blurPixel(ReadPixel(pm, x, z), ReadPixel(pm, x - 1, z), k))
    	Next
    Next

    For Local x:Int = (pm.Width - 3) To 0 Step -1
    	For Local z:Int = 0 To (pm.Height - 1)
			WritePixel(pm, x, z, blurPixel(ReadPixel(pm, x, z), ReadPixel(pm, x + 1, z), k))
    	Next
    Next

    For Local x:Int = 0 To (pm.Width - 1)
    	For Local z:Int = 1 To (pm.Height - 1)
			WritePixel(pm, x, z, blurPixel(ReadPixel(pm, x, z), ReadPixel(pm, x, z - 1), k))
    	Next
    Next

    For Local x:Int = 0 To (pm.Width - 1)
    	For Local z:Int = (pm.Height - 3) To 0 Step -1
			WritePixel(pm, x, z, blurPixel(ReadPixel(pm, x, z), ReadPixel(pm, x, z + 1), k))
    	Next
    Next

	For Local x:Int = 0 To pm.width - 1
		For Local y:Int = 0 To pm.height - 1
			Local a = ReadPixel(pm, x, y)
			WritePixel(pixmap, x, y, a)
		Next
	Next
	
End Function

'**************************************************************

Function blurPixel:Int(px:Int, px2:Int, k:Float)
					
	Local fpx:Float  = Float(px Shr 24)
	Local fpx2:Float = Float(px2 Shr 24)
				
	Return Int((fpx2 * (1 - k)) + (fpx * k)) Shl 24

EndFunction

'**************************************************************