www.pudn.com > chibi > DDAPI.CPP


////////////////////////////// 
//	DDAPI.cpp		:	v0039 
//	Written by		:	Liu Gang 
//	Compiler		:	Microsoft Visual C++ 4.0 & DirectX 
//	Library			:	DDraw.Lib 
//	Copyright (C)	:	1996 WayAhead Corporation  
//	v0010			:	Aug.26.1996 
//	v0011			:	Sep.26.1996 
//	v0020			:	Nov.8.1996 
//					Warning: the width of the surface cannot larger than 640 pixel 
//							when this occurs, there will be only a general error code 
//							and return failed. 
//	v0021			:	Nov.27.1996 
//	v0030			:	Dec.11.1996, upgrade DirectDraw from 1.0 to 2.0 
//	v0031			:	Feb.10.1997, fixed a bug that cannot release surfaces entirly 
//						add a parameter to DD_EraseFrontScreen(), DD_EraseBckScreen() and CDDSurface::Erase() 
//						add CDDSurface::SetColorKeyRGB() and CDDSurface::SetColorKeyPAL(), changed color key method 
//	v0032			:	Mar.7.1997, Add a member "m_bInVideo" to CDDSurface 
//						To decrease the load time when surface lost 
//	v0033			:	Mar.10.1997 
//					Warning:	when using Lock()/Unlock() to access surface, 
//							please use ddsd.lPitch to stand for the width of  
//							the source surface. Mostly, the value in ddsd.dwWidth is equal to 
//                          that in ddsd.lPitch. But if the surface is in video memory, and its 
//							width is less than 640, and cannot devied by 4, they do not match before you  
//							draw ddsd.lpSurface to other surfaces. 
//	v0034			:	April.1.1997, add function FadeOut() and FadeIn(), add surface and palette counter 
//							add a member "m_bCreated" and a function IfCreated() to CDDSurface 
//							add a member "m_strPalette" and a function Reload() to CDDPalette 
//	v0035			:	Apr.9.1997, fixed a bug that generated by last version, did not initialize m_bCreated when  
//							constructing class instance, it took two whole days. 
//	v0036			:	Apr.18.1997, add CS_DBLCLKS to window style 
//	v0037			:	May.6.1997, add fadein and fadeout functions, and read palette from customed palette file 
//	v0038			:	May.10.1997, edited fadein and fadeout functions, to make them easy to use. 
//	v0039			:	May.12.1997, changed the global palette to object 
////////////////////////////// 
 
 
////////////////////////////// 
// implementation file 
 
// This file provide basic interfaces for DirectDraw with C++  
// extension, so that someone can use more easily. 
////////////////////////////// 
 
#include "stdafx.h" 
 
#include  
#include "DDAPI.h" 
#include "DDutils.h" 
#include "Assert.h" 
#include "resource.h" 
 
#define		MAX_SURFACE	256		// max surface is 256 
#define		MAX_PALETTE	8		// max palette is 8 
 
// Aug. 20. 1997 
//#define _DD_SYSTEMMEMORY 
 
#ifdef	_DEBUG 
#define	_DD_DEBUG 
#endif 
////////////////////////////// 
// globals 
// major window object 
HWND	hwndGame; 
////////////////////////////// 
 
////////////////////////////// 
// locals 
// abnormal structure: only one primary buffer 
// not recommended to use global 
 
// DirectDraw个体,唯一 
LPDIRECTDRAW2           DD_lpDD=NULL;			// DirectDraw object 
 
// 第一个面,显示面,全屏 
LPDIRECTDRAWSURFACE2    DD_lpDDSFront=NULL;	// DirectDraw primary surface, front buffer 
 
// 第二个面,用来保存背景,全屏 
LPDIRECTDRAWSURFACE2    DD_lpDDSBack=NULL;		// DirectDraw secondary surface, back buffer 
 
// 系统当前调色版 
LPDIRECTDRAWPALETTE		DD_lpDDPal=NULL;		// current palette that primary surface is using 
 
// global control, cannnot used outside 
// 其它用户生成的面,封装内部操作 
class CDDSurface		*DD_lppSurfaces[MAX_SURFACE];	// stores surfaces, max number is MAX_SURFACE 
int						DD_nSurfaceCounter = 0;			// stores for the number of surfaces have been loaded 
class CDDPalette		*DD_lppPalettes[MAX_PALETTE];	// stores palettes, max number is MAX_PALETTE 
int						DD_nPaletteCounter = 0;			// stores for the number of palettes have been loaded 
 
// 淡入淡出效果 
int						nFadeLevel=0;				// current fading step 
PALETTEENTRY			peFadeSave[256];			// save palette when fading 
//added by tian yue. 
PALETTEENTRY			pe[256]; 
BOOL					bFadeIn;					// TRUE for fading in 
////////////////////////////// 
 
// local functions 
////////////////////////////// 
// get blitter error when using BltFast() and Blt(),  
// not all the errors are here 
// strHead	:	prefix string to be displayed 
// ddrval	:	error number returned by BltFast() and Blt() 
void DD_getBltError( char *strHead, int ddrval ); 
 
// get remained video memory, for debug version only 
void DD_testVideoMemory(); 
////////////////////////////// 
 
////////////////////////////// 
// major window 
////////////////////////////// 
/* 
 * initialize major window 
 */ 
// hInstance	:	handle of application instance 
// nCmdShow	:	show major window or not 
// strName		:	window name 
// return value:	handle of the window 
HWND DD_InitWindow( HANDLE hInstance, int nCmdShow , LPCTSTR strName ) 
{ 
    WNDCLASS            wc; 
 
    /* 
     * set up and register window class 
     */ 
    wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; 
    wc.lpfnWndProc = DD_WindowProc; 
    wc.cbClsExtra = 0; 
    wc.cbWndExtra = 0; 
    wc.hInstance = HINSTANCE(hInstance); 
	// 用户要在其应用程序的资源编辑器里建立一个名为IDI_MAINGAME的图标 
    wc.hIcon = LoadIcon( HINSTANCE(hInstance), MAKEINTRESOURCE(IDI_MAINGAME) ); 
    wc.hCursor = LoadCursor( NULL, IDC_ARROW ); 
    wc.hbrBackground = HBRUSH(GetStockObject(BLACK_BRUSH)); 
    wc.lpszMenuName = strName; 
    wc.lpszClassName = strName; 
    RegisterClass( &wc ); 
     
    /* 
     * create a window 
     */ 
    hwndGame = CreateWindowEx( 
        0, 
        strName, 
        strName, 
        WS_POPUP, 
        0, 
        0, 
        GetSystemMetrics(SM_CXSCREEN), 
        GetSystemMetrics(SM_CYSCREEN), 
        NULL, 
        NULL, 
        HINSTANCE(hInstance), 
        NULL ); 
 
    if( !hwndGame ) 
    { 
        DD_initFail(NULL, DD_ERROR_ID+90); 
		return NULL; 
    } 
	SetCursor(NULL);	// hide cursor when begin application 
    ShowWindow( hwndGame, nCmdShow ); 
    UpdateWindow( hwndGame ); 
 
	return hwndGame; 
}	// DD_InitWindow() 
////////////////////////////// 
 
// graphic mode 
////////////////////////////// 
int gScreenWidth=0, gScreenHeight=0; 
/* 
 * Initialize graphic system 
 */ 
