Hey all,

Im seeking some advice on what to do:

I want to suppy a bitmap background for my edit control im working on. I already have a bitmap interface working, and looks pretty sweet. But the problem is the text becomes *very* hard to read at points (not surprisingly).

I was wondering if any of you graphics guru's knew of a way to diminish the overal bitmap a shade.. Like fading it out, but still have its relative colors in tact.

Basically draw 'faintly'... or in terms of GDI, bitblt a "faint" bitmap ;)

(( I tried drawing the text in a layered style to give a shadow around it, but it look bulky :( ))
Posted on 2002-05-04 05:03:33 by NaN
If you're happy to limit to Win2k,ME,XP you could simply use alpha blt and paint the image onto whatever color you want to fade it to.

Otherwise you'll probably have to do the fading yourself. That's not to bad though as bitRAKE's alphablending routine will do that for you, and pretty damn quickly as well. Create a 32bit DIB Section, bitblt the bitmap into it then loop through the image data with the routine.
Posted on 2002-05-04 07:18:26 by Eóin
If its reading text over any bitmap that you need i guess you can draw a shadow margin arround it, or a lighter one if the background is dark like i see in your image, could be better but...

About fast alpha blending, i guess you need that yiu can use the fast 50% alphablending algorithm we sometimes use in HE: and with a mask both pixels then shift them right and finally add them




mask_50_alpha_24 equ 0.11111110.11111110.1111.1110b

mov eax,[esi] ;get src pixel 1
and eax,mask_50_alpha_24
shr eax,1

mov ebx,[edi] ;get src pixel 2
and ebx,mask_50_alpha_24
shr ebx,1

add eax,ebx
mov [esi],eax ;place 50% blended result pixel back



this is not quite accurate but its fast and should do fine for many controls ;)
Posted on 2002-05-04 09:46:32 by BogdanOntanu
mask_50_alpha_24 equ 0.11111110.11111110.11111111b


mov eax,[esi] ;get src pixel 1
and eax,mask_50_alpha_24

mov ebx,[edi] ;get src pixel 2
and ebx,mask_50_alpha_24

add eax,ebx
shr eax,1
mov [esi],eax ;place 50% blended result pixel back
Only loose 4 bits - instead of 6. One less instruction.
Posted on 2002-05-04 09:56:44 by bitRAKE
Thanx E?in, but i would like to ideally allow it to work on all boxes (might be able to let 95 slide tho).

BogdanOntanu and bitRAKE, Thanks *alot* for the source, more than expected. But can anyone give me an idea what his *actually* does. (( Im a bit ignorant of graphic stuff like whatever Alpha-Blend means?? ))

What is "Only loose 4 bits - instead of 6" mean??

I also found this on the MSDN, Alpha Example , But i think this is overkill. (i dunno really). But instead of the AlphaBlend API, replace it with the suggested routine above??

Thing is i *really* dont know what alpha blend does, other than *somehow* makes the fog effect im looking for. :confused:


Thanx
:NaN:
Posted on 2002-05-04 11:12:24 by NaN
Well i found more info on it:
Alpha blending is the process of combining a translucent foreground color with a background color, thereby producing a new blended color. The degree of the foreground color's translucency may range from completely transparent to completely opaque. If the foreground color is completely transparent, the blended color will be the background color. Conversely, if it is completely opaque, the blended color will be the foreground color. Of course, the translucency can range between these extremes, in which case the blended color is computed as a weighted average of the foreground and background colors.


alpha blending
A technique by which the color in a source bitmap is combined with that in a destination bitmap to produce a new destination bitmap.
GDI performs per-pixel alpha blending, according to the formula: Blend = Alpha * Source + (1 - Alpha) * Destination. This formula is used to compute the alpha blend at each pixel, for each of the red, green, and blue color channels.


I think im starting to see the picture better (pardon the pun ;).
But if you have more advice, please tell ;)

Another quick question, how exactly does the DIB bitmap data play in terms of a buffer length needed, for different color depths? I *assume* if its 265 color, than one byte per pixel, but if its say x Million colors, there would be up to 4 bytes per pixel (right)? Which means the above algo would need to be modified right?? And more GDI processing on just what the bitmap *is* ??

