Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

844 lines
21 KiB

/*==========================================================================
*
* Copyright (c) 1995 - 1997 Microsoft Corporation. All Rights Reserved.
* Copyright (C) 1994-1995 ATI Technologies Inc. All Rights Reserved.
*
* File: ddraw.c
* Content: Misc. Direct Draw access routines
*
***************************************************************************/
#include "foxbear.h"
BOOL bUseEmulation;
BOOL bUseSysMem;
int nBufferCount;
int CmdLineBufferCount;
BOOL bTransDest;
BOOL bColorFill;
HRESULT CALLBACK EnumDisplayModesCallback(LPDDSURFACEDESC pddsd, LPVOID Context);
/*
* DDEnable
*/
BOOL DDEnable( void )
{
LPDIRECTDRAW lpdd;
DDCAPS ddcaps;
HRESULT ddrval;
BOOL use_dest;
nBufferCount = GetProfileInt( "FoxBear", "buffers", CmdLineBufferCount);
bUseEmulation = GetProfileInt( "FoxBear", "use_emulation", bUseEmulation);
bUseSysMem = GetProfileInt( "FoxBear", "sysmem", 0);
use_dest = GetProfileInt( "FoxBear", "use_dest", 0 );
if (lpDD == NULL)
{
if( bUseEmulation )
{
ddrval = DirectDrawCreate( (LPVOID) DDCREATE_EMULATIONONLY, &lpdd, NULL );
}
else
{
ddrval = DirectDrawCreate( NULL, &lpdd, NULL );
}
}
else
{
lpdd = lpDD;
ddrval = DD_OK;
}
if( ddrval != DD_OK )
{
Msg("DirectDrawCreate failed err=%d", ddrval);
goto error;
}
/*
* grab exclusive mode if we are going to run as fullscreen
* otherwise grab normal mode.
*/
if (lpDD == NULL)
{
NumModes = 0;
if (bFullscreen)
{
ddrval = IDirectDraw_SetCooperativeLevel( lpdd, hWndMain,
DDSCL_ALLOWMODEX |
DDSCL_EXCLUSIVE |
DDSCL_FULLSCREEN );
// in fullscreen mode, enumeratte the available modes
IDirectDraw_EnumDisplayModes(lpdd, 0, NULL, 0, EnumDisplayModesCallback);
}
else
{
ddrval = IDirectDraw_SetCooperativeLevel( lpdd, hWndMain,
DDSCL_NORMAL );
// in normal windowed mode, just add some "stock" window
// sizes
ModeList[NumModes].w = 320;
ModeList[NumModes].h = 200;
NumModes++;
ModeList[NumModes].w = 320;
ModeList[NumModes].h = 240;
NumModes++;
ModeList[NumModes].w = 512;
ModeList[NumModes].h = 384;
NumModes++;
ModeList[NumModes].w = 640;
ModeList[NumModes].h = 400;
NumModes++;
ModeList[NumModes].w = 640;
ModeList[NumModes].h = 480;
NumModes++;
}
if( ddrval != DD_OK )
{
Msg("SetCooperativeLevel failed err=%d", ddrval);
goto error;
}
}
if (bFullscreen)
{
Msg("SetDisplayMode %d %d %d",GameMode.cx,GameMode.cy, GameBPP);
ddrval = IDirectDraw_SetDisplayMode( lpdd,
GameMode.cx, GameMode.cy, GameBPP);
if (ddrval != DD_OK && (GameMode.cx != 640 || GameMode.cy != 480))
{
Msg( "cant set mode trying 640x480" );
GameMode.cx = 640;
GameMode.cy = 480;
GameSize = GameMode;
ddrval = IDirectDraw_SetDisplayMode( lpdd,
GameMode.cx, GameMode.cy, GameBPP);
}
if (ddrval != DD_OK && GameBPP != 8)
{
Msg( "cant set mode trying 640x480x8" );
GameBPP = 8;
ddrval = IDirectDraw_SetDisplayMode( lpdd,
GameMode.cx, GameMode.cy, GameBPP);
}
if (ddrval != DD_OK && GameBPP != 16)
{
Msg( "cant set mode trying 640x480x16" );
GameBPP = 16;
ddrval = IDirectDraw_SetDisplayMode( lpdd,
GameMode.cx, GameMode.cy, GameBPP);
}
if( ddrval != DD_OK )
{
Msg("SetMode failed err=%d", ddrval);
goto error;
}
}
else
{
RECT rcWork;
RECT rc;
HDC hdc;
DWORD dwStyle;
//
// when in rome (I mean when in windows) we should use the
// current mode
//
hdc = GetDC(NULL);
GameBPP = GetDeviceCaps(hdc, PLANES) * GetDeviceCaps(hdc, BITSPIXEL);
ReleaseDC(NULL, hdc);
//
// if we are still a WS_POPUP window we should convert to a
// normal app window so we look like a windows app.
//
dwStyle = GetWindowStyle(hWndMain);
dwStyle &= ~WS_POPUP;
dwStyle |= WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX;
SetWindowLong(hWndMain, GWL_STYLE, dwStyle);
if (bStretch)
SetRect(&rc, 0, 0, GameMode.cx*2, GameMode.cy*2);
else
SetRect(&rc, 0, 0, GameMode.cx, GameMode.cy);
AdjustWindowRectEx(&rc,
GetWindowStyle(hWndMain),
GetMenu(hWndMain) != NULL,
GetWindowExStyle(hWndMain));
SetWindowPos(hWndMain, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
SetWindowPos(hWndMain, HWND_NOTOPMOST, 0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
//
// make sure our window does not hang outside of the work area
// this will make people who have the tray on the top or left
// happy.
//
SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWork, 0);
GetWindowRect(hWndMain, &rc);
if (rc.left < rcWork.left) rc.left = rcWork.left;
if (rc.top < rcWork.top) rc.top = rcWork.top;
SetWindowPos(hWndMain, NULL, rc.left, rc.top, 0, 0,
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
}
/*
* check capabilites
*/
ddcaps.dwSize = sizeof( ddcaps );
ddrval = IDirectDraw_GetCaps( lpdd, &ddcaps, NULL );
if( ddrval != DD_OK )
{
Msg("GetCaps failed err=%d", ddrval);
goto error;
}
if( ddcaps.dwCaps & DDCAPS_NOHARDWARE )
{
Msg( "No hardware support at all" );
}
if( ddcaps.dwCaps & DDCAPS_BLTCOLORFILL )
{
bColorFill = TRUE;
Msg( "Device supports color fill" );
}
else
{
bColorFill = FALSE;
Msg( "Device does not support color fill" );
}
/*
* default to double buffered on 1mb, triple buffered
* on > 1mb
*/
if (nBufferCount == 0)
{
if( ddcaps.dwVidMemTotal <= 1024L*1024L*(GameBPP/8) ||
GameMode.cx > 640 )
{
Msg("double buffering (not enough memory)");
nBufferCount = 2;
}
else
{
Msg("triple buffering");
nBufferCount = 3;
}
}
if( ddcaps.dwCaps & DDCAPS_COLORKEY )
{
if( ddcaps.dwCKeyCaps & DDCKEYCAPS_SRCBLT )
{
Msg( "Can do Src colorkey in hardware" );
}
if( ddcaps.dwCKeyCaps & DDCKEYCAPS_DESTBLT )
{
Msg( "Can do Dest colorkey in hardware" );
if( use_dest || !(ddcaps.dwCKeyCaps & DDCKEYCAPS_SRCBLT) )
{
/*
* since direct draw doesn't support
* destination color key in emulation, only
* use it if there is enough vram ...
*/
if( ddcaps.dwVidMemTotal >= 2 * 1024L*1024L*(GameBPP/8) )
{
Msg( "Using destination color key" );
bTransDest = TRUE;
}
}
}
}
else
{
Msg( "Can't do color key in hardware!" );
}
lpDD = lpdd;
return TRUE;
error:
return FALSE;
} /* DDEnable */
/*
* DDDisable
*/
BOOL DDDisable( BOOL fFinal )
{
if( lpClipper )
{
IDirectDrawClipper_Release(lpClipper);
lpClipper = NULL;
}
if( lpBackBuffer )
{
IDirectDrawSurface_Release(lpBackBuffer);
lpBackBuffer = NULL;
}
if( lpFrontBuffer )
{
IDirectDrawSurface_Release(lpFrontBuffer);
lpFrontBuffer = NULL;
}
if( lpStretchBuffer )
{
IDirectDrawSurface_Release(lpStretchBuffer);
lpStretchBuffer = NULL;
}
//
// fFinal is TRUE when the app is exiting, FALSE if we are
// just seting a new game size..
//
if ( fFinal )
{
if( lpDD != NULL )
{
IDirectDraw_Release( lpDD );
lpDD = NULL;
}
}
return TRUE;
}
/*
* DDClear
*
* clear the front buffer and all backbuffers.
*/
BOOL DDClear( void )
{
DDBLTFX ddbltfx;
int i;
HRESULT ddrval;
UpdateWindow(hWndMain);
ddbltfx.dwSize = sizeof( ddbltfx );
ddbltfx.dwFillColor = DDColorMatch(lpBackBuffer, RGB(0, 0, 200));
if (bFullscreen)
{
/*
* do it for all buffers, we either have 1 or 2 back buffers
* make sure we get them all, 4 is plenty!
*/
for( i=0; i<4; i++ )
{
ddrval = IDirectDrawSurface_Blt(
lpBackBuffer, // dest surface
NULL, // dest rect
NULL, // src surface
NULL, // src rect
DDBLT_COLORFILL | DDBLT_WAIT,
&ddbltfx);
if( ddrval != DD_OK )
{
Msg("Fill failed ddrval =0x%08lX", ddrval);
return FALSE;
}
ddrval = IDirectDrawSurface_Flip(lpFrontBuffer, NULL, DDFLIP_WAIT);
if( ddrval != DD_OK )
{
Msg("Flip failed ddrval =0x%08lX", ddrval );
return FALSE;
}
}
}
else
{
ddrval = IDirectDrawSurface_Blt(
lpFrontBuffer, // dest surface
&rcWindow, // dest rect
NULL, // src surface
NULL, // src rect
DDBLT_COLORFILL | DDBLT_WAIT,
&ddbltfx);
if( ddrval != DD_OK )
{
Msg("Fill failed ddrval =0x%08lX", ddrval);
return FALSE;
}
}
return TRUE;
} /* DDClear */
/*
* DDCreateFlippingSurface
*
* create a FrontBuffer and a BackBuffer(s)
*
*/
BOOL DDCreateFlippingSurface( void )
{
DDPIXELFORMAT ddpf;
DDSURFACEDESC ddsd;
HRESULT ddrval;
DDSCAPS ddscaps;
DDCAPS ddcaps;
ddcaps.dwSize = sizeof( ddcaps );
if( IDirectDraw_GetCaps( lpDD, &ddcaps, NULL ) != DD_OK )
return FALSE;
/*
* fill in surface desc:
* want a primary surface with 2 back buffers
*/
ZeroMemory( &ddsd, sizeof( ddsd ) );
ddsd.dwSize = sizeof( ddsd );
if (bFullscreen && nBufferCount > 1)
{
//
// fullscreen case, create a primary (ie front) and
// either 1 or 2 back buffers
//
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.dwBackBufferCount = nBufferCount-1;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
DDSCAPS_FLIP | DDSCAPS_COMPLEX;
OutputDebugString("Creating multiple backbuffer primary\n\r");
ddrval = IDirectDraw_CreateSurface( lpDD, &ddsd, &lpFrontBuffer, NULL );
if( ddrval != DD_OK )
{
Msg( "CreateSurface FAILED! %08lx", ddrval );
return FALSE;
}
/*
* go find the back buffer
*/
ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
ddrval = IDirectDrawSurface_GetAttachedSurface(
lpFrontBuffer,
&ddscaps,
&lpBackBuffer );
if( ddrval != DD_OK )
{
Msg( "GetAttachedSurface failed! err=%d",ddrval );
return FALSE;
}
/*
* if we are stretching create a buffer to stretch into
*
* NOTE we always make this buffer in system memory because
* we render to the backbuffer (in VRAM) at half the size
* now we need to stretch into the backbuffer. we could just
* do a VRAM->VRAM stretch, but this is REAL REAL REAL slow on
* some cards (banked cards..)
*/
if( bStretch && (ddcaps.dwCaps & DDCAPS_BANKSWITCHED) )
{
Msg( "On bank switched hardware, creating stretch buffer" );
lpStretchBuffer = DDCreateSurface( GameSize.cx, GameSize.cy,
TRUE, FALSE );
}
}
else if (bFullscreen && nBufferCount == 1)
{
ddsd.dwFlags = DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
OutputDebugString("Creating no backbuffer primary\n\r");
ddrval = IDirectDraw_CreateSurface( lpDD, &ddsd, &lpFrontBuffer, NULL );
if( ddrval != DD_OK )
{
Msg( "CreateSurface FAILED! %08lx", ddrval );
return FALSE;
}
IDirectDrawSurface_AddRef(lpFrontBuffer);
lpBackBuffer = lpFrontBuffer;
}
else
{
//
// window case, create the primary surface
// and create a backbuffer in offscreen memory.
//
ddsd.dwFlags = DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
ddrval = IDirectDraw_CreateSurface( lpDD, &ddsd, &lpFrontBuffer, NULL );
if( ddrval != DD_OK )
{
Msg( "CreateSurface FAILED! %08lx", ddrval );
return FALSE;
}
lpBackBuffer = DDCreateSurface( GameSize.cx, GameSize.cy, FALSE, FALSE );
if( lpBackBuffer == NULL )
{
Msg( "Cant create the backbuffer" );
return FALSE;
}
//
// now create a DirectDrawClipper object.
//
ddrval = IDirectDraw_CreateClipper(lpDD, 0, &lpClipper, NULL);
if( ddrval != DD_OK )
{
Msg("Cant create clipper");
return FALSE;
}
ddrval = IDirectDrawClipper_SetHWnd(lpClipper, 0, hWndMain);
if( ddrval != DD_OK )
{
Msg("Cant set clipper window handle");
return FALSE;
}
ddrval = IDirectDrawSurface_SetClipper(lpFrontBuffer, lpClipper);
if( ddrval != DD_OK )
{
Msg("Cant attach clipper to front buffer");
return FALSE;
}
}
/*
* init the color key
*/
ddpf.dwSize = sizeof(ddpf);
IDirectDrawSurface_GetPixelFormat(lpFrontBuffer, &ddpf);
/*
* we use white as the color key, if we are in a 8bpp mode, we know
* what white is (because we use a 332 palette) if we are not in a
* a 8bpp mode we dont know what white is and we need to figure it
* out from the device (remember 16bpp comes in two common flavors
* 555 and 565). if we wanted to any random color as the color key
* we would call DDColorMatch (see below) to convert a RGB into a
* physical color.
*/
if (ddpf.dwRGBBitCount == 8)
dwColorKey = 0xff;
else
dwColorKey = ddpf.dwRBitMask | ddpf.dwGBitMask | ddpf.dwBBitMask;
Msg("dwColorKey = 0x%08lX", dwColorKey);
if( bTransDest )
{
DDCOLORKEY ddck;
ddck.dwColorSpaceLowValue = dwColorKey;
ddck.dwColorSpaceHighValue = dwColorKey;
IDirectDrawSurface_SetColorKey( lpBackBuffer, DDCKEY_DESTBLT, &ddck);
}
return TRUE;
} /* DDCreateFlippingSurface */
/*
* DDCreateSurface
*/
LPDIRECTDRAWSURFACE DDCreateSurface(
DWORD width,
DWORD height,
BOOL sysmem,
BOOL trans )
{
DDSURFACEDESC ddsd;
HRESULT ddrval;
DDCOLORKEY ddck;
LPDIRECTDRAWSURFACE psurf;
/*
* fill in surface desc
*/
memset( &ddsd, 0, sizeof( ddsd ) );
ddsd.dwSize = sizeof( ddsd );
ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT |DDSD_WIDTH;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
if( sysmem || bUseSysMem )
{
ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
}
ddsd.dwHeight = height;
ddsd.dwWidth = width;
ddrval = IDirectDraw_CreateSurface( lpDD, &ddsd, &psurf, NULL );
/*
* set the color key for this bitmap
*/
if( ddrval == DD_OK )
{
if( trans && !bTransDest )
{
ddck.dwColorSpaceLowValue = dwColorKey;
ddck.dwColorSpaceHighValue = dwColorKey;
IDirectDrawSurface_SetColorKey( psurf, DDCKEY_SRCBLT, &ddck);
}
}
else
{
Msg( "CreateSurface FAILED, rc = %ld", (DWORD) LOWORD( ddrval ) );
psurf = NULL;
}
return psurf;
} /* DDCreateSurface */
DWORD DDColorMatch(IDirectDrawSurface *pdds, COLORREF rgb)
{
COLORREF rgbT;
HDC hdc;
DWORD dw = CLR_INVALID;
DDSURFACEDESC ddsd;
HRESULT hres;
if (IDirectDrawSurface_GetDC(pdds, &hdc) == DD_OK)
{
rgbT = GetPixel(hdc, 0, 0);
SetPixel(hdc, 0, 0, rgb);
IDirectDrawSurface_ReleaseDC(pdds, hdc);
}
ddsd.dwSize = sizeof(ddsd);
hres = IDirectDrawSurface_Lock(
pdds, NULL, &ddsd, DDLOCK_WAIT, NULL);
if (hres == DD_OK)
{
dw = *(DWORD *)ddsd.lpSurface;
if(ddsd.ddpfPixelFormat.dwRGBBitCount != 32)
dw &= (1 << ddsd.ddpfPixelFormat.dwRGBBitCount)-1;
IDirectDrawSurface_Unlock(pdds, NULL);
}
else
{
IDirectDrawSurface_GetSurfaceDesc(pdds,&ddsd);
if(ddsd.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
Msg("Failed to lock Primary Surface!");
else
Msg("Failed to lock NON-PRIMARY Surface!");
}
if (IDirectDrawSurface_GetDC(pdds, &hdc) == DD_OK)
{
SetPixel(hdc, 0, 0, rgbT);
IDirectDrawSurface_ReleaseDC(pdds, hdc);
}
return dw;
}
/*
* ReadPalFile
*
* Create a DirectDrawPalette from a palette file
*
* if the palette files cant be found, make a default 332 palette
*/
LPDIRECTDRAWPALETTE ReadPalFile( char *fname )
{
int i;
int fh;
HRESULT ddrval;
IDirectDrawPalette *ppal;
struct {
DWORD dwRiff;
DWORD dwFileSize;
DWORD dwPal;
DWORD dwData;
DWORD dwDataSize;
WORD palVersion;
WORD palNumEntries;
PALETTEENTRY ape[256];
} pal;
pal.dwRiff = 0;
if (fname)
{
fh = _lopen( fname, OF_READ);
if (fh != -1)
{
_lread(fh, &pal, sizeof(pal));
_lclose(fh);
}
}
/*
* if the file is not a palette file, or does not exist
* default to a 332 palette
*/
if (pal.dwRiff != 0x46464952 || // 'RIFF'
pal.dwPal != 0x204C4150 || // 'PAL '
pal.dwData != 0x61746164 || // 'data'
pal.palVersion != 0x0300 ||
pal.palNumEntries > 256 ||
pal.palNumEntries < 1)
{
Msg("Can't open palette file, using default 332.");
for( i=0; i<256; i++ )
{
pal.ape[i].peRed = (BYTE)(((i >> 5) & 0x07) * 255 / 7);
pal.ape[i].peGreen = (BYTE)(((i >> 2) & 0x07) * 255 / 7);
pal.ape[i].peBlue = (BYTE)(((i >> 0) & 0x03) * 255 / 3);
pal.ape[i].peFlags = (BYTE)0;
}
}
ddrval = IDirectDraw_CreatePalette(
lpDD,
DDPCAPS_8BIT,
pal.ape,
&ppal,
NULL );
return ppal;
} /* ReadPalFile */
/*
* Splash
*
* Draw a splash screen during startup
* NOTE the screen has been cleared in DDCreateFlippingSurface
*/
void Splash( void )
{
HDC hdc;
HRESULT err;
DDClear();
if ((err = IDirectDrawSurface_GetDC(lpFrontBuffer, &hdc)) == DD_OK)
{
char *szMsg = "FoxBear is loading.......please wait.";
SetTextColor(hdc, RGB(255,255,255));
SetBkMode(hdc, TRANSPARENT);
TextOut(hdc, rcWindow.left, rcWindow.top, szMsg, lstrlen(szMsg));
IDirectDrawSurface_ReleaseDC(lpFrontBuffer, hdc);
}
else
{
Msg("GetDC failed! 0x%x",err);
}
} /* Splash */
/*
* MEMORY ALLOCATION ROUTINES...
*/
/*
* MemAlloc
*/
LPVOID MemAlloc( UINT size )
{
LPVOID ptr;
ptr = LocalAlloc( LPTR, size );
return ptr;
} /* MemAlloc */
/*
* CMemAlloc
*/
LPVOID CMemAlloc( UINT cnt, UINT isize )
{
DWORD size;
LPVOID ptr;
size = cnt * isize;
ptr = LocalAlloc( LPTR, size );
return ptr;
} /* CMemAlloc */
/*
* MemFree
*/
void MemFree( LPVOID ptr )
{
if( ptr != NULL )
{
LocalFree( ptr );
}
} /* MemFree */
HRESULT CALLBACK EnumDisplayModesCallback(LPDDSURFACEDESC pddsd, LPVOID Context)
{
Msg("Mode: %dx%dx%d", pddsd->dwWidth, pddsd->dwHeight,pddsd->ddpfPixelFormat.dwRGBBitCount);
if(
(ModeList[NumModes-1].w == (int)pddsd->dwWidth)&&
(ModeList[NumModes-1].h == (int)pddsd->dwHeight)&&
(ModeList[NumModes-1].bpp == (int)pddsd->ddpfPixelFormat.dwRGBBitCount)
)
return DDENUMRET_OK;
ModeList[NumModes].w = pddsd->dwWidth;
ModeList[NumModes].h = pddsd->dwHeight;
ModeList[NumModes].bpp = pddsd->ddpfPixelFormat.dwRGBBitCount;
NumModes++;
return DDENUMRET_OK;
}