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