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 / stretch3 / stretch.cpp < prev    next >
C/C++ Source or Header  |  1997-07-14  |  25KB  |  991 lines

  1. /*==========================================================================
  2.  *
  3.  *  Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved.
  4.  *
  5.  *  File:       stretch.cpp
  6.  *
  7.  *  stretch with multimonitor support
  8.  *
  9.  ***************************************************************************/
  10.  
  11. #define NAME "Stretch"
  12. #define TITLE "Stretch"
  13.  
  14. #define WIN32_LEAN_AND_MEAN
  15. #include <windows.h>
  16. #include <windowsx.h>
  17. #include <ddraw.h>
  18. #include "resource.h"
  19. #include "ddutil2.h"
  20. #include "ddmm.h"
  21.  
  22. #define SIZEX    64
  23. #define SIZEY    64
  24. char *szBitmap = "DONUT";
  25.  
  26. HWND        hwnd1;
  27. HWND        hwnd2;
  28. DWORD           UpdateDelay = 100;
  29.  
  30. LPDIRECTDRAW2        lpDDArtWork;        // DirectDraw object
  31. LPDIRECTDRAWSURFACE3    lpDDSArtWorkOriginal;    
  32. LPDIRECTDRAWSURFACE3    lpDDSArtWork;    
  33. LPDIRECTDRAWPALETTE    lpDDPal = 0;    // DirectDraw palette
  34.  
  35. LPDIRECTDRAW2        lpDD1;        // DirectDraw object
  36. LPDIRECTDRAWSURFACE3    lpDDSPrimary1;    // DirectDraw primary surface
  37. LPDIRECTDRAWSURFACE3    lpDDSOne1;    // Offscreen surface 1
  38. LPDIRECTDRAWCLIPPER     lpClipper1;      // clipper for primary
  39. DWORD            ThdId1;
  40.  
  41. LPDIRECTDRAW2        lpDD2;        // DirectDraw object
  42. LPDIRECTDRAWSURFACE3    lpDDSPrimary2;    // DirectDraw primary surface
  43. LPDIRECTDRAWSURFACE3    lpDDSOne2;    // Offscreen surface 1
  44. LPDIRECTDRAWCLIPPER     lpClipper2;      // clipper for primary
  45. DWORD            ThdId2;
  46.  
  47. volatile int             SpinLock = 0;
  48. BOOL                    bActive;        // is application active?
  49. VOID *                  lpArtWork;      // shared art work
  50.  
  51. /* multimon stuff
  52. */
  53. int     MyDevice1;
  54. char    MyDeviceName1[128];
  55. RECT    MyDeviceRect1;
  56. int     MyDevice2;
  57. char    MyDeviceName2[128];
  58. RECT    MyDeviceRect2;
  59.  
  60. typedef struct
  61. {
  62.     HINSTANCE hInstance;
  63.     int nCmdShow;
  64. }Thread_Info;
  65.  
  66. Thread_Info ThdInfo;
  67.  
  68. BOOL ddInit(HWND);
  69. BOOL ddInit1(HWND);
  70.  
  71. /*
  72.  * restoreAll
  73.  *
  74.  * restore all lost objects
  75.  */
  76. BOOL restoreAll( void )
  77. {
  78.     return (
  79.            lpDDSPrimary1->Restore() &&
  80.            lpDDSPrimary2->Restore() &&
  81.            lpDDSOne1->Restore() &&
  82.            lpDDSOne2->Restore() 
  83.            );
  84. } /* restoreAll */
  85.  
  86. /*
  87.  * updateFrame
  88.  * 
  89.  * Decide what needs to be blitted next, wait for flip to complete,
  90.  * then flip the buffers.
  91.  */
  92. void updateFrame( void )
  93. {
  94.     static DWORD    lastTickCount = 0;
  95.     static int        currentFrame = 0;
  96.     static BOOL         haveBackground = FALSE;
  97.     DWORD        thisTickCount;
  98.     RECT        rcRect;
  99.     RECT        destRect;
  100.     HRESULT        ddrval;
  101.     POINT               pt;
  102.  
  103.     thisTickCount = GetTickCount();
  104.     if((thisTickCount - lastTickCount) <= UpdateDelay)
  105.     {
  106.     return;
  107.     }
  108.  
  109.     // Move to next frame;
  110.     lastTickCount = thisTickCount;
  111.     currentFrame++;
  112.     if(currentFrame > 59)
  113.     {
  114.         currentFrame = 0;
  115.     }
  116.  
  117.     // Blit the stuff for the next frame
  118.     rcRect.left   = currentFrame%10*64;
  119.     rcRect.top    = currentFrame/10*64;
  120.     rcRect.right  = currentFrame%10*64 + 64;
  121.     rcRect.bottom = currentFrame/10*64 + 64;
  122.  
  123.     GetClientRect( hwnd1, &destRect );
  124.     if (destRect.right  < 64) destRect.right = 64;
  125.     if (destRect.bottom < 64)  destRect.bottom = 64;
  126.  
  127.     pt.x = pt.y = 0;
  128.     ClientToScreen( hwnd1, &pt );
  129.     pt.x -= MyDeviceRect1.left;
  130.     pt.y -= MyDeviceRect1.top;
  131.     OffsetRect(&destRect, pt.x, pt.y);
  132.  
  133.  
  134.     while( 1 )
  135.     {
  136.         ddrval = lpDDSPrimary1->Blt( &destRect, lpDDSOne1, &rcRect, 0, NULL );
  137.  
  138.         if( ddrval == DD_OK )
  139.         {
  140.             break;
  141.         }
  142.         if( ddrval == DDERR_SURFACELOST )
  143.         {
  144.             if(!restoreAll())
  145.             {
  146.                 return;
  147.             }
  148.          }
  149.         if( ddrval != DDERR_WASSTILLDRAWING )
  150.         {
  151.             return;
  152.         }
  153.     };
  154.     if(ddrval != DD_OK)
  155.     {
  156.         return;
  157.     }
  158. } /* updateFrame */
  159.  
  160. /*
  161.  * updateFrame1
  162.  * 
  163.  * Decide what needs to be blitted next, wait for flip to complete,
  164.  * then flip the buffers.
  165.  */
  166. void updateFrame1( void )
  167. {
  168.     static DWORD    lastTickCount = 0;
  169.     static int        currentFrame = 0;
  170.     static BOOL         haveBackground = FALSE;
  171.     DWORD        thisTickCount;
  172.     RECT        rcRect;
  173.     RECT        destRect;
  174.     HRESULT        ddrval;
  175.     POINT               pt;
  176.  
  177.     thisTickCount = GetTickCount();
  178.     if((thisTickCount - lastTickCount) <= UpdateDelay)
  179.     {
  180.     return;
  181.     }
  182.  
  183.     // Move to next frame;
  184.     lastTickCount = thisTickCount;
  185.     currentFrame++;
  186.     if(currentFrame > 59)
  187.     {
  188.         currentFrame = 0;
  189.     }
  190.  
  191.     // Blit the stuff for the next frame
  192.     rcRect.left   = currentFrame%10*64;
  193.     rcRect.top    = currentFrame/10*64;
  194.     rcRect.right  = currentFrame%10*64 + 64;
  195.     rcRect.bottom = currentFrame/10*64 + 64;
  196.  
  197.     GetClientRect( hwnd2, &destRect );
  198.     if (destRect.right  < 64) destRect.right = 64;
  199.     if (destRect.bottom < 64)  destRect.bottom = 64;
  200.  
  201.     pt.x = pt.y = 0;
  202.     ClientToScreen( hwnd2, &pt );
  203.     pt.x -= MyDeviceRect2.left;
  204.     pt.y -= MyDeviceRect2.top;
  205.     OffsetRect(&destRect, pt.x, pt.y);
  206.  
  207.  
  208.     while( 1 )
  209.     {
  210.         ddrval = lpDDSPrimary2->Blt( &destRect, lpDDSOne2, &rcRect, 0, NULL );
  211.  
  212.         if( ddrval == DD_OK )
  213.         {
  214.             break;
  215.         }
  216.         if( ddrval == DDERR_SURFACELOST )
  217.         {
  218.             if(!restoreAll())
  219.             {
  220.                 return;
  221.             }
  222.          }
  223.         if( ddrval != DDERR_WASSTILLDRAWING )
  224.         {
  225.             return;
  226.         }
  227.     }
  228.  
  229.     if(ddrval != DD_OK)
  230.     {
  231.         return;
  232.     }
  233. } /* updateFrame1 */
  234.  
  235.  
  236. /*
  237.  * finiObjects
  238.  *
  239.  * finished with all objects we use; release them
  240.  */
  241. static void finiObjects( BOOL fKillDD )
  242. {
  243.     if( lpDDSPrimary1 != NULL )
  244.     {
  245.         lpDDSPrimary1->Release();
  246.         lpDDSPrimary1 = NULL;
  247.     }
  248.     if( lpDDSOne1 != NULL )
  249.     {
  250.         lpDDSOne1->Release();
  251.         lpDDSOne1 = NULL;
  252.     }
  253.     if( lpDDPal != NULL )
  254.     {
  255.         lpDDPal->Release();
  256.         lpDDPal = NULL;
  257.     }
  258.     if( fKillDD && lpDD1 != NULL )
  259.     {
  260.         lpDD1->Release();
  261.         lpDD1 = NULL;
  262.     }
  263. } /* finiObjects */
  264. static void finiObjects1( BOOL fKillDD )
  265. {
  266.     if( lpDDSPrimary2 != NULL )
  267.     {
  268.         lpDDSPrimary2->Release();
  269.         lpDDSPrimary2 = NULL;
  270.     }
  271.     if( lpDDSOne2 != NULL )
  272.     {
  273.         lpDDSOne2->Release();
  274.         lpDDSOne2 = NULL;
  275.     }
  276.     if( lpDDPal != NULL )
  277.     {
  278.         lpDDPal->Release();
  279.         lpDDPal = NULL;
  280.     }
  281.     if( fKillDD && lpDD2 != NULL )
  282.     {
  283.         lpDD2->Release();
  284.         lpDD2 = NULL;
  285.     }
  286. } /* finiObjects1 */
  287.  
  288. long FAR PASCAL WindowProc( HWND hWnd, UINT message, 
  289.                 WPARAM wParam, LPARAM lParam )
  290. {
  291.     RECT  rc;
  292.  
  293.     switch( message )
  294.     {
  295.     case WM_ACTIVATEAPP:
  296.         bActive = wParam;
  297.     break;
  298.  
  299.     case WM_SIZE:
  300.     case WM_MOVE:
  301.         if(hWnd == hwnd1)
  302.         {
  303.             if (MyDevice1 != DirectDrawDeviceFromWindow(hWnd,NULL,NULL))
  304.             {
  305.                 ddInit(hwnd1);
  306.             }
  307.         }
  308.         if(hWnd == hwnd2)
  309.         {
  310.             if (MyDevice2 != DirectDrawDeviceFromWindow(hWnd,NULL,NULL))
  311.             {
  312.                 ddInit1(hwnd2);
  313.             }
  314.         }
  315.         break;
  316.  
  317.     case WM_PALETTECHANGED:
  318.         if ((HWND)wParam == hWnd)
  319.             break;
  320.         // fall through to WM_QUERYNEWPALETTE
  321.     case WM_QUERYNEWPALETTE:
  322. /*--------------------------------------------------------**
  323. **  Er um, truth is this app is broken on palette change  **
  324. **  see ddInitArtWork to understand why.                  **
  325. **--------------------------------------------------------*/
  326.         break;
  327.  
  328.     case WM_CREATE:
  329.         break;
  330.  
  331.     case WM_GETMINMAXINFO:
  332.         ((MINMAXINFO*)lParam)->ptMinTrackSize.x = SIZEX;
  333.         ((MINMAXINFO*)lParam)->ptMinTrackSize.y = SIZEY;
  334.         return 0;
  335.  
  336.     case WM_KEYDOWN:
  337.     switch( wParam )
  338.     {
  339.     case VK_ESCAPE:
  340.         case VK_F12:
  341.             PostMessage(hWnd, WM_CLOSE, 0, 0);
  342.         break;
  343.     }
  344.     break;
  345.  
  346.     case WM_DESTROY:
  347.         if(hWnd == hwnd1)
  348.         {
  349.             finiObjects(TRUE);
  350.         }
  351.         if(hWnd == hwnd2)
  352.         {
  353.             finiObjects1(TRUE);
  354.         }
  355.     PostQuitMessage( 0 );
  356.         break;
  357.  
  358.     case WM_KEYUP:
  359.         if (wParam >= '1' && wParam <= '9')
  360.         {
  361.             SetRect(&rc, 0, 0, SIZEX*(wParam-'0'), SIZEY*(wParam-'0'));
  362.             goto size_me;
  363.         }
  364.         break;
  365.  
  366.     case WM_COMMAND: 
  367.         switch(LOWORD(wParam))
  368.     {
  369.         case ID_ROTATION_STOP:        
  370.         UpdateDelay = 0x7fffffff;
  371.         break;
  372.         case ID_ROTATION_SLOW:        
  373.         UpdateDelay = 200;
  374.         break;
  375.         case ID_ROTATION_FAST:        
  376.                 UpdateDelay = 100;
  377.         break;
  378.         case ID_FILE_EXIT:        
  379.                 PostMessage( hWnd, WM_CLOSE, 0, 0L );
  380.             break;
  381.             
  382.             case ID_SIZE_1X1: SetRect(&rc, 0, 0, SIZEX*1, SIZEY*1); goto size_me;
  383.             case ID_SIZE_2X1: SetRect(&rc, 0, 0, SIZEX*2, SIZEY*1); goto size_me;
  384.             case ID_SIZE_3X1: SetRect(&rc, 0, 0, SIZEX*3, SIZEY*1); goto size_me;
  385.             case ID_SIZE_1X2: SetRect(&rc, 0, 0, SIZEX*1, SIZEY*2); goto size_me;
  386.             case ID_SIZE_2X2: SetRect(&rc, 0, 0, SIZEX*2, SIZEY*2); goto size_me;
  387.             case ID_SIZE_3X2: SetRect(&rc, 0, 0, SIZEX*3, SIZEY*2); goto size_me;
  388.             case ID_SIZE_1X3: SetRect(&rc, 0, 0, SIZEX*1, SIZEY*3); goto size_me;
  389.             case ID_SIZE_2X3: SetRect(&rc, 0, 0, SIZEX*2, SIZEY*3); goto size_me;
  390.         case ID_SIZE_3X3: SetRect(&rc, 0, 0, SIZEX*3, SIZEY*3); goto size_me;
  391. size_me:
  392.                 AdjustWindowRectEx(&rc, GetWindowLong(hWnd, GWL_STYLE),
  393.             GetMenu(hWnd) != NULL, GetWindowLong(hWnd, GWL_EXSTYLE));
  394.         SetWindowPos(hWnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
  395.                     SWP_NOZORDER|SWP_NOMOVE|SWP_NOACTIVATE);
  396.         break;
  397.         } 
  398.         break;
  399.     }
  400.  
  401.     return DefWindowProc(hWnd, message, wParam, lParam);
  402.  
  403. } /* WindowProc */
  404.  
  405. /*
  406.  * This function is called if the initialization function fails
  407.  */
  408. BOOL initFail( HWND hwnd )
  409. {
  410.     finiObjects(TRUE);
  411.     finiObjects1(TRUE);
  412.     MessageBox( hwnd, "DirectDraw Init FAILED", TITLE, MB_OK );
  413.     DestroyWindow( hwnd );
  414.     return FALSE;
  415.  
  416. } /* initFail */
  417.  
  418. /*
  419.  * ddInit
  420.  */
  421. BOOL ddInit( HWND hwnd )
  422. {
  423.     DDSURFACEDESC    ddsd;
  424.     HRESULT             ddrval;
  425.     char                ach[128];
  426.  
  427.     /*
  428.      * clean up our mess
  429.      */
  430.     finiObjects(TRUE);
  431.  
  432.     MyDevice1 = DirectDrawDeviceFromWindow(hwnd,MyDeviceName1,&MyDeviceRect1);
  433.  
  434.     if (MyDeviceName1[0] == 0) lstrcpy(MyDeviceName1, "(none)");
  435.     wsprintf(ach, "%s - %s", TITLE, MyDeviceName1);
  436.     SetWindowText(hwnd1, ach);
  437.  
  438.     /*
  439.      * create the main DirectDraw object
  440.      */
  441.     LPDIRECTDRAW lpDDT;
  442.     lpDDT = DirectDrawCreateFromWindow(hwnd);
  443.     if( lpDDT == NULL )
  444.     {
  445.         return initFail(hwnd);
  446.     }
  447.     ddrval = lpDDT->QueryInterface(IID_IDirectDraw2, (void**)&lpDD1);
  448.  
  449.     if( lpDD1 == NULL )
  450.     {
  451.         return initFail(hwnd);
  452.     }
  453.     lpDDT->Release();
  454.     
  455.     ddrval = lpDD1->SetCooperativeLevel( hwnd, DDSCL_NORMAL );
  456.  
  457.     // Create the primary surface
  458.     ddsd.dwSize = sizeof( ddsd );
  459.     ddsd.dwFlags = DDSD_CAPS;
  460.     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
  461.  
  462.     LPDIRECTDRAWSURFACE lpDDSTemp;
  463.     ddrval = lpDD1->CreateSurface( &ddsd, &lpDDSTemp, NULL );
  464.     if( ddrval != DD_OK )
  465.     {
  466.         return initFail(hwnd);
  467.     }
  468.     ddrval = lpDDSTemp->QueryInterface(IID_IDirectDrawSurface3, (void**)&lpDDSPrimary1);
  469.     if( ddrval != DD_OK )
  470.     {
  471.         return initFail(hwnd);
  472.     }
  473.     lpDDSTemp->Release();
  474.  
  475.     // create a clipper for the primary surface
  476.     ddrval = lpDD1->CreateClipper( 0, &lpClipper1, NULL );
  477.     if( ddrval != DD_OK )
  478.     {
  479.         return initFail(hwnd);
  480.     }
  481.  
  482.     ddrval = lpClipper1->SetHWnd( 0, hwnd );
  483.     if( ddrval != DD_OK )
  484.     {
  485.         return initFail(hwnd);
  486.     }
  487.  
  488.     ddrval = lpDDSPrimary1->SetClipper( lpClipper1 );
  489.     if( ddrval != DD_OK )
  490.     {
  491.         return initFail(hwnd);
  492.     }
  493.  
  494.      // load our palette                                     
  495.      lpDDPal = DDLoadPalette2(lpDD1, szBitmap);              
  496.                                                              
  497.      // make sure to set the palette before loading bitmaps. 
  498.      if (lpDDPal)                                            
  499.         lpDDSPrimary1->SetPalette(lpDDPal);                    
  500.  
  501.     // load our bitmap
  502.     ZeroMemory(&ddsd, sizeof(ddsd));
  503.     ddsd.dwSize = sizeof(ddsd);
  504.     ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT |DDSD_WIDTH;
  505.     ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
  506.     ddsd.dwWidth = 2;
  507.     ddsd.dwHeight = 2;
  508.  
  509.     if (lpDD1->CreateSurface(&ddsd, &lpDDSTemp, NULL) != DD_OK)
  510.     {
  511.         OutputDebugString("CreateSurf failed");
  512.         return initFail(hwnd);
  513.     }
  514.     //CreateSurface must set SurfaceMemory Flag
  515.     ZeroMemory(&ddsd, sizeof(ddsd));
  516.     ddsd.dwSize = sizeof(ddsd);
  517.     ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT |DDSD_WIDTH;
  518.     ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
  519.     ddsd.dwWidth = 2;  // It's going away anyway
  520.     ddsd.dwHeight = 2;
  521.     if (lpDD1->CreateSurface(&ddsd, &lpDDSTemp, NULL) != DD_OK)
  522.     {
  523.         OutputDebugString("CreateSurf failed");
  524.         return initFail(hwnd);
  525.     };
  526.  
  527.     if (lpDDSTemp->QueryInterface(IID_IDirectDrawSurface3,(void**)&lpDDSOne1) != DD_OK)
  528.     {
  529.         OutputDebugString("QueryInterface failed");
  530.         return initFail(hwnd);
  531.     }
  532.     lpDDSTemp->Release();
  533.  
  534.     if( lpDDSOne1 == NULL )
  535.     {
  536.         return initFail(hwnd);
  537.     }
  538.  
  539.     //Get the size of the surface
  540.     DDSURFACEDESC DDSDesc;
  541.     memset(&DDSDesc,0,sizeof(DDSURFACEDESC));
  542.     DDSDesc.dwSize = sizeof(DDSURFACEDESC);
  543.     DDSDesc.dwFlags =  DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH;
  544.     ddrval = lpDDSArtWork->GetSurfaceDesc(&DDSDesc);
  545.     if( ddrval != DD_OK )
  546.     {
  547.         return initFail(hwnd);
  548.     }
  549.  
  550.     //Set the memory into the surface
  551.     DDSDesc.dwFlags =  DDSD_LPSURFACE | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH;
  552.     DDSDesc.lpSurface = lpArtWork;    
  553.     
  554.     ddrval = lpDDSOne1->SetSurfaceDesc(&DDSDesc,0);
  555.     if( ddrval != DD_OK )
  556.     {
  557.         return initFail(hwnd);
  558.     }
  559.  
  560.  
  561.     return TRUE;
  562. } /* doInit */
  563.  
  564.  
  565. /*
  566.  * ddInit1
  567.  */
  568. BOOL ddInit1( HWND hwnd )
  569. {
  570.     DDSURFACEDESC    ddsd;
  571.     HRESULT             ddrval;
  572.     char                ach[128];
  573.  
  574.     /*
  575.      * clean up our mess
  576.      */
  577.     finiObjects1(TRUE);
  578.  
  579.     MyDevice2 = DirectDrawDeviceFromWindow(hwnd,MyDeviceName2,&MyDeviceRect2);
  580.  
  581.     if (MyDeviceName2[0] == 0) lstrcpy(MyDeviceName2, "(none)");
  582.     wsprintf(ach, "%s - %s", TITLE, MyDeviceName2);
  583.     SetWindowText(hwnd, ach);
  584.  
  585.     /*
  586.      * create the main DirectDraw object
  587.      */
  588.     LPDIRECTDRAW lpDDT;
  589.     lpDDT = DirectDrawCreateFromWindow(hwnd);
  590.     if( lpDDT == NULL )
  591.     {
  592.         return initFail(hwnd);
  593.     }
  594.     ddrval = lpDDT->QueryInterface(IID_IDirectDraw2, (void**)&lpDD2);
  595.  
  596.     if( lpDD2 == NULL )
  597.     {
  598.         return initFail(hwnd);
  599.     }
  600.     lpDDT->Release();
  601.     ddrval = lpDD2->SetCooperativeLevel( hwnd, DDSCL_NORMAL );
  602.  
  603.     // Create the primary surface
  604.     ddsd.dwSize = sizeof( ddsd );
  605.     ddsd.dwFlags = DDSD_CAPS;
  606.     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
  607.  
  608.     LPDIRECTDRAWSURFACE lpDDSTemp;
  609.     ddrval = lpDD2->CreateSurface( &ddsd, &lpDDSTemp, NULL );
  610.     if( ddrval != DD_OK )
  611.     {
  612.         return initFail(hwnd);
  613.     }
  614.     ddrval = lpDDSTemp->QueryInterface(IID_IDirectDrawSurface3, (void**)&lpDDSPrimary2);
  615.     if( ddrval != DD_OK )
  616.     {
  617.         return initFail(hwnd);
  618.     }
  619.     lpDDSTemp->Release();
  620.  
  621.     // create a clipper for the primary surface
  622.     ddrval = lpDD2->CreateClipper( 0, &lpClipper2, NULL );
  623.     if( ddrval != DD_OK )
  624.     {
  625.         return initFail(hwnd);
  626.     }
  627.  
  628.     ddrval = lpClipper2->SetHWnd( 0, hwnd );
  629.     if( ddrval != DD_OK )
  630.     {
  631.         return initFail(hwnd);
  632.     }
  633.  
  634.     ddrval = lpDDSPrimary2->SetClipper( lpClipper2 );
  635.     if( ddrval != DD_OK )
  636.     {
  637.         return initFail(hwnd);
  638.     }
  639.  
  640.     // load our palette                                     
  641.     lpDDPal = DDLoadPalette2(lpDD2, szBitmap);              
  642.                                                              
  643.     // make sure to set the palette before loading bitmaps. 
  644.     if (lpDDPal)                                            
  645.         lpDDSPrimary2->SetPalette(lpDDPal);                    
  646.                                                              
  647.  
  648.     //CreateSurface must set SurfaceMemory Flag
  649.     ZeroMemory(&ddsd, sizeof(ddsd));
  650.     ddsd.dwSize = sizeof(ddsd);
  651.     ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT |DDSD_WIDTH;
  652.     ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
  653.     ddsd.dwWidth = 2;  // It's going away anyway
  654.     ddsd.dwHeight = 2;
  655.     if (lpDD2->CreateSurface(&ddsd, &lpDDSTemp, NULL) != DD_OK)
  656.     {
  657.         OutputDebugString("CreateSurf failed");
  658.         return initFail(hwnd);
  659.     };
  660.  
  661.     if (lpDDSTemp->QueryInterface(IID_IDirectDrawSurface3,(void**)&lpDDSOne2) != DD_OK)
  662.     {
  663.         OutputDebugString("QueryInterface failed");
  664.         return initFail(hwnd);
  665.     }
  666.     lpDDSTemp->Release();
  667.  
  668.     if( lpDDSOne2 == NULL )
  669.     {
  670.         return initFail(hwnd);
  671.     }
  672.  
  673.     //Get the size of the surface
  674.     DDSURFACEDESC DDSDesc;
  675.     memset(&DDSDesc,0,sizeof(DDSURFACEDESC));
  676.     DDSDesc.dwSize = sizeof(DDSURFACEDESC);
  677.     DDSDesc.dwFlags =  DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH;
  678.     ddrval = lpDDSArtWork->GetSurfaceDesc(&DDSDesc);
  679.     if( ddrval != DD_OK )
  680.     {
  681.         return initFail(hwnd);
  682.     }
  683.  
  684.     //Set the memory into the surface
  685.     DDSDesc.dwFlags =  DDSD_LPSURFACE | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH;
  686.     DDSDesc.lpSurface = lpArtWork;    
  687.     
  688.     ddrval = lpDDSOne2->SetSurfaceDesc(&DDSDesc,0);
  689.     if( ddrval != DD_OK )
  690.     {
  691.         return initFail(hwnd);
  692.     }
  693.  
  694.     return TRUE;
  695. } /* doInit1 */
  696.  
  697.  
  698.  
  699. /*-------------------------------------------------------**
  700. ** This code assumes that if more than one monitor exist **
  701. ** that they have the same color depth, else sharing     **
  702. ** artwork doesn't make sense                            **
  703. **-------------------------------------------------------*/
  704. BOOL ddInitArtWork(void )
  705. {
  706.     DDSURFACEDESC    ddsd;
  707.     HRESULT             ddrval;
  708.  
  709.     /*
  710.      * create the main DirectDraw object
  711.      */
  712.     LPDIRECTDRAW lpDDT;
  713.     ddrval = DirectDrawCreate(NULL,&lpDDT,0);
  714.     if( ddrval != DD_OK )
  715.     {
  716.         return initFail(NULL);
  717.     }
  718.     ddrval = lpDDT->QueryInterface(IID_IDirectDraw2, (void**)&lpDDArtWork);
  719.     if( ddrval != DD_OK )
  720.     {
  721.         return initFail(NULL);
  722.     }
  723.  
  724.     lpDDT->Release();
  725.     ddrval = lpDDArtWork->SetCooperativeLevel( NULL, DDSCL_NORMAL );
  726.  
  727.     //CreateSurface must set SurfaceMemory Flag
  728.     LPDIRECTDRAWSURFACE lpDDSTemp;
  729.     ZeroMemory(&ddsd, sizeof(ddsd));
  730.     ddsd.dwSize = sizeof(ddsd);
  731.     ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT |DDSD_WIDTH;
  732.     ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
  733.     ddsd.dwWidth = 2;  // It's going away anyway
  734.     ddsd.dwHeight = 2;
  735.     if (lpDDArtWork->CreateSurface(&ddsd, &lpDDSTemp, NULL) != DD_OK)
  736.     {
  737.         OutputDebugString("CreateSurf failed");
  738.         return initFail(NULL);
  739.     };
  740.  
  741.     if (lpDDSTemp->QueryInterface(IID_IDirectDrawSurface3,(void**)&lpDDSArtWork) != DD_OK)
  742.     {
  743.         OutputDebugString("QueryInterface failed");
  744.         return initFail(NULL);
  745.     }
  746.     lpDDSTemp->Release();
  747.  
  748.     if( lpDDSArtWork == NULL )
  749.     {
  750.         return initFail(NULL);
  751.     }
  752.  
  753.     // load our palette
  754.     lpDDPal = DDLoadPalette2(lpDDArtWork, szBitmap);
  755.  
  756.     //copy the preconverted bits to the surface
  757.     lpDDSArtWorkOriginal = DDLoadBitmap2(lpDDArtWork, szBitmap, 0, 0);
  758.     // make sure to set the palette before loading bitmaps.
  759.     if (lpDDPal != 0)
  760.     lpDDSArtWorkOriginal->SetPalette(lpDDPal);
  761.     //Get the size of the surface
  762.     DDSURFACEDESC DDSDesc;
  763.     memset(&DDSDesc,0,sizeof(DDSURFACEDESC));
  764.     DDSDesc.dwSize = sizeof(DDSURFACEDESC);
  765.     DDSDesc.dwFlags =  DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH;
  766.     ddrval = lpDDSArtWorkOriginal->GetSurfaceDesc(&DDSDesc);
  767.     if( ddrval != DD_OK )
  768.     {
  769.         return initFail(NULL);
  770.     }
  771.  
  772.     //Alloc a surface.  The pitch must always be an integral number
  773.     // of DWORDs, so we compute the theoretical pitch and then round it up.
  774.     DDSDesc.lPitch =  DDSDesc.dwWidth*DDSDesc.ddpfPixelFormat.dwRGBBitCount/8;
  775.     DDSDesc.lPitch = (DDSDesc.lPitch + 3) & ~3;
  776.  
  777.     lpArtWork = GlobalAlloc(GPTR, DDSDesc.lPitch * DDSDesc.dwHeight);
  778.  
  779.     //Set the memory into the surface
  780.     DDSDesc.dwFlags =  DDSD_LPSURFACE | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH;
  781.     DDSDesc.lpSurface = lpArtWork;    
  782.     
  783.     ddrval = lpDDSArtWork->SetSurfaceDesc(&DDSDesc,0);
  784.     if( ddrval != DD_OK )
  785.     {
  786.         return initFail(NULL);
  787.     }
  788.  
  789.     //copy the preconverted bits to the surface
  790.     ddrval = lpDDSArtWork->Blt(NULL,lpDDSArtWorkOriginal,NULL,DDBLT_WAIT,NULL);
  791.     if( ddrval != DD_OK )
  792.     {
  793.         return initFail(NULL);
  794.     }
  795.     return TRUE;
  796. } /* doInitArt */
  797.  
  798.  
  799. /*
  800.  * doInit - do work required for every instance of the application:
  801.  *          create the window, initialize data
  802.  */
  803. static BOOL doInit( Thread_Info *thd)
  804. //HINSTANCE hInstance, int nCmdShow )
  805. {
  806.     WNDCLASS        wc;
  807.     MSG         msg;
  808.  
  809.     /*
  810.      * set up and register window class
  811.      */
  812.     wc.style = CS_HREDRAW | CS_VREDRAW;
  813.     wc.lpfnWndProc = WindowProc;
  814.     wc.cbClsExtra = 0;
  815.     wc.cbWndExtra = 0;
  816.     wc.hInstance = thd->hInstance;
  817.     wc.hIcon = LoadIcon( thd->hInstance, IDI_APPLICATION );
  818.     wc.hCursor = LoadCursor( NULL, IDC_ARROW );
  819.     wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  820.     wc.lpszMenuName = NULL; // MAKEINTRESOURCE(IDR_MENU);
  821.     wc.lpszClassName = NAME;
  822.     RegisterClass( &wc );
  823.     
  824.     /*
  825.      * create a window
  826.      */
  827.     hwnd1 = CreateWindowEx(
  828.     0,
  829.     NAME,
  830.     TITLE,
  831.         WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME,
  832.     CW_USEDEFAULT,
  833.     CW_USEDEFAULT,
  834.     128,
  835.     128,
  836.     NULL,
  837.     NULL,
  838.     thd->hInstance,
  839.     NULL );
  840.  
  841.     if( !hwnd1 )
  842.     {
  843.     return FALSE;
  844.     }
  845.  
  846.     PostMessage(hwnd1, WM_COMMAND, ID_SIZE_3X3, 0);
  847.  
  848.     ShowWindow( hwnd1, thd->nCmdShow );
  849.     UpdateWindow( hwnd1 );
  850.  
  851.     /*
  852.      * create the direct draw objects
  853.      */
  854.     ddInit(hwnd1);
  855.  
  856.     // Wait for both window to get ready
  857.     SpinLock ++;
  858.     while(SpinLock <2);
  859.  
  860.     while( 1 )
  861.     {
  862.         if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
  863.         {
  864.             if( !GetMessage( &msg, NULL, 0, 0 ) )
  865.             return msg.wParam;
  866.             TranslateMessage(&msg); 
  867.             DispatchMessage(&msg);
  868.         }
  869.             else
  870.         {
  871.             updateFrame();
  872.         }
  873.     }
  874. }
  875.  
  876. static BOOL doInit1(Thread_Info *thd)
  877. //HINSTANCE hInstance, int nCmdShow )
  878. {
  879.     WNDCLASS        wc;
  880.     MSG         msg;
  881.  
  882.     wc.style = CS_HREDRAW | CS_VREDRAW;
  883.     wc.lpfnWndProc = WindowProc;
  884.     wc.cbClsExtra = 0;
  885.     wc.cbWndExtra = 0;
  886.     wc.hInstance = thd->hInstance;
  887.     wc.hIcon = LoadIcon( thd->hInstance, IDI_APPLICATION );
  888.     wc.hCursor = LoadCursor( NULL, IDC_ARROW );
  889.     wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  890.     wc.lpszMenuName = NULL; // MAKEINTRESOURCE(IDR_MENU);
  891.     wc.lpszClassName = NAME;
  892.     RegisterClass( &wc );
  893.  
  894.  
  895.     /*
  896.      * create the direct draw objects
  897.      */
  898.  
  899.  
  900.     hwnd2 = CreateWindowEx(
  901.     0,
  902.     NAME,
  903.     TITLE,
  904.         WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME,
  905.     CW_USEDEFAULT,
  906.     CW_USEDEFAULT,
  907.     128,
  908.     128,
  909.     NULL,
  910.     NULL,
  911.     thd->hInstance,
  912.     NULL );
  913.  
  914.     if( !hwnd2 )
  915.     {
  916.     return FALSE;
  917.     }
  918.  
  919.     PostMessage(hwnd2, WM_COMMAND, ID_SIZE_3X3, 0);
  920.  
  921.     ShowWindow( hwnd2, thd->nCmdShow );
  922.     UpdateWindow( hwnd2 );
  923.  
  924.     /*
  925.      * create the direct draw objects
  926.      */
  927.     ddInit1(hwnd2);
  928.  
  929.     // Wait for both window to get ready
  930.     SpinLock ++;
  931.     while(SpinLock <2);
  932.  
  933.     while( 1 )
  934.     {
  935.         if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
  936.         {
  937.             if( !GetMessage( &msg, NULL, 0, 0 ) )
  938.             return msg.wParam;
  939.             TranslateMessage(&msg); 
  940.             DispatchMessage(&msg);
  941.         }
  942.             else
  943.         {
  944.             updateFrame1();
  945.         }
  946.     }
  947.  
  948. } /* doInit */
  949.  
  950. /*
  951.  * WinMain - initialization, message loop
  952.  */
  953. int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
  954.             LPSTR lpCmdLine, int nCmdShow)
  955. {
  956. //    MSG         msg;
  957.     HANDLE ThdHnd[2];
  958.  
  959.     ddInitArtWork();
  960.  
  961.     ThdInfo.hInstance = hInstance;
  962.     ThdInfo.nCmdShow = nCmdShow;
  963.  
  964.     ThdHnd[0] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)doInit,&ThdInfo,0,&ThdId1);
  965.     ThdHnd[1] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)doInit1,&ThdInfo,0,&ThdId2);
  966.  
  967.     WaitForMultipleObjects((DWORD)2,ThdHnd,TRUE,(DWORD)-1);
  968.     if( lpDDSArtWork != NULL )
  969.     {
  970.         lpDDSArtWork->Release();
  971.         lpDDSArtWork = NULL;
  972.     }
  973.     if( lpDDSArtWorkOriginal != NULL )
  974.     {
  975.         lpDDSArtWorkOriginal->Release();
  976.         lpDDSArtWorkOriginal = NULL;
  977.     }
  978.     if( lpDDPal != NULL )
  979.     {
  980.         lpDDPal->Release();
  981.         lpDDPal = NULL;
  982.     }
  983.     if( lpDDArtWork != NULL )
  984.     {
  985.         lpDDArtWork->Release();
  986.         lpDDArtWork = NULL;
  987.     }
  988.    // ExitThread(0);
  989.     return TRUE;
  990. } /* WinMain */
  991.