windows-nt/Source/XPSP1/NT/windows/feime/cht/cblocks/sprite.cpp
2020-09-26 16:20:57 +08:00

322 lines
7.8 KiB
C++

/*************************************************
* sprite.cpp *
* *
* Copyright (C) 1995-1999 Microsoft Inc. *
* *
*************************************************/
// sprite.cpp : implementation file
//
#include "stdafx.h"
#include "dib.h"
#include "spriteno.h"
#include "sprite.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CSprite
IMPLEMENT_SERIAL(CSprite, CDIB, 0 /* schema number*/ )
CSprite::CSprite()
{
m_x = 0;
m_y = 0;
m_z = 50;
m_bTransIndex = 0;
m_pNotifyObj = NULL;
}
CSprite::~CSprite()
{
}
// Set the initial state of the sprite from its DIB image
void CSprite::Initialize()
{
// Get the address of the top, left pixel
BYTE* p = (BYTE*)GetPixelAddress(0, 0);
ASSERT(p);
if ( p == NULL )
{
m_bTransIndex = 0;
return;
}
// get the pixel value and save it
m_bTransIndex = *p;
}
/////////////////////////////////////////////////////////////////////////////
// CSprite serialization
void CSprite::Serialize(CArchive& ar)
{
CDIB::Serialize(ar);
if (ar.IsStoring()) {
ar << (DWORD) m_x;
ar << (DWORD) m_y;
ar << (DWORD) m_z;
} else {
DWORD dw;
ar >> dw; m_x = (int) dw;
ar >> dw; m_y = (int) dw;
ar >> dw; m_z = (int) dw;
// now generate the other parameters from the DIB
Initialize();
}
}
/////////////////////////////////////////////////////////////////////////////
// CSprite commands
// Render a sprite to a DIB
void CSprite::Render(CDIB* pDIB, CRect* pClipRect)
{
ASSERT(pDIB);
// Get the sprite rectangle
CRect rcDraw;
GetRect(&rcDraw);
// If a clip rectangle was supplied, see if the sprite
// is visible in the rectangle
if (pClipRect) {
if (!rcDraw.IntersectRect(pClipRect, &rcDraw)) {
return; // not visible
}
}
// Copy the image of the sprite
CopyBits(pDIB, // dest DIB
rcDraw.left, // dest x
rcDraw.top, // dest y
rcDraw.right - rcDraw.left, // width
rcDraw.bottom - rcDraw.top, // height
rcDraw.left - m_x, // source x
rcDraw.top - m_y, // source y
PALETTEINDEX(m_bTransIndex)); // trans color index
}
void PrintRGB(CDIB* pDib,int n)
{
RGBQUAD *prgb = pDib->GetClrTabAddress();
TRACE("%d>(%d,%d,%d)\n",n,prgb[n].rgbBlue, prgb[n].rgbGreen, prgb[n].rgbRed);
}
void Copy(CDIB* pdibSrc,CDIB* pdibDest,
int xd, int yd,
int w, int h,
int xs, int ys,
COLORREF clrTrans)
{
ASSERT(pdibDest);
// test for strange cases
if (w == 0 || h == 0) return;
// get pointers to the start points in the source
// and destination DIBs. Note that this will be the bottom left
// corner of the DIB as the scan lines are reversed in memory
BYTE* pSrc = (BYTE*)(pdibSrc->GetPixelAddress(xs, ys + h - 1));
ASSERT(pSrc);
BYTE* pDest = (BYTE*)pdibDest->GetPixelAddress(xd, yd + h - 1);
ASSERT(pDest);
// get the scan line widths of each DIB
int iScanS = pdibSrc->StorageWidth();
int iScanD = pdibDest->StorageWidth();
RGBQUAD *prgbSrc = pdibSrc->GetClrTabAddress();
RGBQUAD *prgbDest = pdibDest->GetClrTabAddress();
{
// copy lines with transparency
// We only accept a PALETTEINDEX description
// for the color definition
BYTE bTransClr = LOBYTE(LOWORD(clrTrans));
int iSinc = iScanS - w; // source inc value
int iDinc = iScanD - w; // dest inc value
int iCount;
BYTE pixel;
while (h--) {
iCount = w; // no of pixels to scan
while (iCount--) {
pixel = *pSrc++;
// only copy pixel if not transparent
if (pixel != bTransClr) {
{
*pDest++ = 1;
}
} else {
pDest++;
}
}
// move on to the next line
pSrc += iSinc;
pDest += iDinc;
}
}
}
void CSprite::Coverage(CDIB* pDIB)
{
ASSERT(pDIB);
// Get the sprite rectangle
CRect rcDraw;
GetRect(&rcDraw);
// Copy the image of the sprite
Copy(this,pDIB, // dest DIB
0, // dest x
0, // dest y
DibWidth(), // width
DibHeight(), // height
0, // source x
0, // source y
PALETTEINDEX(m_bTransIndex)); // trans color index
}
// Load a sprite image from a disk file
BOOL CSprite::Load(CBitmap* pBmp)
{
if (!CDIB::Load(pBmp)) {
return FALSE;
}
Initialize();
return TRUE;
}
BOOL CSprite::Load(char* pszFileName)
{
if (!CDIB::Load(pszFileName)) {
return FALSE;
}
Initialize();
/*
{
BYTE* pBits = NULL;
HBITMAP hBmp;
CDC* pDC = GetDC();
hBmp = CreateDIBSection(pDC->GetSafeHdc(),
pBmpInfo,
DIB_PAL_COLORS,
(VOID **) &pBits,
NULL,
0);
ReleaseDC(pDC);
Create(GetWidth
}
*/
return TRUE;
}
// Load a sprite image from a disk file
BOOL CSprite::Load(CFile *fp)
{
if (!CDIB::Load(fp)) {
return FALSE;
}
Initialize();
return TRUE;
}
// Map colors to palette
BOOL CSprite::MapColorsToPalette(CPalette *pPal)
{
BOOL bResult = CDIB::MapColorsToPalette(pPal);
// get the transparency info again
// Note: local call only don't any derived class
CSprite::Initialize();
return bResult;
}
// get the bounding rectangle
void CSprite::GetRect(CRect* pRect)
{
ASSERT(pRect);
pRect->left = m_x;
pRect->top = m_y;
pRect->right = m_x + GetWidth();
pRect->bottom = m_y + GetHeight();
}
// Test for a hit in a non-transparent area
BOOL CSprite::HitTest(CPoint point)
{
// Test if the point is inside the sprite rectangle
if ((point.x > m_x)
&& (point.x < m_x + GetWidth())
&& (point.y > m_y)
&& (point.y < m_y + GetHeight())) {
// See if this point is transparent by testing to
// see if the pixel value is the same as the top
// left corner value. Note that top left of the
// image is bottom left in the DIB.
BYTE* p = (BYTE*)GetPixelAddress(point.x - m_x, point.y - m_y);
if (( p != NULL ) && (*p != m_bTransIndex) ) {
return TRUE; // hit
}
}
return FALSE;
}
void CSprite::Disappear()
{
CRect rcOld;
GetRect(&rcOld);
if (m_pNotifyObj)
{
m_pNotifyObj->Change(this,
CSpriteNotifyObj::IMAGE,
&rcOld,
NULL);
}
}
// set a new x,y position
void CSprite::SetPosition(int x, int y)
{
// Save the current position
CRect rcOld;
GetRect(&rcOld);
// move to new position
m_x = x;
m_y = y;
CRect rcNew;
GetRect(&rcNew);
// notify that we have moved from our old position to
// our new position
if (m_pNotifyObj) {
m_pNotifyObj->Change(this,
CSpriteNotifyObj::POSITION,
&rcOld,
&rcNew);
}
}
// Set a new Z order
void CSprite::SetZ(int z)
{
if (m_z != z) {
m_z = z;
// See if we have to notify anyone
if (m_pNotifyObj) {
CRect rc;
GetRect(&rc);
m_pNotifyObj->Change(this,
CSpriteNotifyObj::ZORDER,
&rc);
}
}
}