Thanx
Posted on 2002-05-04 12:28:48 by NaN
Can I suggest bitRAKEs alpha blending routine over the 50% one. You'll only need to do blending once for the image, then just keep the blended image in memory. This means that speed isn't the primary goal.

By using bitRAKEs routine you'll allow the user specify varying degrees of fading. In some case 50% may not be enough. Generally a watermarking effect would look better and for this you probably want about 90% blending.

As for DIBs, for 32 bit you need 4 bytes per pixel, once blended however you could blit the image into a 8 bit colour DC and delete the 32 bit version to save memory.
Posted on 2002-05-04 13:21:57 by Eóin
Eoin, I *totaly* agree, and am 90% there already. The way im currently showing the background is by creating a 'storage' DC and making a complete copy of the source bitmap (full sized), and placing this Master Copy into to the storage DC.

Then when resize messages comes along, i use the stored master and 'chop' a centered section out and blt it to a 'Sized' DC and bitmap. (this is where i would add the Alpha Blend).

When its time to paint, i do a bitblt of the Sized BM (with the pre formatted background image), onto the back buffer, and redraw the text over top.

This complexity saves speed when drawing, cause the background remains static on the sized DC, ready for one quick copy (untill the window size changes ~ which shouldnt be all to often ;) )

So i will follow your advice here. I would like to allow the user to 'select' the degree of blend.

Where im still lost is controlling DC's color depths. I know enough to get around with GDI, but I've never tried or even thought about the issue of color depths, cause till now all i did was select bitmaps, and blt them (color stuff was done automatically). But now Is appearent that to propely do the alpha blend, i will need to *somehow* create specific bitmaps, and *somehow* find their color depths. If you know of these API's off hand it would be appreciated :) ( I will still try to find them on my own however, im not that lazy ;) )

Again Thanx for the advice, You've all been a great help so far!
:alright:
NaN
Posted on 2002-05-04 16:11:28 by NaN
I always do color conversion the easy way too, with BitBlt. When you create the DIBSection set the height and width of the BITMAPINFOHEADER to the match your bitmap. And set biPlanes to 1, biBitCount to 32 & biCompression to BI_RGB. Everything else is set to 0.

When you BitBlt the bitmap into this its converetd to 32bit for you. This is perfect since this is the format bitRAKE wrote his algo to work with, thats the only reason why you need to perform the conversion in the first place. Also since you're dealing with 4 bytes per pixel there's no padding to worry about. So a simpe loop through each pixel pair applying the routine will do the job nice and quickly.

Once blended you can use BitBlt to do whatever you want to the bitmap.
Posted on 2002-05-04 16:55:10 by Eóin
Thanx Eoin!

(( I was looking way off base here )) ~ I think i can get started now ;)

BTW: Can BitBlt safely blit from a DIB to a DDB?? Ie, if i create the DIB for the alpha blend, and select it to a DC, can i leave it and rely on it as the source for when copying to the back buffer (created as a compatible bitmap of the primary DC ( assumed to be a DDB ) )

:alright:
NaN
Posted on 2002-05-04 17:03:49 by NaN
I've never ever had any problems so I'd assume it ok.

But if someone out there has may they speak up. :)
Posted on 2002-05-04 17:58:49 by Eóin
Well here is my Souce for future reference/searchs:
SizedBM, and BACKDC are the source bitmap and DC that is
pre-existing before this routine is called. The SizedBM is replaced
with the alphablended routine, which is ready for direct
copying onto the back buffer when WM_PAINT comes along.
;=========================================================================================================

DoAlpha PROC USES esi edi
;=========================================================================================================
LOCAL bm :BITMAP
LOCAL bmi :BITMAPINFO
LOCAL lpBits :DWORD
LOCAL hBitmap :DWORD
LOCAL SDC :DWORD
LOCAL OldBM :DWORD

LOCAL BMDC :DWORD

invoke GetObject, [ebx].ECon.IMG.SizedBM, sizeof BITMAP, addr bm ; Get Src Bitmap Size

invoke RtlZeroMemory, addr bmi.bmiHeader, sizeof BITMAPINFOHEADER ; Zero the Header

mov eax, sizeof BITMAPINFOHEADER ; Fill 32 bit bitmap
mov bmi.bmiHeader.biSize, eax ; header, RGB mode

