home *** CD-ROM | disk | FTP | other *** search
/ NEXT Generation 27 / NEXT27.iso / pc / demos / emperor / dx3.exe / SDK / SAMPLES / IKLOWNS / CGBITBUF.CPP < prev    next >
C/C++ Source or Header  |  1996-08-28  |  35KB  |  1,472 lines

  1. /*===========================================================================*\
  2. |
  3. |  File:        cgbitbuf.cpp
  4. |
  5. |  Description: 
  6. |       
  7. |-----------------------------------------------------------------------------
  8. |
  9. |  Copyright (C) 1995-1996 Microsoft Corporation.  All Rights Reserved.
  10. |
  11. |  Written by Moss Bay Engineering, Inc. under contract to Microsoft Corporation
  12. |
  13. \*===========================================================================*/
  14.  
  15. /**************************************************************************
  16.  
  17.     (C) Copyright 1995-1996 Microsoft Corp.  All rights reserved.
  18.  
  19.     You have a royalty-free right to use, modify, reproduce and 
  20.     distribute the Sample Files (and/or any modified version) in 
  21.     any way you find useful, provided that you agree that 
  22.     Microsoft has no warranty obligations or liability for any 
  23.     Sample Application Files which are modified. 
  24.  
  25.     we do not recomend you base your game on IKlowns, start with one of
  26.     the other simpler sample apps in the GDK
  27.  
  28.  **************************************************************************/
  29.  
  30.  
  31. //#ifndef __WATCOMC__
  32. #define WIN32_LEAN_AND_MEAN
  33. //#endif
  34. #include <windows.h>
  35. #include "cgdebug.h"
  36. #include "cgdib.h"
  37. #include "cgbitbuf.h"
  38. #include "cgimage.h"
  39. #include "cgglobl.h"
  40.  
  41. /*---------------------------------------------------------------------------*\
  42. |
  43. |       Class CGameBitBuffer
  44. |
  45. |  DESCRIPTION:
  46. |       
  47. |
  48. |
  49. \*---------------------------------------------------------------------------*/
  50.  
  51. CGameBitBuffer::CGameBitBuffer(
  52.     CGameDIB* pDIB,
  53.     int width,
  54.     int height,
  55.     COLORREF transColor
  56.     ) : mhPalette( NULL ),
  57.         mTransColor( transColor )
  58. {
  59. }   
  60.  
  61. CGameBitBuffer::CGameBitBuffer(
  62.     int width,
  63.     int height,
  64.     HPALETTE hPal,
  65.     COLORREF transColor
  66.     ) : mhPalette( NULL ),
  67.         mTransColor( transColor )
  68. {
  69. }   
  70.  
  71. CGameBitBuffer::~CGameBitBuffer()
  72. {
  73.     if (mhPalette)
  74.     {
  75.         DeleteObject( mhPalette );
  76.     }
  77. }
  78.  
  79. /*---------------------------------------------------------------------------*\
  80. |
  81. |       Class CGameDDrawBitBuffer
  82. |
  83. |  DESCRIPTION:
  84. |       
  85. |
  86. |
  87. \*---------------------------------------------------------------------------*/
  88. // static members
  89. LPDIRECTDRAW CGameDDrawBitBuffer::mpDDrawDriver = NULL;
  90. int CGameDDrawBitBuffer::mInstanceCount = 0;    // for allocating/freeing mpDDrawDriver
  91.  
  92. // construct a buffer from existing DIB, optionally stretching to fit new size
  93. CGameDDrawBitBuffer::CGameDDrawBitBuffer(
  94.         CGameDIB* pDIB,
  95.         int width,      // 0 (default) means use DIB's width
  96.         int height,     // 0 (default) means use DIB's height
  97.         COLORREF transColor
  98.         ) : CGameBitBuffer(pDIB, width, height, transColor),
  99.             mpSurface( NULL ),
  100.             mIsAttached( FALSE ),
  101.             mIsValid( FALSE ),
  102.             mpFileName( NULL )
  103. {
  104.     if (width == 0)
  105.         width = pDIB->GetWidth();
  106.  
  107.     if (height == 0)
  108.         height = pDIB->GetHeight();
  109.  
  110.     // we need to copy the dib's filename so we can reload later if necessary
  111.     char* pFileName = (char*) pDIB->GetNamePtr();
  112.  
  113.     if (pFileName)
  114.     {
  115.         mpFileName = new char[lstrlen(pFileName)+1];
  116.         lstrcpy( mpFileName, pFileName );
  117.     }
  118.  
  119.     InitDDraw();
  120.     CreateSurface( width, height );
  121.  
  122.     if (mIsValid)
  123.     {
  124.         SetBits( pDIB );    // copy DIB bits onto surface
  125.  
  126.         mhPalette = pDIB->CreatePalette();
  127.     }
  128.  }  
  129.  
  130. // construct an "empty" buffer with given size
  131. CGameDDrawBitBuffer::CGameDDrawBitBuffer(
  132.         int width,
  133.         int height,
  134.         HPALETTE hPal,
  135.         COLORREF transColor
  136.         ) : CGameBitBuffer(width, height, hPal, transColor),
  137.             mpSurface( NULL ),
  138.             mIsAttached( FALSE ),
  139.             mIsValid( FALSE ),
  140.             mpFileName( NULL )
  141. {
  142.     InitDDraw();
  143.     CreateSurface( width, height );
  144. }
  145.  
  146. void
  147. CGameDDrawBitBuffer::InitDDraw(
  148.     )
  149. {
  150.     HRESULT result;
  151.  
  152.     // do we need to get the Direct Draw driver?
  153.     if (mpDDrawDriver == NULL)
  154.     {
  155.         result = DirectDrawCreate( NULL, &mpDDrawDriver, NULL );
  156.     }
  157.  
  158.     ++mInstanceCount;   // keep count so we know when to release driver
  159. }
  160.  
  161. void
  162. CGameDDrawBitBuffer::CreateSurface(
  163.     int width,
  164.     int height
  165.     )
  166. {
  167.     if (mpDDrawDriver)
  168.     {
  169.         DDSURFACEDESC surfDesc;
  170.  
  171.         memset( &surfDesc, 0, sizeof( surfDesc ) );
  172.  
  173.         surfDesc.dwSize = sizeof( surfDesc );
  174.         surfDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
  175.         surfDesc.dwFlags |= DDSD_HEIGHT | DDSD_WIDTH;
  176.         surfDesc.dwHeight = height;
  177.         surfDesc.dwWidth = width;
  178.  
  179.         surfDesc.dwFlags |= DDSD_CAPS;
  180.  
  181.         surfDesc.ddckCKSrcBlt.dwColorSpaceLowValue = 1;
  182.         surfDesc.ddckCKSrcBlt.dwColorSpaceHighValue = 1;
  183.  
  184.         // ask driver for the surface
  185.         HRESULT result;
  186.         if ((result = mpDDrawDriver->CreateSurface(&surfDesc,
  187.                 &mpSurface, NULL )) == DD_OK)
  188.         {
  189.             // have to call SetColorKey
  190.             result = mpSurface->SetColorKey( DDCKEY_SRCBLT, &surfDesc.ddckCKSrcBlt );
  191.  
  192.             mIsValid = TRUE;
  193.         }
  194.     }
  195. }
  196.  
  197. void
  198. CGameDDrawBitBuffer::SetBits(
  199.     CGameDIB* pSource
  200.     )
  201. {
  202.     HRESULT     ddrawrval;
  203.     DDSURFACEDESC   dsd;
  204.     LPBYTE      lpdest;
  205.     DWORD       y;
  206.     DWORD       bytes_scanline;
  207.     LPBYTE      lpdib_bits;
  208.  
  209.     /*
  210.      * get surface description
  211.      */
  212.     mSurfD.dwSize = sizeof( mSurfD );
  213.     ddrawrval = mpSurface->GetSurfaceDesc( &mSurfD );
  214.     if( ddrawrval != DD_OK )
  215.     {
  216.         DB_LOG( DB_PROBLEM, "Could not get surface description!" );
  217.         return;
  218.     }
  219.  
  220.     if( !(mSurfD.ddpfPixelFormat.dwFlags & DDPF_RGB) )
  221.     {
  222.         DB_LOG( DB_PROBLEM, "Can only copy to RGB surfaces for now" );
  223.         return;
  224.     }
  225.  
  226.     bytes_scanline = pSource->BytesPerScanline();
  227.  
  228.     /*
  229.      * access the surface
  230.      */
  231.     dsd.dwSize = sizeof( dsd );
  232.     do {
  233.         ddrawrval = mpSurface->Lock( NULL, &dsd, DDLOCK_SURFACEMEMORYPTR, NULL );
  234.         if( ddrawrval != DD_OK && ddrawrval != DDERR_WASSTILLDRAWING )
  235.         {
  236.             DB_LOG( DB_PROBLEM, "Lock failed in creating DDBitBuffer" );
  237.             return;
  238.         }
  239.     } 
  240.     while( ddrawrval == DDERR_WASSTILLDRAWING );
  241.  
  242.     lpdest = (LPBYTE) dsd.lpSurface;
  243.     mPitch = mSurfD.lPitch;
  244.  
  245.     // NOTE: we only work with 8bpp; need different code for different bitdepths
  246.     // this code just assumes 8 bits
  247.     for( y=0;y<mSurfD.dwHeight;y++ )
  248.     {
  249.         lpdib_bits = pSource->GetPixelAddress(0,y);
  250.         memcpy( lpdest, lpdib_bits, bytes_scanline );
  251.         lpdest += (DWORD) mSurfD.lPitch;
  252.     }
  253.  
  254.     /*
  255.     * release the surface and go home...
  256.     */
  257.     mpSurface->Unlock( NULL );
  258. }   
  259.  
  260. CGameDDrawBitBuffer::~CGameDDrawBitBuffer()
  261. {
  262.     if (mpSurface && !mIsAttached)
  263.     {
  264.         mpSurface->Release(  );
  265.     }
  266.  
  267.     if (--mInstanceCount == 0)
  268.     {
  269.         if (mpDDrawDriver)
  270.         {
  271.             mpDDrawDriver->Release( );
  272.             mpDDrawDriver = NULL;
  273.         }
  274.     }
  275.  
  276.     delete mpFileName;
  277. }
  278.  
  279. // call this to re-create the surface if it was lost
  280. // this can happen if we've switched modes & switch back
  281. void
  282. CGameDDrawBitBuffer::ReCreate(
  283.     )
  284. {
  285.     int width = mSurfD.dwWidth;
  286.     int height = mSurfD.dwHeight;
  287.  
  288.     HRESULT result = mpSurface->Restore();
  289.  
  290.     if (result == DD_OK)
  291.         mIsValid = TRUE;
  292.  
  293.     if (mIsValid && mpFileName)
  294.     {
  295.         // reload the file
  296.         CGameDIB dib( mpFileName );
  297.         SetBits( &dib );    // copy DIB bits onto surface
  298.     }
  299. }
  300.  
  301.  
  302. // generic blt call to this buffer from another DDraw surface
  303. void
  304. CGameDDrawBitBuffer::Blt(
  305.     int xDest,
  306.     int yDest,
  307.     int wDest,
  308.     int hDest,
  309.     CGameBitBuffer* pSrcBuffer,
  310.     int xSrc,
  311.     int ySrc,
  312.     DWORD rop
  313.     )
  314. {
  315.     HRESULT result;
  316.     DDBLTFX dbf;
  317.     BOOL useFX = FALSE;
  318.  
  319.     // negative width or height means mirror the blt
  320.     RECT destRect = 
  321.     {
  322.         xDest,
  323.         yDest,
  324.         xDest+((wDest<0) ? -wDest : wDest),
  325.         yDest+((hDest<0) ? -hDest : hDest)
  326.     };
  327.  
  328.     RECT srcRect = 
  329.     {
  330.         xSrc,
  331.         ySrc,
  332.         xSrc+((wDest<0) ? -wDest : wDest),
  333.         ySrc+((hDest<0) ? -hDest : hDest)
  334.     };
  335.  
  336.  
  337.     if ((wDest < 0) || (hDest < 0))
  338.     {
  339.         useFX = TRUE;
  340.         memset( &dbf, 0, sizeof( dbf ) );
  341.  
  342.         dbf.dwSize = sizeof(dbf);
  343.         dbf.dwDDFX = (wDest<0) ? DDBLTFX_MIRRORLEFTRIGHT : 0;
  344.         dbf.dwDDFX |= (hDest<0) ? DDBLTFX_MIRRORUPDOWN : 0;
  345.     }
  346.  
  347.     result = mpSurface->Blt( 
  348.             &destRect,  // dest rect
  349.             ((CGameDDrawBitBuffer*)pSrcBuffer)->mpSurface,      // src surf
  350.             &srcRect,   // src rect
  351.             useFX ? DDBLT_DDFX : 0,// flags
  352.             useFX ? &dbf : NULL );  // bltfx
  353.  
  354. }   
  355.  
  356. // generic blt call -- determine type of destination buffer
  357. void
  358. CGameDDrawBitBuffer::Blt(
  359.     CGameBitBuffer* pDestBuffer,
  360.     int xDest,
  361.     int yDest,
  362.     int wDest,
  363.     int hDest,
  364.     int xSrc,
  365.     int ySrc,
  366.     DWORD rop
  367.     )
  368. {
  369.     switch (pDestBuffer->TypeID())
  370.     {
  371.         case BB_DDraw:
  372.             Blt(
  373.                 (CGameDDrawBitBuffer*)pDestBuffer,
  374.                 xDest,
  375.                 yDest,
  376.                 wDest,
  377.                 hDest,
  378.                 xSrc,
  379.                 ySrc,
  380.                 rop
  381.                 );
  382.             break;
  383.         case BB_DS:
  384.             Blt(
  385.                 (CGameDSBitBuffer*)pDestBuffer,
  386.                 xDest,
  387.                 yDest,
  388.                 wDest,
  389.                 hDest,
  390.                 xSrc,
  391.                 ySrc,
  392.                 rop
  393.                 );
  394.             break;
  395.         default:
  396.             DB_BREAK();
  397.             break;
  398.     }
  399. }
  400.  
  401. // generic transblt call -- determine type of source buffer
  402. void
  403. CGameDDrawBitBuffer::TransBlt(
  404.     CGameBitBuffer* pDestBuffer,
  405.     int xDest,
  406.     int yDest,
  407.     int wDest,
  408.     int hDest,
  409.     int xSrc,
  410.     int ySrc,
  411.     int transColor
  412.     )
  413. {
  414.     switch (pDestBuffer->TypeID())
  415.     {
  416.         case BB_DDraw:
  417.             TransBlt(
  418.                 (CGameDDrawBitBuffer*)pDestBuffer,
  419.                 xDest,
  420.                 yDest,
  421.                 wDest,
  422.                 hDest,
  423.                 xSrc,
  424.                 ySrc,
  425.                 transColor
  426.                 );
  427.             break;
  428.         case BB_DS:
  429.             TransBlt(
  430.                 (CGameDSBitBuffer*)pDestBuffer,
  431.                 xDest,
  432.                 yDest,
  433.                 wDest,
  434.                 hDest,
  435.                 xSrc,
  436.                 ySrc,
  437.                 transColor
  438.                 );
  439.             break;
  440.         default:
  441.             DB_BREAK();
  442.             break;
  443.     }
  444. }
  445.  
  446. // specific blt call for another DDraw surface
  447. void
  448. CGameDDrawBitBuffer::BltDDraw(
  449.     CGameDDrawBitBuffer* pDestBuffer,
  450.     int xDest,
  451.     int yDest,
  452.     int wDest,
  453.     int hDest,
  454.     int xSrc,
  455.     int ySrc,
  456.     DWORD rop
  457.     )
  458. {
  459.     HRESULT result;
  460.     DDBLTFX dbf;
  461.     BOOL useFX = FALSE;
  462.  
  463.     // negative width or height means mirror the blt
  464.     RECT destRect =
  465.     {
  466.         xDest,
  467.         yDest,
  468.         xDest+((wDest<0) ? -wDest : wDest),
  469.         yDest+((hDest<0) ? -hDest : hDest)
  470.     };
  471.  
  472.     RECT srcRect =
  473.     {
  474.         xSrc,
  475.         ySrc,
  476.         xSrc+((wDest<0) ? -wDest : wDest),
  477.         ySrc+((hDest<0) ? -hDest : hDest)
  478.     };
  479.  
  480.     if ((wDest < 0) || (hDest < 0))
  481.     {
  482.         useFX = TRUE;
  483.         memset( &dbf, 0, sizeof( dbf ) );
  484.  
  485.         dbf.dwSize = sizeof(dbf);
  486.         dbf.dwDDFX = (wDest<0) ? DDBLTFX_MIRRORLEFTRIGHT : 0;
  487.         dbf.dwDDFX |= (hDest<0) ? DDBLTFX_MIRRORUPDOWN : 0;
  488.     }
  489.  
  490.     // force a stop if we never succeed
  491.     int stopCount = DDRAW_RETRY;
  492.  
  493.     do
  494.     {
  495.         result = pDestBuffer->mpSurface->BltFast( 
  496.                 destRect.left,
  497.                 destRect.top,
  498.                 mpSurface,      // src surf
  499.                 &srcRect,   // src rect
  500.                 FALSE           // transparent
  501.                 );
  502.  
  503.         // surface may have been lost due to mode switch
  504.         if (result == DDERR_SURFACELOST)
  505.         {
  506.             mIsValid = FALSE;
  507.             // re-create our surface
  508.             ReCreate();
  509.         }
  510.     }
  511.     while( (result != DD_OK) && (--stopCount > 0));
  512. }   
  513.  
  514. // specific transblt call for another DDraw buffer
  515. void
  516. CGameDDrawBitBuffer::TransBltDDraw(
  517.     CGameDDrawBitBuffer* pDestBuffer,
  518.     int xDest,
  519.     int yDest,
  520.     int wDest,
  521.     int hDest,
  522.     int xSrc,
  523.     int ySrc,
  524.     int transColor
  525.     )
  526. {
  527.     HRESULT result;
  528.  
  529.     RECT destRect = 
  530.     {
  531.         xDest, yDest, xDest+wDest, yDest+hDest
  532.     };
  533.  
  534.     RECT srcRect =
  535.     {
  536.         xSrc, ySrc, xSrc+wDest, ySrc+hDest
  537.     };
  538.  
  539.     // force a stop if we never succeed
  540.     int stopCount = DDRAW_RETRY;
  541.  
  542.     do
  543.     {
  544.         result = pDestBuffer->mpSurface->BltFast( 
  545.                 destRect.left,
  546.                 destRect.top,
  547.                 mpSurface,      // src surf
  548.                 &srcRect,   // src rect
  549.                 TRUE            // transparent
  550.                 );
  551.  
  552.         // surface may have been lost due to mode switch
  553.         if (result == DDERR_SURFACELOST)
  554.         {
  555.             mIsValid = FALSE;
  556.             // re-create our surface
  557.             ReCreate();
  558.         }
  559.     }
  560.     while( (result != DD_OK) && (--stopCount > 0));
  561. }
  562.  
  563. // specific blt call for a dibsection destination buffer
  564. void
  565. CGameDDrawBitBuffer::BltDS(
  566.     CGameDSBitBuffer* pDestBuffer,
  567.     int xDest,
  568.     int yDest,
  569.     int wDest,
  570.     int hDest,
  571.     int xSrc,
  572.     int ySrc,
  573.     DWORD rop
  574.     )
  575. {
  576.     LPBYTE pSrc = GetLockedAddress( xSrc, ySrc );
  577.  
  578.     if (pSrc)
  579.     {
  580.         int scanDest = -(pDestBuffer->mpDIB->BytesPerScanline());
  581.         int scanSrc = mPitch;
  582.  
  583.         CopyDIBBits(
  584.             pDestBuffer->mpDIB->GetPixelAddress( xDest, yDest ),
  585.             pSrc,
  586.             wDest,  // width pixels
  587.             hDest,
  588.             (DWORD) scanDest,
  589.             (DWORD) scanSrc
  590.             );
  591.  
  592.     }
  593.     Unlock();
  594. }
  595.  
  596. // specific transblt call for a ds buffer
  597. void
  598. CGameDDrawBitBuffer::TransBltDS(
  599.     CGameDSBitBuffer* pDestBuffer,
  600.     int xDest,
  601.     int yDest,
  602.     int wDest,
  603.     int hDest,
  604.     int xSrc,
  605.     int ySrc,
  606.     int transColor
  607.     )
  608. {
  609.     LPBYTE pSrc = GetLockedAddress( xSrc, ySrc );
  610.  
  611.     if (pSrc)
  612.     {
  613.         int scanDest = -(pDestBuffer->mpDIB->BytesPerScanline());
  614.         int scanSrc = mPitch;
  615.  
  616.         TransCopyDIBBits(
  617.             pDestBuffer->mpDIB->GetPixelAddress( xDest, yDest ),
  618.             pSrc,
  619.             wDest,  // width pixels
  620.             hDest,
  621.             (DWORD) scanDest,
  622.             (DWORD) scanSrc,
  623.             transColor
  624.             );
  625.  
  626.     }
  627.     Unlock();
  628. }
  629.  
  630. void
  631. CGameDDrawBitBuffer::SetPalette( HPALETTE hPal )
  632. {
  633. }
  634.  
  635. LPBYTE  // return address to given pixel in locked surface
  636. CGameDDrawBitBuffer::GetLockedAddress(
  637.     int x,
  638.     int y
  639.     )
  640. {
  641.     HRESULT     ddrawrval;
  642.     DDSURFACEDESC   dsd;
  643.     /*
  644.     * access the surface
  645.     */
  646.     dsd.dwSize = sizeof( dsd );
  647.  
  648.     int stopCount = DDRAW_RETRY;
  649.  
  650.     do
  651.     {
  652.         ddrawrval = mpSurface->Lock( NULL, &dsd, DDLOCK_SURFACEMEMORYPTR, NULL );
  653.  
  654.         // surface may have been lost due to mode switch
  655.         if (ddrawrval == DDERR_SURFACELOST)
  656.         {
  657.             mIsValid = FALSE;
  658.             // re-create our surface
  659.             ReCreate();
  660.         }
  661.     }
  662.     while( (ddrawrval != DD_OK) && (--stopCount > 0) );
  663.  
  664.     if (ddrawrval == DD_OK)
  665.     {
  666.         mPitch = dsd.lPitch;
  667.  
  668.         return (LPBYTE) dsd.lpSurface + x + (y * mPitch);
  669.     }
  670.     else
  671.     {
  672.         DB_BREAK();
  673.         return NULL;
  674.     }
  675. }
  676.  
  677. void
  678. CGameDDrawBitBuffer::Unlock()
  679. {
  680.     mpSurface->Unlock( NULL );
  681. }
  682.  
  683. /*---------------------------------------------------------------------------*\
  684. |
  685. |       Class CGameDDrawScreenBuffer
  686. |
  687. |  DESCRIPTION:
  688. |       
  689. |
  690. |
  691. \*---------------------------------------------------------------------------*/
  692. // construct the screen's primary surface
  693. CGameDDrawScreenBuffer::CGameDDrawScreenBuffer(
  694.         ) : CGameDDrawBitBuffer(),
  695.         mpPalette( NULL ),
  696.         mpOldPalette( NULL )
  697. {
  698.     InitDDraw();
  699.  
  700.     // call our create surface to create the primary surface
  701.     CreateSurface( 0,0 );
  702. }   
  703.  
  704. // create an attached-buffer object from given primary surface
  705. CGameDDrawScreenBuffer::CGameDDrawScreenBuffer(
  706.     CGameDDrawScreenBuffer* pFront
  707.     ) : CGameDDrawBitBuffer(),
  708.         mpPalette( NULL ),
  709.         mpOldPalette( NULL )
  710. {
  711.     HRESULT result;
  712.     DDSCAPS caps;
  713.  
  714.     memset(&caps, 0, sizeof(caps));
  715.     caps.dwCaps = DDSCAPS_BACKBUFFER;
  716.  
  717.     result = pFront->mpSurface->GetAttachedSurface(
  718.                 &caps,
  719.                 &mpSurface);
  720.  
  721.     mSurfD.dwSize = sizeof( mSurfD );
  722.     pFront->mpSurface->GetSurfaceDesc(
  723.                 &mSurfD
  724.                 );
  725.  
  726.     mPitch = mSurfD.lPitch;
  727.  
  728.     if (mpSurface)
  729.         mIsValid = TRUE;
  730.  
  731.     // flag this as an attached surface so we won't release it
  732.     mIsAttached = TRUE;
  733.     ++mInstanceCount;   // keep count so we know when to release driver
  734. }
  735.  
  736. void
  737. CGameDDrawScreenBuffer::CreateSurface(
  738.     int width,
  739.     int height
  740.     )
  741. {
  742.     HRESULT result;
  743.  
  744.         result = mpDDrawDriver->SetCooperativeLevel( ghMainWnd,
  745.                                       DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN );
  746.     if( result != DD_OK )
  747.     {
  748.         return;
  749.     }
  750.  
  751.     // first, force display into our 640x480, 8bpp mode
  752.     result = mpDDrawDriver->SetDisplayMode(
  753.                         SCREEN_WIDTH,
  754.                         SCREEN_HEIGHT,
  755.                         8
  756.                         );
  757.     if( result != DD_OK )
  758.     {
  759.         return;
  760.     }
  761.  
  762.     memset( &mSurfD, 0, sizeof( mSurfD ) );
  763.  
  764.     mSurfD.dwSize = sizeof( mSurfD );
  765.     mSurfD.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
  766.  
  767.     mSurfD.dwFlags |= DDSD_BACKBUFFERCOUNT | DDSD_CAPS;
  768.     if( gDoubleBuffer )
  769.     {
  770.         mSurfD.dwBackBufferCount = 1;
  771.     }
  772.     else
  773.     {
  774.         mSurfD.dwBackBufferCount = 2;
  775.     }
  776.  
  777.     // ask DirectDraw for the surface
  778.     if ((result = mpDDrawDriver->CreateSurface(&mSurfD, &mpSurface,
  779.                 NULL)) == DD_OK)
  780.     {
  781.         mPitch = mSurfD.lPitch;
  782.         mIsValid = TRUE;
  783.     }
  784. }
  785.  
  786. CGameDDrawScreenBuffer::~CGameDDrawScreenBuffer()
  787. {
  788.     // free up palette
  789.     DeleteDDPalette();
  790. }   
  791.  
  792. void
  793. CGameDDrawScreenBuffer::SetMode(
  794.     int width,
  795.     int height,
  796.     int bits
  797.     )
  798. {
  799.     mpDDrawDriver->SetDisplayMode(
  800.                         width,
  801.                         height,
  802.                         bits
  803.                         );
  804. }
  805.  
  806. void
  807. CGameDDrawScreenBuffer::RestoreMode()
  808. {
  809.     mpDDrawDriver->FlipToGDISurface();
  810.     mpDDrawDriver->RestoreDisplayMode();
  811. }
  812.  
  813. void
  814. CGameDDrawScreenBuffer::ShowGDIPage()
  815. {
  816.     mpDDrawDriver->FlipToGDISurface();
  817. }
  818.  
  819. void
  820. CGameDDrawScreenBuffer::SetPalette(
  821.     LPPALETTEENTRY pPal
  822.     )
  823. {
  824.     // grab current palette if we don't already have it
  825.     if (mpOldPalette == NULL)
  826.     {
  827.         mpSurface->GetPalette( &mpOldPalette );
  828.     }
  829.  
  830.     // free up current palette
  831.     if (mpPalette)
  832.     {
  833.         DeleteDDPalette();
  834.     }
  835.  
  836.     if ((mpDDrawDriver->CreatePalette(
  837.                 DDPCAPS_8BIT,
  838.                 pPal,
  839.                 &mpPalette,
  840.                 NULL
  841.                 ) == DD_OK) && mpSurface)
  842.     {
  843.         mpSurface->SetPalette( mpPalette );
  844.     }
  845.     
  846. }
  847.  
  848. void
  849. CGameDDrawScreenBuffer::DeleteDDPalette()
  850. {
  851.     if (mpPalette)
  852.     {
  853.         // reset to old palette if we have it
  854.         if (mpOldPalette && mpSurface)
  855.         {
  856.             mpSurface->SetPalette( mpOldPalette );
  857.         }
  858.  
  859.         if (mpPalette->Release() == DD_OK)
  860.             mpPalette = NULL;
  861.     }
  862. }
  863.  
  864. int
  865. CGameDDrawScreenBuffer::GetVideoMemory()
  866. {
  867.     DDCAPS caps;
  868.  
  869.     caps.dwSize = sizeof(DDCAPS);
  870.     if ((mpDDrawDriver != NULL) && (mpDDrawDriver->GetCaps(&caps,NULL) == DD_OK))
  871.     {
  872.         return caps.dwVidMemTotal;
  873.     }
  874.  
  875.     return 0;
  876. }
  877.  
  878. /*---------------------------------------------------------------------------*\
  879. |
  880. |       Class CGameDSBitBuffer
  881. |
  882. |  DESCRIPTION:
  883. |       Use Win32's CreateDIBSection for a non-Direct Draw bitbuffer
  884. |
  885. |
  886. \*---------------------------------------------------------------------------*/
  887. // construct a buffer from existing DIB, optionally stretching to fit new size
  888. CGameDSBitBuffer::CGameDSBitBuffer(
  889.         CGameDIB* pDIB,
  890.         int width,      // 0 (default) means use DIB's width
  891.         int height,     // 0 (default) means use DIB's height
  892.         COLORREF transColor
  893.         ) : CGameBitBuffer(pDIB, width, height, transColor),
  894.             mpBitmapInfo( NULL ),
  895.             mpDIB( NULL ),
  896.             mpBits( NULL ),
  897.             mIsValid( FALSE )
  898. {
  899.     if (width == 0)
  900.         width = pDIB->GetWidth();
  901.  
  902.     if (height == 0)
  903.         height = pDIB->GetHeight();
  904.  
  905.     mhPalette = pDIB->CreatePalette();
  906.  
  907.     // create our empty DIBSection
  908.     mpDIB = new CGameDIB( width, height, mhPalette );
  909.     SetBits( pDIB );    // copy DIB bits onto surface
  910.  
  911.     // cache important ptrs for blting
  912.     mpBits = mpDIB->GetBits();
  913.     mpBitmapInfo = mpDIB->GetBitmapInfo();
  914.     mIsValid = TRUE;
  915. }   
  916.  
  917. // construct an "empty" buffer with given size
  918. CGameDSBitBuffer::CGameDSBitBuffer(
  919.         int width,
  920.         int height,
  921.         HPALETTE hPal,
  922.         COLORREF transColor
  923.         ) : CGameBitBuffer(width, height, hPal, transColor),
  924.             mpBitmapInfo( NULL ),
  925.             mpDIB( NULL ),
  926.             mpBits( NULL ),
  927.             mIsValid( FALSE )
  928. {
  929.     mpDIB = new CGameDIB( width, height, hPal );
  930.  
  931.     // cache important ptrs for blting
  932.     mpBits = mpDIB->GetBits();
  933.     mpBitmapInfo = mpDIB->GetBitmapInfo();
  934.     mIsValid = TRUE;
  935. }
  936.  
  937. void
  938. CGameDSBitBuffer::SetBits(
  939.     CGameDIB* pSource
  940.     )
  941. {
  942.     LPBYTE      lpdest;
  943.     DWORD       bytes_scanline;
  944.     LPBYTE      lpdib_bits;
  945.  
  946.     bytes_scanline = pSource->BytesPerScanline();
  947.  
  948.     for( int y=0;y<pSource->GetHeight();y++ )
  949.     {
  950.         lpdib_bits = pSource->GetPixelAddress(0,y);
  951.         lpdest = mpDIB->GetPixelAddress(0,y);
  952.         CopyMemory( lpdest, lpdib_bits, bytes_scanline );
  953.     }
  954. }   
  955.  
  956. CGameDSBitBuffer::~CGameDSBitBuffer()
  957. {
  958.     delete mpDIB;
  959. }   
  960.  
  961. // specific blt call to this buffer from another DS buffer
  962. void CGameDSBitBuffer::Blt(
  963.     int xDest,
  964.     int yDest,
  965.     int wDest,
  966.     int hDest,
  967.     CGameBitBuffer* pSrcBuffer,
  968.     int xSrc,
  969.     int ySrc,
  970.     DWORD rop
  971.     )
  972. {
  973.     int scanDest = -(mpDIB->BytesPerScanline());
  974.     int scanSrc = -(((CGameDSBitBuffer*)pSrcBuffer)->mpDIB->BytesPerScanline());
  975.  
  976.     CopyDIBBits(
  977.         mpDIB->GetPixelAddress( xDest, yDest ),
  978.         ((CGameDSBitBuffer*)pSrcBuffer)->mpDIB->GetPixelAddress( xSrc, ySrc ),
  979.         wDest,  // width pixels
  980.         hDest,
  981.         (DWORD) scanDest,
  982.         (DWORD) scanSrc
  983.         );
  984. }   
  985.  
  986. // generic dest blt call -- determine type of source buffer
  987. void
  988. CGameDSBitBuffer::Blt(
  989.     CGameBitBuffer* pDestBuffer,
  990.     int xDest,
  991.     int yDest,
  992.     int wDest,
  993.     int hDest,
  994.     int xSrc,
  995.     int ySrc,
  996.     DWORD rop
  997.     )
  998. {
  999.     switch (pDestBuffer->TypeID())
  1000.     {
  1001.         case BB_DDraw:
  1002.             Blt(
  1003.                 (CGameDDrawBitBuffer*)pDestBuffer,
  1004.                 xDest,
  1005.                 yDest,
  1006.                 wDest,
  1007.                 hDest,
  1008.                 xSrc,
  1009.                 ySrc,
  1010.                 rop
  1011.                 );
  1012.             break;
  1013.         case BB_DS:
  1014.             Blt(
  1015.                 (CGameDSBitBuffer*)pDestBuffer,
  1016.                 xDest,
  1017.                 yDest,
  1018.                 wDest,
  1019.                 hDest,
  1020.                 xSrc,
  1021.                 ySrc,
  1022.                 rop
  1023.                 );
  1024.             break;
  1025.         default:
  1026.             DB_BREAK();
  1027.             break;
  1028.     }
  1029. }
  1030.  
  1031. // generic transblt call -- determine type of dest buffer
  1032. void
  1033. CGameDSBitBuffer::TransBlt(
  1034.     CGameBitBuffer* pDestBuffer,
  1035.     int xDest,
  1036.     int yDest,
  1037.     int wDest,
  1038.     int hDest,
  1039.     int xSrc,
  1040.     int ySrc,
  1041.     int transColor
  1042.     )
  1043. {
  1044.     switch (pDestBuffer->TypeID())
  1045.     {
  1046.         case BB_DDraw:
  1047.             TransBlt(
  1048.                 (CGameDDrawBitBuffer*)pDestBuffer,
  1049.                 xDest,
  1050.                 yDest,
  1051.                 wDest,
  1052.                 hDest,
  1053.                 xSrc,
  1054.                 ySrc,
  1055.                 transColor
  1056.                 );
  1057.             break;
  1058.         case BB_DS:
  1059.             TransBlt(
  1060.                 (CGameDSBitBuffer*)pDestBuffer,
  1061.                 xDest,
  1062.                 yDest,
  1063.                 wDest,
  1064.                 hDest,
  1065.                 xSrc,
  1066.                 ySrc,
  1067.                 transColor
  1068.                 );
  1069.             break;
  1070.         default:
  1071.             DB_BREAK();
  1072.             break;
  1073.     }
  1074. }
  1075.  
  1076. // specific blt call for a DS buffer
  1077. void CGameDSBitBuffer::BltDS(
  1078.     CGameDSBitBuffer* pDestBuffer,
  1079.     int xDest,
  1080.     int yDest,
  1081.     int wDest,
  1082.     int hDest,
  1083.     int xSrc,
  1084.     int ySrc,
  1085.     DWORD rop
  1086.     )
  1087. {
  1088.     int scanDest = -(pDestBuffer->mpDIB->BytesPerScanline());
  1089.     int scanSrc = -(mpDIB->BytesPerScanline());
  1090.  
  1091.     CopyDIBBits(
  1092.         pDestBuffer->mpDIB->GetPixelAddress( xDest, yDest ),
  1093.         mpDIB->GetPixelAddress( xSrc, ySrc ),
  1094.         wDest,  // width pixels
  1095.         hDest,
  1096.         (DWORD) scanDest,
  1097.         (DWORD) scanSrc
  1098.         );
  1099. }   
  1100.  
  1101. // specific transblt call for a DDraw buffer
  1102. void
  1103. CGameDSBitBuffer::TransBltDS(
  1104.     CGameDSBitBuffer* pDestBuffer,
  1105.     int xDest,
  1106.     int yDest,
  1107.     int wDest,
  1108.     int hDest,
  1109.     int xSrc,
  1110.     int ySrc,
  1111.     int transColor
  1112.     )
  1113. {
  1114.     int scanDest = -(pDestBuffer->mpDIB->BytesPerScanline());
  1115.     int scanSrc = -(mpDIB->BytesPerScanline());
  1116.  
  1117.     TransCopyDIBBits(
  1118.         pDestBuffer->mpDIB->GetPixelAddress( xDest, yDest ),
  1119.         mpDIB->GetPixelAddress( xSrc, ySrc ),
  1120.         wDest,  // width pixels
  1121.         hDest,
  1122.         (DWORD) scanDest,
  1123.         (DWORD) scanSrc,
  1124.         transColor
  1125.         );
  1126. }
  1127.  
  1128. // specific blt call for a DDraw buffer
  1129. void CGameDSBitBuffer::BltDDraw(
  1130.     CGameDDrawBitBuffer* pDestBuffer,
  1131.     int xDest,
  1132.     int yDest,
  1133.     int wDest,
  1134.     int hDest,
  1135.     int xSrc,
  1136.     int ySrc,
  1137.     DWORD rop
  1138.     )
  1139. {
  1140.     LPBYTE lpdest;
  1141.  
  1142.     lpdest = pDestBuffer->GetLockedAddress( xDest, yDest );
  1143.  
  1144.     if (lpdest)
  1145.     {
  1146.         int scanDest = pDestBuffer->mPitch;
  1147.         int scanSrc = -(mpDIB->BytesPerScanline());
  1148.  
  1149.         CopyDIBBits(
  1150.             lpdest,
  1151.             mpDIB->GetPixelAddress( xSrc, ySrc ),
  1152.             wDest,  // width pixels
  1153.             hDest,
  1154.             (DWORD) scanDest,
  1155.             (DWORD) scanSrc
  1156.             );
  1157.  
  1158.     }
  1159.     pDestBuffer->Unlock();
  1160. }
  1161.  
  1162. // specific transblt call for a DDraw buffer
  1163. void
  1164. CGameDSBitBuffer::TransBltDDraw(
  1165.     CGameDDrawBitBuffer* pDestBuffer,
  1166.     int xDest,
  1167.     int yDest,
  1168.     int wDest,
  1169.     int hDest,
  1170.     int xSrc,
  1171.     int ySrc,
  1172.     int transColor
  1173.     )
  1174. {
  1175.     LPBYTE lpdest = pDestBuffer->GetLockedAddress( xDest, yDest );
  1176.  
  1177.     if (lpdest)
  1178.     {
  1179.         int scanDest = pDestBuffer->mPitch;
  1180.         int scanSrc = -(mpDIB->BytesPerScanline());
  1181.  
  1182.         TransCopyDIBBits(
  1183.             lpdest,
  1184.             mpDIB->GetPixelAddress( xSrc, ySrc ),
  1185.             wDest,  // width pixels
  1186.             hDest,
  1187.             (DWORD) scanDest,
  1188.             (DWORD) scanSrc,
  1189.             transColor
  1190.             );
  1191.  
  1192.     }
  1193.     pDestBuffer->Unlock();
  1194. }
  1195.  
  1196. void
  1197. CGameDSBitBuffer::SetPalette( HPALETTE hPal )
  1198. {
  1199. }
  1200.  
  1201. #if !(defined(__BORLANDC__) || defined(__WATCOMC__))
  1202. void
  1203. TransCopyDIBBits(
  1204.         LPBYTE pDest,       // destination
  1205.         LPBYTE pSource,     //         ; source pointer
  1206.         DWORD dwWidth,      //         ; width pixels
  1207.         DWORD dwHeight,     //        ; height pixels
  1208.         DWORD dwScanD,      //         ; width bytes dest
  1209.         DWORD dwScanS,      //         ; width bytes source
  1210.         BYTE bTranClr       //        ; transparent color
  1211.     )
  1212. {
  1213.     _asm
  1214.     {
  1215.         push ds
  1216.         push esi
  1217.         push edi
  1218.  
  1219.         mov ecx, dwWidth
  1220.         or ecx,ecx
  1221.         jz tcdb_nomore     ; test for silly case
  1222.  
  1223.         mov edx, dwHeight       ; EDX is line counter
  1224.         mov bl, bTranClr        ; BL has transparency color
  1225.  
  1226.         mov esi, pSource         ; DS:[ESI] point to source
  1227.  
  1228.         mov edi, pDest
  1229.  
  1230.         or  edi, edi        ; check NULL ptrs
  1231.         jz  tcdb_nomore
  1232.  
  1233.         or  esi, esi        ; check NULL ptrs
  1234.         jz  tcdb_nomore
  1235.  
  1236.         sub dwScanD,ecx         ; bias these
  1237.         sub dwScanS,ecx
  1238.  
  1239.         push ecx
  1240.  
  1241.         align 4
  1242.  
  1243. tcdb_morelines:
  1244.         pop ecx
  1245.         push ecx
  1246.  
  1247.         shr ecx,2
  1248.         jz  short tcdb_nextscan
  1249.  
  1250. // ;
  1251. // ; The idea here is to not branch very often so we unroll the loop by four
  1252. // ; and try to not branch when a whole run of pixels is either transparent
  1253. // ; or not transparent.
  1254. // ;
  1255. // ; There are two loops. One loop is for a run of pixels equal to the
  1256. // ; transparent color, the other is for runs of pixels we need to store.
  1257. // ;
  1258. // ; When we detect a "bad" pixel we jump to the same position in the
  1259. // ; other loop.
  1260. // ;
  1261. // ; Here is the loop we will stay in as long as we encounter a "transparent"
  1262. // ; pixel in the source.
  1263. // ;
  1264.  
  1265.         align 4
  1266.  
  1267. tcdb_same:
  1268.         mov eax, ds:[esi]
  1269.         cmp al, bl
  1270.         jne short tcdb_diff0
  1271.  
  1272. tcdb_same0:
  1273.         cmp ah, bl
  1274.         jne short tcdb_diff1
  1275.  
  1276. tcdb_same1:
  1277.         shr eax, 16
  1278.         cmp al, bl
  1279.         jne short tcdb_diff2
  1280.  
  1281. tcdb_same2:
  1282.         cmp ah, bl
  1283.         jne short tcdb_diff3
  1284.  
  1285. tcdb_same3:
  1286.         add edi,4
  1287.         add esi,4
  1288.         dec ecx
  1289.         jnz short tcdb_same
  1290.         jz  short tcdb_nextscan
  1291.  
  1292. // ;
  1293. // ; Here is the loop we will stay in as long as
  1294. // ; we encounter a "non transparent" pixel in the source.
  1295. // ;
  1296.  
  1297.         align 4
  1298.  
  1299. tcdb_diff:
  1300.         mov eax, ds:[esi]
  1301.         cmp al, bl
  1302.         je short tcdb_same0
  1303.  
  1304. tcdb_diff0:
  1305.         mov es:[edi],al
  1306.         cmp ah, bl
  1307.         je short tcdb_same1
  1308.  
  1309. tcdb_diff1:
  1310.         mov es:[edi+1],ah
  1311.  
  1312.         shr eax, 16
  1313.         cmp al, bl
  1314.         je short tcdb_same2
  1315.  
  1316. tcdb_diff2:
  1317.         mov es:[edi+2],al
  1318.         cmp ah, bl
  1319.         je short tcdb_same3
  1320.  
  1321. tcdb_diff3:
  1322.         mov es:[edi+3],ah
  1323.  
  1324.         add edi,4
  1325.         add esi,4
  1326.         dec ecx
  1327.         jnz short tcdb_diff
  1328.         jz  short tcdb_nextscan
  1329.  
  1330. // ;
  1331. // ; We are at the end of a scan, check for odd leftover pixels to do
  1332. // ; and go to the next scan.
  1333. // ;
  1334.  
  1335.         align 4
  1336.  
  1337. tcdb_nextscan:
  1338.         pop ecx
  1339.         push ecx
  1340.  
  1341.         and ecx,11b
  1342.         jnz short tcdb_oddstuff
  1343.         // ; move on to the start of the next line
  1344.  
  1345. tcdb_nextscan1:
  1346.         add esi, dwScanS
  1347.         add edi, dwScanD
  1348.  
  1349.         dec edx                 // ; line counter
  1350.         jnz short tcdb_morelines
  1351.         jz  short tcdb_nomore
  1352.  
  1353. // ;
  1354. // ; If the width is not a multiple of 4 we will come here to clean up
  1355. // ; the last few pixels
  1356. // ;
  1357.  
  1358. tcdb_oddstuff:
  1359.         inc ecx
  1360. tcdb_oddloop:
  1361.         dec ecx
  1362.         jz  short tcdb_nextscan1
  1363.         mov al, ds:[esi]
  1364.         inc esi
  1365.         inc edi
  1366.         cmp al, bl
  1367.         je  short tcdb_oddloop
  1368.         mov es:[edi-1],al
  1369.         jmp short tcdb_oddloop
  1370.  
  1371. tcdb_nomore:
  1372.         pop ecx
  1373.  
  1374.         pop edi
  1375.         pop esi
  1376.         pop ds
  1377.     }
  1378. }
  1379.  
  1380. void
  1381. CopyDIBBits(
  1382.         LPBYTE pDest,   //           ; dest pointer
  1383.         LPBYTE pSource, //         ; source pointer
  1384.         DWORD dwWidth,  //         ; width pixels
  1385.         DWORD dwHeight, //        ; height pixels
  1386.         DWORD dwScanD,  //         ; width bytes dest
  1387.         DWORD dwScanS   //         ; width bytes source
  1388.     )
  1389. {
  1390.     _asm
  1391.     {
  1392.         push    esi
  1393.         push    edi
  1394.  
  1395.         ; load scanline width into EBX, image height into EDX
  1396.         mov ebx, [dwWidth]
  1397.                 or      ebx, ebx
  1398.                 jz      silly_case          ; width is 0
  1399.         mov edx, [dwHeight]
  1400.                 or      edx, edx
  1401.         jz  silly_case      ; height is 0
  1402.  
  1403.         ; bias offsets
  1404.         sub [dwScanD], ebx
  1405.         sub [dwScanS], ebx
  1406.  
  1407.         ; load ESI
  1408.         mov esi, [pSource]
  1409.  
  1410.         ; load EDI and guarantee it is aligned on a DWORD boundary
  1411.         mov edi, [pDest]
  1412.  
  1413.         or  edi, edi        ; check NULL ptrs
  1414.         jz  silly_case
  1415.  
  1416.         or  esi, esi        ; check NULL ptrs
  1417.         jz  silly_case
  1418.  
  1419.     ;; NOTE: this assumes that the scanwidth will always be a multiple
  1420.     ;;  of DWORDs, so that the misalignment will be the same for all
  1421.     ;;  scanlines.  This allows us to calculate it once outside the loop
  1422.  
  1423.         mov ecx, edi
  1424.         and ecx, 11b                ; deal with non-aligned case
  1425.  
  1426.         mov eax, 100b
  1427.         sub eax, ecx            ; eax now contains aligment offset
  1428.  
  1429.         cmp eax, ebx            ; do we really have that many to do?
  1430.         jb next_scanline        ; if not, we're all set to blast
  1431.  
  1432.         mov eax, ebx            ; put actual width into offset
  1433.  
  1434.  
  1435.         ALIGN 4
  1436. next_scanline:
  1437.  
  1438.         ; adjust_alignment
  1439.         mov ecx, eax            ; eax == alignment offset
  1440.         rep movsb               ; move bytewise to make EDI aligned properly
  1441.  
  1442.         mov ecx, ebx                ; total count per scanline
  1443.         sub ecx, eax                ; residue left over: misaligned amount!
  1444.  
  1445.         ; at this point, ECX is number of BYTES to transfer, ESI and EDI point to source and dest
  1446.         push eax
  1447.  
  1448.         mov eax, ecx
  1449.         shr ecx, 2              ; div 4 to get number of DWORDS to transfer
  1450.         rep movsd               ; move by DWORDS as much as possible
  1451.  
  1452.         and eax, 11b                ; number of *bytes* to transfer (if any)
  1453.         mov ecx, eax
  1454.         rep movsb               ; move remaining bytes (may be zero)
  1455.  
  1456.         pop eax
  1457.  
  1458.         ; now adjust ESI and EDI for next scanline and jump to it!
  1459.         add     esi, [dwScanS]
  1460.         add     edi, [dwScanD]
  1461.         dec edx                 ; if more scanlines, process them
  1462.         jnz next_scanline
  1463.  
  1464. silly_case:
  1465.         pop edi
  1466.         pop esi
  1467.  
  1468.     }
  1469.  
  1470. }
  1471. #endif
  1472.