|
|
/*==========================================================================
* * 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; }
|