mov eax, bm.bmWidth
mov bmi.bmiHeader.biWidth, eax
mov eax, bm.bmHeight
neg eax ; make this a top->down bitmap
mov bmi.bmiHeader.biHeight, eax
mov bmi.bmiHeader.biPlanes, 1
mov bmi.bmiHeader.biCompression, BI_RGB
mov bmi.bmiHeader.biBitCount, 32 ; 32 bits per pixel

invoke CreateDIBSection, [ebx].ECon.IMG.BACKDC,addr bmi, DIB_RGB_COLORS, ; Make the DIB section
addr lpBits, NULL, NULL
mov hBitmap, eax ; Save the handle

invoke GetDC, [ebx].ECon.hWnd ; Get the main DC
mov SDC, eax
invoke CreateCompatibleDC, eax ; Create a Temp DC
mov BMDC, eax
invoke ReleaseDC, [ebx].ECon.hWnd, SDC ; Release the source DC
invoke SelectObject, BMDC, hBitmap ; Select the new DIB
mov OldBM, eax ; Save the OLD BM

invoke BitBlt, BMDC, 0,0, ; Copy to the Sized BM the
[ebx].ECon.WIN.DRCT.right,[ebx].ECon.WIN.DRCT.bottom, ; and do RGB conversion
[ebx].ECon.IMG.BACKDC, 0,0, SRCCOPY


; Do Alpha.
mask_50_alpha_24 equ 0111111101111111011111111b
xor edx, edx
mov eax, bm.bmWidth
mul bm.bmHeight
mov ecx, eax ; Get the # of RGB quad's
mov esi, lpBits
mov edi, 00FFFFFFh
.while( ecx )

mov eax,[esi] ;get src pixel 1
and eax, mask_50_alpha_24

mov edx, edi ;get src pixel 2
and edx, mask_50_alpha_24

add eax,edx
shr eax,1
mov [esi],eax ;place 50% blended result pixel back
add esi, 4
dec ecx
.endw

xor edx, edx
mov eax, bm.bmWidth
mul bm.bmHeight
mov ecx, eax ; Get the # of RGB quad's
mov esi, lpBits
mov edi, 00FFFFFFh
.while( ecx )

mov eax,[esi] ;get src pixel 1
and eax, mask_50_alpha_24

mov edx, edi ;get src pixel 2
and edx, mask_50_alpha_24

add eax,edx
shr eax,1
mov [esi],eax ;place 50% blended result pixel back
add esi, 4
dec ecx
.endw

invoke BitBlt, [ebx].ECon.IMG.BACKDC, 0,0, ; Copy Alpha'd DC
[ebx].ECon.WIN.DRCT.right,[ebx].ECon.WIN.DRCT.bottom, ; To SizedBM on BACKDC
BMDC, 0, 0, SRCCOPY

invoke SelectObject, BMDC, OldBM
invoke DeleteDC, BMDC
invoke DeleteObject, hBitmap


ret
DoAlpha ENDP


One last question, Im doing the Alpha blend twice to get 75% reduction. How would i determin a variable percent reduction with this algo. Is it even possible with this. The equate looks kinda specific to me, but i dont fully understand how it is derived anyways :rolleyes:

However,
Posted on 2002-05-04 18:56:16 by NaN
The equ makes sure that once you use shr to average the source pixels, the most insignificant bit of one color doesn't become the most significant bit of another color. (The last 3 bytes of a 32 bit color each signify one of the three basic colors)

Edit: forgot to post what is the thing that happens.

