From: Bee on 12 Dec 2009 19:56 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 13 Dec 2009 06:22 "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 13 Dec 2009 23:19 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 15 Dec 2009 22:26 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 16 Dec 2009 09:08 "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
First
|
Prev
|
Next
|
Last
Pages: 1 2 3 Prev: New problem installing VB6 on Win7 64 bit Next: converting doubles to string |