Translucency in 2D

BlitzPlus Forums/BlitzPlus Programming/Translucency in 2D

binarydecay(Posted 2003) [#1]
Hi all, just bought B3D and this is my first post!

I've been working on a retro style rpg game, like a modernised version of the old Moria games :). The reason I write using 2D is because I can't get my head around 3D modelling (at least not complicated models like humans), but I want to be able to do cool effects like alpha channels with 2D blits.

I understand fully that DirectDraw doesn't support this feature natively. I also understand that you can cheat and use Direct 3D somehow... maybe using sprites perhaps?

Basically if I want to draw a 32x32 image at x, y on the screen with say 80% opacity is it possible? I don't want to maintain the sprite, just dump a copy of it on screen like with DrawImage.

I had a play with a trial version of *cough* DarkBasic and this manages to do hardware accelerated 2D style sprites with translucency, but I don't even need anything this complicated - as I said I just want to draw it on the screen and forget about it without having a sprite object present.

I thought about using a complex pixel based algorithm to do it, but I am thinking it would be way too slow.

So... is it possible in B3D?


AL(Posted 2003) [#2]
As far as i know you have you would have to use a sprite, or maybe a textured quad to do this with hardware.

There was a function going around a long time ago that could do this in blitz2d, can't find it in the code archives so here is the one on my harddisk (it does hit the CPU hard though):

Function draw_alpha(image%, x%, y%, alpha#)

  ; if the opacity is 100% then no point in rendering the opaque image
  ; just draw original image
  If alpha# >= 1 Then
    han_x% = ImageXHandle(image%)
    han_y% = ImageYHandle(image%)
    HandleImage image%, 0, 0
    DrawImage image%, x%, y%
    HandleImage image%, han_x%, han_y%

  ; else if the opacity is greater than zero (if less the 0 don't bother drawing it!)
  Else If alpha# > 0 Then

    nalpha# = 1 - alpha# 

    ; Lock the buffers
    LockBuffer BackBuffer()
    LockBuffer ImageBuffer(image%)

    ; Loop through each pixel in the image, 
    ; To create New opaque image pixel by pixel
    For xx% = 0 To ImageWidth(image%)
      For yy% = 0 To ImageHeight(image%)

        ; Get colors from sprite pixel
        rgb1% = ReadPixelFast(xx%, yy%, ImageBuffer(image%))

        If rgb1% <> 0 Then
          r1% = ((rgb1 And 16711680) Shr 16)
          g1% = ((rgb1 And 65280) Shr 8)
          b1% = (rgb1 And 255)

          rgb2% = ReadPixelFast(xx + x, yy + y, BackBuffer())

          r2% = ((rgb2 And 16711680) Shr 16)
          g2% = ((rgb2 And 65280) Shr 8)
          b2% = (rgb2 And 255)

          ; Calculate the color of the new opaque pixel and draw pixel to new image
          r3 = r1%*alpha# + r2%*nalpha#
          g3 = g1%*alpha# + g2%*nalpha#
          b3 = b1%*alpha# + b2%*nalpha# 
          WritePixelFast(xx + x, yy + y, ((r3 Shl 16) + (g3 Shl 8) + b3), BackBuffer())
        End If

      Next
    Next
  
    ; Unlock the buffers
    UnlockBuffer BackBuffer()
    UnlockBuffer ImageBuffer(image%) 

  End If

End Function



Ross C(Posted 2003) [#3]
Hey! Are you meaning you just want transparency once? You don't want to update it all the time?


binarydecay(Posted 2003) [#4]
Thanks guys.

To clarify I'm working on a 2d tile based map engine and I want the alpha for lighting effects. That's why I don't want to use sprites because I don't want to have a sprite for every square on my map. The map is being redrawn constantly.

Because I have to do this a lot I can't use the pixel method above... it would be too slow, need some way to tap into the hardware acceleration on the card (2d or 3d).

I can't believe theres no way to draw a normal 2d image on the screen with alpha, colouring etc.

I had a look at the sprite conrol library someone has written, and although it's very good it does use sprites and textures (therefore having a sprite list to maintain and not getting a pixel accurate copy of the image).

Any more suggestions?


Ross C(Posted 2003) [#5]
well, do the shadows ever project onto moving images or tiles? I'd imagine they do. mmmm. You could use the checked shadow approach.

#.#.#.#.#.
.#.#.#.#.#
#.#.#.#.#.
.#.#.#.#.#
#.#.#.#.#.
.#.#.#.#.#


basically meaning that #=a pixel of the image and .=a black pixel. It tricks the eye into thinking the image is transparent. Use only on resolutions 800x600 or greater.

And also, don't let any of these checked shadows overlap, cause it looks kinda bad. Hope that helps!

[EDIT] sorry, sounds a bit vague. For the shadows your wanting, make the shadow a very dark grey, but NOT black. Then checker the image with black pixel. I sent you an image to show you what i mean, only it's a circle.


injeevious(Posted 2003) [#6]
This code uses jokers approach but allows images to overlap and keep their transparency, but its very inefficient.
(needs images argb values stored in the pic(width,height) array)
        LockBuffer
	For x=xx To picw+xx
		If x=>0 And x<gw
			If x Mod 2 > 0 Then
				For y=yy To pich+yy
					If y=>0 And x<gh And pic(x-xx,y-yy)>-16777216
						If y Mod 2=0 Then WritePixelFast x,y,pic(x-xx,y-yy)
					EndIf
				Next
			Else
				For y=yy To pich+yy
					If y=>0 And x<gh And pic(x-xx,y-yy)>-16777216
						If y Mod 2>0 Then WritePixelFast x,y,pic(x-xx,y-yy)
					EndIf
				Next
			EndIf
		EndIf
	Next
	UnlockBuffer