First the most insignificant bit of the first two colors is removed, then the two colors are added, and shifted right once. If you need 75% reduction use a bitmask the removes the two most insignificant bits of the first two colors, and get 3 times as much white into it (That's what the 0FFFFFFh stand for)

so:
mask_50_alpha_24 equ 0111111101111111011111111b
becomes:
mask_50_alpha_24 equ 0111111001111110011111111b

and add after:
and edx, mask_50_alpha_24
the following
lea edx, ; gets 3 times white

and change:
shr eax,1
to:
shr eax,2 ; divide by 4 for the 3 whites and 1 source
Posted on 2002-05-04 19:29:58 by _js_
Gotcha,

But i guess 75% was a poor choice to ask the question on. I have in mind an Up/Down counter form 0-100%, and allow the user to DYNAMICALLY set the level of blend.

I guest i would then need to write the slower:

Blend = Alpha * Source + (1 - Alpha) * Destination

Algo for each R, G, and B bytes?

Right?
:NaN:
Posted on 2002-05-04 19:49:08 by NaN
Yes, but that would be slow I think, you could search for a different algo, perhaps try 'or'ing it with 256 different shades of white depending on the slider? (00.00.00, 01.01.01, ... , ff.ff.ff) It that would distort the image somewhat but be faster.
Posted on 2002-05-04 20:25:49 by _js_
This is a good idea, but i have the advantage here. The routine is *only* called when a new bitmap is sent *or* when the window is resized. So i can take more time to get the job done, (if needed). But as always, faster is prefered!

:alright:
NaN
Posted on 2002-05-05 03:29:46 by NaN
I've been looking at bitRAKEs algo, I forgot that it blends two images together, which you don't want to do. But its easy to change it to blend one image towards a certain colour.

	mov eax,lpBits

mov ecx,Count ; number of pixels/2
dec ecx
pxor mm7,mm7
movq mm1,DesiredColour ;
Format 0AABBGGRRAABBGGRRh
movq mm0,[eax+ecx*8]
@@: movq mm4,mm1; <- Here
movq mm2,mm0
psrlw mm4,1
movq mm3,mm1
movq mm5,mm4
punpcklbw mm0,mm7
punpcklbw mm1,mm7
punpckhbw mm2,mm7
punpckhbw mm3,mm7
psubsw mm0,mm1
psubsw mm2,mm3
punpcklwd mm4,mm4
punpckhwd mm5,mm5
punpckhdq mm4,mm4
punpckhdq mm5,mm5
psllw mm0,1
psllw mm2,1
pmulhw mm0,mm4
pmulhw mm2,mm5
paddsw mm0,mm1
paddsw mm2,mm3
packuswb mm0,mm2
movq [edx+ecx*8],mm0
dec ecx
movq mm0,[eax+ecx*8]
;movq mm1,[edx+ecx*8] ; <- Here
jnz @B


I may have the red and blue of the desiredColor format wrong here, plus I'm doing this in my head at the momnet so the changes I've made to the origional (indicated by "<- Here") may not work. But hopefully they will.
Posted on 2002-05-05 06:24:05 by Eóin
Woo Hoo! :)

My first valid reason to dive into MMX ;)

Think its safe to say everyone has MMX by now. However, if someone didnt, what would this code do on their machines, anything?
Posted on 2002-05-05 10:37:46 by NaN
NaN, that algo is overkill for what your trying to do. I've marked all the instructions below that can be moved outside the loop because they are constant:
@@:	movq mm4,mm1 ;*

movq mm2,mm0
psrlw mm4,1 ;*
movq mm3,mm1 ;*
movq mm5,mm4 ;*
punpcklbw mm0,mm7
punpcklbw mm1,mm7 ;*
punpckhbw mm2,mm7
punpckhbw mm3,mm7 ;*
psubsw mm0,mm1
psubsw mm2,mm3
punpcklwd mm4,mm4 ;*
punpckhwd mm5,mm5 ;*
punpckhdq mm4,mm4 ;*
punpckhdq mm5,mm5 ;*
psllw mm0,1
psllw mm2,1
pmulhw mm0,mm4
pmulhw mm2,mm5
paddsw mm0,mm1
paddsw mm2,mm3
packuswb mm0,mm2
movq [edx+ecx*8],mm0
dec ecx
movq mm0,[eax+ecx*8]
movq mm1,mm6 ;*
jnz @B
If you wanted to support non-MMX CPU's then you'd have to test if MMX is suported, and execute alternate code or not support the feature. These instructions would produce an exception on unsupported processors. Of course, an alternate version of your control would be another option.
Posted on 2002-05-05 12:22:29 by bitRAKE
Sounds good.

And ya.. i did a study on MMX this morning and commented the crap outa it. I really dont know *what* it does, but it definitely is not the alpha blend. As well, i see no area for selecting % opacity.

