home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / directx / mosquito / mosquito.cpp < prev    next >
C/C++ Source or Header  |  1997-10-09  |  32KB  |  897 lines

  1. //****************************************************************************
  2. //* Program: Mosquito
  3. //*
  4. //* Description:
  5. //*     Sample application to demonstrate the creation, display, and 
  6. //*     positioning of overlays.
  7. //*
  8. //* Contents:
  9. //*     WinMain() - Main entry point for this application.
  10. //*     MainDlgProc() - Message proc for this app.
  11. //*     InitDirectDraw() - Creates core DirectDraw objects.
  12. //*     FreeDirectDraw() - Frees up core DirectDraw objects.
  13. //*     CreatePrimarySurface() - Creates Primary surface.
  14. //*     CreateOverlay() - Creates a multi-buffer flippable overlay surface.
  15. //*     DestroyOverlay() - Hides overlay surface and releases it.
  16. //*     CopyBitmapToYUVSurface() - Copies a GDI bitmap to a YUV surface.
  17. //*                                Used by LoadImageOntoSurface().
  18. //*     LoadImageOntoSurface() - Loads a resource based bitmap onto a surface.
  19. //*     EnumAttachedCallback() - Callback for EnumAttachedSurfaces().
  20. //*     DisplayOverlay() - Displays our overlay on the primary.
  21. //*     RestoreAllSurfaces() - Restores the primary and overlay surfaces.
  22. //*     MoveOverlayTimerCallback() - TimerProc for moving the overlay surface.
  23. //*
  24. //* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF 
  25. //* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO 
  26. //* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 
  27. //* PARTICULAR PURPOSE.
  28. //*
  29. //* Copyright (C) 1996-1997 Microsoft Corporation.  All Rights Reserved.
  30. //****************************************************************************
  31.  
  32. // C RunTime Header Files
  33. #include <stdlib.h>
  34. #include <malloc.h>
  35. #include <memory.h>
  36.  
  37. // Windows Header Files:
  38. #include <windows.h>
  39. #include <mmsystem.h> //added to compile under NT
  40. #define INITGUID
  41. #include <objbase.h>
  42. #include <initguid.h>
  43. #include <ddraw.h>                                                                
  44.  
  45. // Local Headers
  46. #include "resource.h"
  47.  
  48. // Define some macros
  49. #define INIT_DIRECTDRAW_STRUCT(x) (ZeroMemory(&x, sizeof(x)), x.dwSize=sizeof(x))
  50. #define RAND_INT(x) (rand()*x/RAND_MAX)
  51. #define RANDOM_VELOCITY() ((RAND_INT(5)+3)*2)
  52.  
  53. // Global Variables:
  54.  
  55. LPDIRECTDRAW2       g_lpdd = NULL;
  56. LPDIRECTDRAWSURFACE g_lpddsPrimary = NULL;
  57. LPDIRECTDRAWSURFACE g_lpddsOverlay = NULL;
  58.  
  59. int g_nOverlayXPos, g_nOverlayYPos;
  60. int g_nOverlayXVel, g_nOverlayYVel;
  61. int g_nOverlayWidth, g_nOverlayHeight;
  62. int g_nOverlayFlipCounter; 
  63. DWORD g_dwOverlayXPositionAlignment;  // used to keep track of any alignment
  64.                                       // restrictions on the X postion of
  65.                                       // our overlay surface.  Comes from the
  66.                                       // the DDCAPS dwBoundaryAlignDest field.
  67.                                       // Initialized in DisplayOverlay().
  68.  
  69. // These are the pixel formats this app supports.  Most display adapters
  70. // with overlay support will recognize one or more of these formats.
  71. // The first on our list is the 16-bit RGB formats.  These have the widest
  72. // support.
  73. DDPIXELFORMAT g_ddpfOverlayFormats[] = 
  74. {   {sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 16,  0x7C00, 0x03e0, 0x001F, 0},      // 16-bit RGB 5:5:5
  75.     {sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 16,  0xF800, 0x07e0, 0x001F, 0},   // 16-bit RGB 5:6:5
  76.     {sizeof(DDPIXELFORMAT), DDPF_FOURCC,MAKEFOURCC('U','Y','V','Y'),0,0,0,0,0}, // UYVY
  77.     {sizeof(DDPIXELFORMAT), DDPF_FOURCC,MAKEFOURCC('Y','U','Y','2'),0,0,0,0,0}};  // YUY2
  78.  
  79. #define NUM_OVERLAY_FORMATS (sizeof(g_ddpfOverlayFormats) / sizeof(g_ddpfOverlayFormats[0]))
  80.  
  81. // Define some error messages.  If we had many more we'd stick 'em in our RC file.
  82. #define NO_OVERLAY_HARDWARE     "Sorry, In order to run this sample application you must "\
  83.                                 "have a display adapter and driver which support overlays."
  84.  
  85. #define UNABLE_TO_CREATE_OVERLAY    "Sorry, your display adapter appears to "\
  86.                                     "support overlays, but we were unable to "\
  87.                                     "create an overlay in any of the formats "\
  88.                                     "this app supports (16-bit RGB and YUV).  "\
  89.                                     "You may want to try shutting down other "\
  90.                                     "DirectX apps to free video memory, or try "\
  91.                                     "rerunning this app in a different display "\
  92.                                     "mode."
  93.  
  94. #define UNABLE_TO_DISPLAY_OVERLAY   "Sorry, we created an overlay on your "\
  95.                                     "system, but were unable to display it.  "\
  96.                                     "Please try rerunning this app in "\
  97.                                     "a different display mode."
  98.  
  99. //****************************************************************************
  100. //* Function: FreeDirectDraw
  101. //*
  102. //* Description:
  103. //*             Releases core DirectDraw objects
  104. //****************************************************************************
  105. void FreeDirectDraw(void)
  106. {
  107.     if (g_lpddsPrimary)
  108.     {
  109.         g_lpddsPrimary->Release();
  110.         g_lpddsPrimary=NULL;
  111.     }
  112.  
  113.     if (g_lpdd)
  114.     {
  115.         g_lpdd->Release();
  116.         g_lpdd=NULL;
  117.     }
  118. }
  119.  
  120.  
  121. //****************************************************************************
  122. //* Function: CreatePrimarySurface()
  123. //*
  124. //* Description:
  125. //*     Creates a Primary Surface.  Implemented as a separate function from
  126. //* InitDirectDraw() because we occasionally need to just recreate the primary
  127. //* surface such as when a mode change occurs.
  128. //****************************************************************************
  129. HRESULT CreatePrimarySurface()
  130. {
  131.     DDSURFACEDESC   ddsd;
  132.     HRESULT         ddrval;
  133.  
  134.     if (!g_lpdd) return E_FAIL;
  135.  
  136.     INIT_DIRECTDRAW_STRUCT(ddsd);
  137.     ddsd.dwFlags = DDSD_CAPS;
  138.     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
  139.     ddrval = g_lpdd->CreateSurface(&ddsd, &g_lpddsPrimary, NULL );
  140.  
  141.     return ddrval;
  142. }
  143.  
  144.  
  145. //****************************************************************************
  146. //* Function: InitDirectDraw
  147. //*
  148. //* Description:
  149. //*     Performs DirectDraw initialization.  Creates a primary surface which
  150. //*     is needed to display our overlay on.  The actual overlay surface is
  151. //*     created later in our CreateOverlay() call.
  152. //****************************************************************************
  153. BOOL InitDirectDraw()
  154. {
  155.     HRESULT         ddrval;
  156.     LPDIRECTDRAW    lpDD1;
  157.  
  158.     ddrval = DirectDrawCreate( NULL, &lpDD1, NULL );
  159.     if( FAILED(ddrval))
  160.         goto ErrorOut;
  161.  
  162.     ddrval = lpDD1->QueryInterface(IID_IDirectDraw2, (void **)&g_lpdd);
  163.     if( FAILED(ddrval))
  164.         goto ErrorOut;
  165.     
  166.     lpDD1->Release();
  167.  
  168.     // For NORMAL cooperative level we no longer need to provide an HWND.
  169.     ddrval = g_lpdd->SetCooperativeLevel(NULL, DDSCL_NORMAL);
  170.     if( FAILED(ddrval))
  171.         goto ErrorOut;
  172.  
  173.     ddrval= CreatePrimarySurface();
  174.     if( FAILED(ddrval))
  175.         goto ErrorOut;
  176.  
  177.  
  178.     return TRUE;
  179.  
  180. ErrorOut:
  181.  
  182.     FreeDirectDraw();
  183.  
  184.     return FALSE;
  185. }
  186.  
  187.  
  188. //****************************************************************************
  189. //* Function: DestroyOverlay()
  190. //* Description:
  191. //*     Hides the overlay then releases it's surface.
  192. //****************************************************************************
  193. void DestroyOverlay()
  194. {
  195.     if (g_lpddsOverlay)
  196.     {
  197.         // Use UpdateOverlay() with the DDOVER_HIDE flag to remove an overlay 
  198.         // from the display.
  199.         g_lpddsOverlay->UpdateOverlay(NULL, g_lpddsPrimary, NULL, DDOVER_HIDE, NULL);
  200.         g_lpddsOverlay->Release();
  201.         g_lpddsOverlay=NULL;
  202.     }
  203. }
  204.  
  205.  
  206. //****************************************************************************
  207. //* Function: CopyBitmapToYUVSurface
  208. //* Description: 
  209. //*     Copies an RGB GDI bitmap to a YUV surface. Both bitmap and surface
  210. //*     must be a multiple of 2 pixels in width for the supported YUV formats.  
  211. //*     The following formats are supported:
  212. //*             YUY2
  213. //*             UYVY
  214. //*     
  215. //*     The "YUY2" YUV pixel format looks like this:
  216. //*         As a series of BYTES:    [Y0][U][Y1][V] (reverse it for a DWORD)
  217. //*
  218. //*     The "UYVY" YUV pixel format looks like this:
  219. //*         As a series of BYTES:    [U][Y0][V][Y1] (reverse it for a DWORD)
  220. //*
  221. //*     As you can see, both formats pack two pixels into a single DWORD. The 
  222. //*     pixels share U and V components and have separate Y components.
  223. //*     
  224. //* Returns: TRUE if successful, otherwise FALSE.
  225. //****************************************************************************
  226. BOOL CopyBitmapToYUVSurface(LPDIRECTDRAWSURFACE lpDDSurf, HBITMAP hbm)
  227. {
  228.     HDC                 hdcImage;
  229.     HRESULT             ddrval;
  230.     DDSURFACEDESC       ddsd;
  231.     DWORD               x, y, dwWidth, dwHeight;
  232.     LONG                lPitch;
  233.     LPBYTE              pSurf;
  234.     DWORD               dwBytesInRow;
  235.     COLORREF            color;
  236.     BYTE                R,G,B, Y0,Y1,U,V;
  237.     BOOL                bRet = FALSE;
  238.  
  239.     if (hbm == NULL || lpDDSurf == NULL)
  240.         return FALSE;
  241.  
  242.     //
  243.     //  select bitmap into a memoryDC so we can use it.
  244.     //
  245.     hdcImage = CreateCompatibleDC(NULL);
  246.     SelectObject(hdcImage, hbm);
  247.  
  248.  
  249.     INIT_DIRECTDRAW_STRUCT(ddsd);
  250.     // Lock down the surface so we can modify it's contents.
  251.     ddrval=lpDDSurf->Lock( NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT, NULL);
  252.     if (FAILED(ddrval))
  253.         goto CleanUp;
  254.  
  255.     dwWidth=ddsd.dwWidth;
  256.     dwHeight=ddsd.dwHeight;
  257.     lPitch=ddsd.lPitch;
  258.     pSurf=(LPBYTE)ddsd.lpSurface;
  259.     dwBytesInRow=ddsd.dwWidth*2;
  260.  
  261.     // Go through the image 2 pixels at a time and convert to YUV
  262.     for(y=0; y<dwHeight; y++)
  263.     {
  264.         for(x=0; x<dwWidth; x+=2)
  265.         {
  266.             // The equations for color conversion used here, probably aren't 
  267.             // exact, but they seem to do an OK job.
  268.             color=GetPixel(hdcImage, x,y);
  269.             R=GetRValue(color);
  270.             G=GetGValue(color);
  271.             B=GetBValue(color);
  272.             Y0= (BYTE)(0.29*R + 0.59*G + 0.14*B);
  273.             U= (BYTE)(128.0 - 0.14*R - 0.29*G + 0.43*B);
  274.  
  275.             color=GetPixel(hdcImage, x+1,y);
  276.             R=GetRValue(color);
  277.             G=GetGValue(color);
  278.             B=GetBValue(color);
  279.             Y1= (BYTE)(0.29*R + 0.57*G + 0.14*B);
  280.             V= (BYTE)(128.0 + 0.36*R - 0.29*G - 0.07*B);
  281.  
  282.             switch (ddsd.ddpfPixelFormat.dwFourCC)
  283.             {
  284.                 case MAKEFOURCC('Y','U','Y','2'): 
  285.                     *(pSurf++) = Y0;
  286.                     *(pSurf++) = U;
  287.                     *(pSurf++) = Y1;
  288.                     *(pSurf++) = V;
  289.                     break;
  290.                 case MAKEFOURCC('U','Y','V','Y'): 
  291.                     *(pSurf++) = U;
  292.                     *(pSurf++) = Y0;
  293.                     *(pSurf++) = V;
  294.                     *(pSurf++) = Y1;
  295.                     break;
  296.             }                       
  297.         }
  298.         pSurf+=(lPitch-dwBytesInRow);
  299.     }
  300.  
  301.     lpDDSurf->Unlock(NULL);     
  302.  
  303. CleanUp:
  304.     if(hdcImage)
  305.         DeleteDC(hdcImage);
  306.  
  307.     return TRUE;
  308. }
  309.  
  310. //****************************************************************************
  311. //* Function: LoadImageOnToSurface
  312. //* Description:
  313. //*     Loads a resource based bitmap image onto a DirectDraw surface.  Can
  314. //*     covert the bitmap to all RGB formats, plus a couple YUV formats.
  315. //****************************************************************************
  316. BOOL LoadImageOntoSurface(LPDIRECTDRAWSURFACE lpdds, LPSTR lpstrResID)
  317. {
  318.     HBITMAP hbm;
  319.     HDC     hdcImage= NULL;
  320.     HDC     hdcSurf = NULL;
  321.     BOOL bRetVal = FALSE;
  322.     HRESULT ddrval;
  323.     DDSURFACEDESC ddsd;
  324.  
  325.     if (!lpdds)
  326.         return FALSE;
  327.  
  328.     //
  329.     // get surface size and format.
  330.     //
  331.     INIT_DIRECTDRAW_STRUCT(ddsd);
  332.     ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH;
  333.     ddrval = lpdds->GetSurfaceDesc(&ddsd);
  334.     if (FAILED(ddrval))
  335.         goto Exit;
  336.  
  337.        // Load the bitmap resource.  We'll use LoadImage() since it'll scale the 
  338.     // image to fit our surface, and maintain the color information in the
  339.     // bitmap.
  340.     hbm = (HBITMAP) LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(lpstrResID), IMAGE_BITMAP, ddsd.dwWidth, ddsd.dwHeight, LR_CREATEDIBSECTION);
  341.     if (hbm == NULL)
  342.         goto Exit;
  343.  
  344.  
  345.     // If our surface is a FOURCC YUV format, we need to do a little work to convert
  346.     // our RGB resource bitmap into the appropriate YUV format.
  347.     if (ddsd.ddpfPixelFormat.dwFlags == DDPF_FOURCC)
  348.     {
  349.         if (!CopyBitmapToYUVSurface(lpdds, hbm))
  350.             goto Exit;        
  351.     }
  352.     else  //Looks like we're just using a standard RGB surface format, let GDI do the work.
  353.     {
  354.         // Create a DC and associate the bitmap with it.
  355.         hdcImage = CreateCompatibleDC(NULL);
  356.         SelectObject(hdcImage, hbm);
  357.    
  358.         ddrval = lpdds->GetDC(&hdcSurf);
  359.         if (FAILED(ddrval))
  360.             goto Exit;
  361.     
  362.         if (BitBlt(hdcSurf, 0, 0, ddsd.dwWidth, ddsd.dwHeight, hdcImage, 0, 0, SRCCOPY) == FALSE)
  363.             goto Exit;
  364.     }
  365.  
  366.     bRetVal = TRUE;
  367.     
  368. Exit:
  369.     if (hdcSurf)
  370.         lpdds->ReleaseDC(hdcSurf);
  371.     if (hdcImage)
  372.         DeleteDC(hdcImage);
  373.     if(hbm)
  374.         DeleteObject(hbm);
  375.  
  376.     return bRetVal;
  377.  
  378. }
  379.  
  380.  
  381. //****************************************************************************
  382. //* Function: EnumAttachedCallback
  383. //* 
  384. //* Description:
  385. //*     Callback function for EnumAttachedSurfaces().  Used to recursively
  386. //*     load each frame of the flying insect animation onto the appropriate
  387. //*     overlay surface buffer.
  388. //****************************************************************************
  389. HRESULT WINAPI EnumAttachedCallback(LPDIRECTDRAWSURFACE lpdds, LPDDSURFACEDESC lpddsd, LPVOID lpContext)
  390. {
  391.     int     nResourceID = (int)lpContext;
  392.     HRESULT hr = DDENUMRET_OK;
  393.  
  394.     // Check to see if we've gone full circle through all surfaces and are now looking at the first one again.
  395.     if (lpdds == g_lpddsOverlay)
  396.         goto Exit;
  397.  
  398.     if (!LoadImageOntoSurface(lpdds, MAKEINTRESOURCE(nResourceID)))
  399.     {
  400.         hr = DDENUMRET_CANCEL;
  401.         goto Exit;
  402.     }
  403.  
  404.     nResourceID++;
  405.  
  406.     lpdds->EnumAttachedSurfaces((LPVOID)nResourceID, EnumAttachedCallback);    
  407.  
  408. Exit:
  409.     lpdds->Release();
  410.     return DDENUMRET_OK;
  411. }
  412.  
  413. //****************************************************************************
  414. //* Function: DisplayOverlay
  415. //*
  416. //* Description:
  417. //*     Displays the overlay on the primary surface
  418. //****************************************************************************
  419. BOOL DisplayOverlay()
  420. {
  421.     HRESULT         ddrval;
  422.     RECT            rs, rd;
  423.     DDOVERLAYFX     ovfx;
  424.     DDCAPS          capsDrv;
  425.     unsigned int    uStretchFactor1000;
  426.     unsigned int    uDestSizeAlign, uSrcSizeAlign;
  427.     DWORD           dwUpdateFlags;
  428.  
  429.     if(!g_lpdd || !g_lpddsPrimary || !g_lpddsOverlay)
  430.         return FALSE;
  431.  
  432.     // Get driver capabilities
  433.     INIT_DIRECTDRAW_STRUCT(capsDrv);
  434.     ddrval = g_lpdd->GetCaps(&capsDrv, NULL);
  435.     if (FAILED(ddrval))
  436.         return FALSE;
  437.  
  438.     // We need to check the minimum stretch.  Many display adpators require that
  439.     // the overlay be stretched by a minimum amount.  The stretch factor will 
  440.     // usually vary with the display mode (including changes in refresh rate).
  441.     // The stretch factor is returned x1000.
  442.     uStretchFactor1000 = capsDrv.dwMinOverlayStretch>1000 ? capsDrv.dwMinOverlayStretch : 1000;
  443.  
  444.     // Grab any alignment restrictions.  The DDCAPS struct contains a series of
  445.     // alignment fields that are not clearly defined. They are intended for
  446.     // overlay use.  It's important to observe alignment restrictions.
  447.     // Many adapters with overlay capabilities require the overlay image be
  448.     // located on 4 or even 8 byte boundaries, and have similar restrictions
  449.     // on the overlay width (for both source and destination areas).
  450.     uDestSizeAlign = capsDrv.dwAlignSizeDest;
  451.     uSrcSizeAlign =  capsDrv.dwAlignSizeSrc;
  452.  
  453.     // Set the flags we'll send to UpdateOverlay
  454.     dwUpdateFlags = DDOVER_SHOW | DDOVER_DDFX;
  455.  
  456.     // Does the overlay hardware support source color keying?
  457.     // If so, we can hide the black background around the image.
  458.     // This probably won't work with YUV formats
  459.     if (capsDrv.dwCKeyCaps & DDCKEYCAPS_SRCOVERLAY)
  460.         dwUpdateFlags |= DDOVER_KEYSRCOVERRIDE;
  461.  
  462.     // Create an overlay FX structure so we can specify a source color key.
  463.     // This information is ignored if the DDOVER_SRCKEYOVERRIDE flag isn't set.
  464.     INIT_DIRECTDRAW_STRUCT(ovfx);
  465.     ovfx.dckSrcColorkey.dwColorSpaceLowValue=0; // Specify black as the color key
  466.     ovfx.dckSrcColorkey.dwColorSpaceHighValue=0;
  467.  
  468.     // Set up our Source Rect. This is the area of the overlay surface we
  469.     // want to display.  If you want to display your entire surface and
  470.     // happen to know for certain that your surface width meets any alignment
  471.     // restrictions you can go ahead and pass NULL for the source rect in your
  472.     // calls to UpdateOverlay().  Our surface width of 320 probably will meet
  473.     // every alignment restriction, but just in case we'll create a source rect
  474.     // and check for it.
  475.     rs.left=0; rs.top=0; // position 0,0 is already position (boundary aligned)
  476.     rs.right = 320;
  477.     rs.bottom = 240;
  478.     //Apply any size alignment restrictions if necessary.
  479.     if (capsDrv.dwCaps & DDCAPS_ALIGNSIZESRC && uSrcSizeAlign)
  480.         rs.right -= rs.right % uSrcSizeAlign;
  481.  
  482.     // Set up our destination rect, indicating where we want the overlay to 
  483.     // appear on the primary surface.  This is where we have to take into 
  484.     // account any stretch factor which may be needed to ensure the overlay is
  485.     // displayed.  Really only the destination width must be stretched for the
  486.     // overlay hardware to work, but we stretch the height as well just to
  487.     // maintain a proper aspect ratio.
  488.  
  489.  
  490.     // Note: We use the source rect dimensions, not the surface dimensions in
  491.     // case they differ.
  492.     // UpdateOverlay will fail unless the minimum stretch value is observed.
  493.     
  494.     rd.left=0; rd.top=0; 
  495.     rd.right  = (rs.right*uStretchFactor1000+999)/1000; // adding 999 takes care of integer truncation problems.
  496.     rd.bottom = rs.bottom*uStretchFactor1000/1000;
  497.  
  498.     // It's also important to observe any alignment restrictions on size and
  499.     // position with respect to the destination rect. Tweak the destination 
  500.     // width a bit more to get the size alignment correct (Be sure to round up
  501.     // to keep any minimum stretch restrictions met). we'll assume the 
  502.     // position 0,0 is already "position aligned".
  503.     if (capsDrv.dwCaps & DDCAPS_ALIGNSIZEDEST && uDestSizeAlign)
  504.         rd.right = (int)((rd.right+uDestSizeAlign-1)/uDestSizeAlign)*uDestSizeAlign;
  505.  
  506.     // Make the call to UpdateOverlay() which actually displays the overlay on
  507.     // the screen.
  508.     ddrval = g_lpddsOverlay->UpdateOverlay(&rs, g_lpddsPrimary, &rd, dwUpdateFlags, &ovfx);
  509.     if(FAILED(ddrval))
  510.     {
  511.         // Ok, the call to UpdateOVerlay() failed.  A likely cause is the
  512.         // driver lied about the minimum stretch needed. 
  513.         // Ideally we should try upping the destination size a bit, or
  514.         // perhaps shrinking the source size so the destination stretch
  515.         // is effectively higher.   For this sample, however, we'll just
  516.         // bail!
  517.         return FALSE;
  518.     }
  519.  
  520.     // Set the initial position and velocity for our overlay.  We'll actually
  521.     // move the image around using a timer proc (see MoveOverlayTimerCallback
  522.     // below).
  523.     g_nOverlayXPos = 0;
  524.     g_nOverlayYPos = 0;
  525.     g_nOverlayXVel = RANDOM_VELOCITY();
  526.     g_nOverlayYVel = RANDOM_VELOCITY();
  527.     g_nOverlayWidth = rd.right - rd.left;
  528.     g_nOverlayHeight = rd.bottom - rd.top;
  529.     g_nOverlayFlipCounter=0;
  530.     
  531.     // Set the "destination position alignment" global so we won't have to
  532.     // keep calling GetCaps() everytime we move the overlay surface.
  533.     if (capsDrv.dwCaps & DDCAPS_ALIGNBOUNDARYDEST)
  534.         g_dwOverlayXPositionAlignment = capsDrv.dwAlignBoundaryDest;
  535.     else 
  536.         g_dwOverlayXPositionAlignment = 0;
  537.  
  538.     return TRUE;
  539. }
  540.  
  541.  
  542. //****************************************************************************
  543. //* Function: AreOverlaysSupported
  544. //*
  545. //* Description:
  546. //*     Determines whether or not the display hardware supports overlays.  If
  547. //*     so, the function returns TRUE, otherwise FALSE.
  548. //****************************************************************************
  549. BOOL AreOverlaysSupported()
  550. {
  551.     DDCAPS  capsDrv;
  552.     HRESULT ddrval;
  553.  
  554.     // Get driver capabilities to determine Overlay support.
  555.     INIT_DIRECTDRAW_STRUCT(capsDrv);
  556.     ddrval = g_lpdd->GetCaps(&capsDrv, NULL);
  557.     if (FAILED(ddrval))
  558.         return FALSE;
  559.  
  560.     // Does the driver support overlays in the current mode? 
  561.     // (Currently the DirectDraw emulation layer does not support overlays.
  562.     // Overlay related APIs will fail without hardware support).  
  563.     if (!(capsDrv.dwCaps & DDCAPS_OVERLAY))
  564.         return FALSE;
  565.  
  566.     return TRUE;
  567. }
  568.  
  569.  
  570. //****************************************************************************
  571. //* Function: CreateOverlay
  572. //*
  573. //* Description:
  574. //*     This is where we create the overlay surface, and put the flying insect 
  575. //*     artwork on it.
  576. //****************************************************************************
  577. BOOL CreateOverlay()
  578. {
  579.     DDSURFACEDESC   ddsdOverlay;
  580.     HRESULT         ddrval;
  581.     int             i;
  582.  
  583.     if (!g_lpdd || !g_lpddsPrimary)
  584.         return FALSE;
  585.     
  586.     // It's currently not possible to query for pixel formats supported by the
  587.     // overlay hardware (though GetFourCCCodes() usually provides a partial 
  588.     // list).  Instead you need to call CreateSurface() to try a variety of  
  589.     // formats till one works.  
  590.     INIT_DIRECTDRAW_STRUCT(ddsdOverlay);
  591.     ddsdOverlay.ddsCaps.dwCaps=DDSCAPS_OVERLAY | DDSCAPS_FLIP | DDSCAPS_COMPLEX | DDSCAPS_VIDEOMEMORY;
  592.     ddsdOverlay.dwFlags= DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_BACKBUFFERCOUNT| DDSD_PIXELFORMAT;
  593.     ddsdOverlay.dwWidth=320;
  594.     ddsdOverlay.dwHeight=240;
  595.     ddsdOverlay.dwBackBufferCount=2;
  596.  
  597.     // Try to create an overlay surface using one of the pixel formats in our
  598.     // global list.
  599.     i=0;
  600.     do 
  601.     {
  602.             ddsdOverlay.ddpfPixelFormat=g_ddpfOverlayFormats[i];
  603.             // Try to create the overlay surface
  604.             ddrval = g_lpdd->CreateSurface(&ddsdOverlay, &g_lpddsOverlay, NULL);
  605.     } while( FAILED(ddrval) && (++i < NUM_OVERLAY_FORMATS) );
  606.  
  607.     // If we failed to create an overlay surface, let's try again with a single
  608.     // (non-flippable) buffer.
  609.     if(FAILED(ddrval))
  610.     {
  611.         // Just in case we're short on video memory or the hardware doesn't like flippable
  612.         // overlay surfaces, let's make another pass using a single buffer.
  613.         ddsdOverlay.dwBackBufferCount=0;
  614.         ddsdOverlay.ddsCaps.dwCaps=DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY;
  615.         ddsdOverlay.dwFlags= DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT;
  616.         // Try to create the overlay surface
  617.         ddrval = g_lpdd->CreateSurface(&ddsdOverlay, &g_lpddsOverlay, NULL);
  618.         i=0;
  619.         do 
  620.         {
  621.                 ddsdOverlay.ddpfPixelFormat=g_ddpfOverlayFormats[i];
  622.                 ddrval = g_lpdd->CreateSurface(&ddsdOverlay, &g_lpddsOverlay, NULL);
  623.         } while( FAILED(ddrval) && (++i < NUM_OVERLAY_FORMATS) );
  624.  
  625.         // We just couldn't create an overlay surface.  Let's exit.
  626.         if (FAILED(ddrval))
  627.             return FALSE;
  628.     }
  629.  
  630.     // Put the first bug image onto the first buffer of our complex surface.
  631.     if (!LoadImageOntoSurface(g_lpddsOverlay, MAKEINTRESOURCE(IDB_BUGIMAGE1)))
  632.         return FALSE;
  633.  
  634.     // This will recursively get all back buffers and load them with the appropriate image.
  635.     ddrval = g_lpddsOverlay->EnumAttachedSurfaces((LPVOID)IDB_BUGIMAGE2, EnumAttachedCallback);
  636.     if(FAILED(ddrval))
  637.         return FALSE;
  638.  
  639.     return TRUE;
  640. }
  641.  
  642.  
  643. //****************************************************************************
  644. //* Function: RestoreAllSurfaces
  645. //****************************************************************************
  646. BOOL RestoreAllSurfaces()
  647. {
  648.     HRESULT ddrval;
  649.  
  650.     // It's possible that our surfaces were destroyed in a prior call to 
  651.     // RestoreAllSurfaces().  If this happened we need to check for it, 
  652.     // and perhaps try to recreate the surfaces.
  653.     if (!g_lpddsPrimary)
  654.     {
  655.         ddrval = CreatePrimarySurface();
  656.         if (FAILED(ddrval))
  657.         {
  658.             // We probably couldn't recreate the primary because someone has
  659.             // exclusive mode.
  660.             g_lpddsPrimary = NULL;
  661.             return FALSE;
  662.         }
  663.     }
  664.  
  665.     if(!g_lpddsOverlay)
  666.         if (!CreateOverlay())
  667.             return FALSE;
  668.  
  669.     // Try Restoring the primary surface.
  670.     ddrval = g_lpddsPrimary->Restore();
  671.     if(FAILED(ddrval))
  672.     {
  673.         // If we weren't able to restore the primary surface, It's probably 
  674.         // because some one else has exclusive mode, or the display mode
  675.         // has been changed such that our primary surface needs to be recreated
  676.         
  677.         // Check to see if the mode changed on us.  Is so, we'll need to recreate
  678.         // all surfaces.  (Note: we could have watched for the WM_DISPLAYCHANGE 
  679.         // message as well)
  680.         if (ddrval == DDERR_WRONGMODE)
  681.         {
  682.             g_lpddsPrimary->Release();
  683.             DestroyOverlay();
  684.             g_lpddsPrimary = NULL;
  685.             g_lpddsOverlay = NULL;
  686.             
  687.             return FALSE;
  688.         }
  689.  
  690.         else 
  691.             return FALSE;
  692.     }
  693.  
  694.     // Try Restoring the overlay surface.
  695.     ddrval = g_lpddsOverlay->Restore();
  696.     if (FAILED(ddrval))
  697.         return FALSE;
  698.  
  699.     // Reload artwork onto overlay
  700.     // Put the first bug image onto the first buffer of our complex surface.
  701.     if ( !LoadImageOntoSurface(g_lpddsOverlay, MAKEINTRESOURCE(IDB_BUGIMAGE1)) )
  702.         return FALSE;
  703.  
  704.     // This will recursively get all back buffers and load them with the appropriate image.
  705.     ddrval = g_lpddsOverlay->EnumAttachedSurfaces((LPVOID)IDB_BUGIMAGE2, EnumAttachedCallback);
  706.     if(FAILED(ddrval))
  707.         return FALSE;
  708.  
  709.     // Redisplay overlay
  710.     if(!DisplayOverlay())
  711.         return FALSE;
  712.  
  713.     return TRUE;
  714. }
  715.  
  716.  
  717. //****************************************************************************
  718. //* Function: MoveOverlayTimerCallback
  719. //*
  720. //* Description:
  721. //*     TimeProc callback for moving the overlay surface around
  722. //****************************************************************************
  723. void CALLBACK MoveOverlayTimerCallback(HWND hwndUnused, UINT uUnused, UINT uUnused2, DWORD dwUnused)
  724. {
  725.     HRESULT ddrval;
  726.     DWORD   dwXAligned;
  727.  
  728.     // Make sure the overlay really exists before we mess with it.
  729.     if (!g_lpddsOverlay)
  730.         if (!RestoreAllSurfaces())
  731.             return;
  732.  
  733.     //Add the current velocity vectors to the position.
  734.     g_nOverlayXPos += g_nOverlayXVel;
  735.     g_nOverlayYPos += g_nOverlayYVel;
  736.  
  737.     // Check to see if this new position puts the overlay off the edge of the screen.
  738.     // SetOverlayPosition() won't like that.
  739.  
  740.     // Have we gone off the left edge?
  741.     if (g_nOverlayXPos < 0)
  742.     {
  743.         g_nOverlayXPos = 0;
  744.         g_nOverlayXVel = RANDOM_VELOCITY();
  745.     }
  746.  
  747.     // Have we gone off the right edge?
  748.     if ( (g_nOverlayXPos+g_nOverlayWidth) >  GetSystemMetrics(SM_CXSCREEN))
  749.     {
  750.         g_nOverlayXPos = GetSystemMetrics(SM_CXSCREEN)-g_nOverlayWidth;
  751.         g_nOverlayXVel = -RANDOM_VELOCITY();
  752.     }
  753.  
  754.     // Have we gone off the top edge?
  755.     if (g_nOverlayYPos < 0)
  756.     {
  757.         g_nOverlayYPos = 0;
  758.         g_nOverlayYVel = RANDOM_VELOCITY();
  759.     }
  760.  
  761.     // Have we gone off the bottom edge?
  762.     if ( (g_nOverlayYPos+g_nOverlayHeight) >  GetSystemMetrics(SM_CYSCREEN))
  763.     {
  764.         g_nOverlayYPos = GetSystemMetrics(SM_CYSCREEN)-g_nOverlayHeight;
  765.         g_nOverlayYVel = -RANDOM_VELOCITY();
  766.     }
  767.  
  768.     // We need to check for any alignment restrictions on the X position
  769.     if (g_dwOverlayXPositionAlignment)
  770.         dwXAligned = g_nOverlayXPos - g_nOverlayXPos % g_dwOverlayXPositionAlignment;
  771.     else
  772.         dwXAligned = g_nOverlayXPos;
  773.  
  774.     // Set the overlay to it's new position.
  775.     ddrval = g_lpddsOverlay->SetOverlayPosition(dwXAligned, g_nOverlayYPos);
  776.     if (ddrval == DDERR_SURFACELOST)
  777.     {
  778.         if (!RestoreAllSurfaces()) 
  779.             return;
  780.     }
  781.  
  782.     // Every fourth time this timer proc is called, lets flip the overlay surface.
  783.     if (g_nOverlayFlipCounter++ > 3) 
  784.     {
  785.         g_nOverlayFlipCounter = 0; // reset counter
  786.         // Flip to the next image in the sequence.  This is gonna fail if we
  787.         // our overlay surface only contains one buffer (see CreateOverlay. 
  788.         // This is a possibility), but the failure should be benign.
  789.         g_lpddsOverlay->Flip(NULL, DDFLIP_WAIT);
  790.     }
  791. }
  792.  
  793. //****************************************************************************
  794. //* Function: DisplayError
  795. //* Description:
  796. //*    Displays an error message box.
  797. //****************************************************************************
  798. int DisplayError(HINSTANCE hInst, LPSTR lpstrErr)
  799. {
  800.     MSGBOXPARAMS mbp;
  801.     
  802.     mbp.cbSize = sizeof(mbp);
  803.     mbp.hwndOwner=NULL;
  804.     mbp.hInstance=hInst;
  805.     mbp.lpszText = lpstrErr;
  806.     mbp.lpszCaption = "Mosquito Error!";
  807.     mbp.dwStyle = MB_OK | MB_USERICON;
  808.     mbp.lpszIcon = MAKEINTRESOURCE(IDI_BUGICON);
  809.     mbp.dwContextHelpId = NULL;
  810.     mbp.lpfnMsgBoxCallback = NULL;
  811.     mbp.dwLanguageId = NULL;
  812.  
  813.     return MessageBoxIndirect(&mbp);
  814. }
  815.  
  816. //****************************************************************************
  817. //* Function: MainDialogProc
  818. //****************************************************************************
  819. LRESULT CALLBACK MainDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  820. {
  821.     int uTimer=0;
  822.  
  823.     switch (message) 
  824.     {
  825.         case WM_INITDIALOG:
  826.             // Create a timer to periodically move the overlay image around.
  827.             uTimer = SetTimer(NULL, 0, 50, (TIMERPROC)MoveOverlayTimerCallback);
  828.             break;
  829.  
  830.         case WM_COMMAND:
  831.             // Check to see if the "Quit" button was clicked.
  832.             if ( IDQUIT == LOWORD(wParam))
  833.             {
  834.                 KillTimer(NULL, uTimer);
  835.                 EndDialog(hDlg, TRUE);
  836.                 return (TRUE);
  837.             }
  838.             break;
  839.  
  840.         case WM_CLOSE:
  841.             KillTimer(NULL, uTimer);
  842.             EndDialog(hDlg, TRUE);
  843.             return (TRUE);
  844.     }
  845.  
  846.     return FALSE;
  847. }
  848.  
  849.  
  850. //****************************************************************************
  851. //* Function: WinMain(HANDLE, HANDLE, LPSTR, int)
  852. //*
  853. //* Description: 
  854. //*     Entry point for the application.  Since we use a simple dialog for 
  855. //*     user interaction we don't need to pump messages.
  856. //*
  857. //****************************************************************************
  858. int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
  859. {
  860.  
  861.     // Call DirectDraw Initialization function
  862.     if (!InitDirectDraw())
  863.         return FALSE;
  864.  
  865.  
  866.     if (!AreOverlaysSupported())
  867.     {
  868.         // Display an error dialog if the hardware doesn't support overlays.
  869.         DisplayError(hInstance, NO_OVERLAY_HARDWARE);
  870.         return FALSE;
  871.     }
  872.  
  873.     if (!CreateOverlay())
  874.     {
  875.         // display an error dialog if we couldn't create the overlay.
  876.         DisplayError(hInstance, UNABLE_TO_CREATE_OVERLAY);
  877.         return FALSE;
  878.     }
  879.  
  880.     if (!DisplayOverlay())
  881.     {
  882.         // Display an error dialog if we couldn't display the overlay.
  883.         DisplayError(hInstance, UNABLE_TO_DISPLAY_OVERLAY);
  884.         return FALSE;
  885.     }
  886.  
  887.     // Display our "Quit" dialog box.  As part of it's initialization it'll get the overlay going.
  888.     DialogBox(hInstance, MAKEINTRESOURCE(IDD_QUITDIALOG), NULL, (DLGPROC)MainDialogProc);
  889.  
  890.     DestroyOverlay();
  891.     FreeDirectDraw();
  892.  
  893.     lpCmdLine; // This will prevent 'unused formal parameter' warnings
  894.  
  895.     return TRUE;
  896. }
  897.