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.

897 lines
25 KiB

  1. /******************************Header*File*********************************\
  2. *
  3. * glsup.c
  4. *
  5. * GL metafiling and printing support
  6. *
  7. * History:
  8. * Wed Mar 15 15:20:49 1995 -by- Drew Bliss [drewb]
  9. * Created
  10. *
  11. * Copyright (c) 1995-1999 Microsoft Corporation
  12. *
  13. \**************************************************************************/
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. #include "glsup.h"
  17. // GL metafile callbacks in opengl32
  18. typedef struct _GLMFCALLBACKS
  19. {
  20. BOOL (APIENTRY *GlmfInitPlayback)(HDC, ENHMETAHEADER *, LPRECTL);
  21. BOOL (APIENTRY *GlmfBeginGlsBlock)(HDC);
  22. BOOL (APIENTRY *GlmfPlayGlsRecord)(HDC, DWORD, BYTE *, LPRECTL);
  23. BOOL (APIENTRY *GlmfEndGlsBlock)(HDC);
  24. BOOL (APIENTRY *GlmfEndPlayback)(HDC);
  25. BOOL (APIENTRY *GlmfCloseMetaFile)(HDC);
  26. HGLRC (APIENTRY *wglCreateContext)(HDC);
  27. BOOL (APIENTRY *wglDeleteContext)(HGLRC);
  28. BOOL (APIENTRY *wglMakeCurrent)(HDC, HGLRC);
  29. HGLRC (APIENTRY *wglGetCurrentContext)(void);
  30. } GLMFCALLBACKS;
  31. #define GL_MF_CALLBACKS (sizeof(GLMFCALLBACKS)/sizeof(PROC))
  32. static char *pszGlmfEntryPoints[] =
  33. {
  34. "GlmfInitPlayback",
  35. "GlmfBeginGlsBlock",
  36. "GlmfPlayGlsRecord",
  37. "GlmfEndGlsBlock",
  38. "GlmfEndPlayback",
  39. "GlmfCloseMetaFile",
  40. "wglCreateContext",
  41. "wglDeleteContext",
  42. "wglMakeCurrent",
  43. "wglGetCurrentContext"
  44. };
  45. #define GL_MF_ENTRYPOINTS (sizeof(pszGlmfEntryPoints)/sizeof(char *))
  46. RTL_CRITICAL_SECTION semGlLoad;
  47. static GLMFCALLBACKS gmcGlFuncs = {NULL};
  48. static HMODULE hOpenGL = NULL;
  49. static LONG lLoadCount = 0;
  50. /*****************************Private*Routine******************************\
  51. *
  52. * LoadOpenGL
  53. *
  54. * Loads opengl32.dll if necessary
  55. *
  56. * History:
  57. * Wed Mar 01 10:41:59 1995 -by- Drew Bliss [drewb]
  58. * Created
  59. *
  60. \**************************************************************************/
  61. BOOL LoadOpenGL(void)
  62. {
  63. HMODULE hdll;
  64. BOOL fRet;
  65. PROC *ppfn;
  66. int i;
  67. GLMFCALLBACKS gmc;
  68. ASSERTGDI(GL_MF_CALLBACKS == GL_MF_ENTRYPOINTS,
  69. "Glmf callback/entry points mismatch\n");
  70. ENTERCRITICALSECTION(&semGlLoad);
  71. if (hOpenGL != NULL)
  72. {
  73. goto Success;
  74. }
  75. fRet = FALSE;
  76. hdll = LoadLibrary("opengl32.dll");
  77. if (hdll == NULL)
  78. {
  79. WARNING("Unable to load opengl32.dll\n");
  80. goto Exit;
  81. }
  82. ppfn = (PROC *)&gmc;
  83. for (i = 0; i < GL_MF_CALLBACKS; i++)
  84. {
  85. if (!(*ppfn = (PROC)GetProcAddress(hdll,
  86. pszGlmfEntryPoints[i])))
  87. {
  88. WARNING("opengl32 missing '");
  89. WARNING(pszGlmfEntryPoints[i]);
  90. WARNING("'\n");
  91. FreeLibrary(hdll);
  92. goto Exit;
  93. }
  94. ppfn++;
  95. }
  96. gmcGlFuncs = gmc;
  97. hOpenGL = hdll;
  98. Success:
  99. fRet = TRUE;
  100. lLoadCount++;
  101. Exit:
  102. LEAVECRITICALSECTION(&semGlLoad);
  103. return fRet;
  104. }
  105. /*****************************Private*Routine******************************\
  106. *
  107. * UnloadOpenGL
  108. *
  109. * Unloads opengl32.dll if necessary
  110. *
  111. * History:
  112. * Wed Mar 01 11:02:06 1995 -by- Drew Bliss [drewb]
  113. * Created
  114. *
  115. \**************************************************************************/
  116. void UnloadOpenGL(void)
  117. {
  118. ENTERCRITICALSECTION(&semGlLoad);
  119. ASSERTGDI(lLoadCount > 0, "UnloadOpenGL called without Load\n");
  120. if (--lLoadCount == 0)
  121. {
  122. HMODULE hdll;
  123. ASSERTGDI(hOpenGL != NULL, "Positive load count with no DLL\n");
  124. hdll = hOpenGL;
  125. hOpenGL = NULL;
  126. memset(&gmcGlFuncs, 0, sizeof(gmcGlFuncs));
  127. FreeLibrary(hdll);
  128. }
  129. LEAVECRITICALSECTION(&semGlLoad);
  130. }
  131. /*****************************Private*Routine******************************\
  132. *
  133. * GlmfInitPlayback
  134. *
  135. * Stub to forward call to opengl
  136. *
  137. * History:
  138. * Wed Mar 01 11:02:31 1995 -by- Drew Bliss [drewb]
  139. * Created
  140. *
  141. \**************************************************************************/
  142. BOOL APIENTRY GlmfInitPlayback(HDC hdc, ENHMETAHEADER *pemh, LPRECTL prclDest)
  143. {
  144. ASSERTGDI(gmcGlFuncs.GlmfInitPlayback != NULL,
  145. "GlmfInitPlayback not set\n");
  146. return gmcGlFuncs.GlmfInitPlayback ? gmcGlFuncs.GlmfInitPlayback(hdc, pemh, prclDest) : FALSE;
  147. }
  148. /*****************************Private*Routine******************************\
  149. *
  150. * GlmfBeginGlsBlock
  151. *
  152. * Stub to forward call to opengl
  153. *
  154. * History:
  155. * Mon Apr 10 11:38:13 1995 -by- Drew Bliss [drewb]
  156. * Created
  157. *
  158. \**************************************************************************/
  159. BOOL APIENTRY GlmfBeginGlsBlock(HDC hdc)
  160. {
  161. ASSERTGDI(gmcGlFuncs.GlmfBeginGlsBlock != NULL,
  162. "GlmfBeginGlsBlock not set\n");
  163. return gmcGlFuncs.GlmfBeginGlsBlock ? gmcGlFuncs.GlmfBeginGlsBlock(hdc) : FALSE;
  164. }
  165. /*****************************Private*Routine******************************\
  166. *
  167. * GlmfPlayGlsRecord
  168. *
  169. * Stub to forward call to opengl
  170. *
  171. * History:
  172. * Wed Mar 01 11:02:49 1995 -by- Drew Bliss [drewb]
  173. * Created
  174. *
  175. \**************************************************************************/
  176. BOOL APIENTRY GlmfPlayGlsRecord(HDC hdc, DWORD cb, BYTE *pb,
  177. LPRECTL prclBounds)
  178. {
  179. ASSERTGDI(gmcGlFuncs.GlmfPlayGlsRecord != NULL,
  180. "GlmfPlayGlsRecord not set\n");
  181. return gmcGlFuncs.GlmfPlayGlsRecord ? gmcGlFuncs.GlmfPlayGlsRecord(hdc, cb, pb, prclBounds) : FALSE;
  182. }
  183. /*****************************Private*Routine******************************\
  184. *
  185. * GlmfEndGlsBlock
  186. *
  187. * Stub to forward call to opengl
  188. *
  189. * History:
  190. * Mon Apr 10 11:38:13 1995 -by- Drew Bliss [drewb]
  191. * Created
  192. *
  193. \**************************************************************************/
  194. BOOL APIENTRY GlmfEndGlsBlock(HDC hdc)
  195. {
  196. ASSERTGDI(gmcGlFuncs.GlmfEndGlsBlock != NULL,
  197. "GlmfEndGlsBlock not set\n");
  198. return gmcGlFuncs.GlmfEndGlsBlock ? gmcGlFuncs.GlmfEndGlsBlock(hdc) : FALSE;
  199. }
  200. /*****************************Private*Routine******************************\
  201. *
  202. * GlmfEndPlayback
  203. *
  204. * Stub to forward call to opengl
  205. *
  206. * History:
  207. * Wed Mar 01 11:03:02 1995 -by- Drew Bliss [drewb]
  208. * Created
  209. *
  210. \**************************************************************************/
  211. BOOL APIENTRY GlmfEndPlayback(HDC hdc)
  212. {
  213. BOOL fRet;
  214. ASSERTGDI(gmcGlFuncs.GlmfEndPlayback != NULL,
  215. "GlmfEndPlayback not set\n");
  216. fRet = gmcGlFuncs.GlmfEndPlayback ? gmcGlFuncs.GlmfEndPlayback(hdc) : FALSE;
  217. // WINBUG #82850 2-7-2000 bhouse We might was to unload opengl32.dll
  218. // This is not really a problem . This WINBUG is actually asking about
  219. // if we should unload("opengl32.dll"). The opengl32.dll is loaded as
  220. // a side effect of calling InitGlPrinting() call. This will only cause
  221. // a ref count leak. Also as this is user mode code on the client side.
  222. return fRet;
  223. }
  224. /*****************************Private*Routine******************************\
  225. *
  226. * GlmfCloseMetaFile
  227. *
  228. * Stub to forward call to opengl
  229. *
  230. * History:
  231. * Fri Mar 03 17:50:57 1995 -by- Drew Bliss [drewb]
  232. * Created
  233. *
  234. \**************************************************************************/
  235. BOOL APIENTRY GlmfCloseMetaFile(HDC hdc)
  236. {
  237. if (!LoadOpenGL())
  238. {
  239. return FALSE;
  240. }
  241. ASSERTGDI(gmcGlFuncs.GlmfCloseMetaFile != NULL,
  242. "GlmfCloseMetaFile not set\n");
  243. // WINBUG #82850 2-7-2000 bhouse Investigate need to unload
  244. // Old Comment:
  245. // - Unload?
  246. // This is not really a problem . The WINBUG is actually asking about
  247. // if we should unload("opengl32.dll"). The opengl32.dll is loaded as
  248. // a side effect of calling InitGlPrinting() call. This will only cause
  249. // a ref count leak. Also as this is user mode code on the client side.
  250. return gmcGlFuncs.GlmfCloseMetaFile(hdc);
  251. }
  252. // WINBUG #82854 2-7-2000 bhouse Investigate magic value used for band memory limit
  253. static DWORD cbBandMemoryLimit = 0x400000;
  254. #define RECT_CB(w, h, cbp) ((cbp)*(w)*(h))
  255. // GL has hardcoded limits on maximum rendering size
  256. #define GL_WIDTH_LIMIT 16384
  257. #define GL_HEIGHT_LIMIT 16384
  258. /******************************Public*Routine******************************\
  259. *
  260. * EndGlPrinting
  261. *
  262. * Cleans up resources used while printing OpenGL metafiles
  263. *
  264. * History:
  265. * Wed Apr 12 17:51:24 1995 -by- Drew Bliss [drewb]
  266. * Created
  267. *
  268. \**************************************************************************/
  269. void EndGlPrinting(GLPRINTSTATE *pgps)
  270. {
  271. ASSERTGDI(hOpenGL != NULL, "EndGlPrinting: No opengl\n");
  272. if (pgps->iReduceFactor > 1)
  273. {
  274. if (pgps->bBrushOrgSet)
  275. {
  276. SetBrushOrgEx(pgps->hdcDest,
  277. pgps->ptBrushOrg.x, pgps->ptBrushOrg.y,
  278. NULL);
  279. }
  280. if (pgps->iStretchMode != 0)
  281. {
  282. SetStretchBltMode(pgps->hdcDest, pgps->iStretchMode);
  283. }
  284. }
  285. if (gmcGlFuncs.wglGetCurrentContext() != NULL)
  286. {
  287. gmcGlFuncs.wglMakeCurrent(pgps->hdcDib, NULL);
  288. }
  289. if (pgps->hrc != NULL)
  290. {
  291. gmcGlFuncs.wglDeleteContext(pgps->hrc);
  292. }
  293. if (pgps->hdcDib != NULL)
  294. {
  295. DeleteDC(pgps->hdcDib);
  296. }
  297. if (pgps->hbmDib != NULL)
  298. {
  299. DeleteObject(pgps->hbmDib);
  300. }
  301. // WINBUG #82850 2-7-2000 bhouse Investigate need to unload
  302. // Old Comment:
  303. // - Unload?
  304. // This is not really a problem . The WINBUG is actually asking about
  305. // if we should unload("opengl32.dll"). The opengl32.dll is loaded as
  306. // a side effect of calling InitGlPrinting() call. This will only cause
  307. // a ref count leak. Also as this is user mode code on the client side.
  308. }
  309. /******************************Public*Routine******************************\
  310. *
  311. * InitGlPrinting
  312. *
  313. * Performs all setup necessary for OpenGL printing
  314. *
  315. * History:
  316. * Wed Apr 12 17:51:46 1995 -by- Drew Bliss [drewb]
  317. * Created
  318. *
  319. \**************************************************************************/
  320. BOOL InitGlPrinting(HENHMETAFILE hemf, HDC hdcDest, RECT *rc,
  321. DEVMODEW *pdm, GLPRINTSTATE *pgps)
  322. {
  323. PIXELFORMATDESCRIPTOR pfd;
  324. int iFmt;
  325. BITMAPINFO *pbmi;
  326. BITMAPINFOHEADER *pbmih;
  327. int iWidth, iHeight;
  328. DWORD cbMeta;
  329. POINT pt;
  330. UINT cbPixelFormat;
  331. UINT cbPixel;
  332. UINT nColors;
  333. PVOID pvBits;
  334. // Zero out in case we need to do cleanup
  335. memset(pgps, 0, sizeof(*pgps));
  336. pgps->hdcDest = hdcDest;
  337. if (!LoadOpenGL())
  338. {
  339. return FALSE;
  340. }
  341. pbmi = NULL;
  342. // Set the reduction factor according to the dithering setting
  343. // for the DC
  344. switch(pdm->dmDitherType)
  345. {
  346. case DMDITHER_NONE:
  347. case DMDITHER_LINEART:
  348. pgps->iReduceFactor = 1;
  349. break;
  350. case DMDITHER_COARSE:
  351. pgps->iReduceFactor = 2;
  352. break;
  353. default:
  354. pgps->iReduceFactor = 4;
  355. break;
  356. }
  357. // Put the destination DC into the mode we need for rendering
  358. if (pgps->iReduceFactor > 1)
  359. {
  360. pgps->iStretchMode = SetStretchBltMode(hdcDest, HALFTONE);
  361. if (pgps->iStretchMode == 0)
  362. {
  363. goto EH_Cleanup;
  364. }
  365. // Need to reset the brush origin after changing the stretch mode
  366. if (!SetBrushOrgEx(hdcDest, 0, 0, &pgps->ptBrushOrg))
  367. {
  368. goto EH_Cleanup;
  369. }
  370. pgps->bBrushOrgSet = TRUE;
  371. }
  372. // Get the pixel format in the metafile if one exists
  373. cbPixelFormat = GetEnhMetaFilePixelFormat(hemf, sizeof(pfd), &pfd);
  374. if (cbPixelFormat == GDI_ERROR ||
  375. (cbPixelFormat != 0 && cbPixelFormat != sizeof(pfd)))
  376. {
  377. goto EH_Cleanup;
  378. }
  379. // No pixel format in the header, so use a default
  380. if (cbPixelFormat == 0)
  381. {
  382. pfd.nSize = sizeof(pfd);
  383. pfd.nVersion = 1;
  384. pfd.dwFlags = PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL;
  385. pfd.iPixelType = PFD_TYPE_RGBA;
  386. pfd.cColorBits = 16;
  387. pfd.cRedBits = 5;
  388. pfd.cRedShift = 0;
  389. pfd.cGreenBits = 5;
  390. pfd.cGreenShift = 5;
  391. pfd.cBlueBits = 5;
  392. pfd.cBlueShift = 10;
  393. pfd.cAlphaBits = 0;
  394. pfd.cAccumBits = 0;
  395. pfd.cDepthBits = 16;
  396. pfd.cStencilBits = 0;
  397. pfd.cAuxBuffers = 0;
  398. pfd.iLayerType = PFD_MAIN_PLANE;
  399. }
  400. else
  401. {
  402. // Force draw-to-bitmap and single buffered
  403. // Turn off flags not supported
  404. pfd.dwFlags = (pfd.dwFlags &
  405. ~(PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER |
  406. PFD_STEREO | PFD_SUPPORT_GDI)) |
  407. PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL;
  408. // What happens in color index mode?
  409. if (pfd.iPixelType == PFD_TYPE_RGBA)
  410. {
  411. pfd.cColorBits = 16;
  412. pfd.cRedBits = 5;
  413. pfd.cRedShift = 0;
  414. pfd.cGreenBits = 5;
  415. pfd.cGreenShift = 5;
  416. pfd.cBlueBits = 5;
  417. pfd.cBlueShift = 10;
  418. }
  419. pfd.iLayerType = PFD_MAIN_PLANE;
  420. }
  421. // Determine the amount of memory used per pixel
  422. // This rounds 4bpp to one byte per pixel but that's close
  423. // enough
  424. cbPixel =
  425. (pfd.cColorBits+7)/8+
  426. (pfd.cAlphaBits+7)/8+
  427. (pfd.cAccumBits+7)/8+
  428. (pfd.cDepthBits+7)/8+
  429. (pfd.cStencilBits+7)/8;
  430. // Determine the size of the band based on smaller of:
  431. // The biggest DIB that can fit in cbBandMemoryLimit
  432. // The size of the metafile
  433. // The given rectangle is the size the metafile is supposed to
  434. // be rendered into so base our computations on it
  435. pgps->xSource = rc->left;
  436. pgps->ySource = rc->top;
  437. iWidth = rc->right-rc->left;
  438. iHeight = rc->bottom-rc->top;
  439. if (iWidth == 0 || iHeight == 0)
  440. {
  441. WARNING("InitGlPrinting: Metafile has no size\n");
  442. return FALSE;
  443. }
  444. pgps->iSourceWidth = iWidth;
  445. pgps->iSourceHeight = iHeight;
  446. // Reduce the resolution somewhat to allow halftoning space to work
  447. iWidth = iWidth/pgps->iReduceFactor;
  448. iHeight = iHeight/pgps->iReduceFactor;
  449. pgps->iReducedWidth = iWidth;
  450. pgps->iReducedHeight = iHeight;
  451. if (iWidth > GL_WIDTH_LIMIT)
  452. {
  453. iWidth = GL_WIDTH_LIMIT;
  454. }
  455. if (iHeight > GL_HEIGHT_LIMIT)
  456. {
  457. iHeight = GL_HEIGHT_LIMIT;
  458. }
  459. cbMeta = RECT_CB(iWidth, iHeight, cbPixel);
  460. // Shrink the rectangle until it fits in our memory limit
  461. if (cbMeta > cbBandMemoryLimit)
  462. {
  463. // How many scanlines will fit
  464. iHeight = cbBandMemoryLimit/RECT_CB(iWidth, 1, cbPixel);
  465. if (iHeight == 0)
  466. {
  467. // Can't fit a full scanline, so figure out how much
  468. // of a scanline will fit
  469. iWidth = cbBandMemoryLimit/cbPixel;
  470. iHeight = 1;
  471. }
  472. }
  473. if (iWidth < 1 || iHeight < 1)
  474. {
  475. WARNING("InitGlPrinting: "
  476. "Not enough memory to render anything\n");
  477. return FALSE;
  478. }
  479. // Create a DIB for the band
  480. switch(pfd.cColorBits)
  481. {
  482. case 4:
  483. nColors = 16;
  484. break;
  485. case 8:
  486. nColors = 256;
  487. break;
  488. case 16:
  489. case 32:
  490. nColors = 3;
  491. break;
  492. case 24:
  493. // Use one since it's already included in the BITMAPINFO definition
  494. nColors = 1;
  495. break;
  496. }
  497. pbmi = (BITMAPINFO *)LocalAlloc(LMEM_FIXED,
  498. sizeof(BITMAPINFO)+(nColors-1)*
  499. sizeof(RGBQUAD));
  500. if (pbmi == NULL)
  501. {
  502. goto EH_Cleanup;
  503. }
  504. pbmih = &pbmi->bmiHeader;
  505. pbmih->biSize = sizeof(BITMAPINFOHEADER);
  506. pbmih->biWidth = iWidth;
  507. pbmih->biHeight = iHeight;
  508. pbmih->biPlanes = 1;
  509. pbmih->biBitCount = pfd.cColorBits;
  510. if (pfd.cColorBits == 16 || pfd.cColorBits == 32)
  511. {
  512. pbmih->biCompression = BI_BITFIELDS;
  513. *((DWORD *)pbmi->bmiColors+0) =
  514. ((1 << pfd.cRedBits)-1) << pfd.cRedShift;
  515. *((DWORD *)pbmi->bmiColors+1) =
  516. ((1 << pfd.cGreenBits)-1) << pfd.cGreenShift;
  517. *((DWORD *)pbmi->bmiColors+2) =
  518. ((1 << pfd.cBlueBits)-1) << pfd.cBlueShift;
  519. }
  520. else if (pfd.cColorBits == 24)
  521. {
  522. pbmih->biCompression = BI_RGB;
  523. }
  524. else
  525. {
  526. UINT nEnt, i;
  527. pbmih->biCompression = BI_RGB;
  528. nEnt = GetEnhMetaFilePaletteEntries(hemf, nColors,
  529. (PALETTEENTRY *)pbmi->bmiColors);
  530. if (nEnt == GDI_ERROR)
  531. {
  532. goto EH_Cleanup;
  533. }
  534. // Force the flags byte to zero just to make sure
  535. for (i = 0; i < nEnt; i++)
  536. {
  537. pbmi->bmiColors[i].rgbReserved = 0;
  538. }
  539. }
  540. pbmih->biSizeImage= 0;
  541. pbmih->biXPelsPerMeter = 0;
  542. pbmih->biYPelsPerMeter = 0;
  543. pbmih->biClrUsed = 0;
  544. pbmih->biClrImportant = 0;
  545. // It doesn't matter what this DC is compatible with because that
  546. // will be overridden when we select the DIB into it
  547. pgps->hdcDib = CreateCompatibleDC(NULL);
  548. if (pgps->hdcDib == NULL)
  549. {
  550. WARNING("InitGlPrinting: CreateCompatibleDC failed\n");
  551. goto EH_Cleanup;
  552. }
  553. pgps->hbmDib = CreateDIBSection(pgps->hdcDib, pbmi, DIB_RGB_COLORS,
  554. &pvBits, NULL, 0);
  555. if (pgps->hbmDib == NULL)
  556. {
  557. WARNING("InitGlPrinting: CreateDibSection failed\n");
  558. goto EH_Cleanup;
  559. }
  560. if (SelectObject(pgps->hdcDib, pgps->hbmDib) == NULL)
  561. {
  562. WARNING("InitGlPrinting: SelectObject failed\n");
  563. goto EH_Cleanup;
  564. }
  565. // Set the pixel format for the DC
  566. iFmt = ChoosePixelFormat(pgps->hdcDib, &pfd);
  567. if (iFmt == 0)
  568. {
  569. WARNING("InitGlPrinting: ChoosePixelFormat failed\n");
  570. goto EH_Cleanup;
  571. }
  572. if (!SetPixelFormat(pgps->hdcDib, iFmt, &pfd))
  573. {
  574. WARNING("InitGlPrinting: SetPixelFormat failed\n");
  575. goto EH_Cleanup;
  576. }
  577. pgps->hrc = gmcGlFuncs.wglCreateContext(pgps->hdcDib);
  578. if (pgps->hrc == NULL)
  579. {
  580. WARNING("InitGlPrinting: wglCreateContext failed\n");
  581. goto EH_Cleanup;
  582. }
  583. if (!gmcGlFuncs.wglMakeCurrent(pgps->hdcDib, pgps->hrc))
  584. {
  585. WARNING("InitGlPrinting: wglMakeCurrent failed\n");
  586. goto EH_Cleanup;
  587. }
  588. pgps->iReducedBandWidth = iWidth;
  589. pgps->iBandWidth = iWidth*pgps->iReduceFactor;
  590. pgps->iReducedBandHeight = iHeight;
  591. pgps->iBandHeight = iHeight*pgps->iReduceFactor;
  592. return TRUE;
  593. EH_Cleanup:
  594. if (pbmi != NULL)
  595. {
  596. LocalFree(pbmi);
  597. }
  598. EndGlPrinting(pgps);
  599. return FALSE;
  600. }
  601. /*****************************Private*Routine******************************\
  602. *
  603. * RenderGlBand
  604. *
  605. * Plays the metafile and stretches the resulting band into the
  606. * appropriate location in the destination
  607. *
  608. * Uses PlayEnhMetaFile-style error reporting, where we remember errors
  609. * but continue to complete processing. This avoids complete failure
  610. * in cases where metafiles contain minor errors
  611. *
  612. * History:
  613. * Wed Apr 12 18:22:08 1995 -by- Drew Bliss [drewb]
  614. * Created
  615. *
  616. \**************************************************************************/
  617. static BOOL RenderGlBand(HENHMETAFILE hemf, GLPRINTSTATE *pgps, int x, int y)
  618. {
  619. RECT rcBand;
  620. int iWidth, iHeight;
  621. int iReducedWidth, iReducedHeight;
  622. int ySrc;
  623. BOOL fSuccess = TRUE;
  624. // We want to render a band-size rectangle of the source metafile
  625. // at (x,y), so we need to do a negative translation by (x,y)
  626. // Size remains constant since we don't want any scaling
  627. //
  628. // The caller of this routine may have already shifted the
  629. // viewport with SetViewport so we don't attempt to use it
  630. // to do our translation
  631. // WINBUG #82858 2-7-2000 bhouse Investigate propoer metafile handling
  632. // Old Comment:
  633. // - Proper handling of metafile left,top?
  634. // x and y are guaranteed to be even multiples of pgps->iReduceFactor
  635. rcBand.left = -x/pgps->iReduceFactor;
  636. rcBand.right = rcBand.left+pgps->iReducedWidth;
  637. rcBand.top = -y/pgps->iReduceFactor;
  638. rcBand.bottom = rcBand.top+pgps->iReducedHeight;
  639. if (!PlayEnhMetaFile(pgps->hdcDib, hemf, &rcBand))
  640. {
  641. WARNING("RenderBand: PlayEnhMetaFile failed\n");
  642. fSuccess = FALSE;
  643. }
  644. // Copy the DIB bits to the destination
  645. // Compute minimal width and height to avoid clipping problems
  646. iWidth = pgps->iBandWidth;
  647. iReducedWidth = pgps->iReducedBandWidth;
  648. iHeight = pgps->iBandHeight;
  649. iReducedHeight = pgps->iReducedBandHeight;
  650. ySrc = 0;
  651. // Check for X overflow
  652. if (x+iWidth > pgps->iSourceWidth)
  653. {
  654. iWidth = pgps->iSourceWidth-x;
  655. // If iWidth is not an even multiple of pgps->iReduceFactor then
  656. // this can result in a different stretch factor
  657. // I think this is more or less unavoidable
  658. iReducedWidth = (iWidth+pgps->iReduceFactor-1)/pgps->iReduceFactor;
  659. }
  660. // Invert destination Y
  661. y = pgps->iSourceHeight-pgps->iBandHeight-y;
  662. // Check for Y underflow
  663. if (y < 0)
  664. {
  665. iHeight += y;
  666. iReducedHeight = (iHeight+pgps->iReduceFactor-1)/pgps->iReduceFactor;
  667. // This can cause registration problems when y is not a
  668. // multiple of pgps->iReduceFactor. Again, I'm not sure that
  669. // anything can be done
  670. ySrc -= (y+pgps->iReduceFactor-1)/pgps->iReduceFactor;
  671. y = 0;
  672. }
  673. #if 0
  674. DbgPrint("GL band (%d,%d - %d,%d)\n", x, y, iWidth, iHeight);
  675. #endif
  676. if (!StretchBlt(pgps->hdcDest,
  677. x+pgps->xSource, y+pgps->ySource, iWidth, iHeight,
  678. pgps->hdcDib,
  679. 0, ySrc, iReducedWidth, iReducedHeight,
  680. SRCCOPY))
  681. {
  682. WARNING("RenderBand: StretchBlt failed\n");
  683. fSuccess = FALSE;
  684. }
  685. return fSuccess;
  686. }
  687. /******************************Public*Routine******************************\
  688. *
  689. * PrintMfWithGl
  690. *
  691. * Prints a metafile that contains OpenGL records by rendering bands
  692. * in a DIB and then stretching them to the printer DC
  693. *
  694. * Uses PlayEnhMetaFile-style error reporting, where we remember errors
  695. * but continue to complete processing. This avoids complete failure
  696. * in cases where metafiles contain minor errors
  697. *
  698. * History:
  699. * Wed Apr 12 18:22:41 1995 -by- Drew Bliss [drewb]
  700. * Created
  701. *
  702. \**************************************************************************/
  703. BOOL PrintMfWithGl(HENHMETAFILE hemf, GLPRINTSTATE *pgps,
  704. POINTL *pptlBand, SIZE *pszBand)
  705. {
  706. int iHorzBands, iVertBands;
  707. int iH, iV;
  708. int x, y;
  709. BOOL fSuccess = TRUE;
  710. int iStretchMode;
  711. POINT ptBrushOrg;
  712. ASSERTGDI(hOpenGL != NULL, "PrintMfWithGl: No opengl\n");
  713. // To render banded to a destination we create a 24-bit DIB and
  714. // play the metafile into that, then blt the DIB to
  715. // the destination DC
  716. //
  717. // The DIB and Z buffer take a large amount of memory
  718. // so the playback is banded into bands whose size is
  719. // determined by the amount of memory we want to consume
  720. iHorzBands = (pgps->iSourceWidth+pgps->iBandWidth-1)/pgps->iBandWidth;
  721. iVertBands = (pgps->iSourceHeight+pgps->iBandHeight-1)/pgps->iBandHeight;
  722. // Render high to low because the Y axis is positive up and
  723. // we want to go down the page
  724. y = (iVertBands-1)*pgps->iBandHeight;
  725. for (iV = 0; iV < iVertBands; iV++)
  726. {
  727. x = 0;
  728. for (iH = 0; iH < iHorzBands; iH++)
  729. {
  730. // If the current OpenGL band doesn't overlap any of the
  731. // current printer band, there's no point in drawing anything
  732. if (pptlBand != NULL &&
  733. pszBand != NULL &&
  734. (x+pgps->iBandWidth <= pptlBand->x ||
  735. x >= pptlBand->x+pszBand->cx ||
  736. y+pgps->iBandHeight <= pptlBand->y ||
  737. y >= pptlBand->y+pszBand->cy))
  738. {
  739. // No band overlap
  740. }
  741. else if (!RenderGlBand(hemf, pgps, x, y))
  742. {
  743. fSuccess = FALSE;
  744. }
  745. x += pgps->iBandWidth;
  746. }
  747. y -= pgps->iBandHeight;
  748. }
  749. return fSuccess;
  750. }
  751. /******************************Public*Routine******************************\
  752. *
  753. * IsMetafileWithGl()
  754. *
  755. * IsMetafileWithGl will determines the matafile contains
  756. * OpenGL records or not.
  757. *
  758. * History:
  759. * Wed Jan 29 00:00:00 1997 -by- Hideyuki Nagase [hideyukn]
  760. * Created.
  761. *
  762. \**************************************************************************/
  763. BOOL IsMetafileWithGl(HENHMETAFILE hmeta)
  764. {
  765. ENHMETAHEADER emh;
  766. UINT cbEmh;
  767. cbEmh = GetEnhMetaFileHeader(hmeta, sizeof(emh), &emh);
  768. if (cbEmh == 0)
  769. {
  770. WARNING("IsMetafileWithGl(): GetEnhMetaFileHeader failed\n");
  771. return FALSE;
  772. }
  773. if (cbEmh >= META_HDR_SIZE_VERSION_2)
  774. {
  775. return emh.bOpenGL;
  776. }
  777. else
  778. {
  779. return FALSE;
  780. }
  781. }