And the 'edx' hidden at the bottom managed to crash Win98SE real good (reboot).


Here is my commented version:
     mov COLOR[0], 0FFFFFFh

mov COLOR[1], 0FFFFFFh
lea eax, COLOR
movq mm1, [eax] ; mm1 = Color (white)
; Format 0AABBGGRRAABBGGRRh

xor edx, edx
mov eax, bm.bmWidth
mul bm.bmHeight
mov ecx, eax ; Get the # of RGB quad's
shr ecx, 1 ; Divide by two
mov eax, lpBits ; place lpBits in eax

; FUNTION: Blend = Alpha * Source + (1 - Alpha) * Destination
; -----------------------------------------------------------

dec ecx ; Dec eax the count
pxor mm7,mm7 ; Format mm7 to zero


movq mm0,[eax+ecx*8] ; mm0 = first 8 bytes
@@: movq mm4,mm1 ;<- Her ; mm4 = mm1 (copy of color)
movq mm2,mm0 ; mm2 = mm0 (copy of src data)
psrlw mm4,1 ; mm4 = mm4 >> 1 (packed word)
movq mm3,mm1 ; mm3 = mm1 (copy of color)
movq mm5,mm4 ; mm5 = mm4 (copy of shifted mask)
punpcklbw mm0,mm7 ; A = mm0, 0 = mm7 -> mm0 = 0A0A0A0A LSB (lower 4 data)
punpcklbw mm1,mm7 ; B = mm1, 0 = mm7 -> mm1 = 0B0B0B0B LSB (lower 4 color)
punpckhbw mm2,mm7 ; A = mm2, 0 = mm7 -> mm2 = 0A0A0A0A LSB (upper 4 data)
punpckhbw mm3,mm7 ; B = mm3, 0 = mm7 -> mm3 = 0B0B0B0B LSB (upper 4 color)
psubsw mm0,mm1 ; sined&sat sub w -> mm0 = mm0 - mm1 (lower data - color)
psubsw mm2,mm3 ; sined&sat sub w -> mm2 = mm2 - mm3 (upper data - color)
punpcklwd mm4,mm4 ; mm4 = AAaaAAaa LSB (lower 2 shift color)
punpckhwd mm5,mm5 ; mm5 = AAaaAAaa LSB (upper 2 shift color)
punpckhdq mm4,mm4 ; mm4 = AAAAaaaa LSB (lower 1 shift color)
punpckhdq mm5,mm5 ; mm5 = AAAAaaaa LSB (upper 1 shift color)
psllw mm0,1 ; mm0 = mm0 << 1 (lower data-color*2 )
psllw mm2,1 ; mm2 = mm2 << 1 (upper data-color*2 )
pmulhw mm0,mm4 ; MSW( w * w ) -> mm0 = mm0 * mm4 (MSW low(col)*low(dif)2)
pmulhw mm2,mm5 ; MSW( w * w ) -> mm2 = mm2 * mm5 (MSW upr(col)*upr(dif)2)
paddsw mm0,mm1 ; sined&sat add w -> mm0 = mm0 + mm1 (MSW low + B0B0B0B0 low color)
paddsw mm2,mm3 ; sined&sat add w -> mm2 = mm2 + mm3 (MSW upr + B0B0B0B0 upr color)
packuswb mm0,mm2 ; pack uns W->b -> mm0 = 22002200 LSB (pack resulting 2 DWORDS)
movq [eax+ecx*8],mm0 ; over write the first 8 bytes (2 pixel RGB's)
dec ecx ; next incremente
movq mm0,[eax+ecx*8] ; mm0 = next 8 bytes
;movq mm1,[edx+ecx*8] ; <- Here
jnz @B ; loop Back if ecx == 0 (movq is transparent)


I can see it being re-worked into an equation of this form:
Dest + Alpha(Color - Destination). And i see hints of this
happening, (Data - Color). But what i dont get is the logical
shifting (both right and left shifts) and the High order multiply??
What are they trying to do? Are theses routines attempting to build or fractionize the difference (alpha)??


Anyways, it only makes a dark blue image when tested.

However, Eoin, thanx for the src, its has still been a good learning lesson so far!
:alright:
NaN
Posted on 2002-05-05 13:30:29 by NaN