// hwnd			:	handle of the major window 
// nWidth, nHeight, nDepth:	the display mode of screen 
// bInVideo		:	if 1, should load back buffer surface in video memory 
//					if 0, should load back buffer surface in system memory 
//					if -1, can load back buffer surface anywhere 
// return value	:	TRUE if succeeded 
BOOL DD_InitGraph( HWND hwnd, int nWidth/*=-1*/, int nHeight/*=-1*/, int nDepth/*=-1*/, int bInVideo/*=-1*/ ) 
{ 
    DDSURFACEDESC       ddsd; 
    HRESULT             ddrval; 
 
    /* 
     * create the main DirectDraw object 
     */ 
	LPDIRECTDRAW	lpDD = NULL; 
    ddrval = DirectDrawCreate( NULL, &lpDD, NULL ); 
    if( ddrval != DD_OK ) 
    { 
        return DD_initFail(hwnd, DD_ERROR_ID+0); 
    } 
	// query direct draw object to object2 
	ddrval = lpDD->QueryInterface(IID_IDirectDraw2, (LPVOID *)&DD_lpDD); 
	if(ddrval != DD_OK) 
	{ 
		return DD_initFail( hwnd, DD_ERROR_ID+6 ); 
	} 
	// lpDD->Release();	// do not release, maybe useful 
 
	gScreenWidth = GetSystemMetrics( SM_CXSCREEN ); 
	gScreenHeight = GetSystemMetrics( SM_CYSCREEN ); 
    // Get exclusive mode 
#ifdef	_DD_DEBUG 
    ddrval = DD_lpDD->SetCooperativeLevel( hwnd, DDSCL_NORMAL ); 
    if( ddrval != DD_OK ) 
    { 
        return DD_initFail(hwnd, DD_ERROR_ID+1); 
    } 
#else 
	ddrval = DD_lpDD->SetCooperativeLevel( hwnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT ); 
    if( ddrval != DD_OK ) 
    { 
        return DD_initFail(hwnd, DD_ERROR_ID+3); 
    } 
 
    // Set the video mode to 640x480x256 
	// SCREEN_WIDTH*SCREEN_HEIGHT*SCREEN_THICK 
	if( nWidth == -1 ) nWidth = SCREEN_WIDTH; 
	if( nHeight == -1 )	nHeight = SCREEN_HEIGHT; 
	if( nDepth == -1 ) nDepth = SCREEN_THICK; 
    ddrval = DD_lpDD->SetDisplayMode( nWidth, nHeight, nDepth, 0, 0 ); 
    if( ddrval != DD_OK ) 
    { 
		if( nDepth > 8 ) 
		{ 
			DD_lpDD->SetCooperativeLevel( hwnd, DDSCL_NORMAL ); 
			DD_lpDD->Release(); 
			DD_lpDD = NULL; 
			return FALSE; 
		} 
		else 
			return DD_initFail(hwnd, DD_ERROR_ID+2); 
    } 
#endif 
 
	// get remained video memory 
#ifdef	_DEBUG 
	if( bInVideo ) 
		DD_testVideoMemory(); 
#endif 
 
    // Create the primary surface without back buffer 
	LPDIRECTDRAWSURFACE	lpDDSFront = NULL; 
    ddsd.dwSize = sizeof( ddsd ); 
    ddsd.dwFlags = DDSD_CAPS; 
    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; 
    ddrval = DD_lpDD->CreateSurface( &ddsd, &lpDDSFront, NULL ); 
    if( ddrval != DD_OK ) 
    { 
        return DD_initFail(hwnd, DD_ERROR_ID+4); 
    } 
	// query direct draw surface to surface2 
	ddrval = lpDDSFront->QueryInterface(IID_IDirectDrawSurface2, (LPVOID *)&DD_lpDDSFront); 
	if(ddrval != DD_OK) 
	{ 
		return DD_initFail( hwnd, DD_ERROR_ID+7 ); 
	} 
	//lpDDSFront->Release();	// do not release, if so,  
								// when surface lost there are something wrong with that 
 
	// get remained video memory 
#ifdef	_DEBUG 
	if( bInVideo ) 
		DD_testVideoMemory(); 
#endif 
 
    // create secondary surface, back buffer 
	LPDIRECTDRAWSURFACE lpDDSBack = NULL; 
    ddsd.dwSize = sizeof(ddsd); 
    ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT |DDSD_WIDTH; 
    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; 
#ifdef	_DD_DEBUG 
#else 
#ifdef	_DD_SYSTEMMEMORY 
	ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; 
#else 
	if( bInVideo == 0 ) 
		ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; 
	else if( bInVideo == 1 ) 
		ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY; 
#endif	// _DDSYSTEMMEMORY 
#endif	// _DD_DEBUG 
	// same size as full screen 
    ddsd.dwWidth = SCREEN_WIDTH; 
    ddsd.dwHeight = SCREEN_HEIGHT; 
	ddrval = DD_lpDD->CreateSurface(&ddsd, &lpDDSBack, NULL); 
    if( ddrval != DD_OK ) 
    { 
		if( bInVideo ) 
		{ 
			// try in system memory again 
			ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; 
			ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; 
			ddrval = DD_lpDD->CreateSurface(&ddsd, &lpDDSBack, NULL); 
			if( ddrval != DD_OK ) 
				return DD_initFail(hwnd, DD_ERROR_ID+10); 
		} 
		else 
			return DD_initFail(hwnd, DD_ERROR_ID+5); 
	} 
	// query direct draw surface to surface2 
	ddrval = lpDDSBack->QueryInterface(IID_IDirectDrawSurface2, (LPVOID *)&DD_lpDDSBack); 
	if(ddrval != DD_OK) 
	{ 
		return DD_initFail( hwnd, DD_ERROR_ID+8 ); 
	} 
	lpDDSBack->Release();	// must release, bug fix 
 
// init other (user) surfaces 
	for( int i=0 ; i< MAX_SURFACE; i++ ) 
		DD_lppSurfaces[i] = NULL; 
 
// init other (user) palettes 
	for( int j=0 ; j< MAX_PALETTE; j++ ) 
		DD_lppPalettes[j] = NULL; 
 
//------------- 
// init primary palette object 
    PALETTEENTRY        ape[256]; 
    // build a 332 palette as the default. 
    // 
    for (i=0; i<256; i++) 
    { 
        ape[i].peRed   = (BYTE)(((i >> 5) & 0x07) * 255 / 7); 
        ape[i].peGreen = (BYTE)(((i >> 2) & 0x07) * 255 / 7); 
        ape[i].peBlue  = (BYTE)(((i >> 0) & 0x03) * 255 / 3); 
        ape[i].peFlags = (BYTE)0; 
    } 
	DD_lpDD->CreatePalette(DDPCAPS_8BIT, ape, &DD_lpDDPal, NULL); 
	if( DD_lpDDPal == NULL ) 
	{ 
		return DD_initFail(hwnd, DD_ERROR_ID+9); 
	} 
//------------- 
	 
	// clear screens 
	DD_EraseFrontScreen(); 
	DD_EraseBackScreen(); 
 
	return TRUE; 
} /* DD_InitGraph */ 
 
 
/* 
 * quit graphic system, end DirectDraw section 
 */ 
void DD_QuitGraph() 
{ 
	HRESULT ddrval; 
 
	if( DD_lpDD == NULL ) 
		return; 
 
	// reset graph mode and cooperative level 
    ddrval = DD_lpDD->SetDisplayMode( gScreenWidth, gScreenHeight, 8, 0, 0 ); 
	if( ddrval != DD_OK ) 
	{ 
	} 
 
    ddrval = DD_lpDD->SetCooperativeLevel( hwndGame, DDSCL_NORMAL ); 
    if( ddrval != DD_OK ) 
    { 
    } 
 
	if( DD_lpDD != NULL ) 
	{ 
		// restore other surfaces 
		for( int i=0 ; i< MAX_SURFACE; i++ ) 
		{ 
			if( DD_lppSurfaces[i] != NULL ) 
			{ 
				DD_lppSurfaces[i]->Release(); 
				DD_lppSurfaces[i] = NULL; 
			} 
		} 
		Assert( DD_nSurfaceCounter == 0 ); 
 
//------------- 
		// release primary palette 
		if( DD_lpDDPal != NULL ) 
		{ 
			Assert( DD_lpDDPal != NULL ); 
			DD_lpDDPal->Release(); 
			DD_lpDDPal = NULL; 
		} 
//------------- 
 
		// release palettes 
		for( int j=0; j< MAX_PALETTE ; j++ ) 
		{ 
			if( DD_lppPalettes[j] != NULL ) 
			{ 
				DD_lppPalettes[j]->Release(); 
				DD_lppPalettes[j] = NULL; 
			} 
		} 
		Assert( DD_nPaletteCounter == 0 ); 
 
		// release global surfaces 
		if( DD_lpDDSFront )	 
			DD_lpDDSFront->Release();	 
		DD_lpDDSFront = NULL; 
		if( DD_lpDDSBack ) 
			DD_lpDDSBack->Release();	 
		DD_lpDDSBack = NULL; 
 
		// release DirectDraw Object 
		DD_lpDD->Release(); 
        DD_lpDD = NULL; 
	} 
 
/* 
	LPDIRECTDRAW	lpDD = NULL; 
    ddrval = DirectDrawCreate( NULL, &lpDD, NULL ); 
    if( ddrval != DD_OK ) 
    { 
		return; 
    } 
	// query direct draw object to object2 
	ddrval = lpDD->QueryInterface(IID_IDirectDraw2, (LPVOID *)&DD_lpDD); 
	if(ddrval != DD_OK) 
	{ 
		return; 
	} 
	// lpDD->Release();	// do not release, maybe useful 
 
	ddrval = DD_lpDD->SetCooperativeLevel( hwndGame, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT ); 
    if( ddrval != DD_OK ) 
    { 
        return; 
    } 
 
    // Set the video mode to 640x480x256 
	// SCREEN_WIDTH*SCREEN_HEIGHT*SCREEN_THICK 
    ddrval = DD_lpDD->SetDisplayMode( gScreenWidth, gScreenHeight, 8, 0, 0 ); 
    if( ddrval != DD_OK ) 
    { 
		return; 
    } 
 
    ddrval = DD_lpDD->SetCooperativeLevel( hwndGame, DDSCL_NORMAL ); 
    if( ddrval != DD_OK ) 
    { 
		return; 
    } 
	if( DD_lpDD != NULL ) 
	{ 
		// release DirectDraw Object 
		DD_lpDD->Release(); 
        DD_lpDD = NULL; 
	} 
*/ 
} /* DD_QuitGraph */ 
 
 
/* 
 * This function is called if the initialization function fails 
 */ 
