From: Bee on
(1) when i click flip (on my mod of your latest code) the image flips
correctly but the rubberband is off to the side. also the filpped image
location jumps rather than staying at the newly moved to position.
the active area (cursor still correct over the sprite) can be moved and
rubberband moves but is off to the side and leaves a trail.
if i flip several times, the rubberband will line up gain in the proper place.
i am thinking that the rubberband shoud go away after the area iis selected
and the sprite first moves. to my eye, the rubberband makes it difficult to
line up the sprite for a paste.

(2) i prefer that the mouse cirsor does not reside inside the sprite during
a move since a small sprite is somewhat obscured by the cursor so in the
regions method i have working i offset the mouse (effectively) to the lower
right corner of the sprite.
the regions method does not have a rubberband while dragging and i think
that is better since the rubberbad can get in the way of placing the sprite.

thanks for you continued support.

"Mike Williams" wrote:

> "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
>
>
>
> .
>
From: Mike Williams on
"Bee" <Bee(a)discussions.microsoft.com> wrote in message
news:98190371-C484-4CAC-944B-23C725A8A67A(a)microsoft.com...

> (1) when i click flip (on my mod of your latest code) the
> image flips correctly but the rubberband is off to the side.

Well you're not actually using my code, but rather you have modified your
own code to include some of the functionality of mine, so I can't really say
exactly what is happening unless I see your own full code. However, the
reason why the rubberband (by which I presume you mean the marching ants
outline) is off to one side when you flip the sprite in your own code is
almost certainly because you have either not "flipped" the POINTAPI data as
well as the sprite and mask, or have flipped it but have not set the
appropriate offset to take account of the "rotation about the POINTAPI
starting position" that I mentioned in my previous response (the polyOffsetX
and polyOffsetY variables in my own posted example).

> location jumps rather than staying at the newly moved to
> position. the active area (cursor still correct over the sprite)
> can be moved and rubberband moves but is off to the side
> and leaves a trail.

Even when you fix the "off to one side" problem (as mentioned above) you are
still likely to find the marching ants outline leaves a trail under certain
conditions (at least with your code as it currently stands) because of the
slightly different behaviour of CreatePolygonRgn and PolyLine / Polygon on
the exact same set of POINTAPI data, resulting in some odd pixels of the
marching ants outline under some conditions being slightly outside the
sprite shape whilst most of them are just on the edge. That's why I
suggested in some previous posts that you would be wise to use something
other than CreatePolygonRgn when initially creating your mask and / or
sprite shapes from the POINTAPI data, so that the sprite and mask and the
marching ants outline are all exactly the same pixel for pixel size and
shape as the outline manually drawn by the user. That's what I do in the
examples I've been posting and it works well (apart from my very first
example which did use CreatePolygonRgn).

However, if you do want to stick with your existing code (which uses
CreatePolygonRgn in the creation of the sprite and mask) then there are
various ways of fixing your current "marching ants sometimes leaves a trail"
problem. Probably the easiest way is to simply draw a slightly larger
rectangle from the backbuffer when overwriting the sprite at its existing
position just before drawing it at its new position. Just a pixel or two
wider and taller will suffice.

> if i flip several times, the rubberband will line up gain in the
> proper place.

Again, that'll be because you are probably not setting the polyOffsetX and
polyOffsetY variables to the correct values when you perform a flip, or are
not taking them into account when drawing the marching ants. When the sprite
is flipped both of those variables should contain the appropriate calculated
offset, whereas when the sprite is not flipped they should both contain
zero, so in your own existing code (if it is as I imagine to to be)
sometimes they will be correct and sometimes they will not

> i am thinking that the rubberband shoud go away after the
> area iis selected and the sprite first moves. to my eye, the
> rubberband makes it difficult to line up the sprite for a paste.
> the regions method does not have a rubberband while dragging
> and i think that is better since the rubberbad

Yep. That's a good idea (although the marching ants visibility is not itself
a function of whether or not you use the Region method for the initial
creation of your sprite, it just happens to be the way it is apparently
currently working in your own code). Sprite visibility is much clearer when
the marching ants are present, and lining up for a final drop in the correct
desired position if often much easier when they are not present. It is still
necessary to fix your code so that they are drawn and positioned correctly
though, both on normal and flipped sprites, so that they are correct when
they actually are present. Have you thought about having a key the user can
press which turns the marching ants on or off (the Shift key perhaps, or
some other suitable key). I think that might probably be the best, because
then the user himself can decide when he wants the marching ant outline on
and when he wants it off, with it perhaps initially defaulting to "on" when
he first draws a sprite.

> (2) i prefer that the mouse cirsor does not reside inside the sprite
> during a move since a small sprite is somewhat obscured by the
> cursor so in the regions method i have working i offset the mouse
> (effectively) to the lower right corner of the sprite.

Yep. That's a good idea too for small sprites, and of course it can be
achieved whether you use your current Region method of creating the sprite
and mask or not.

Anyway, reading through this latest post of yours I'm not quite sure whether
you are telling me that you have it all working now (or are in the process
of getting it all working) or whether you are asking for some help to do so.
Perhaps you might like to post again if there is something you feel we have
not yet covered?

Mike



From: Mike Williams on
"Bee" <Bee(a)discussions.microsoft.com> wrote in message
news:98190371-C484-4CAC-944B-23C725A8A67A(a)microsoft.com...

> thanks for you continued support.

