home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
NEXT Generation 27
/
NEXT27.iso
/
pc
/
demos
/
emperor
/
dx3.exe
/
SDK
/
SAMPLES
/
IKLOWNS
/
CGBITBUF.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1996-08-28
|
35KB
|
1,472 lines
/*===========================================================================*\
|
| File: cgbitbuf.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
**************************************************************************/
//#ifndef __WATCOMC__
#define WIN32_LEAN_AND_MEAN
//#endif
#include <windows.h>
#include "cgdebug.h"
#include "cgdib.h"
#include "cgbitbuf.h"
#include "cgimage.h"
#include "cgglobl.h"
/*---------------------------------------------------------------------------*\
|
| Class CGameBitBuffer
|
| DESCRIPTION:
|
|
|
\*---------------------------------------------------------------------------*/
CGameBitBuffer::CGameBitBuffer(
CGameDIB* pDIB,
int width,
int height,
COLORREF transColor
) : mhPalette( NULL ),
mTransColor( transColor )
{
}
CGameBitBuffer::CGameBitBuffer(
int width,
int height,
HPALETTE hPal,
COLORREF transColor
) : mhPalette( NULL ),
mTransColor( transColor )
{
}
CGameBitBuffer::~CGameBitBuffer()
{
if (mhPalette)
{
DeleteObject( mhPalette );
}
}
/*---------------------------------------------------------------------------*\
|
| Class CGameDDrawBitBuffer
|
| DESCRIPTION:
|
|
|
\*---------------------------------------------------------------------------*/
// static members
LPDIRECTDRAW CGameDDrawBitBuffer::mpDDrawDriver = NULL;
int CGameDDrawBitBuffer::mInstanceCount = 0; // for allocating/freeing mpDDrawDriver
// construct a buffer from existing DIB, optionally stretching to fit new size
CGameDDrawBitBuffer::CGameDDrawBitBuffer(
CGameDIB* pDIB,
int width, // 0 (default) means use DIB's width
int height, // 0 (default) means use DIB's height
COLORREF transColor
) : CGameBitBuffer(pDIB, width, height, transColor),
mpSurface( NULL ),
mIsAttached( FALSE ),
mIsValid( FALSE ),
mpFileName( NULL )
{
if (width == 0)
width = pDIB->GetWidth();
if (height == 0)
height = pDIB->GetHeight();
// we need to copy the dib's filename so we can reload later if necessary
char* pFileName = (char*) pDIB->GetNamePtr();
if (pFileName)
{
mpFileName = new char[lstrlen(pFileName)+1];
lstrcpy( mpFileName, pFileName );
}
InitDDraw();
CreateSurface( width, height );
if (mIsValid)
{
SetBits( pDIB ); // copy DIB bits onto surface
mhPalette = pDIB->CreatePalette();
}
}
// construct an "empty" buffer with given size
CGameDDrawBitBuffer::CGameDDrawBitBuffer(
int width,
int height,
HPALETTE hPal,
COLORREF transColor
) : CGameBitBuffer(width, height, hPal, transColor),
mpSurface( NULL ),
mIsAttached( FALSE ),
mIsValid( FALSE ),
mpFileName( NULL )
{
InitDDraw();
CreateSurface( width, height );
}
void
CGameDDrawBitBuffer::InitDDraw(
)
{
HRESULT result;
// do we need to get the Direct Draw driver?
if (mpDDrawDriver == NULL)
{
result = DirectDrawCreate( NULL, &mpDDrawDriver, NULL );
}
++mInstanceCount; // keep count so we know when to release driver
}
void
CGameDDrawBitBuffer::CreateSurface(
int width,
int height
)
{
if (mpDDrawDriver)
{
DDSURFACEDESC surfDesc;
memset( &surfDesc, 0, sizeof( surfDesc ) );
surfDesc.dwSize = sizeof( surfDesc );
surfDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
surfDesc.dwFlags |= DDSD_HEIGHT | DDSD_WIDTH;
surfDesc.dwHeight = height;
surfDesc.dwWidth = width;
surfDesc.dwFlags |= DDSD_CAPS;
surfDesc.ddckCKSrcBlt.dwColorSpaceLowValue = 1;
surfDesc.ddckCKSrcBlt.dwColorSpaceHighValue = 1;
// ask driver for the surface
HRESULT result;
if ((result = mpDDrawDriver->CreateSurface(&surfDesc,
&mpSurface, NULL )) == DD_OK)
{
// have to call SetColorKey
result = mpSurface->SetColorKey( DDCKEY_SRCBLT, &surfDesc.ddckCKSrcBlt );
mIsValid = TRUE;
}
}
}
void
CGameDDrawBitBuffer::SetBits(
CGameDIB* pSource
)
{
HRESULT ddrawrval;
DDSURFACEDESC dsd;
LPBYTE lpdest;
DWORD y;
DWORD bytes_scanline;
LPBYTE lpdib_bits;
/*
* get surface description
*/
mSurfD.dwSize = sizeof( mSurfD );
ddrawrval = mpSurface->GetSurfaceDesc( &mSurfD );
if( ddrawrval != DD_OK )
{
DB_LOG( DB_PROBLEM, "Could not get surface description!" );
return;
}
if( !(mSurfD.ddpfPixelFormat.dwFlags & DDPF_RGB) )
{
DB_LOG( DB_PROBLEM, "Can only copy to RGB surfaces for now" );
return;
}
bytes_scanline = pSource->BytesPerScanline();
/*
* access the surface
*/
dsd.dwSize = sizeof( dsd );
do {
ddrawrval = mpSurface->Lock( NULL, &dsd, DDLOCK_SURFACEMEMORYPTR, NULL );
if( ddrawrval != DD_OK && ddrawrval != DDERR_WASSTILLDRAWING )
{
DB_LOG( DB_PROBLEM, "Lock failed in creating DDBitBuffer" );
return;
}
}
while( ddrawrval == DDERR_WASSTILLDRAWING );
lpdest = (LPBYTE) dsd.lpSurface;
mPitch = mSurfD.lPitch;
// NOTE: we only work with 8bpp; need different code for different bitdepths
// this code just assumes 8 bits
for( y=0;y<mSurfD.dwHeight;y++ )
{
lpdib_bits = pSource->GetPixelAddress(0,y);
memcpy( lpdest, lpdib_bits, bytes_scanline );
lpdest += (DWORD) mSurfD.lPitch;
}
/*
* release the surface and go home...
*/
mpSurface->Unlock( NULL );
}
CGameDDrawBitBuffer::~CGameDDrawBitBuffer()
{
if (mpSurface && !mIsAttached)
{
mpSurface->Release( );
}
if (--mInstanceCount == 0)
{
if (mpDDrawDriver)
{
mpDDrawDriver->Release( );
mpDDrawDriver = NULL;
}
}
delete mpFileName;
}
// call this to re-create the surface if it was lost
// this can happen if we've switched modes & switch back
void
CGameDDrawBitBuffer::ReCreate(
)
{
int width = mSurfD.dwWidth;
int height = mSurfD.dwHeight;
HRESULT result = mpSurface->Restore();
if (result == DD_OK)
mIsValid = TRUE;
if (mIsValid && mpFileName)
{
// reload the file
CGameDIB dib( mpFileName );
SetBits( &dib ); // copy DIB bits onto surface
}
}
// generic blt call to this buffer from another DDraw surface
void
CGameDDrawBitBuffer::Blt(
int xDest,
int yDest,
int wDest,
int hDest,
CGameBitBuffer* pSrcBuffer,
int xSrc,
int ySrc,
DWORD rop
)
{
HRESULT result;
DDBLTFX dbf;
BOOL useFX = FALSE;
// negative width or height means mirror the blt
RECT destRect =
{
xDest,
yDest,
xDest+((wDest<0) ? -wDest : wDest),
yDest+((hDest<0) ? -hDest : hDest)
};
RECT srcRect =
{
xSrc,
ySrc,
xSrc+((wDest<0) ? -wDest : wDest),
ySrc+((hDest<0) ? -hDest : hDest)
};
if ((wDest < 0) || (hDest < 0))
{
useFX = TRUE;
memset( &dbf, 0, sizeof( dbf ) );
dbf.dwSize = sizeof(dbf);
dbf.dwDDFX = (wDest<0) ? DDBLTFX_MIRRORLEFTRIGHT : 0;
dbf.dwDDFX |= (hDest<0) ? DDBLTFX_MIRRORUPDOWN : 0;
}
result = mpSurface->Blt(
&destRect, // dest rect
((CGameDDrawBitBuffer*)pSrcBuffer)->mpSurface, // src surf
&srcRect, // src rect
useFX ? DDBLT_DDFX : 0,// flags
useFX ? &dbf : NULL ); // bltfx
}
// generic blt call -- determine type of destination buffer
void
CGameDDrawBitBuffer::Blt(
CGameBitBuffer* pDestBuffer,
int xDest,
int yDest,
int wDest,
int hDest,
int xSrc,
int ySrc,
DWORD rop
)
{
switch (pDestBuffer->TypeID())
{
case BB_DDraw:
Blt(
(CGameDDrawBitBuffer*)pDestBuffer,
xDest,
yDest,
wDest,
hDest,
xSrc,
ySrc,
rop
);
break;
case BB_DS:
Blt(
(CGameDSBitBuffer*)pDestBuffer,
xDest,
yDest,
wDest,
hDest,
xSrc,
ySrc,
rop
);
break;
default:
DB_BREAK();
break;
}
}
// generic transblt call -- determine type of source buffer
void
CGameDDrawBitBuffer::TransBlt(
CGameBitBuffer* pDestBuffer,
int xDest,
int yDest,
int wDest,
int hDest,
int xSrc,
int ySrc,
int transColor
)
{
switch (pDestBuffer->TypeID())
{
case BB_DDraw:
TransBlt(
(CGameDDrawBitBuffer*)pDestBuffer,
xDest,
yDest,
wDest,
hDest,
xSrc,
ySrc,
transColor
);
break;
case BB_DS:
TransBlt(
(CGameDSBitBuffer*)pDestBuffer,
xDest,
yDest,
wDest,
hDest,
xSrc,
ySrc,
transColor
);
break;
default:
DB_BREAK();
break;
}
}
// specific blt call for another DDraw surface
void
CGameDDrawBitBuffer::BltDDraw(
CGameDDrawBitBuffer* pDestBuffer,
int xDest,
int yDest,
int wDest,
int hDest,
int xSrc,
int ySrc,
DWORD rop
)
{
HRESULT result;
DDBLTFX dbf;
BOOL useFX = FALSE;
// negative width or height means mirror the blt
RECT destRect =
{
xDest,
yDest,
xDest+((wDest<0) ? -wDest : wDest),
yDest+((hDest<0) ? -hDest : hDest)
};
RECT srcRect =
{
xSrc,
ySrc,
xSrc+((wDest<0) ? -wDest : wDest),
ySrc+((hDest<0) ? -hDest : hDest)
};
if ((wDest < 0) || (hDest < 0))
{
useFX = TRUE;
memset( &dbf, 0, sizeof( dbf ) );
dbf.dwSize = sizeof(dbf);
dbf.dwDDFX = (wDest<0) ? DDBLTFX_MIRRORLEFTRIGHT : 0;
dbf.dwDDFX |= (hDest<0) ? DDBLTFX_MIRRORUPDOWN : 0;
}
// force a stop if we never succeed
int stopCount = DDRAW_RETRY;
do
{
result = pDestBuffer->mpSurface->BltFast(
destRect.left,
destRect.top,
mpSurface, // src surf
&srcRect, // src rect
FALSE // transparent
);
// surface may have been lost due to mode switch
if (result == DDERR_SURFACELOST)
{
mIsValid = FALSE;
// re-create our surface
ReCreate();
}
}
while( (result != DD_OK) && (--stopCount > 0));
}
// specific transblt call for another DDraw buffer
void
CGameDDrawBitBuffer::TransBltDDraw(
CGameDDrawBitBuffer* pDestBuffer,
int xDest,
int yDest,
int wDest,
int hDest,
int xSrc,
int ySrc,
int transColor
)
{
HRESULT result;
RECT destRect =
{
xDest, yDest, xDest+wDest, yDest+hDest
};
RECT srcRect =
{
xSrc, ySrc, xSrc+wDest, ySrc+hDest
};
// force a stop if we never succeed
int stopCount = DDRAW_RETRY;
do
{
result = pDestBuffer->mpSurface->BltFast(
destRect.left,
destRect.top,
mpSurface, // src surf
&srcRect, // src rect
TRUE // transparent
);
// surface may have been lost due to mode switch
if (result == DDERR_SURFACELOST)
{
mIsValid = FALSE;
// re-create our surface
ReCreate();
}
}
while( (result != DD_OK) && (--stopCount > 0));
}
// specific blt call for a dibsection destination buffer
void
CGameDDrawBitBuffer::BltDS(
CGameDSBitBuffer* pDestBuffer,
int xDest,
int yDest,
int wDest,
int hDest,
int xSrc,
int ySrc,
DWORD rop
)
{
LPBYTE pSrc = GetLockedAddress( xSrc, ySrc );
if (pSrc)
{
int scanDest = -(pDestBuffer->mpDIB->BytesPerScanline());
int scanSrc = mPitch;
CopyDIBBits(
pDestBuffer->mpDIB->GetPixelAddress( xDest, yDest ),
pSrc,
wDest, // width pixels
hDest,
(DWORD) scanDest,
(DWORD) scanSrc
);
}
Unlock();
}
// specific transblt call for a ds buffer
void
CGameDDrawBitBuffer::TransBltDS(
CGameDSBitBuffer* pDestBuffer,
int xDest,
int yDest,
int wDest,
int hDest,
int xSrc,
int ySrc,
int transColor
)
{
LPBYTE pSrc = GetLockedAddress( xSrc, ySrc );
if (pSrc)
{
int scanDest = -(pDestBuffer->mpDIB->BytesPerScanline());
int scanSrc = mPitch;
TransCopyDIBBits(
pDestBuffer->mpDIB->GetPixelAddress( xDest, yDest ),
pSrc,
wDest, // width pixels
hDest,
(DWORD) scanDest,
(DWORD) scanSrc,
transColor
);
}
Unlock();
}
void
CGameDDrawBitBuffer::SetPalette( HPALETTE hPal )
{
}
LPBYTE // return address to given pixel in locked surface
CGameDDrawBitBuffer::GetLockedAddress(
int x,
int y
)
{
HRESULT ddrawrval;
DDSURFACEDESC dsd;
/*
* access the surface
*/
dsd.dwSize = sizeof( dsd );
int stopCount = DDRAW_RETRY;
do
{
ddrawrval = mpSurface->Lock( NULL, &dsd, DDLOCK_SURFACEMEMORYPTR, NULL );
// surface may have been lost due to mode switch
if (ddrawrval == DDERR_SURFACELOST)
{
mIsValid = FALSE;
// re-create our surface
ReCreate();
}
}
while( (ddrawrval != DD_OK) && (--stopCount > 0) );
if (ddrawrval == DD_OK)
{
mPitch = dsd.lPitch;
return (LPBYTE) dsd.lpSurface + x + (y * mPitch);
}
else
{
DB_BREAK();
return NULL;
}
}
void
CGameDDrawBitBuffer::Unlock()
{
mpSurface->Unlock( NULL );
}
/*---------------------------------------------------------------------------*\
|
| Class CGameDDrawScreenBuffer
|
| DESCRIPTION:
|
|
|
\*---------------------------------------------------------------------------*/
// construct the screen's primary surface
CGameDDrawScreenBuffer::CGameDDrawScreenBuffer(
) : CGameDDrawBitBuffer(),
mpPalette( NULL ),
mpOldPalette( NULL )
{
InitDDraw();
// call our create surface to create the primary surface
CreateSurface( 0,0 );
}
// create an attached-buffer object from given primary surface
CGameDDrawScreenBuffer::CGameDDrawScreenBuffer(
CGameDDrawScreenBuffer* pFront
) : CGameDDrawBitBuffer(),
mpPalette( NULL ),
mpOldPalette( NULL )
{
HRESULT result;
DDSCAPS caps;
memset(&caps, 0, sizeof(caps));
caps.dwCaps = DDSCAPS_BACKBUFFER;
result = pFront->mpSurface->GetAttachedSurface(
&caps,
&mpSurface);
mSurfD.dwSize = sizeof( mSurfD );
pFront->mpSurface->GetSurfaceDesc(
&mSurfD
);
mPitch = mSurfD.lPitch;
if (mpSurface)
mIsValid = TRUE;
// flag this as an attached surface so we won't release it
mIsAttached = TRUE;
++mInstanceCount; // keep count so we know when to release driver
}
void
CGameDDrawScreenBuffer::CreateSurface(
int width,
int height
)
{
HRESULT result;
result = mpDDrawDriver->SetCooperativeLevel( ghMainWnd,
DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN );
if( result != DD_OK )
{
return;
}
// first, force display into our 640x480, 8bpp mode
result = mpDDrawDriver->SetDisplayMode(
SCREEN_WIDTH,
SCREEN_HEIGHT,
8
);
if( result != DD_OK )
{
return;
}
memset( &mSurfD, 0, sizeof( mSurfD ) );
mSurfD.dwSize = sizeof( mSurfD );
mSurfD.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
mSurfD.dwFlags |= DDSD_BACKBUFFERCOUNT | DDSD_CAPS;
if( gDoubleBuffer )
{
mSurfD.dwBackBufferCount = 1;
}
else
{
mSurfD.dwBackBufferCount = 2;
}
// ask DirectDraw for the surface
if ((result = mpDDrawDriver->CreateSurface(&mSurfD, &mpSurface,
NULL)) == DD_OK)
{
mPitch = mSurfD.lPitch;
mIsValid = TRUE;
}
}
CGameDDrawScreenBuffer::~CGameDDrawScreenBuffer()
{
// free up palette
DeleteDDPalette();
}
void
CGameDDrawScreenBuffer::SetMode(
int width,
int height,
int bits
)
{
mpDDrawDriver->SetDisplayMode(
width,
height,
bits
);
}
void
CGameDDrawScreenBuffer::RestoreMode()
{
mpDDrawDriver->FlipToGDISurface();
mpDDrawDriver->RestoreDisplayMode();
}
void
CGameDDrawScreenBuffer::ShowGDIPage()
{
mpDDrawDriver->FlipToGDISurface();
}
void
CGameDDrawScreenBuffer::SetPalette(
LPPALETTEENTRY pPal
)
{
// grab current palette if we don't already have it
if (mpOldPalette == NULL)
{
mpSurface->GetPalette( &mpOldPalette );
}
// free up current palette
if (mpPalette)
{
DeleteDDPalette();
}
if ((mpDDrawDriver->CreatePalette(
DDPCAPS_8BIT,
pPal,
&mpPalette,
NULL
) == DD_OK) && mpSurface)
{
mpSurface->SetPalette( mpPalette );
}
}
void
CGameDDrawScreenBuffer::DeleteDDPalette()
{
if (mpPalette)
{
// reset to old palette if we have it
if (mpOldPalette && mpSurface)
{
mpSurface->SetPalette( mpOldPalette );
}
if (mpPalette->Release() == DD_OK)
mpPalette = NULL;
}
}
int
CGameDDrawScreenBuffer::GetVideoMemory()
{
DDCAPS caps;
caps.dwSize = sizeof(DDCAPS);
if ((mpDDrawDriver != NULL) && (mpDDrawDriver->GetCaps(&caps,NULL) == DD_OK))
{
return caps.dwVidMemTotal;
}
return 0;
}
/*---------------------------------------------------------------------------*\
|
| Class CGameDSBitBuffer
|
| DESCRIPTION:
| Use Win32's CreateDIBSection for a non-Direct Draw bitbuffer
|
|
\*---------------------------------------------------------------------------*/
// construct a buffer from existing DIB, optionally stretching to fit new size
CGameDSBitBuffer::CGameDSBitBuffer(
CGameDIB* pDIB,
int width, // 0 (default) means use DIB's width
int height, // 0 (default) means use DIB's height
COLORREF transColor
) : CGameBitBuffer(pDIB, width, height, transColor),
mpBitmapInfo( NULL ),
mpDIB( NULL ),
mpBits( NULL ),
mIsValid( FALSE )
{
if (width == 0)
width = pDIB->GetWidth();
if (height == 0)
height = pDIB->GetHeight();
mhPalette = pDIB->CreatePalette();
// create our empty DIBSection
mpDIB = new CGameDIB( width, height, mhPalette );
SetBits( pDIB ); // copy DIB bits onto surface
// cache important ptrs for blting
mpBits = mpDIB->GetBits();
mpBitmapInfo = mpDIB->GetBitmapInfo();
mIsValid = TRUE;
}
// construct an "empty" buffer with given size
CGameDSBitBuffer::CGameDSBitBuffer(
int width,
int height,
HPALETTE hPal,
COLORREF transColor
) : CGameBitBuffer(width, height, hPal, transColor),
mpBitmapInfo( NULL ),
mpDIB( NULL ),
mpBits( NULL ),
mIsValid( FALSE )
{
mpDIB = new CGameDIB( width, height, hPal );
// cache important ptrs for blting
mpBits = mpDIB->GetBits();
mpBitmapInfo = mpDIB->GetBitmapInfo();
mIsValid = TRUE;
}
void
CGameDSBitBuffer::SetBits(
CGameDIB* pSource
)
{
LPBYTE lpdest;
DWORD bytes_scanline;
LPBYTE lpdib_bits;
bytes_scanline = pSource->BytesPerScanline();
for( int y=0;y<pSource->GetHeight();y++ )
{
lpdib_bits = pSource->GetPixelAddress(0,y);
lpdest = mpDIB->GetPixelAddress(0,y);
CopyMemory( lpdest, lpdib_bits, bytes_scanline );
}
}
CGameDSBitBuffer::~CGameDSBitBuffer()
{
delete mpDIB;
}
// specific blt call to this buffer from another DS buffer
void CGameDSBitBuffer::Blt(
int xDest,
int yDest,
int wDest,
int hDest,
CGameBitBuffer* pSrcBuffer,
int xSrc,
int ySrc,
DWORD rop
)
{
int scanDest = -(mpDIB->BytesPerScanline());
int scanSrc = -(((CGameDSBitBuffer*)pSrcBuffer)->mpDIB->BytesPerScanline());
CopyDIBBits(
mpDIB->GetPixelAddress( xDest, yDest ),
((CGameDSBitBuffer*)pSrcBuffer)->mpDIB->GetPixelAddress( xSrc, ySrc ),
wDest, // width pixels
hDest,
(DWORD) scanDest,
(DWORD) scanSrc
);
}
// generic dest blt call -- determine type of source buffer
void
CGameDSBitBuffer::Blt(
CGameBitBuffer* pDestBuffer,
int xDest,
int yDest,
int wDest,
int hDest,
int xSrc,
int ySrc,
DWORD rop
)
{
switch (pDestBuffer->TypeID())
{
case BB_DDraw:
Blt(
(CGameDDrawBitBuffer*)pDestBuffer,
xDest,
yDest,
wDest,
hDest,
xSrc,
ySrc,
rop
);
break;
case BB_DS:
Blt(
(CGameDSBitBuffer*)pDestBuffer,
xDest,
yDest,
wDest,
hDest,
xSrc,
ySrc,
rop
);
break;
default:
DB_BREAK();
break;
}
}
// generic transblt call -- determine type of dest buffer
void
CGameDSBitBuffer::TransBlt(
CGameBitBuffer* pDestBuffer,
int xDest,
int yDest,
int wDest,
int hDest,
int xSrc,
int ySrc,
int transColor
)
{
switch (pDestBuffer->TypeID())
{
case BB_DDraw:
TransBlt(
(CGameDDrawBitBuffer*)pDestBuffer,
xDest,
yDest,
wDest,
hDest,
xSrc,
ySrc,
transColor
);
break;
case BB_DS:
TransBlt(
(CGameDSBitBuffer*)pDestBuffer,
xDest,
yDest,
wDest,
hDest,
xSrc,
ySrc,
transColor
);
break;
default:
DB_BREAK();
break;
}
}
// specific blt call for a DS buffer
void CGameDSBitBuffer::BltDS(
CGameDSBitBuffer* pDestBuffer,
int xDest,
int yDest,
int wDest,
int hDest,
int xSrc,
int ySrc,
DWORD rop
)
{
int scanDest = -(pDestBuffer->mpDIB->BytesPerScanline());
int scanSrc = -(mpDIB->BytesPerScanline());
CopyDIBBits(
pDestBuffer->mpDIB->GetPixelAddress( xDest, yDest ),
mpDIB->GetPixelAddress( xSrc, ySrc ),
wDest, // width pixels
hDest,
(DWORD) scanDest,
(DWORD) scanSrc
);
}
// specific transblt call for a DDraw buffer
void
CGameDSBitBuffer::TransBltDS(
CGameDSBitBuffer* pDestBuffer,
int xDest,
int yDest,
int wDest,
int hDest,
int xSrc,
int ySrc,
int transColor
)
{
int scanDest = -(pDestBuffer->mpDIB->BytesPerScanline());
int scanSrc = -(mpDIB->BytesPerScanline());
TransCopyDIBBits(
pDestBuffer->mpDIB->GetPixelAddress( xDest, yDest ),
mpDIB->GetPixelAddress( xSrc, ySrc ),
wDest, // width pixels
hDest,
(DWORD) scanDest,
(DWORD) scanSrc,
transColor
);
}
// specific blt call for a DDraw buffer
void CGameDSBitBuffer::BltDDraw(
CGameDDrawBitBuffer* pDestBuffer,
int xDest,
int yDest,
int wDest,
int hDest,
int xSrc,
int ySrc,
DWORD rop
)
{
LPBYTE lpdest;
lpdest = pDestBuffer->GetLockedAddress( xDest, yDest );
if (lpdest)
{
int scanDest = pDestBuffer->mPitch;
int scanSrc = -(mpDIB->BytesPerScanline());
CopyDIBBits(
lpdest,
mpDIB->GetPixelAddress( xSrc, ySrc ),
wDest, // width pixels
hDest,
(DWORD) scanDest,
(DWORD) scanSrc
);
}
pDestBuffer->Unlock();
}
// specific transblt call for a DDraw buffer
void
CGameDSBitBuffer::TransBltDDraw(
CGameDDrawBitBuffer* pDestBuffer,
int xDest,
int yDest,
int wDest,
int hDest,
int xSrc,
int ySrc,
int transColor
)
{
LPBYTE lpdest = pDestBuffer->GetLockedAddress( xDest, yDest );
if (lpdest)
{
int scanDest = pDestBuffer->mPitch;
int scanSrc = -(mpDIB->BytesPerScanline());
TransCopyDIBBits(
lpdest,
mpDIB->GetPixelAddress( xSrc, ySrc ),
wDest, // width pixels
hDest,
(DWORD) scanDest,
(DWORD) scanSrc,
transColor
);
}
pDestBuffer->Unlock();
}
void
CGameDSBitBuffer::SetPalette( HPALETTE hPal )
{
}
#if !(defined(__BORLANDC__) || defined(__WATCOMC__))
void
TransCopyDIBBits(
LPBYTE pDest, // destination
LPBYTE pSource, // ; source pointer
DWORD dwWidth, // ; width pixels
DWORD dwHeight, // ; height pixels
DWORD dwScanD, // ; width bytes dest
DWORD dwScanS, // ; width bytes source
BYTE bTranClr // ; transparent color
)
{
_asm
{
push ds
push esi
push edi
mov ecx, dwWidth
or ecx,ecx
jz tcdb_nomore ; test for silly case
mov edx, dwHeight ; EDX is line counter
mov bl, bTranClr ; BL has transparency color
mov esi, pSource ; DS:[ESI] point to source
mov edi, pDest
or edi, edi ; check NULL ptrs
jz tcdb_nomore
or esi, esi ; check NULL ptrs
jz tcdb_nomore
sub dwScanD,ecx ; bias these
sub dwScanS,ecx
push ecx
align 4
tcdb_morelines:
pop ecx
push ecx
shr ecx,2
jz short tcdb_nextscan
// ;
// ; The idea here is to not branch very often so we unroll the loop by four
// ; and try to not branch when a whole run of pixels is either transparent
// ; or not transparent.
// ;
// ; There are two loops. One loop is for a run of pixels equal to the
// ; transparent color, the other is for runs of pixels we need to store.
// ;
// ; When we detect a "bad" pixel we jump to the same position in the
// ; other loop.
// ;
// ; Here is the loop we will stay in as long as we encounter a "transparent"
// ; pixel in the source.
// ;
align 4
tcdb_same:
mov eax, ds:[esi]
cmp al, bl
jne short tcdb_diff0
tcdb_same0:
cmp ah, bl
jne short tcdb_diff1
tcdb_same1:
shr eax, 16
cmp al, bl
jne short tcdb_diff2
tcdb_same2:
cmp ah, bl
jne short tcdb_diff3
tcdb_same3:
add edi,4
add esi,4
dec ecx
jnz short tcdb_same
jz short tcdb_nextscan
// ;
// ; Here is the loop we will stay in as long as
// ; we encounter a "non transparent" pixel in the source.
// ;
align 4
tcdb_diff:
mov eax, ds:[esi]
cmp al, bl
je short tcdb_same0
tcdb_diff0:
mov es:[edi],al
cmp ah, bl
je short tcdb_same1
tcdb_diff1:
mov es:[edi+1],ah
shr eax, 16
cmp al, bl
je short tcdb_same2
tcdb_diff2:
mov es:[edi+2],al
cmp ah, bl
je short tcdb_same3
tcdb_diff3:
mov es:[edi+3],ah
add edi,4
add esi,4
dec ecx
jnz short tcdb_diff
jz short tcdb_nextscan
// ;
// ; We are at the end of a scan, check for odd leftover pixels to do
// ; and go to the next scan.
// ;
align 4
tcdb_nextscan:
pop ecx
push ecx
and ecx,11b
jnz short tcdb_oddstuff
// ; move on to the start of the next line
tcdb_nextscan1:
add esi, dwScanS
add edi, dwScanD
dec edx // ; line counter
jnz short tcdb_morelines
jz short tcdb_nomore
// ;
// ; If the width is not a multiple of 4 we will come here to clean up
// ; the last few pixels
// ;
tcdb_oddstuff:
inc ecx
tcdb_oddloop:
dec ecx
jz short tcdb_nextscan1
mov al, ds:[esi]
inc esi
inc edi
cmp al, bl
je short tcdb_oddloop
mov es:[edi-1],al
jmp short tcdb_oddloop
tcdb_nomore:
pop ecx
pop edi
pop esi
pop ds
}
}
void
CopyDIBBits(
LPBYTE pDest, // ; dest pointer
LPBYTE pSource, // ; source pointer
DWORD dwWidth, // ; width pixels
DWORD dwHeight, // ; height pixels
DWORD dwScanD, // ; width bytes dest
DWORD dwScanS // ; width bytes source
)
{
_asm
{
push esi
push edi
; load scanline width into EBX, image height into EDX
mov ebx, [dwWidth]
or ebx, ebx
jz silly_case ; width is 0
mov edx, [dwHeight]
or edx, edx
jz silly_case ; height is 0
; bias offsets
sub [dwScanD], ebx
sub [dwScanS], ebx
; load ESI
mov esi, [pSource]
; load EDI and guarantee it is aligned on a DWORD boundary
mov edi, [pDest]
or edi, edi ; check NULL ptrs
jz silly_case
or esi, esi ; check NULL ptrs
jz silly_case
;; NOTE: this assumes that the scanwidth will always be a multiple
;; of DWORDs, so that the misalignment will be the same for all
;; scanlines. This allows us to calculate it once outside the loop
mov ecx, edi
and ecx, 11b ; deal with non-aligned case
mov eax, 100b
sub eax, ecx ; eax now contains aligment offset
cmp eax, ebx ; do we really have that many to do?
jb next_scanline ; if not, we're all set to blast
mov eax, ebx ; put actual width into offset
ALIGN 4
next_scanline:
; adjust_alignment
mov ecx, eax ; eax == alignment offset
rep movsb ; move bytewise to make EDI aligned properly
mov ecx, ebx ; total count per scanline
sub ecx, eax ; residue left over: misaligned amount!
; at this point, ECX is number of BYTES to transfer, ESI and EDI point to source and dest
push eax
mov eax, ecx
shr ecx, 2 ; div 4 to get number of DWORDS to transfer
rep movsd ; move by DWORDS as much as possible
and eax, 11b ; number of *bytes* to transfer (if any)
mov ecx, eax
rep movsb ; move remaining bytes (may be zero)
pop eax
; now adjust ESI and EDI for next scanline and jump to it!
add esi, [dwScanS]
add edi, [dwScanD]
dec edx ; if more scanlines, process them
jnz next_scanline
silly_case:
pop edi
pop esi
}
}
#endif