home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
NEXT Generation 27
/
NEXT27.iso
/
pc
/
demos
/
emperor
/
dx3.exe
/
SDK
/
SAMPLES
/
IKLOWNS
/
CGSPRITE.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1996-08-28
|
15KB
|
538 lines
/*===========================================================================*\
|
| File: cgsprite.cpp
|
| Description:
|
|-----------------------------------------------------------------------------
|
| Copyright (C) 1995-1996 Microsoft Corporation. All Rights Reserved.
|
| Written by Moss Bay Engineering, Inc. under contract to Microsoft Corporation
|
\*===========================================================================*/
/**************************************************************************
(C) Copyright 1995-1996 Microsoft Corp. All rights reserved.
You have a royalty-free right to use, modify, reproduce and
distribute the Sample Files (and/or any modified version) in
any way you find useful, provided that you agree that
Microsoft has no warranty obligations or liability for any
Sample Application Files which are modified.
we do not recomend you base your game on IKlowns, start with one of
the other simpler sample apps in the GDK
**************************************************************************/
#include <windows.h>
#include "cgdebug.h"
#include "cgglobl.h"
#include "cgtimer.h"
#include "cgscreen.h"
#include "cgsprite.h"
#include "cgupdate.h"
extern CGameTimer* Timer;
char seqSection[] = "Sequences";
char seqKey[] = "Sequence";
char spriteKey[] = "Sprite";
char sprExtension[] = "spr";
char bmpExtension[] = "bmp";
/*---------------------------------------------------------------------------*\
|
| Class CGameSprite
|
| DESCRIPTION:
|
|
|
\*---------------------------------------------------------------------------*/
CGameSprite::CGameSprite(
char* pFileName,
char* pSpriteName,
CGameBitBuffer* pBits,
BOOL needHorzMirror,
BOOL needVertMirror
)
{
// grab this sprite's parameters from the .spr file
// and put into mInfo[0]
mInfo[SRI_NORMAL].mSrcX = (int) GetPrivateProfileInt(
pSpriteName,
"X",
0, // default to 0
pFileName
);
mInfo[SRI_NORMAL].mSrcY = (int) GetPrivateProfileInt(
pSpriteName,
"Y",
0, // default to 0
pFileName
);
mInfo[SRI_NORMAL].mpBits = pBits;
mInfo[SRI_NORMAL].mNewBits = FALSE;
mInfo[SRI_NORMAL].mWidth = (int) GetPrivateProfileInt(
pSpriteName,
"Width",
0, // default to 0
pFileName
);
mInfo[SRI_NORMAL].mHeight = (int) GetPrivateProfileInt(
pSpriteName,
"Height",
0, // default to 0
pFileName
);
// create mirrored images if necessary
if (needHorzMirror)
{
if (gUse_DDraw)
{
mInfo[SRI_HORZMIRROR].mpBits = new CGameDDrawBitBuffer(
mInfo[SRI_NORMAL].mWidth,
mInfo[SRI_NORMAL].mHeight,
pBits->GetHPalette(),
pBits->GetTransColor()
);
}
else
{
mInfo[SRI_HORZMIRROR].mpBits = new CGameDSBitBuffer(
mInfo[SRI_NORMAL].mWidth,
mInfo[SRI_NORMAL].mHeight,
pBits->GetHPalette(),
pBits->GetTransColor()
);
}
mInfo[SRI_HORZMIRROR].mNewBits = TRUE;
mInfo[SRI_HORZMIRROR].mWidth = mInfo[SRI_NORMAL].mWidth;
mInfo[SRI_HORZMIRROR].mHeight = mInfo[SRI_NORMAL].mHeight;
mInfo[SRI_HORZMIRROR].mSrcX = 0;
mInfo[SRI_HORZMIRROR].mSrcY = 0;
mInfo[SRI_HORZMIRROR].mpBits->Blt(
mInfo[SRI_HORZMIRROR].mWidth-1,
0,
-mInfo[SRI_HORZMIRROR].mWidth, // create mirror image
mInfo[SRI_HORZMIRROR].mHeight,
pBits,
mInfo[SRI_NORMAL].mSrcX,
mInfo[SRI_NORMAL].mSrcY,
SRCCOPY
);
}
else
{
// just make a copy of normal image
mInfo[SRI_HORZMIRROR] = mInfo[SRI_NORMAL];
// negate the width to force a mirrored blt
mInfo[SRI_HORZMIRROR].mWidth = -mInfo[SRI_NORMAL].mWidth;
// make sure we don't delete it
mInfo[SRI_HORZMIRROR].mNewBits = FALSE;
}
if (needVertMirror)
{
if (gUse_DDraw)
{
mInfo[SRI_VERTMIRROR].mpBits = new CGameDDrawBitBuffer(
mInfo[SRI_NORMAL].mWidth,
mInfo[SRI_NORMAL].mHeight,
pBits->GetHPalette(),
pBits->GetTransColor()
);
}
else
{
mInfo[SRI_VERTMIRROR].mpBits = new CGameDSBitBuffer(
mInfo[SRI_NORMAL].mWidth,
mInfo[SRI_NORMAL].mHeight,
pBits->GetHPalette(),
pBits->GetTransColor()
);
}
mInfo[SRI_VERTMIRROR].mNewBits = TRUE;
mInfo[SRI_VERTMIRROR].mWidth = mInfo[SRI_NORMAL].mWidth;
mInfo[SRI_VERTMIRROR].mHeight = mInfo[SRI_NORMAL].mHeight;
mInfo[SRI_VERTMIRROR].mSrcX = 0;
mInfo[SRI_VERTMIRROR].mSrcY = 0;
mInfo[SRI_VERTMIRROR].mpBits->Blt(
0,
mInfo[SRI_VERTMIRROR].mHeight-1,
mInfo[SRI_VERTMIRROR].mWidth,
-mInfo[SRI_VERTMIRROR].mHeight, // create mirror image
pBits,
mInfo[SRI_NORMAL].mSrcX,
mInfo[SRI_NORMAL].mSrcY,
SRCCOPY
);
}
else
{
// just make a copy of normal image
mInfo[SRI_VERTMIRROR] = mInfo[SRI_NORMAL];
// negate the height to force a mirrored blt
mInfo[SRI_VERTMIRROR].mHeight = -mInfo[SRI_NORMAL].mHeight;
// make sure we don't delete it
mInfo[SRI_VERTMIRROR].mNewBits = FALSE;
}
// do we need both horizontal and vertical?
if (needHorzMirror && needVertMirror)
{
if (gUse_DDraw)
{
mInfo[SRI_BOTHMIRROR].mpBits = new CGameDDrawBitBuffer(
mInfo[SRI_NORMAL].mWidth,
mInfo[SRI_NORMAL].mHeight,
pBits->GetHPalette(),
pBits->GetTransColor()
);
}
else
{
mInfo[SRI_BOTHMIRROR].mpBits = new CGameDSBitBuffer(
mInfo[SRI_NORMAL].mWidth,
mInfo[SRI_NORMAL].mHeight,
pBits->GetHPalette(),
pBits->GetTransColor()
);
}
mInfo[SRI_BOTHMIRROR].mNewBits = TRUE;
mInfo[SRI_BOTHMIRROR].mWidth = mInfo[SRI_NORMAL].mWidth;
mInfo[SRI_BOTHMIRROR].mHeight = mInfo[SRI_NORMAL].mHeight;
mInfo[SRI_BOTHMIRROR].mSrcX = 0;
mInfo[SRI_BOTHMIRROR].mSrcY = 0;
mInfo[SRI_BOTHMIRROR].mpBits->Blt(
mInfo[SRI_BOTHMIRROR].mWidth-1,
mInfo[SRI_NORMAL].mHeight-1,
-mInfo[SRI_BOTHMIRROR].mWidth, // create mirror image
-mInfo[SRI_BOTHMIRROR].mHeight,
pBits,
mInfo[SRI_NORMAL].mSrcX,
mInfo[SRI_NORMAL].mSrcY,
SRCCOPY
);
}
else
{
// just make a copy of normal image
mInfo[SRI_BOTHMIRROR] = mInfo[SRI_NORMAL];
// negate the width and height to force a mirrored blt
mInfo[SRI_BOTHMIRROR].mWidth = -mInfo[SRI_NORMAL].mHeight;
mInfo[SRI_BOTHMIRROR].mHeight = -mInfo[SRI_NORMAL].mHeight;
// make sure we don't delete it
mInfo[SRI_BOTHMIRROR].mNewBits = FALSE;
}
}
CGameSprite::~CGameSprite()
{
for (int i = SRI_INFOCOUNT; i>0; i--)
{
if (mInfo[i-1].mNewBits)
{
delete mInfo[i-1].mpBits;
}
}
}
/*---------------------------------------------------------------------------*\
|
| class CGameSpriteBuffer
|
| DESCRIPTION:
|
|
|
\*---------------------------------------------------------------------------*/
CGameSpriteBuffer::CGameSpriteBuffer(
char* pFileName
) : mpFileName( NULL ),
mpBitBuffer( NULL ),
mRefCount( 0 )
{
mpFileName = new char[lstrlen( pFileName ) +1];
lstrcpy( mpFileName, pFileName );
// open the set's DIB file
char bmpName[256];
SprToBmp( pFileName, bmpName, 256 );
CGameDIB dib( bmpName );
if (gUse_DDraw)
{
mpBitBuffer = new CGameDDrawBitBuffer( &dib );
if (!mpBitBuffer->IsValid())
{
// we didn't get video memory, so delete that buffer
delete mpBitBuffer;
// & create a system memory one
mpBitBuffer = new CGameDSBitBuffer( &dib );
}
}
else
{
mpBitBuffer = new CGameDSBitBuffer( &dib );
}
++mRefCount;
}
CGameSpriteBuffer::~CGameSpriteBuffer()
{
delete mpBitBuffer;
delete[] mpFileName;
}
void
CGameSpriteBuffer::SprToBmp(
char* pSprName,
char* pOutBuffer,
int size
)
{
lstrcpyn( pOutBuffer, pSprName, size );
int dotPos = strcspn( pOutBuffer, "." );
if (dotPos < lstrlen( pOutBuffer ))
{
pOutBuffer[dotPos] = '\0';
lstrcat( pOutBuffer, "." );
lstrcat( pOutBuffer, bmpExtension );
}
}
/*---------------------------------------------------------------------------*\
|
| Class CGameSpriteSequence
|
| DESCRIPTION:
|
|
|
\*---------------------------------------------------------------------------*/
LinkedList* CGameSpriteSequence::mpBufferList = NULL;
CGameSpriteSequence::CGameSpriteSequence(
char* pFileName,
char* pSequenceName,
int rate,
BOOL mirrorHorz, // keep mirror images of sprites?
BOOL mirrorVert
) : mpSpriteArray( NULL ),
mNumSprites( 0 ),
mCurSprite( 0 ),
mpMyBuffer( NULL ),
mLastTime( -1 )
{
char sprFile[MAX_PATH];
lstrcpy(sprFile, gDataPath);
lstrcat(sprFile, "\\");
lstrcat(sprFile, pFileName);
// get a ptr to this sequence's source bitmap
mpMyBuffer = LoadSpriteBits( pFileName );
// get the number of sprites
mNumSprites = GetPrivateProfileInt(
"Sequences",
pSequenceName,
0,
sprFile
);
mpSpriteArray = new CGameSprite*[mNumSprites];
// get the sprite list
char spriteBuf[256];
char defSprite[] = ""; // no default sprite names
GetPrivateProfileString(
pSequenceName,
NULL, // grab all the key names
defSprite,
spriteBuf,
sizeof( spriteBuf ),
sprFile
);
int i=0;
for (char *pSprite = spriteBuf; *pSprite && (i<mNumSprites); pSprite++)
{
mpSpriteArray[i] = new CGameSprite( sprFile, pSprite, mpMyBuffer->mpBitBuffer, mirrorHorz, mirrorVert );
pSprite += lstrlen( pSprite ); // move beyond terminator
++i;
}
mPeriod = 1000 / rate;
}
CGameSpriteSequence::~CGameSpriteSequence()
{
// !!! assumes that mpSpriteArray is valid if mNumSprites>0
for (; mNumSprites>0; mNumSprites--)
{
delete mpSpriteArray[mNumSprites-1];
}
// remove our file from list
UnloadSpriteBits();
delete[] mpSpriteArray;
}
BOOL // return TRUE if the are more sprites in sequence
CGameSpriteSequence::Frame()
{
return TRUE;
}
int // return mCurSprite .... is Zero if no more (i.e., wrapped)
CGameSpriteSequence::NextSprite(
int time, // current game time
BOOL wrap // wrap around (i.e. loop) at end of sequence
)
{
if (mLastTime == -1)
mLastTime = time-mPeriod;
int elapsed = time - mLastTime;
if (elapsed >= mPeriod)
{
mLastTime = time;
mCurSprite += elapsed / mPeriod;
if (mCurSprite >= mNumSprites)
{
mCurSprite = wrap ? (mCurSprite % mNumSprites) : 0;
}
}
return mCurSprite;
}
void
CGameSpriteSequence::Render(
CGameScreen* pScreen,
int x,
int y,
BOOL revX, // reverse the image?
BOOL revY, // reverse the image?
LPRECT pDirty // invalid rectangle in screen coordinates
)
{
int which = (int) revX + ((int) revY * 2);
RECT update;
int clipX = max(x, pDirty->left);
int clipY = max(y, pDirty->top);
int offsetX = max(pDirty->left - x, 0);
int offsetY = max(pDirty->top - y, 0);
update.left = mpSpriteArray[mCurSprite]->mInfo[which].mSrcX +
offsetX;
update.top = mpSpriteArray[mCurSprite]->mInfo[which].mSrcY +
offsetY;
// we're using right & bottom for width & height
update.right = min( mpSpriteArray[mCurSprite]->mInfo[which].mWidth -
offsetX, pDirty->right-clipX+1 );
update.bottom = min( mpSpriteArray[mCurSprite]->mInfo[which].mHeight -
offsetY, pDirty->bottom-clipY+1 );
if ((update.right > 0) && (update.bottom > 0))
pScreen->TransRender(
clipX,
clipY,
update.right,
update.bottom,
mpSpriteArray[mCurSprite]->mInfo[which].mpBits,
update.left,
update.top
);
}
// return a ptr to the sprite buffer corresponding to this .spr filename
// keeps track of whether file is already loaded & maintains reference count
CGameSpriteBuffer*
CGameSpriteSequence::LoadSpriteBits( char* pFileName )
{
CGameSpriteBuffer* pResult = NULL;
CGameSpriteBuffer* pCurBuffer = NULL;
// initialize buffer list if necessary
if (!mpBufferList)
{
mpBufferList = new LinkedList;
}
else
{
pCurBuffer = (CGameSpriteBuffer*) mpBufferList->GetFirst();
while (pCurBuffer && !pResult)
{
if (lstrcmpi( pFileName, pCurBuffer->mpFileName ) == 0 )
{
pResult = pCurBuffer;
pCurBuffer->mRefCount++;
}
else
{
pCurBuffer = (CGameSpriteBuffer*) mpBufferList->GetNext();
}
}
}
// if we didn't find it, we need to load it
if (!pResult)
{
pResult = new CGameSpriteBuffer(pFileName); // increments ref count
mpBufferList->Append( pResult );
}
return pResult;
}
// decrement the ref count for the given file & remove it if 0
void
CGameSpriteSequence::UnloadSpriteBits()
{
if (--mpMyBuffer->mRefCount == 0)
{
mpBufferList->Remove( mpMyBuffer );
delete mpMyBuffer;
// !!! should we delete the list if empty?
}
}