|
|
/*==========================================================================
* * Copyright (c) 1995 - 1997 Microsoft Corporation. All Rights Reserved. * Copyright (C) 1994-1995 ATI Technologies Inc. All Rights Reserved. * * File: gfx.c * Content: graphics API * ***************************************************************************/ #include "foxbear.h"
GFX_BITMAP *lpVRAM;
static BOOL fForceRestore = FALSE;
/*****
BOOL gfxUpdate(GFX_HBM bm, IVideoSource *pSource) { GFX_BITMAP* pbm = (GFX_BITMAP*)bm; IDirectDrawSurface *pSurface = pbm->lpSurface;
if (!pSurface) { return FALSE; } if (SUCCEEDED(pSource->lpVtbl->SetSurface(pSource, pSurface))) { pSource->lpVtbl->Update(pSource, 0, NULL); } return TRUE; }
***/
/*
* gfxBlt */ BOOL gfxBlt(RECT *dst, GFX_HBM bm, POINT *src) { GFX_BITMAP* pbm = (GFX_BITMAP*)bm; HRESULT ddrval; DWORD bltflags; RECT rc; int x,y,dx,dy;
if( GameSize.cy == C_SCREEN_H ) { x = dst->left; y = dst->top; dx = dst->right - dst->left; dy = dst->bottom - dst->top; rc.left = src->x; rc.top = src->y; rc.right = rc.left + dx; rc.bottom = rc.top + dy; } else { x = MapX(dst->left); y = MapY(dst->top); dx = MapX(dst->right) - x; dy = MapY(dst->bottom) - y; rc.left = MapDX(src->x); rc.top = MapDY(src->y); rc.right = rc.left + dx; rc.bottom = rc.top + dy; }
if( dx == 0 || dy == 0 ) { return TRUE; }
if (pbm->lpSurface) { if( pbm->bTrans ) bltflags = bTransDest ? DDBLTFAST_DESTCOLORKEY : DDBLTFAST_SRCCOLORKEY; else bltflags = bTransDest ? DDBLTFAST_DESTCOLORKEY : DDBLTFAST_NOCOLORKEY;
ddrval = IDirectDrawSurface_BltFast( lpBackBuffer, x, y, pbm->lpSurface, &rc, bltflags | DDBLTFAST_WAIT);
if (ddrval != DD_OK) { Msg("BltFast failed err=%d", ddrval); } } else { DDBLTFX ddbltfx;
rc.left = x; rc.top = y; rc.right = rc.left + dx; rc.bottom = rc.top + dy;
ddbltfx.dwSize = sizeof( ddbltfx ); ddbltfx.dwFillColor = pbm->dwColor;
ddrval = IDirectDrawSurface_Blt( lpBackBuffer, // dest surface
&rc, // dest rect
NULL, // src surface
NULL, // src rect
DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); }
return TRUE;
} /* gfxBlt */
/*
* gfxCreateSolidColorBitmap */ GFX_HBM gfxCreateSolidColorBitmap(COLORREF rgb) { GFX_BITMAP *pvram;
pvram = MemAlloc( sizeof( *pvram ) );
if( pvram == NULL ) { return NULL; }
pvram->dwColor = DDColorMatch(lpBackBuffer, rgb); pvram->lpSurface = NULL; pvram->lpbi = NULL; pvram->bTrans = FALSE;
pvram->link = lpVRAM; lpVRAM = pvram;
return (GFX_HBM) pvram;
} /* gfxCreateSolidColorBitmap */
/*
* gfxCreateBitmap */ GFX_HBM gfxCreateVramBitmap(BITMAPINFOHEADER UNALIGNED *lpbi,BOOL bTrans) { GFX_BITMAP *pvram;
pvram = MemAlloc( sizeof( *pvram ) );
if( pvram == NULL ) { return NULL; } pvram->lpSurface = DDCreateSurface(MapRX(lpbi->biWidth), MapRY(lpbi->biHeight), FALSE, TRUE); pvram->lpbi = lpbi; pvram->dwColor = 0; pvram->bTrans = bTrans;
if( pvram->lpSurface == NULL ) { return NULL; }
pvram->link = lpVRAM; lpVRAM = pvram; gfxRestore((GFX_HBM) pvram);
return (GFX_HBM) pvram;
} /* gfxCreateVramBitmap */
/*
* gfxDestroyBitmap */ BOOL gfxDestroyBitmap ( GFX_HBM hbm ) { GFX_BITMAP *p = (GFX_BITMAP *)hbm;
if (hbm == NULL || hbm == GFX_TRUE) { return FALSE; }
if (p->lpSurface) { IDirectDrawSurface_Release(p->lpSurface); p->lpSurface = NULL; }
if (p->lpbi) { p->lpbi = NULL; }
MemFree((VOID *)p);
return TRUE;
} /* gfxDestroyBitmap */
/*
* gfxStretchBackBuffer() */ BOOL gfxStretchBackbuffer() { if (lpStretchBuffer) { IDirectDrawSurface_Blt( lpStretchBuffer, // dest surface
NULL, // dest rect (all of it)
lpBackBuffer, // src surface
&GameRect, // src rect
DDBLT_WAIT, NULL);
IDirectDrawSurface_Blt( lpBackBuffer, // dest surface
NULL, // dest rect (all of it)
lpStretchBuffer, // src surface
NULL, // src rect
DDBLT_WAIT, NULL); } else { IDirectDrawSurface_Blt( lpBackBuffer, // dest surface
NULL, // dest rect (all of it)
lpBackBuffer, // src surface
&GameRect, // src rect
DDBLT_WAIT, NULL); }
return TRUE;
} /* gfxStretchBackbuffer */
/*
* gfxFlip */ BOOL gfxFlip( void ) { HRESULT ddrval;
ddrval = IDirectDrawSurface_Flip( lpFrontBuffer, NULL, DDFLIP_WAIT ); if( ddrval != DD_OK ) { Msg( "Flip FAILED, rc=%08lx", ddrval ); return FALSE; } return TRUE;
} /* gfxFlip */
/*
* gfxUpdateWindow */ BOOL gfxUpdateWindow() { HRESULT ddrval;
ddrval = IDirectDrawSurface_Blt( lpFrontBuffer, // dest surface
&rcWindow, // dest rect
lpBackBuffer, // src surface
NULL, // src rect (all of it)
DDBLT_WAIT, NULL);
return ddrval == DD_OK;
} /* gfxUpdateWindow */
/*
* gfxSwapBuffers * * this is called when the game loop has rendered a frame into * the backbuffer, its goal is to display something for the user to see. * * there are four cases... * * Fullscreen: * we just call IDirectDrawSurface::Flip(lpFrontBuffer) * being careful to handle return code right. * * Fullscreen (stretched): * the game loop has rendered a frame 1/2 the display * size, we do a Blt to stretch the frame to the backbuffer * the we just call IDirectDrawSurface::Flip(lpFrontBuffer) * * Window mode (foreground palette): * in this case we call IDirectDrawSurface::Blt to copy * the back buffer to the window. * * Window mode (background palette): * in this case we are in a window, but we dont own the * palette. all our art was loaded to a specific palette * IDirectDrawSurface::Blt does not do color translation * we have a few options in this case... * * reload or remap the art to the the current palette * (we can do this easily with a GetDC, StetchDIBits) * FoxBear has *alot* of art, so this would be too slow. * * use GDI to draw the backbuffer, GDI will handle * the color conversion so things will look correct. * * pause the game (this is what we do so this function * will never be called) * */ BOOL gfxSwapBuffers( void ) { if( bFullscreen ) { if( bStretch ) { gfxStretchBackbuffer(); }
if (nBufferCount > 1) return gfxFlip(); else return TRUE; } else { return gfxUpdateWindow(); }
} /* gfxSwapBuffers */
/*
* gfxBegin */ GFX_HBM gfxBegin( void ) { if( !DDEnable() ) { return NULL; }
if( !DDCreateFlippingSurface() ) { DDDisable(TRUE); return NULL; } Splash();
return GFX_TRUE;
} /* gfxBegin */
/*
* gfxEnd */ BOOL gfxEnd ( GFX_HBM hbm ) { GFX_BITMAP *curr; GFX_BITMAP *next;
for( curr = lpVRAM; curr; curr=next ) { next = curr->link; gfxDestroyBitmap ((GFX_HBM)curr); }
lpVRAM = NULL;
return DDDisable(FALSE);
return TRUE;
} /* gfxEnd */
/*
* gfxRestore * * restore the art when one or more surfaces are lost */ BOOL gfxRestore(GFX_HBM bm) { GFX_BITMAP *pbm = (GFX_BITMAP*)bm; HRESULT ddrval; HDC hdc; LPVOID lpBits; RGBQUAD *prgb; int i,w,h; RECT rc;
struct { BITMAPINFOHEADER bi; RGBQUAD ct[256]; } dib;
IDirectDrawSurface *pdds = pbm->lpSurface; BITMAPINFOHEADER UNALIGNED *pbi = pbm->lpbi;
if (pdds == NULL) return TRUE;
if (IDirectDrawSurface_Restore(pdds) != DD_OK) return FALSE;
if (pbi == NULL) return TRUE;
//
// in 8bbp mode if we get switched away from while loading
// (and palette mapping) our art, the colors will not be correct
// because some app may have changed the system palette.
//
// if we are in stress mode, just keep going. It is more important
// to make progress than to get the colors right.
//
if (!bFullscreen && GameBPP == 8 && GetForegroundWindow() != hWndMain && !bStress ) { Msg("gfxRestore: **** foreground window changed while loading art!"); fForceRestore = TRUE; PauseGame(); return FALSE; }
dib.bi = *pbi;
prgb = (RGBQUAD *)((LPBYTE)pbi + pbi->biSize); lpBits = (LPBYTE)(prgb + pbi->biClrUsed);
if( pbi->biClrUsed == 0 && pbi->biBitCount <= 8 ) { lpBits = (LPBYTE)(prgb + (1<<pbi->biBitCount)); }
w = MapRX(pbi->biWidth); h = MapRY(pbi->biHeight); /*
* hack to make sure fox off-white doesn't become * pure white (which is transparent) */ for( i=0; i<256; i++ ) { dib.ct[i] = prgb[i];
if( dib.ct[i].rgbRed == 0xff && dib.ct[i].rgbGreen == 0xff && dib.ct[i].rgbBlue == 224 ) { dib.ct[i].rgbBlue = 0x80; } else if( dib.ct[i].rgbRed == 251 && dib.ct[i].rgbGreen == 243 && dib.ct[i].rgbBlue == 234 ) { dib.ct[i].rgbBlue = 0x80; } }
/*
* if we are in 8bit mode we know the palette is 332 we can * do the mapping our self. * * NOTE we can only do this in fullscreen mode * in windowed mode, we have to share the palette with * the window manager and we dont get all of the colors * in the order we assume. * */ if (bFullscreen && GameBPP == pbi->biBitCount && GameBPP == 8 ) { BYTE xlat332[256]; DDSURFACEDESC ddsd; int x,y,dib_pitch; BYTE *src, *dst; BOOL stretch; IDirectDrawSurface *pdds1; HDC hdc1;
stretch = w != pbi->biWidth || h != pbi->biHeight;
for( i=0;i<256;i++ ) { xlat332[i] = ((dib.ct[i].rgbRed >> 0) & 0xE0 ) | ((dib.ct[i].rgbGreen >> 3) & 0x1C ) | ((dib.ct[i].rgbBlue >> 6) & 0x03 ); }
/*
* if we are stretching copy into the back buffer * then use GDI to stretch later. */ if( stretch ) { pdds1 = lpBackBuffer; } else { pdds1 = pdds; }
ddsd.dwSize = sizeof(ddsd); ddrval = IDirectDrawSurface_Lock( pdds1, NULL, &ddsd, DDLOCK_WAIT, NULL);
if( ddrval == DD_OK ) { dib_pitch = (pbi->biWidth+3)&~3; src = (BYTE *)lpBits + dib_pitch * (pbi->biHeight-1); dst = (BYTE *)ddsd.lpSurface; for( y=0; y<(int)pbi->biHeight; y++ ) { for( x=0; x<(int)pbi->biWidth; x++ ) { dst[x] = xlat332[src[x]]; } dst += ddsd.lPitch; src -= dib_pitch; } IDirectDrawSurface_Unlock(pdds1, NULL); } else { Msg("Lock failed err=%d", ddrval); return FALSE; }
if( stretch ) { if( IDirectDrawSurface_GetDC(pdds,&hdc) == DD_OK ) { if( IDirectDrawSurface_GetDC(pdds1,&hdc1) == DD_OK ) { SetStretchBltMode(hdc, COLORONCOLOR); StretchBlt(hdc, 0, 0, w, h, hdc1, 0, 0, pbi->biWidth, pbi->biHeight, SRCCOPY); IDirectDrawSurface_ReleaseDC(pdds1,hdc1); } IDirectDrawSurface_ReleaseDC(pdds,hdc); } } } else if( IDirectDrawSurface_GetDC(pdds,&hdc) == DD_OK ) { SetStretchBltMode(hdc, COLORONCOLOR); StretchDIBits(hdc, 0, 0, w, h, 0, 0, pbi->biWidth, pbi->biHeight, lpBits, (BITMAPINFO *)&dib.bi, DIB_RGB_COLORS, SRCCOPY);
IDirectDrawSurface_ReleaseDC(pdds,hdc); }
/*
* show the art while loading... */ rc.left = rcWindow.left, rc.top = rcWindow.top + 20; rc.right = rc.left + w; rc.bottom = rc.top + h; IDirectDrawSurface_Blt(lpFrontBuffer, &rc, pdds, NULL, DDBLT_WAIT, NULL);
return TRUE;
} /* gfxRestore */
/*
* gfxRestoreAll * * restore the art when one or more surfaces are lost */ BOOL gfxRestoreAll() { GFX_BITMAP *curr; HWND hwndF = GetForegroundWindow();
Splash();
for( curr = lpVRAM; curr != NULL; curr = curr->link) { if (curr->lpSurface && (fForceRestore || IDirectDrawSurface_IsLost(curr->lpSurface) == DDERR_SURFACELOST)) { if( !gfxRestore(curr) ) { Msg( "gfxRestoreAll: ************ Restore FAILED!" ); return FALSE; } } }
DDClear(); fForceRestore = FALSE; return TRUE;
} /* gfxRestoreAll */
/*
* gfxFillBack */ void gfxFillBack( DWORD dwColor ) { DDBLTFX ddbltfx;
ddbltfx.dwSize = sizeof( ddbltfx ); ddbltfx.dwFillColor = dwColor;
IDirectDrawSurface_Blt( lpBackBuffer, // dest surface
NULL, // dest rect
NULL, // src surface
NULL, // src rect
DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);
} /* gfxFillBack */
|