From: Rob on
Hi,

I'm working on a usercontrol that is basically a bunch of different
sized boxes (sometimes more than 30 on screen at once). I'd like those
boxes to have an alphablended dropshadow effect but the code I've been
using to draw (using SetPixel) the shadows is to slow when the whole
control has to be drawn at once.

What approach to drawing dropshadows that blend with the background
would be quickest?

Thanks
Rob
From: Mike Williams on
"Rob" <noname(a)noserver.com> wrote in message
news:p3fus59m0sinmmeuvac6bf4t99a9279fpc(a)4ax.com...

> I'm working on a usercontrol that is basically a bunch of different
> sized boxes (sometimes more than 30 on screen at once). I'd like
> those boxes to have an alphablended dropshadow effect but the
> code I've been using to draw (using SetPixel) the shadows is to
> slow when the whole control has to be drawn at once. What
> approach to drawing dropshadows that blend with the background
> would be quickest?

You say that you want an alphablend drop shadow effect, so I assume you are
actually using the AlphaBlend function? Is that what you are using? If so
then you will find it pretty quick. The problem is that you also say you are
using SetPixel to set individual pixels, which is dreadfully slow for such
tasks, so I'm not sure exactly what you are doing. The only reason I can see
which might cause you to be using /both/ the AlphaBlend function and the
SetPixel function is if you are using AlphaBlend in its "per pixel
translucency" mode (where you have set the BlendFunction AlphaFormat to
AC_SRC_ALPHA) and which requires you to fiddle about with the individual
"pre-multiplication" of each bitmap colour byte with its alpha channel. Is
that what you are doing? If so then you really need to get your bitmap pixel
data into a DIB (if it is not already in one) and then point a VB SafeArray
structure at the DIB data which will enable you to perform the
pre-multiplication stuff very quickly by accessing the DIB data as though it
was a standard VB Byte array. However, having said that, per pixel
translucency is not actually required for the job you are doing (at least
judging by your explanation of that job).

There are all sorts of ways of drawing things with drop shadows, with
different methods being suitable for different circumstances depending on
exactly what it is you are drawing and whether they are regularly or
irregularly shaped. For example, you say you are drawing "boxes", which I
assume are rectangular and solid. If that is the case then you can draw
them, and their drop shadows, with considerably less code that you could if
they were rectangles with rounded corners or if they were irregularly
shaped.

Perhaps it might be best if you were to describe in more detail exactly what
bitmaps your are drawing, and how you are initially creating those bitmaps,
and exactly what you mean by "drop shadow" (I know that sounds odd, but to
me a drop shadow is where the background in the shadow area is blended with
black, but I've come across some people who see it differently and see it as
being blended with the pixels of the object that is causing the shadow,
which of course is not quite the same as a shadow). It would also be very
helpful if you were to post your existing code, so we can see exactly what
it is you are currently doing.

Mike




From: Mike Williams on
"Rob" <noname(a)noserver.com> wrote in message
news:p3fus59m0sinmmeuvac6bf4t99a9279fpc(a)4ax.com...

> I'm working on a usercontrol that is basically a bunch of different
> sized boxes (sometimes more than 30 on screen at once). I'd like
> those boxes to have an alphablended dropshadow effect but the
> code I've been using to draw (using SetPixel) the shadows is to
> slow when the whole control has to be drawn at once. What
> approach to drawing dropshadows that blend with the background
> would be quickest?

One thing I forgot to mention in my previous response is the fact that
Micro$oft, having failed for many years in their attempts to destroy VB6
itself, and having also failed in their long standing attempts to destroy
this newsgroup by sending in their team of specially brainwashed MVP
saboteurs (Bill McCarthy, Paul Clement, Cor ligthert and others), has
finally decided to attempt to destroy the group in a different way, by
closing down its servers, which incidentally is in any case part of their
plan to extract the maximum profits for themselves by shamelessly riding on
the backs of the unpaid volunteers who freely give their time here to help
the programming community. Therefore, it might be best if you forgot for the
time being about responding to my own answer to your question in this group
and if you instead re-posted your original question to the following group,
which is not connected in any way with the Micro$oft servers:

comp.lang.visual.basic.misc

Mike



