fliphelp.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809
  1. //---------------------------------------------------------------------------------------------
  2. //
  3. // This file provides DirectDraw rendering services through FlipHELP, a programming
  4. // technique that allows for the rendering of non-DirectDraw-aware windows to the
  5. // DirectDraw GDI surface.
  6. //
  7. // Also of interest, and noted in this header, is FlipHelpES, which provides additional
  8. // services to FlipHELP. FlipHelpES allows for the rendering of out-of-process windows
  9. // (WOOPs) to the DirectDraw GDI surface. Prior to this, any activation of a window in
  10. // another process caused DirectDraw to minimize and mode-switch (its default behavior).
  11. //
  12. // Search on the term "fswindow" in the DirectX 6.1 SDK documentation for additional
  13. // details and alternative sample code.
  14. //
  15. //---------------------------------------------------------------------------------------------
  16. //
  17. // (C) Copyright 1995-1999 Microsoft Corp. All rights reserved.
  18. //
  19. // You have a royalty-free right to use, modify, reproduce and
  20. // distribute the Sample Files (and/or any modified version) in
  21. // any way you find useful, provided that you agree that
  22. // Microsoft has no warranty obligations or liability for any
  23. // Sample Application Files which are modified.
  24. //
  25. //---------------------------------------------------------------------------------------------
  26. #include "pch.h"
  27. #include "FlipHelp.h"
  28. //#include "FlipHelpES.h" // support for out-of-process windows (WOOPs)
  29. //
  30. // declare/define global
  31. //
  32. SIZE structSurfaceSize = {0, 0}; // DirectDraw front buffer dimensions
  33. //
  34. // declare/define module globals
  35. //
  36. static LPDIRECTDRAW2 ddObject = NULL;
  37. /*
  38. static LPDIRECTDRAWSURFACE3 ddFrontBuffer = NULL;
  39. static LPDIRECTDRAWSURFACE3 ddBackBuffer = NULL;
  40. */
  41. static LPDIRECTDRAWSURFACE2 ddFrontBuffer = NULL;
  42. static LPDIRECTDRAWSURFACE2 ddBackBuffer = NULL;
  43. static LPDIRECTDRAWCLIPPER ddClipper = NULL;
  44. static HWND hwndHelpWindow = NULL;
  45. static HBITMAP hwndHelpWindowBMP = NULL;
  46. static HWND hwndAppWindow = NULL;
  47. static HRESULT hrResult = 0;
  48. static BOOL f3Dfx = FALSE;
  49. static BOOL fDrawMouse = FALSE;
  50. static BOOL fBuffersSame = FALSE;
  51. static BOOL fUsingBadDriver = FALSE;
  52. static BOOL fStaticContent = FALSE;
  53. //
  54. // internal function prototypes
  55. //
  56. static HBITMAP CreateHelpBMP(HWND hwnd);
  57. static HBITMAP CreateDibBMP(HDC hdc, int w, int h, int bpp);
  58. static HRGN GetInvWindowRgn(HWND hwnd);
  59. //static LPDIRECTDRAW2 GetDDObjectFromDDSurface(LPDIRECTDRAWSURFACE3 ddSurface);
  60. static LPDIRECTDRAW2 GetDDObjectFromDDSurface(LPDIRECTDRAWSURFACE2 ddSurface);
  61. /*
  62. static BOOL CheckForBrokenDriver(LPDIRECTDRAWSURFACE3 pSurface);
  63. */
  64. static BOOL CheckForBrokenDriver(LPDIRECTDRAWSURFACE2 pSurface);
  65. static void GetOptimalDIBFormat(HDC hdc, BITMAPINFOHEADER *pbi);
  66. //
  67. // external function prototype
  68. //
  69. extern "C" int APIENTRY GetRandomRgn(HDC, HRGN, int); // GDI function to get a region from a HDC
  70. //---------------------------------------------------------------------------------------------
  71. // FlipHelp_Init() does preliminary setup of global values for FlipHelp. It should get
  72. // called each time DirectDraw surfaces are altered (i.e. changes to the device that
  73. // the client application is running under).
  74. //
  75. // Be sure to call FlipHelp_Release() prior to calling any subsequent FlipHelp_Init() calls,
  76. // otherwise, the reference count on the DirectDraw objects will become out of sync.
  77. //
  78. // Note that the buffers passed in are of type LPVOID. This allows DirectDraw buffers of
  79. // any surface interface type to be accepted. However, this function will fail if it
  80. // cannot get a base DirectDraw interface of type IID_IDirectDrawSurface.
  81. //
  82. // purpose: assigns local DD object and buffers, and sets globals
  83. // requires: handle to app window, front/back buffer pointers, initialization flags
  84. // returns: HRESULT
  85. // side effect: sets globals and attaches clipper to DD object
  86. //---------------------------------------------------------------------------------------------
  87. HRESULT FlipHelp_Init(HWND hwndApp, LPVOID FrontBuffer, LPVOID BackBuffer, DWORD dwFlags)
  88. {
  89. hrResult = S_OK;
  90. //
  91. // check for valid buffer pointers
  92. //
  93. if (FrontBuffer == NULL || BackBuffer == NULL)
  94. return(HR_ERR);
  95. //
  96. // make sure we're not trying to re-init (addref) our buffers
  97. //
  98. FlipHelp_Release();
  99. //
  100. // check for LPDIRECTDRAWSURFACE3 interface, return if none found
  101. //
  102. /* if (!((hrResult = ((IUnknown*)FrontBuffer)->QueryInterface(IID_IDirectDrawSurface3, (LPVOID *)&ddFrontBuffer)) == DD_OK) ||
  103. !((hrResult = ((IUnknown*)BackBuffer)->QueryInterface(IID_IDirectDrawSurface3, (LPVOID *)&ddBackBuffer)) == DD_OK))
  104. */
  105. if (!((hrResult = ((IUnknown*)FrontBuffer)->QueryInterface(IID_IDirectDrawSurface2, (LPVOID *)&ddFrontBuffer)) == DD_OK) ||
  106. !((hrResult = ((IUnknown*)BackBuffer)->QueryInterface(IID_IDirectDrawSurface2, (LPVOID *)&ddBackBuffer)) == DD_OK))
  107. {
  108. FlipHelp_Release();
  109. return(hrResult);
  110. }
  111. //
  112. // get handle to application window
  113. //
  114. hwndAppWindow = hwndApp;
  115. //
  116. // set flags
  117. //
  118. fDrawMouse = (BOOL)(dwFlags & FH_DRAW_MOUSE); // do we draw hardware mouse?
  119. fBuffersSame = (ddFrontBuffer == ddBackBuffer); // are DirectDraw buffers identical?
  120. f3Dfx = (BOOL)(dwFlags & FH_3DFX_HARDWARE); // are we running on 3Dfx hardware?
  121. //
  122. // check for broken drivers that do not do 555<->565 blts correctly
  123. //
  124. fUsingBadDriver = ((f3Dfx) && (!(dwFlags & FH_BITMAP_UPDATE)) && CheckForBrokenDriver(ddBackBuffer));
  125. //
  126. // if not 3Dfx, then get DirectDraw object from surface passed in
  127. // needed for CreateClipper() and FlipToGDISurface() calls
  128. //
  129. if ((!f3Dfx) && (!(ddObject = GetDDObjectFromDDSurface(ddFrontBuffer))))
  130. return(hrResult);
  131. //
  132. // get DirectDraw surface dimensions
  133. //
  134. DDSURFACEDESC ddsd;
  135. ddsd.dwSize = sizeof(ddsd);
  136. ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH;
  137. hrResult = ddBackBuffer->GetSurfaceDesc(&ddsd);
  138. structSurfaceSize.cx = ddsd.dwWidth;
  139. structSurfaceSize.cy = ddsd.dwHeight;
  140. return(hrResult);
  141. }
  142. //---------------------------------------------------------------------------------------------
  143. // FlipHelp_Begin() preps the DirectDraw surface depending on 3D hardware. It should get called
  144. // whenever a window (represented by the hwnd parameter) needs to be displayed under DirectDraw.
  145. // FlipHelp_Begin() should also get called if the window changes its content (if its static
  146. // content becomes dynamic, and vice-versa).
  147. //
  148. // purpose: for 3DFX, creates content image, else just flip to GDI surface
  149. // requires: handle to content window, 3DFX flag and if content is dynamic or static
  150. // returns: handle to the hwndHelpWindow, else NULL if not successful
  151. // side effect: creates content image or flips to GDI surface
  152. //---------------------------------------------------------------------------------------------
  153. HWND FlipHelp_Begin(HWND hwnd, BOOL bStaticContent)
  154. {
  155. //
  156. // if no handle passed in, assume existing content window
  157. //
  158. if (hwnd == NULL)
  159. {
  160. if ((hwnd = hwndHelpWindow) == NULL)
  161. return(NULL);
  162. }
  163. fStaticContent = bStaticContent;
  164. if (f3Dfx)
  165. {
  166. //
  167. // constrain cursor to DirectDraw surface
  168. //
  169. RECT rc = {0, 0, structSurfaceSize.cx, structSurfaceSize.cy};
  170. ClipCursor(&rc);
  171. //
  172. // clear out lingering content
  173. //
  174. if (hwndHelpWindowBMP)
  175. {
  176. DeleteObject(hwndHelpWindowBMP);
  177. hwndHelpWindowBMP = NULL;
  178. }
  179. //
  180. // need to create an image of content window just once
  181. //
  182. if (fStaticContent)
  183. {
  184. if (!FlipHelp_IsActive())
  185. UpdateWindow(hwnd);
  186. //
  187. // assign content window image to global
  188. //
  189. hwndHelpWindowBMP = CreateHelpBMP(hwnd);
  190. }
  191. }
  192. else
  193. {
  194. //
  195. // create a clipper (used in LPDIRECTDRAWSURFACE::Blt)
  196. //
  197. if (ddObject->CreateClipper(0, &ddClipper, NULL) == DD_OK)
  198. {
  199. hrResult = ddClipper->SetHWnd(0, hwndAppWindow);
  200. assert(SUCCEEDED(hrResult));
  201. //
  202. // attach the clipper here if buffers are the same
  203. //
  204. if (fBuffersSame)
  205. {
  206. hrResult = ddFrontBuffer->SetClipper(ddClipper);
  207. assert(SUCCEEDED(hrResult));
  208. }
  209. }
  210. else
  211. return(NULL);
  212. //
  213. // not 3DFX, so just flip to GDI so content window can be seen
  214. //
  215. hrResult = ddObject->FlipToGDISurface();
  216. }
  217. hwndHelpWindow = hwnd;
  218. return(hwndHelpWindow);
  219. }
  220. //---------------------------------------------------------------------------------------------
  221. // FlipHelp_End() deletes objects associated with the content window. Note that these are
  222. // objects created within this module, not objects created by the calling client (e.g. content
  223. // window). Call this function whenever the content window is destroyed (e.g. WM_CLOSE).
  224. //
  225. // purpose: cleans up after content window
  226. // requires: flag to determine if running under 3DFX
  227. // returns: none
  228. // side effect: cleans up anything associated with existing content window
  229. //---------------------------------------------------------------------------------------------
  230. void FlipHelp_End()
  231. {
  232. if (hwndHelpWindowBMP)
  233. {
  234. DeleteObject(hwndHelpWindowBMP);
  235. hwndHelpWindowBMP = NULL;
  236. }
  237. hwndHelpWindow = NULL;
  238. if (f3Dfx)
  239. ClipCursor(NULL);
  240. if (ddFrontBuffer)
  241. ddFrontBuffer->SetClipper(NULL);
  242. RELEASE(ddClipper);
  243. }
  244. //---------------------------------------------------------------------------------------------
  245. // FlipHelp_Update() is responsible for the actual rendering of the help content window (held
  246. // in global hwndHelpWindow). This function must be called each time a DirectDraw frame
  247. // gets rendered and FlipHelp_IsActive() returns TRUE, so it should be placed in the main
  248. // application's DirectDraw rendering routine. An example of this might look like the
  249. // following:
  250. //
  251. // void RenderFrame()
  252. // {
  253. // if (FlipHelp_IsActive())
  254. // {
  255. // FlipHelp_Update();
  256. // }
  257. // else
  258. // {
  259. // FrontBuffer->Blt(...);
  260. // }
  261. // }
  262. //
  263. // purpose: main routine to handle DirectDraw output of content window
  264. // requires: handle to application window and 3DFX flag
  265. // returns: HRESULT
  266. // side effect: blts/flips content window to DirectDraw surface
  267. //---------------------------------------------------------------------------------------------
  268. HRESULT FlipHelp_Update()
  269. {
  270. hrResult = 0;
  271. //
  272. // if front and back buffers are the same, then we're already drawing to display
  273. //
  274. if (fBuffersSame)
  275. return(hrResult);
  276. //
  277. // new multiwindow method
  278. //
  279. if (f3Dfx)
  280. {
  281. //
  282. // get a DC to the backbuffer on the 3Dfx (where we need to copy it)
  283. //
  284. HDC hdcBackBuffer;
  285. hrResult = ddBackBuffer->GetDC(&hdcBackBuffer);
  286. assert(SUCCEEDED(hrResult));
  287. if (FlipHelp_IsStatic())
  288. {
  289. //
  290. // if window has a complex region associated with it, be sure to include it in the draw
  291. //
  292. RECT rc;
  293. GetWindowRect(hwndHelpWindow, &rc);
  294. HRGN hrgn = CreateRectRgn(0, 0, 0, 0);
  295. if (GetWindowRgn(hwndHelpWindow, hrgn) == COMPLEXREGION)
  296. {
  297. OffsetRgn(hrgn, rc.left, rc.top);
  298. SelectClipRgn(hdcBackBuffer, hrgn);
  299. }
  300. //
  301. // since the window content is static, use the existing bitmap image
  302. //
  303. HDC hdcMemory = CreateCompatibleDC(NULL);
  304. SelectObject(hdcMemory, hwndHelpWindowBMP);
  305. BitBlt(hdcBackBuffer, rc.left, rc.top, (rc.right - rc.left), (rc.bottom - rc.top), hdcMemory, 0, 0, SRCCOPY);
  306. DeleteDC(hdcMemory);
  307. SelectClipRgn(hdcBackBuffer, NULL);
  308. }
  309. else if (fUsingBadDriver)
  310. {
  311. //
  312. // to resolve the bad video driver situation, we must first create a bitmap, and then blt
  313. // to the screen, the same as is done in FlipHelp_IsStatic(), except that it must get
  314. // done for each successive frame
  315. //
  316. HDC hdcMemory = CreateCompatibleDC(NULL);
  317. HBITMAP hbm = CreateHelpBMP(hwndAppWindow);
  318. SelectObject(hdcMemory, hbm);
  319. //
  320. // since the window content is always changing, an image of it must
  321. // get created with each frame update
  322. //
  323. RECT rc;
  324. HRGN hrgn = GetInvWindowRgn(hwndAppWindow);
  325. GetRgnBox(hrgn, &rc);
  326. HDC hdcScreen = GetDC(NULL);
  327. //
  328. // blt from screen to memory
  329. //
  330. SelectClipRgn(hdcMemory, hrgn);
  331. BitBlt(hdcMemory, rc.left, rc.top, (rc.right - rc.left), (rc.bottom - rc.top), hdcScreen, rc.left, rc.top, SRCCOPY);
  332. SelectClipRgn(hdcMemory, NULL);
  333. //
  334. // blt from memory to backbuffer
  335. //
  336. SelectClipRgn(hdcBackBuffer, hrgn);
  337. BitBlt(hdcBackBuffer, rc.left, rc.top, (rc.right - rc.left), (rc.bottom - rc.top), hdcMemory, rc.left, rc.top, SRCCOPY);
  338. SelectClipRgn(hdcBackBuffer, NULL);
  339. DeleteObject(hrgn);
  340. DeleteObject(hdcMemory);
  341. DeleteObject(hbm);
  342. ReleaseDC(NULL, hdcScreen);
  343. }
  344. else
  345. {
  346. //
  347. // since the window content is always changing, an image of it must
  348. // get created with each frame update
  349. //
  350. RECT rc;
  351. HRGN hrgn = GetInvWindowRgn(hwndAppWindow);
  352. GetRgnBox(hrgn, &rc);
  353. HDC hdcScreen = GetDC(NULL);
  354. //
  355. // blt from screen directly to backbuffer
  356. //
  357. SelectClipRgn(hdcBackBuffer, hrgn);
  358. BitBlt(hdcBackBuffer, rc.left, rc.top, (rc.right - rc.left), (rc.bottom - rc.top), hdcScreen, rc.left, rc.top, SRCCOPY);
  359. SelectClipRgn(hdcBackBuffer, NULL);
  360. DeleteObject(hrgn);
  361. ReleaseDC(NULL, hdcScreen);
  362. }
  363. //
  364. // draw mouse cursor
  365. //
  366. if (fDrawMouse)
  367. {
  368. //
  369. // values for tracking changes in mouse cursor between blts
  370. //
  371. static HCURSOR MouseCursor;
  372. static ICONINFO IconInfo;
  373. HCURSOR MouseCursorCur;
  374. HWND hwndF = GetForegroundWindow();
  375. //
  376. // check for existence of out-of-process window (WOOP)
  377. // if it's the foreground window, then need to use AttachThreadInput() to
  378. // get back valid results of GetCursor() call
  379. //
  380. /*if (hwndF && GetWindowThreadProcessId(hwndF, NULL) == GetWindowThreadProcessId(hwndWOOP, NULL))
  381. {
  382. //
  383. // need to attach thread in order to allow correct return of GetCursor() call
  384. //
  385. DWORD dwWinHelpThreadId = GetWindowThreadProcessId(hwndWOOP, NULL);
  386. AttachThreadInput(GetCurrentThreadId(), dwWinHelpThreadId, TRUE);
  387. MouseCursorCur = GetCursor();
  388. AttachThreadInput(GetCurrentThreadId(), dwWinHelpThreadId, FALSE);
  389. }
  390. else*/
  391. {
  392. MouseCursorCur = GetCursor();
  393. };
  394. //
  395. // update the cursor only if it's changed
  396. //
  397. if (MouseCursorCur != MouseCursor)
  398. {
  399. MouseCursor = MouseCursorCur;
  400. GetIconInfo(MouseCursor, &IconInfo);
  401. if (IconInfo.hbmMask)
  402. DeleteObject(IconInfo.hbmMask);
  403. if (IconInfo.hbmColor)
  404. DeleteObject(IconInfo.hbmColor);
  405. };
  406. POINT pt;
  407. GetCursorPos(&pt);
  408. pt.x -= IconInfo.xHotspot;
  409. pt.y -= IconInfo.yHotspot;
  410. DrawIcon(hdcBackBuffer, pt.x, pt.y, MouseCursor);
  411. }
  412. hrResult = ddBackBuffer->ReleaseDC(hdcBackBuffer);
  413. assert(SUCCEEDED(hrResult));
  414. hrResult = ddFrontBuffer->Flip(NULL, DDFLIP_WAIT);
  415. assert(SUCCEEDED(hrResult));
  416. }
  417. else // not 3DFX hardware
  418. {
  419. //
  420. // create region to update
  421. //
  422. POINT ptScreen = {0, 0};
  423. ClientToScreen(hwndAppWindow, &ptScreen);
  424. RECT rc = {ptScreen.x , ptScreen.y, ptScreen.x + structSurfaceSize.cx, ptScreen.y + structSurfaceSize.cy};
  425. hrResult = ddFrontBuffer->SetClipper(ddClipper);
  426. //
  427. // update the surface with a blt
  428. //
  429. hrResult = ddFrontBuffer->Blt(&rc, ddBackBuffer, NULL, DDBLT_WAIT, NULL);
  430. assert(SUCCEEDED(hrResult));
  431. };
  432. return(hrResult);
  433. }
  434. //---------------------------------------------------------------------------------------------
  435. // FlipHelp_IsActive() simply checks to see if there's a content window displayed. This check
  436. // should be made prior to calling FlipHelp_Update().
  437. //
  438. // purpose: checks status of help window
  439. // requires: none
  440. // returns: true/false
  441. // side effect: none
  442. //---------------------------------------------------------------------------------------------
  443. BOOL FlipHelp_IsActive(void)
  444. {
  445. return(hwndHelpWindow != NULL);
  446. }
  447. //---------------------------------------------------------------------------------------------
  448. // FlipHelp_IsStatic() checks to see whether or not the content window needs to be regularly
  449. // updated (its content is dynamic, such as an animation or text entry field). A static window
  450. // is created (an image of the window created with a call to CreateHelpBMP()) once and used
  451. // over and over.
  452. //
  453. // purpose: checks if help window content is static or dynamic
  454. // requires: none
  455. // returns: true/false
  456. // side effect: none
  457. //---------------------------------------------------------------------------------------------
  458. BOOL FlipHelp_IsStatic(void)
  459. {
  460. return(fStaticContent);
  461. }
  462. //---------------------------------------------------------------------------------------------
  463. // FlipHelp_Release() releases interface pointers as necessary. It should get
  464. // called each time DirectDraw surfaces are altered (e.g. changes to the device that
  465. // the client application is running under).
  466. //
  467. // purpose: decrement refcount for interfaces created in FlipHelp
  468. // requires: none
  469. // returns: none
  470. // side effect: releases interface pointers created in FlipHelp
  471. //---------------------------------------------------------------------------------------------
  472. void FlipHelp_Release()
  473. {
  474. RELEASE(ddObject);
  475. RELEASE(ddBackBuffer);
  476. RELEASE(ddFrontBuffer);
  477. }
  478. //---------------------------------------------------------------------------------------------
  479. // CreateHelpBMP() takes the hwnd of the content window, and returns a bitmap handle. Note that
  480. // this is an internal (not exported) function.
  481. //
  482. // purpose: creates a bitmap from hwnd (content window)
  483. // requires: handle to content window
  484. // returns: handle to updated bitmap
  485. // side effect: none
  486. //---------------------------------------------------------------------------------------------
  487. static HBITMAP CreateHelpBMP(HWND hwnd)
  488. {
  489. //
  490. // create a bitmap of the window passed in
  491. //
  492. RECT rc;
  493. GetWindowRect(hwnd, &rc);
  494. int x = rc.left;
  495. int y = rc.top;
  496. int cx = rc.right - rc.left;
  497. int cy = rc.bottom - rc.top;
  498. HDC hdcScreen = GetDC(NULL);
  499. HDC hdcMemory = CreateCompatibleDC(NULL);
  500. HBITMAP hbmBitmap = NULL;
  501. hbmBitmap = CreateDibBMP(hdcScreen, cx, cy, 0);
  502. //
  503. // blt the image from screen to bitmap
  504. //
  505. SelectObject(hdcMemory, hbmBitmap);
  506. BitBlt(hdcMemory, 0, 0, cx, cy, hdcScreen, x, y, SRCCOPY);
  507. DeleteDC(hdcMemory);
  508. ReleaseDC(NULL, hdcScreen);
  509. return(hbmBitmap);
  510. }
  511. //---------------------------------------------------------------------------------------------
  512. // CreateDibBMP() created an empty bitmap, used exclusively in CreateHelpBMP(). Note that
  513. // this is an internal (not exported) function.
  514. //
  515. // purpose: creates an "empty" bitmap
  516. // requires: dc, dimensions of image, and color depth (bits per pixel)
  517. // note that bpp == 0 will call into GetOptimalDIBFormat()
  518. // returns: handle to new bitmap
  519. // side effect: none
  520. //---------------------------------------------------------------------------------------------
  521. static HBITMAP CreateDibBMP(HDC hdc, int w, int h, int bpp)
  522. {
  523. LPVOID lpBits;
  524. struct
  525. {
  526. BITMAPINFOHEADER bi;
  527. DWORD ct[256];
  528. } dib;
  529. dib.bi.biSize = sizeof(BITMAPINFOHEADER);
  530. dib.bi.biWidth = w;
  531. dib.bi.biHeight = h;
  532. dib.bi.biBitCount = (WORD)bpp;
  533. dib.bi.biPlanes = 1;
  534. dib.bi.biCompression = 0;
  535. dib.bi.biSizeImage = 0;
  536. dib.bi.biClrUsed = 0;
  537. if (bpp == 0)
  538. {
  539. GetOptimalDIBFormat(hdc, &dib.bi);
  540. dib.bi.biBitCount = (dib.bi.biBitCount < 16 ? 16 : dib.bi.biBitCount);
  541. dib.bi.biWidth = w;
  542. dib.bi.biHeight = h;
  543. }
  544. else if (bpp == 15)
  545. {
  546. dib.bi.biBitCount = 16;
  547. }
  548. else if (bpp == 16)
  549. {
  550. dib.bi.biCompression = BI_BITFIELDS;
  551. dib.ct[0] = 0xf800;
  552. dib.ct[1] = 0x07E0;
  553. dib.ct[2] = 0x001F;
  554. };
  555. return(CreateDIBSection(hdc, (LPBITMAPINFO)&dib, DIB_RGB_COLORS, &lpBits, NULL, 0));
  556. }
  557. //---------------------------------------------------------------------------------------------
  558. // GetInvWindowRgn() get the inverse of the visible region of a window
  559. //
  560. // purpose: used to Blt the contents of a window to the 3DFX
  561. // requires: handle to the app window
  562. // returns: HRGN of non-visible region
  563. // side effect: none
  564. //---------------------------------------------------------------------------------------------
  565. static HRGN GetInvWindowRgn(HWND hwnd)
  566. {
  567. HRGN WinRgn;
  568. HRGN VisRgn;
  569. HRGN InvRgn;
  570. RECT rc;
  571. HDC hdc;
  572. //
  573. // get the whole window rect/rgn
  574. //
  575. GetWindowRect(hwnd, &rc);
  576. WinRgn = CreateRectRgnIndirect(&rc);
  577. //
  578. // get the visible region
  579. //
  580. hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS);
  581. VisRgn = CreateRectRgn(0, 0, 0, 0);
  582. GetRandomRgn(hdc, VisRgn, 4);
  583. ReleaseDC(hwnd, hdc);
  584. //
  585. // subtract the vis rgn from the whole window rgn, where InvRgn = WinRgn - VisRgn;
  586. //
  587. InvRgn = CreateRectRgn(0, 0, 0, 0);
  588. CombineRgn(InvRgn, WinRgn, VisRgn, RGN_DIFF);
  589. DeleteObject(WinRgn);
  590. DeleteObject(VisRgn);
  591. //
  592. // convert the region from screen cordinates to window cordinates
  593. //
  594. OffsetRgn(InvRgn, -rc.left, -rc.top);
  595. return(InvRgn);
  596. }
  597. //---------------------------------------------------------------------------------------------
  598. // GetDDObjectFromDDSurface() gets the DirectDraw object from a surface passed in
  599. //
  600. // purpose: gets DirectDraw object from DirectDraw surface
  601. // requires: pointer to DirectDraw surface
  602. // returns: pointer to DirectDraw object
  603. // side effect: none
  604. //---------------------------------------------------------------------------------------------
  605. //static LPDIRECTDRAW2 GetDDObjectFromDDSurface(LPDIRECTDRAWSURFACE3 ddSurface)
  606. static LPDIRECTDRAW2 GetDDObjectFromDDSurface(LPDIRECTDRAWSURFACE2 ddSurface)
  607. {
  608. LPDIRECTDRAW2 ddObject = NULL;
  609. LPDIRECTDRAWSURFACE2 ddSurface2 = NULL;
  610. hrResult = 0;
  611. //
  612. // check to make sure surface is valid
  613. //
  614. if (ddSurface == NULL)
  615. return(NULL);
  616. //
  617. // get the DirectDraw object, but first check for LPDIRECTDRAWSURFACE2 interface
  618. // needed for GetDDInterface() call
  619. //
  620. if (ddSurface->QueryInterface(IID_IDirectDrawSurface2, (LPVOID *)&ddSurface2) != DD_OK)
  621. return(NULL);
  622. hrResult = ddSurface2->GetDDInterface((LPVOID *)&ddObject);
  623. assert(SUCCEEDED(hrResult));
  624. hrResult = ddSurface2->Release();
  625. assert(SUCCEEDED(hrResult));
  626. return(ddObject);
  627. }
  628. //---------------------------------------------------------------------------------------------
  629. // CheckForBrokenDriver() checks for the case when the 2D video driver does not correctly
  630. // handle 565<->555 bitmap conversion
  631. //
  632. // purpose: side-step really bad video drivers in this world
  633. // requires: DirectDraw surface
  634. // returns: whether or not the video driver has passed the test
  635. // side effect: none
  636. //---------------------------------------------------------------------------------------------
  637. //static BOOL CheckForBrokenDriver(LPDIRECTDRAWSURFACE3 pSurface)
  638. static BOOL CheckForBrokenDriver(LPDIRECTDRAWSURFACE2 pSurface)
  639. {
  640. HDC hdcSurface = NULL, hdcScreen = NULL;
  641. COLORREF rgbTest = 0, rgbScreen = 0, rgbSurface = 0;
  642. //
  643. // to test for bad driver case, put a pure green pixel in the upper left corner
  644. // of the surface, then get it again (getting rid of the pixel so it doesn't display)
  645. //
  646. // if the pixel comes back with red or blue in it, then the test failed
  647. // and we have a bad driver to content with (so return TRUE)
  648. //
  649. if (pSurface->GetDC(&hdcSurface) == DD_OK)
  650. {
  651. hdcScreen = GetDC(NULL);
  652. //
  653. // get the pixel
  654. //
  655. rgbScreen = GetPixel(hdcScreen, 0, 0);
  656. rgbSurface= GetPixel(hdcSurface, 0, 0);
  657. //
  658. // set the pixel to green and blt it to the screen
  659. //
  660. SetPixel(hdcScreen, 0, 0, RGB(0, 255, 0));
  661. BitBlt(hdcSurface, 0, 0, 1, 1, hdcScreen, 0, 0, SRCCOPY);
  662. //
  663. // get the pixel from the screen
  664. //
  665. rgbTest = GetPixel(hdcSurface, 0, 0);
  666. //
  667. // put the original pixel back
  668. //
  669. SetPixel(hdcScreen, 0, 0, rgbScreen);
  670. SetPixel(hdcSurface, 0, 0, rgbSurface);
  671. ReleaseDC(NULL, hdcScreen);
  672. pSurface->ReleaseDC(hdcSurface);
  673. }
  674. //
  675. // test here to see if it there's any red or blue in the pixel
  676. //
  677. return (GetRValue(rgbTest) != 0 || GetBValue(rgbTest) != 0);
  678. }
  679. //---------------------------------------------------------------------------------------------
  680. // GetOptimalDIBFormat() gets the optimal DIB format for a display device. The optimal DIB
  681. // format is the format that exactly matches the format of the device, this is very important
  682. // when dealing with 16bpp modes, you need to know what bitfields to use (555 or 565 for
  683. // example).
  684. //
  685. // You normally use this function to get the best format to pass to CreateDIBSection().
  686. //
  687. // If you are going to use this function on a 8bpp device, you should make sure the
  688. // colortable contains an identity palette for optimal blt'ing
  689. //
  690. // requires: device to get format for, pointer to bitmapinfo + color table
  691. // returns: none
  692. // side effect: optimal DIB format in pbi
  693. // if <= 8bpp, color table will contain system palette
  694. // if >= 16bpp, the "table" will contain corrected BI_BITFIELDS
  695. //---------------------------------------------------------------------------------------------
  696. static void GetOptimalDIBFormat(HDC hdc, BITMAPINFOHEADER *pbi)
  697. {
  698. HBITMAP hbm;
  699. hbm = CreateCompatibleBitmap(hdc, 1, 1);
  700. ZeroMemory(pbi, sizeof(BITMAPINFOHEADER));
  701. pbi->biSize = sizeof(BITMAPINFOHEADER);
  702. pbi->biBitCount = 0;
  703. //
  704. // first call will fill in the optimal biBitCount
  705. //
  706. GetDIBits(hdc, hbm, 0, 1, NULL, (BITMAPINFO*)pbi, DIB_RGB_COLORS);
  707. //
  708. // second call will get the optimal color table, or the optimal bitfields
  709. //
  710. GetDIBits(hdc, hbm, 0, 1, NULL, (BITMAPINFO*)pbi, DIB_RGB_COLORS);
  711. DeleteObject(hbm);
  712. }