From: Bee on
Did the temp pic thing and it still fails the same way so I am sure it is not
related to the flip but how I have things set up.

Here is more code. Extracted from big app.

Initialization
' ------ Rubberband -------
' VIEW
' prepare the sprite holder
With picDraw(eDrawViewSprite)
.ScaleMode = vbPixels
.BorderStyle = vbBSNone
.BackColor = vbBlack
'.BackColor = vbWhite
.AutoRedraw = True
.ZOrder 1
End With 'picDraw(eDrawViewSprite)

' prepare the mask holder
With picDraw(eDrawViewMask)
.ScaleMode = vbPixels
.BorderStyle = vbBSNone

.BackColor = vbWhite
.FillColor = vbBlack

.FillStyle = vbFSSolid
.AutoRedraw = True
.ZOrder 1
End With 'picDraw(eDrawViewMask)


Private Sub CopyCutViewToSprite(eOp As eCopyOpEnum, Optional lFillColor As
Long = vbBlack)

' we need both a View and an Image Sprite + Mask
' Copy Sprite + Mask
' View: used to move the sprite around on the View
' Image: hold for possible paste
' Image is not updated
'
' Cut Sprite + Mask
' View: used to move the sprite around on the next View
' Image: hold for possible paste
' Image is cut and the View is updated to this cut image

' Cut selected area to sprite and mask buffers
Dim lRtn As Long

' VIEW OPERATIONS
'
' erase vbXorPen drawn View polygon by redrawing
' only drawing rubberband polyline here
Polygon picEffectsView.hdc, tVPt(0), m_lSpriteCoordLast + 1

' create two regions using the polygon data
DeleteObject m_lRgn1
DeleteObject m_lRgn2
m_lRgn1 = CreatePolygonRgn(tVPt(0), m_lSpriteCoordLast + 1, WINDING)
m_lRgn2 = CreatePolygonRgn(tVPt(0), m_lSpriteCoordLast + 1, WINDING)

' paint the region white
lRtn = GetRgnBox(m_lRgn1, tSpriteRect) ' also returns a rectangle
tSpriteRect containing the sprite
If lRtn <> 0 Then
If lRtn <> NULLREGION Then
SpriteAndMaskCreateView
' cut the selected area to white
With picEffectsView
Select Case eOp
Case eCut
.FillColor = lFillColor
'.FillColor = vbWhite
.FillStyle = vbFSSolid
.DrawMode = vbCopyPen
PaintRgn .hdc, m_lRgn1
.FillStyle = vbFSTransparent
Case Else
End Select
.Refresh
End With 'picEffectsView
End If
End If

End Sub 'CopyCutViewToSprite

Private Sub SpriteAndMaskCreateView()

picDraw(eDrawViewSprite).Width = Me.ScaleX(tSpriteRect.Right -
tSpriteRect.Left, vbPixels, Me.ScaleMode)
picDraw(eDrawViewSprite).Height = Me.ScaleY(tSpriteRect.Bottom -
tSpriteRect.Top, vbPixels, Me.ScaleMode)
picDraw(eDrawViewSprite).Cls ' clear to white

' move m_lRgn2 to location (0, 0) and select into picDraw(eDrawViewSprite)
OffsetRgn m_lRgn2, -tSpriteRect.Left, -tSpriteRect.Top

With picDraw(eDrawViewSprite)
SelectClipRgn .hdc, m_lRgn2
' blit the rectangle containing the region into
' from picEffectsView into picDraw(eDrawViewSprite)
BitBlt .hdc, 0, 0, .ScaleWidth, .ScaleHeight, picEffectsView.hdc,
tSpriteRect.Left, tSpriteRect.Top, vbSrcCopy
'

.Refresh ' just for display while testing
' set up picDraw(eDrawViewMask) accordingly
picDraw(eDrawViewMask).Width = .Width
picDraw(eDrawViewMask).Height = .Height
End With 'picDraw(eDrawViewSprite)

' now the mask
picDraw(eDrawViewMask).Cls
PaintRgn picDraw(eDrawViewMask).hdc, m_lRgn2
picDraw(eDrawViewMask).Refresh ' just for display while testing

BitBlt picDraw(eDrawViewSprite).hdc, 0, 0,
picDraw(eDrawViewSprite).Width, picDraw(eDrawViewSprite).Height,
picDraw(eDrawViewMask).hdc, 0, 0, vbSrcPaint

End Sub 'SpriteAndMaskCreateView

' placed in the mousemove event for picEffectsView

Private Function SpriteViewPlace(x As Single, y As Single)

On Error GoTo SpriteViewPlaceErr

' make sure to do this when pciture is loaded
' .Picture = .Image
' then .Cls wil not clear the .Picture
'
picEffectsView.Cls

'Draw the mask
BitBlt picEffectsView.hdc, x, y, picDraw(eDrawViewSprite).Width,
picDraw(eDrawViewSprite).Height, picDraw(eDrawViewMask).hdc, 0, 0, vbSrcAnd

'Draw the sprite
BitBlt picEffectsView.hdc, x, y, picDraw(eDrawViewSprite).Width,
picDraw(eDrawViewSprite).Height, picDraw(eDrawViewSprite).hdc, 0, 0,
vbSrcPaint

picEffectsView.Refresh

SpriteViewPlaceExit:
Exit Function

SpriteViewPlaceErr:
Resume SpriteViewPlaceExit

End Function 'SpriteViewPlace


"Mike Williams" wrote:

