Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1159 lines
28 KiB

  1. #include "precomp.hxx"
  2. #pragma hdrstop
  3. #include <stdio.h>
  4. #include "glddint.hxx"
  5. // Track the last error returned from a call made by this library
  6. HRESULT hrGlddLast = DD_OK;
  7. // Get the last Win32 error and turn it into an HRESULT
  8. #define WIN32_HR() ((HRESULT)GetLastError())
  9. // Window class
  10. static char *pszClass = "glddWindow";
  11. // Global IDirectDraw
  12. static LPDIRECTDRAW pdd = NULL;
  13. // Structure to pass window creation data
  14. #pragma pack(1)
  15. struct GLDDCREATESTRUCT
  16. {
  17. WORD wSize;
  18. GLDDWINDOW gw;
  19. };
  20. #pragma pack()
  21. /******************************Public*Routine******************************\
  22. *
  23. * glddWndProc
  24. *
  25. * Window procedure for gldd windows
  26. *
  27. * History:
  28. * Fri Aug 30 13:00:23 1996 -by- Drew Bliss [drewb]
  29. * Created
  30. *
  31. \**************************************************************************/
  32. LRESULT glddWndProc(HWND hwnd, UINT uiMsg, WPARAM wpm, LPARAM lpm)
  33. {
  34. PAINTSTRUCT ps;
  35. LRESULT lr;
  36. GLDDWINDOW gw;
  37. GLDDCREATESTRUCT *pgcs;
  38. // Set up the window-related data immediately on WM_CREATE so that
  39. // a callback can be made for it as well as after it
  40. if (uiMsg == WM_CREATE)
  41. {
  42. pgcs = (GLDDCREATESTRUCT *)((CREATESTRUCT *)lpm)->lpCreateParams;
  43. SetWindowLong(hwnd, GWL_USERDATA, (LONG)pgcs->gw);
  44. }
  45. gw = (GLDDWINDOW)GetWindowLong(hwnd, GWL_USERDATA);
  46. // Pass off window messages if requested
  47. if (gw != NULL && gw->_cbMessage != NULL)
  48. {
  49. if (gw->_cbMessage(gw, hwnd, uiMsg, wpm, lpm, &lr))
  50. {
  51. return lr;
  52. }
  53. }
  54. switch(uiMsg)
  55. {
  56. case WM_PAINT:
  57. // Validate paint region. The assumption is that the app will either
  58. // interpose and catch the WM_PAINT itself or it's dynamic so
  59. // the screen will be repainted shortly anyway. Either way,
  60. // there's nothing for the library to do.
  61. BeginPaint(hwnd, &ps);
  62. EndPaint(hwnd, &ps);
  63. break;
  64. case WM_CLOSE:
  65. DestroyWindow(hwnd);
  66. break;
  67. case WM_DESTROY:
  68. // Doesn't work with multiple windows
  69. PostQuitMessage(1);
  70. break;
  71. default:
  72. return DefWindowProc(hwnd, uiMsg, wpm, lpm);
  73. }
  74. return 0;
  75. }
  76. // Default palette entry flags
  77. #define PALETTE_FLAGS PC_NOCOLLAPSE
  78. // Maximum color distance with 8-bit components
  79. #define MAX_COL_DIST (3*256*256L)
  80. // Number of static colors
  81. #define STATIC_COLORS 20
  82. // Flags used when matching colors
  83. #define EXACT_MATCH 1
  84. #define COLOR_USED 1
  85. // Tables to convert color components between bit sizes
  86. // These tables are corrected for a gamma of 1.4
  87. static unsigned char abThreeToEight[8] =
  88. {
  89. 0, 63, 104, 139, 171, 200, 229, 255
  90. };
  91. static unsigned char abTwoToEight[4] =
  92. {
  93. 0, 116, 191, 255
  94. };
  95. static unsigned char abOneToEight[2] =
  96. {
  97. 0, 255
  98. };
  99. // Table which indicates which colors in a 3-3-2 palette should be
  100. // replaced with the system default colors
  101. static int aiDefaultOverride[STATIC_COLORS] =
  102. {
  103. 0, 3, 24, 27, 64, 67, 88, 173, 181, 236,
  104. 247, 164, 91, 7, 56, 63, 192, 199, 248, 255
  105. };
  106. /******************************Public*Routine******************************\
  107. *
  108. * glddComponentFromIndex
  109. *
  110. * Converts a color index to a color component
  111. *
  112. * History:
  113. * Fri Aug 30 14:04:45 1996 -by- Drew Bliss [drewb]
  114. * Created
  115. *
  116. \**************************************************************************/
  117. unsigned char glddComponentFromIndex(int i, int nbits, int shift)
  118. {
  119. unsigned char val;
  120. val = i >> shift;
  121. switch (nbits)
  122. {
  123. case 1:
  124. return abOneToEight[val & 1];
  125. case 2:
  126. return abTwoToEight[val & 3];
  127. case 3:
  128. return abThreeToEight[val & 7];
  129. }
  130. return 0;
  131. }
  132. // System default colors
  133. static PALETTEENTRY apeDefaultPalEntry[STATIC_COLORS] =
  134. {
  135. { 0, 0, 0, 0 },
  136. { 0x80,0, 0, 0 },
  137. { 0, 0x80,0, 0 },
  138. { 0x80,0x80,0, 0 },
  139. { 0, 0, 0x80, 0 },
  140. { 0x80,0, 0x80, 0 },
  141. { 0, 0x80,0x80, 0 },
  142. { 0xC0,0xC0,0xC0, 0 },
  143. { 192, 220, 192, 0 },
  144. { 166, 202, 240, 0 },
  145. { 255, 251, 240, 0 },
  146. { 160, 160, 164, 0 },
  147. { 0x80,0x80,0x80, 0 },
  148. { 0xFF,0, 0, 0 },
  149. { 0, 0xFF,0, 0 },
  150. { 0xFF,0xFF,0, 0 },
  151. { 0, 0, 0xFF, 0 },
  152. { 0xFF,0, 0xFF, 0 },
  153. { 0, 0xFF,0xFF, 0 },
  154. { 0xFF,0xFF,0xFF, 0 }
  155. };
  156. /******************************Public*Routine******************************\
  157. *
  158. * glddUpdateStaticMapping
  159. *
  160. * Computes the best match between the current system static colors
  161. * and a 3-3-2 palette
  162. *
  163. * History:
  164. * Tue Aug 01 18:18:12 1995 -by- Drew Bliss [drewb]
  165. * Created
  166. *
  167. \**************************************************************************/
  168. void glddUpdateStaticMapping(PALETTEENTRY *pe332Palette)
  169. {
  170. HPALETTE hpalStock;
  171. int iStatic, i332;
  172. int iMinDist, iDist;
  173. int iDelta;
  174. int iMinEntry;
  175. PALETTEENTRY *peStatic, *pe332;
  176. hpalStock = (HPALETTE)GetStockObject(DEFAULT_PALETTE);
  177. // Get the current static colors
  178. GetPaletteEntries(hpalStock, 0, STATIC_COLORS, apeDefaultPalEntry);
  179. // Zero the flags in the static colors because they are used later
  180. peStatic = apeDefaultPalEntry;
  181. for (iStatic = 0; iStatic < STATIC_COLORS; iStatic++)
  182. {
  183. peStatic->peFlags = 0;
  184. peStatic++;
  185. }
  186. // Zero the flags in the incoming palette because they are used later
  187. pe332 = pe332Palette;
  188. for (i332 = 0; i332 < 256; i332++)
  189. {
  190. pe332->peFlags = 0;
  191. pe332++;
  192. }
  193. // Try to match each static color exactly
  194. // This saves time by avoiding the least-squares match for each
  195. // exact match
  196. peStatic = apeDefaultPalEntry;
  197. for (iStatic = 0; iStatic < STATIC_COLORS; iStatic++)
  198. {
  199. pe332 = pe332Palette;
  200. for (i332 = 0; i332 < 256; i332++)
  201. {
  202. if (peStatic->peRed == pe332->peRed &&
  203. peStatic->peGreen == pe332->peGreen &&
  204. peStatic->peBlue == pe332->peBlue)
  205. {
  206. peStatic->peFlags = EXACT_MATCH;
  207. pe332->peFlags = COLOR_USED;
  208. aiDefaultOverride[iStatic] = i332;
  209. break;
  210. }
  211. pe332++;
  212. }
  213. peStatic++;
  214. }
  215. // Match each static color as closely as possible to an entry
  216. // in the 332 palette by minimized the square of the distance
  217. peStatic = apeDefaultPalEntry;
  218. for (iStatic = 0; iStatic < STATIC_COLORS; iStatic++)
  219. {
  220. // Skip colors already matched exactly
  221. if (peStatic->peFlags == EXACT_MATCH)
  222. {
  223. peStatic++;
  224. continue;
  225. }
  226. iMinDist = MAX_COL_DIST+1;
  227. #if DBG
  228. iMinEntry = -1;
  229. #endif
  230. pe332 = pe332Palette;
  231. for (i332 = 0; i332 < 256; i332++)
  232. {
  233. // Skip colors already used
  234. if (pe332->peFlags == COLOR_USED)
  235. {
  236. pe332++;
  237. continue;
  238. }
  239. // Compute Euclidean distance squared
  240. iDelta = pe332->peRed-peStatic->peRed;
  241. iDist = iDelta*iDelta;
  242. iDelta = pe332->peGreen-peStatic->peGreen;
  243. iDist += iDelta*iDelta;
  244. iDelta = pe332->peBlue-peStatic->peBlue;
  245. iDist += iDelta*iDelta;
  246. if (iDist < iMinDist)
  247. {
  248. iMinDist = iDist;
  249. iMinEntry = i332;
  250. }
  251. pe332++;
  252. }
  253. // Remember the best match
  254. aiDefaultOverride[iStatic] = iMinEntry;
  255. pe332Palette[iMinEntry].peFlags = COLOR_USED;
  256. peStatic++;
  257. }
  258. // Zero the flags in the static colors because they may have been
  259. // set. We want them to be zero so the colors can be remapped
  260. peStatic = apeDefaultPalEntry;
  261. for (iStatic = 0; iStatic < STATIC_COLORS; iStatic++)
  262. {
  263. peStatic->peFlags = 0;
  264. peStatic++;
  265. }
  266. // Reset the 332 flags because we may have set them
  267. pe332 = pe332Palette;
  268. for (i332 = 0; i332 < 256; i332++)
  269. {
  270. pe332->peFlags = PALETTE_FLAGS;
  271. pe332++;
  272. }
  273. }
  274. /******************************Public*Routine******************************\
  275. *
  276. * glddMapInSystemColors
  277. *
  278. * Reorganizes the given palette to include the system colors in
  279. * the lower and upper ten slots
  280. *
  281. * History:
  282. * Fri Aug 30 14:07:32 1996 -by- Drew Bliss [drewb]
  283. * Created
  284. *
  285. \**************************************************************************/
  286. void glddMapInSystemColors(PALETTEENTRY *ppe)
  287. {
  288. int iOld, iNew, iDef;
  289. PALETTEENTRY peTmp[256-STATIC_COLORS];
  290. // Find matches between the given palette and the current system colors.
  291. glddUpdateStaticMapping(ppe);
  292. // Place the first half of the system colors at the beginning of
  293. // the palette and the second half at the end of the palette.
  294. // The colors in the given palette which match the system colors most
  295. // closely are deleted and the remainder are packed into the middle
  296. // entries.
  297. iNew = 0;
  298. for (iOld = 0; iOld < 256; iOld++)
  299. {
  300. for (iDef = 0; iDef < STATIC_COLORS; iDef++)
  301. {
  302. if (iOld == aiDefaultOverride[iDef])
  303. {
  304. break;
  305. }
  306. }
  307. if (iDef == STATIC_COLORS)
  308. {
  309. peTmp[iNew++] = ppe[iOld];
  310. }
  311. }
  312. memcpy(ppe, apeDefaultPalEntry,
  313. sizeof(PALETTEENTRY)*(STATIC_COLORS/2));
  314. memcpy(ppe+STATIC_COLORS/2, peTmp,
  315. sizeof(PALETTEENTRY)*(256-STATIC_COLORS));
  316. memcpy(ppe+256-STATIC_COLORS/2, apeDefaultPalEntry+STATIC_COLORS/2,
  317. sizeof(PALETTEENTRY)*(STATIC_COLORS/2));
  318. }
  319. /******************************Public*Routine******************************\
  320. *
  321. * _GLDDWINDOW::_GLDDWINDOW
  322. *
  323. * Initialize fresh window to NULL
  324. *
  325. * History:
  326. * Fri Aug 30 14:08:11 1996 -by- Drew Bliss [drewb]
  327. * Created
  328. *
  329. \**************************************************************************/
  330. _GLDDWINDOW::_GLDDWINDOW(void)
  331. {
  332. _hwnd = NULL;
  333. _hrc = NULL;
  334. _pddc = NULL;
  335. _pddsFront = NULL;
  336. _pddsBack = NULL;
  337. _pddsZ = NULL;
  338. }
  339. /******************************Public*Routine******************************\
  340. *
  341. * _GLDDWINDOW::Create
  342. *
  343. * Creates a new rendering window
  344. *
  345. * History:
  346. * Fri Aug 30 14:34:15 1996 -by- Drew Bliss [drewb]
  347. * Created
  348. *
  349. \**************************************************************************/
  350. BOOL _GLDDWINDOW::Create(char *pszTitle, int x, int y,
  351. int iWidth, int iHeight, int iDepth,
  352. DWORD dwFlags)
  353. {
  354. RECT rct;
  355. DDSURFACEDESC ddsd, ddsdFront;
  356. PIXELFORMATDESCRIPTOR pfd;
  357. GLDDCREATESTRUCT gcs;
  358. DDSCAPS ddscaps;
  359. LPDIRECTDRAWSURFACE pddsRender;
  360. int ipfd;
  361. HDC hdc;
  362. BOOL bRet;
  363. DWORD dwZDepth;
  364. // Create base window
  365. if (dwFlags & GLDD_FULL_SCREEN)
  366. {
  367. rct.left = 0;
  368. rct.top = 0;
  369. rct.right = iWidth;
  370. rct.bottom = iHeight;
  371. }
  372. else
  373. {
  374. rct.left = x;
  375. rct.top = y;
  376. rct.right = x+iWidth;
  377. rct.bottom = y+iHeight;
  378. AdjustWindowRect(&rct, WS_OVERLAPPEDWINDOW, FALSE);
  379. }
  380. gcs.wSize = sizeof(gcs);
  381. gcs.gw = this;
  382. _hwnd = CreateWindow(pszClass, pszTitle,
  383. WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN |
  384. WS_CLIPSIBLINGS,
  385. rct.left, rct.top,
  386. rct.right-rct.left, rct.bottom-rct.top,
  387. NULL, NULL, GetModuleHandle(NULL), &gcs);
  388. if (_hwnd == NULL)
  389. {
  390. hrGlddLast = WIN32_HR();
  391. return FALSE;
  392. }
  393. if (dwFlags & GLDD_FULL_SCREEN)
  394. {
  395. DWORD dwDdFlags;
  396. // If fullscreen, take over the screen, switch the video mode and
  397. // create a complex flipping surface
  398. dwDdFlags = DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN;
  399. if (dwFlags & GLDD_USE_MODE_X)
  400. {
  401. dwDdFlags |= DDSCL_ALLOWMODEX;
  402. }
  403. hrGlddLast = pdd->SetCooperativeLevel(_hwnd, dwDdFlags);
  404. if (hrGlddLast != DD_OK)
  405. {
  406. return FALSE;
  407. }
  408. hrGlddLast = pdd->SetDisplayMode(iWidth, iHeight, iDepth);
  409. if (hrGlddLast != DD_OK)
  410. {
  411. return FALSE;
  412. }
  413. memset(&ddsdFront, 0, sizeof(DDSURFACEDESC));
  414. ddsdFront.dwSize = sizeof(ddsdFront);
  415. ddsdFront.dwFlags = DDSD_CAPS;
  416. ddsdFront.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
  417. if (dwFlags & GLDD_BACK_BUFFER)
  418. {
  419. ddsdFront.dwFlags |= DDSD_BACKBUFFERCOUNT;
  420. ddsdFront.dwBackBufferCount = 1;
  421. ddsdFront.ddsCaps.dwCaps |= DDSCAPS_FLIP | DDSCAPS_COMPLEX;
  422. }
  423. hrGlddLast = pdd->CreateSurface(&ddsdFront, &_pddsFront, NULL);
  424. if (hrGlddLast != DD_OK)
  425. {
  426. return FALSE;
  427. }
  428. hrGlddLast = _pddsFront->GetSurfaceDesc(&ddsdFront);
  429. if (hrGlddLast != DD_OK)
  430. {
  431. return FALSE;
  432. }
  433. if (dwFlags & GLDD_BACK_BUFFER)
  434. {
  435. ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
  436. hrGlddLast = _pddsFront->GetAttachedSurface(&ddscaps, &_pddsBack);
  437. if (hrGlddLast != DD_OK)
  438. {
  439. return FALSE;
  440. }
  441. // Ensure that the back buffer went into video memory so
  442. // that flipping isn't emulated
  443. if ((dwFlags & GLDD_STRICT_MEMORY) &&
  444. (_pddsBack->GetSurfaceDesc(&ddsd) != DD_OK ||
  445. (ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) == 0))
  446. {
  447. hrGlddLast = DDERR_OUTOFVIDEOMEMORY;
  448. return FALSE;
  449. }
  450. }
  451. }
  452. else
  453. {
  454. // If windowed, get access to the screen and attach a clipper
  455. // for visrgn management.
  456. hrGlddLast = pdd->SetCooperativeLevel(NULL, DDSCL_NORMAL);
  457. if (hrGlddLast != DD_OK)
  458. {
  459. return FALSE;
  460. }
  461. memset(&ddsdFront, 0, sizeof(ddsdFront));
  462. ddsdFront.dwSize = sizeof(DDSURFACEDESC);
  463. ddsdFront.dwFlags = DDSD_CAPS;
  464. ddsdFront.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
  465. hrGlddLast = pdd->CreateSurface(&ddsdFront, &_pddsFront, NULL);
  466. if (hrGlddLast != DD_OK)
  467. {
  468. return FALSE;
  469. }
  470. hrGlddLast = _pddsFront->GetSurfaceDesc(&ddsdFront);
  471. if (hrGlddLast != DD_OK)
  472. {
  473. return FALSE;
  474. }
  475. hrGlddLast = pdd->CreateClipper(0, &_pddc, NULL);
  476. if (hrGlddLast != DD_OK)
  477. {
  478. return FALSE;
  479. }
  480. hrGlddLast = _pddc->SetHWnd(0, _hwnd);
  481. if (hrGlddLast != DD_OK)
  482. {
  483. return FALSE;
  484. }
  485. // Works with multiple windows? Depends on whether
  486. // multiple primary creates have individual state
  487. hrGlddLast = _pddsFront->SetClipper(_pddc);
  488. if (hrGlddLast != DD_OK)
  489. {
  490. return FALSE;
  491. }
  492. if (dwFlags & GLDD_BACK_BUFFER)
  493. {
  494. memset(&ddsd, 0, sizeof(DDSURFACEDESC));
  495. ddsd.dwSize = sizeof(DDSURFACEDESC);
  496. ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
  497. ddsd.dwWidth = iWidth;
  498. ddsd.dwHeight = iHeight;
  499. ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
  500. if (dwFlags & GLDD_VIDEO_MEMORY)
  501. {
  502. ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
  503. }
  504. else
  505. {
  506. ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
  507. }
  508. hrGlddLast = pdd->CreateSurface(&ddsd, &_pddsBack, NULL);
  509. if (hrGlddLast != DD_OK)
  510. {
  511. return FALSE;
  512. }
  513. // Ensure that the back buffer went where we wanted it
  514. if ((dwFlags & GLDD_STRICT_MEMORY) &&
  515. (_pddsBack->GetSurfaceDesc(&ddsd) != DD_OK ||
  516. ((ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) == 0) !=
  517. ((dwFlags & GLDD_VIDEO_MEMORY) == 0)))
  518. {
  519. if (dwFlags & GLDD_VIDEO_MEMORY)
  520. {
  521. hrGlddLast = DDERR_OUTOFVIDEOMEMORY;
  522. }
  523. else
  524. {
  525. hrGlddLast = DDERR_OUTOFMEMORY;
  526. }
  527. return FALSE;
  528. }
  529. }
  530. }
  531. // If we're double-buffered, use the back buffer as the rendering target.
  532. // Otherwise use the front buffer.
  533. if (dwFlags & GLDD_BACK_BUFFER)
  534. {
  535. pddsRender = _pddsBack;
  536. }
  537. else
  538. {
  539. pddsRender = _pddsFront;
  540. }
  541. // Create a palette for paletted surfaces
  542. if (ddsdFront.ddpfPixelFormat.dwRGBBitCount < 16)
  543. {
  544. int i;
  545. PALETTEENTRY ppe[256];
  546. for (i = 0; i < 256; i++)
  547. {
  548. ppe[i].peRed = glddComponentFromIndex(i, 3, 0);
  549. ppe[i].peGreen = glddComponentFromIndex(i, 3, 3);
  550. ppe[i].peBlue = glddComponentFromIndex(i, 2, 6);
  551. ppe[i].peFlags = 0;
  552. }
  553. if ((dwFlags & GLDD_FULL_SCREEN) == 0)
  554. {
  555. glddMapInSystemColors(ppe);
  556. }
  557. hrGlddLast = pdd->CreatePalette(DDPCAPS_8BIT | DDPCAPS_INITIALIZE,
  558. ppe, &_pddp, NULL);
  559. if (hrGlddLast != DD_OK)
  560. {
  561. return FALSE;
  562. }
  563. if (_pddsBack != NULL)
  564. {
  565. hrGlddLast = _pddsBack->SetPalette(_pddp);
  566. if (hrGlddLast != DD_OK)
  567. {
  568. return FALSE;
  569. }
  570. }
  571. // Works with multiple windows?
  572. hrGlddLast = _pddsFront->SetPalette(_pddp);
  573. if (hrGlddLast != DD_OK)
  574. {
  575. return FALSE;
  576. }
  577. }
  578. // Create a Z buffer if requested
  579. if (dwFlags & (GLDD_Z_BUFFER_16 | GLDD_Z_BUFFER_32))
  580. {
  581. memset(&ddsd, 0, sizeof(DDSURFACEDESC));
  582. ddsd.dwSize = sizeof(DDSURFACEDESC);
  583. ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS |
  584. DDSD_ZBUFFERBITDEPTH;
  585. ddsd.dwWidth = iWidth;
  586. ddsd.dwHeight = iHeight;
  587. dwZDepth = (dwFlags & GLDD_Z_BUFFER_16) ? 16 : 32;
  588. ddsd.dwZBufferBitDepth = dwZDepth;
  589. ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
  590. if (dwFlags & GLDD_VIDEO_MEMORY)
  591. {
  592. ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
  593. }
  594. else
  595. {
  596. ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
  597. }
  598. hrGlddLast = pdd->CreateSurface(&ddsd, &_pddsZ, NULL);
  599. if (hrGlddLast != DD_OK)
  600. {
  601. return FALSE;
  602. }
  603. // Ensure that the Z buffer went where we wanted it
  604. if ((dwFlags & GLDD_STRICT_MEMORY) &&
  605. (_pddsZ->GetSurfaceDesc(&ddsd) != DD_OK ||
  606. ((ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) == 0) !=
  607. ((dwFlags & GLDD_VIDEO_MEMORY) == 0)))
  608. {
  609. if (dwFlags & GLDD_VIDEO_MEMORY)
  610. {
  611. hrGlddLast = DDERR_OUTOFVIDEOMEMORY;
  612. }
  613. else
  614. {
  615. hrGlddLast = DDERR_OUTOFMEMORY;
  616. }
  617. return FALSE;
  618. }
  619. hrGlddLast = pddsRender->AddAttachedSurface(_pddsZ);
  620. if (hrGlddLast != DD_OK)
  621. {
  622. return FALSE;
  623. }
  624. }
  625. else
  626. {
  627. dwZDepth = 0;
  628. }
  629. // Create an OpenGL rendering context
  630. memset(&pfd, 0, sizeof(pfd));
  631. pfd.nSize = sizeof(pfd);
  632. pfd.nVersion = 1;
  633. pfd.dwFlags = PFD_GENERIC_FORMAT | PFD_SUPPORT_DIRECTDRAW;
  634. if (dwFlags & GLDD_GENERIC_ACCELERATED)
  635. {
  636. pfd.dwFlags |= PFD_GENERIC_ACCELERATED;
  637. }
  638. pfd.iPixelType = PFD_TYPE_RGBA;
  639. if (dwFlags & GLDD_ACCUM_BUFFER)
  640. {
  641. pfd.cAccumBits = 64;
  642. }
  643. if (dwFlags & GLDD_STENCIL_BUFFER)
  644. {
  645. pfd.cStencilBits = 8;
  646. }
  647. pfd.cDepthBits = (BYTE)dwZDepth;
  648. hrGlddLast = pddsRender->GetDC(&hdc);
  649. if (hrGlddLast != DD_OK)
  650. {
  651. return FALSE;
  652. }
  653. bRet = TRUE;
  654. ipfd = ChoosePixelFormat(hdc, &pfd);
  655. if (ipfd <= 0 ||
  656. DescribePixelFormat(hdc, ipfd, sizeof(pfd), &pfd) <= 0 ||
  657. !SetPixelFormat(hdc, ipfd, &pfd) ||
  658. (_hrc = wglCreateContext(hdc)) == NULL)
  659. {
  660. hrGlddLast = WIN32_HR();
  661. bRet = FALSE;
  662. }
  663. pddsRender->ReleaseDC(hdc);
  664. if (!bRet)
  665. {
  666. return FALSE;
  667. }
  668. _iWidth = iWidth;
  669. _iHeight = iHeight;
  670. _dwFlags = dwFlags;
  671. ShowWindow(_hwnd, SW_SHOWDEFAULT);
  672. UpdateWindow(_hwnd);
  673. return TRUE;
  674. }
  675. /******************************Public*Routine******************************\
  676. *
  677. * _GLDDWINDOW::~_GLDDWINDOW
  678. *
  679. * Clean up
  680. *
  681. * History:
  682. * Fri Aug 30 14:37:12 1996 -by- Drew Bliss [drewb]
  683. * Created
  684. *
  685. \**************************************************************************/
  686. _GLDDWINDOW::~_GLDDWINDOW(void)
  687. {
  688. if (_hrc != NULL)
  689. {
  690. if (wglGetCurrentContext() == _hrc)
  691. {
  692. wglMakeCurrent(NULL, NULL);
  693. }
  694. wglDeleteContext(_hrc);
  695. }
  696. if (_pddsBack != NULL)
  697. {
  698. _pddsBack->Release();
  699. }
  700. if (_pddsZ != NULL)
  701. {
  702. _pddsZ->Release();
  703. }
  704. if (_pddp != NULL)
  705. {
  706. _pddp->Release();
  707. }
  708. if (_pddc != NULL)
  709. {
  710. if (_pddsFront != NULL)
  711. {
  712. LPDIRECTDRAWCLIPPER pddc;
  713. // Only detach our clipper if it's still the current clipper
  714. if (_pddsFront->GetClipper(&pddc) == DD_OK &&
  715. pddc == _pddc)
  716. {
  717. _pddsFront->SetClipper(NULL);
  718. }
  719. }
  720. _pddc->Release();
  721. }
  722. if (_pddsFront != NULL)
  723. {
  724. _pddsFront->Release();
  725. }
  726. if (_dwFlags & GLDD_FULL_SCREEN)
  727. {
  728. // Recover from mode changes
  729. pdd->SetCooperativeLevel(_hwnd, DDSCL_NORMAL);
  730. pdd->RestoreDisplayMode();
  731. }
  732. if (_hwnd != NULL)
  733. {
  734. DestroyWindow(_hwnd);
  735. }
  736. }
  737. /******************************Public*Routine******************************\
  738. *
  739. * glddRegisterClass
  740. *
  741. * Register a window class if necessary
  742. *
  743. * History:
  744. * Fri Aug 30 14:37:49 1996 -by- Drew Bliss [drewb]
  745. * Created
  746. *
  747. \**************************************************************************/
  748. BOOL glddRegisterClass(void)
  749. {
  750. static ATOM aClass = 0;
  751. WNDCLASS wc;
  752. if (aClass == 0)
  753. {
  754. wc.style = CS_HREDRAW | CS_VREDRAW;
  755. wc.lpfnWndProc = glddWndProc;
  756. wc.cbClsExtra = 0;
  757. wc.cbWndExtra = 0;
  758. wc.hInstance = (HINSTANCE)GetModuleHandle(NULL);
  759. wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  760. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  761. wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
  762. wc.lpszMenuName = NULL;
  763. wc.lpszClassName = pszClass;
  764. aClass = RegisterClass(&wc);
  765. if (aClass == 0)
  766. {
  767. hrGlddLast = WIN32_HR();
  768. return FALSE;
  769. }
  770. }
  771. return TRUE;
  772. }
  773. /******************************Public*Routine******************************\
  774. *
  775. * glddCreateWindow
  776. *
  777. * Create a new rendering window
  778. *
  779. * History:
  780. * Fri Aug 30 14:38:49 1996 -by- Drew Bliss [drewb]
  781. * Created
  782. *
  783. \**************************************************************************/
  784. GLDDWINDOW glddCreateWindow(char *pszTitle, int x, int y,
  785. int iWidth, int iHeight, int iDepth,
  786. DWORD dwFlags)
  787. {
  788. GLDDWINDOW gw;
  789. if (!glddRegisterClass())
  790. {
  791. return NULL;
  792. }
  793. // If we haven't initialized the global IDirectDraw, do so
  794. if (pdd == NULL)
  795. {
  796. hrGlddLast = DirectDrawCreate(NULL, &pdd, NULL);
  797. if (hrGlddLast != DD_OK)
  798. {
  799. return NULL;
  800. }
  801. }
  802. gw = new _GLDDWINDOW;
  803. if (gw == NULL)
  804. {
  805. hrGlddLast = E_OUTOFMEMORY;
  806. return NULL;
  807. }
  808. if (gw->Create(pszTitle, x, y, iWidth, iHeight, iDepth, dwFlags))
  809. {
  810. return gw;
  811. }
  812. else
  813. {
  814. delete gw;
  815. return NULL;
  816. }
  817. }
  818. /******************************Public*Routine******************************\
  819. *
  820. * glddDestroyWindow
  821. *
  822. * Clean up a rendering window
  823. *
  824. * History:
  825. * Fri Aug 30 14:39:20 1996 -by- Drew Bliss [drewb]
  826. * Created
  827. *
  828. \**************************************************************************/
  829. void glddDestroyWindow(GLDDWINDOW gw)
  830. {
  831. delete gw;
  832. }
  833. /******************************Public*Routine******************************\
  834. *
  835. * glddGetGlrc
  836. *
  837. * Return a rendering window's OpenGL rendering context
  838. *
  839. * History:
  840. * Fri Aug 30 14:39:29 1996 -by- Drew Bliss [drewb]
  841. * Created
  842. *
  843. \**************************************************************************/
  844. HGLRC glddGetGlrc(GLDDWINDOW gw)
  845. {
  846. return gw->_hrc;
  847. }
  848. /******************************Public*Routine******************************\
  849. *
  850. * glddGetLastError
  851. *
  852. * Returns the last error recorded by the library
  853. *
  854. * History:
  855. * Fri Aug 30 14:39:39 1996 -by- Drew Bliss [drewb]
  856. * Created
  857. *
  858. \**************************************************************************/
  859. HRESULT glddGetLastError(void)
  860. {
  861. #if DBG
  862. char pszMsg[80];
  863. if (hrGlddLast != DD_OK)
  864. {
  865. sprintf(pszMsg, "glddGetLastError returning 0x%08lX\n", hrGlddLast);
  866. OutputDebugString(pszMsg);
  867. }
  868. #endif
  869. return hrGlddLast;
  870. }
  871. /******************************Public*Routine******************************\
  872. *
  873. * glddMakeCurrent
  874. *
  875. * Makes the given rendering window's OpenGL rendering context current
  876. *
  877. * History:
  878. * Fri Aug 30 14:39:47 1996 -by- Drew Bliss [drewb]
  879. * Created
  880. *
  881. \**************************************************************************/
  882. BOOL glddMakeCurrent(GLDDWINDOW gw)
  883. {
  884. BOOL b;
  885. HDC hdc;
  886. LPDIRECTDRAWSURFACE pddsRender;
  887. if (gw->_dwFlags & GLDD_BACK_BUFFER)
  888. {
  889. pddsRender = gw->_pddsBack;
  890. }
  891. else
  892. {
  893. pddsRender = gw->_pddsFront;
  894. }
  895. hrGlddLast = pddsRender->GetDC(&hdc);
  896. if (hrGlddLast != DD_OK)
  897. {
  898. return FALSE;
  899. }
  900. b = wglMakeCurrent(hdc, gw->_hrc);
  901. pddsRender->ReleaseDC(hdc);
  902. if (!b)
  903. {
  904. hrGlddLast = WIN32_HR();
  905. }
  906. return b;
  907. }
  908. /******************************Public*Routine******************************\
  909. *
  910. * glddSwapBuffers
  911. *
  912. * Performs double-buffer swapping through blt or flip
  913. *
  914. * History:
  915. * Fri Aug 30 14:40:49 1996 -by- Drew Bliss [drewb]
  916. * Created
  917. *
  918. \**************************************************************************/
  919. BOOL glddSwapBuffers(GLDDWINDOW gw)
  920. {
  921. // Check for a back buffer
  922. if ((gw->_dwFlags & GLDD_BACK_BUFFER) == 0)
  923. {
  924. hrGlddLast = E_INVALIDARG;
  925. return FALSE;
  926. }
  927. if (gw->_dwFlags & GLDD_FULL_SCREEN)
  928. {
  929. hrGlddLast = gw->_pddsFront->Flip(NULL, DDFLIP_WAIT);
  930. return hrGlddLast == DD_OK;
  931. }
  932. else
  933. {
  934. RECT rctSrc, rctDst;
  935. POINT pt;
  936. GetClientRect(gw->_hwnd, &rctDst);
  937. pt.x = 0;
  938. pt.y = 0;
  939. ClientToScreen(gw->_hwnd, &pt);
  940. rctDst.left = pt.x;
  941. rctDst.top = pt.y;
  942. rctDst.right += pt.x;
  943. rctDst.bottom += pt.y;
  944. rctSrc.left = 0;
  945. rctSrc.top = 0;
  946. rctSrc.right = gw->_iWidth;
  947. rctSrc.bottom = gw->_iHeight;
  948. hrGlddLast = gw->_pddsFront->Blt(&rctDst, gw->_pddsBack,
  949. &rctSrc, DDBLT_WAIT,
  950. NULL);
  951. return hrGlddLast == DD_OK;
  952. }
  953. }
  954. /******************************Public*Routine******************************\
  955. *
  956. * glddIdleCallback
  957. *
  958. * Set the idle-time callback
  959. *
  960. * History:
  961. * Fri Aug 30 14:41:28 1996 -by- Drew Bliss [drewb]
  962. * Created
  963. *
  964. \**************************************************************************/
  965. void glddIdleCallback(GLDDWINDOW gw, GLDDIDLECALLBACK cb)
  966. {
  967. gw->_cbIdle = cb;
  968. }
  969. /******************************Public*Routine******************************\
  970. *
  971. * glddMessageCallback
  972. *
  973. * Set the message interposition callback
  974. *
  975. * History:
  976. * Fri Aug 30 14:41:40 1996 -by- Drew Bliss [drewb]
  977. * Created
  978. *
  979. \**************************************************************************/
  980. void glddMessageCallback(GLDDWINDOW gw, GLDDMESSAGECALLBACK cb)
  981. {
  982. gw->_cbMessage = cb;
  983. }
  984. /******************************Public*Routine******************************\
  985. *
  986. * glddRun
  987. *
  988. * Run the message loop
  989. *
  990. * History:
  991. * Fri Aug 30 14:41:58 1996 -by- Drew Bliss [drewb]
  992. * Created
  993. *
  994. \**************************************************************************/
  995. void glddRun(GLDDWINDOW gw)
  996. {
  997. MSG msg;
  998. BOOL bQuit;
  999. bQuit = FALSE;
  1000. while (!bQuit)
  1001. {
  1002. // NULL hwnd doesn't work with multiple windows but
  1003. // is necessary to get quit message
  1004. while (!bQuit && PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
  1005. {
  1006. if (GetMessage(&msg, NULL, 0, 0))
  1007. {
  1008. TranslateMessage(&msg);
  1009. DispatchMessage(&msg);
  1010. }
  1011. else
  1012. {
  1013. bQuit = TRUE;
  1014. }
  1015. }
  1016. // Call the idle callback if one exists
  1017. if (gw->_cbIdle)
  1018. {
  1019. gw->_cbIdle(gw);
  1020. }
  1021. }
  1022. }