// hwnd	:	handle of the parent window 
// err		:	error ID 
// return value:	Always FALSE 
BOOL DD_initFail( HWND hwnd , int err ) 
{ 
	char buf[MAX_SURFACE]; 
 
    DD_QuitGraph(); 
    wsprintf(buf, "DirectDraw init FAILED (%d)", err); 
    MessageBox( hwnd, buf, "ERROR", MB_OK ); 
    return FALSE; 
 
} /* DD_initFail */ 
 
// get front buffer pointer 
// return value	:	pointer of front buffer 
inline LPDIRECTDRAWSURFACE2 DD_GetFrontBuffer( void ) 
{ 
	return DD_lpDDSFront; 
} 
 
// get back buffer pointer 
// return value	:	pointer of back buffer 
inline LPDIRECTDRAWSURFACE2 DD_GetBackBuffer( void ) 
{ 
	return DD_lpDDSBack; 
} 
////////////////////////////// 
 
// screen 
////////////////////////////// 
// if surface is lost, run retore 
// return value	:	TRUE if succeeded 
BOOL DD_RestoreScreen( void ) 
{ 
	HRESULT ddrval; 
 
	// reset primary surface 
	if( DD_lpDDSFront ) 
	{ 
		ddrval = DD_lpDDSFront->Restore(); 
		if( ddrval != DD_OK ) 
		{ 
			int nErr=-1; 
			switch( ddrval ) 
			{ 
			case	DDERR_GENERIC	: 
				nErr = 1; 
				break; 
			case	DDERR_INCOMPATIBLEPRIMARY : 
				nErr = 2; 
				break; 
			case	DDERR_IMPLICITLYCREATED	: 
				nErr = 3; 
				break; 
			case	DDERR_INVALIDOBJECT : 
				nErr = 4; 
				break; 
			case	DDERR_INVALIDPARAMS	: 
				nErr = 5; 
				break; 
			case	DDERR_NOEXCLUSIVEMODE : 
				nErr = 6; 
				break; 
			case	DDERR_OUTOFMEMORY	: 
				nErr = 7; 
				break; 
			case	DDERR_UNSUPPORTED : 
				nErr = 8; 
				break; 
			case	DDERR_WRONGMODE : 
				nErr = 9; 
				break; 
			} 
//			WriteErrorFile( "a.log", nErr ); 
			return FALSE; 
		} 
	} 
 
	// reset secondary surface 
	if( DD_lpDDSBack ) 
	{ 
		ddrval = DD_lpDDSBack->Restore(); 
		if( ddrval != DD_OK ) 
			return FALSE; 
	} 
 
	// reset palette, disband fade mode 
	int nLevel = nFadeLevel; 
	DD_FadeScreen( FALSE, 0 ); 
 
	// reset surfaces 
	for( int i=0; iRestore() )  
				return FALSE; 
		} 
	} 
 
	// reset fade mode 
	for( int l=0; l < nLevel ; l++ ) 
		DD_FadeScreen( bFadeIn ); 
 
	// send surface lost error message to user's application 
	PostMessage( hwndGame, WM_DD_SURFACELOST, 0, 0 ); 
	return TRUE; 
} /* DD_RestoreScreen */ 
 
// draw from back buffer to front buffer 
// pRect		:	rectangle region to update, full surface if it is NULL 
// return value	:	TRUE if succeeded 
BOOL DD_UpdateScreen( RECT *pRect/*=NULL*/ ) 
{ 
    HRESULT     ddrval; 
 
	RECT rect; 
	if( pRect == NULL ) 
	{ 
		rect.left = 0, rect.top = 0, 
		rect.right = SCREEN_WIDTH, rect.bottom = SCREEN_HEIGHT; 
	} 
	else 
	{ 
		rect.left = pRect->left, rect.top = pRect->top; 
		rect.right = pRect->right, rect.bottom = pRect->bottom; 
	} 
    while( 1 ) 
    { 
		ddrval = DD_lpDDSFront->BltFast( rect.left, rect.top, DD_lpDDSBack, &rect, DDBLTFAST_NOCOLORKEY ); 
        if( ddrval == DD_OK ) 
            break; 
#ifdef	_DEBUG 
		DD_getBltError( "DD_UpdateScreen", ddrval ); 
#endif 
        if( ddrval == DDERR_SURFACELOST ) 
            if( !DD_RestoreScreen() ) 
                return FALSE; 
        if( ddrval != DDERR_WASSTILLDRAWING ) 
            return FALSE; 
    } 
	return TRUE; 
}	// DD_UpdateScreen() 
 
// fill black color to front screen 
// nColor		:	color index you want to fill, default is BLACK 
// pRect		:	rectangle region to erase, full surface if it is NULL 
// return value	:	TRUE if succeeded 
BOOL DD_EraseFrontScreen( int nColor, RECT *pRect/*=NULL*/ ) 
{ 
    DDBLTFX     ddbltfx; 
    HRESULT     ddrval; 
 
    // Erase the background 
    ddbltfx.dwSize = sizeof( ddbltfx ); 
    ddbltfx.dwFillColor = nColor; 
    while( 1 ) 
    { 
		ddrval = DD_lpDDSFront->Blt( pRect, NULL, NULL, DDBLT_COLORFILL, &ddbltfx ); 
 
        if( ddrval == DD_OK ) 
        { 
            break; 
        } 
#ifdef	_DEBUG 
		DD_getBltError( "DD_EraseFrontScreen", ddrval ); 
#endif 
        if( ddrval == DDERR_SURFACELOST ) 
        { 
            if( !DD_RestoreScreen() ) 
                return FALSE; 
        } 
        if( ddrval != DDERR_WASSTILLDRAWING ) 
        { 
            return FALSE; 
        } 
    } 
	return TRUE; 
} /* DD_EraseFrontScreen() */ 
 
// fill black color to back screen 
// nColor		:	color index you want to fill, default is BLACK 
// pRect		:	rectangle region to erase, full surface if it is NULL 
// return value	:	TRUE if succeeded 
BOOL DD_EraseBackScreen( int nColor/*=0*/, RECT *pRect/*=NULL*/ ) 
{ 
    DDBLTFX     ddbltfx; 
    HRESULT     ddrval; 
 
    // Erase the background 
    ddbltfx.dwSize = sizeof( ddbltfx ); 
    ddbltfx.dwFillColor = nColor; 
    while( 1 ) 
    { 
		ddrval = DD_lpDDSBack->Blt( pRect, NULL, NULL, DDBLT_COLORFILL, &ddbltfx ); 
 
        if( ddrval == DD_OK ) 
        { 
            break; 
        } 
#ifdef	_DEBUG 
		DD_getBltError( "DDEraseBackScreen", ddrval ); 
#endif 
        if( ddrval == DDERR_SURFACELOST ) 
        { 
            if( !DD_RestoreScreen() ) 
                return FALSE; 
        } 
        if( ddrval != DDERR_WASSTILLDRAWING ) 
        { 
            return FALSE; 
        } 
    } 
	return TRUE; 
}	// DD_EraseBackScreen() 
 
 
// fill black color to a given surface 
// pSurface		:	surface to be erased 
// nColor		:	color index you want to fill, default is BLACK 
// pRect		:	rectangle region to erase, full surface if it is NULL 
// return value	:	TRUE if succeeded 
BOOL DD_EraseScreen( LPDIRECTDRAWSURFACE2 pSurface, int nColor, RECT *pRect/*=NULL*/ ) 
{ 
    DDBLTFX     ddbltfx; 
    HRESULT     ddrval; 
 
    // Erase the background 
    ddbltfx.dwSize = sizeof( ddbltfx ); 
    ddbltfx.dwFillColor = nColor; 
    while( 1 ) 
    { 
		ddrval = pSurface->Blt( pRect, NULL, NULL, DDBLT_COLORFILL, &ddbltfx ); 
 
        if( ddrval == DD_OK ) 
        { 
            break; 
        } 
#ifdef	_DEBUG 
		DD_getBltError( "DDEraseScreen", ddrval ); 
#endif 
        if( ddrval == DDERR_SURFACELOST ) 
        { 
            if( !DD_RestoreScreen() ) 
                return FALSE; 
        } 
        if( ddrval != DDERR_WASSTILLDRAWING ) 
        { 
            return FALSE; 
        } 
    } 
	return TRUE; 
} 
////////////////////////////// 
 
