DirectX:DirectDraw:Tutorials:VB:DX7:Special Effects

From GPWiki

Files:GUITutorial_warn.gif The Game Programming Wiki has moved! Files:GUITutorial_warn.gif

The wiki is now hosted by GameDev.NET at wiki.gamedev.net. All gpwiki.org content has been moved to the new server.

However, the GPWiki forums are still active! Come say hello.

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 
Copies 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, the BitBlt API call can take over; The BitBlt API call 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 the BitBlt API call 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 call, 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 this sample source code to see all of the different ROPs in action.