dcsimg
Results 1 to 4 of 4
  1. #1

    Thread Starter
    PowerPoster
    Join Date
    Feb 2006
    Posts
    18,852

    PlgBlt weirdness... or a bug?

    So I was playing around and ran into something odd.

    This code uses PlgBlt() to draw a "compass needle" and spin it on a Timer:

    Code:
    Option Explicit
    
    Private Needle As StdPicture
    Private Rotation As Long
    
    Private Sub Form_Load()
        Set Needle = LoadResPicture("NEEDLE", vbResBitmap)
        Timer1.Enabled = True
    End Sub
    
    Private Sub Timer1_Timer()
        With Picture1
            .AutoRedraw = True
            .Cls
            PlgBlt.Render Picture1, 0, 0, 300, 300, Needle, vbGreen, Rotation, 1
            .AutoRedraw = False
        End With
        Rotation = (Rotation + 1) Mod 360
    End Sub
    Name:  sshot1.png
Views: 79
Size:  1.8 KB

    For the most part it works just fine, but at two rotation angles (95 deg. and about 180 deg. past that) the dot in the center stretches strangely:

    Name:  sshot2.png
Views: 79
Size:  1.5 KB


    Here is the code:

    Code:
    Public Sub Render( _
        ByVal Dest As Object, _
        ByVal DestX As Long, _
        ByVal DestY As Long, _
        ByVal DestWidth As Long, _
        ByVal DestHeight As Long, _
        ByVal Source As StdPicture, _
        ByVal MaskColor As Long, _
        Optional ByVal Rotation As Double, _
        Optional ByVal SourceScale As Double = 1, _
        Optional ByVal SourceX As Long, _
        Optional ByVal SourceY As Long, _
        Optional ByVal SourceWidth As Long, _
        Optional ByVal SourceHeight As Long)
        'Dest is a Form, UserControl with an hDC, PictureBox, etc. or the Printer object for
        'a printer that supports this operation (PlgBlt).
        '
        'Source is a bitmap type StdPicture.
        '
        'MaskColor is the pixel color within Source to be treated as transparent.
        '
        'Rotation is a clockwise angle in degrees.
        '
        'SourceScale is a scale factor, 1.0 = 100%.
        '
        'When SourceWidth and/or SourceHeight are 0 we will use the full size of Source.
    
        Dim BITMAP As BITMAP
        Dim hbmMask As Long
        Dim hdcMemColor As Long
        Dim hbmColorOrig As Long
        Dim bkColorOrig As Long
        Dim hDCMemMask As Long
        Dim hbmMaskOrig As Long
        Dim Points(2) As POINTAPI
        Dim I As Long
        Dim RotatedPoints(2) As POINTAPI
        Dim StretchBltModeOrig As StretchBltModes
    
        'Set up memory DCs and create mask bitmap:
        GetBitmap Source.Handle, LenB(BITMAP), BITMAP
        With BITMAP
            If SourceWidth < 1 Then SourceWidth = .bmWidth
            If SourceHeight < 1 Then SourceHeight = .bmHeight
            hbmMask = CreateBitmap(.bmWidth, .bmHeight, 1, 1, WIN32_NULL)
        End With
        hdcMemColor = CreateCompatibleDC(Dest.hDC)
        hbmColorOrig = SelectObject(hdcMemColor, Source.Handle)
        bkColorOrig = SetBkColor(hdcMemColor, MaskColor)
        hDCMemMask = CreateCompatibleDC(Dest.hDC)
        hbmMaskOrig = SelectObject(hDCMemMask, hbmMask)
        BitBlt hDCMemMask, 0, 0, SourceWidth, SourceHeight, hdcMemColor, 0, 0, vbNotSrcCopy
        SetBkColor hdcMemColor, bkColorOrig
    
        'Origins at center (0, 0) of the dest area:
        Points(0).x = Int(SourceScale * SourceWidth + 0.5) \ 2 - Int(SourceScale * SourceWidth + 0.5)
        Points(0).y = Int(SourceScale * SourceHeight + 0.5) \ 2 - Int(SourceScale * SourceHeight + 0.5)
        Points(1).x = Points(0).x + Int(SourceScale * SourceWidth + 0.5)
        Points(1).y = Points(0).y
        Points(2).x = Points(0).x
        Points(2).y = Points(0).y + Int(SourceScale * SourceHeight + 0.5)
        'Degrees to radians:
        Rotation = Rotation * PI / 180
        'Rotate points and adjust origins:
        For I = 0 To 2
            RotatedPoints(I).x = (DestX + DestWidth) \ 2 _
                               + Int(Points(I).x * Cos(Rotation) - Points(I).y * Sin(Rotation) + 0.5)
            RotatedPoints(I).y = (DestY + DestHeight) \ 2 _
                               + Int(Points(I).x * Sin(Rotation) + Points(I).y * Cos(Rotation) + 0.5)
        Next
    
        StretchBltModeOrig = SetStretchBltMode(Dest.hDC, sbmHalftone)
        If PlgBlt(Dest.hDC, _
                  RotatedPoints(0), _
                  hdcMemColor, _
                  SourceX, _
                  SourceY, _
                  SourceWidth, _
                  SourceHeight, _
                  hbmMask, _
                  SourceX, _
                  SourceY) = 0 Then
            Err.Raise &H8004C700, TypeName(Me), "PlgBlt error " & CStr(Err.LastDllError)
        End If
        SetStretchBltMode Dest.hDC, StretchBltModeOrig
    
        'Cleanup:
        SelectObject hDCMemMask, hbmMaskOrig
        DeleteDC hDCMemMask
        SelectObject hdcMemColor, hbmColorOrig
        DeleteDC hdcMemColor
    End Sub
    I can't tell whether I have a bug, some sort of rounding error, or a flaw in PlgBlt() working with my video adapter or its driver.

    I haven't tried to use this GDI call in a very long time, so I may have just screwed it up. The rotation logic may be more convoluted than necessary too, it is just "air code" with a few tweaks until it seemed to work.

    Any ideas?
    Attached Files Attached Files

  2. #2
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    4,446

    Re: PlgBlt weirdness... or a bug?

    No, I think you're seeing a known bug. I've used plgblt a bit in the past, and I know that I had to check to insure I didn't use an exact 180 degree rotation, always added a slight offset like .001 to avoid the issue.

    I'm not 100% sure that is what you're seeing, but I know there is a bug. Since your rotation is around 95 degrees and 180 off of that, it might be a variation of the bug.
    I changed from using plgblt to using the gdi matrix call to implement rotation later on (actually a bit simpler, I think), and I don't know if it has the same issues or not.

    I have to go to a long meeting, and have a number of meetings today so don't have time to dig around and see if I can fine some examples of where I've used plgblt vs matrix rotation for comparison. Maybe, this evening.
    Last edited by passel; Jun 12th, 2018 at 06:54 AM.

  3. #3
    Frenzied Member
    Join Date
    Jun 2015
    Posts
    1,959

    Re: PlgBlt weirdness... or a bug?

    http://www.vb-fun.de/cgi-bin/forumar...&nummer=164134

    Hello NW90,
    yes, that's a bug. The somewhat inelegant solution is to offset
    the coordinates of
    a vertex by one pixel at a rotation angle of 180 . This
    does not create an exact rectangle and the error does
    not occur. The clean, but rather elaborate, solution
    is to
    execute the rotation with StretchBlt (negative width and height) in
    another bitmap at an angle of rotation of 180 and then
    to copy it into the target bitmap with TransparentBlt.

    Greetings,
    Imagine what it would be like to set breakpoints in, or step through subclassing code;
    and then being able to hit stop/end/debug or continue, without crashing the IDE.

    VB6.tlb | Bulletproof Subclassing in the IDE (no thunks/assembly/DEP issues)

  4. #4

    Thread Starter
    PowerPoster
    Join Date
    Feb 2006
    Posts
    18,852

    Re: PlgBlt weirdness... or a bug?

    Thanks, that's probably it. It is even beginning to sound familiar so it was probably discussed a lot in days gone by.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Featured


Click Here to Expand Forum to Full Width


×
We have made updates to our Privacy Policy to reflect the implementation of the General Data Protection Regulation.