// fade screen 
////////////////////////////// 
// make screen fade in or fade out 
// bIn			:	TRUE for fade in screen, else for fade out screen 
// nMaxStep		:	ranges from 1 to 255, set to 0 if to reset this function 
// return value	:	TRUE for end session 
BOOL DD_FadeScreen( BOOL bIn , int nMaxStep /*=10*/ ) 
{ 
	RGBQUAD        rgb[256]; 
	PALETTEENTRY	pe[256]; 
	int nStep; 
 
	// reset Fade mode 
	if( nMaxStep == 0 )  
	{ 
		if( nFadeLevel != 0 ) 
			DD_lpDDPal->SetEntries( 0, 0, 256, peFadeSave ); 
		nFadeLevel=0;	return TRUE; 
	} 
 
	// get palette entries and save it 
	if( nFadeLevel == 0 ) 
	{ 
		if(DD_lpDDPal->GetEntries( 0, 0, 256, peFadeSave ) != DD_OK) 
		{ 
			return	TRUE; 
		} 
	} 
 
	// if end section, restore palette 
	if( nFadeLevel == nMaxStep ) 
	{ 
		nFadeLevel = 0; 
		DD_lpDDPal->SetEntries( 0, 0, 256, peFadeSave ); 
		return TRUE; 
	} 
 
	// set from palette entries to rgb 
	for ( int j = 0; j< 256; j++ ) 
	{ 
		rgb[j].rgbRed = peFadeSave[j].peRed; 
		rgb[j].rgbGreen = peFadeSave[j].peGreen; 
		rgb[j].rgbBlue = peFadeSave[j].peBlue; 
	} 
 
	// fade in or fade out 
	bFadeIn = bIn; 
	if( bIn )		nStep=nFadeLevel;	// fade in 
	else			nStep=nMaxStep-nFadeLevel; 
 
	// do it 
	for( int i=0; i<256; i++ ) 
	{ 
		rgb[i].rgbRed = peFadeSave[i].peRed*nStep/nMaxStep; 
		rgb[i].rgbGreen = peFadeSave[i].peGreen*nStep/nMaxStep; 
		rgb[i].rgbBlue = peFadeSave[i].peBlue*nStep/nMaxStep; 
	} 
 
	// set from rgb to palette entries 
	for ( int k = 0; k< 256; k++ ) 
	{ 
		pe[k].peRed = rgb[k].rgbRed; 
		pe[k].peGreen = rgb[k].rgbGreen; 
		pe[k].peBlue = rgb[k].rgbBlue; 
	} 
 
	// set to palette 
	if(DD_lpDDPal->SetEntries( 0, 0, 256, pe ) != DD_OK) 
	{ 
		nFadeLevel = 0; 
		DD_lpDDPal->SetEntries( 0, 0, 256, peFadeSave ); 
		return TRUE; 
	} 
 
	nFadeLevel ++; 
	return	FALSE; 
} /* DD_FadeScreen */ 
 
// fade out  
// nMaxStep		:	ranges from 1 to 255, set to 0 if to reset this function 
// return value	:	TRUE for end session 
BOOL DD_FadeOut( int nMaxStep ) 
{ 
	PALETTEENTRY	pe[256]; 
	int nStep; 
 
	// get palette entries and save it 
	if( nFadeLevel == 0 ) 
	{ 
		if(DD_lpDDPal->GetEntries( 0, 0, 256, peFadeSave ) != DD_OK) 
		{ 
			return	TRUE; 
		} 
	} 
 
	// if end section, restore palette 
	if( nFadeLevel == (nMaxStep+1) ) 
	{ 
		nFadeLevel = 0; 
		return TRUE; 
	} 
	// to computation the current step 
	nStep= nMaxStep - nFadeLevel; 
	// do it 
	for( int i=0; i<256; i++ ) 
	{ 
		pe[i].peRed = peFadeSave[i].peRed*nStep/nMaxStep; 
		pe[i].peGreen = peFadeSave[i].peGreen*nStep/nMaxStep; 
		pe[i].peBlue = peFadeSave[i].peBlue*nStep/nMaxStep; 
	} 
	if(DD_lpDDPal->SetEntries( 0, 0, 256, pe ) != DD_OK) 
	{ 
		nFadeLevel = 0; 
		DD_lpDDPal->SetEntries( 0, 0, 256, peFadeSave ); 
		return TRUE; 
	} 
 
	nFadeLevel ++; 
	return	FALSE; 
} /* DD_FadeOut */ 
 
// fade in  
// nMaxStep		:	ranges from 1 to 255, set to 0 if to reset this function 
// return value	:	TRUE for end session 
BOOL DD_FadeIn(PALETTEENTRY	 * pe,PALETTEENTRY	* peFadeSave,int nMaxStep ) 
{ 
	// do it 
	DD_lpDDPal->SetEntries( 0, 0, 256, pe ) ; 
 
	for( int i=0; i<256; i++ ) 
	{ 
		if (pe[i].peRed SetEntries( 0, 0, 256, peFadeSave ); 
		return TRUE; 
	} 
 
	if(DD_lpDDPal->SetEntries( 0, 0, 256, pe ) != DD_OK) 
	{ 
		nFadeLevel = 0; 
		DD_lpDDPal->SetEntries( 0, 0, 256, peFadeSave ); 
		return TRUE; 
	} 
 
	nFadeLevel ++; 
 
	return	FALSE; 
} /* DD_FadeOut */ 
 
// fade out screen, from color to black 
// nMaxStep		:	how much steps fade from begin to end 
// nDelay		:	time each step should pause, in million second 
void DD_FadeOutScreen( int nMaxStep, int nDelay ) 
{ 
	PALETTEENTRY	pe[256]; 
 
#ifdef	_DD_DEBUG 
	return; 
#endif //_DD_DEBUG 
 
	// get palette entries and save it 
	Assert( DD_lpDDPal != NULL ); 
	if(DD_lpDDPal->GetEntries( 0, 0, 256, peFadeSave ) != DD_OK) 
	{	// error in get entry 
		return; 
	} 
 
	if( nMaxStep <= 0 )	return;	// step error 
 
	for( int nStep=nMaxStep-1; nStep>=0; nStep-- ) 
	{ 
		// do it 
		for( int i=0; i<256; i++ ) 
		{ 
			pe[i].peRed = peFadeSave[i].peRed*nStep/nMaxStep; 
			pe[i].peGreen = peFadeSave[i].peGreen*nStep/nMaxStep; 
			pe[i].peBlue = peFadeSave[i].peBlue*nStep/nMaxStep; 
		} 
		if(DD_lpDDPal->SetEntries( 0, 0, 256, pe ) != DD_OK) 
		{	// error in set entry 
			DD_lpDDPal->SetEntries( 0, 0, 256, peFadeSave ); 
			return; 
		} 
		Sleep( nDelay ); 
	} 
}	// DD_FadeOutScreen() 
 
// fade in screen, from black to color, muset used with DD_FadeClear() 
// nStep		:	how much steps fade from begin to end 
// nDelay		:	time each step should pause, in million second 
// pPal			:	the palette you want to display at last 
void DD_FadeInScreen( int nMaxStep, int nDelay ) 
{ 
	PALETTEENTRY	pe[256]; 
 
#ifdef	_DD_DEBUG 
	return; 
#endif //_DD_DEBUG 
 
	Assert( DD_lpDDPal != NULL ); 
	if( DD_lpDDPal == NULL ) 
	{ 
		OutputDebugString( "FadeInScreen Error(4): current palette is NULL!\n" ); 
		return;	// palette pointer cannot be NULL 
	} 
 
	if( nMaxStep <= 0 ) 
	{ 
		OutputDebugString( "DD_FadeInScreen Error(5): Step is less than 0!\n" ); 
		if( DD_lpDDPal->SetEntries( 0, 0, 256, peFadeSave ) != DD_OK ) 
		{ 
			OutputDebugString( "DD_FadeInScreen Error(0): Cannot set entries at last!\n" ); 
		} 
		return;	// step error, set palette directly 
	} 
 
	for( int nStep=0; nStepSetEntries( 0, 0, 256, pe ) != DD_OK) 
		{	// error in set entry 
			OutputDebugString( "DD_FadeInScreen Error(1): Cannot set entries!\n" ); 
			DD_lpDDPal->SetEntries( 0, 0, 256, peFadeSave ); 
			return; 
		} 
		Sleep( nDelay ); 
	} 
	if( DD_lpDDPal->SetEntries( 0, 0, 256, peFadeSave ) != DD_OK ) 
	{ 
		OutputDebugString( "DD_FadeInScreen Error(2): Cannot set entries at last!\n" ); 
	} 
}	// DD_FadeInScreen() 
 
