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 / foxbear / ddraw.c < prev    next >
C/C++ Source or Header  |  1997-07-14  |  24KB  |  930 lines

  1. /*==========================================================================
  2.  *
  3.  *  Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved.
  4.  *  Copyright (C) 1994-1995 ATI Technologies Inc. All Rights Reserved.
  5.  *
  6.  *  File:    ddraw.c
  7.  *  Content:    Misc. Direct Draw access routines
  8.  *
  9.  ***************************************************************************/
  10. #include "foxbear.h"
  11.  
  12. typedef struct {
  13.     GUID *guid;
  14.     GUID DriverGUID;
  15.     CHAR DriverDesc[128];
  16.     CHAR DriverName[128];
  17. } Devices;
  18.  
  19. Devices aDDDevs[15];
  20. int     MaxDevIndex = 0;
  21. int     DevIndex = 0;
  22.  
  23. BOOL    bUseEmulation;
  24. BOOL    bUseSysMem;
  25. int     nBufferCount;
  26. int     CmdLineBufferCount;
  27. BOOL    bTransDest;
  28. BOOL    bColorFill;
  29.  
  30. HRESULT CALLBACK EnumDisplayModesCallback(LPDDSURFACEDESC pddsd, LPVOID Context);
  31.  
  32. HRESULT CALLBACK DDEnumCallback(GUID * lpGUID, LPSTR DRiverDesc, LPSTR DriverName, LPVOID lpContext);
  33.  
  34. /*
  35.  * DDInit
  36.  */
  37. BOOL DDInit( void )
  38. {
  39.     DirectDrawEnumerate(&DDEnumCallback,NULL);
  40.     DDEnumCallback((GUID *)DDCREATE_EMULATIONONLY, "Hardware Emulation Layer", "", NULL);
  41.     return TRUE;
  42. }
  43. /*
  44.  * DDEnable
  45.  */
  46. BOOL DDEnable( void )
  47. {
  48.     LPDIRECTDRAW    lpdd;
  49.     LPDIRECTDRAW2   lpdd2;
  50.     DDCAPS              ddcaps;
  51.     HRESULT        ddrval;
  52.     BOOL        use_dest;
  53.     OSVERSIONINFO osv;
  54.  
  55.     osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  56.     //
  57.     //What are we running on ?
  58.     //
  59.     GetVersionEx(&osv);
  60.  
  61.  
  62.     nBufferCount = GetProfileInt( "FoxBear", "buffers", CmdLineBufferCount);
  63.     bUseEmulation = GetProfileInt( "FoxBear", "use_emulation", bUseEmulation);
  64.     bUseSysMem = GetProfileInt( "FoxBear", "sysmem", 0);
  65.     use_dest = GetProfileInt( "FoxBear", "use_dest", 0 );
  66.  
  67.     if ((lpDD == NULL) || (lpDD2 == NULL))
  68.     {
  69.         if( bUseEmulation)
  70.             DevIndex = MaxDevIndex-1;
  71.         ddrval = DirectDrawCreate(aDDDevs[DevIndex].guid,&lpdd,NULL);
  72.         if(ddrval == DD_OK)
  73.         {
  74.             ddrval = IDirectDraw_QueryInterface(lpdd, &IID_IDirectDraw2, &lpdd2);
  75.         }
  76.     }
  77.     else
  78.     {
  79.         lpdd = lpDD;
  80.         lpdd2 = lpDD2;
  81.         ddrval = DD_OK;
  82.     }
  83.  
  84.     if( ddrval != DD_OK )
  85.     {
  86.         Msg("DirectDrawCreate failed err=%d", ddrval);
  87.         goto error;
  88.     }
  89.  
  90.     /*
  91.      * grab exclusive mode if we are going to run as fullscreen
  92.      * otherwise grab normal mode.
  93.      */
  94.     if (lpDD == NULL)
  95.     {
  96.     NumModes = 0;
  97.  
  98.         if (bFullscreen)
  99.         {
  100.             ddrval = IDirectDraw_SetCooperativeLevel( lpdd, hWndMain,
  101.                             DDSCL_ALLOWMODEX |
  102.                             DDSCL_EXCLUSIVE |
  103.                             DDSCL_FULLSCREEN );
  104.         
  105.             ddrval = IDirectDraw_EnumDisplayModes(lpdd, DDEDM_STANDARDVGAMODES, NULL, 0, EnumDisplayModesCallback);
  106.             if(ddrval != DD_OK)
  107.             {
  108.                 ddrval = IDirectDraw_EnumDisplayModes(lpdd, 0, NULL, 0, EnumDisplayModesCallback);
  109.             };
  110.         }
  111.  
  112.  
  113.         else
  114.         {
  115.             ddrval = IDirectDraw_SetCooperativeLevel( lpdd, hWndMain,
  116.                 DDSCL_NORMAL );
  117.  
  118.         // in normal windowed mode, just add some "stock" window
  119.         // sizes
  120.  
  121.         ModeList[NumModes].w = 320;
  122.         ModeList[NumModes].h = 200;
  123.         NumModes++;
  124.  
  125.         ModeList[NumModes].w = 320;
  126.         ModeList[NumModes].h = 240;
  127.         NumModes++;
  128.  
  129.         ModeList[NumModes].w = 512;
  130.         ModeList[NumModes].h = 384;
  131.         NumModes++;
  132.  
  133.         ModeList[NumModes].w = 640;
  134.         ModeList[NumModes].h = 400;
  135.         NumModes++;
  136.  
  137.         ModeList[NumModes].w = 640;
  138.         ModeList[NumModes].h = 480;
  139.         NumModes++;
  140.         }
  141.  
  142.         if( ddrval != DD_OK )
  143.         {
  144.             Msg("SetCooperativeLevel failed err=%d", ddrval);
  145.             goto error;
  146.         }
  147.     }
  148.  
  149.     if (bFullscreen)
  150.     {
  151.         Msg("SetDisplayMode %d %d %d",GameMode.cx,GameMode.cy, GameBPP);
  152.         if((GameMode.cx == 320) && (GameMode.cy == 200) && (GameBPP == 8))
  153.         {
  154.             ddrval = IDirectDraw2_SetDisplayMode(lpdd2, GameMode.cx, GameMode.cy, GameBPP,0,DDSDM_STANDARDVGAMODE);
  155.         } else {
  156.             ddrval = IDirectDraw_SetDisplayMode( lpdd, GameMode.cx, GameMode.cy, GameBPP);
  157.         }
  158.  
  159.         if (ddrval != DD_OK && (GameMode.cx != 640 || GameMode.cy != 480))
  160.         {
  161.             Msg( "cant set mode trying 640x480" );
  162.  
  163.             GameMode.cx = 640;
  164.             GameMode.cy = 480;
  165.         GameSize = GameMode;
  166.  
  167.             ddrval = IDirectDraw_SetDisplayMode( lpdd,
  168.                 GameMode.cx, GameMode.cy, GameBPP);
  169.         }
  170.  
  171.         if (ddrval != DD_OK && GameBPP != 8)
  172.         {
  173.             Msg( "cant set mode trying 640x480x8" );
  174.  
  175.             GameBPP = 8;
  176.  
  177.             ddrval = IDirectDraw_SetDisplayMode( lpdd,
  178.                 GameMode.cx, GameMode.cy, GameBPP);
  179.         }
  180.  
  181.         if (ddrval != DD_OK && GameBPP != 16)
  182.         {
  183.             Msg( "cant set mode trying 640x480x16" );
  184.  
  185.             GameBPP = 16;
  186.  
  187.             ddrval = IDirectDraw_SetDisplayMode( lpdd,
  188.                 GameMode.cx, GameMode.cy, GameBPP);
  189.         }
  190.  
  191.         if( ddrval != DD_OK )
  192.         {
  193.             Msg("SetMode failed err=%d", ddrval);
  194.             goto error;
  195.         }
  196.     }
  197.     else
  198.     {
  199.         RECT rcWork;
  200.         RECT rc;
  201.         HDC hdc;
  202.         DWORD dwStyle;
  203.  
  204.         //
  205.         //  when in rome (I mean when in windows) we should use the
  206.         //  current mode
  207.         //
  208.         hdc = GetDC(NULL);
  209.         GameBPP = GetDeviceCaps(hdc, PLANES) * GetDeviceCaps(hdc, BITSPIXEL);
  210.         ReleaseDC(NULL, hdc);
  211.  
  212.         //
  213.         // if we are still a WS_POPUP window we should convert to a
  214.         // normal app window so we look like a windows app.
  215.         //
  216.         dwStyle = GetWindowStyle(hWndMain);
  217.         dwStyle &= ~WS_POPUP;
  218.         dwStyle |= WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX;
  219.         SetWindowLong(hWndMain, GWL_STYLE, dwStyle);
  220.  
  221.         if (bStretch)
  222.             SetRect(&rc, 0, 0, GameMode.cx*2, GameMode.cy*2);
  223.         else
  224.             SetRect(&rc, 0, 0, GameMode.cx, GameMode.cy);
  225.  
  226.         AdjustWindowRectEx(&rc,
  227.             GetWindowStyle(hWndMain),
  228.             GetMenu(hWndMain) != NULL,
  229.             GetWindowExStyle(hWndMain));
  230.  
  231.         SetWindowPos(hWndMain, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
  232.             SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  233.  
  234.         SetWindowPos(hWndMain, HWND_NOTOPMOST, 0, 0, 0, 0,
  235.             SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
  236.  
  237.         //
  238.         //  make sure our window does not hang outside of the work area
  239.         //  this will make people who have the tray on the top or left
  240.         //  happy.
  241.         //
  242.         SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWork, 0);
  243.         GetWindowRect(hWndMain, &rc);
  244.         if (rc.left < rcWork.left) rc.left = rcWork.left;
  245.         if (rc.top  < rcWork.top)  rc.top  = rcWork.top;
  246.         SetWindowPos(hWndMain, NULL, rc.left, rc.top, 0, 0,
  247.             SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
  248.     }
  249.  
  250.     /*
  251.      * check capabilites
  252.      */
  253.     ddcaps.dwSize = sizeof( ddcaps );
  254.     ddrval = IDirectDraw_GetCaps( lpdd, &ddcaps, NULL );
  255.  
  256.     if( ddrval != DD_OK )
  257.     {
  258.         Msg("GetCaps failed err=%d", ddrval);
  259.         goto error;
  260.     }
  261.  
  262.     if( ddcaps.dwCaps & DDCAPS_NOHARDWARE )
  263.     {
  264.         Msg( "No hardware support at all" );
  265.     }
  266.  
  267.     if( ddcaps.dwCaps & DDCAPS_BLTCOLORFILL )
  268.     {
  269.         bColorFill = TRUE;
  270.         Msg( "Device supports color fill" );
  271.     }
  272.     else
  273.     {
  274.         bColorFill = FALSE;
  275.         Msg( "Device does not support color fill" );
  276.     }
  277.  
  278.     /*
  279.      * default to double buffered on 1mb, triple buffered
  280.      * on > 1mb
  281.      */
  282.     if (nBufferCount == 0)
  283.     {
  284.         if( ddcaps.dwVidMemTotal <= 1024L*1024L*(GameBPP/8) ||
  285.             GameMode.cx > 640 )
  286.         {
  287.             Msg("double buffering (not enough memory)");
  288.             nBufferCount = 2;
  289.         }
  290.         else
  291.         {
  292.             Msg("triple buffering");
  293.             nBufferCount = 3;
  294.         }
  295.     }
  296.  
  297.     if( ddcaps.dwCaps & DDCAPS_COLORKEY )
  298.     {
  299.         if( ddcaps.dwCKeyCaps & DDCKEYCAPS_SRCBLT )
  300.         {
  301.             Msg( "Can do Src colorkey in hardware" );
  302.         }
  303.  
  304.         if( ddcaps.dwCKeyCaps & DDCKEYCAPS_DESTBLT )
  305.         {
  306.             Msg( "Can do Dest colorkey in hardware" );
  307.             if( use_dest || !(ddcaps.dwCKeyCaps & DDCKEYCAPS_SRCBLT) )
  308.             {
  309.                 /*
  310.                  * since direct draw doesn't support
  311.                  * destination color key in emulation, only
  312.                  * use it if there is enough vram ...
  313.                  */
  314.                 if( ddcaps.dwVidMemTotal >= 2 * 1024L*1024L*(GameBPP/8) )
  315.                 {
  316.                     Msg( "Using destination color key" );
  317.                     bTransDest = TRUE;
  318.                 }
  319.             }
  320.         }
  321.     }
  322.     else
  323.     {
  324.         Msg( "Can't do color key in hardware!" );
  325.     }
  326.  
  327.     lpDD = lpdd;
  328.     lpDD2 = lpdd2;
  329.     return TRUE;
  330.  
  331. error:
  332.     return FALSE;
  333.  
  334. } /* DDEnable */
  335.  
  336. /*
  337.  * DDDisable
  338.  */
  339. BOOL DDDisable( BOOL fFinal )
  340. {
  341.     if( lpClipper )
  342.     {
  343.         IDirectDrawClipper_Release(lpClipper);
  344.         lpClipper = NULL;
  345.     }
  346.  
  347.     if( lpBackBuffer )
  348.     {
  349.         IDirectDrawSurface_Release(lpBackBuffer);
  350.         lpBackBuffer = NULL;
  351.     }
  352.  
  353.     if( lpFrontBuffer )
  354.     {
  355.         IDirectDrawSurface_Release(lpFrontBuffer);
  356.         lpFrontBuffer = NULL;
  357.     }
  358.  
  359.     if( lpStretchBuffer )
  360.     {
  361.         IDirectDrawSurface_Release(lpStretchBuffer);
  362.         lpStretchBuffer = NULL;
  363.     }
  364.  
  365.     //
  366.     // fFinal is TRUE when the app is exiting, FALSE if we are
  367.     // just seting a new game size..
  368.     //
  369.     if ( fFinal )
  370.     {
  371.         if( lpDD != NULL )
  372.         {
  373.             IDirectDraw_Release( lpDD );
  374.             IDirectDraw_Release( lpDD2 );
  375.             lpDD = NULL;
  376.         }
  377.     }
  378.  
  379.     return TRUE;
  380. }
  381.  
  382. /*
  383.  * DDClear
  384.  *
  385.  * clear the front buffer and all backbuffers.
  386.  */
  387. BOOL DDClear( void )
  388. {
  389.     DDBLTFX     ddbltfx;
  390.     int        i;
  391.     HRESULT     ddrval;
  392.  
  393.     UpdateWindow(hWndMain);
  394.  
  395.     ddbltfx.dwSize = sizeof( ddbltfx );
  396.     ddbltfx.dwFillColor = DDColorMatch(lpBackBuffer, RGB(0, 0, 200));
  397.  
  398.     if (bFullscreen)
  399.     {
  400.         /*
  401.          * do it for all buffers, we either have 1 or 2 back buffers
  402.          * make sure we get them all, 4 is plenty!
  403.          */
  404.         for( i=0; i<4; i++ )
  405.         {
  406.             ddrval = IDirectDrawSurface_Blt(
  407.                             lpBackBuffer,           // dest surface
  408.                             NULL,                   // dest rect
  409.                             NULL,                   // src surface
  410.                             NULL,                   // src rect
  411.                             DDBLT_COLORFILL | DDBLT_WAIT,
  412.                             &ddbltfx);
  413.  
  414.             if( ddrval != DD_OK )
  415.             {
  416.                 Msg("Fill failed ddrval =0x%08lX", ddrval);
  417.                 return FALSE;
  418.             }
  419.  
  420.             ddrval = IDirectDrawSurface_Flip(lpFrontBuffer, NULL, DDFLIP_WAIT);
  421.  
  422.             if( ddrval != DD_OK )
  423.             {
  424.                 Msg("Flip failed ddrval =0x%08lX", ddrval );
  425.                 return FALSE;
  426.             }
  427.         }
  428.     }
  429.     else
  430.     {
  431.         ddrval = IDirectDrawSurface_Blt(
  432.                         lpFrontBuffer,          // dest surface
  433.                         &rcWindow,              // dest rect
  434.                         NULL,                   // src surface
  435.                         NULL,                   // src rect
  436.                         DDBLT_COLORFILL | DDBLT_WAIT,
  437.                         &ddbltfx);
  438.  
  439.         if( ddrval != DD_OK )
  440.         {
  441.             Msg("Fill failed ddrval =0x%08lX", ddrval);
  442.             return FALSE;
  443.         }
  444.     }
  445.  
  446.     return TRUE;
  447.  
  448. } /* DDClear */
  449.  
  450. /*
  451.  * DDCreateFlippingSurface
  452.  *
  453.  * create a FrontBuffer and a BackBuffer(s)
  454.  *
  455.  */
  456. BOOL DDCreateFlippingSurface( void )
  457. {
  458.     DDPIXELFORMAT       ddpf;
  459.     DDSURFACEDESC    ddsd;
  460.     HRESULT        ddrval;
  461.     DDSCAPS        ddscaps;
  462.     DDCAPS              ddcaps;
  463.  
  464.     ddcaps.dwSize = sizeof( ddcaps );
  465.  
  466.     if( IDirectDraw_GetCaps( lpDD, &ddcaps, NULL ) != DD_OK )
  467.         return FALSE;
  468.  
  469.     /*
  470.      * fill in surface desc:
  471.      * want a primary surface with 2 back buffers
  472.      */
  473.     ZeroMemory( &ddsd, sizeof( ddsd ) );
  474.     ddsd.dwSize = sizeof( ddsd );
  475.  
  476.     if (bFullscreen && nBufferCount > 1)
  477.     {
  478.         //
  479.         //  fullscreen case, create a primary (ie front) and
  480.         //  either 1  or 2 back buffers
  481.         //
  482.         ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
  483.         ddsd.dwBackBufferCount = nBufferCount-1;
  484.         ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
  485.                 DDSCAPS_FLIP | DDSCAPS_COMPLEX;
  486.  
  487.         OutputDebugString("Creating multiple backbuffer primary\n\r");
  488.         ddrval = IDirectDraw_CreateSurface( lpDD, &ddsd, &lpFrontBuffer, NULL );
  489.  
  490.         if( ddrval != DD_OK )
  491.         {
  492.             Msg( "CreateSurface FAILED! %08lx", ddrval );
  493.             return FALSE;
  494.         }
  495.  
  496.         /*
  497.          * go find the back buffer
  498.          */
  499.         ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
  500.         ddrval = IDirectDrawSurface_GetAttachedSurface(
  501.                     lpFrontBuffer,
  502.                     &ddscaps,
  503.                     &lpBackBuffer );
  504.  
  505.         if( ddrval != DD_OK )
  506.         {
  507.             Msg( "GetAttachedSurface failed! err=%d",ddrval );
  508.             return FALSE;
  509.         }
  510.  
  511.         /*
  512.          *  if we are stretching create a buffer to stretch into
  513.          *
  514.          *  NOTE we always make this buffer in system memory because
  515.          *  we render to the backbuffer (in VRAM) at half the size
  516.          *  now we need to stretch into the backbuffer.  we could just
  517.          *  do a VRAM->VRAM stretch, but this is REAL REAL REAL slow on
  518.          *  some cards (banked cards..)
  519.          */
  520.         if( bStretch && (ddcaps.dwCaps & DDCAPS_BANKSWITCHED) )
  521.         {
  522.             Msg( "On bank switched hardware, creating stretch buffer" );
  523.             lpStretchBuffer = DDCreateSurface( GameSize.cx, GameSize.cy,
  524.                             TRUE, FALSE );
  525.         }
  526.     }
  527.     else if (bFullscreen && nBufferCount == 1)
  528.     {
  529.         ddsd.dwFlags = DDSD_CAPS;
  530.         ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
  531.  
  532.         OutputDebugString("Creating no backbuffer primary\n\r");
  533.         ddrval = IDirectDraw_CreateSurface( lpDD, &ddsd, &lpFrontBuffer, NULL );
  534.  
  535.         if( ddrval != DD_OK )
  536.         {
  537.             Msg( "CreateSurface FAILED! %08lx", ddrval );
  538.             return FALSE;
  539.         }
  540.  
  541.         IDirectDrawSurface_AddRef(lpFrontBuffer);
  542.         lpBackBuffer = lpFrontBuffer;
  543.     }
  544.     else
  545.     {
  546.         //
  547.         //  window case, create the primary surface
  548.         //  and create a backbuffer in offscreen memory.
  549.         //
  550.         ddsd.dwFlags = DDSD_CAPS;
  551.         ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
  552.  
  553.         ddrval = IDirectDraw_CreateSurface( lpDD, &ddsd, &lpFrontBuffer, NULL );
  554.  
  555.         if( ddrval != DD_OK )
  556.         {
  557.             Msg( "CreateSurface FAILED! %08lx", ddrval );
  558.             return FALSE;
  559.         }
  560.  
  561.         lpBackBuffer = DDCreateSurface( GameSize.cx, GameSize.cy, FALSE, FALSE );
  562.  
  563.         if( lpBackBuffer == NULL )
  564.         {
  565.             Msg( "Cant create the backbuffer" );
  566.             return FALSE;
  567.         }
  568.  
  569.         //
  570.         // now create a DirectDrawClipper object.
  571.         //
  572.         ddrval = IDirectDraw_CreateClipper(lpDD, 0, &lpClipper, NULL);
  573.  
  574.         if( ddrval != DD_OK )
  575.         {
  576.             Msg("Cant create clipper");
  577.             return FALSE;
  578.         }
  579.  
  580.         ddrval = IDirectDrawClipper_SetHWnd(lpClipper, 0, hWndMain);
  581.  
  582.         if( ddrval != DD_OK )
  583.         {
  584.             Msg("Cant set clipper window handle");
  585.             return FALSE;
  586.         }
  587.  
  588.         ddrval = IDirectDrawSurface_SetClipper(lpFrontBuffer, lpClipper);
  589.  
  590.         if( ddrval != DD_OK )
  591.         {
  592.             Msg("Cant attach clipper to front buffer");
  593.             return FALSE;
  594.         }
  595.     }
  596.  
  597.     /*
  598.      * init the color key
  599.      */
  600.     ddpf.dwSize = sizeof(ddpf);
  601.     IDirectDrawSurface_GetPixelFormat(lpFrontBuffer, &ddpf);
  602.  
  603.     /*
  604.      * we use white as the color key, if we are in a 8bpp mode, we know
  605.      * what white is (because we use a 332 palette) if we are not in a
  606.      * a 8bpp mode we dont know what white is and we need to figure it
  607.      * out from the device (remember 16bpp comes in two common flavors
  608.      * 555 and 565).  if we wanted to any random color as the color key
  609.      * we would call DDColorMatch (see below) to convert a RGB into a
  610.      * physical color.
  611.      */
  612.     if (ddpf.dwRGBBitCount == 8)
  613.         dwColorKey = 0xff;
  614.     else
  615.         dwColorKey = ddpf.dwRBitMask | ddpf.dwGBitMask | ddpf.dwBBitMask;
  616.  
  617.     Msg("dwColorKey = 0x%08lX", dwColorKey);
  618.  
  619.     if( bTransDest )
  620.     {
  621.     DDCOLORKEY        ddck;
  622.         ddck.dwColorSpaceLowValue = dwColorKey;
  623.         ddck.dwColorSpaceHighValue = dwColorKey;
  624.         IDirectDrawSurface_SetColorKey( lpBackBuffer, DDCKEY_DESTBLT, &ddck);
  625.     }
  626.  
  627.     return TRUE;
  628.  
  629. } /* DDCreateFlippingSurface */
  630.  
  631. /*
  632.  * DDCreateSurface
  633.  */
  634. LPDIRECTDRAWSURFACE DDCreateSurface(
  635.         DWORD width,
  636.         DWORD height,
  637.         BOOL sysmem,
  638.         BOOL trans )
  639. {
  640.     DDSURFACEDESC    ddsd;
  641.     HRESULT        ddrval;
  642.     DDCOLORKEY        ddck;
  643.     LPDIRECTDRAWSURFACE    psurf;
  644.  
  645.  
  646.     /*
  647.      * fill in surface desc
  648.      */
  649.     memset( &ddsd, 0, sizeof( ddsd ) );
  650.     ddsd.dwSize = sizeof( ddsd );
  651.     ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT |DDSD_WIDTH;
  652.  
  653.     ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
  654.     if( sysmem || bUseSysMem )
  655.     {
  656.     ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
  657.     }
  658.  
  659.     ddsd.dwHeight = height;
  660.     ddsd.dwWidth = width;
  661.  
  662.     ddrval = IDirectDraw_CreateSurface( lpDD, &ddsd, &psurf, NULL );
  663.  
  664.     /*
  665.      * set the color key for this bitmap
  666.      */
  667.     if( ddrval == DD_OK )
  668.     {
  669.     if( trans && !bTransDest )
  670.     {
  671.             ddck.dwColorSpaceLowValue = dwColorKey;
  672.             ddck.dwColorSpaceHighValue = dwColorKey;
  673.             IDirectDrawSurface_SetColorKey( psurf, DDCKEY_SRCBLT, &ddck);
  674.     }
  675.     }
  676.     else
  677.     {
  678.     Msg( "CreateSurface FAILED, rc = %ld", (DWORD) LOWORD( ddrval ) );
  679.     psurf = NULL;
  680.     }
  681.  
  682.      return psurf;
  683.  
  684. } /* DDCreateSurface */
  685.  
  686. DWORD DDColorMatch(IDirectDrawSurface *pdds, COLORREF rgb)
  687. {
  688.     COLORREF rgbT;
  689.     HDC hdc;
  690.     DWORD dw = CLR_INVALID;
  691.     DDSURFACEDESC ddsd;
  692.     HRESULT hres;
  693.  
  694.     if (IDirectDrawSurface_GetDC(pdds, &hdc) == DD_OK)
  695.     {
  696.         rgbT = GetPixel(hdc, 0, 0);
  697.         SetPixel(hdc, 0, 0, rgb);
  698.         IDirectDrawSurface_ReleaseDC(pdds, hdc);
  699.     }
  700.  
  701.     ddsd.dwSize = sizeof(ddsd);
  702.     hres = IDirectDrawSurface_Lock(
  703.         pdds, NULL, &ddsd, DDLOCK_WAIT, NULL);
  704.  
  705.     if (hres == DD_OK)
  706.     {
  707.         dw  = *(DWORD *)ddsd.lpSurface;
  708.     if(ddsd.ddpfPixelFormat.dwRGBBitCount != 32)
  709.         dw &= (1 << ddsd.ddpfPixelFormat.dwRGBBitCount)-1;
  710.         IDirectDrawSurface_Unlock(pdds, NULL);
  711.     }
  712.     else
  713.     {
  714.     IDirectDrawSurface_GetSurfaceDesc(pdds,&ddsd);
  715.     if(ddsd.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
  716.         Msg("Failed to lock Primary Surface!");
  717.     else
  718.         Msg("Failed to lock NON-PRIMARY Surface!");
  719.     }
  720.  
  721.     if (IDirectDrawSurface_GetDC(pdds, &hdc) == DD_OK)
  722.     {
  723.         SetPixel(hdc, 0, 0, rgbT);
  724.         IDirectDrawSurface_ReleaseDC(pdds, hdc);
  725.     }
  726.  
  727.     return dw;
  728. }
  729.  
  730. /*
  731.  * ReadPalFile
  732.  *
  733.  * Create a DirectDrawPalette from a palette file
  734.  *
  735.  * if the palette files cant be found, make a default 332 palette
  736.  */
  737. LPDIRECTDRAWPALETTE ReadPalFile( char *fname )
  738. {
  739.     int                 i;
  740.     int            fh;
  741.     HRESULT        ddrval;
  742.     IDirectDrawPalette *ppal;
  743.  
  744.     struct  {
  745.         DWORD           dwRiff;
  746.         DWORD           dwFileSize;
  747.         DWORD           dwPal;
  748.         DWORD           dwData;
  749.         DWORD           dwDataSize;
  750.         WORD            palVersion;
  751.         WORD            palNumEntries;
  752.         PALETTEENTRY    ape[256];
  753.     }   pal;
  754.  
  755.     pal.dwRiff = 0;
  756.  
  757.     if (fname)
  758.     {
  759.         fh = _lopen( fname, OF_READ);
  760.  
  761.         if (fh != -1)
  762.         {
  763.             _lread(fh, &pal, sizeof(pal));
  764.             _lclose(fh);
  765.         }
  766.     }
  767.  
  768.     /*
  769.      * if the file is not a palette file, or does not exist
  770.      * default to a 332 palette
  771.      */
  772.     if (pal.dwRiff != 0x46464952 || // 'RIFF'
  773.         pal.dwPal  != 0x204C4150 || // 'PAL '
  774.         pal.dwData != 0x61746164 || // 'data'
  775.         pal.palVersion != 0x0300 ||
  776.         pal.palNumEntries > 256  ||
  777.         pal.palNumEntries < 1)
  778.     {
  779.         Msg("Can't open palette file, using default 332.");
  780.  
  781.         for( i=0; i<256; i++ )
  782.         {
  783.             pal.ape[i].peRed   = (BYTE)(((i >> 5) & 0x07) * 255 / 7);
  784.             pal.ape[i].peGreen = (BYTE)(((i >> 2) & 0x07) * 255 / 7);
  785.             pal.ape[i].peBlue  = (BYTE)(((i >> 0) & 0x03) * 255 / 3);
  786.             pal.ape[i].peFlags = (BYTE)0;
  787.         }
  788.     }
  789.  
  790.     ddrval = IDirectDraw_CreatePalette(
  791.                 lpDD,
  792.                 DDPCAPS_8BIT,
  793.                             pal.ape,
  794.                 &ppal,
  795.                 NULL );
  796.     return ppal;
  797.  
  798. } /* ReadPalFile */
  799.  
  800.  
  801. /*
  802.  * Splash
  803.  *
  804.  * Draw a splash screen during startup
  805.  * NOTE the screen has been cleared in DDCreateFlippingSurface
  806.  */
  807. void Splash( void )
  808. {
  809.     HDC hdc;
  810.     HRESULT err = 0;
  811.  
  812.     DDClear();
  813.  
  814. //    if ((err = IDirectDrawSurface_GetDC(lpFrontBuffer, &hdc)) == DD_OK)
  815.     if ((hdc = GetDC(hWndMain)) )
  816.     {
  817.         char ach[256];
  818.         int len;
  819.  
  820.         len = wsprintf(ach,
  821.             "FoxBear is loading......   Device:%s %s",
  822.             aDDDevs[DevIndex].DriverDesc, aDDDevs[DevIndex].DriverName);
  823.  
  824.         SetTextColor(hdc, RGB(255,255,255));
  825.         SetBkMode(hdc, TRANSPARENT);
  826.         TextOut(hdc, rcWindow.left, rcWindow.top, ach, len);
  827.  
  828.         //IDirectDrawSurface_ReleaseDC(lpFrontBuffer, hdc);
  829.         ReleaseDC(hWndMain,hdc);
  830.     }
  831.     else
  832.     {
  833.     Msg("GetDC failed! 0x%x",err);
  834.     }
  835.  
  836. } /* Splash */
  837.  
  838. /*
  839.  * MEMORY ALLOCATION ROUTINES...
  840.  */
  841.  
  842. /*
  843.  * MemAlloc
  844.  */
  845. LPVOID MemAlloc( UINT size )
  846. {
  847.     LPVOID    ptr;
  848.  
  849.     ptr = LocalAlloc( LPTR, size );
  850.     return ptr;
  851.  
  852. } /* MemAlloc */
  853.  
  854. /*
  855.  * CMemAlloc
  856.  */
  857. LPVOID CMemAlloc( UINT cnt, UINT isize )
  858. {
  859.     DWORD    size;
  860.     LPVOID    ptr;
  861.  
  862.     size = cnt * isize;
  863.     ptr = LocalAlloc( LPTR, size );
  864.     return ptr;
  865.  
  866. } /* CMemAlloc */
  867.  
  868. /*
  869.  * MemFree
  870.  */
  871. void MemFree( LPVOID ptr )
  872. {
  873.     if( ptr != NULL )
  874.     {
  875.     LocalFree( ptr );
  876.     }
  877.  
  878. } /* MemFree */
  879.  
  880. HRESULT CALLBACK EnumDisplayModesCallback(LPDDSURFACEDESC pddsd, LPVOID Context)
  881. {
  882.     int ChkMode;
  883.  
  884.     Msg("Mode: %dx%dx%d", pddsd->dwWidth, pddsd->dwHeight,pddsd->ddpfPixelFormat.dwRGBBitCount);
  885.  
  886.     for(ChkMode = 0;ChkMode < NumModes;ChkMode++)
  887.     {
  888.         if(
  889.             (ModeList[ChkMode].w == (int)pddsd->dwWidth)&&
  890.             (ModeList[ChkMode].h == (int)pddsd->dwHeight)&&
  891.             (ModeList[ChkMode].bpp == (int)pddsd->ddpfPixelFormat.dwRGBBitCount)&& 
  892.             (ModeList[ChkMode].dwFlags == (int)pddsd->ddsCaps.dwCaps)
  893.           )
  894.             return DDENUMRET_OK;
  895.     }
  896.  
  897.     ModeList[NumModes].w   = pddsd->dwWidth;
  898.     ModeList[NumModes].h   = pddsd->dwHeight;
  899.     ModeList[NumModes].bpp = pddsd->ddpfPixelFormat.dwRGBBitCount;
  900.     ModeList[NumModes].dwFlags = pddsd->ddsCaps.dwCaps;
  901.  
  902.     NumModes++;
  903.  
  904.     return DDENUMRET_OK;
  905. }
  906.  
  907. HRESULT CALLBACK DDEnumCallback(GUID * lpGUID, LPSTR DriverDesc, LPSTR DriverName, LPVOID lpContext)
  908. {
  909.     if(MaxDevIndex >= sizeof(aDDDevs)/sizeof(aDDDevs[0]))
  910.         return E_FAIL;
  911.  
  912.     Msg("Device: %s (%s)", DriverDesc, DriverName);
  913.  
  914.     if(lpGUID == NULL || lpGUID == (GUID*)DDCREATE_EMULATIONONLY)
  915.     {
  916.         aDDDevs[MaxDevIndex].guid = lpGUID;
  917.     }
  918.     else
  919.     {
  920.         aDDDevs[MaxDevIndex].DriverGUID = *lpGUID;
  921.         aDDDevs[MaxDevIndex].guid = &aDDDevs[MaxDevIndex].DriverGUID;
  922.     }
  923.  
  924.     lstrcpyn(aDDDevs[MaxDevIndex].DriverDesc, DriverDesc, 128);
  925.     lstrcpyn(aDDDevs[MaxDevIndex].DriverName, DriverName, 128);
  926.  
  927.     MaxDevIndex++;
  928.     return DDENUMRET_OK;
  929. }
  930.