From: Mike Williams on
"Mike Williams" <Mike(a)WhiskeyAndCoke.com> wrote in message
news:O%23sKBYI8KHA.4508(a)TK2MSFTNGP06.phx.gbl...

> . . . if you instead re-posted your original question to the following
> group, which is not connected in any way with the Micro$oft servers:
> comp.lang.visual.basic.misc

Sorry, that's:

comp.lang.basic.visual.misc

Mike



From: Robert on

Thanks for the reply

At the moment the drop shadow is being drawn directly on the
usercontrol's DC using setpixel using a value calculated based on the
background colour (which, at the moment, is COLOR_WINDOW but I'd like
the option to use a gradient or even a tiled bitmap in future)

The boxes in question are simple rectangles which contain text. The
height of a box is determined by the amount of text it contains.
Widths are all the same but can be changed by the user (which can also
effect the heights).

If you picture the Outlook CardView you won't be too far off.

The actual routine I'm using to draw the shadows is something I picked
up (I think) from the groups by (I think) MikeD, as follows:

Public Sub DrawShadow(ByVal hdc As Long, rec As RECT, Optional
nOpacity As Long = 6)

Dim X As Long, Y As Long, c As Long

' Simulate a shadow on right edge...
For X = 1 To 4
' For Y = 0 To 3
' c = GetPixel(hDC, Rec.Right - X, Rec.Bottom + Y)
' SetPixel hDC, Rec.Right - X, Rec.Top + Y, c
' Next Y
' For Y = 4 To 7
' c = GetPixel(m_hDC, Rec.Right - X, Rec.Top + Y)
' SetPixel m_hDC, Rec.Right - X, Rec.Top + Y, _
' pMask(3 * X * (Y - 3), c)
' Next Y
For Y = 1 To 4
c = GetPixel(hdc, rec.Right - X, rec.Top + Y)
SetPixel hdc, rec.Right - X, rec.Top + Y, _
pMask(nOpacity * X * (Y - 0), c)
Next Y
For Y = 5 To RectHeight(rec) - 5
c = GetPixel(hdc, rec.Right + X, rec.Top + Y)
SetPixel hdc, rec.Right - X, rec.Top + Y, _
pMask((nOpacity * 5) * X, c)
Next Y
For Y = RectHeight(rec) - 4 To RectHeight(rec) - 1
c = GetPixel(hdc, rec.Right - X, rec.Top + Y)
SetPixel hdc, rec.Right - X, rec.Top + Y, _
pMask(nOpacity * X * -(Y - RectHeight(rec)), c)
Next Y
Next X

' Simulate a shadow on the bottom edge...
For Y = 1 To 4
' For X = 0 To 3
' c = GetPixel(hDC, Rec.Left + X, Rec.Bottom - Y)
' SetPixel hDC, Rec.Left + X, Rec.Bottom - Y, c
' Next X
' For X = 4 To 7
' c = GetPixel(m_hDC, Rec.Left + X, Rec.Bottom - Y)
' SetPixel m_hDC, Rec.Left + X, Rec.Bottom - Y, _
' pMask(3 * (X - 3) * Y, c)
' Next X
For X = 1 To 4
c = GetPixel(hdc, rec.Left + X, rec.bottom - Y)
SetPixel hdc, rec.Left + X, rec.bottom - Y, _
pMask(nOpacity * (X - 0) * Y, c)
Next X
For X = 5 To RectWidth(rec) - 5
c = GetPixel(hdc, rec.Left + X, rec.bottom - Y)
SetPixel hdc, rec.Left + X, rec.bottom - Y, _
pMask((nOpacity * 5) * Y, c)
Next X
Next Y
End Sub


' - Function pMask splits a color
' into its RGB components and
' transforms the color using
' a scale 0..255
Private Function pMask(ByVal lScale As Long, ByVal lColor As Long) As
Long
Dim r As Long
Dim g As Long
Dim b As Long

r = pTransform(lScale, GetRValue(lColor))
g = pTransform(lScale, GetGValue(lColor))
b = pTransform(lScale, GetBValue(lColor))

pMask = rgb(r, g, b)

End Function

' - Function pTransform converts
' a RGB subcolor using a scale
' where 0 = 0 and 255 = lScale
Private Function pTransform(ByVal lScale As Long, ByVal lColor As
Long) As Long
pTransform = lColor - Int(lColor * lScale / 255)
End Function