// Restore saved palette from "peFadeSave" to spcecified palette  
// pointer. Usually used after DD_FadeOutScreen(), to reset the  
// palette at last, or maybe not useful after v0039. 
// pPal			:	palette pointer to be restored 
void DD_FadeRestore( LPDIRECTDRAWPALETTE pPal ) 
{ 
 
#ifdef	_DD_DEBUG 
	return; 
#endif //_DD_DEBUG 
 
	if( pPal->SetEntries( 0, 0, 256, peFadeSave ) != DD_OK ) 
	{ 
		OutputDebugString( "DD_FaceRestore Error: Cannot set entries!\n" ); 
	} 
}	// DD_FadeRestore() 
 
// Clear the palette pointer to whole black. Usually used before  
// DD_FadeInScreen(), to set a palette first and save the origional  
// value to "peFadeSave" 
// pPal			:	palette to be cleared 
void DD_FadeClear( LPDIRECTDRAWPALETTE pPal ) 
{ 
	PALETTEENTRY	pe[256]; 
 
#ifdef	_DD_DEBUG 
	return; 
#endif //_DD_DEBUG 
 
	if( pPal == NULL )	return; 
	if( pPal->GetEntries( 0, 0, 256, peFadeSave ) != DD_OK ) 
	{	// save palette 
		OutputDebugString( "DD_FaceClear Error(0): Cannot get entries!\n" ); 
	} 
	memset( pe, 0, sizeof( pe ) ); 
	if( pPal->SetEntries( 0, 0, 256, pe ) != DD_OK ) 
	{	// set to Zero 
		OutputDebugString( "DD_FaceClear Error(1): Cannot set entries!\n" ); 
	} 
}	// DD_FadeClear() 
////////////////////////////// 
 
// blt 
////////////////////////////// 
// draw from one surface to another 
// ptDest		:	destination position in destination surface 
// lprcSrc		:	source rectangle in source surface, full surface if it is NULL 
// dwFlags		:	DDBLTFAST_NOCOLORKEY or DDBLTFAST_SRCCOLORKEY 
// return value	:	TRUE if succeeded 
BOOL DD_BltSurface( POINT ptDest, LPDIRECTDRAWSURFACE2 lpDDSDest, RECT *lprcSrc, LPDIRECTDRAWSURFACE2 lpDDSSrc, DWORD dwFlags ) 
{ 
	HRESULT ddrval; 
	while( 1 ) 
	{ 
		ddrval = lpDDSDest->BltFast( ptDest.x, ptDest.y, lpDDSSrc, lprcSrc, dwFlags ); 
		if( ddrval == DD_OK ) 
			break; 
#ifdef	_DEBUG 
		DD_getBltError( "DD_BltSurface", ddrval ); 
#endif 
		if( ddrval == DDERR_SURFACELOST ) 
			if( !::DD_RestoreScreen() ) 
				return FALSE; 
		if( ddrval != DDERR_WASSTILLDRAWING ) 
			return FALSE; 
	} 
	return TRUE; 
} 
 
// get global palette pointer 
LPDIRECTDRAWPALETTE DD_GetPalette() 
{ 
	return DD_lpDDPal; 
} 
////////////////////////////// 
 
 
////////////////////////////// 
// for class CDDSurface, standard offscreen plain surface 
// contructor 
CDDSurface::CDDSurface() 
{ 
	m_lpSurface = NULL; 
	m_lpPalette = NULL; 
 
	// the surface is not created yet 
	m_bCreated = FALSE; 
 
	// bitmap attributes 
	m_bHasBitmap = FALSE; 
	strcpy( m_strBitmap, "" ); 
	m_szBitmap.cx = m_szBitmap.cy = 0; 
 
	// color key 
	m_dwDrawFlag = 0; 
	// if in video memory, only used when surface lost 
	m_bInVideo = FALSE;	 
} 
 
// destructor 
CDDSurface::~CDDSurface() 
{ 
	Release(); 
	if( m_lpPalette != NULL ) 
	{ 
		m_lpPalette->Release(); 
		m_lpPalette = NULL; 
	} 
	m_bHasBitmap = FALSE; 
} 
 
