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.

619 lines
15 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (c) 1995 - 1997 Microsoft Corporation. All Rights Reserved.
  4. * Copyright (C) 1994-1995 ATI Technologies Inc. All Rights Reserved.
  5. *
  6. * File: gfx.c
  7. * Content: graphics API
  8. *
  9. ***************************************************************************/
  10. #include "foxbear.h"
  11. GFX_BITMAP *lpVRAM;
  12. static BOOL fForceRestore = FALSE;
  13. /*****
  14. BOOL gfxUpdate(GFX_HBM bm, IVideoSource *pSource)
  15. {
  16. GFX_BITMAP* pbm = (GFX_BITMAP*)bm;
  17. IDirectDrawSurface *pSurface = pbm->lpSurface;
  18. if (!pSurface) {
  19. return FALSE;
  20. }
  21. if (SUCCEEDED(pSource->lpVtbl->SetSurface(pSource, pSurface))) {
  22. pSource->lpVtbl->Update(pSource, 0, NULL);
  23. }
  24. return TRUE;
  25. }
  26. ***/
  27. /*
  28. * gfxBlt
  29. */
  30. BOOL gfxBlt(RECT *dst, GFX_HBM bm, POINT *src)
  31. {
  32. GFX_BITMAP* pbm = (GFX_BITMAP*)bm;
  33. HRESULT ddrval;
  34. DWORD bltflags;
  35. RECT rc;
  36. int x,y,dx,dy;
  37. if( GameSize.cy == C_SCREEN_H )
  38. {
  39. x = dst->left;
  40. y = dst->top;
  41. dx = dst->right - dst->left;
  42. dy = dst->bottom - dst->top;
  43. rc.left = src->x;
  44. rc.top = src->y;
  45. rc.right = rc.left + dx;
  46. rc.bottom = rc.top + dy;
  47. }
  48. else
  49. {
  50. x = MapX(dst->left);
  51. y = MapY(dst->top);
  52. dx = MapX(dst->right) - x;
  53. dy = MapY(dst->bottom) - y;
  54. rc.left = MapDX(src->x);
  55. rc.top = MapDY(src->y);
  56. rc.right = rc.left + dx;
  57. rc.bottom = rc.top + dy;
  58. }
  59. if( dx == 0 || dy == 0 )
  60. {
  61. return TRUE;
  62. }
  63. if (pbm->lpSurface)
  64. {
  65. if( pbm->bTrans )
  66. bltflags = bTransDest ? DDBLTFAST_DESTCOLORKEY : DDBLTFAST_SRCCOLORKEY;
  67. else
  68. bltflags = bTransDest ? DDBLTFAST_DESTCOLORKEY : DDBLTFAST_NOCOLORKEY;
  69. ddrval = IDirectDrawSurface_BltFast(
  70. lpBackBuffer, x, y,
  71. pbm->lpSurface, &rc, bltflags | DDBLTFAST_WAIT);
  72. if (ddrval != DD_OK)
  73. {
  74. Msg("BltFast failed err=%d", ddrval);
  75. }
  76. }
  77. else
  78. {
  79. DDBLTFX ddbltfx;
  80. rc.left = x;
  81. rc.top = y;
  82. rc.right = rc.left + dx;
  83. rc.bottom = rc.top + dy;
  84. ddbltfx.dwSize = sizeof( ddbltfx );
  85. ddbltfx.dwFillColor = pbm->dwColor;
  86. ddrval = IDirectDrawSurface_Blt(
  87. lpBackBuffer, // dest surface
  88. &rc, // dest rect
  89. NULL, // src surface
  90. NULL, // src rect
  91. DDBLT_COLORFILL | DDBLT_WAIT,
  92. &ddbltfx);
  93. }
  94. return TRUE;
  95. } /* gfxBlt */
  96. /*
  97. * gfxCreateSolidColorBitmap
  98. */
  99. GFX_HBM gfxCreateSolidColorBitmap(COLORREF rgb)
  100. {
  101. GFX_BITMAP *pvram;
  102. pvram = MemAlloc( sizeof( *pvram ) );
  103. if( pvram == NULL )
  104. {
  105. return NULL;
  106. }
  107. pvram->dwColor = DDColorMatch(lpBackBuffer, rgb);
  108. pvram->lpSurface = NULL;
  109. pvram->lpbi = NULL;
  110. pvram->bTrans = FALSE;
  111. pvram->link = lpVRAM;
  112. lpVRAM = pvram;
  113. return (GFX_HBM) pvram;
  114. } /* gfxCreateSolidColorBitmap */
  115. /*
  116. * gfxCreateBitmap
  117. */
  118. GFX_HBM gfxCreateVramBitmap(BITMAPINFOHEADER UNALIGNED *lpbi,BOOL bTrans)
  119. {
  120. GFX_BITMAP *pvram;
  121. pvram = MemAlloc( sizeof( *pvram ) );
  122. if( pvram == NULL )
  123. {
  124. return NULL;
  125. }
  126. pvram->lpSurface = DDCreateSurface(MapRX(lpbi->biWidth),
  127. MapRY(lpbi->biHeight), FALSE, TRUE);
  128. pvram->lpbi = lpbi;
  129. pvram->dwColor = 0;
  130. pvram->bTrans = bTrans;
  131. if( pvram->lpSurface == NULL )
  132. {
  133. return NULL;
  134. }
  135. pvram->link = lpVRAM;
  136. lpVRAM = pvram;
  137. gfxRestore((GFX_HBM) pvram);
  138. return (GFX_HBM) pvram;
  139. } /* gfxCreateVramBitmap */
  140. /*
  141. * gfxDestroyBitmap
  142. */
  143. BOOL gfxDestroyBitmap ( GFX_HBM hbm )
  144. {
  145. GFX_BITMAP *p = (GFX_BITMAP *)hbm;
  146. if (hbm == NULL || hbm == GFX_TRUE)
  147. {
  148. return FALSE;
  149. }
  150. if (p->lpSurface)
  151. {
  152. IDirectDrawSurface_Release(p->lpSurface);
  153. p->lpSurface = NULL;
  154. }
  155. if (p->lpbi)
  156. {
  157. p->lpbi = NULL;
  158. }
  159. MemFree((VOID *)p);
  160. return TRUE;
  161. } /* gfxDestroyBitmap */
  162. /*
  163. * gfxStretchBackBuffer()
  164. */
  165. BOOL gfxStretchBackbuffer()
  166. {
  167. if (lpStretchBuffer)
  168. {
  169. IDirectDrawSurface_Blt(
  170. lpStretchBuffer, // dest surface
  171. NULL, // dest rect (all of it)
  172. lpBackBuffer, // src surface
  173. &GameRect, // src rect
  174. DDBLT_WAIT,
  175. NULL);
  176. IDirectDrawSurface_Blt(
  177. lpBackBuffer, // dest surface
  178. NULL, // dest rect (all of it)
  179. lpStretchBuffer, // src surface
  180. NULL, // src rect
  181. DDBLT_WAIT,
  182. NULL);
  183. }
  184. else
  185. {
  186. IDirectDrawSurface_Blt(
  187. lpBackBuffer, // dest surface
  188. NULL, // dest rect (all of it)
  189. lpBackBuffer, // src surface
  190. &GameRect, // src rect
  191. DDBLT_WAIT,
  192. NULL);
  193. }
  194. return TRUE;
  195. } /* gfxStretchBackbuffer */
  196. /*
  197. * gfxFlip
  198. */
  199. BOOL gfxFlip( void )
  200. {
  201. HRESULT ddrval;
  202. ddrval = IDirectDrawSurface_Flip( lpFrontBuffer, NULL, DDFLIP_WAIT );
  203. if( ddrval != DD_OK )
  204. {
  205. Msg( "Flip FAILED, rc=%08lx", ddrval );
  206. return FALSE;
  207. }
  208. return TRUE;
  209. } /* gfxFlip */
  210. /*
  211. * gfxUpdateWindow
  212. */
  213. BOOL gfxUpdateWindow()
  214. {
  215. HRESULT ddrval;
  216. ddrval = IDirectDrawSurface_Blt(
  217. lpFrontBuffer, // dest surface
  218. &rcWindow, // dest rect
  219. lpBackBuffer, // src surface
  220. NULL, // src rect (all of it)
  221. DDBLT_WAIT,
  222. NULL);
  223. return ddrval == DD_OK;
  224. } /* gfxUpdateWindow */
  225. /*
  226. * gfxSwapBuffers
  227. *
  228. * this is called when the game loop has rendered a frame into
  229. * the backbuffer, its goal is to display something for the user to see.
  230. *
  231. * there are four cases...
  232. *
  233. * Fullscreen:
  234. * we just call IDirectDrawSurface::Flip(lpFrontBuffer)
  235. * being careful to handle return code right.
  236. *
  237. * Fullscreen (stretched):
  238. * the game loop has rendered a frame 1/2 the display
  239. * size, we do a Blt to stretch the frame to the backbuffer
  240. * the we just call IDirectDrawSurface::Flip(lpFrontBuffer)
  241. *
  242. * Window mode (foreground palette):
  243. * in this case we call IDirectDrawSurface::Blt to copy
  244. * the back buffer to the window.
  245. *
  246. * Window mode (background palette):
  247. * in this case we are in a window, but we dont own the
  248. * palette. all our art was loaded to a specific palette
  249. * IDirectDrawSurface::Blt does not do color translation
  250. * we have a few options in this case...
  251. *
  252. * reload or remap the art to the the current palette
  253. * (we can do this easily with a GetDC, StetchDIBits)
  254. * FoxBear has *alot* of art, so this would be too slow.
  255. *
  256. * use GDI to draw the backbuffer, GDI will handle
  257. * the color conversion so things will look correct.
  258. *
  259. * pause the game (this is what we do so this function
  260. * will never be called)
  261. *
  262. */
  263. BOOL gfxSwapBuffers( void )
  264. {
  265. if( bFullscreen )
  266. {
  267. if( bStretch )
  268. {
  269. gfxStretchBackbuffer();
  270. }
  271. if (nBufferCount > 1)
  272. return gfxFlip();
  273. else
  274. return TRUE;
  275. }
  276. else
  277. {
  278. return gfxUpdateWindow();
  279. }
  280. } /* gfxSwapBuffers */
  281. /*
  282. * gfxBegin
  283. */
  284. GFX_HBM gfxBegin( void )
  285. {
  286. if( !DDEnable() )
  287. {
  288. return NULL;
  289. }
  290. if( !DDCreateFlippingSurface() )
  291. {
  292. DDDisable(TRUE);
  293. return NULL;
  294. }
  295. Splash();
  296. return GFX_TRUE;
  297. } /* gfxBegin */
  298. /*
  299. * gfxEnd
  300. */
  301. BOOL gfxEnd ( GFX_HBM hbm )
  302. {
  303. GFX_BITMAP *curr;
  304. GFX_BITMAP *next;
  305. for( curr = lpVRAM; curr; curr=next )
  306. {
  307. next = curr->link;
  308. gfxDestroyBitmap ((GFX_HBM)curr);
  309. }
  310. lpVRAM = NULL;
  311. return DDDisable(FALSE);
  312. return TRUE;
  313. } /* gfxEnd */
  314. /*
  315. * gfxRestore
  316. *
  317. * restore the art when one or more surfaces are lost
  318. */
  319. BOOL gfxRestore(GFX_HBM bm)
  320. {
  321. GFX_BITMAP *pbm = (GFX_BITMAP*)bm;
  322. HRESULT ddrval;
  323. HDC hdc;
  324. LPVOID lpBits;
  325. RGBQUAD *prgb;
  326. int i,w,h;
  327. RECT rc;
  328. struct {
  329. BITMAPINFOHEADER bi;
  330. RGBQUAD ct[256];
  331. } dib;
  332. IDirectDrawSurface *pdds = pbm->lpSurface;
  333. BITMAPINFOHEADER UNALIGNED *pbi = pbm->lpbi;
  334. if (pdds == NULL)
  335. return TRUE;
  336. if (IDirectDrawSurface_Restore(pdds) != DD_OK)
  337. return FALSE;
  338. if (pbi == NULL)
  339. return TRUE;
  340. //
  341. // in 8bbp mode if we get switched away from while loading
  342. // (and palette mapping) our art, the colors will not be correct
  343. // because some app may have changed the system palette.
  344. //
  345. // if we are in stress mode, just keep going. It is more important
  346. // to make progress than to get the colors right.
  347. //
  348. if (!bFullscreen &&
  349. GameBPP == 8 &&
  350. GetForegroundWindow() != hWndMain &&
  351. !bStress )
  352. {
  353. Msg("gfxRestore: **** foreground window changed while loading art!");
  354. fForceRestore = TRUE;
  355. PauseGame();
  356. return FALSE;
  357. }
  358. dib.bi = *pbi;
  359. prgb = (RGBQUAD *)((LPBYTE)pbi + pbi->biSize);
  360. lpBits = (LPBYTE)(prgb + pbi->biClrUsed);
  361. if( pbi->biClrUsed == 0 && pbi->biBitCount <= 8 )
  362. {
  363. lpBits = (LPBYTE)(prgb + (1<<pbi->biBitCount));
  364. }
  365. w = MapRX(pbi->biWidth);
  366. h = MapRY(pbi->biHeight);
  367. /*
  368. * hack to make sure fox off-white doesn't become
  369. * pure white (which is transparent)
  370. */
  371. for( i=0; i<256; i++ )
  372. {
  373. dib.ct[i] = prgb[i];
  374. if( dib.ct[i].rgbRed == 0xff &&
  375. dib.ct[i].rgbGreen == 0xff &&
  376. dib.ct[i].rgbBlue == 224 )
  377. {
  378. dib.ct[i].rgbBlue = 0x80;
  379. }
  380. else
  381. if( dib.ct[i].rgbRed == 251 &&
  382. dib.ct[i].rgbGreen == 243 &&
  383. dib.ct[i].rgbBlue == 234 )
  384. {
  385. dib.ct[i].rgbBlue = 0x80;
  386. }
  387. }
  388. /*
  389. * if we are in 8bit mode we know the palette is 332 we can
  390. * do the mapping our self.
  391. *
  392. * NOTE we can only do this in fullscreen mode
  393. * in windowed mode, we have to share the palette with
  394. * the window manager and we dont get all of the colors
  395. * in the order we assume.
  396. *
  397. */
  398. if (bFullscreen && GameBPP == pbi->biBitCount && GameBPP == 8 )
  399. {
  400. BYTE xlat332[256];
  401. DDSURFACEDESC ddsd;
  402. int x,y,dib_pitch;
  403. BYTE *src, *dst;
  404. BOOL stretch;
  405. IDirectDrawSurface *pdds1;
  406. HDC hdc1;
  407. stretch = w != pbi->biWidth || h != pbi->biHeight;
  408. for( i=0;i<256;i++ )
  409. {
  410. xlat332[i] =
  411. ((dib.ct[i].rgbRed >> 0) & 0xE0 ) |
  412. ((dib.ct[i].rgbGreen >> 3) & 0x1C ) |
  413. ((dib.ct[i].rgbBlue >> 6) & 0x03 );
  414. }
  415. /*
  416. * if we are stretching copy into the back buffer
  417. * then use GDI to stretch later.
  418. */
  419. if( stretch )
  420. {
  421. pdds1 = lpBackBuffer;
  422. }
  423. else
  424. {
  425. pdds1 = pdds;
  426. }
  427. ddsd.dwSize = sizeof(ddsd);
  428. ddrval = IDirectDrawSurface_Lock(
  429. pdds1, NULL, &ddsd, DDLOCK_WAIT, NULL);
  430. if( ddrval == DD_OK )
  431. {
  432. dib_pitch = (pbi->biWidth+3)&~3;
  433. src = (BYTE *)lpBits + dib_pitch * (pbi->biHeight-1);
  434. dst = (BYTE *)ddsd.lpSurface;
  435. for( y=0; y<(int)pbi->biHeight; y++ )
  436. {
  437. for( x=0; x<(int)pbi->biWidth; x++ )
  438. {
  439. dst[x] = xlat332[src[x]];
  440. }
  441. dst += ddsd.lPitch;
  442. src -= dib_pitch;
  443. }
  444. IDirectDrawSurface_Unlock(pdds1, NULL);
  445. }
  446. else
  447. {
  448. Msg("Lock failed err=%d", ddrval);
  449. return FALSE;
  450. }
  451. if( stretch )
  452. {
  453. if( IDirectDrawSurface_GetDC(pdds,&hdc) == DD_OK )
  454. {
  455. if( IDirectDrawSurface_GetDC(pdds1,&hdc1) == DD_OK )
  456. {
  457. SetStretchBltMode(hdc, COLORONCOLOR);
  458. StretchBlt(hdc, 0, 0, w, h,
  459. hdc1, 0, 0, pbi->biWidth, pbi->biHeight, SRCCOPY);
  460. IDirectDrawSurface_ReleaseDC(pdds1,hdc1);
  461. }
  462. IDirectDrawSurface_ReleaseDC(pdds,hdc);
  463. }
  464. }
  465. }
  466. else if( IDirectDrawSurface_GetDC(pdds,&hdc) == DD_OK )
  467. {
  468. SetStretchBltMode(hdc, COLORONCOLOR);
  469. StretchDIBits(hdc, 0, 0, w, h,
  470. 0, 0, pbi->biWidth, pbi->biHeight,
  471. lpBits, (BITMAPINFO *)&dib.bi, DIB_RGB_COLORS, SRCCOPY);
  472. IDirectDrawSurface_ReleaseDC(pdds,hdc);
  473. }
  474. /*
  475. * show the art while loading...
  476. */
  477. rc.left = rcWindow.left,
  478. rc.top = rcWindow.top + 20;
  479. rc.right = rc.left + w;
  480. rc.bottom = rc.top + h;
  481. IDirectDrawSurface_Blt(lpFrontBuffer, &rc, pdds, NULL, DDBLT_WAIT, NULL);
  482. return TRUE;
  483. } /* gfxRestore */
  484. /*
  485. * gfxRestoreAll
  486. *
  487. * restore the art when one or more surfaces are lost
  488. */
  489. BOOL gfxRestoreAll()
  490. {
  491. GFX_BITMAP *curr;
  492. HWND hwndF = GetForegroundWindow();
  493. Splash();
  494. for( curr = lpVRAM; curr != NULL; curr = curr->link)
  495. {
  496. if (curr->lpSurface &&
  497. (fForceRestore || IDirectDrawSurface_IsLost(curr->lpSurface) == DDERR_SURFACELOST))
  498. {
  499. if( !gfxRestore(curr) )
  500. {
  501. Msg( "gfxRestoreAll: ************ Restore FAILED!" );
  502. return FALSE;
  503. }
  504. }
  505. }
  506. DDClear();
  507. fForceRestore = FALSE;
  508. return TRUE;
  509. } /* gfxRestoreAll */
  510. /*
  511. * gfxFillBack
  512. */
  513. void gfxFillBack( DWORD dwColor )
  514. {
  515. DDBLTFX ddbltfx;
  516. ddbltfx.dwSize = sizeof( ddbltfx );
  517. ddbltfx.dwFillColor = dwColor;
  518. IDirectDrawSurface_Blt(
  519. lpBackBuffer, // dest surface
  520. NULL, // dest rect
  521. NULL, // src surface
  522. NULL, // src rect
  523. DDBLT_COLORFILL | DDBLT_WAIT,
  524. &ddbltfx);
  525. } /* gfxFillBack */