> "Bee" <Bee(a)discussions.microsoft.com> wrote in message
> news:2C6B4DE2-75C2-4E8C-A83B-3F33397E798A(a)microsoft.com...
>
> > pardon my ignorance. how do I post the images?
> > I hate to impose and email directly to you so I have
> > avoided that thinking that is not good form
>
> Ideally of course they should be hosted on the web somewhere and a link to
> the file posted on the newsgroup, so that anyone else following the thread
> can also see them (posting attachments to the newsgroup itself is frowned
> upon, and doesn't always work anyway). If you have your own web page, or if
> perhaps your ISP gives you a free web page facility, then you can host the
> images on the page and post a link to it. In fact I think there some sites
> out there that allow you to upload images or other files to their own
> servers for free and they'll host them for you, although I've never used any
> of them myself so I don't know how useful they are. Otherwise, if you can't
> do any of those things then you can always email me. If you post your real
> email address then I'll let you know mine, and then you can mail me the
> images.
>
> > the code I have is dispersed through out my app so
> > i am not sure how to do that without introducing
> > confusion to both of us.
>
> You only need to post the relevant parts of the code, specifically just the
> part that contains your two StretchBlt functions which flip the images (mask
> and sprite) together with the declarations for any variables they use and
> details of the values that are assigned to them, and of course details of
> the size of the PictureBoxes involved.
>
> > the sprite image seems to fold itself over in the middle such
> > that the black area on the right is now overlayed on the left.
> > so an irregular shaped mask now become symmetrical about
> > the center (based on a horz flip).
>
> Did you try my previous suggestion when I said that instead of using the
> same hDC for both the source and destination DC in your call to StretchBlt
> you should instead flip the sprite into an otherwise unused Autoredraw
> PictureBox (picTemp) of the same size, and then blit the contents of picTemp
> to the sprite picture box? Have you tried that? Also, have you properly
> checked the values you are using in the StretchBlt call? Post the relevant
> code sample.
>
> Mike
>
>
> .
>
From: Mike Williams on
"Bee" <Bee(a)discussions.microsoft.com> wrote in message
news:E89B7F00-95F0-4EA1-8F37-26FA44C68C8E(a)microsoft.com...

> Here is the flip routine. It works fine for all other image
> flip operations. I am in the process of coding the last
> suggestion [using a tempDC in the flip operation]

I'm not sure why your code is altering the Autoredraw property or why it is
performing a Refresh of the hidden mask or sprite PictureBoxes, but I assume
that's purely for testing purposes so that you can see the result. But your
flip code itself works fine, both for horizontal and vertical flips (and
especially now that you say you have since added the "temp pic thing" to
make the flip totally reliable), so the fact that it appears to be producing
a wrong result in your actual displayed sprite is obviously due to a problem
elsewhere in your code. Regarding your other post in which you show some of
your sprite creation code, I haven't looked through it in detail (partly
because I don't think you should be using the Region method anyway) but I
imagine it must be okay because you have said that it works fine when you
are creating the mask and sprite images for non flipped sprites. Before you
go looking in more detail for the cause of your problem I really think you
should change to a method that does not use Regions in the creation of the
mask and sprite images, because (as I've mentioned before) the irregular
region produced by the CreatePolygonRgn API (and therefore your sprite and
mask) will not be exactly the same shape or size as the irregular area drawn
using the same array of POINTAPI by the Polygon API, because of the
different way in which those two functions interpret and act on the array
data. You will be far better off using the Polygon API both for the creation
of your mask and sprite and for the drawing of any static or "marching ants"
outlines that you might wish to use. I really think you should tackle that
part of the job first, before you go looking for the cause of the problem
you are currently having. In fact, the problem might go away in the process
anyway! Here is an updated copy of the exam,ple I last posted, this time
including the code to correctly draw the marching ants outline for both
standard and flipped sprites. I've included only a horizontal flip in this
example, but you'll find it easy to add the code for a vertical flip in the
same manner as the example. To try it create a new project and add one Timer
and five PictureBoxes. Name the PictureBoxes picMain, picBackBuffer,
picSprite, picMask and picTemp.

Mike

Option Explicit
' Irregular area sprite selection and display
' [curently just beta, but working, test code]
' Mike Williams (2009)
Private Declare Function StretchBlt Lib "gdi32" _
(ByVal hdc As Long, _
ByVal x As Long, ByVal y As Long, _
ByVal nWidth As Long, ByVal nHeight As Long, _
ByVal hSrcDC As Long, _
ByVal xSrc As Long, ByVal ySrc As Long, _
ByVal nSrcWidth As Long, ByVal nSrcHeight As Long, _
ByVal dwRop As Long) As Long
Private Declare Function SetStretchBltMode Lib "gdi32" _
(ByVal hdc As Long, ByVal nStretchMode As Long) As Long
Private Declare Function Polygon Lib "gdi32" _
(ByVal hdc As Long, lpPoint As POINTAPI, _
ByVal nCount As Long) As Long
Private Declare Function BitBlt Lib "gdi32" _
(ByVal hDestDC As Long, ByVal x As Long, ByVal y As Long, _
ByVal nWidth As Long, ByVal nHeight As Long, _
ByVal hSrcDC As Long, ByVal xSrc As Long, _
ByVal ySrc As Long, ByVal dwRop As Long) As Long
Private Declare Function SetViewportOrgEx Lib "gdi32" _
(ByVal hdc As Long, ByVal nX As Long, _
ByVal nY As Long, lpPoint As POINTAPI) As Long
Private Declare Function SetPolyFillMode Lib "gdi32" _
(ByVal hdc As Long, ByVal nPolyFillMode As Long) As Long
Private Const COLORONCOLOR = 3
Private Const ALTERNATE As Long = 1
Private Const WINDING As Long = 2
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Type POINTAPI
x As Long
y As Long
End Type
Private d1() As POINTAPI, d2() As POINTAPI
Private lastCoord As Long
Private mainWidth As Long, mainHeight As Long
Private xMin As Long, xMax As Long
Private yMin As Long, yMax As Long
Private SpriteX As Long, SpriteY As Long
Private polyOffsetX As Long, polyOffsetY As Long
Private spriteWide As Long, spriteHigh As Long
Private SpriteDisplayed As Boolean, Drawing As Boolean
Private MouseInSprite As Boolean, Dragging As Boolean
Private offsetX As Long, offsetY As Long
Private flipX As Boolean

Private Sub Form_KeyUp(KeyCode As Integer, Shift As Integer)
If KeyCode = vbKeyControl Then
flipX = Not flipX
DisplayFlipStatus
End If
End Sub

Private Sub DisplayFlipStatus()
If flipX Then
Me.Caption = "Next selection will be flipped"
Else
Me.Caption = "Next selection will NOT be flipped"
End If
Me.Caption = Me.Caption & " (Press Ctrl to change)"
End Sub

Private Sub Form_Load()
Dim s1 As String
Me.WindowState = vbMaximized
Me.Show
s1 = "c:\temp\jessica1.jpg"
InitPicBox picMain, True
InitPicBox picBackBuffer, False
InitPicBox picSprite, False
InitPicBox picMask, False
InitPicBox picTemp, False
picMain.Move 0, 0, Me.ScaleWidth, Me.ScaleHeight
picBackBuffer.Move 0, 0, picMain.Width, picMain.Height
mainWidth = picMain.ScaleWidth
mainHeight = picMain.ScaleHeight
picMain.PaintPicture LoadPicture(s1), 0, 0, _
mainWidth, mainHeight
BitBlt picBackBuffer.hdc, 0, 0, mainWidth, mainHeight, _
picMain.hdc, 0, 0, vbSrcCopy
picMask.BackColor = vbWhite
picMask.FillColor = vbBlack
picMask.FillStyle = vbFSSolid
SetStretchBltMode picMain.hdc, COLORONCOLOR
DisplayFlipStatus
Me.KeyPreview = True
Timer1.Interval = 200
Timer1.Enabled = True
End Sub

Private Sub InitPicBox(p1 As PictureBox, SetVisible As Boolean)
p1.Visible = SetVisible
p1.BorderStyle = vbBSNone
p1.ScaleMode = vbPixels
p1.AutoRedraw = True
End Sub

Private Sub picMain_DblClick()
' A double click inside the area of a sprite indicates
' that user has finished dragging and wants to drop the
' sprite where it is.
If MouseInSprite Then
DropSprite SpriteX, SpriteY
End If
End Sub

Private Sub picmain_MouseDown(Button As Integer, _
Shift As Integer, x As Single, y As Single)
'If Button <> vbLeftButton Then Exit Sub
If MouseInSprite Then
' User wants to start dragging sprite
offsetX = SpriteX - x
offsetY = SpriteY - y
Dragging = True
'picMain.DrawStyle = vbDot
Else
' A click outside the sprite indicates user has finished
' dragging and possibly also wants to start drawing a new
' selection area, so we need to drop the sprite at its
' current location and then set up the conditions for
' a new drawing
If Button = vbLeftButton Then
' drop sprite at current position
DropSprite SpriteX, SpriteY
' start a new drawing
Drawing = True
picMain.DrawMode = vbNop
picMain.DrawStyle = vbSolid
picMain.PSet (x, y)
picMain.DrawMode = vbInvert
ReDim d1(0 To 100)
lastCoord = 0
d1(lastCoord).x = x
d1(lastCoord).y = y
xMin = x: xMax = x
yMin = y: yMax = y
Else
' cancel the operation (remove sprite from picMain)
DropSprite -spriteWide, -spriteHigh
End If
End If
End Sub

Private Sub picmain_MouseMove(Button As Integer, _
Shift As Integer, x As Single, y As Single)
If x >= mainWidth Then x = mainWidth - 1
If y >= mainHeight Then y = mainHeight - 1
If x < 0 Then x = 0
If y < 0 Then y = 0
If Drawing Then
If x > xMax Then xMax = x
If x < xMin Then xMin = x
If y > yMax Then yMax = y
If y < yMin Then yMin = y
picMain.Line -(x, y)
lastCoord = lastCoord + 1
If lastCoord > UBound(d1) Then
ReDim Preserve d1(0 To lastCoord + 100)
End If
d1(lastCoord).x = x
d1(lastCoord).y = y
End If
If Dragging And Button = vbLeftButton Then
DisplaySprite CLng(x) + offsetX, CLng(y) + offsetY, True
End If
MouseInSprite = SpriteDisplayed And _
(picMask.Point(x - SpriteX, y - SpriteY) = 0)
If MouseInSprite Then
If picMain.MousePointer <> 15 Then
picMain.MousePointer = 15
End If
Else
If picMain.MousePointer <> 0 Then
picMain.MousePointer = 0
End If
End If
End Sub

Private Sub picmain_MouseUp(Button As Integer, _
Shift As Integer, x As Single, y As Single)
If Button <> vbLeftButton Then Exit Sub
If Drawing Then
' close the shape and create the sprite and mask
picMain.Line -(d1(0).x, d1(0).y)
spriteWide = xMax - xMin + 1
spriteHigh = yMax - yMin + 1
If lastCoord > 0 Then
CreateAndDisplaySprite
End If
Drawing = False
End If
End Sub

Private Sub MakeSpriteAndMask()
Dim oldOrg As POINTAPI
picSprite.Width = Me.ScaleX(spriteWide, vbPixels, Me.ScaleMode)
picSprite.Height = Me.ScaleY(spriteHigh, vbPixels, Me.ScaleMode)
' create black on white picMask
picMask.Move 0, 0, picSprite.Width, picSprite.Height
picTemp.Move 0, 0, picSprite.Width, picSprite.Height
picMask.Cls ' clear mask to white
' Draw black on white mask to picMask.
' First offset the origin of picMask so that we
' can use the same array of point data to draw
' a copy of the polygon at the top left of the
' Mask picbox.
SetViewportOrgEx picMask.hdc, -xMin, -yMin, oldOrg
' Then draw the polygon
SetPolyFillMode picMask.hdc, WINDING
Polygon picMask.hdc, d1(0), lastCoord + 1
' Then set the origin back to normal, otherwise VB
' will become very confused when we use any native
' VB methods on the picturebox.
SetViewportOrgEx picMask.hdc, oldOrg.x, oldOrg.y, oldOrg
' blit the full rectangle of the selection to picSprite
BitBlt picSprite.hdc, 0, 0, spriteWide, _
spriteHigh, picMain.hdc, _
xMin, yMin, vbSrcCopy
' Now OR the mask to it to create a standard
' "image on white" sprite image
BitBlt picSprite.hdc, 0, 0, spriteWide, _
spriteHigh, picMask.hdc, _
0, 0, vbSrcPaint
End Sub

Private Sub CreateAndDisplaySprite()
Dim n As Long
' temporarily erase vbinvert drawn polygon by redrawing
Polygon picMain.hdc, d1(0), lastCoord + 1
' don't bother with extremely small sprites
If spriteWide > 2 And spriteHigh > 2 Then
' call the routine to make the sprite and mask
MakeSpriteAndMask
SpriteX = xMin
SpriteY = yMin ' initial sprite position
If flipX = True Then
' Note about flipping: At first I used the same DC for
' both the source and destination in the call to
' StretchBlt, and it worked okay on both machines on
' which I tested it (both running Vista) but I have a
' feeling that doing so might not work on all systems
' because it relies on the behaviour of the underlying
' StretchBlt algorithm working on all machines in a way
' that will allow such a technique to succeed. Therefore
' the following code uses an aternative method of flipping
' into a temporary DC first and then blitting the result
' from the temporary DC to the destination DC.
'
' flip the mask
StretchBlt picTemp.hdc, spriteWide - 1, 0, -spriteWide, _
spriteHigh, picMask.hdc, _
0, 0, spriteWide, spriteHigh, vbSrcCopy
BitBlt picMask.hdc, 0, 0, spriteWide, spriteHigh, _
picTemp.hdc, 0, 0, vbSrcCopy
' flip the sprite
StretchBlt picTemp.hdc, spriteWide - 1, 0, -spriteWide, _
spriteHigh, picSprite.hdc, _
0, 0, spriteWide, spriteHigh, vbSrcCopy
BitBlt picSprite.hdc, 0, 0, spriteWide, spriteHigh, _
picTemp.hdc, 0, 0, vbSrcCopy
' flip the array data and calculate the required
' offset (note: there is an alternative method of
' getting the Polygon API to draw the polygon in
' a flipped state without needing to alter any of
' the POINTAPI data, by using SetMapMode to
' temporary set the mode to MM_ANISOTROPIC together
' with SetWindowExtEx and SetViewPortExtEx to
' effectively set the scale back to the logical
' equivalent of pixels and to cause increasingly
' positive X values (and/or Y values) to move to the
' left instead of the right (and/or up instead of down).
' I did play with this method for some time, and I got
' the Polygon API to draw the polygon in its flipped
' state okay, but I had problems reliably calculating
' and setting the correct offset so that the flipped
' Polygon occupied the same rectangular area of the
' PicBox in all cases, whether it was flipped or not.
' In the end I dropped that method, at least for the
' time being, and used the following method instead,
' which requires a one off "flip" of the array data
' (something which is very fast anyway) and which
' works fine).
ReDim d2(0 To lastCoord)
For n = 0 To lastCoord
d2(n).x = d1(n).x
d2(n).y = d1(n).y
Next n
For n = 1 To lastCoord
d1(n).x = d2(n - 1).x - (d1(n).x - d1(n - 1).x)
Next n
polyOffsetX = (spriteWide - 1) - ((d1(0).x - xMin) * 2)
polyOffsetY = 0 ' haven't done flipY yet
Else
polyOffsetX = 0
polyOffsetY = 0
End If
DisplaySprite SpriteX, SpriteY, True ' (True = include outline)
SpriteDisplayed = True
End If
End Sub

Private Sub DisplaySprite(x As Long, y As Long, AddOutline As Boolean)
' The method used here eliminates flicker when dragging
' or animating the sprite by having the display PictureBox
' Autoredraw True. There are other ways of doing it if you
' are running a very slow machine at a very high display
' resolution.
Dim orgOld As POINTAPI
' first redraw original background at old sprite position
BitBlt picMain.hdc, SpriteX, SpriteY, _
spriteWide, spriteHigh, picBackBuffer.hdc, _
SpriteX, SpriteY, vbSrcCopy
' now transparently draw the sprite at its new position
BitBlt picMain.hdc, x, y, spriteWide, spriteHigh, _
picMask.hdc, 0, 0, vbMergePaint
BitBlt picMain.hdc, x, y, spriteWide, spriteHigh, _
picSprite.hdc, 0, 0, vbSrcAnd
If AddOutline Then
SetViewportOrgEx picMain.hdc, x - xMin + polyOffsetX, _
y - yMin + polyOffsetY, orgOld
picMain.DrawStyle = vbDot
Polygon picMain.hdc, d1(0), lastCoord + 1
SetViewportOrgEx picMain.hdc, orgOld.x, orgOld.y, orgOld
picMain.DrawStyle = vbSolid
End If
picMain.Refresh
' update SpriteX and SpriteY variables to new coordinates
SpriteX = x
SpriteY = y
End Sub

Private Sub DropSprite(x As Long, y As Long)
DisplaySprite x, y, False ' display without outline
' copy modified main image to buffer
BitBlt picBackBuffer.hdc, 0, 0, mainWidth, mainHeight, _
picMain.hdc, 0, 0, vbSrcCopy
SpriteDisplayed = False
MouseInSprite = False
Dragging = False
If picMain.MousePointer <> 0 Then
picMain.MousePointer = 0
End If
End Sub

Private Sub Timer1_Timer()
' draw "marching ants" outline by repeatedly drawing
' a solid/invert polygon over an initially drawn
' dotted/invert polygon.
Dim orgOld As POINTAPI
If SpriteDisplayed Then
' setting Autoredraw to False whilst drawing the Polygon
' means we don't need to issue a PicBox.Refresh in order
' for the drawing to be seen, saving time overall, whilst
' maintaing Autoredraw True for other purposes
picMain.AutoRedraw = False
' offset viewport so we can use the same original polygon
' data array at any other position we wish
SetViewportOrgEx picMain.hdc, SpriteX - xMin + polyOffsetX, _
SpriteY - yMin + polyOffsetY, orgOld
Polygon picMain.hdc, d1(0), lastCoord + 1
' set viewport back to normal or VB will become confused
SetViewportOrgEx picMain.hdc, orgOld.x, orgOld.y, orgOld
picMain.AutoRedraw = True
End If
End Sub







>
> Public Function PictureBoxFlip(PicBox As PictureBox, ByVal eFlip As
> eFlipEnum) As Boolean
>
> ' flip horz and/or flip vert
> On Error GoTo PictureBoxFlipErr
> Dim lW As Long
> Dim lH As Long
> Dim lRet As Long
> Dim lX As Long
> Dim lY As Long
> Dim lWA As Long ' width adjust
> Dim lHA As Long ' height adjjust
>
> ' make sure PicBox.ScaleMode = vbPixels ' pixels
>
> lW = IIf((eFlip And eFlipHorizontal) = eFlipHorizontal, -1, 1)
> lH = IIf((eFlip And eFlipVertical) = eFlipVertical, -1, 1)
>
> '
> lRet = SetStretchBltMode(PicBox.hdc, STRETCH_DELETESCANS) '
> STRETCHMODE) '
>
> If lW < 0 Then
> lX = PicBox.ScaleWidth
> lWA = 1
> Else
> lX = 0
> End If
> If lH < 0 Then
> lY = PicBox.ScaleHeight
> lHA = 1
> Else
> lY = 0
> End If
>
> PictureBoxFlip = (StretchBlt(PicBox.hdc, (lX - lWA), (lY - lHA), (lW *
> PicBox.ScaleWidth), (lH * PicBox.ScaleHeight), PicBox.hdc, 0, 0,
> PicBox.ScaleWidth, PicBox.ScaleHeight, vbSrcCopy) = 1)
> PicBox.AutoRedraw = False
> PicBox.AutoRedraw = True
> PicBox.Refresh
>
> PictureBoxFlipExit:
> Exit Function
>
> PictureBoxFlipErr:
> Resume PictureBoxFlipExit
>
> End Function 'PictureBoxFlip
>
>
> "Mike Williams" wrote:
>
>> "Bee" <Bee(a)discussions.microsoft.com> wrote in message
>> news:2C6B4DE2-75C2-4E8C-A83B-3F33397E798A(a)microsoft.com...
>>
>> > pardon my ignorance. how do I post the images?
>> > I hate to impose and email directly to you so I have
>> > avoided that thinking that is not good form
>>
>> Ideally of course they should be hosted on the web somewhere and a link
>> to
>> the file posted on the newsgroup, so that anyone else following the
>> thread
>> can also see them (posting attachments to the newsgroup itself is frowned
>> upon, and doesn't always work anyway). If you have your own web page, or
>> if
>> perhaps your ISP gives you a free web page facility, then you can host
>> the
>> images on the page and post a link to it. In fact I think there some
>> sites
>> out there that allow you to upload images or other files to their own
>> servers for free and they'll host them for you, although I've never used
>> any
>> of them myself so I don't know how useful they are. Otherwise, if you
>> can't
>> do any of those things then you can always email me. If you post your
>> real
>> email address then I'll let you know mine, and then you can mail me the
>> images.
>>
>> > the code I have is dispersed through out my app so
>> > i am not sure how to do that without introducing
>> > confusion to both of us.
>>
>> You only need to post the relevant parts of the code, specifically just
>> the
>> part that contains your two StretchBlt functions which flip the images
>> (mask
>> and sprite) together with the declarations for any variables they use and
>> details of the values that are assigned to them, and of course details of
>> the size of the PictureBoxes involved.
>>
>> > the sprite image seems to fold itself over in the middle such
>> > that the black area on the right is now overlayed on the left.
>> > so an irregular shaped mask now become symmetrical about
>> > the center (based on a horz flip).
>>
>> Did you try my previous suggestion when I said that instead of using the
>> same hDC for both the source and destination DC in your call to
>> StretchBlt
>> you should instead flip the sprite into an otherwise unused Autoredraw
>> PictureBox (picTemp) of the same size, and then blit the contents of
>> picTemp
>> to the sprite picture box? Have you tried that? Also, have you properly
>> checked the values you are using in the StretchBlt call? Post the
>> relevant
>> code sample.
>>
>> Mike
>>
>>
>> .
>>
>

From: Bee on
what can I say?
this is totally new territory for me.
I have this latest code up and running and I am stepping through to try to
undestand it as best I can. I see that the ants march properly on the flip.
wow!
Thanks again.
I will give up on regions since I cannot figure what else to try there.
I will see if i can work this new code in tomorrow.


"Mike Williams" wrote:

> "Bee" <Bee(a)discussions.microsoft.com> wrote in message
> news:E89B7F00-95F0-4EA1-8F37-26FA44C68C8E(a)microsoft.com...
>
> > Here is the flip routine. It works fine for all other image
> > flip operations. I am in the process of coding the last
> > suggestion [using a tempDC in the flip operation]
>
> I'm not sure why your code is altering the Autoredraw property or why it is
> performing a Refresh of the hidden mask or sprite PictureBoxes, but I assume
> that's purely for testing purposes so that you can see the result. But your
> flip code itself works fine, both for horizontal and vertical flips (and
> especially now that you say you have since added the "temp pic thing" to
> make the flip totally reliable), so the fact that it appears to be producing
> a wrong result in your actual displayed sprite is obviously due to a problem
> elsewhere in your code. Regarding your other post in which you show some of
> your sprite creation code, I haven't looked through it in detail (partly
> because I don't think you should be using the Region method anyway) but I
> imagine it must be okay because you have said that it works fine when you
> are creating the mask and sprite images for non flipped sprites. Before you
> go looking in more detail for the cause of your problem I really think you
> should change to a method that does not use Regions in the creation of the
> mask and sprite images, because (as I've mentioned before) the irregular
> region produced by the CreatePolygonRgn API (and therefore your sprite and
> mask) will not be exactly the same shape or size as the irregular area drawn
> using the same array of POINTAPI by the Polygon API, because of the
> different way in which those two functions interpret and act on the array
> data. You will be far better off using the Polygon API both for the creation
> of your mask and sprite and for the drawing of any static or "marching ants"
> outlines that you might wish to use. I really think you should tackle that
> part of the job first, before you go looking for the cause of the problem
> you are currently having. In fact, the problem might go away in the process
> anyway! Here is an updated copy of the exam,ple I last posted, this time
> including the code to correctly draw the marching ants outline for both
> standard and flipped sprites. I've included only a horizontal flip in this
> example, but you'll find it easy to add the code for a vertical flip in the
> same manner as the example. To try it create a new project and add one Timer
> and five PictureBoxes. Name the PictureBoxes picMain, picBackBuffer,
> picSprite, picMask and picTemp.
>
> Mike
>
> Option Explicit
> ' Irregular area sprite selection and display
> ' [curently just beta, but working, test code]
> ' Mike Williams (2009)
> Private Declare Function StretchBlt Lib "gdi32" _
> (ByVal hdc As Long, _
> ByVal x As Long, ByVal y As Long, _
> ByVal nWidth As Long, ByVal nHeight As Long, _
> ByVal hSrcDC As Long, _
> ByVal xSrc As Long, ByVal ySrc As Long, _
> ByVal nSrcWidth As Long, ByVal nSrcHeight As Long, _
> ByVal dwRop As Long) As Long
> Private Declare Function SetStretchBltMode Lib "gdi32" _
> (ByVal hdc As Long, ByVal nStretchMode As Long) As Long
> Private Declare Function Polygon Lib "gdi32" _
> (ByVal hdc As Long, lpPoint As POINTAPI, _
> ByVal nCount As Long) As Long
> Private Declare Function BitBlt Lib "gdi32" _
> (ByVal hDestDC As Long, ByVal x As Long, ByVal y As Long, _
> ByVal nWidth As Long, ByVal nHeight As Long, _
> ByVal hSrcDC As Long, ByVal xSrc As Long, _
> ByVal ySrc As Long, ByVal dwRop As Long) As Long
> Private Declare Function SetViewportOrgEx Lib "gdi32" _
> (ByVal hdc As Long, ByVal nX As Long, _
> ByVal nY As Long, lpPoint As POINTAPI) As Long
> Private Declare Function SetPolyFillMode Lib "gdi32" _
> (ByVal hdc As Long, ByVal nPolyFillMode As Long) As Long
> Private Const COLORONCOLOR = 3
> Private Const ALTERNATE As Long = 1
> Private Const WINDING As Long = 2
> Private Type RECT
> Left As Long
> Top As Long
> Right As Long
> Bottom As Long
> End Type
> Private Type POINTAPI
> x As Long
> y As Long
> End Type
> Private d1() As POINTAPI, d2() As POINTAPI
> Private lastCoord As Long
> Private mainWidth As Long, mainHeight As Long
> Private xMin As Long, xMax As Long
> Private yMin As Long, yMax As Long
> Private SpriteX As Long, SpriteY As Long
> Private polyOffsetX As Long, polyOffsetY As Long
> Private spriteWide As Long, spriteHigh As Long
> Private SpriteDisplayed As Boolean, Drawing As Boolean
> Private MouseInSprite As Boolean, Dragging As Boolean
> Private offsetX As Long, offsetY As Long
> Private flipX As Boolean
>
> Private Sub Form_KeyUp(KeyCode As Integer, Shift As Integer)
> If KeyCode = vbKeyControl Then
> flipX = Not flipX
> DisplayFlipStatus
> End If
> End Sub
>
> Private Sub DisplayFlipStatus()
> If flipX Then
> Me.Caption = "Next selection will be flipped"
> Else
> Me.Caption = "Next selection will NOT be flipped"
> End If
> Me.Caption = Me.Caption & " (Press Ctrl to change)"
> End Sub
>
> Private Sub Form_Load()
> Dim s1 As String
> Me.WindowState = vbMaximized
> Me.Show
> s1 = "c:\temp\jessica1.jpg"
> InitPicBox picMain, True
> InitPicBox picBackBuffer, False
> InitPicBox picSprite, False
> InitPicBox picMask, False
> InitPicBox picTemp, False
> picMain.Move 0, 0, Me.ScaleWidth, Me.ScaleHeight
> picBackBuffer.Move 0, 0, picMain.Width, picMain.Height
> mainWidth = picMain.ScaleWidth
> mainHeight = picMain.ScaleHeight
> picMain.PaintPicture LoadPicture(s1), 0, 0, _
> mainWidth, mainHeight
> BitBlt picBackBuffer.hdc, 0, 0, mainWidth, mainHeight, _
> picMain.hdc, 0, 0, vbSrcCopy
> picMask.BackColor = vbWhite
> picMask.FillColor = vbBlack
> picMask.FillStyle = vbFSSolid
> SetStretchBltMode picMain.hdc, COLORONCOLOR
> DisplayFlipStatus
> Me.KeyPreview = True
> Timer1.Interval = 200
> Timer1.Enabled = True
> End Sub
>
> Private Sub InitPicBox(p1 As PictureBox, SetVisible As Boolean)
> p1.Visible = SetVisible
> p1.BorderStyle = vbBSNone
> p1.ScaleMode = vbPixels
> p1.AutoRedraw = True
> End Sub
>
> Private Sub picMain_DblClick()
> ' A double click inside the area of a sprite indicates
> ' that user has finished dragging and wants to drop the
> ' sprite where it is.
> If MouseInSprite Then
> DropSprite SpriteX, SpriteY
> End If
> End Sub
>
> Private Sub picmain_MouseDown(Button As Integer, _
> Shift As Integer, x As Single, y As Single)
> 'If Button <> vbLeftButton Then Exit Sub
> If MouseInSprite Then
> ' User wants to start dragging sprite
> offsetX = SpriteX - x
> offsetY = SpriteY - y
> Dragging = True
> 'picMain.DrawStyle = vbDot
> Else
> ' A click outside the sprite indicates user has finished
> ' dragging and possibly also wants to start drawing a new
> ' selection area, so we need to drop the sprite at its
> ' current location and then set up the conditions for
> ' a new drawing
> If Button = vbLeftButton Then
> ' drop sprite at current position
> DropSprite SpriteX, SpriteY
> ' start a new drawing
> Drawing = True
> picMain.DrawMode = vbNop
> picMain.DrawStyle = vbSolid
> picMain.PSet (x, y)
> picMain.DrawMode = vbInvert
> ReDim d1(0 To 100)
> lastCoord = 0
> d1(lastCoord).x = x
> d1(lastCoord).y = y
> xMin = x: xMax = x
> yMin = y: yMax = y
> Else
> ' cancel the operation (remove sprite from picMain)
> DropSprite -spriteWide, -spriteHigh
> End If
> End If
> End Sub
>
> Private Sub picmain_MouseMove(Button As Integer, _
> Shift As Integer, x As Single, y As Single)
> If x >= mainWidth Then x = mainWidth - 1
> If y >= mainHeight Then y = mainHeight - 1
> If x < 0 Then x = 0
> If y < 0 Then y = 0
> If Drawing Then
> If x > xMax Then xMax = x
> If x < xMin Then xMin = x
> If y > yMax Then yMax = y
> If y < yMin Then yMin = y
> picMain.Line -(x, y)
> lastCoord = lastCoord + 1
> If lastCoord > UBound(d1) Then
> ReDim Preserve d1(0 To lastCoord + 100)
> End If
> d1(lastCoord).x = x
> d1(lastCoord).y = y
> End If
> If Dragging And Button = vbLeftButton Then
> DisplaySprite CLng(x) + offsetX, CLng(y) + offsetY, True
> End If
> MouseInSprite = SpriteDisplayed And _
> (picMask.Point(x - SpriteX, y - SpriteY) = 0)
> If MouseInSprite Then
> If picMain.MousePointer <> 15 Then
> picMain.MousePointer = 15
> End If
> Else
> If picMain.MousePointer <> 0 Then
> picMain.MousePointer = 0
> End If
> End If
> End Sub
>
> Private Sub picmain_MouseUp(Button As Integer, _
> Shift As Integer, x As Single, y As Single)
> If Button <> vbLeftButton Then Exit Sub
> If Drawing Then
> ' close the shape and create the sprite and mask
> picMain.Line -(d1(0).x, d1(0).y)
> spriteWide = xMax - xMin + 1
> spriteHigh = yMax - yMin + 1
> If lastCoord > 0 Then
> CreateAndDisplaySprite
> End If
> Drawing = False
> End If
> End Sub
>
> Private Sub MakeSpriteAndMask()
> Dim oldOrg As POINTAPI
> picSprite.Width = Me.ScaleX(spriteWide, vbPixels, Me.ScaleMode)
> picSprite.Height = Me.ScaleY(spriteHigh, vbPixels, Me.ScaleMode)
> ' create black on white picMask
> picMask.Move 0, 0, picSprite.Width, picSprite.Height
> picTemp.Move 0, 0, picSprite.Width, picSprite.Height
> picMask.Cls ' clear mask to white
> ' Draw black on white mask to picMask.
> ' First offset the origin of picMask so that we
> ' can use the same array of point data to draw
> ' a copy of the polygon at the top left of the
> ' Mask picbox.
> SetViewportOrgEx picMask.hdc, -xMin, -yMin, oldOrg
> ' Then draw the polygon
> SetPolyFillMode picMask.hdc, WINDING
> Polygon picMask.hdc, d1(0), lastCoord + 1
> ' Then set the origin back to normal, otherwise VB
> ' will become very confused when we use any native
> ' VB methods on the picturebox.
> SetViewportOrgEx picMask.hdc, oldOrg.x, oldOrg.y, oldOrg
> ' blit the full rectangle of the selection to picSprite
> BitBlt picSprite.hdc, 0, 0, spriteWide, _
> spriteHigh, picMain.hdc, _
> xMin, yMin, vbSrcCopy
> ' Now OR the mask to it to create a standard
> ' "image on white" sprite image
> BitBlt picSprite.hdc, 0, 0, spriteWide, _
> spriteHigh, picMask.hdc, _
> 0, 0, vbSrcPaint
> End Sub
>
> Private Sub CreateAndDisplaySprite()
> Dim n As Long
> ' temporarily erase vbinvert drawn polygon by redrawing
> Polygon picMain.hdc, d1(0), lastCoord + 1
> ' don't bother with extremely small sprites
> If spriteWide > 2 And spriteHigh > 2 Then
> ' call the routine to make the sprite and mask
> MakeSpriteAndMask
> SpriteX = xMin
> SpriteY = yMin ' initial sprite position
> If flipX = True Then
> ' Note about flipping: At first I used the same DC for
> ' both the source and destination in the call to
> ' StretchBlt, and it worked okay on both machines on
> ' which I tested it (both running Vista) but I have a
> ' feeling that doing so might not work on all systems
> ' because it relies on the behaviour of the underlying
> ' StretchBlt algorithm working on all machines in a way
> ' that will allow such a technique to succeed. Therefore
> ' the following code uses an aternative method of flipping
> ' into a temporary DC first and then blitting the result
> ' from the temporary DC to the destination DC.
> '
> ' flip the mask
> StretchBlt picTemp.hdc, spriteWide - 1, 0, -spriteWide, _
> spriteHigh, picMask.hdc, _
> 0, 0, spriteWide, spriteHigh, vbSrcCopy
From: Bee on
This is where I am at.
Regions
I modified my flip routine and got the regions method to work.
Why, because I realized that I did not understand how important .CLS is.
Is it that the mask is not overwritten and needs to be .CLS before
overwiting? seems so.
I am using a pic temp that is sized and cleared then StretchBlt into it.
Then the image destination (the original source) is .CLS and BitBlt into.
This works fine.

Viewport
I "adjusted" the code to provide flipping both horz, vert and both.
This works per the structure you presented.
But the operation is not what I need.
I need to be able to lasso the area, move it around and then apply the flip
as needed.
Unfortunately, I have only been able to figure out how to flip.
The sprite is in the original position but the rubberband will not follow.
I would really prefer to have the sprite moved then flip in place with
rubberband correctly positioned.



From: Mike Williams on
"Bee" <Bee(a)discussions.microsoft.com> wrote in message
news:A4EA3749-0AE4-4A11-BB4C-6C7C4DC1865D(a)microsoft.com...

> I modified my flip routine and got the regions method
> to work. Why, because I realized that I did not understand
> how important .CLS is. Is it that the mask is not overwritten
> and needs to be .CLS before overwiting? seems so.

Yes. Cls performs a number of functions but the important one in this
specific case is that it fills the PictureBox with its background colour,
which in the case of the mask PictureBox is white, thereby clearing any
"black on white" mask image that it might have previously contained, so that
we are starting off with a solid white PictureBox before we draw the shape
of the mask onto it. This clearing of the PictureBox to white would not be
needed if we were blitting or stretching a similarly sized image into it
(using the standard vbSrcCopy), because the blit would entirely overwite the
existing contents anyway, but it is needed in the case of our mask because
we are drawing a defined filled shape into it rather than blitting, and the
filled shape will overwrite only the stuff that happens to be directly
undeneath the shape itself. The black part of the mask is drawn onto the
white background using the GDI PaintRgn function, which in this specific
case (picbox FillStyle = vbFSSolid and FillColor = vbBlack) draws a solid
black shape onto the otherwise white background in order to produce our
"black on white" mask.

By the way, I noticed that there actually was a Cls immediately before
PaintRgn in the code extract you posted the other day, otherwise I would
have mentioned it before, so perhaps there was the required Cls missing from
somewhere else in your code, which you have now fixed. Anyway, you seem to
have that part of your problem sorted now.

> I "adjusted" the code to provide flipping both horz, vert and
> both. This works per the structure you presented. But the
> operation is not what I need. I need to be able to lasso the
> area, move it around and then apply the flip as needed.
> Unfortunately, I have only been able to figure out how to
> flip. The sprite is in the original position but the rubberband
> will not follow. I would really prefer to have the sprite moved
> then flip in place with rubberband correctly positioned.

By "rubber band" I take it you mean the marching ants outline that is the
same shape as the sprite and that sticks with it as you drag it around the
screen? Are you having problems creating and drawing that marching ants
outline correctly on a standard orientation sprite, or just on a "flipped"
sprite, or perhaps both? Also, when you say "it will not follow" do you mean
that the marching ants outline flips and positions itself correctly but does
not follow the sprite as you move it, or do you mean it either flips or
positions itself incorrectly, and follows the flipped sprite but at the
wrong position? Or all or some of those?

The code I previously posted draws the marching ants outline correctly for
both a standard sprite and a flipped sprite, although as it stands it allows
you to select "flip" only before you manually draw a sprite with the mouse,
and not afterwards. If you are having problems with that then perhaps you
have not worked the examples properly into your own code (which I notice
still uses regions as in my early examples rather method used in my later
examples which I suggested you should also use). Or is that side of things
still working okay and are you having problems only when you modify it so as
to allow the user to flip the sprite after it has been created, as per your
latest requirements?

Perhaps you would like to post back with more details of your problem,
explaining in more detail what the problem actually is. In the meantime,
with the current methods being used, if you are performing flips on an
already drawn sprite then as well as flipping the mask and the sprite image
you must also flip the POINTAPI array data, as per the code in the examples
I have already posted. Also, and this is important, you must also set the
appropriate offsets (PolyOffsetX and PolyOffsetY in the example code)
otherwise the Polygon will be drawn in its correct flipped state but not at
its correct flipped position.

To explain very briefly why this is necessary, imagine that in our mouse
move routines (where the user manually draws a shape using the mouse) the
user draws the shape of the left facing side view of a person's head and he
starts his drawing somewhere on the top of the head above the eye and moves
around the forehead and face and nose and chin and up around the back of the
head and around to his starting position. The various positions of the mouse
as he moves it will end up in our array of POINTAPI data, and the starting
position (the point near the top of the head bove the eye) represents the
very first data item in our array of POINTAPI. When we use the GDI Polygon
function to draw that data it will effectively follow the mouse moves made
by the user, thus drawing the same shape that he drew and in the same
manner. However, when we "Xflip" that POINTAPI array data (such that the
start position remains the same but all other positions effectively move
right instead of left and vice versa) then the drawing will flip (the head
will be drawn facing right instead of left) but it will be in slightly the
wrong position. It's as though the drawing of the head was rotated around a
vertical pin fixed above the eye (the user's starting point). When the head
is flipped then an imaginary rectangle around the entire drawing of the head
will change its position, because the pin is not in the centre of the
rectangle. Does that make sense to you (I don't seem to have explained it as
well as I though I might)?

And of course the user can start a drawing at any point he wishes. The
Xflipped mask and sprite images will not have moved in such a way within
their imaginary enclosing rectangles of course, just the line drawing (the
"marching ants"). That's why it important that as well as positioning the
GDI Polygon marching ants output in accordance with the current x and y
coordinates of the sprite we must also position it in accordance with
whether or not the sprite is currently "flipped" from its original drawn
orientation. Those two offsets together (the offset in accordance with the
current sprite position and the offset according to it slipped state) are
applied to the GDI Polygon output using the SetViewportOrgEx function
immediately before calling Polygon to draw the "marching ants" outline. For
correct positioning it is important that your code records the state of the
drawing (whether it is currently flipped or not) and sets the PolyOffsetX
and PolyOffsetY values both to zero if the sprite is not currently flipped
and both to the calculated offset values if it is.

Anyway, if the above does not help you and if you are still having problems
then post again. I'll be going out shortly but if I get time later (perhaps
this evening) I'll modify my own previously posted example so that it
performs the flips "on the fly" as per your new requirements and I'll post
it for you.

Mike