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 / gfx.c < prev    next >
C/C++ Source or Header  |  1997-07-14  |  15KB  |  610 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:    gfx.c
  7.  *  Content:    graphics API
  8.  *
  9.  ***************************************************************************/
  10. #include "foxbear.h"
  11.  
  12. GFX_BITMAP  *lpVRAM;
  13.  
  14. static BOOL fForceRestore = FALSE;
  15.  
  16. /*
  17.  * gfxBlt
  18.  */
  19. BOOL gfxBlt(RECT *dst, GFX_HBM bm, POINT *src)
  20. {
  21.     GFX_BITMAP* pbm = (GFX_BITMAP*)bm;
  22.     HRESULT     ddrval;
  23.     DWORD       bltflags;
  24.     RECT        rc;
  25.     int         x,y,dx,dy;
  26.  
  27.     if( GameSize.cy == C_SCREEN_H )
  28.     {
  29.         y         = dst->top;
  30.         dy        = dst->bottom - dst->top;
  31.         rc.top    = src->y;
  32.         rc.bottom = rc.top  + dy;
  33.     }
  34.     else
  35.     {
  36.         y         = MapY(dst->top);
  37.         dy        = MapY(dst->bottom) - y;
  38.         rc.top    = MapDY(src->y);
  39.         rc.bottom = rc.top  + dy;
  40.     }
  41.  
  42.     if( GameSize.cx == C_SCREEN_W )
  43.     {
  44.         x         = dst->left;
  45.         dx        = dst->right  - dst->left;
  46.         rc.left   = src->x;
  47.         rc.right  = rc.left + dx;
  48.     }
  49.     else
  50.     {
  51.         x         = MapX(dst->left);
  52.         dx        = MapX(dst->right) - x;
  53.         rc.left   = MapDX(src->x);
  54.         rc.right  = rc.left + dx;
  55.     }
  56.  
  57.  
  58.     if( dx == 0 || dy == 0 )
  59.     {
  60.         return TRUE;
  61.     }
  62.  
  63.     if (pbm->lpSurface)
  64.     {
  65.         if( pbm->bTrans )
  66.             bltflags = bTransDest ? DDBLTFAST_DESTCOLORKEY : DDBLTFAST_SRCCOLORKEY;
  67.         else
  68.             bltflags = bTransDest ? DDBLTFAST_DESTCOLORKEY : DDBLTFAST_NOCOLORKEY;
  69.         ddrval = IDirectDrawSurface_BltFast(
  70.                         lpBackBuffer, x, y,
  71.                         pbm->lpSurface, &rc, bltflags | DDBLTFAST_WAIT);
  72.  
  73.         if (ddrval != DD_OK)
  74.         {
  75.             Msg("BltFast failed err=%d", ddrval);
  76.         }
  77.     }
  78.     else
  79.     {
  80.         DDBLTFX     ddbltfx;
  81.  
  82.         rc.left   = x;
  83.         rc.top    = y;
  84.         rc.right  = rc.left + dx;
  85.         rc.bottom = rc.top  + dy;
  86.  
  87.         ddbltfx.dwSize = sizeof( ddbltfx );
  88.         ddbltfx.dwFillColor = pbm->dwColor;
  89.  
  90.         ddrval = IDirectDrawSurface_Blt(
  91.                         lpBackBuffer,           // dest surface
  92.                         &rc,                    // dest rect
  93.                         NULL,                   // src surface
  94.                         NULL,                   // src rect
  95.                         DDBLT_COLORFILL | DDBLT_WAIT,
  96.                         &ddbltfx);
  97.     }
  98.  
  99.     return TRUE;
  100.  
  101. } /* gfxBlt */
  102.  
  103. /*
  104.  * gfxCreateSolidColorBitmap
  105.  */
  106. GFX_HBM gfxCreateSolidColorBitmap(COLORREF rgb)
  107. {
  108.     GFX_BITMAP *pvram;
  109.  
  110.     pvram = MemAlloc( sizeof( *pvram ) );
  111.  
  112.     if( pvram == NULL )
  113.     {
  114.     return NULL;
  115.     }
  116.  
  117.     pvram->dwColor = DDColorMatch(lpBackBuffer, rgb);
  118.     pvram->lpSurface = NULL;
  119.     pvram->lpbi = NULL;
  120.     pvram->bTrans = FALSE;
  121.  
  122.     pvram->link = lpVRAM;
  123.     lpVRAM = pvram;
  124.  
  125.     return (GFX_HBM) pvram;
  126.  
  127. } /* gfxCreateSolidColorBitmap */
  128.  
  129. /*
  130.  * gfxCreateBitmap
  131.  */
  132. GFX_HBM gfxCreateVramBitmap(BITMAPINFOHEADER UNALIGNED *lpbi,BOOL bTrans)
  133. {
  134.     GFX_BITMAP *pvram;
  135.  
  136.     pvram = MemAlloc( sizeof( *pvram ) );
  137.  
  138.     if( pvram == NULL )
  139.     {
  140.     return NULL;
  141.     }
  142.     pvram->lpSurface = DDCreateSurface(MapRX(lpbi->biWidth),
  143.                                        MapRY(lpbi->biHeight), FALSE, TRUE);
  144.     pvram->lpbi = lpbi;
  145.     pvram->dwColor = 0;
  146.     pvram->bTrans = bTrans;
  147.  
  148.     if( pvram->lpSurface == NULL )
  149.     {
  150.     return NULL;
  151.     }
  152.  
  153.     pvram->link = lpVRAM;
  154.     lpVRAM = pvram;
  155.     gfxRestore((GFX_HBM) pvram);
  156.  
  157.     return (GFX_HBM) pvram;
  158.  
  159. } /* gfxCreateVramBitmap */
  160.  
  161. /*
  162.  * gfxDestroyBitmap
  163.  */
  164. BOOL gfxDestroyBitmap ( GFX_HBM hbm )
  165. {
  166.     GFX_BITMAP *p = (GFX_BITMAP *)hbm;
  167.  
  168.     if (hbm == NULL || hbm == GFX_TRUE)
  169.     {
  170.     return FALSE;
  171.     }
  172.  
  173.     if (p->lpSurface)
  174.     {
  175.         IDirectDrawSurface_Release(p->lpSurface);
  176.         p->lpSurface = NULL;
  177.     }
  178.  
  179.     if (p->lpbi)
  180.     {
  181.         p->lpbi = NULL;
  182.     }
  183.  
  184.     MemFree((VOID *)p);
  185.  
  186.     return TRUE;
  187.  
  188. } /* gfxDestroyBitmap */
  189.  
  190. /*
  191.  * gfxStretchBackBuffer()
  192.  */
  193. BOOL gfxStretchBackbuffer()
  194. {
  195.     if (lpStretchBuffer)
  196.     {
  197.         IDirectDrawSurface_Blt(
  198.                             lpStretchBuffer,        // dest surface
  199.                             NULL,                   // dest rect (all of it)
  200.                             lpBackBuffer,           // src surface
  201.                             &GameRect,              // src rect
  202.                             DDBLT_WAIT,
  203.                             NULL);
  204.  
  205.         IDirectDrawSurface_Blt(
  206.                             lpBackBuffer,           // dest surface
  207.                             NULL,                   // dest rect (all of it)
  208.                             lpStretchBuffer,        // src surface
  209.                             NULL,                   // src rect
  210.                             DDBLT_WAIT,
  211.                             NULL);
  212.     }
  213.     else
  214.     {
  215.         IDirectDrawSurface_Blt(
  216.                         lpBackBuffer,           // dest surface
  217.                         NULL,                   // dest rect (all of it)
  218.                         lpBackBuffer,           // src surface
  219.                         &GameRect,              // src rect
  220.                         DDBLT_WAIT,
  221.                         NULL);
  222.     }
  223.  
  224.     return TRUE;
  225.  
  226. } /* gfxStretchBackbuffer */
  227.  
  228. /*
  229.  * gfxFlip
  230.  */
  231. BOOL gfxFlip( void )
  232. {
  233.     HRESULT     ddrval;
  234.  
  235.     ddrval = IDirectDrawSurface_Flip( lpFrontBuffer, NULL, DDFLIP_WAIT );
  236.     if( ddrval != DD_OK )
  237.     {
  238.     Msg( "Flip FAILED, rc=%08lx", ddrval );
  239.     return FALSE;
  240.     }
  241.     return TRUE;
  242.  
  243. } /* gfxFlip */
  244.  
  245. /*
  246.  * gfxUpdateWindow
  247.  */
  248. BOOL gfxUpdateWindow()
  249. {
  250.     HRESULT     ddrval;
  251.  
  252.     ddrval = IDirectDrawSurface_Blt(
  253.                     lpFrontBuffer,          // dest surface
  254.                     &rcWindow,              // dest rect
  255.                     lpBackBuffer,           // src surface
  256.                     NULL,                   // src rect (all of it)
  257.                     DDBLT_WAIT,
  258.                     NULL);
  259.  
  260.     return ddrval == DD_OK;
  261.  
  262. } /* gfxUpdateWindow */
  263.  
  264. /*
  265.  * gfxSwapBuffers
  266.  *
  267.  * this is called when the game loop has rendered a frame into
  268.  * the backbuffer, its goal is to display something for the user to see.
  269.  *
  270.  * there are four cases...
  271.  *
  272.  * Fullscreen:
  273.  *      we just call IDirectDrawSurface::Flip(lpFrontBuffer)
  274.  *      being careful to handle return code right.
  275.  *
  276.  * Fullscreen (stretched):
  277.  *      the game loop has rendered a frame 1/2 the display
  278.  *      size, we do a Blt to stretch the frame to the backbuffer
  279.  *      the we just call IDirectDrawSurface::Flip(lpFrontBuffer)
  280.  *
  281.  * Window mode (foreground palette):
  282.  *      in this case we call IDirectDrawSurface::Blt to copy
  283.  *      the back buffer to the window.
  284.  *
  285.  * Window mode (background palette):
  286.  *      in this case we are in a window, but we dont own the
  287.  *      palette. all our art was loaded to a specific palette
  288.  *      IDirectDrawSurface::Blt does not do color translation
  289.  *      we have a few options in this case...
  290.  *
  291.  *          reload or remap the art to the the current palette
  292.  *          (we can do this easily with a GetDC, StetchDIBits)
  293.  *          FoxBear has *alot* of art, so this would be too slow.
  294.  *
  295.  *          use GDI to draw the backbuffer, GDI will handle
  296.  *          the color conversion so things will look correct.
  297.  *
  298.  *          pause the game (this is what we do so this function
  299.  *          will never be called)
  300.  *
  301.  */
  302. BOOL gfxSwapBuffers( void )
  303. {
  304.     if( bFullscreen )
  305.     {
  306.         if( bStretch )
  307.     {
  308.             gfxStretchBackbuffer();
  309.     }
  310.  
  311.         if (nBufferCount > 1)
  312.             return gfxFlip();
  313.         else
  314.             return TRUE;
  315.     }
  316.     else
  317.     {
  318.         return gfxUpdateWindow();
  319.     }
  320.  
  321. } /* gfxSwapBuffers */
  322.  
  323. /*
  324.  * gfxBegin
  325.  */
  326. GFX_HBM gfxBegin( void )
  327. {
  328.     if( !DDEnable() )
  329.     {
  330.     return NULL;
  331.     }
  332.  
  333.     if( !DDCreateFlippingSurface() )
  334.     {
  335.         DDDisable(TRUE);
  336.     return NULL;
  337.     }
  338.     Splash();
  339.  
  340.     return GFX_TRUE;
  341.  
  342. } /* gfxBegin */
  343.  
  344. /*
  345.  * gfxEnd
  346.  */
  347. BOOL gfxEnd ( GFX_HBM hbm )
  348. {
  349.     GFX_BITMAP  *curr;
  350.     GFX_BITMAP  *next;
  351.  
  352.     for( curr = lpVRAM; curr; curr=next )
  353.     {
  354.         next = curr->link;
  355.         gfxDestroyBitmap ((GFX_HBM)curr);
  356.     }
  357.  
  358.     lpVRAM = NULL;
  359.  
  360.     return DDDisable(FALSE);
  361.  
  362.     return TRUE;
  363.  
  364. } /* gfxEnd */
  365.  
  366. /*
  367.  * gfxRestore
  368.  *
  369.  * restore the art when one or more surfaces are lost
  370.  */
  371. BOOL gfxRestore(GFX_HBM bm)
  372. {
  373.     GFX_BITMAP *pbm = (GFX_BITMAP*)bm;
  374.     HRESULT     ddrval;
  375.     HDC hdc;
  376.     LPVOID lpBits;
  377.     RGBQUAD *prgb;
  378.     int i,w,h;
  379.     RECT rc;
  380.  
  381.     struct {
  382.         BITMAPINFOHEADER bi;
  383.         RGBQUAD          ct[256];
  384.     }   dib;
  385.  
  386.     IDirectDrawSurface *pdds = pbm->lpSurface;
  387.     BITMAPINFOHEADER   UNALIGNED *pbi  = pbm->lpbi;
  388.  
  389.     if (pdds == NULL)
  390.         return TRUE;
  391.  
  392.     if (IDirectDrawSurface_Restore(pdds) != DD_OK)
  393.         return FALSE;
  394.  
  395.     if (pbi == NULL)
  396.         return TRUE;
  397.  
  398.     //
  399.     // in 8bbp mode if we get switched away from while loading
  400.     // (and palette mapping) our art, the colors will not be correct
  401.     // because some app may have changed the system palette.
  402.     //
  403.     // if we are in stress mode, just keep going.  It is more important
  404.     // to make progress than to get the colors right.
  405.     //
  406.  
  407.     if (!bFullscreen &&
  408.          GameBPP == 8 && 
  409.          GetForegroundWindow() != hWndMain && 
  410.          !bStress )
  411.     {
  412.         Msg("gfxRestore: **** foreground window changed while loading art!");
  413.         fForceRestore = TRUE;
  414.         PauseGame();
  415.         return FALSE;
  416.     }
  417.  
  418.     dib.bi = *pbi;
  419.  
  420.     prgb = (RGBQUAD *)((LPBYTE)pbi + pbi->biSize);
  421.     lpBits = (LPBYTE)(prgb + pbi->biClrUsed);
  422.  
  423.     if( pbi->biClrUsed == 0 && pbi->biBitCount <= 8 )
  424.     {
  425.         lpBits = (LPBYTE)(prgb + (1<<pbi->biBitCount));
  426.     }
  427.  
  428.     w = MapRX(pbi->biWidth);
  429.     h = MapRY(pbi->biHeight);
  430.     /*
  431.      * hack to make sure fox off-white doesn't become
  432.      * pure white (which is transparent)
  433.      */
  434.     for( i=0; i<256; i++ )
  435.     {
  436.         dib.ct[i] = prgb[i];
  437.  
  438.         if( dib.ct[i].rgbRed   == 0xff &&
  439.             dib.ct[i].rgbGreen == 0xff &&
  440.             dib.ct[i].rgbBlue  == 224 )
  441.         {
  442.             dib.ct[i].rgbBlue = 0x80;
  443.         }
  444.         else
  445.         if( dib.ct[i].rgbRed   == 251 &&
  446.             dib.ct[i].rgbGreen == 243 &&
  447.             dib.ct[i].rgbBlue  == 234 )
  448.         {
  449.             dib.ct[i].rgbBlue = 0x80;
  450.         }
  451.     }
  452.  
  453.     /*
  454.      * if we are in 8bit mode we know the palette is 332 we can
  455.      * do the mapping our self.
  456.      *
  457.      * NOTE we can only do this in fullscreen mode
  458.      * in windowed mode, we have to share the palette with
  459.      * the window manager and we dont get all of the colors
  460.      * in the order we assume.
  461.      *
  462.      */
  463.     if (bFullscreen && GameBPP == pbi->biBitCount && GameBPP == 8 )
  464.     {
  465.         BYTE xlat332[256];
  466.         DDSURFACEDESC ddsd;
  467.         int x,y,dib_pitch;
  468.         BYTE *src, *dst;
  469.         BOOL stretch;
  470.         IDirectDrawSurface *pdds1;
  471.         HDC hdc1;
  472.  
  473.         stretch = w != pbi->biWidth || h != pbi->biHeight;
  474.  
  475.         for( i=0;i<256;i++ )
  476.         {
  477.             xlat332[i] =
  478.                 ((dib.ct[i].rgbRed   >> 0) & 0xE0 ) |
  479.                 ((dib.ct[i].rgbGreen >> 3) & 0x1C ) |
  480.                 ((dib.ct[i].rgbBlue  >> 6) & 0x03 );
  481.         }
  482.  
  483.         /*
  484.          * if we are stretching copy into the back buffer
  485.          * then use GDI to stretch later.
  486.          */
  487.         if( stretch )
  488.     {
  489.             pdds1 = lpBackBuffer;
  490.     }
  491.         else
  492.     {
  493.             pdds1 = pdds;
  494.     }
  495.  
  496.         ddsd.dwSize = sizeof(ddsd);
  497.         ddrval = IDirectDrawSurface_Lock(
  498.             pdds1, NULL, &ddsd, DDLOCK_WAIT, NULL);
  499.  
  500.         if( ddrval == DD_OK )
  501.         {
  502.             dib_pitch = (pbi->biWidth+3)&~3;
  503.             src = (BYTE *)lpBits + dib_pitch * (pbi->biHeight-1);
  504.             dst = (BYTE *)ddsd.lpSurface;
  505.             for( y=0; y<(int)pbi->biHeight; y++ )
  506.             {
  507.                 for( x=0; x<(int)pbi->biWidth; x++ )
  508.                 {
  509.                     dst[x] = xlat332[src[x]];
  510.                 }
  511.                 dst += ddsd.lPitch;
  512.                 src -= dib_pitch;
  513.             }
  514.             IDirectDrawSurface_Unlock(pdds1, NULL);
  515.         }
  516.         else
  517.         {
  518.             Msg("Lock failed err=%d", ddrval);
  519.             return FALSE;
  520.         }
  521.  
  522.         if( stretch )
  523.         {
  524.             if( IDirectDrawSurface_GetDC(pdds,&hdc) == DD_OK )
  525.             {
  526.                 if( IDirectDrawSurface_GetDC(pdds1,&hdc1) == DD_OK )
  527.                 {
  528.             SetStretchBltMode(hdc, COLORONCOLOR);
  529.                     StretchBlt(hdc, 0, 0, w, h,
  530.                         hdc1, 0, 0, pbi->biWidth, pbi->biHeight, SRCCOPY);
  531.                     IDirectDrawSurface_ReleaseDC(pdds1,hdc1);
  532.                 }
  533.                 IDirectDrawSurface_ReleaseDC(pdds,hdc);
  534.             }
  535.         }
  536.     }
  537.     else if( IDirectDrawSurface_GetDC(pdds,&hdc) == DD_OK )
  538.     {
  539.         SetStretchBltMode(hdc, COLORONCOLOR);
  540.         StretchDIBits(hdc, 0, 0, w, h,
  541.             0, 0, pbi->biWidth, pbi->biHeight,
  542.             lpBits, (BITMAPINFO *)&dib.bi, DIB_RGB_COLORS, SRCCOPY);
  543.  
  544.         IDirectDrawSurface_ReleaseDC(pdds,hdc);
  545.     }
  546.  
  547.     /*
  548.      * show the art while loading...
  549.      */
  550.     rc.left = rcWindow.left,
  551.     rc.top  = rcWindow.top + 20;
  552.     rc.right = rc.left + w;
  553.     rc.bottom = rc.top + h;
  554.     IDirectDrawSurface_Blt(lpFrontBuffer, &rc, pdds, NULL, DDBLT_WAIT, NULL);
  555.  
  556.     return TRUE;
  557.  
  558. } /* gfxRestore */
  559.  
  560. /*
  561.  * gfxRestoreAll
  562.  *
  563.  * restore the art when one or more surfaces are lost
  564.  */
  565. BOOL gfxRestoreAll()
  566. {
  567.     GFX_BITMAP  *curr;
  568.     HWND hwndF = GetForegroundWindow();
  569.  
  570.     Splash();
  571.  
  572.     for( curr = lpVRAM; curr != NULL; curr = curr->link)
  573.     {
  574.     if (curr->lpSurface &&
  575.         (fForceRestore || IDirectDrawSurface_IsLost(curr->lpSurface) == DDERR_SURFACELOST))
  576.         {
  577.             if( !gfxRestore(curr) )
  578.             {
  579.                 Msg( "gfxRestoreAll: ************ Restore FAILED!" );
  580.                 return FALSE;
  581.             }
  582.         }
  583.     }
  584.  
  585.     DDClear();
  586.     fForceRestore = FALSE;
  587.     return TRUE;
  588.  
  589. } /* gfxRestoreAll */
  590.  
  591. /*
  592.  * gfxFillBack
  593.  */
  594. void gfxFillBack( DWORD dwColor )
  595. {
  596.     DDBLTFX    ddbltfx;
  597.  
  598.     ddbltfx.dwSize = sizeof( ddbltfx );
  599.     ddbltfx.dwFillColor = dwColor;
  600.  
  601.     IDirectDrawSurface_Blt(
  602.             lpBackBuffer,        // dest surface
  603.             NULL,            // dest rect
  604.             NULL,            // src surface
  605.             NULL,            // src rect
  606.                         DDBLT_COLORFILL | DDBLT_WAIT,
  607.                         &ddbltfx);
  608.  
  609. } /* gfxFillBack */
  610.