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

  1. /*===========================================================================*\
  2. |
  3. |  File:        cgsprite.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. #include <windows.h>
  31. #include "cgdebug.h"
  32. #include "cgglobl.h"
  33. #include "cgtimer.h"
  34. #include "cgscreen.h"
  35. #include "cgsprite.h"
  36. #include "cgupdate.h"
  37.  
  38. extern CGameTimer* Timer;
  39.  
  40. char seqSection[] = "Sequences";
  41. char seqKey[] = "Sequence";
  42. char spriteKey[] = "Sprite";
  43. char sprExtension[] = "spr";
  44. char bmpExtension[] = "bmp";
  45.  
  46. /*---------------------------------------------------------------------------*\
  47. |
  48. |       Class CGameSprite
  49. |
  50. |  DESCRIPTION:
  51. |       
  52. |
  53. |
  54. \*---------------------------------------------------------------------------*/
  55. CGameSprite::CGameSprite(
  56.     char* pFileName,
  57.     char* pSpriteName,
  58.     CGameBitBuffer* pBits,
  59.     BOOL needHorzMirror,
  60.     BOOL needVertMirror
  61.     ) 
  62. {
  63.     // grab this sprite's parameters from the .spr file
  64.     // and put into mInfo[0]
  65.     mInfo[SRI_NORMAL].mSrcX = (int) GetPrivateProfileInt(
  66.         pSpriteName,
  67.         "X",
  68.         0,  // default to 0
  69.         pFileName
  70.         );
  71.  
  72.     mInfo[SRI_NORMAL].mSrcY = (int) GetPrivateProfileInt(
  73.         pSpriteName,
  74.         "Y",
  75.         0,  // default to 0
  76.         pFileName
  77.         );
  78.  
  79.     mInfo[SRI_NORMAL].mpBits = pBits;
  80.     mInfo[SRI_NORMAL].mNewBits = FALSE;
  81.  
  82.     mInfo[SRI_NORMAL].mWidth = (int) GetPrivateProfileInt(
  83.         pSpriteName,
  84.         "Width",
  85.         0,  // default to 0
  86.         pFileName
  87.         );
  88.  
  89.     mInfo[SRI_NORMAL].mHeight = (int) GetPrivateProfileInt(
  90.         pSpriteName,
  91.         "Height",
  92.         0,  // default to 0
  93.         pFileName
  94.         );
  95.  
  96.     // create mirrored images if necessary
  97.     if (needHorzMirror)
  98.     {
  99.         if (gUse_DDraw)
  100.         {
  101.             mInfo[SRI_HORZMIRROR].mpBits = new CGameDDrawBitBuffer(
  102.                             mInfo[SRI_NORMAL].mWidth,
  103.                             mInfo[SRI_NORMAL].mHeight,
  104.                             pBits->GetHPalette(),
  105.                             pBits->GetTransColor()
  106.                             );
  107.         }
  108.         else
  109.         {
  110.             mInfo[SRI_HORZMIRROR].mpBits = new CGameDSBitBuffer(
  111.                             mInfo[SRI_NORMAL].mWidth,
  112.                             mInfo[SRI_NORMAL].mHeight,
  113.                             pBits->GetHPalette(),
  114.                             pBits->GetTransColor()
  115.                             );
  116.         }
  117.  
  118.         mInfo[SRI_HORZMIRROR].mNewBits = TRUE;
  119.         mInfo[SRI_HORZMIRROR].mWidth = mInfo[SRI_NORMAL].mWidth;
  120.         mInfo[SRI_HORZMIRROR].mHeight = mInfo[SRI_NORMAL].mHeight;
  121.         mInfo[SRI_HORZMIRROR].mSrcX = 0;
  122.         mInfo[SRI_HORZMIRROR].mSrcY = 0;
  123.  
  124.         mInfo[SRI_HORZMIRROR].mpBits->Blt(
  125.                 mInfo[SRI_HORZMIRROR].mWidth-1,
  126.                 0,
  127.                 -mInfo[SRI_HORZMIRROR].mWidth,  // create mirror image
  128.                 mInfo[SRI_HORZMIRROR].mHeight,
  129.                 pBits,
  130.                 mInfo[SRI_NORMAL].mSrcX,
  131.                 mInfo[SRI_NORMAL].mSrcY,
  132.                 SRCCOPY
  133.                 );
  134.     }
  135.     else
  136.     {
  137.         // just make a copy of normal image
  138.         mInfo[SRI_HORZMIRROR] = mInfo[SRI_NORMAL];
  139.  
  140.         // negate the width to force a mirrored blt
  141.         mInfo[SRI_HORZMIRROR].mWidth = -mInfo[SRI_NORMAL].mWidth;
  142.  
  143.         // make sure we don't delete it
  144.         mInfo[SRI_HORZMIRROR].mNewBits = FALSE;
  145.     }
  146.  
  147.     if (needVertMirror)
  148.     {
  149.         if (gUse_DDraw)
  150.         {
  151.             mInfo[SRI_VERTMIRROR].mpBits = new CGameDDrawBitBuffer(
  152.                             mInfo[SRI_NORMAL].mWidth,
  153.                             mInfo[SRI_NORMAL].mHeight,
  154.                             pBits->GetHPalette(),
  155.                             pBits->GetTransColor()
  156.                             );
  157.  
  158.         }
  159.         else
  160.         {
  161.             mInfo[SRI_VERTMIRROR].mpBits = new CGameDSBitBuffer(
  162.                             mInfo[SRI_NORMAL].mWidth,
  163.                             mInfo[SRI_NORMAL].mHeight,
  164.                             pBits->GetHPalette(),
  165.                             pBits->GetTransColor()
  166.                             );
  167.         }
  168.  
  169.         mInfo[SRI_VERTMIRROR].mNewBits = TRUE;
  170.         mInfo[SRI_VERTMIRROR].mWidth = mInfo[SRI_NORMAL].mWidth;
  171.         mInfo[SRI_VERTMIRROR].mHeight = mInfo[SRI_NORMAL].mHeight;
  172.         mInfo[SRI_VERTMIRROR].mSrcX = 0;
  173.         mInfo[SRI_VERTMIRROR].mSrcY = 0;
  174.  
  175.         mInfo[SRI_VERTMIRROR].mpBits->Blt(
  176.                 0,
  177.                 mInfo[SRI_VERTMIRROR].mHeight-1,
  178.                 mInfo[SRI_VERTMIRROR].mWidth,
  179.                 -mInfo[SRI_VERTMIRROR].mHeight, // create mirror image
  180.                 pBits,
  181.                 mInfo[SRI_NORMAL].mSrcX,
  182.                 mInfo[SRI_NORMAL].mSrcY,
  183.                 SRCCOPY
  184.                 );
  185.     }
  186.     else
  187.     {
  188.         // just make a copy of normal image
  189.         mInfo[SRI_VERTMIRROR] = mInfo[SRI_NORMAL];
  190.  
  191.         // negate the height to force a mirrored blt
  192.         mInfo[SRI_VERTMIRROR].mHeight = -mInfo[SRI_NORMAL].mHeight;
  193.  
  194.         // make sure we don't delete it
  195.         mInfo[SRI_VERTMIRROR].mNewBits = FALSE;
  196.     }
  197.  
  198.     // do we need both horizontal and vertical?
  199.     if (needHorzMirror && needVertMirror)
  200.     {
  201.         if (gUse_DDraw)
  202.         {
  203.             mInfo[SRI_BOTHMIRROR].mpBits = new CGameDDrawBitBuffer(
  204.                             mInfo[SRI_NORMAL].mWidth,
  205.                             mInfo[SRI_NORMAL].mHeight,
  206.                             pBits->GetHPalette(),
  207.                             pBits->GetTransColor()
  208.                             );
  209.  
  210.         }
  211.         else
  212.         {
  213.             mInfo[SRI_BOTHMIRROR].mpBits = new CGameDSBitBuffer(
  214.                             mInfo[SRI_NORMAL].mWidth,
  215.                             mInfo[SRI_NORMAL].mHeight,
  216.                             pBits->GetHPalette(),
  217.                             pBits->GetTransColor()
  218.                             );
  219.         }
  220.  
  221.         mInfo[SRI_BOTHMIRROR].mNewBits = TRUE;
  222.         mInfo[SRI_BOTHMIRROR].mWidth = mInfo[SRI_NORMAL].mWidth;
  223.         mInfo[SRI_BOTHMIRROR].mHeight = mInfo[SRI_NORMAL].mHeight;
  224.         mInfo[SRI_BOTHMIRROR].mSrcX = 0;
  225.         mInfo[SRI_BOTHMIRROR].mSrcY = 0;
  226.  
  227.  
  228.         mInfo[SRI_BOTHMIRROR].mpBits->Blt(
  229.                 mInfo[SRI_BOTHMIRROR].mWidth-1,
  230.                 mInfo[SRI_NORMAL].mHeight-1,
  231.                 -mInfo[SRI_BOTHMIRROR].mWidth,  // create mirror image
  232.                 -mInfo[SRI_BOTHMIRROR].mHeight,
  233.                 pBits,
  234.                 mInfo[SRI_NORMAL].mSrcX,
  235.                 mInfo[SRI_NORMAL].mSrcY,
  236.                 SRCCOPY
  237.                 );
  238.     }
  239.     else
  240.     {
  241.         // just make a copy of normal image
  242.         mInfo[SRI_BOTHMIRROR] = mInfo[SRI_NORMAL];
  243.  
  244.         // negate the width and height to force a mirrored blt
  245.         mInfo[SRI_BOTHMIRROR].mWidth = -mInfo[SRI_NORMAL].mHeight;
  246.         mInfo[SRI_BOTHMIRROR].mHeight = -mInfo[SRI_NORMAL].mHeight;
  247.  
  248.         // make sure we don't delete it
  249.         mInfo[SRI_BOTHMIRROR].mNewBits = FALSE;
  250.     }
  251. }
  252.  
  253. CGameSprite::~CGameSprite()
  254. {
  255.     for (int i = SRI_INFOCOUNT; i>0; i--)
  256.     {
  257.         if (mInfo[i-1].mNewBits)
  258.         {
  259.             delete mInfo[i-1].mpBits;
  260.         }
  261.     }
  262. }
  263.  
  264. /*---------------------------------------------------------------------------*\
  265. |
  266. |       class CGameSpriteBuffer
  267. |
  268. |  DESCRIPTION:
  269. |       
  270. |
  271. |
  272. \*---------------------------------------------------------------------------*/
  273. CGameSpriteBuffer::CGameSpriteBuffer(
  274.     char* pFileName
  275.     ) : mpFileName( NULL ),
  276.         mpBitBuffer( NULL ),
  277.         mRefCount( 0 )
  278. {
  279.     mpFileName = new char[lstrlen( pFileName ) +1];
  280.     lstrcpy( mpFileName, pFileName );
  281.  
  282.     // open the set's DIB file
  283.     char bmpName[256];
  284.     SprToBmp( pFileName, bmpName, 256 );
  285.  
  286.     CGameDIB dib( bmpName );
  287.  
  288.     if (gUse_DDraw)
  289.     {
  290.         mpBitBuffer = new CGameDDrawBitBuffer( &dib );
  291.         if (!mpBitBuffer->IsValid())
  292.         {
  293.             // we didn't get video memory, so delete that buffer
  294.             delete mpBitBuffer;
  295.             // & create a system memory one
  296.             mpBitBuffer = new CGameDSBitBuffer( &dib );
  297.         }
  298.     }
  299.     else
  300.     {
  301.         mpBitBuffer = new CGameDSBitBuffer( &dib );
  302.     }
  303.     ++mRefCount;
  304. }
  305.  
  306. CGameSpriteBuffer::~CGameSpriteBuffer()
  307. {
  308.     delete mpBitBuffer;
  309.     delete[] mpFileName;
  310. }
  311.  
  312. void
  313. CGameSpriteBuffer::SprToBmp(
  314.     char* pSprName,
  315.     char* pOutBuffer,
  316.     int size
  317.     )
  318. {
  319.     lstrcpyn( pOutBuffer, pSprName, size );
  320.  
  321.     int dotPos = strcspn( pOutBuffer, "." );
  322.  
  323.     if (dotPos < lstrlen( pOutBuffer ))
  324.     {
  325.         pOutBuffer[dotPos] = '\0';
  326.         lstrcat( pOutBuffer, "." );
  327.         lstrcat( pOutBuffer, bmpExtension );
  328.     }
  329. }   
  330.  
  331. /*---------------------------------------------------------------------------*\
  332. |
  333. |       Class CGameSpriteSequence
  334. |
  335. |  DESCRIPTION:
  336. |       
  337. |
  338. |
  339. \*---------------------------------------------------------------------------*/
  340.  
  341. LinkedList* CGameSpriteSequence::mpBufferList = NULL;
  342.  
  343. CGameSpriteSequence::CGameSpriteSequence(
  344.     char* pFileName,
  345.     char* pSequenceName,
  346.     int rate,
  347.     BOOL mirrorHorz,        // keep mirror images of sprites?
  348.     BOOL mirrorVert
  349.     ) : mpSpriteArray( NULL ),
  350.         mNumSprites( 0 ),
  351.         mCurSprite( 0 ),
  352.         mpMyBuffer( NULL ),
  353.         mLastTime( -1 )
  354. {
  355.     char    sprFile[MAX_PATH];
  356.  
  357.     lstrcpy(sprFile, gDataPath);
  358.     lstrcat(sprFile, "\\");
  359.     lstrcat(sprFile, pFileName);
  360.  
  361.     // get a ptr to this sequence's source bitmap
  362.     mpMyBuffer = LoadSpriteBits( pFileName );
  363.  
  364.     // get the number of sprites
  365.     mNumSprites = GetPrivateProfileInt(
  366.             "Sequences",
  367.             pSequenceName,
  368.             0,
  369.             sprFile
  370.             );
  371.  
  372.     mpSpriteArray = new CGameSprite*[mNumSprites];
  373.  
  374.     // get the sprite list
  375.     char spriteBuf[256];
  376.     char defSprite[] = "";  // no default sprite names
  377.  
  378.     GetPrivateProfileString(
  379.         pSequenceName,
  380.         NULL,       // grab all the key names
  381.         defSprite,
  382.         spriteBuf,
  383.         sizeof( spriteBuf ),
  384.         sprFile
  385.         );
  386.  
  387.     int i=0;
  388.     for (char *pSprite = spriteBuf; *pSprite && (i<mNumSprites); pSprite++)
  389.     {
  390.         mpSpriteArray[i] = new CGameSprite( sprFile, pSprite, mpMyBuffer->mpBitBuffer, mirrorHorz, mirrorVert );
  391.         pSprite += lstrlen( pSprite );  // move beyond terminator
  392.         ++i;
  393.     }
  394.  
  395.     mPeriod = 1000 / rate;
  396. }
  397.  
  398. CGameSpriteSequence::~CGameSpriteSequence()
  399. {
  400.     // !!! assumes that mpSpriteArray is valid if mNumSprites>0
  401.     for (; mNumSprites>0; mNumSprites--)
  402.     {
  403.         delete mpSpriteArray[mNumSprites-1];
  404.     }
  405.  
  406.     // remove our file from list
  407.     UnloadSpriteBits();
  408.  
  409.     delete[] mpSpriteArray;
  410. }
  411.  
  412. BOOL    // return TRUE if the are more sprites in sequence
  413. CGameSpriteSequence::Frame()
  414. {
  415.     return TRUE;
  416. }
  417.  
  418. int // return mCurSprite .... is Zero if no more (i.e., wrapped)
  419. CGameSpriteSequence::NextSprite(
  420.     int time,   // current game time
  421.     BOOL wrap   // wrap around (i.e. loop) at end of sequence
  422.     )
  423. {
  424.     if (mLastTime == -1)
  425.         mLastTime = time-mPeriod;
  426.  
  427.     int elapsed = time - mLastTime;
  428.     if (elapsed >= mPeriod)
  429.     {
  430.         mLastTime = time;
  431.         mCurSprite += elapsed / mPeriod;
  432.         if (mCurSprite >= mNumSprites)
  433.         {
  434.             mCurSprite = wrap ? (mCurSprite % mNumSprites) : 0;
  435.         }
  436.     }
  437.     return mCurSprite;
  438. }
  439.  
  440. void
  441. CGameSpriteSequence::Render(
  442.     CGameScreen* pScreen,
  443.     int x,
  444.     int y,
  445.     BOOL revX,  // reverse the image?
  446.     BOOL revY,  // reverse the image?
  447.     LPRECT pDirty   // invalid rectangle in screen coordinates
  448.     )
  449. {
  450.     int which = (int) revX + ((int) revY * 2);
  451.     RECT update;
  452.     int clipX = max(x, pDirty->left);
  453.     int clipY = max(y, pDirty->top);
  454.  
  455.     int offsetX = max(pDirty->left - x, 0);
  456.     int offsetY = max(pDirty->top - y, 0);
  457.  
  458.     update.left = mpSpriteArray[mCurSprite]->mInfo[which].mSrcX +
  459.             offsetX;
  460.  
  461.     update.top = mpSpriteArray[mCurSprite]->mInfo[which].mSrcY +
  462.             offsetY;
  463.  
  464.     // we're using right & bottom for width & height
  465.     update.right = min( mpSpriteArray[mCurSprite]->mInfo[which].mWidth -
  466.             offsetX, pDirty->right-clipX+1 );
  467.  
  468.     update.bottom = min( mpSpriteArray[mCurSprite]->mInfo[which].mHeight -
  469.             offsetY, pDirty->bottom-clipY+1 );
  470.  
  471.     if ((update.right > 0) && (update.bottom > 0))
  472.         pScreen->TransRender(
  473.                 clipX,
  474.                 clipY,
  475.                 update.right,
  476.                 update.bottom,
  477.                 mpSpriteArray[mCurSprite]->mInfo[which].mpBits,
  478.                 update.left,
  479.                 update.top
  480.                 );
  481. }
  482.  
  483. // return a ptr to the sprite buffer corresponding to this .spr filename
  484. // keeps track of whether file is already loaded & maintains reference count
  485. CGameSpriteBuffer*
  486. CGameSpriteSequence::LoadSpriteBits( char* pFileName )
  487. {
  488.     CGameSpriteBuffer* pResult = NULL;
  489.     CGameSpriteBuffer* pCurBuffer = NULL;
  490.  
  491.     // initialize buffer list if necessary
  492.     if (!mpBufferList)
  493.     {
  494.         mpBufferList = new LinkedList;
  495.     }
  496.     else
  497.     {
  498.         pCurBuffer = (CGameSpriteBuffer*) mpBufferList->GetFirst();
  499.  
  500.         while (pCurBuffer && !pResult)
  501.         {
  502.             if (lstrcmpi( pFileName, pCurBuffer->mpFileName ) == 0 )
  503.             {
  504.                 pResult = pCurBuffer;
  505.                 pCurBuffer->mRefCount++;
  506.             }
  507.             else
  508.             {
  509.                 pCurBuffer = (CGameSpriteBuffer*) mpBufferList->GetNext();
  510.             }
  511.         }
  512.     }
  513.  
  514.     // if we didn't find it, we need to load it
  515.     if (!pResult)
  516.     {
  517.         pResult = new CGameSpriteBuffer(pFileName);     // increments ref count
  518.  
  519.         mpBufferList->Append( pResult );
  520.     }
  521.  
  522.     return pResult;
  523. }
  524.  
  525.  
  526. // decrement the ref count for the given file & remove it if 0
  527. void
  528. CGameSpriteSequence::UnloadSpriteBits()
  529. {
  530.     if (--mpMyBuffer->mRefCount == 0)
  531.     {
  532.         mpBufferList->Remove( mpMyBuffer );
  533.         delete mpMyBuffer;
  534.  
  535.         // !!! should we delete the list if empty?
  536.     }
  537. }
  538.