@@ -59,20 +59,23 @@ Friend Sub BlendDIBs(ByRef topDIB As pdDIB, ByRef bottomDIB As pdDIB, ByVal blen
5959
6060 'With loop bounds safely calculated, we can now proceed with blending.
6161
62- 'Because we are potentially doing a *lot* of calculations here, we need to make a temporary copy of the top DIB. (Our copy will
63- ' be a beaten, mangled mess by the end of this function, and we aren't allowed to make changes to the caller's copy.)
62+ 'Because we are potentially doing a *lot* of calculations here, we need to make a temporary copy of the top DIB.
63+ ' (Our copy will be a beaten, mangled mess by the end of this function, and we aren't allowed to make changes
64+ ' to the caller's copy.)
6465 If (m_topDIBCopy.GetDIBWidth <> topDIB.GetDIBWidth) Or (m_topDIBCopy.GetDIBHeight <> topDIB.GetDIBHeight) Then
6566 m_topDIBCopy.CreateBlank topDIB.GetDIBWidth, topDIB.GetDIBHeight, 32 , 0 , 0
6667 End If
68+
6769 GDI.BitBltWrapper m_topDIBCopy.GetDIBDC, 0 , 0 , topDIB.GetDIBWidth, topDIB.GetDIBHeight, topDIB.GetDIBDC, 0 , 0 , vbSrcCopy
6870 m_topDIBCopy.SetInitialAlphaPremultiplicationState topDIB.GetAlphaPremultiplication
6971
70- 'To keep our individual blend functions as simple as possible, we apply a pre-processing alpha pass that handles several things:
72+ 'To keep our individual blend functions as simple as possible, we apply a pre-processing alpha pass
73+ ' that handles several things:
7174 ' 1) Apply layer masks (if any)
7275 ' 2) Apply alpha inheritance (if any)
76+ ' 3) Overwrite blend mode on paintbrush (identified by presence of a top layer mask)
7377
7478 'Note that we can skip these steps if none of these special alpha modes are active for the top DIB.
75-
7679 If (topAlphaMode <> AM_Normal) Or (bottomAlphaMode <> AM_Normal) Or (Not topLayerMask Is Nothing ) Then
7780 PreProcessAlphaEffects m_topDIBCopy, bottomDIB, bottomAlphaMode, topAlphaMode, initX, initY, finalX, finalY, xOffsetBottom, yOffsetBottom, False , ptrToTopLayerAlternateRectF, topLayerMask
7881 End If
@@ -167,6 +170,13 @@ Friend Sub BlendDIBs(ByRef topDIB As pdDIB, ByRef bottomDIB As pdDIB, ByVal blen
167170 ApplyBlendMode_Erase m_topDIBCopy, bottomDIB, initX, initY, finalX, finalY, xOffsetBottom, yOffsetBottom, alphaModifier
168171 End If
169172
173+ Case BM_Behind
174+ '"Behind" mode is handled by the final blend step (see below)
175+
176+ Case BM_Overwrite
177+ 'Note that overwrite mode also requires a mask - this is so that paint strokes can be correctly composited.
178+ 'TODO
179+
170180 'Some blendmodes don't have dedicated, optimized subs just yet. This catch-all function handles their code for now.
171181 Case Else
172182 PDDebug.LogAction "WARNING: UNKNOWN BLEND MODE REQUESTED IN pdPixelBlender.BlendDIBs!"
@@ -176,9 +186,45 @@ Friend Sub BlendDIBs(ByRef topDIB As pdDIB, ByRef bottomDIB As pdDIB, ByVal blen
176186 'Composited results will have been placed inside the temporary top DIB copy. Apply the final blend now!
177187 If applyFinalBlend Then
178188
179- 'Some blend modes ignore this step (Erase, at present)
180- If (blendMode <> BM_Erase) Then m_topDIBCopy.AlphaBlendToDCEx bottomDIB.GetDIBDC, xOffsetBottom + initX, yOffsetBottom + initY, finalX - initX + 1 , finalY - initY + 1 , initX, initY, finalX - initX + 1 , finalY - initY + 1 , Int(alphaModifier * 255 ! + 0.5 !)
181- 'Debug.Print "Blending this many pixels: " & CStr((finalX - initX + 1) * (finalY - initY + 1))
189+ 'In "behind" blend mode, this step is different.
190+ If (blendMode = BM_Behind) Then
191+
192+ 'In "Behind" blend mode, we actually blend the bottom DIB "atop" the top DIB. Instead of making a
193+ ' temporary copy of the top DIB, we actually need to make a copy of the *bottom* one.
194+ If (m_topDIBCopy.GetDIBWidth <> bottomDIB.GetDIBWidth) Or (m_topDIBCopy.GetDIBHeight <> bottomDIB.GetDIBHeight) Then
195+ m_topDIBCopy.CreateBlank bottomDIB.GetDIBWidth, bottomDIB.GetDIBHeight, 32 , 0 , 0
196+ End If
197+
198+ GDI.BitBltWrapper m_topDIBCopy.GetDIBDC, 0 , 0 , bottomDIB.GetDIBWidth, bottomDIB.GetDIBHeight, bottomDIB.GetDIBDC, 0 , 0 , vbSrcCopy
199+ m_topDIBCopy.SetInitialAlphaPremultiplicationState bottomDIB.GetAlphaPremultiplication
200+
201+ 'm_topDIBCopy now contains a copy of the *bottom* DIB's data. Next we want to "cut out" the
202+ ' merge region in the *bottom* DIB, and replace it with the top DIB's pixels. (We also need
203+ ' to blank out the target region first, so that the layer's opacity - if any - is reflected
204+ ' correctly in the blend.)
205+ Dim tmpFillRectF As RectF
206+ With tmpFillRectF
207+ .Left = xOffsetBottom + initX
208+ .Top = yOffsetBottom + initY
209+ .Width = finalX - initX + 1
210+ .Height = finalY - initY + 1
211+ End With
212+
213+ bottomDIB.FillRectWithColor tmpFillRectF, 0 , 0
214+ topDIB.AlphaBlendToDCEx bottomDIB.GetDIBDC, xOffsetBottom + initX, yOffsetBottom + initY, finalX - initX + 1 , finalY - initY + 1 , initX, initY, finalX - initX + 1 , finalY - initY + 1 , Int(alphaModifier * 255 ! + 0.5 !)
215+
216+ 'Now, blend the *copy* of the bottom layer onto the space where we just "chopped out"
217+ ' the bottom layer's pixels and replaced them with the top layer's
218+ m_topDIBCopy.AlphaBlendToDCEx bottomDIB.GetDIBDC, xOffsetBottom + initX, yOffsetBottom + initY, finalX - initX + 1 , finalY - initY + 1 , xOffsetBottom + initX, yOffsetBottom + initY, finalX - initX + 1 , finalY - initY + 1 , 255 !
219+
220+ 'All other blend modes behave normally
221+ Else
222+
223+ 'Some blend modes ignore this step (Erase, at present)
224+ If (blendMode <> BM_Erase) Then m_topDIBCopy.AlphaBlendToDCEx bottomDIB.GetDIBDC, xOffsetBottom + initX, yOffsetBottom + initY, finalX - initX + 1 , finalY - initY + 1 , initX, initY, finalX - initX + 1 , finalY - initY + 1 , Int(alphaModifier * 255 ! + 0.5 !)
225+ 'Debug.Print "Blending this many pixels: " & CStr((finalX - initX + 1) * (finalY - initY + 1))
226+
227+ End If
182228
183229 'Also, locked alpha requires us to restore the original bottom layer alpha values now
184230 If (bottomAlphaMode = AM_Locked) Then PostProcessAlphaEffects m_topDIBCopy, bottomDIB, bottomAlphaMode, topAlphaMode, initX, initY, finalX, finalY, xOffsetBottom, yOffsetBottom, False , ptrToTopLayerAlternateRectF
@@ -365,8 +411,9 @@ Friend Sub ApplyMaskToTopDIB(ByRef dstDIB As pdDIB, ByRef maskDIB As pdDIB, Opti
365411
366412End Sub
367413
368- 'Prior to blending two DIBs, call this function preprocess any alpha-specific effects (masks, inheritance, etc). This greatly simplifies
369- ' the actual blending code inside each blend function, because special alpha handling is never required.
414+ 'Prior to blending two DIBs, call this function preprocess any alpha-specific effects (masks, inheritance, etc).
415+ ' This greatly simplifies the actual blending code inside each blend function, because special alpha handling
416+ ' is never required.
370417Private Sub PreProcessAlphaEffects (ByRef topDIB As pdDIB , ByRef bottomDIB As pdDIB , ByVal bottomAlphaMode As PD_AlphaMode , ByVal topAlphaMode As PD_AlphaMode , ByVal initX As Long , ByVal initY As Long , ByVal finalX As Long , ByVal finalY As Long , ByVal xOffset As Long , ByVal yOffset As Long , Optional ByVal returnResultsUnpremultiplied As Boolean = False , Optional ByVal ptrToTopLayerAlternateRectF As Long = 0 , Optional ByRef topLayerMask As pdDIB = Nothing )
371418
372419 'Only some settings require us to use this function.
@@ -406,8 +453,8 @@ Private Sub PreProcessAlphaEffects(ByRef topDIB As pdDIB, ByRef bottomDIB As pdD
406453 If (tmpFinalX > topLayerMask.GetDIBStride - 1 ) Then tmpFinalX = topLayerMask.GetDIBStride - 1
407454 If (tmpFinalY > topLayerMask.GetDIBHeight - 1 ) Then tmpFinalY = topLayerMask.GetDIBHeight - 1
408455
409- '2D array access is slow (because VB must apply multiplication "behind-the-scenes" on each access), so we cheat and use 1D arrays,
410- ' which we reset between scanlines.
456+ '2D array access is slow (because VB must apply multiplication "behind-the-scenes" on each access),
457+ ' so we cheat and use 1D arrays, which we reset between scanlines.
411458 bottomScanlineSize = topDIB.GetDIBStride: bottomDIBPointer = topDIB.GetDIBPointer
412459 topScanlineSize = topLayerMask.GetDIBStride: topDIBPointer = topLayerMask.GetDIBPointer
413460
@@ -1199,7 +1246,7 @@ Private Sub ApplyBlendMode_Difference(ByRef topDIB As pdDIB, ByRef bottomDIB As
11991246 If (newG < 0 !) Then newG = -newG
12001247 newB = (bottomB - topB)
12011248 If (newB < 0 !) Then newB = -newB
1202-
1249+
12031250 'If the bottom layer contains transparency, mix the newly calculated RGB values against the original top layer
12041251 ' RGB values. This reduces the strength of the blend mode result, proportional to the bottom layer's alpha.
12051252 If (bottomA <> 1 !) Then
0 commit comments