// create surface object 
// width, height:	size of surface to create 
// bColorkey	:	TRUE if want color key, BLACK 
// bInVideo		:	1, should load surface in video memory 
//					0, should load surface in system memory 
//					-1, load surface anywhere possible 
// return value	:	TRUE if succeeded 
BOOL CDDSurface::Create( int width, int height, BOOL bColorKey/*=FALSE*/, BOOL bInVideo/*=-1*/ ) 
{ 
	HRESULT				ddrval; 
    DDSURFACEDESC       ddsd; 
	LPDIRECTDRAWSURFACE	lpSurface = NULL; 
 
	// get remained video memory 
#ifdef	_DEBUG 
	if( bInVideo ) 
		DD_testVideoMemory(); 
#endif 
 
	if( m_bCreated == TRUE ) 
	{ 
		OutputDebugString( "CDDSurface Create Warning: surface has been already created\n " ); 
		return FALSE; 
	} 
 
    ddsd.dwSize = sizeof(ddsd); 
    ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; 
    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; 
#ifdef	_DD_SYSTEMMEMORY 
	m_bInVideo = FALSE; 
	ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; 
#else 
	m_bInVideo = bInVideo; 
	if( bInVideo == 0 ) 
		ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; 
	else if( bInVideo == 1 ) 
		ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY; 
#endif	// _DDSYSTEMMEMORY 
    ddsd.dwWidth = width; 
    ddsd.dwHeight = height; 
 
    // create DirectDraw surface 
	if ((ddrval = DD_lpDD->CreateSurface(&ddsd, &lpSurface, NULL)) != DD_OK) 
	{ 
		int nErr=-1; 
		switch( ddrval ) 
		{ 
		case	DDERR_INVALIDOBJECT: 
			nErr = 0; 
			break; 
		case	DDERR_INVALIDPARAMS: 
			nErr = 1; 
			break; 
		case	DDERR_OUTOFVIDEOMEMORY: 
			nErr = 2; 
			break; 
		case	DDERR_NODIRECTDRAWHW:	 
			nErr = 3; 
			break; 
		case	DDERR_NOCOOPERATIVELEVELSET: 
			nErr = 4; 
			break; 
		case	DDERR_INVALIDCAPS: 
			nErr = 5; 
			break; 
		case	DDERR_INVALIDPIXELFORMAT: 
			nErr = 6; 
			break; 
		case	DDERR_NOALPHAHW: 
			nErr = 7; 
			break; 
		case	DDERR_NOFLIPHW: 
			nErr = 8; 
			break; 
		case	DDERR_NOZBUFFERHW: 
			nErr = 9; 
			break; 
		case	DDERR_NOEXCLUSIVEMODE: 
			nErr = 10; 
			break; 
		case	DDERR_OUTOFMEMORY: 
			nErr = 11; 
			break; 
		case	DDERR_PRIMARYSURFACEALREADYEXISTS: 
			nErr = 12; 
			break; 
		case	DDERR_NOEMULATION: 
			nErr = 13; 
			break; 
		case	DDERR_INCOMPATIBLEPRIMARY: 
			nErr = 14; 
			break; 
		} 
		if( nErr == 2 )	// out of video memory is not an Must Quit eror 
		{ 
			OutputDebugString( "Out of video memory error!\n" ); 
			return FALSE; 
		} 
		if( bInVideo == TRUE ) 
		{ 
			OutputDebugString( "In video error!\n" ); 
			return FALSE; 
		} 
		OutputDebugString( "CDDSurface Create() Error(5): Surface create error!\n" ); 
        return DD_initFail(hwndGame, DD_ERROR_ID+70+nErr); 
	} 
 
	// query direct draw surface to surface2 
	ddrval = lpSurface->QueryInterface(IID_IDirectDrawSurface2, (LPVOID *)&m_lpSurface); 
	if( ddrval != DD_OK ) 
	{ 
		OutputDebugString( "CDDSurface Create() Error(6): Query interface error!\n" ); 
		return DD_initFail( hwndGame, DD_ERROR_ID+68 ); 
	} 
	lpSurface->Release();	// must release, bug fix 
 
	// add to global surfaces array 
	BOOL	bSuccess = FALSE; 
	for( int i=0; iGetSurfaceDesc( &ddsd ); 
	if( ddrval != DD_OK )	 
	{ 
		OutputDebugString( "CDDSurface Loadbitmap() Error(2): Get Surface desc error!\n" ); 
		return DD_initFail(hwndGame, DD_ERROR_ID+59); 
	} 
	m_szBitmap.cx = ddsd.dwWidth, m_szBitmap.cy = ddsd.dwHeight; 
 
	// set color key 
	if( bColorKey ) 
	{ 
		// use color on top-left corner of the surface as color key  
		SetColorKeyRGB( RGB(0,0,0) ); 
 
		//m_dwDrawFlag set by SetColorKeyRGB() just now. 
		//m_dwDrawFlag = DDBLTFAST_SRCCOLORKEY;  
	} 
	else 
		m_dwDrawFlag = DDBLTFAST_NOCOLORKEY; 
 
	m_bCreated = TRUE; 
	return TRUE; 
} 
////////////////////////////// 
 
// color key 
////////////////////////////// 
// actually, you need not use these two functions to set color key,  
// if you want color key, by default, BLACK is the color key 
 
// they all can run correctly on 256 color, exclusive mode. 
// in unexclusive mode, surface created by Create(),  
//		SetColorKeyPAL() and SetColorKeyRGB() are not correct. 
// in high color mode, surface created by Create(),  
//		SetColorKeyPAL() and SetColorKeyRGB() are not correct. 
// if surface created by LoadBitmap(), they are all correct. 
// only SetColorKeyDEF() can run correctly in any condition. 
 
// set colorkey by default 
// color on top left corner of the surface to be color key 
// must be used after Create() or LoadBitmap() 
// if used before, no effects 
// return	:	TRUE if successful 
BOOL CDDSurface::SetColorKeyDEF() 
{ 
	// use color on top-left corner of the surface as color key  
	HRESULT	ddrval; 
	if( !m_lpSurface ) 
	{ 
		OutputDebugString( "CDDSurface Error(38): Set color key before create surface!\n" ); 
		return FALSE; 
	} 
 
	// get color from top-left corner of the surface 
	DWORD dw; 
	DDSURFACEDESC ddsd; 
	ddsd.dwSize = sizeof(ddsd); 
	while ((ddrval = m_lpSurface->Lock(NULL, &ddsd, 0, NULL)) == DDERR_WASSTILLDRAWING) 
		; 
	if (ddrval == DD_OK) 
	{ 
		dw  = *(DWORD *)ddsd.lpSurface;                     // get DWORD 
		dw &= (1 << ddsd.ddpfPixelFormat.dwRGBBitCount)-1;  // mask it to bpp 
		m_lpSurface->Unlock(NULL); 
	} 
 
	// set as color key 
	DDCOLORKEY          ddck; 
	ddck.dwColorSpaceLowValue  = dw; 
	ddck.dwColorSpaceHighValue = ddck.dwColorSpaceLowValue; 
	while( 1 ) 
	{ 
		ddrval = m_lpSurface->SetColorKey(DDCKEY_SRCBLT, &ddck); 
		if( ddrval == DD_OK ) 
			break; 
		if( ddrval == DDERR_SURFACELOST ) 
			if( !::DD_RestoreScreen() ) 
				return DD_initFail(hwndGame, DD_ERROR_ID+52); 
		if( ddrval != DDERR_WASSTILLDRAWING ) 
			return DD_initFail(hwndGame, DD_ERROR_ID+53); 
	} 
	m_dwDrawFlag = DDBLTFAST_SRCCOLORKEY; 
	return TRUE; 
} 
 
// set colorkey by given RGB value 
// must be used after Create() or LoadBitmap() 
// if used before, no effects 
// nColor	:	color key value 
// return	:	TRUE if successful 
BOOL CDDSurface::SetColorKeyRGB( DWORD dwColor ) 
{ 
	HRESULT	ddrval; 
	if( !m_lpSurface ) 
	{ 
		OutputDebugString( "CDDSurface Error(39): Set color key before create surface!\n" ); 
		return FALSE; 
	} 
	while( 1 ) 
	{ 
		ddrval = ::DDSetColorKey(m_lpSurface, dwColor); 
		if( ddrval == DD_OK ) 
			break; 
		if( ddrval == DDERR_SURFACELOST ) 
			if( !::DD_RestoreScreen() ) 
				return DD_initFail(hwndGame, DD_ERROR_ID+54); 
		if( ddrval != DDERR_WASSTILLDRAWING ) 
			return DD_initFail(hwndGame, DD_ERROR_ID+55); 
	} 
	m_dwDrawFlag = DDBLTFAST_SRCCOLORKEY; 
	return TRUE; 
} 
 
// set colorkey by given palette entry 
// must be used after Create() or LoadBitmap() 
// if used before, no effects 
// if in high/true color mode, this functions is obsolete 
// nColor	:	color key value 
// return	:	TRUE if successful 
BOOL CDDSurface::SetColorKeyPAL( BYTE nColor ) 
{ 
	HRESULT	ddrval; 
	if( !m_lpSurface ) 
	{ 
		OutputDebugString( "CDDSurface Error(40): Set color key before create surface!\n" ); 
		return FALSE; 
	} 
/* 
//	There is a bug here: 
//	a surface may not have palette of its own if created by Create()  
//	function. 
	if( !m_lpPalette ) 
	{ 
		OutputDebugString( "CDDSurface Error(41): Set color key before load palette!\n" ); 
		OutputDebugString( "This may usually occured when set program with high/true color!\n" ); 
		return FALSE; 
	} 
*/ 
    DDCOLORKEY          ddck; 
 
    ddck.dwColorSpaceLowValue  = nColor; 
    ddck.dwColorSpaceHighValue = ddck.dwColorSpaceLowValue; 
	while( 1 ) 
	{ 
	    ddrval = m_lpSurface->SetColorKey(DDCKEY_SRCBLT, &ddck); 
		if( ddrval == DD_OK ) 
			break; 
		if( ddrval == DDERR_SURFACELOST ) 
			if( !::DD_RestoreScreen() ) 
				return DD_initFail(hwndGame, DD_ERROR_ID+66); 
		if( ddrval != DDERR_WASSTILLDRAWING ) 
			return DD_initFail(hwndGame, DD_ERROR_ID+57); 
	} 
	m_dwDrawFlag = DDBLTFAST_SRCCOLORKEY; 
	return TRUE; 
} 
////////////////////////////// 
 
////////////////////////////// 
// release surface object 
void CDDSurface::Release() 
{ 
	if( DD_lpDD == NULL )	return; 
 
	if( m_lpSurface != NULL ) 
	{ 
		// delete surface object from global array 
		for( int i=0 ; iRelease(); 
		m_lpSurface = NULL; 
		m_lpPalette = NULL; 
	} 
 
	m_bCreated = FALSE; 
} 
 
// load a bitmap to an existing surface 
// strBitmap:	new bitmap file name 
// return value:	TRUE if succeeded 
BOOL CDDSurface::ReLoadBitmap( LPCTSTR strBitmap /*= NULL*/) 
{ 
	// store name of file or resource 
	if( strBitmap != NULL )	strcpy( m_strBitmap, strBitmap ); 
	m_bHasBitmap = TRUE; 
 
	// test if the palette pointer has been deleted 
	if( m_lpPalette != NULL )  
	{	 
		BOOL bSuccess = FALSE; 
		for ( int j=0 ; j< MAX_PALETTE ; j++ ) 
		{ 
			if( DD_lppPalettes[j] != NULL &&  
			m_lpPalette == DD_lppPalettes[j]->GetPalette() ) 
				bSuccess = TRUE; 
		} 
		if( bSuccess == FALSE ) m_lpPalette = NULL; 
	} 
 
	// set my palette 
//	if( m_lpPalette != NULL ) DD_lpDDSFront->SetPalette( m_lpPalette ); 
 
	// reload 
	if( ::DDReLoadBitmap(m_lpSurface, m_strBitmap) == NULL )  
		return DD_initFail(hwndGame, DD_ERROR_ID+67); 
	 
	// restore palette 
	DD_lpDDSFront->SetPalette( DD_lpDDPal ); 
	return TRUE; 
} 
 
// if surface is lost, run restore 
// there maybe a bug, if bitmap was loaded by Auto memory detect,  
// and load into video memory, but got surface lost, the bitmap may 
// not be reloaded. 
// return value	:	TRUE if it is succeeded 
BOOL CDDSurface::Restore( void ) 
{ 
	HRESULT ddrval; 
	ddrval = m_lpSurface->Restore(); 
	if( ddrval == DD_OK ) 
    { 
		// only if has bitmap loaded and is in video memory,  
		// should reload bitmap from file 
        if( m_bHasBitmap && m_bInVideo != FALSE ) 
		{ 
			// test if the palette pointer has been deleted 
			if( m_lpPalette != NULL )  
			{ 
				BOOL bSuccess = FALSE; 
				for ( int j=0 ; j< MAX_PALETTE ; j++ ) 
				{ 
					if( DD_lppPalettes[j] != NULL &&  
					m_lpPalette == DD_lppPalettes[j]->GetPalette() ) 
						bSuccess = TRUE; 
				} 
				if( bSuccess == FALSE ) m_lpPalette = NULL; 
			} 
			// set my palette  
			if( m_lpPalette != NULL )  
				DD_lpDDSFront->SetPalette( m_lpPalette ); 
 
			// reload 
			ddrval = ::DDReLoadBitmap(m_lpSurface, m_strBitmap); 
			if( ddrval != DD_OK )  
				return FALSE; 
			 
			// reset palette 
			DD_lpDDSFront->SetPalette( DD_lpDDPal ); 
 
		} 
		return TRUE; 
    } 
	return FALSE; 
} 
 
// MMX 
// blt my surface to front surface 
// 贴图直接到显示面上 
// ptDest		:	destination position, top-left 
// lpercSrc		:	source rectangle, full surface if it is NULL 
// return value	:	TRUE if succeeded 
BOOL CDDSurface::BltToFront( POINT ptDest, LPRECT lprcSrc ) 
{ 
    HRESULT ddrval; 
 
    while( 1 ) 
    { 
		ddrval = DD_lpDDSFront->BltFast( ptDest.x, ptDest.y, m_lpSurface, lprcSrc, m_dwDrawFlag ); 
        if( ddrval == DD_OK ) 
            break; 
#ifdef	_DEBUG 
		DD_getBltError( "CDDSurface::BltToFront", ddrval ); 
#endif 
        if( ddrval == DDERR_SURFACELOST ) 
            if( !::DD_RestoreScreen() ) 
                return FALSE; 
        if( ddrval != DDERR_WASSTILLDRAWING ) 
            return FALSE; 
    } 
	return TRUE; 
} 
 
// MMX 
// blt my surface to back surface 
// 贴图到背景面上 
// ptDest	:	destination position, top-left 
// lprcSrc	:	source rectangle, full surface if it is NULL 
// return value	:	TRUE if succeeded 
BOOL CDDSurface::BltToBack( POINT ptDest, LPRECT lprcSrc ) 
{ 
    HRESULT ddrval; 
 
    while( 1 ) 
    { 
		ddrval = DD_lpDDSBack->BltFast( ptDest.x, ptDest.y, m_lpSurface, lprcSrc, m_dwDrawFlag ); 
        if( ddrval == DD_OK ) 
            break; 
#ifdef	_DEBUG 
		DD_getBltError( "CDDSurface::BltToBack", ddrval ); 
#endif 
        if( ddrval == DDERR_SURFACELOST ) 
            if( !::DD_RestoreScreen() ) 
                return FALSE; 
        if( ddrval != DDERR_WASSTILLDRAWING ) 
            return FALSE; 
    } 
	return TRUE; 
} 
 
 
// blt given surface to my surface 
// if created by Create(), flags must be DDBLTFAST_NOCOLORKEY 
// if created by LoadBitmap( .., FALSE ), flags must be DDBLTFAST_NOCOLORKEY 
// if created by LoadBitmap( .., [TRUE]), flags must be DDBLTFAST_SRCCOLORKEY 
// x,y			:	Destinaiton position 
// lpsrcSurface	:	source surface 
// src			:	source rectangle, full surface if it is NULL 
// flags		:	blting flag, DDBLTFAST_NOCOLORKEY or DDBLTFAST_SRCCOLORKEY 
// return value	:	TRUE if succeeded 
BOOL CDDSurface::BltSurface( int x, int y,  
	LPDIRECTDRAWSURFACE2 lpsrcSurface, LPRECT src, DWORD dwflags ) 
{ 
    HRESULT ddrval; 
 
    while( 1 ) 
    { 
        ddrval = m_lpSurface->BltFast( x, y, lpsrcSurface, src, dwflags ); 
        if( ddrval == DD_OK ) 
            break; 
#ifdef	_DEBUG 
		DD_getBltError( "CDDSurface::BltSurface", ddrval ); 
#endif 
        if( ddrval == DDERR_SURFACELOST ) 
            if( !::DD_RestoreScreen() ) 
                return FALSE; 
        if( ddrval != DDERR_WASSTILLDRAWING ) 
            return FALSE; 
    } 
	return TRUE; 
} 
 
// fill black color to the surface 
// nColor		:	color index you want to fill, default is BLACK 
// pRect		:	region to fill, default is the entire surface 
// return value	:	TRUE if succeeded 
BOOL CDDSurface::Erase( int nColor/*=0*/, RECT *pRect/*=NULL*/ ) 
{ 
    DDBLTFX     ddbltfx; 
    HRESULT     ddrval; 
 
    // Erase the background 
    ddbltfx.dwSize = sizeof( ddbltfx ); 
    ddbltfx.dwFillColor = nColor; 
 
    while( 1 ) 
    { 
        ddrval = m_lpSurface->Blt( pRect, NULL, NULL, DDBLT_COLORFILL, &ddbltfx ); 
 
        if( ddrval == DD_OK ) 
        { 
            break; 
        } 
#ifdef	_DEBUG 
		DD_getBltError( "CDDSurface::Erase", ddrval ); 
#endif 
        if( ddrval == DDERR_SURFACELOST ) 
        { 
            if( !::DD_RestoreScreen() ) 
                return FALSE; 
        } 
        if( ddrval != DDERR_WASSTILLDRAWING ) 
        { 
            return FALSE; 
        } 
    } 
	return TRUE; 
} 
////////////////////////////// 
 
 
////////////////////////////// 
// class palette 
// contructor 
CDDPalette::CDDPalette() 
{ 
	m_lpPalette = NULL; 
	m_nType = -1; 
} 
 
// destructor 
CDDPalette::~CDDPalette() 
{ 
	Release(); 
} 
 
// create palette object from a bitmap 
// strBitmap	:	bitmap file name 
// bSet			:	TRUE if should set palette to  
//					the primary surface right after creation 
BOOL CDDPalette::LoadPalette( LPCTSTR strBitmap , BOOL bSet /*=FALSE*/) 
{ 
	strcpy( m_strPalette, strBitmap );	// save source bitmap file name 
	m_lpPalette = DDLoadPalette(DD_lpDD, strBitmap); 
	m_nType = DD_PALTYPE_BMP; 
	if( m_lpPalette )	 
	{ 
		// add to global palette array 
		BOOL bSuccess = FALSE; 
		for ( int j=0 ; j< MAX_PALETTE ; j++ ) 
		{ 
			if( DD_lppPalettes[j] == NULL ) 
			{ 
				DD_lppPalettes[j] = this; 
				DD_nPaletteCounter++; 
				bSuccess = TRUE; 
				break; 
			} 
		} 
		if( !bSuccess )	return DD_initFail(hwndGame, DD_ERROR_ID+60); 
		 
		// set palette to primary if you want 
		if( bSet )	 
			if( !SetPalette() ) 
				return DD_initFail(hwndGame, DD_ERROR_ID+62); 
		return TRUE; 
	} 
	return DD_initFail(hwndGame, DD_ERROR_ID+61); 
} 
 
// create palette object from a customed palette file 
// strPal		:	palette file name 
// bSet			:	TRUE if should set palette to  
//					the primary surface right after creation 
BOOL CDDPalette::LoadPalettePAL( LPCTSTR strPal , BOOL bSet /*=TRUE*/) 
{ 
    PALETTEENTRY        ape[256]; 
	strcpy( m_strPalette, strPal );	// save source bitmap file name 
     
	TY_LoadPaletteFromPAL( strPal, ape, 256 ); 
 
	// !Warning:  
	// you must use DDPCAPS_ALLOW256 if you want to use all the 256 palette entries 
	//|DDPCAPS_ALLOW256 
    DD_lpDD->CreatePalette(DDPCAPS_8BIT, ape, &m_lpPalette, NULL); 
 
	m_nType = DD_PALTYPE_PAL; 
 
	if( m_lpPalette )	 
	{ 
		// add to global palette array 
		BOOL bSuccess = FALSE; 
		for ( int j=0 ; j< MAX_PALETTE ; j++ ) 
		{ 
			if( DD_lppPalettes[j] == NULL ) 
			{ 
				DD_lppPalettes[j] = this; 
				DD_nPaletteCounter++; 
				bSuccess = TRUE; 
				break; 
			} 
		} 
		if( !bSuccess )	return DD_initFail(hwndGame, DD_ERROR_ID+63); 
		 
		// set palette to primary if you want 
		if( bSet )	 
			if( !SetPalette() ) 
				return DD_initFail(hwndGame, DD_ERROR_ID+64); 
		return TRUE; 
	} 
	return DD_initFail(hwndGame, DD_ERROR_ID+65); 
} 
 
// return		:	TRUE if successful 
BOOL CDDPalette::ReloadPalette() 
{ 
	int nType = m_nType; 
	Release(); 
	if( nType == DD_PALTYPE_PAL ) 
		return LoadPalettePAL( m_strPalette ); 
	else if( nType == DD_PALTYPE_BMP ) 
		return LoadPalette( m_strPalette ); 
	return FALSE; 
} 
 
// set palette to primary surface 
// if color depth is higher than 256, this may result an unkown error 
// return value	:	TRUE if succeeded 
BOOL CDDPalette::SetPalette( void ) 
{ 
	HRESULT	ddrval; 
 
	if ( m_lpPalette ) 
	{ 
		PALETTEENTRY pe[256]; 
		if(m_lpPalette->GetEntries( 0, 0, 256, pe ) != DD_OK) 
		{	// get source palette entries 
			OutputDebugString( "CDDPalette SetPalette Error(0): Cannot get entries!\n" ); 
			return	FALSE; 
		} 
		if(DD_lpDDPal->SetEntries( 0, 0, 256, pe ) != DD_OK) 
		{	// set to global palette object 
			OutputDebugString( "CDDPalette SetPalette Error(1): Cannot set entries!\n" ); 
			return	FALSE; 
		} 
 
		ddrval = DD_lpDDSFront->SetPalette( DD_lpDDPal ); 
		if( ddrval == DDERR_SURFACELOST ) 
		{ 
			if( DD_RestoreScreen() == FALSE ) 
			{ 
				return FALSE; 
			} 
			return TRUE; 
		} 
		else if( ddrval == DD_OK ) 
		{ 
			return TRUE; 
		} 
		else 
		{ 
			int nErr = -1; 
			switch( ddrval ) 
			{ 
			case	DDERR_GENERIC : 
				nErr = 0; 
				break; 
			case	DDERR_INVALIDOBJECT : 
				nErr = 1; 
				break; 
			case	DDERR_INVALIDPARAMS : 
				nErr = 2; 
				break; 
			case	DDERR_INVALIDSURFACETYPE : 
				nErr = 3; 
				break; 
			case	DDERR_NOEXCLUSIVEMODE : 
				nErr = 4; 
				break; 
			case	DDERR_NOPALETTEATTACHED : 
				nErr = 5; 
				break; 
			case	DDERR_NOPALETTEHW : 
				nErr = 6; 
				break; 
			case	DDERR_NOT8BITCOLOR : 
				nErr = 7; 
				break; 
			case	DDERR_SURFACELOST : 
				nErr = 8; 
				break; 
			case	DDERR_UNSUPPORTED : 
				nErr = 9; 
				break; 
			case	0x88760091: 
				// the palette cannot be initialized under high 
				// color or True color mode 
				nErr = 10; 
				break; 
			} 
			OutputDebugString( "CDDPalette SetPalette Error(2): Set palette error!\n" ); 
			return DD_initFail(hwndGame, DD_ERROR_ID+30+nErr); 
		} 
	} 
	OutputDebugString( "CDDPalette SetPalette Error(3): No palette pointer at all!\n" ); 
	return FALSE; 
} 
 
// release palette object 
void CDDPalette::Release( void ) 
{ 
	if( DD_lpDD == NULL )	return; 
 
	m_nType = -1; 
 
	if( m_lpPalette ) 
	{ 
		// reset current palette to NULL 
		if( m_lpPalette == DD_lpDDPal )	DD_lpDDPal = NULL; 
 
		// delete palette object from global array 
		for( int j=0 ; jRelease(); 
		m_lpPalette = NULL; 
	} 
} 
////////////////////////////// 
 
// local functions 
////////////////////////////// 
// get remained video memory, for debug version only 
void DD_testVideoMemory() 
{ 
	DDCAPS capsDRV, capsHEL; 
	capsDRV.dwSize = sizeof( DDCAPS ); 
	capsHEL.dwSize = sizeof( DDCAPS ); 
	if( DD_lpDD->GetCaps( &capsDRV, &capsHEL ) == DD_OK ) 
	{ 
		char strVideo[128]; 
		wsprintf( strVideo, "DD_testVideoMemory: %d, %d\n", capsDRV.dwVidMemTotal, capsDRV.dwVidMemFree );  
		//OutputDebugString( strVideo ); 
	} 
} 
 
// get blitter error when using BltFast() and Blt(),  
// not all the errors are here 
// ddrval	:	error number returned by BltFast() and Blt() 
void DD_getBltError( char * strHead, int ddrval ) 
{ 
	char msg[128]; 
	if( strlen( strHead ) > 65 ) return; 
 
	strcpy( msg, strHead ); 
	strcat( msg, ": " ); 
	switch( ddrval ) 
	{ 
	case	DDERR_EXCEPTION : 
		strcat( msg, "Exception" ); 
		break; 
	case	DDERR_GENERIC : 
		strcat( msg, "Generic" ); 
		break; 
	case	DDERR_INVALIDOBJECT : 
		strcat( msg, "Invalid Object" ); 
		break; 
	case	DDERR_INVALIDPARAMS : 
		strcat( msg, "Invalid Params" ); 
		break; 
	case	DDERR_INVALIDRECT : 
		strcat( msg, "Invalid Rect" ); 
		break; 
	case	DDERR_NOBLTHW : 
		strcat( msg, "No Blitter HardWare" ); 
		break; 
	case	DDERR_SURFACEBUSY : 
		strcat( msg, "Surface Busy" ); 
		break; 
	case	DDERR_SURFACELOST : 
		strcat( msg, "Surface Lost" ); 
		break; 
	case	DDERR_UNSUPPORTED : 
		strcat( msg, "This Operation is Unsupported" ); 
		break; 
	default: 
		strcat( msg, "I don\'t know this" ); 
	} 
	strcat( msg, " Error!\n" ); 
//	WriteLogFile( "DDApi.log", msg ); 
	OutputDebugString( msg ); 
} 
//////////////////////////////