Leaked source code of windows server 2003
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.

2164 lines
69 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: wglsup.c *
  3. * *
  4. * WGL support routines. *
  5. * *
  6. * Created: 15-Dec-1994 *
  7. * Author: Gilman Wong [gilmanw] *
  8. * *
  9. * Copyright (c) 1994 Microsoft Corporation *
  10. \**************************************************************************/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #include "devlock.h"
  14. #define DONTUSE(x) ( (x) = (x) )
  15. //!!!XXX -- Patrick says is necessary, but so far we seem OK. I think
  16. // it is really the apps responsibility.
  17. //!!!dbug
  18. #if 1
  19. #define REALIZEPALETTE(hdc) RealizePalette((hdc))
  20. #else
  21. #define REALIZEPALETTE(hdc)
  22. #endif
  23. //!!!XXX -- BitBlt's involving DIB sections are batched.
  24. // A GdiFlush is required, but perhaps can be taken out when
  25. // GDI goes to kernel-mode. Can probably take out for Win95.
  26. //#ifdef _OPENGL_NT_
  27. #if 1
  28. #define GDIFLUSH GdiFlush()
  29. #else
  30. #define GDIFLUSH
  31. #endif
  32. /******************************Public*Routine******************************\
  33. * wglPixelVisible
  34. *
  35. * Determines if the pixel (x, y) is visible in the window associated with
  36. * the given DC. The determination is made by checking the coordinate
  37. * against the visible region data cached in the GLGENwindow structure for
  38. * this winodw.
  39. *
  40. * Returns:
  41. * TRUE if pixel (x, y) is visible, FALSE if clipped out.
  42. *
  43. \**************************************************************************/
  44. BOOL APIENTRY wglPixelVisible(LONG x, LONG y)
  45. {
  46. BOOL bRet = FALSE;
  47. __GLGENcontext *gengc = (__GLGENcontext *) GLTEB_SRVCONTEXT();
  48. GLGENwindow *pwnd = gengc->pwndLocked;
  49. // If direct screen access isn't active we shouldn't call this function
  50. // since there's no need to do any visibility clipping ourselves
  51. ASSERTOPENGL(GLDIRECTSCREEN,
  52. "wglPixelVisible called without direct access\n");
  53. // Quick test against bounds.
  54. if (
  55. pwnd->prgndat && pwnd->pscandat &&
  56. x >= pwnd->prgndat->rdh.rcBound.left &&
  57. x < pwnd->prgndat->rdh.rcBound.right &&
  58. y >= pwnd->prgndat->rdh.rcBound.top &&
  59. y < pwnd->prgndat->rdh.rcBound.bottom
  60. )
  61. {
  62. ULONG cScans = pwnd->pscandat->cScans;
  63. GLGENscan *pscan = pwnd->pscandat->aScans;
  64. // Find right scan.
  65. for ( ; cScans; cScans--, pscan = pscan->pNext )
  66. {
  67. // Check if point is above scan.
  68. if ( pscan->top > y )
  69. {
  70. // Since scans are ordered top-down, we can conclude that
  71. // point is also above subsequent scans. Therefore intersection
  72. // must be NULL and we can terminate search.
  73. break;
  74. }
  75. // Check if point is within scan.
  76. else if ( pscan->bottom > y )
  77. {
  78. LONG *plWalls = pscan->alWalls;
  79. LONG *plWallsEnd = plWalls + pscan->cWalls;
  80. // Check x against each pair of walls.
  81. for ( ; plWalls < plWallsEnd; plWalls+=2 )
  82. {
  83. // Each pair of walls (inclusive-exclusive) defines
  84. // a non-NULL interval in the span that is visible.
  85. ASSERTOPENGL(
  86. plWalls[0] < plWalls[1],
  87. "wglPixelVisible(): bad walls in span\n"
  88. );
  89. // Check if x is within current interval.
  90. if ( x >= plWalls[0] && x < plWalls[1] )
  91. {
  92. bRet = TRUE;
  93. break;
  94. }
  95. }
  96. break;
  97. }
  98. // Point is below current scan. Try next scan.
  99. }
  100. }
  101. return bRet;
  102. }
  103. /******************************Public*Routine******************************\
  104. * wglSpanVisible
  105. *
  106. * Determines the visibility of the span [(x, y), (x+w, y)) (test is
  107. * inclusive-exclusive) in the current window. The span is either
  108. * completely visible, partially visible (clipped), or completely
  109. * clipped out (WGL_SPAN_ALL, WGL_SPAN_PARTIAL, and WGL_SPAN_NONE,
  110. * respectively).
  111. *
  112. * WGL_SPAN_ALL
  113. * ------------
  114. * The entire span is visible. *pcWalls and *ppWalls are not set.
  115. *
  116. * WGL_SPAN_NONE
  117. * -------------
  118. * The span is completely obscured (clipped out). *pcWalls and *ppWalls
  119. * are not set.
  120. *
  121. * WGL_SPAN_PARTIAL
  122. * ----------------
  123. * If the span is WGL_SPAN_PARTIAL, the function also returns a pointer
  124. * to the wall array (starting with the first wall actually intersected
  125. * by the span) and a count of the walls at this pointer.
  126. *
  127. * If the wall count is even, then the span starts outside the visible
  128. * region and the first wall is where the span enters a visible portion.
  129. *
  130. * If the wall count is odd, then the span starts inside the visible
  131. * region and the first wall is where the span exits a visible portion.
  132. *
  133. * The span may or may not cross all the walls in the array, but definitely
  134. * does cross the first wall.
  135. *
  136. * Return:
  137. * Returns WGL_SPAN_ALL, WGL_SPAN_NONE, or WGL_SPAN_PARTIAL. In
  138. * addition, if return is WGL_SPAN_PARTIAL, pcWalls and ppWalls will
  139. * be set (see above).
  140. *
  141. * History:
  142. * 06-Dec-1994 -by- Gilman Wong [gilmanw]
  143. * Wrote it.
  144. \**************************************************************************/
  145. ULONG APIENTRY
  146. wglSpanVisible(LONG x, LONG y, ULONG w, LONG *pcWalls, LONG **ppWalls)
  147. {
  148. ULONG ulRet = WGL_SPAN_NONE;
  149. __GLGENcontext *gengc = (__GLGENcontext *) GLTEB_SRVCONTEXT();
  150. GLGENwindow *pwnd = gengc->pwndLocked;
  151. LONG xRight = x + w; // Right edge of span (exclusive)
  152. // If direct access is not active we shouldn't call this function since
  153. // there's no need to do any visibility clipping ourselves
  154. ASSERTOPENGL(GLDIRECTSCREEN,
  155. "wglSpanVisible called without direct access\n");
  156. // Quick test against bounds.
  157. if (
  158. pwnd->prgndat && pwnd->pscandat &&
  159. (x < pwnd->prgndat->rdh.rcBound.right ) &&
  160. (xRight > pwnd->prgndat->rdh.rcBound.left ) &&
  161. (y >= pwnd->prgndat->rdh.rcBound.top ) &&
  162. (y < pwnd->prgndat->rdh.rcBound.bottom)
  163. )
  164. {
  165. ULONG cScans = pwnd->pscandat->cScans;
  166. GLGENscan *pscan = pwnd->pscandat->aScans;
  167. // Find right scan.
  168. for ( ; cScans; cScans--, pscan = pscan->pNext )
  169. {
  170. // Check if span is above scan.
  171. if ( pscan->top > y ) // Scans have gone past span
  172. {
  173. // Since scans are ordered top-down, we can conclude that
  174. // span will aslo be above subsequent scans. Therefore
  175. // intersection must be NULL and we can terminate search.
  176. goto wglSpanVisible_exit;
  177. }
  178. // Span is below top of scan. If span is also above bottom,
  179. // span vertically intersects this scan and only this scan.
  180. else if ( pscan->bottom > y )
  181. {
  182. LONG *plWalls = pscan->alWalls;
  183. ULONG cWalls = pscan->cWalls;
  184. ASSERTOPENGL(
  185. (cWalls & 0x1) == 0,
  186. "wglSpanVisible(): wall count must be even!\n"
  187. );
  188. // Check span against each pair of walls. Walls are walked
  189. // from left to right.
  190. //
  191. // Possible intersections where "[" is inclusive
  192. // and ")" is exclusive:
  193. // left wall right wall
  194. // [ )
  195. // case 1a [-----) [ )
  196. // 1b [-----) )
  197. // [ )
  198. // case 2a [-----) ) return
  199. // 2b [-------------------) left wall
  200. // [ )
  201. // case 3a [-----) )
  202. // 3b [ [-----) )
  203. // 3c [ [-----)
  204. // 3d [----------------)
  205. // [ )
  206. // case 4a [ [-----) return
  207. // 4b [-------------------) right wall
  208. // [ )
  209. // case 5a [ [-----)
  210. // 5b [ ) [-----)
  211. // [ )
  212. // case 6 [----------------------) return
  213. // [ ) left wall
  214. for ( ; cWalls; cWalls-=2, plWalls+=2 )
  215. {
  216. // Each pair of walls (inclusive-exclusive) defines
  217. // a non-NULL interval in the span that is visible.
  218. ASSERTOPENGL(
  219. plWalls[0] < plWalls[1],
  220. "wglSpanVisible(): bad walls in span\n"
  221. );
  222. // Checking right end against left wall will partition the
  223. // set into case 1 vs. case 2 thru 6.
  224. if ( plWalls[0] >= xRight )
  225. {
  226. // Case 1 -- span outside interval on the left.
  227. //
  228. // The walls are ordered from left to right (i.e., low
  229. // to high). So if span is left of this interval, it
  230. // must also be left of all subsequent intervals and
  231. // we can terminate the search.
  232. goto wglSpanVisible_exit;
  233. }
  234. // Cases 2 thru 6.
  235. //
  236. // Checking left end against right wall will partition subset
  237. // into case 5 vs. cases 2, 3, 4, 6.
  238. else if ( plWalls[1] > x )
  239. {
  240. // Cases 2, 3, 4, and 6.
  241. //
  242. // Checking left end against left wall will partition
  243. // subset into cases 2, 6 vs. cases 3, 4.
  244. if ( plWalls[0] <= x )
  245. {
  246. // Cases 3 and 4.
  247. //
  248. // Checking right end against right wall will
  249. // distinguish between the two cases.
  250. if ( plWalls[1] >= xRight )
  251. {
  252. // Case 3 -- completely visible.
  253. ulRet = WGL_SPAN_ALL;
  254. }
  255. else
  256. {
  257. // Case 4 -- partially visible, straddling the
  258. // right wall.
  259. ulRet = WGL_SPAN_PARTIAL;
  260. *ppWalls = &plWalls[1];
  261. *pcWalls = cWalls - 1;
  262. }
  263. }
  264. else
  265. {
  266. // Cases 2 and 6 -- in either case its a partial
  267. // intersection where the first intersection is with
  268. // the left wall.
  269. ulRet = WGL_SPAN_PARTIAL;
  270. *ppWalls = &plWalls[0];
  271. *pcWalls = cWalls;
  272. }
  273. goto wglSpanVisible_exit;
  274. }
  275. // Case 5 -- span outside interval to the right. Try
  276. // next pair of walls.
  277. }
  278. // A span can intersect only one scan. We don't need to check
  279. // any other scans.
  280. goto wglSpanVisible_exit;
  281. }
  282. // Span is below current scan. Try next scan.
  283. }
  284. }
  285. wglSpanVisible_exit:
  286. return ulRet;
  287. }
  288. /******************************Public*Routine******************************\
  289. * bComputeLogicalToSurfaceMap
  290. *
  291. * Copy logical palette to surface palette translation vector to the buffer
  292. * pointed to by pajVector. The logical palette is specified by hpal. The
  293. * surface is specified by hdc.
  294. *
  295. * Note: The hdc may identify either a direct (display) dc or a DIB memory dc.
  296. * If hdc is a display dc, then the surface palette is the system palette.
  297. * If hdc is a memory dc, then the surface palette is the DIB color table.
  298. *
  299. * History:
  300. * 27-Jan-1996 -by- Gilman Wong [gilmanw]
  301. * Wrote it.
  302. \**************************************************************************/
  303. BOOL bComputeLogicalToSurfaceMap(HPALETTE hpal, HDC hdc, BYTE *pajVector)
  304. {
  305. BOOL bRet = FALSE;
  306. HPALETTE hpalSurf;
  307. ULONG cEntries, cSysEntries;
  308. DWORD dwDcType = wglObjectType(hdc);
  309. LPPALETTEENTRY lppeTmp, lppeEnd;
  310. BYTE aj[sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * 512) + (sizeof(RGBQUAD) * 256)];
  311. LOGPALETTE *ppal = (LOGPALETTE *) aj;
  312. LPPALETTEENTRY lppeSurf = &ppal->palPalEntry[0];
  313. LPPALETTEENTRY lppe = lppeSurf + 256;
  314. RGBQUAD *prgb = (RGBQUAD *) (lppe + 256);
  315. // Determine number of colors in each palette.
  316. cEntries = GetPaletteEntries(hpal, 0, 1, NULL);
  317. if (dwDcType == OBJ_DC)
  318. cSysEntries = wglGetSystemPaletteEntries(hdc, 0, 1, NULL);
  319. else
  320. cSysEntries = 256;
  321. // Dynamic color depth changing can cause this.
  322. if ((cSysEntries > 256) || (cEntries > 256))
  323. {
  324. WARNING("wglCopyTranslationVector(): palette on > 8BPP device\n");
  325. // Drawing will have corrupted colors, but at least we should not crash.
  326. cSysEntries = min(cSysEntries, 256);
  327. cEntries = min(cEntries, 256);
  328. }
  329. // Get the logical palette entries.
  330. cEntries = GetPaletteEntries(hpal, 0, cEntries, lppe);
  331. // Get the surface palette entries.
  332. if (dwDcType == OBJ_DC)
  333. {
  334. cSysEntries = wglGetSystemPaletteEntries(hdc, 0, cSysEntries, lppeSurf);
  335. lppeTmp = lppeSurf;
  336. lppeEnd = lppeSurf + cSysEntries;
  337. for (; lppeTmp < lppeEnd; lppeTmp++)
  338. lppeTmp->peFlags = 0;
  339. }
  340. else
  341. {
  342. RGBQUAD *prgbTmp;
  343. // First get RGBQUADs from DIB color table...
  344. cSysEntries = GetDIBColorTable(hdc, 0, cSysEntries, prgb);
  345. // ...then convert RGBQUADs into PALETTEENTRIES.
  346. prgbTmp = prgb;
  347. lppeTmp = lppeSurf;
  348. lppeEnd = lppeSurf + cSysEntries;
  349. while (lppeTmp < lppeEnd)
  350. {
  351. lppeTmp->peRed = prgbTmp->rgbRed;
  352. lppeTmp->peGreen = prgbTmp->rgbGreen;
  353. lppeTmp->peBlue = prgbTmp->rgbBlue;
  354. lppeTmp->peFlags = 0;
  355. lppeTmp++;
  356. prgbTmp++;
  357. }
  358. }
  359. // Construct a translation vector by using GetNearestPaletteIndex to
  360. // map each entry in the logical palette to the surface palette.
  361. if (cEntries && cSysEntries)
  362. {
  363. // Create a temporary logical palette that matches the surface
  364. // palette retrieved above.
  365. ppal->palVersion = 0x300;
  366. ppal->palNumEntries = (USHORT) cSysEntries;
  367. if ( hpalSurf = CreatePalette(ppal) )
  368. {
  369. // Translate each logical palette entry into a surface palette index.
  370. lppeTmp = lppe;
  371. lppeEnd = lppe + cEntries;
  372. for ( ; lppeTmp < lppeEnd; lppeTmp++, pajVector++)
  373. {
  374. *pajVector = (BYTE) GetNearestPaletteIndex(
  375. hpalSurf,
  376. RGB(lppeTmp->peRed,
  377. lppeTmp->peGreen,
  378. lppeTmp->peBlue)
  379. );
  380. ASSERTOPENGL(
  381. *pajVector != CLR_INVALID,
  382. "bComputeLogicalToSurfaceMap: GetNearestPaletteIndex failed\n"
  383. );
  384. }
  385. bRet = TRUE;
  386. DeleteObject(hpalSurf);
  387. }
  388. else
  389. {
  390. WARNING("bComputeLogicalToSurfaceMap: CreatePalette failed\n");
  391. }
  392. }
  393. else
  394. {
  395. WARNING("bComputeLogicalToSurfaceMap: failed to get pal info\n");
  396. }
  397. return bRet;
  398. }
  399. /******************************Public*Routine******************************\
  400. * wglCopyTranslateVector
  401. *
  402. * Create a logical palette index to system palette index translation
  403. * vector.
  404. *
  405. * This is done by first reading both the logical palette and system palette
  406. * entries. A temporary palette is created from the read system palette
  407. * entries. This will be passed to GetNearestPaletteIndex to translate
  408. * each logical palette entry into the desired system palette entry.
  409. *
  410. * Note: when GetNearestColor was called instead, very unstable results
  411. * were obtained. GetNearestPaletteIndex is definitely the right way to go.
  412. *
  413. * Returns:
  414. * TRUE if successful, FALSE otherwise.
  415. *
  416. * History:
  417. * 25-Oct-1994 -by- Gilman Wong [gilmanw]
  418. * Ported from gdi\gre\wglsup.cxx.
  419. \**************************************************************************/
  420. static GLubyte vubRGBtoVGA[8] = {
  421. 0x0,
  422. 0x9,
  423. 0xa,
  424. 0xb,
  425. 0xc,
  426. 0xd,
  427. 0xe,
  428. 0xf
  429. };
  430. BOOL APIENTRY wglCopyTranslateVector(__GLGENcontext *gengc, BYTE *pajVector,
  431. ULONG cEntries)
  432. {
  433. BOOL bRet = FALSE;
  434. ULONG i;
  435. HDC hdc;
  436. CHECKSCREENLOCKOUT();
  437. if (gengc->dwCurrentFlags & GLSURF_DIRECTDRAW)
  438. {
  439. // DirectDraw palettes are set directly into the hardware so
  440. // the translation vector is always identity
  441. for (i = 0; i < cEntries; i++)
  442. {
  443. *pajVector++ = (BYTE)i;
  444. }
  445. return TRUE;
  446. }
  447. hdc = gengc->gwidCurrent.hdc;
  448. if (GLSURF_IS_MEMDC(gengc->dwCurrentFlags))
  449. {
  450. HBITMAP hbm, hbmSave;
  451. // Technically this assert is invalid
  452. // because we can't be sure that cEntries will be one
  453. // of these two cases. To fix this we'd have to add
  454. // another parameter to this function indicating the
  455. // bit depth desired and go by that.
  456. ASSERTOPENGL(cEntries == 16 || cEntries == 256,
  457. "wglCopyTranslateVector: Unknown cEntries\n");
  458. if (gengc->dwCurrentFlags & GLSURF_DIRECT_ACCESS)
  459. {
  460. // For compatibility, do not do this if the stock palette is
  461. // selected. The old behavior assumed that the logical palette
  462. // can be ignored because the bitmap will have a color table
  463. // that exactly corresponds to the format specified by the
  464. // pixelformat. Thus, if no palette is selected into the memdc,
  465. // OpenGL would still render properly since it assumed 1-to-1.
  466. //
  467. // However, to enable using optimized DIB sections (i.e., DIBs
  468. // whose color tables match the system palette exactly), we need
  469. // to be able to specify the logical palette in the memdc.
  470. //
  471. // Therefore the hack is to assume 1-to-1 iff the stock
  472. // palette is selected into the memdc. Otherwise, we will
  473. // compute the logical to surface mapping.
  474. if ( gengc->gc.modes.rgbMode &&
  475. (GetCurrentObject(hdc, OBJ_PAL) !=
  476. GetStockObject(DEFAULT_PALETTE)) )
  477. {
  478. // If an RGB DIB section, compute a mapping from logical
  479. // palette to surface (DIB color table).
  480. bRet = bComputeLogicalToSurfaceMap(
  481. GetCurrentObject(hdc, OBJ_PAL),
  482. hdc,
  483. pajVector
  484. );
  485. }
  486. return bRet;
  487. }
  488. // 4bpp has a fixed color table so we can just copy the standard
  489. // translation into the output vector.
  490. if (cEntries == 16)
  491. {
  492. // For RGB mode, 4bpp uses a 1-1-1 format. We want to utilize
  493. // bright versions which exist in the upper 8 entries.
  494. if ( gengc->gc.modes.rgbMode )
  495. {
  496. memcpy(pajVector, vubRGBtoVGA, 8);
  497. // Set the other mappings to white to make problems show up
  498. memset(pajVector+8, 15, 8);
  499. bRet = TRUE;
  500. }
  501. // For CI mode, just return FALSE and use the trivial vector.
  502. return bRet;
  503. }
  504. // For bitmaps, we can determine the forward translation vector by
  505. // filling a compatible bitmap with palette index specifiers from
  506. // 1 to 255 and reading the bits back with GetBitmapBits.
  507. hbm = CreateCompatibleBitmap(hdc, cEntries, 1);
  508. if (hbm)
  509. {
  510. LONG cBytes;
  511. hbmSave = SelectObject(hdc, hbm);
  512. RealizePalette(hdc);
  513. for (i = 0; i < cEntries; i++)
  514. SetPixel(hdc, i, 0, PALETTEINDEX(i));
  515. cBytes = 256;
  516. if ( GetBitmapBits(hbm, cBytes, (LPVOID) pajVector) >= cBytes )
  517. bRet = TRUE;
  518. #if DBG
  519. else
  520. WARNING("wglCopyTranslateVector: GetBitmapBits failed\n");
  521. #endif
  522. SelectObject(hdc, hbmSave);
  523. DeleteObject(hbm);
  524. RealizePalette(hdc);
  525. }
  526. return bRet;
  527. }
  528. // Determine number of colors in logical and system palettes, respectively.
  529. cEntries = min(GetPaletteEntries(GetCurrentObject(hdc, OBJ_PAL),
  530. 0, cEntries, NULL),
  531. cEntries);
  532. if (cEntries == 16)
  533. {
  534. // For 16-color displays we are using RGB 1-1-1 since the
  535. // full 16-color palette doesn't make for very good mappings
  536. // Since we're only using the first eight of the colors we
  537. // want to map them to the bright colors in the VGA palette
  538. // rather than having them map to the dark colors as they would
  539. // if we ran the loop below
  540. if ( gengc->gc.modes.rgbMode )
  541. {
  542. memcpy(pajVector, vubRGBtoVGA, 8);
  543. // Set the other mappings to white to make problems show up
  544. memset(pajVector+8, 15, 8);
  545. bRet = TRUE;
  546. }
  547. // For CI mode, return FALSE and use the trivial translation vector.
  548. return bRet;
  549. }
  550. // Compute logical to surface palette mapping.
  551. bRet = bComputeLogicalToSurfaceMap(GetCurrentObject(hdc, OBJ_PAL), hdc,
  552. pajVector);
  553. return bRet;
  554. }
  555. /******************************Public*Routine******************************\
  556. * wglCopyBits
  557. *
  558. * Calls DrvCopyBits to copy scanline bits into or out of the driver surface.
  559. *
  560. \**************************************************************************/
  561. VOID APIENTRY wglCopyBits(
  562. __GLGENcontext *gengc,
  563. GLGENwindow *pwnd,
  564. HBITMAP hbm, // ignore
  565. LONG x, // screen coordinate of scan
  566. LONG y,
  567. ULONG cx, // width of scan
  568. BOOL bIn) // if TRUE, copy from bm to dev; otherwise, dev to bm
  569. {
  570. CHECKSCREENLOCKOUT();
  571. // Convert screen coordinates to window coordinates.
  572. x -= pwnd->rclClient.left;
  573. y -= pwnd->rclClient.top;
  574. // this shouldn't happen, but better safe than sorry
  575. if (y < 0)
  576. return;
  577. //!!!XXX
  578. REALIZEPALETTE(gengc->gwidCurrent.hdc);
  579. // Copy from bitmap to device.
  580. if (bIn)
  581. {
  582. LONG xSrc, x0Dst, x1Dst;
  583. if (x < 0)
  584. {
  585. xSrc = -x;
  586. x0Dst = 0;
  587. x1Dst = x + (LONG)cx;
  588. }
  589. else
  590. {
  591. xSrc = 0;
  592. x0Dst = x;
  593. x1Dst = x + (LONG)cx;
  594. }
  595. if (x1Dst <= x0Dst)
  596. return;
  597. BitBlt(gengc->gwidCurrent.hdc, x0Dst, y, cx, 1,
  598. gengc->ColorsMemDC, xSrc, 0, SRCCOPY);
  599. }
  600. // Copy from device to bitmap.
  601. else
  602. {
  603. LONG xSrc, x0Dst, x1Dst;
  604. if (x < 0)
  605. {
  606. xSrc = 0;
  607. x0Dst = -x;
  608. x1Dst = (LONG)cx;
  609. }
  610. else
  611. {
  612. xSrc = x;
  613. x0Dst = 0;
  614. x1Dst = (LONG)cx;
  615. }
  616. if (x1Dst <= x0Dst)
  617. return;
  618. if (dwPlatformId == VER_PLATFORM_WIN32_NT ||
  619. GLSURF_IS_MEMDC(gengc->dwCurrentFlags))
  620. {
  621. BitBlt(gengc->ColorsMemDC, x0Dst, 0, cx, 1,
  622. gengc->gwidCurrent.hdc, xSrc, y, SRCCOPY);
  623. }
  624. else
  625. {
  626. /* If we're copying from the screen,
  627. copy through a DDB to avoid some layers of unnecessary
  628. code in Win95 that deals with translating between
  629. different bitmap layouts */
  630. if (gengc->ColorsDdbDc)
  631. {
  632. BitBlt(gengc->ColorsDdbDc, 0, 0, cx, 1,
  633. gengc->gwidCurrent.hdc, xSrc, y, SRCCOPY);
  634. BitBlt(gengc->ColorsMemDC, x0Dst, 0, cx, 1,
  635. gengc->ColorsDdbDc, 0, 0, SRCCOPY);
  636. }
  637. else
  638. {
  639. //!!!Viper fix -- Diamond Viper (Weitek 9000) fails
  640. //!!! CreateCompatibleBitmap for some
  641. //!!! (currently unknown) reason. Thus,
  642. //!!! the DDB does not exist and we will
  643. //!!! have to incur the perf. hit.
  644. BitBlt(gengc->ColorsMemDC, x0Dst, 0, cx, 1,
  645. gengc->gwidCurrent.hdc, xSrc, y, SRCCOPY);
  646. }
  647. }
  648. }
  649. GDIFLUSH;
  650. }
  651. /******************************Public*Routine******************************\
  652. * wglCopyBits2
  653. *
  654. * Calls DrvCopyBits to copy scanline bits into or out of the driver surface.
  655. *
  656. \**************************************************************************/
  657. VOID APIENTRY wglCopyBits2(
  658. HDC hdc, // dst/src device
  659. GLGENwindow *pwnd, // clipping
  660. __GLGENcontext *gengc,
  661. LONG x, // screen coordinate of scan
  662. LONG y,
  663. ULONG cx, // width of scan
  664. BOOL bIn) // if TRUE, copy from bm to dev; otherwise, dev to bm
  665. {
  666. CHECKSCREENLOCKOUT();
  667. // Convert screen coordinates to window coordinates.
  668. x -= pwnd->rclClient.left;
  669. y -= pwnd->rclClient.top;
  670. // this shouldn't happen, but better safe than sorry
  671. if (y < 0)
  672. return;
  673. //!!!XXX
  674. REALIZEPALETTE(hdc);
  675. // Copy from bitmap to device.
  676. if (bIn)
  677. {
  678. LONG xSrc, x0Dst, x1Dst;
  679. if (x < 0)
  680. {
  681. xSrc = -x;
  682. x0Dst = 0;
  683. x1Dst = x + (LONG)cx;
  684. }
  685. else
  686. {
  687. xSrc = 0;
  688. x0Dst = x;
  689. x1Dst = x + (LONG)cx;
  690. }
  691. if (x1Dst <= x0Dst)
  692. return;
  693. BitBlt(hdc, x0Dst, y, cx, 1,
  694. gengc->ColorsMemDC, xSrc, 0, SRCCOPY);
  695. }
  696. // Copy from device to bitmap.
  697. else
  698. {
  699. LONG xSrc, x0Dst, x1Dst;
  700. if (x < 0)
  701. {
  702. xSrc = 0;
  703. x0Dst = -x;
  704. x1Dst = (LONG)cx;
  705. }
  706. else
  707. {
  708. xSrc = x;
  709. x0Dst = 0;
  710. x1Dst = (LONG)cx;
  711. }
  712. if (x1Dst <= x0Dst)
  713. return;
  714. if (dwPlatformId == VER_PLATFORM_WIN32_NT ||
  715. GLSURF_IS_MEMDC(gengc->dwCurrentFlags))
  716. {
  717. BitBlt(gengc->ColorsMemDC, x0Dst, 0, cx, 1,
  718. hdc, xSrc, y, SRCCOPY);
  719. }
  720. else
  721. {
  722. /* If we're copying from the screen,
  723. copy through a DDB to avoid some layers of unnecessary
  724. code in Win95 that deals with translating between
  725. different bitmap layouts */
  726. if (gengc->ColorsDdbDc)
  727. {
  728. BitBlt(gengc->ColorsDdbDc, 0, 0, cx, 1,
  729. hdc, xSrc, y, SRCCOPY);
  730. BitBlt(gengc->ColorsMemDC, x0Dst, 0, cx, 1,
  731. gengc->ColorsDdbDc, 0, 0, SRCCOPY);
  732. }
  733. else
  734. {
  735. //!!!Viper fix -- Diamond Viper (Weitek 9000) fails
  736. //!!! CreateCompatibleBitmap for some
  737. //!!! (currently unknown) reason. Thus,
  738. //!!! the DDB does not exist and we will
  739. //!!! have to incur the perf. hit.
  740. BitBlt(gengc->ColorsMemDC, x0Dst, 0, cx, 1,
  741. hdc, xSrc, y, SRCCOPY);
  742. }
  743. }
  744. }
  745. GDIFLUSH;
  746. }
  747. /******************************Public*Routine******************************\
  748. *
  749. * wglTranslateColor
  750. *
  751. * Transforms a GL logical color into a Windows COLORREF
  752. *
  753. * Note: This is relatively expensive so it should be avoided if possible
  754. *
  755. * History:
  756. * Tue Aug 15 15:23:29 1995 -by- Drew Bliss [drewb]
  757. * Created
  758. *
  759. \**************************************************************************/
  760. COLORREF wglTranslateColor(COLORREF crColor,
  761. HDC hdc,
  762. __GLGENcontext *gengc,
  763. PIXELFORMATDESCRIPTOR *ppfd)
  764. {
  765. //!!!XXX
  766. REALIZEPALETTE(hdc);
  767. // If palette managed, then crColor is actually a palette index.
  768. if ( ppfd->cColorBits <= 8 )
  769. {
  770. PALETTEENTRY peTmp;
  771. ASSERTOPENGL(
  772. crColor < (COLORREF) (1 << ppfd->cColorBits),
  773. "TranslateColor(): bad color\n"
  774. );
  775. // If rendering to a bitmap, we need to do different things depending
  776. // on whether it's a DIB or DDB
  777. if ( gengc->gc.drawBuffer->buf.flags & MEMORY_DC )
  778. {
  779. DIBSECTION ds;
  780. // Check whether we're drawing to a DIB or a DDB
  781. if (GetObject(GetCurrentObject(hdc, OBJ_BITMAP),
  782. sizeof(ds), &ds) == sizeof(ds) && ds.dsBm.bmBits)
  783. {
  784. RGBQUAD rgbq;
  785. // Drawing to a DIB so retrieve the color from the
  786. // DIB color table
  787. if (GetDIBColorTable(hdc, crColor, 1, &rgbq))
  788. {
  789. crColor = RGB(rgbq.rgbRed, rgbq.rgbGreen,
  790. rgbq.rgbBlue);
  791. }
  792. else
  793. {
  794. WARNING("TranslateColor(): GetDIBColorTable failed\n");
  795. crColor = RGB(0, 0, 0);
  796. }
  797. }
  798. else
  799. {
  800. // Reverse the forward translation so that we get back
  801. // to a normal palette index
  802. crColor = gengc->pajInvTranslateVector[crColor];
  803. // Drawing to a DDB so we can just use the palette
  804. // index directly since going through the inverse
  805. // translation table has given us an index into
  806. // the logical palette
  807. crColor = PALETTEINDEX((WORD) crColor);
  808. }
  809. }
  810. // Otherwise...
  811. else
  812. {
  813. // I hate to have to confess this, but I don't really understand
  814. // why this needs to be this way. Either way should work regardless
  815. // of the bit depth.
  816. //
  817. // The reality is that 4bpp we *have* to go into the system palette
  818. // and fetch an RGB value. At 8bpp on the MGA driver (and possibly
  819. // others), we *have* to specify PALETTEINDEX.
  820. if ( ppfd->cColorBits == 4 )
  821. {
  822. if ( wglGetSystemPaletteEntries(hdc, crColor, 1, &peTmp) )
  823. {
  824. crColor = RGB(peTmp.peRed, peTmp.peGreen, peTmp.peBlue);
  825. }
  826. else
  827. {
  828. WARNING("TranslateColor(): wglGetSystemPaletteEntries failed\n");
  829. crColor = RGB(0, 0, 0);
  830. }
  831. }
  832. else
  833. {
  834. if (!(gengc->flags & GENGC_MCD_BGR_INTO_RGB))
  835. crColor = gengc->pajInvTranslateVector[crColor];
  836. crColor = PALETTEINDEX((WORD) crColor);
  837. }
  838. }
  839. }
  840. // If 24BPP DIB section, BGR ordering is implied.
  841. else if ( ppfd->cColorBits == 24 )
  842. {
  843. crColor = RGB((crColor & 0xff0000) >> 16,
  844. (crColor & 0x00ff00) >> 8,
  845. (crColor & 0x0000ff));
  846. }
  847. // Win95 and 16 BPP case.
  848. //
  849. // On Win95, additional munging is necessary to get a COLORREF value
  850. // that will result in a non-dithered brush.
  851. else if ( (dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) &&
  852. (ppfd->cColorBits == 16) )
  853. {
  854. HBITMAP hbmTmp;
  855. HDC hdcTmp;
  856. if (hdcTmp = CreateCompatibleDC(hdc))
  857. {
  858. if (hbmTmp = CreateCompatibleBitmap(hdc, 1, 1))
  859. {
  860. HBITMAP hbmOld;
  861. hbmOld = SelectObject(hdcTmp, hbmTmp);
  862. if (SetBitmapBits(hbmTmp, 2, (VOID *) &crColor))
  863. {
  864. crColor = GetPixel(hdcTmp, 0, 0);
  865. }
  866. else
  867. {
  868. WARNING("TranslateColor(): SetBitmapBits failed\n");
  869. }
  870. SelectObject(hdcTmp, hbmOld);
  871. DeleteObject(hbmTmp);
  872. }
  873. else
  874. {
  875. WARNING("TranslateColor(): CreateCompatibleBitmap failed\n");
  876. }
  877. DeleteDC(hdcTmp);
  878. }
  879. else
  880. {
  881. WARNING("TranslateColor(): CreateCompatibleDC failed\n");
  882. }
  883. }
  884. // Bitfield format (16BPP or 32BPP).
  885. else
  886. {
  887. // Shift right to position bits at zero and then scale into
  888. // an 8-bit quantity
  889. //!!!XXX -- use rounding?!?
  890. crColor =
  891. RGB(((crColor & gengc->gc.modes.redMask) >> ppfd->cRedShift) *
  892. 255 / ((1 << ppfd->cRedBits) - 1),
  893. ((crColor & gengc->gc.modes.greenMask) >> ppfd->cGreenShift) *
  894. 255 / ((1 << ppfd->cGreenBits) - 1),
  895. ((crColor & gengc->gc.modes.blueMask) >> ppfd->cBlueShift) *
  896. 255 / ((1 << ppfd->cBlueBits) - 1));
  897. }
  898. return crColor;
  899. }
  900. /******************************Public*Routine******************************\
  901. * wglFillRect
  902. *
  903. * Calls DrvBitBlt to fill a rectangle area of a driver surface with a
  904. * given color.
  905. *
  906. \**************************************************************************/
  907. VOID APIENTRY wglFillRect(
  908. __GLGENcontext *gengc,
  909. GLGENwindow *pwnd,
  910. PRECTL prcl, // screen coordinate of the rectangle area
  911. COLORREF crColor) // color to set
  912. {
  913. HBRUSH hbr;
  914. PIXELFORMATDESCRIPTOR *ppfd = &gengc->gsurf.pfd;
  915. CHECKSCREENLOCKOUT();
  916. // If the rectangle is empty, return.
  917. if ( (prcl->left >= prcl->right) || (prcl->top >= prcl->bottom) )
  918. {
  919. WARNING("wglFillRect(): bad or empty rectangle\n");
  920. return;
  921. }
  922. // Convert from screen to window coordinates.
  923. prcl->left -= pwnd->rclClient.left;
  924. prcl->right -= pwnd->rclClient.left;
  925. prcl->top -= pwnd->rclClient.top;
  926. prcl->bottom -= pwnd->rclClient.top;
  927. // Make a solid color brush and fill the rectangle.
  928. // If the fill color is the same as the last one, we can reuse
  929. // the cached brush rather than creating a new one
  930. if (crColor == gengc->crFill &&
  931. gengc->gwidCurrent.hdc == gengc->hdcFill)
  932. {
  933. hbr = gengc->hbrFill;
  934. ASSERTOPENGL(hbr != NULL, "Cached fill brush is null\n");
  935. }
  936. else
  937. {
  938. if (gengc->hbrFill != NULL)
  939. {
  940. DeleteObject(gengc->hbrFill);
  941. }
  942. gengc->crFill = crColor;
  943. crColor = wglTranslateColor(crColor, gengc->gwidCurrent.hdc, gengc, ppfd);
  944. hbr = CreateSolidBrush(crColor);
  945. gengc->hbrFill = hbr;
  946. if (hbr == NULL)
  947. {
  948. gengc->crFill = COLORREF_UNUSED;
  949. return;
  950. }
  951. gengc->hdcFill = gengc->gwidCurrent.hdc;
  952. }
  953. FillRect(gengc->gwidCurrent.hdc, (RECT *) prcl, hbr);
  954. GDIFLUSH;
  955. }
  956. /******************************Public*Routine******************************\
  957. * wglCopyBuf
  958. *
  959. * Calls DrvCopyBits to copy a bitmap into the driver surface.
  960. *
  961. \**************************************************************************/
  962. //!!!XXX -- change to a macro
  963. VOID APIENTRY wglCopyBuf(
  964. HDC hdc, // dst/src DCOBJ
  965. HDC hdcBmp, // scr/dst bitmap
  966. LONG x, // dst rect (UL corner) in window coord.
  967. LONG y,
  968. ULONG cx, // width of dest rect
  969. ULONG cy // height of dest rect
  970. )
  971. {
  972. CHECKSCREENLOCKOUT();
  973. //!!!XXX
  974. REALIZEPALETTE(hdc);
  975. if (!BitBlt(hdc, x, y, cx, cy, hdcBmp, 0, 0, SRCCOPY))
  976. {
  977. WARNING1("wglCopyBuf BitBlt failed %d\n", GetLastError());
  978. }
  979. GDIFLUSH;
  980. }
  981. /******************************Public*Routine******************************\
  982. * wglCopyBufRECTLIST
  983. *
  984. * Calls DrvCopyBits to copy a bitmap into the driver surface.
  985. *
  986. \**************************************************************************/
  987. VOID APIENTRY wglCopyBufRECTLIST(
  988. HDC hdc, // dst/src DCOBJ
  989. HDC hdcBmp, // scr/dst bitmap
  990. LONG x, // dst rect (UL corner) in window coord.
  991. LONG y,
  992. ULONG cx, // width of dest rect
  993. ULONG cy, // height of dest rect
  994. PRECTLIST prl
  995. )
  996. {
  997. PYLIST pylist;
  998. CHECKSCREENLOCKOUT();
  999. //!!!XXX
  1000. REALIZEPALETTE(hdc);
  1001. for (pylist = prl->pylist; pylist != NULL; pylist = pylist->pnext)
  1002. {
  1003. PXLIST pxlist;
  1004. for (pxlist = pylist->pxlist; pxlist != NULL; pxlist = pxlist->pnext)
  1005. {
  1006. int xx = pxlist->s;
  1007. int cxx = pxlist->e - pxlist->s;
  1008. int yy = pylist->s;
  1009. int cyy = pylist->e - pylist->s;
  1010. if (!BitBlt(hdc, xx, yy, cxx, cyy, hdcBmp, xx, yy, SRCCOPY))
  1011. {
  1012. WARNING1("wglCopyBufRL BitBlt failed %d\n", GetLastError());
  1013. }
  1014. }
  1015. }
  1016. GDIFLUSH;
  1017. }
  1018. /******************************Public*Routine******************************\
  1019. * wglPaletteChanged
  1020. *
  1021. * Check if the palette changed.
  1022. *
  1023. * If the surface for the DC is palette managed we care about the
  1024. * foreground realization, so, return iUniq
  1025. *
  1026. * If the surface is not palette managed, return ulTime
  1027. *
  1028. \**************************************************************************/
  1029. ULONG APIENTRY wglPaletteChanged(__GLGENcontext *gengc,
  1030. GLGENwindow *pwnd)
  1031. {
  1032. ULONG ulRet = 0;
  1033. HDC hdc;
  1034. // Palette must stay fixed for DirectDraw after initialization
  1035. if (gengc->dwCurrentFlags & GLSURF_DIRECTDRAW)
  1036. {
  1037. if (gengc->PaletteTimestamp == 0xffffffff)
  1038. {
  1039. return 0;
  1040. }
  1041. else
  1042. {
  1043. return gengc->PaletteTimestamp;
  1044. }
  1045. }
  1046. hdc = gengc->gwidCurrent.hdc;
  1047. // Technically we shouldn't be making these GDI calls while we
  1048. // have a screen lock but currently it would be very difficult
  1049. // to fix because we're actually invoking this routine in
  1050. // glsrvGrabLock in order to ensure that we have stable information
  1051. // while we have the lock
  1052. // We don't seem to be having too many problems so for the moment
  1053. // this will be commented out
  1054. // CHECKSCREENLOCKOUT();
  1055. if (pwnd)
  1056. {
  1057. PIXELFORMATDESCRIPTOR *ppfd = &gengc->gsurf.pfd;
  1058. BYTE cBitsThreshold;
  1059. // WM_PALETTECHANGED messages are sent for 8bpp on Win95 when the
  1060. // palette is realized. This allows us to update the palette time.
  1061. //
  1062. // When running WinNT on >= 8bpp or running Win95 on >= 16bpp,
  1063. // WM_PALETTECHANGED is not sent so we need to manually examine
  1064. // the contents of the logical palette and compare it with a previously
  1065. // cached copy to look for a palette change.
  1066. cBitsThreshold = ( dwPlatformId == VER_PLATFORM_WIN32_NT ) ? 8 : 16;
  1067. if (((ppfd->cColorBits >= cBitsThreshold) &&
  1068. (ppfd->iPixelType == PFD_TYPE_COLORINDEX)) )
  1069. {
  1070. if ( !gengc->ppalBuf )
  1071. {
  1072. UINT cjPal, cjRgb;
  1073. // Allocate buffer space for *two* copies of the palette.
  1074. // That way we don't need to dynamically allocate space
  1075. // for temp storage of the palette. Also,we don't need
  1076. // to copy the current palette to the save buffer if we
  1077. // keep two pointers (one for the temp storage and one for
  1078. // the saved copy) and swap them.
  1079. cjRgb = 0;
  1080. cjPal = sizeof(LOGPALETTE) +
  1081. (MAXPALENTRIES * sizeof(PALETTEENTRY));
  1082. gengc->ppalBuf = (LOGPALETTE *)
  1083. ALLOC((cjPal + cjRgb) * 2);
  1084. if ( gengc->ppalBuf )
  1085. {
  1086. // Setup the logical palette buffers.
  1087. gengc->ppalSave = gengc->ppalBuf;
  1088. gengc->ppalTemp = (LOGPALETTE *)
  1089. (((BYTE *) gengc->ppalBuf) + cjPal);
  1090. gengc->ppalSave->palVersion = 0x300;
  1091. gengc->ppalTemp->palVersion = 0x300;
  1092. // How many palette entries? Note that only the first
  1093. // MAXPALENTRIES are significant to generic OpenGL. The
  1094. // rest are ignored.
  1095. gengc->ppalSave->palNumEntries =
  1096. (WORD) GetPaletteEntries(
  1097. GetCurrentObject(hdc, OBJ_PAL),
  1098. 0, 0, (LPPALETTEENTRY) NULL
  1099. );
  1100. gengc->ppalSave->palNumEntries =
  1101. min(gengc->ppalSave->palNumEntries, MAXPALENTRIES);
  1102. gengc->ppalSave->palNumEntries =
  1103. (WORD) GetPaletteEntries(
  1104. GetCurrentObject(hdc, OBJ_PAL),
  1105. 0, gengc->ppalSave->palNumEntries,
  1106. gengc->ppalSave->palPalEntry
  1107. );
  1108. // Since we had to allocate buffer, this must be the
  1109. // first time wglPaletteChanged was called for this
  1110. // context.
  1111. pwnd->ulPaletteUniq++;
  1112. }
  1113. }
  1114. else
  1115. {
  1116. BOOL bNewPal = FALSE; // TRUE if log palette is different
  1117. // How many palette entries? Note that only the first
  1118. // MAXPALENTRIES are significant to generic OpenGL. The
  1119. // rest are ignored.
  1120. gengc->ppalTemp->palNumEntries =
  1121. (WORD) GetPaletteEntries(
  1122. GetCurrentObject(hdc, OBJ_PAL),
  1123. 0, 0, (LPPALETTEENTRY) NULL
  1124. );
  1125. gengc->ppalTemp->palNumEntries =
  1126. min(gengc->ppalTemp->palNumEntries, MAXPALENTRIES);
  1127. gengc->ppalTemp->palNumEntries =
  1128. (WORD) GetPaletteEntries(
  1129. GetCurrentObject(hdc, OBJ_PAL),
  1130. 0, gengc->ppalTemp->palNumEntries,
  1131. gengc->ppalTemp->palPalEntry
  1132. );
  1133. // If number of entries differ, know the palette has changed.
  1134. // Otherwise, need to do the hard word of comparing each entry.
  1135. ASSERTOPENGL(
  1136. sizeof(PALETTEENTRY) == sizeof(ULONG),
  1137. "wglPaletteChanged(): PALETTEENTRY should be 4 bytes\n"
  1138. );
  1139. // If color table comparison already detected a change, no
  1140. // need to do logpal comparison.
  1141. //
  1142. // However, we will still go ahead and swap logpal pointers
  1143. // below because we want the palette cache to stay current.
  1144. if ( !bNewPal )
  1145. {
  1146. bNewPal = (gengc->ppalSave->palNumEntries != gengc->ppalTemp->palNumEntries);
  1147. if ( !bNewPal )
  1148. {
  1149. bNewPal = !LocalCompareUlongMemory(
  1150. gengc->ppalSave->palPalEntry,
  1151. gengc->ppalTemp->palPalEntry,
  1152. gengc->ppalSave->palNumEntries * sizeof(PALETTEENTRY)
  1153. );
  1154. }
  1155. }
  1156. // So, if palette is different, increment uniqueness and
  1157. // update the saved copy.
  1158. if ( bNewPal )
  1159. {
  1160. LOGPALETTE *ppal;
  1161. pwnd->ulPaletteUniq++;
  1162. // Update saved palette by swapping pointers.
  1163. ppal = gengc->ppalSave;
  1164. gengc->ppalSave = gengc->ppalTemp;
  1165. gengc->ppalTemp = ppal;
  1166. }
  1167. }
  1168. }
  1169. ulRet = pwnd->ulPaletteUniq;
  1170. }
  1171. return ulRet;
  1172. }
  1173. /******************************Public*Routine******************************\
  1174. * wglPaletteSize
  1175. *
  1176. * Return the size of the current palette
  1177. *
  1178. \**************************************************************************/
  1179. //!!!XXX -- make into a macro?
  1180. ULONG APIENTRY wglPaletteSize(__GLGENcontext *gengc)
  1181. {
  1182. CHECKSCREENLOCKOUT();
  1183. if (gengc->dwCurrentFlags & GLSURF_DIRECTDRAW)
  1184. {
  1185. DWORD dwCaps;
  1186. LPDIRECTDRAWPALETTE pddp = NULL;
  1187. HRESULT hr;
  1188. if (gengc->gsurf.dd.gddsFront.pdds->lpVtbl->
  1189. GetPalette(gengc->gsurf.dd.gddsFront.pdds, &pddp) != DD_OK ||
  1190. pddp == NULL)
  1191. {
  1192. return 0;
  1193. }
  1194. hr = pddp->lpVtbl->GetCaps(pddp, &dwCaps);
  1195. pddp->lpVtbl->Release(pddp);
  1196. if (hr != DD_OK)
  1197. {
  1198. return 0;
  1199. }
  1200. if (dwCaps & DDPCAPS_1BIT)
  1201. {
  1202. return 1;
  1203. }
  1204. else if (dwCaps & DDPCAPS_2BIT)
  1205. {
  1206. return 4;
  1207. }
  1208. else if (dwCaps & DDPCAPS_4BIT)
  1209. {
  1210. return 16;
  1211. }
  1212. else if (dwCaps & DDPCAPS_8BIT)
  1213. {
  1214. return 256;
  1215. }
  1216. else
  1217. return 0;
  1218. }
  1219. else
  1220. {
  1221. return GetPaletteEntries(GetCurrentObject(gengc->gwidCurrent.hdc,
  1222. OBJ_PAL), 0, 0, NULL);
  1223. }
  1224. }
  1225. /******************************Public*Routine******************************\
  1226. * wglComputeIndexedColors
  1227. *
  1228. * Copy current index-to-color table to the supplied array. Colors are
  1229. * formatted as specified in the current pixelformat and are put into the
  1230. * table as DWORDs (i.e., DWORD alignment) starting at the second DWORD.
  1231. * The first DWORD in the table is the number of colors in the table.
  1232. *
  1233. * History:
  1234. * 15-Dec-1994 -by- Gilman Wong [gilmanw]
  1235. * Ported from gdi\gre\wglsup.cxx.
  1236. \**************************************************************************/
  1237. BOOL APIENTRY wglComputeIndexedColors(__GLGENcontext *gengc, ULONG *rgbTable,
  1238. ULONG cEntries)
  1239. {
  1240. UINT cColors = 0;
  1241. LPPALETTEENTRY lppe, lppeTable;
  1242. UINT i;
  1243. LPDIRECTDRAWPALETTE pddp = NULL;
  1244. CHECKSCREENLOCKOUT();
  1245. // first element in table is number of entries
  1246. rgbTable[0] = min(wglPaletteSize(gengc), cEntries);
  1247. lppeTable = (LPPALETTEENTRY)
  1248. ALLOC(sizeof(PALETTEENTRY) * rgbTable[0]);
  1249. if (lppeTable)
  1250. {
  1251. int rScale, gScale, bScale;
  1252. int rShift, gShift, bShift;
  1253. rScale = (1 << gengc->gsurf.pfd.cRedBits ) - 1;
  1254. gScale = (1 << gengc->gsurf.pfd.cGreenBits) - 1;
  1255. bScale = (1 << gengc->gsurf.pfd.cBlueBits ) - 1;
  1256. rShift = gengc->gsurf.pfd.cRedShift ;
  1257. gShift = gengc->gsurf.pfd.cGreenShift;
  1258. bShift = gengc->gsurf.pfd.cBlueShift ;
  1259. if (gengc->dwCurrentFlags & GLSURF_DIRECTDRAW)
  1260. {
  1261. if (gengc->gsurf.dd.gddsFront.pdds->lpVtbl->
  1262. GetPalette(gengc->gsurf.dd.gddsFront.pdds, &pddp) != DD_OK ||
  1263. pddp == NULL)
  1264. {
  1265. return 0;
  1266. }
  1267. if (pddp->lpVtbl->GetEntries(pddp, 0, 0,
  1268. rgbTable[0], lppeTable) != DD_OK)
  1269. {
  1270. cColors = 0;
  1271. }
  1272. else
  1273. {
  1274. cColors = rgbTable[0];
  1275. }
  1276. }
  1277. else
  1278. {
  1279. cColors = GetPaletteEntries(GetCurrentObject(gengc->gwidCurrent.hdc,
  1280. OBJ_PAL),
  1281. 0, rgbTable[0], lppeTable);
  1282. }
  1283. for (i = 1, lppe = lppeTable; i <= cColors; i++, lppe++)
  1284. {
  1285. // Whack the PALETTEENTRY color into proper color format. Store as
  1286. // ULONG.
  1287. //!!!XXX -- use rounding?!?
  1288. rgbTable[i] = (((ULONG)lppe->peRed * rScale / 255) << rShift) |
  1289. (((ULONG)lppe->peGreen * gScale / 255) << gShift) |
  1290. (((ULONG)lppe->peBlue * bScale / 255) << bShift);
  1291. }
  1292. FREE(lppeTable);
  1293. }
  1294. if (pddp != NULL)
  1295. {
  1296. pddp->lpVtbl->Release(pddp);
  1297. }
  1298. return(cColors != 0);
  1299. }
  1300. /******************************Public*Routine******************************\
  1301. * wglValidPixelFormat
  1302. *
  1303. * Determines if a pixelformat is usable with the DC specified.
  1304. *
  1305. \**************************************************************************/
  1306. BOOL APIENTRY wglValidPixelFormat(HDC hdc, int ipfd, DWORD dwObjectType,
  1307. LPDIRECTDRAWSURFACE pdds,
  1308. DDSURFACEDESC *pddsd)
  1309. {
  1310. BOOL bRet = FALSE;
  1311. PIXELFORMATDESCRIPTOR pfd, pfdDC;
  1312. if ( wglDescribePixelFormat(hdc, ipfd, sizeof(pfd), &pfd) )
  1313. {
  1314. if ( dwObjectType == OBJ_DC )
  1315. {
  1316. // We have a display DC; make sure the pixelformat allows drawing
  1317. // to the window.
  1318. bRet = ( (pfd.dwFlags & PFD_DRAW_TO_WINDOW) != 0 );
  1319. if (!bRet)
  1320. {
  1321. SetLastError(ERROR_INVALID_FLAGS);
  1322. }
  1323. }
  1324. else if ( dwObjectType == OBJ_MEMDC )
  1325. {
  1326. // We have a memory DC. Make sure pixelformat allows drawing
  1327. // to a bitmap.
  1328. if ( pfd.dwFlags & PFD_DRAW_TO_BITMAP )
  1329. {
  1330. // Make sure that the bitmap and pixelformat have the same
  1331. // color depth.
  1332. HBITMAP hbm;
  1333. BITMAP bm;
  1334. ULONG cBitmapColorBits;
  1335. hbm = CreateCompatibleBitmap(hdc, 1, 1);
  1336. if ( hbm )
  1337. {
  1338. if ( GetObject(hbm, sizeof(bm), &bm) )
  1339. {
  1340. cBitmapColorBits = bm.bmPlanes * bm.bmBitsPixel;
  1341. bRet = ( cBitmapColorBits == pfd.cColorBits );
  1342. if (!bRet)
  1343. {
  1344. SetLastError(ERROR_INVALID_FUNCTION);
  1345. }
  1346. }
  1347. else
  1348. {
  1349. WARNING("wglValidPixelFormat: GetObject failed\n");
  1350. }
  1351. DeleteObject(hbm);
  1352. }
  1353. else
  1354. {
  1355. WARNING("wglValidPixelFormat: Unable to create cbm\n");
  1356. }
  1357. }
  1358. }
  1359. else if (dwObjectType == OBJ_ENHMETADC)
  1360. {
  1361. // We don't know anything about what surfaces this
  1362. // metafile will be played back on so allow any kind
  1363. // of pixel format
  1364. bRet = TRUE;
  1365. }
  1366. else if (dwObjectType == OBJ_DDRAW)
  1367. {
  1368. DDSCAPS ddscaps;
  1369. LPDIRECTDRAWSURFACE pddsZ;
  1370. DDSURFACEDESC ddsdZ;
  1371. // We have a DDraw surface.
  1372. // Check that DDraw is supported and that double buffering
  1373. // is not defined.
  1374. if ((pfd.dwFlags & PFD_SUPPORT_DIRECTDRAW) == 0 ||
  1375. (pfd.dwFlags & PFD_DOUBLEBUFFER))
  1376. {
  1377. WARNING1("DDSurf pfd has bad flags 0x%08lX\n", pfd.dwFlags);
  1378. SetLastError(ERROR_INVALID_FLAGS);
  1379. return FALSE;
  1380. }
  1381. // We only understand 4 and 8bpp paletted formats plus RGB
  1382. // We don't support alpha-only or Z-only surfaces
  1383. if ((pddsd->ddpfPixelFormat.dwFlags & (DDPF_PALETTEINDEXED4 |
  1384. DDPF_PALETTEINDEXED8 |
  1385. DDPF_RGB)) == 0 ||
  1386. (pddsd->ddpfPixelFormat.dwFlags & (DDPF_ALPHA |
  1387. DDPF_ZBUFFER)) != 0)
  1388. {
  1389. WARNING1("DDSurf ddpf has bad flags, 0x%08lX\n",
  1390. pddsd->ddpfPixelFormat.dwFlags);
  1391. SetLastError(ERROR_INVALID_PIXEL_FORMAT);
  1392. return FALSE;
  1393. }
  1394. if (DdPixelDepth(pddsd) != pfd.cColorBits)
  1395. {
  1396. WARNING2("DDSurf pfd cColorBits %d "
  1397. "doesn't match ddsd depth %d\n",
  1398. pfd.cColorBits, DdPixelDepth(pddsd));
  1399. SetLastError(ERROR_INVALID_PIXEL_FORMAT);
  1400. return FALSE;
  1401. }
  1402. // Check for alpha
  1403. if (pfd.cAlphaBits > 0)
  1404. {
  1405. // Interleaved destination alpha is not supported.
  1406. if (pddsd->ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS)
  1407. {
  1408. WARNING("DDSurf has alpha pixels\n");
  1409. SetLastError(ERROR_INVALID_PIXEL_FORMAT);
  1410. return FALSE;
  1411. }
  1412. }
  1413. // Check for an attached Z buffer
  1414. memset(&ddscaps, 0, sizeof(ddscaps));
  1415. ddscaps.dwCaps = DDSCAPS_ZBUFFER;
  1416. if (pdds->lpVtbl->
  1417. GetAttachedSurface(pdds, &ddscaps, &pddsZ) == DD_OK)
  1418. {
  1419. HRESULT hr;
  1420. memset(&ddsdZ, 0, sizeof(ddsdZ));
  1421. ddsdZ.dwSize = sizeof(ddsdZ);
  1422. hr = pddsZ->lpVtbl->GetSurfaceDesc(pddsZ, &ddsdZ);
  1423. pddsZ->lpVtbl->Release(pddsZ);
  1424. if (hr != DD_OK)
  1425. {
  1426. WARNING("Unable to get Z ddsd\n");
  1427. return FALSE;
  1428. }
  1429. // Ensure that the Z surface depth is the same as the
  1430. // one in the pixel format
  1431. if (pfd.cDepthBits !=
  1432. (BYTE)DdPixDepthToCount(ddsdZ.ddpfPixelFormat.
  1433. dwZBufferBitDepth))
  1434. {
  1435. WARNING2("DDSurf pfd cDepthBits %d doesn't match "
  1436. "Z ddsd depth %d\n", pfd.cDepthBits,
  1437. DdPixDepthToCount(ddsdZ.ddpfPixelFormat.
  1438. dwZBufferBitDepth));
  1439. SetLastError(ERROR_INVALID_PIXEL_FORMAT);
  1440. return FALSE;
  1441. }
  1442. }
  1443. else
  1444. {
  1445. // No Z so make sure the pfd doesn't ask for it
  1446. if (pfd.cDepthBits > 0)
  1447. {
  1448. WARNING("DDSurf pfd wants depth with no Z attached\n");
  1449. SetLastError(ERROR_INVALID_PIXEL_FORMAT);
  1450. return FALSE;
  1451. }
  1452. }
  1453. bRet = TRUE;
  1454. }
  1455. else
  1456. {
  1457. WARNING("wglValidPixelFormat: not a valid DC!\n");
  1458. }
  1459. }
  1460. else
  1461. {
  1462. WARNING("wglValidPixelFormat: wglDescribePixelFormat failed\n");
  1463. }
  1464. return bRet;
  1465. }
  1466. /******************************Public*Routine******************************\
  1467. * wglMakeScans
  1468. *
  1469. * Converts the visible rectangle list in the provided GLGENwindow to a
  1470. * scan-based data structure. The scan-data is put into the GLGENwindow
  1471. * structure.
  1472. *
  1473. * Note: this function assumes that the rectangles are already organized
  1474. * top-down, left-right in scans. This is true for Windows NT 3.5 and
  1475. * Windows 95. This is because the internal representation of regions
  1476. * in both systems is already a scan-based structure. When the APIs
  1477. * (such as GetRegionData) convert the scans to rectangles, the rectangles
  1478. * automatically have this property.
  1479. *
  1480. * Returns:
  1481. * TRUE if successful, FALSE otherwise.
  1482. * Note: if failure, clipping info is invalid.
  1483. *
  1484. * History:
  1485. * 05-Dec-1994 -by- Gilman Wong [gilmanw]
  1486. * Wrote it.
  1487. \**************************************************************************/
  1488. BOOL APIENTRY wglMakeScans(GLGENwindow *pwnd)
  1489. {
  1490. RECT *prc, *prcEnd;
  1491. LONG lPrevScanTop;
  1492. ULONG cScans = 0;
  1493. UINT cjNeed;
  1494. GLGENscan *pscan;
  1495. LONG *plWalls;
  1496. ASSERTOPENGL(
  1497. pwnd->prgndat,
  1498. "wglMakeScans(): NULL region data\n"
  1499. );
  1500. ASSERTOPENGL(
  1501. pwnd->prgndat->rdh.iType == RDH_RECTANGLES,
  1502. "wglMakeScans(): not RDH_RECTANGLES!\n"
  1503. );
  1504. // Bail out if no rectangles.
  1505. if (pwnd->prgndat->rdh.nCount == 0)
  1506. return TRUE;
  1507. // First pass: determine the number of scans.
  1508. lPrevScanTop = -(LONG) 0x7FFFFFFF;
  1509. prc = (RECT *) pwnd->prgndat->Buffer;
  1510. prcEnd = prc + pwnd->prgndat->rdh.nCount;
  1511. for ( ; prc < prcEnd; prc++)
  1512. {
  1513. if (prc->top != lPrevScanTop)
  1514. {
  1515. lPrevScanTop = prc->top;
  1516. cScans++;
  1517. }
  1518. }
  1519. // Determine the size needed: 1 GLGENscanData PLUS a GLGENscan per scan PLUS
  1520. // two walls per rectangle.
  1521. cjNeed = offsetof(GLGENscanData, aScans) +
  1522. cScans * offsetof(GLGENscan, alWalls) +
  1523. pwnd->prgndat->rdh.nCount * sizeof(LONG) * 2;
  1524. // Allocate the scan structure.
  1525. if ( cjNeed > pwnd->cjscandat || !pwnd->pscandat )
  1526. {
  1527. if ( pwnd->pscandat )
  1528. FREE(pwnd->pscandat);
  1529. pwnd->pscandat = ALLOC(pwnd->cjscandat = cjNeed);
  1530. if ( !pwnd->pscandat )
  1531. {
  1532. WARNING("wglMakeScans(): memory failure\n");
  1533. pwnd->cjscandat = 0;
  1534. return FALSE;
  1535. }
  1536. }
  1537. // Second pass: fill the scan structure.
  1538. pwnd->pscandat->cScans = cScans;
  1539. lPrevScanTop = -(LONG) 0x7FFFFFFF;
  1540. prc = (RECT *) pwnd->prgndat->Buffer; // need to reset prc but prcEnd OK
  1541. plWalls = (LONG *) pwnd->pscandat->aScans;
  1542. pscan = (GLGENscan *) NULL;
  1543. for ( ; prc < prcEnd; prc++ )
  1544. {
  1545. // Do we need to start a new scan?
  1546. if ( prc->top != lPrevScanTop )
  1547. {
  1548. // Scan we just finished needs pointer to the next scan. Next
  1549. // will start just after this scan (which, conveniently enough,
  1550. // plWalls is pointing at).
  1551. if ( pscan )
  1552. pscan->pNext = (GLGENscan *) plWalls;
  1553. lPrevScanTop = prc->top;
  1554. // Start the new span.
  1555. pscan = (GLGENscan *) plWalls;
  1556. pscan->cWalls = 0;
  1557. pscan->top = prc->top;
  1558. pscan->bottom = prc->bottom;
  1559. plWalls = pscan->alWalls;
  1560. }
  1561. pscan->cWalls+=2;
  1562. *plWalls++ = prc->left;
  1563. *plWalls++ = prc->right;
  1564. }
  1565. if ( pscan )
  1566. pscan->pNext = (GLGENscan *) NULL; // don't leave ptr unitialized in
  1567. // the last scan
  1568. #if DBG
  1569. DBGLEVEL1(LEVEL_INFO, "\n-----\nwglMakeScans(): cScans = %ld\n", pwnd->pscandat->cScans);
  1570. cScans = pwnd->pscandat->cScans;
  1571. pscan = pwnd->pscandat->aScans;
  1572. for ( ; cScans; cScans--, pscan = pscan->pNext )
  1573. {
  1574. LONG *plWalls = pscan->alWalls;
  1575. LONG *plWallsEnd = plWalls + pscan->cWalls;
  1576. DBGLEVEL3(LEVEL_INFO, "Scan: top = %ld, bottom = %ld, walls = %ld\n", pscan->top, pscan->bottom, pscan->cWalls);
  1577. for ( ; plWalls < plWallsEnd; plWalls+=2 )
  1578. {
  1579. DBGLEVEL2(LEVEL_INFO, "\t%ld, %ld\n", plWalls[0], plWalls[1]);
  1580. }
  1581. }
  1582. #endif
  1583. return TRUE;
  1584. }
  1585. /******************************Public*Routine******************************\
  1586. * wglGetClipList
  1587. *
  1588. * Gets the visible region in the form of a list of rectangles,
  1589. * for the window associated with the given window. The data is placed
  1590. * in the GLGENwindow structure.
  1591. *
  1592. * Returns:
  1593. * TRUE if successful, FALSE otherwise.
  1594. *
  1595. * History:
  1596. * 01-Dec-1994 -by- Gilman Wong [gilmanw]
  1597. * Wrote it.
  1598. \**************************************************************************/
  1599. BOOL APIENTRY wglGetClipList(GLGENwindow *pwnd)
  1600. {
  1601. UINT cj;
  1602. RECT rc;
  1603. // Set clipping to empty. If an error occurs getting clip information,
  1604. // all drawing will be clipped.
  1605. pwnd->clipComplexity = CLC_RECT;
  1606. pwnd->rclBounds.left = 0;
  1607. pwnd->rclBounds.top = 0;
  1608. pwnd->rclBounds.right = 0;
  1609. pwnd->rclBounds.bottom = 0;
  1610. // Make sure we have enough memory to cache the clip list.
  1611. if (pwnd->pddClip->lpVtbl->
  1612. GetClipList(pwnd->pddClip, NULL, NULL, &cj) == DD_OK)
  1613. {
  1614. if ( cj > pwnd->cjrgndat || !pwnd->prgndat )
  1615. {
  1616. if ( pwnd->prgndat )
  1617. FREE(pwnd->prgndat);
  1618. pwnd->prgndat = ALLOC(pwnd->cjrgndat = cj);
  1619. if ( !pwnd->prgndat )
  1620. {
  1621. WARNING("wglGetClipList(): memory failure\n");
  1622. pwnd->cjrgndat = 0;
  1623. return FALSE;
  1624. }
  1625. }
  1626. }
  1627. else
  1628. {
  1629. WARNING("wglGetClipList(): clipper failed to return size\n");
  1630. return FALSE;
  1631. }
  1632. // Get the clip list (RGNDATA format).
  1633. if ( pwnd->pddClip->lpVtbl->
  1634. GetClipList(pwnd->pddClip, NULL, pwnd->prgndat, &cj) == DD_OK )
  1635. {
  1636. // Compose the scan version of the clip list.
  1637. if (!wglMakeScans(pwnd))
  1638. {
  1639. WARNING("wglGetClipList(): scan conversion failed\n");
  1640. return FALSE;
  1641. }
  1642. }
  1643. else
  1644. {
  1645. WARNING("wglGetClipList(): clipper failed\n");
  1646. return FALSE;
  1647. }
  1648. // Fixup the protected portions of the window.
  1649. ASSERT_WINCRIT(pwnd);
  1650. {
  1651. __GLGENbuffers *buffers;
  1652. // Update rclBounds to match RGNDATA bounds.
  1653. pwnd->rclBounds = *(RECTL *) &pwnd->prgndat->rdh.rcBound;
  1654. // Update rclClient to match client area. We cannot do this from the
  1655. // information in RGNDATA as the bounds may be smaller than the window
  1656. // client area. We will have to call GetClientRect().
  1657. GetClientRect(pwnd->gwid.hwnd, (LPRECT) &pwnd->rclClient);
  1658. ClientToScreen(pwnd->gwid.hwnd, (LPPOINT) &pwnd->rclClient);
  1659. pwnd->rclClient.right += pwnd->rclClient.left;
  1660. pwnd->rclClient.bottom += pwnd->rclClient.top;
  1661. //
  1662. // Setup window clip complexity
  1663. //
  1664. if ( pwnd->prgndat->rdh.nCount > 1 )
  1665. {
  1666. // Clip list will be used for clipping.
  1667. pwnd->clipComplexity = CLC_COMPLEX;
  1668. }
  1669. else if ( pwnd->prgndat->rdh.nCount == 1 )
  1670. {
  1671. RECT *prc = (RECT *) pwnd->prgndat->Buffer;
  1672. // Recently, DirectDraw has been occasionally returning rclBounds
  1673. // set to the screen dimensions. This is being investigated as a
  1674. // bug on DDraw's part, but let us protect ourselves in any case.
  1675. //
  1676. // When there is only a single clip rectangle, it should be
  1677. // the same as the bounds.
  1678. pwnd->rclBounds = *((RECTL *) prc);
  1679. // If bounds rectangle is smaller than client area, we need to
  1680. // clip to the bounds rectangle. Otherwise, clip to the window
  1681. // client area.
  1682. if ( (pwnd->rclBounds.left <= pwnd->rclClient.left ) &&
  1683. (pwnd->rclBounds.right >= pwnd->rclClient.right ) &&
  1684. (pwnd->rclBounds.top <= pwnd->rclClient.top ) &&
  1685. (pwnd->rclBounds.bottom >= pwnd->rclClient.bottom) )
  1686. pwnd->clipComplexity = CLC_TRIVIAL;
  1687. else
  1688. pwnd->clipComplexity = CLC_RECT;
  1689. }
  1690. else
  1691. {
  1692. // Clip count is zero. Bounds should be an empty rectangle.
  1693. pwnd->clipComplexity = CLC_RECT;
  1694. pwnd->rclBounds.left = 0;
  1695. pwnd->rclBounds.top = 0;
  1696. pwnd->rclBounds.right = 0;
  1697. pwnd->rclBounds.bottom = 0;
  1698. }
  1699. // Finally, the window has changed, so change the uniqueness number.
  1700. if ((buffers = pwnd->buffers))
  1701. {
  1702. buffers->WndUniq++;
  1703. // Don't let it hit -1. -1 is special and is used by
  1704. // MakeCurrent to signal that an update is required
  1705. if (buffers->WndUniq == -1)
  1706. buffers->WndUniq = 0;
  1707. }
  1708. }
  1709. return TRUE;
  1710. }
  1711. /******************************Public*Routine******************************\
  1712. * wglCleanupWindow
  1713. *
  1714. * Removes references to the specified window from
  1715. * all contexts by running through the list of RCs in the handle manager
  1716. * table.
  1717. *
  1718. * History:
  1719. * 05-Jul-1994 -by- Gilman Wong [gilmanw]
  1720. * Wrote it.
  1721. \**************************************************************************/
  1722. VOID APIENTRY wglCleanupWindow(GLGENwindow *pwnd)
  1723. {
  1724. if (pwnd)
  1725. {
  1726. //!!!XXX -- For now remove reference from current context. Need to
  1727. //!!!XXX scrub all contexts for multi-threaded cleanup to work.
  1728. //!!!XXX We need to implement a gengc tracking mechanism.
  1729. __GLGENcontext *gengc = (__GLGENcontext *) GLTEB_SRVCONTEXT();
  1730. if ( gengc && (gengc->pwndMakeCur == pwnd) )
  1731. {
  1732. // Found a victim. Must NULL out the pointer both in the RC
  1733. // and in the generic context.
  1734. glsrvCleanupWindow(gengc, pwnd);
  1735. }
  1736. }
  1737. }
  1738. /******************************Public*Routine******************************\
  1739. * wglGetSystemPaletteEntries
  1740. *
  1741. * Internal version of GetSystemPaletteEntries.
  1742. *
  1743. * GetSystemPaletteEntries fails on some 4bpp devices. This wgl version
  1744. * will detect the 4bpp case and supply the hardcoded 16-color VGA palette.
  1745. * Otherwise, it will pass the call on to GDI's GetSystemPaletteEntries.
  1746. *
  1747. * It is expected that this call will only be called in the 4bpp and 8bpp
  1748. * cases as it is not necessary for OpenGL to query the system palette
  1749. * for > 8bpp devices.
  1750. *
  1751. * History:
  1752. * 17-Aug-1995 -by- Gilman Wong [gilmanw]
  1753. * Wrote it.
  1754. \**************************************************************************/
  1755. static PALETTEENTRY gapeVgaPalette[16] =
  1756. {
  1757. { 0, 0, 0, 0 },
  1758. { 0x80,0, 0, 0 },
  1759. { 0, 0x80,0, 0 },
  1760. { 0x80,0x80,0, 0 },
  1761. { 0, 0, 0x80, 0 },
  1762. { 0x80,0, 0x80, 0 },
  1763. { 0, 0x80,0x80, 0 },
  1764. { 0x80,0x80,0x80, 0 },
  1765. { 0xC0,0xC0,0xC0, 0 },
  1766. { 0xFF,0, 0, 0 },
  1767. { 0, 0xFF,0, 0 },
  1768. { 0xFF,0xFF,0, 0 },
  1769. { 0, 0, 0xFF, 0 },
  1770. { 0xFF,0, 0xFF, 0 },
  1771. { 0, 0xFF,0xFF, 0 },
  1772. { 0xFF,0xFF,0xFF, 0 }
  1773. };
  1774. UINT APIENTRY wglGetSystemPaletteEntries(
  1775. HDC hdc,
  1776. UINT iStartIndex,
  1777. UINT nEntries,
  1778. LPPALETTEENTRY lppe)
  1779. {
  1780. int nDeviceBits;
  1781. nDeviceBits = GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES);
  1782. if ( nDeviceBits == 4 )
  1783. {
  1784. if ( lppe )
  1785. {
  1786. nEntries = min(nEntries, (16 - iStartIndex));
  1787. memcpy(lppe, &gapeVgaPalette[iStartIndex],
  1788. nEntries * sizeof(PALETTEENTRY));
  1789. }
  1790. else
  1791. nEntries = 16;
  1792. return nEntries;
  1793. }
  1794. else
  1795. {
  1796. return GetSystemPaletteEntries(hdc, iStartIndex, nEntries, lppe);
  1797. }
  1798. }