You're welcome. By the way, I meant to add some more example code to my
previous response but I forgot. Here is a modification of the code I have
previously posted. I've added a facility for flipping the sprite after you
have created it, as per your recent request. When the user initially draws
the outline of his desired sprite with the mouse the sprite is initially
created and displayed in its normal orientation. The user may then move the
sprite around the screen and he can flip it whenever he wishes simply by
pressing the Ctrl key. In fact the user can flip the sprite whilst he is
actually dragging it if he wishes to do so. The code should help you with
the problem you are currently having in your own code getting the marching
ants outline orientated and positioned correctly. Since it is just testbed
"proof of concept" code I've included just a horizontal flip, but having
seen your own example code I can see that you will have no trouble at all
modifying it yourself to include a horizontal flip as well. I've also just
now, in response to your most recent post, added the facility for the user
to turn the marching ants outline on or off at will by pressing the Shift
key. As before, paste the code into a new VB project containing a Form with
one Timer Control and five small PictureBoxes, appropriately named as per my
other examples:

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 Xflipped As Boolean, Yflipped As Boolean
Private CtrlDown As Boolean, ShiftDown As Boolean
Private ShowAnts As Boolean

Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
If Not SpriteDisplayed Then Exit Sub
If KeyCode = vbKeyControl Then
XFlipSprite
End If
If KeyCode = vbKeyShift Then
ShowAnts = Not ShowAnts
If SpriteDisplayed Then
DisplaySprite SpriteX, SpriteY, ShowAnts
End If
End If
End Sub

Private Sub XFlipSprite()
Dim n As Long
' 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 marching ants outline
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
Xflipped = Not Xflipped
If Xflipped Then
' this is needed for a flipped sprite
polyOffsetX = (spriteWide - 1) - ((d1(0).x - xMin) * 2)
polyOffsetY = 0 ' haven't done flipY yet
Else
' this is needed for a non flippped sprite
polyOffsetX = 0
polyOffsetY = 0
End If
' display the flipped sprite
DisplaySprite SpriteX, SpriteY, True
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
Me.KeyPreview = True
Timer1.Interval = 200
Timer1.Enabled = True
Caption = "Press Alt to flip sprite. " _
& "Press Shift to toggle marching ants on or off."
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 Button = 0 Then
' the above "If Button = 0" was added when I added
' code to allo the user to flip the sprite even as
' he was moving it, and it allows the mousepointer
' to remain in its "moving hand" state even if the
' flipped shape of the sprite initially causes the
' pointer to temporarily be outside of the shape
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 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
Xflipped = False
ShowAnts = True ' initial starting condition
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
polyOffsetX = 0
polyOffsetY = 0
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 And ShowAnts 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 And ShowAnts 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



From: Bee on
I have this latest code up and running in a stand alone app.
I works perfectly.
Now I am stepping through it to try to better understand what you have done.
Thank you very much for the time you have taken and the code you have written.

"Mike Williams" wrote:

> "Bee" <Bee(a)discussions.microsoft.com> wrote in message
> news:98190371-C484-4CAC-944B-23C725A8A67A(a)microsoft.com...
>
> > thanks for you continued support.
>
> You're welcome. By the way, I meant to add some more example code to my
> previous response but I forgot. Here is a modification of the code I have
> previously posted. I've added a facility for flipping the sprite after you
> have created it, as per your recent request. When the user initially draws
> the outline of his desired sprite with the mouse the sprite is initially
> created and displayed in its normal orientation. The user may then move the
> sprite around the screen and he can flip it whenever he wishes simply by
> pressing the Ctrl key. In fact the user can flip the sprite whilst he is
> actually dragging it if he wishes to do so. The code should help you with
> the problem you are currently having in your own code getting the marching
> ants outline orientated and positioned correctly. Since it is just testbed
> "proof of concept" code I've included just a horizontal flip, but having
> seen your own example code I can see that you will have no trouble at all
> modifying it yourself to include a horizontal flip as well. I've also just
> now, in response to your most recent post, added the facility for the user
> to turn the marching ants outline on or off at will by pressing the Shift
> key. As before, paste the code into a new VB project containing a Form with
> one Timer Control and five small PictureBoxes, appropriately named as per my
> other examples:
>
> 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 Xflipped As Boolean, Yflipped As Boolean
> Private CtrlDown As Boolean, ShiftDown As Boolean
> Private ShowAnts As Boolean
>
> Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
> If Not SpriteDisplayed Then Exit Sub
> If KeyCode = vbKeyControl Then
> XFlipSprite
> End If
> If KeyCode = vbKeyShift Then
> ShowAnts = Not ShowAnts
> If SpriteDisplayed Then
> DisplaySprite SpriteX, SpriteY, ShowAnts
> End If
> End If
> End Sub
>
> Private Sub XFlipSprite()
> Dim n As Long
> ' 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 marching ants outline
> 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
> Xflipped = Not Xflipped
> If Xflipped Then
> ' this is needed for a flipped sprite
> polyOffsetX = (spriteWide - 1) - ((d1(0).x - xMin) * 2)
> polyOffsetY = 0 ' haven't done flipY yet
> Else
> ' this is needed for a non flippped sprite
> polyOffsetX = 0
> polyOffsetY = 0
> End If
> ' display the flipped sprite
> DisplaySprite SpriteX, SpriteY, True
> 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
> Me.KeyPreview = True
> Timer1.Interval = 200
> Timer1.Enabled = True
> Caption = "Press Alt to flip sprite. " _
> & "Press Shift to toggle marching ants on or off."
> 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 Button = 0 Then
> ' the above "If Button = 0" was added when I added
> ' code to allo the user to flip the sprite even as
> ' he was moving it, and it allows the mousepointer
> ' to remain in its "moving hand" state even if the
> ' flipped shape of the sprite initially causes the
> ' pointer to temporarily be outside of the shape
> 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 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
> Xflipped = False
> ShowAnts = True ' initial starting condition
> 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