Special Effects

Too lazy to write a C, C++, or ASM DLL to do your special effects dirty work? Put blitter Raster Operations (ROPs) to work for you! Maximal results with minimal effort, that's my motto ;)

There are a number of different ROP constants available to us in VB:

  • vbSrcPaint - ORs the source and destination image data, giving a pseudo-alphablending effect.
  • vbSrcAnd - ANDs the source and destination image data, giving a pseudo-gamma effect.
  • vbSrcInvert - XORs the source and destination image data.
  • vbSrcErase - Inverts the destination image data then ANDs with the source image data.
  • vbSrcCopy - Copy the source image data directly onto the destination, replacing it completely.
  • vbDstInvert - Inverts the destination image data, and ignores the source image data completely.
  • vbNotSrcCopy - Inverts the source image data and copies directly onto the destination, replacing it completely.
  • vbNotSrcErase - ORs the source and destination image data and inverts the result.

    Now, we have two methods at our disposal for implementing these various ROPs. We can use the API BitBlt function, or we can use the DirectX BltFx function. BltFx will ONLY work if the user's video card supports the ROP in hardware. BltFx WILL fail otherwise! Where BltFx fails however, BitBlt API can take over; The BitBlt API will never fail since all operations are carried out via software!

    (Important Speed Consideration: When using BltFx, it is ideal to place surfaces in Video Memory as they can be accessed there most quickly by the video card's blitter. When using BitBlt API on the other hand, it is ideal to place surfaces in System Memory, otherwise the data must be fetched from video memory, modified, and then sent back to video memory. Inefficient!)

    It would be nice to know for certain whether the user's video card can support a specific ROP in hardware or not, and I have written a simple function to do just that:

    Private Function TestROP(ByRef surfBack As DirectDrawSurface7, lngROP As Long) As Boolean
    
    Dim objBltFx As DDBLTFX
    Dim rectTemp As RECT
    Dim surfTemp As DirectDrawSurface7
    Dim udtDDSD As DDSURFACEDESC2
    
        'Create a small temporary surface
        udtDDSD.lFlags = DDSD_HEIGHT Or DDSD_WIDTH
        udtDDSD.lHeight = 1
        udtDDSD.lWidth = 1
        Set surfTemp = mdd.CreateSurface(udtDDSD)
        
        'Set the BltFx ROP code
        objBltFx.lROP = lngROP
        
        'Our source and dest rectangle
        rectTemp.Right = 1
        rectTemp.Bottom = 1
        
        'Test the BltFx capability
        If surfBack.BltFx(rectTemp, surfTemp, rectTemp, DDBLT_ROP Or DDBLT_WAIT, objBltFx) <> 0 Then
            TestROP = False
        Else
            TestROP = True
        End If
    
    End Function
    

    Simply pass this function a reference to your current backbuffer and the ROP constant you're interested in and it will inform you of the user's hardware capabilities. It does this by performing a sample BltFx blit and examining the error code returned.

    Now that we know if our desired ROP is supported, we can go ahead and perform our blit! If the ROP is supported, we can use BltFx, like so:

        objBltFx.lROP = lngROP
        msurfBack.BltFx rectDest, surfDisplay, rectSource, DDBLT_ROP Or DDBLT_WAIT, objBltFx
    

    objBltFx is of the DDBLTFX type, and must be loaded with the ROP we wish to perform (here stored in lngROP). Once we have our DDBLTFX type filled, we can call the backbuffer's BltFx method, passing our source and dest rectangles, our desired surface, a few constants (DDBLT_ROP and DDBLT_WAIT) and our objBltFx. The constant DDBLT_ROP is required, informing BltFx that we wish to use the lROP member of the DDBLTFX structure.

    If we're forced to use the BitBlt API, it can be handled in this fashion:

        'Lock down the surface DCs
        lngDestDC = msurfBack.GetDC
        lngSrcDC = surfDisplay.GetDC
    	
        'Do the fancy old-fashioned blit
        BitBlt lngDestDC, intX, intY, intWidth, intHeight, lngSrcDC, 0, 0, lngROP
    	
        'Release our DCs
        surfDisplay.ReleaseDC lngSrcDC
        msurfBack.ReleaseDC lngDestDC
    

    First we need to acquire the source (surface to be blitted) and destination (backbuffer) DCs. Once we have them, we feed this data into the BitBlt call, along with our sprite dimensions and the ROP we desire (lngROP). Afterward we MUST release the DCs, lest we freeze the computer

    So there you have it! A few magic little functions and you can employ nifty raster operations in your games and programs. Download the source to see all of the different ROPs in action.