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.

589 lines
24 KiB

  1. /*
  2. Copyright 2005-2014 Intel Corporation. All Rights Reserved.
  3. This file is part of Threading Building Blocks.
  4. Threading Building Blocks is free software; you can redistribute it
  5. and/or modify it under the terms of the GNU General Public License
  6. version 2 as published by the Free Software Foundation.
  7. Threading Building Blocks is distributed in the hope that it will be
  8. useful, but WITHOUT ANY WARRANTY; without even the implied warranty
  9. of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with Threading Building Blocks; if not, write to the Free Software
  13. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  14. As a special exception, you may use this file as part of a free software
  15. library without restriction. Specifically, if other files instantiate
  16. templates or use macros or inline functions from this file, or you compile
  17. this file and link it with other files to produce an executable, this
  18. file does not by itself cause the resulting executable to be covered by
  19. the GNU General Public License. This exception does not however
  20. invalidate any other reasons why the executable file might be covered by
  21. the GNU General Public License.
  22. */
  23. // common Windows parts
  24. #include "winvideo.h"
  25. #include <dxsdkver.h>
  26. #if _DXSDK_PRODUCT_MAJOR >= 9
  27. // new implementation based on Direct2D
  28. #include "d2dvideo.cpp"
  29. #else // _DXSDK_PRODUCT_MAJOR >= 9
  30. // and another headers
  31. #include <cassert>
  32. #include <stdio.h>
  33. #include <ddraw.h>
  34. #pragma comment(lib, "ddraw.lib")
  35. #pragma comment(lib, "dxguid.lib")
  36. LPDIRECTDRAW7 g_pDD = NULL; // DirectDraw object
  37. LPDIRECTDRAWSURFACE7 g_pDDSPrimary = NULL;// DirectDraw primary surface
  38. LPDIRECTDRAWSURFACE7 g_pDDSBack = NULL; // DirectDraw back surface
  39. LPDIRECTDRAWSURFACE7 g_pDDSOverlay = NULL;// DirectDraw overlay surface
  40. LPDIRECTDRAWCLIPPER g_pClipper = NULL; // DirectDraw clipping struct
  41. DDOVERLAYFX g_OverlayFX; // DirectDraw overlay effects struct
  42. DDCAPS g_DDCaps; // DirectDraw hardware capabilities struct
  43. DWORD g_OverlayFlags = 0; // DirectDraw overlay flags variable
  44. DWORD g_dwXRatio,
  45. g_dwYRatio; // The ratios between the src and dst rects
  46. RECT g_rcSrc = {0, 0, 0, 0},
  47. g_rcDst = {0, 0, 0, 0};
  48. HANDLE g_hVSync;
  49. // check for new DX SDK (8 & 9)
  50. #ifdef DDSCAPS_PRIMARYSURFACELEFT
  51. #include <dxerr8.h>
  52. #pragma comment(lib, "dxerr8.lib")
  53. #else
  54. // old SDK (7)
  55. #include <d3dx.h>
  56. #pragma comment(lib, "d3dx.lib")
  57. #endif
  58. //! Create a dialog box and tell the user what went wrong
  59. bool DisplayError(LPSTR lpstrErr, HRESULT hres)
  60. {
  61. static bool InError = false;
  62. int retval = 0;
  63. if (!InError)
  64. {
  65. InError = true;
  66. #ifdef DDSCAPS_PRIMARYSURFACELEFT
  67. const char *message = hres?DXGetErrorString8A(hres):0;
  68. #else
  69. char message[256]; if(hres) D3DXGetErrorString(hres, 256, message);
  70. #endif
  71. retval = MessageBoxA(g_hAppWnd, lpstrErr, hres?message:"Error!", MB_OK|MB_ICONERROR);
  72. InError = false;
  73. }
  74. return false;
  75. }
  76. //! Releases the overlay surface
  77. void DestroyOverlay()
  78. {
  79. if (g_pClipper)
  80. g_pClipper->Release();
  81. if (g_pDDSOverlay) {
  82. g_pImg = 0; LPDIRECTDRAWSURFACE7 pDDSOverlay(g_pDDSOverlay);
  83. g_pDDSOverlay = NULL;
  84. YIELD_TO_THREAD();
  85. pDDSOverlay->Release(); // be sure nobody uses old value
  86. }
  87. }
  88. //! Releases the primary surface
  89. void DestroyPrimary()
  90. {
  91. if (g_pDDSPrimary)
  92. {
  93. g_pDDSPrimary->Release();
  94. g_pDDSPrimary = NULL;
  95. }
  96. }
  97. //! Releases core DirectDraw objects
  98. void DestroyDDraw()
  99. {
  100. DestroyPrimary();
  101. // Release the DDraw object
  102. if (g_pDD) {
  103. LPDIRECTDRAW7 pDD(g_pDD); // be sure nobody uses old value
  104. g_pDD = NULL; Sleep(1); pDD->Release();
  105. }
  106. }
  107. //! Checks and corrects all boundries for alignment and stretching
  108. void CheckBoundries(void)
  109. {
  110. // Make sure the coordinates fulfill the stretching requirements. Often
  111. // the hardware will require a certain ammount of stretching to do
  112. // overlays. This stretch factor is held in dwMinOverlayStretch as the
  113. // stretch factor multiplied by 1000 (to keep an accuracy of 3 decimal places).
  114. if ((g_DDCaps.dwCaps & DDCAPS_OVERLAYSTRETCH) && (g_DDCaps.dwMinOverlayStretch)
  115. && (g_dwXRatio < g_DDCaps.dwMinOverlayStretch))
  116. {
  117. g_rcDst.right = 2 * GetSystemMetrics(SM_CXSIZEFRAME) + g_rcDst.left + (g_sizex
  118. * (g_DDCaps.dwMinOverlayStretch + 1)) / 1000;
  119. SetWindowTextA(g_hAppWnd, "Window is too small!");
  120. }
  121. else if ((g_DDCaps.dwCaps & DDCAPS_OVERLAYSTRETCH) && (g_DDCaps.dwMaxOverlayStretch)
  122. && (g_dwXRatio > g_DDCaps.dwMaxOverlayStretch))
  123. {
  124. g_rcDst.right = 2 * GetSystemMetrics(SM_CXSIZEFRAME) + g_rcDst.left + (g_sizey
  125. * (g_DDCaps.dwMaxOverlayStretch + 999)) / 1000;
  126. SetWindowTextA(g_hAppWnd, "Window is too large!");
  127. }
  128. else if(!g_video->calc_fps) SetWindowText(g_hAppWnd, g_video->title);
  129. // Recalculate the ratio's for the upcoming calculations
  130. g_dwXRatio = (g_rcDst.right - g_rcDst.left) * 1000 / (g_rcSrc.right - g_rcSrc.left);
  131. g_dwYRatio = (g_rcDst.bottom - g_rcDst.top) * 1000 / (g_rcSrc.bottom - g_rcSrc.top);
  132. // Check to make sure we're within the screen's boundries, if not then fix
  133. // the problem by adjusting the source rectangle which we draw from.
  134. if (g_rcDst.left < 0)
  135. {
  136. g_rcSrc.left = -g_rcDst.left * 1000 / g_dwXRatio;
  137. g_rcDst.left = 0;
  138. }
  139. if (g_rcDst.right > GetSystemMetrics(SM_CXSCREEN))
  140. {
  141. g_rcSrc.right = g_sizex - ((g_rcDst.right - GetSystemMetrics(SM_CXSCREEN)) * 1000 / g_dwXRatio);
  142. g_rcDst.right = GetSystemMetrics(SM_CXSCREEN);
  143. }
  144. if (g_rcDst.bottom > GetSystemMetrics(SM_CYSCREEN))
  145. {
  146. g_rcSrc.bottom = g_sizey - ((g_rcDst.bottom - GetSystemMetrics(SM_CYSCREEN)) * 1000 / g_dwYRatio);
  147. g_rcDst.bottom = GetSystemMetrics(SM_CYSCREEN);
  148. }
  149. // I don't know how useful this is... but just in case someone can do it - here's the check.
  150. if (g_rcDst.top < 0)
  151. {
  152. g_rcSrc.top = -g_rcDst.top * 1000 / g_dwYRatio;
  153. g_rcDst.top = 0;
  154. }
  155. // Make sure the coordinates fulfill the alignment requirements
  156. // these expressions (x & -y) just do alignment by dropping low order bits...
  157. // so to round up, we add first, then truncate.
  158. if ((g_DDCaps.dwCaps & DDCAPS_ALIGNBOUNDARYSRC) && g_DDCaps.dwAlignBoundarySrc)
  159. g_rcSrc.left = (g_rcSrc.left + g_DDCaps.dwAlignBoundarySrc / 2) & -(signed)
  160. (g_DDCaps.dwAlignBoundarySrc);
  161. if ((g_DDCaps.dwCaps & DDCAPS_ALIGNSIZESRC) && g_DDCaps.dwAlignSizeSrc)
  162. g_rcSrc.right = g_rcSrc.left + (g_rcSrc.right - g_rcSrc.left + g_DDCaps.dwAlignSizeSrc
  163. / 2) & -(signed) (g_DDCaps.dwAlignSizeSrc);
  164. if ((g_DDCaps.dwCaps & DDCAPS_ALIGNBOUNDARYDEST) && g_DDCaps.dwAlignBoundaryDest)
  165. g_rcDst.left = (g_rcDst.left + g_DDCaps.dwAlignBoundaryDest / 2) & -(signed)
  166. (g_DDCaps.dwAlignBoundaryDest);
  167. if ((g_DDCaps.dwCaps & DDCAPS_ALIGNSIZEDEST) && g_DDCaps.dwAlignSizeDest)
  168. g_rcDst.right = g_rcDst.left + (g_rcDst.right - g_rcDst.left) & -(signed) (g_DDCaps.dwAlignSizeDest);
  169. }
  170. //! Get translated by system color value
  171. DWORD DDColorMatch(IDirectDrawSurface7 * pdds, COLORREF rgb)
  172. {
  173. COLORREF rgbT;
  174. HDC hdc;
  175. DWORD dw = CLR_INVALID;
  176. DDSURFACEDESC2 ddsd;
  177. HRESULT hres;
  178. // Use GDI SetPixel to color match for us
  179. if (rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK) {
  180. rgbT = GetPixel(hdc, 0, 0); // Save current pixel value
  181. SetPixel(hdc, 0, 0, rgb); // Set our value
  182. pdds->ReleaseDC(hdc);
  183. }
  184. // Now lock the surface so we can read back the converted color
  185. ddsd.dwSize = sizeof(ddsd);
  186. while ((hres = pdds->Lock(NULL, &ddsd, 0, NULL)) == DDERR_WASSTILLDRAWING)
  187. YIELD_TO_THREAD();
  188. if (hres == DD_OK) {
  189. dw = *(DWORD *) ddsd.lpSurface; // Get DWORD
  190. if (ddsd.ddpfPixelFormat.dwRGBBitCount < 32)
  191. dw &= (1 << ddsd.ddpfPixelFormat.dwRGBBitCount) - 1; // Mask it to bpp
  192. pdds->Unlock(NULL);
  193. }
  194. else return DisplayError("Can't lock primary surface", hres);
  195. // Now put the color that was there back.
  196. if (rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK) {
  197. SetPixel(hdc, 0, 0, rgbT);
  198. pdds->ReleaseDC(hdc);
  199. }
  200. return dw;
  201. }
  202. //! Load the bitmap and copy it to the overlay surface
  203. bool DrawOverlay()
  204. {
  205. HRESULT hRet; // This is where we put return values from DirectDraw.
  206. DDSURFACEDESC2 surfDesc;
  207. // Setup structure
  208. memset(&surfDesc, 0, sizeof(surfDesc)); surfDesc.dwSize = sizeof(surfDesc);
  209. hRet = g_pDDSOverlay->Lock(NULL, &surfDesc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_NOSYSLOCK | DDLOCK_WRITEONLY, NULL);
  210. if (hRet != DD_OK || surfDesc.lpSurface == NULL)
  211. return DisplayError("Can't lock overlay surface", hRet);
  212. else {
  213. g_pImg = (unsigned int *)surfDesc.lpSurface;
  214. //g_pDDSOverlay->Unlock(NULL); is not needed?
  215. }
  216. // Setup effects structure
  217. memset(&g_OverlayFX, 0, sizeof(g_OverlayFX)); g_OverlayFX.dwSize = sizeof(g_OverlayFX);
  218. // Setup overlay flags.
  219. g_OverlayFlags = DDOVER_SHOW;
  220. // Check for destination color keying capability
  221. if ((g_DDCaps.dwCKeyCaps & DDCKEYCAPS_DESTOVERLAY) && ((g_DDCaps.dwCaps & DDCAPS_OVERLAYCANTCLIP) || (g_DDCaps.dwCKeyCaps & DDCKEYCAPS_NOCOSTOVERLAY) ))
  222. {
  223. // If so, we'll use it to clip the bitmap when other windows go on top
  224. // of us. Just for the record - this color range for color keying (the
  225. // high/low values) are not heavily supported right now, so for almost
  226. // all cards, just use the same color for both.
  227. g_OverlayFX.dckDestColorkey.dwColorSpaceLowValue =
  228. g_OverlayFX.dckDestColorkey.dwColorSpaceHighValue = DDColorMatch(g_pDDSPrimary, RGBKEY);
  229. g_OverlayFlags |= DDOVER_DDFX | DDOVER_KEYDESTOVERRIDE;
  230. } else {
  231. // If not, we'll setup a clipper for the window. This will fix the
  232. // problem on a few video cards - but the ones that don't shouldn't care.
  233. hRet = g_pDD->CreateClipper(0, &g_pClipper, NULL);
  234. if (hRet != DD_OK)
  235. return DisplayError("Can't create clipper", hRet);
  236. hRet = g_pClipper->SetHWnd(0, g_hAppWnd);
  237. if (hRet != DD_OK)
  238. return DisplayError("Can't attach clipper", hRet);
  239. hRet = g_pDDSPrimary->SetClipper(g_pClipper);
  240. if (hRet != DD_OK)
  241. return DisplayError("Can't set clipper", hRet);
  242. }
  243. return true;
  244. }
  245. //! Init the primary surface
  246. bool DDPrimaryInit()
  247. {
  248. HRESULT hRet;
  249. DDSURFACEDESC2 ddsd; // A surface description structure
  250. // Create the primary surface. The primary surface is the full screen -
  251. // since we're a windowed app - we'll just write to the portion of the
  252. // screen within our window.
  253. memset(&ddsd, 0, sizeof(ddsd)); // Set all fields of struct to 0 and set .dwSize to
  254. ddsd.dwSize = sizeof(ddsd); // Sizeof the variable - these two steps required for most DDraw structs
  255. ddsd.dwFlags = DDSD_CAPS; // Set flags for variables we're using...
  256. ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; // Set the variables we said we would in dwFlags
  257. hRet = g_pDD->CreateSurface(&ddsd, &g_pDDSPrimary, NULL);
  258. if (hRet != DD_OK)
  259. return DisplayError("Can't create primary surface", hRet);
  260. return true;
  261. }
  262. //! Init DirectDraw Stuff
  263. bool DDInit()
  264. {
  265. HRESULT hRet;
  266. g_rcSrc.right = g_sizex;
  267. g_rcSrc.bottom = g_sizey;
  268. hRet = DirectDrawCreateEx(NULL, (VOID**)&g_pDD, IID_IDirectDraw7, NULL);
  269. if (hRet != DD_OK)
  270. return DisplayError("Can't create DirectDraw7 instance", hRet);
  271. // Set cooperation level with other windows to be normal (ie. not full screen)
  272. // You MUST set the cooperation level to be SOMETHING, for windowed apps use
  273. // DDSCL_NORMAL, for full screen use: DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN.
  274. hRet = g_pDD->SetCooperativeLevel(g_hAppWnd, DDSCL_NORMAL);
  275. if (hRet != DD_OK)
  276. return DisplayError("Can't set cooperative level", hRet);
  277. return DDPrimaryInit();
  278. }
  279. //! Setup the overlay object
  280. bool DDOverlayInit()
  281. {
  282. // Get hardware's CAPabilitieS
  283. memset(&g_DDCaps, 0, sizeof(g_DDCaps));
  284. g_DDCaps.dwSize = sizeof(g_DDCaps);
  285. if (g_pDD->GetCaps(&g_DDCaps, 0))
  286. return DisplayError("Can't get capabilities");
  287. // Make sure it supports overlays
  288. if (!(g_DDCaps.dwCaps & DDCAPS_OVERLAY))
  289. return DisplayError("Hardware doesn't support overlays");
  290. //DO NOT Make sure it supports stretching (scaling)
  291. //if (!(g_DDCaps.dwCaps & DDCAPS_OVERLAYSTRETCH)) return false;
  292. DDSURFACEDESC2 ddsd; // DirectDraw surface descriptor
  293. HRESULT hRet; // I'm not even going to try...
  294. // The pixel formats that we want the surface to be in
  295. DDPIXELFORMAT ddpfOverlayFormats[] = {
  296. {sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 32, 0xFF0000, 0x0FF00, 0x0000FF, 0}, // 32-bit RGB
  297. {sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 16, 0x007C00, 0x003e0, 0x00001F, 0}, // 16-bit RGB 5:5:5
  298. {sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 16, 0x00F800, 0x007e0, 0x00001F, 0}, // 16-bit RGB 5:6:5
  299. {sizeof(DDPIXELFORMAT), DDPF_FOURCC, mmioFOURCC('U','Y','V','Y'), 16, 0, 0, 0, 0}, // UYVY
  300. {sizeof(DDPIXELFORMAT), DDPF_FOURCC, mmioFOURCC('Y','4','2','2'), 16, 0, 0, 0, 0}, // the same as UYVY
  301. {sizeof(DDPIXELFORMAT), DDPF_FOURCC, mmioFOURCC('Y','U','Y','2'), 16, 0, 0, 0, 0}, // YUY2 is unsupported color-space here
  302. {0}};
  303. // Setup the overlay surface's attributes in the surface descriptor
  304. memset(&ddsd, 0, sizeof(ddsd));
  305. ddsd.dwSize = sizeof(ddsd);
  306. ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY | g_DDCaps.ddsCaps.dwCaps&DDSCAPS_VIDEOMEMORY;
  307. ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
  308. ddsd.dwBackBufferCount = 0;
  309. ddsd.dwWidth = g_sizex;
  310. ddsd.dwHeight = g_sizey;
  311. for(int format = 0; ddpfOverlayFormats[format].dwSize; format++) {
  312. ddsd.ddpfPixelFormat = ddpfOverlayFormats[format];
  313. // Attempt to create the surface with theses settings
  314. hRet = g_pDD->CreateSurface(&ddsd, &g_pDDSOverlay, NULL);
  315. if(hRet == DD_OK) break;
  316. }
  317. if (hRet != DD_OK)
  318. return DisplayError("Can't create appropriate overlay surface", hRet);
  319. return true;
  320. }
  321. inline void mouse(int k, LPARAM lParam)
  322. {
  323. int x = (int)LOWORD(lParam), y = (int)HIWORD(lParam);
  324. g_video->on_mouse( x*g_sizex/(g_rcDst.right - g_rcDst.left),
  325. y*g_sizey/(g_rcDst.bottom - g_rcDst.top), k);
  326. }
  327. LRESULT CALLBACK InternalWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
  328. {
  329. PAINTSTRUCT ps; // Structure for the paint message
  330. POINT p = {0, 0}; // Translation point for the window's client region
  331. HRESULT hRet;
  332. switch (iMsg)
  333. {
  334. case WM_MOVE:
  335. // Make sure we're not moving to be minimized - because otherwise
  336. // our ratio varialbes (g_dwXRatio and g_dwYRatio) will end up
  337. // being 0, and once we hit CheckBoundries it divides by 0.
  338. if (!IsIconic(hwnd))
  339. {
  340. g_rcSrc.left = 0;
  341. g_rcSrc.right = g_sizex;
  342. g_rcSrc.top = 0;
  343. g_rcSrc.bottom = g_sizey;
  344. GetClientRect(hwnd, &g_rcDst);
  345. g_dwXRatio = (g_rcDst.right - g_rcDst.left) * 1000 /
  346. (g_rcSrc.right - g_rcSrc.left);
  347. g_dwYRatio = (g_rcDst.bottom - g_rcDst.top) * 1000 /
  348. (g_rcSrc.bottom - g_rcSrc.top);
  349. ClientToScreen(hwnd, &p);
  350. g_rcDst.left = p.x;
  351. g_rcDst.top = p.y;
  352. g_rcDst.bottom += p.y;
  353. g_rcDst.right += p.x;
  354. CheckBoundries();
  355. }
  356. else
  357. // Else, hide the overlay... just in case we can't do
  358. // destination color keying, this will pull the overlay
  359. // off of the screen for the user.
  360. if (g_pDDSOverlay && g_pDDSPrimary)
  361. g_pDDSOverlay->UpdateOverlay(NULL, g_pDDSPrimary, NULL, DDOVER_HIDE, NULL);
  362. // Check to make sure our window exists before we tell it to
  363. // repaint. This will fail the first time (while the window is being created).
  364. if (hwnd)
  365. {
  366. InvalidateRect(hwnd, NULL, FALSE);
  367. UpdateWindow(hwnd);
  368. }
  369. return 0L;
  370. case WM_SIZE:
  371. // Another check for the minimization action. This check is
  372. // quicker though...
  373. if (wParam != SIZE_MINIMIZED)
  374. {
  375. GetClientRect(hwnd, &g_rcDst);
  376. ClientToScreen(hwnd, &p);
  377. g_rcDst.left = p.x;
  378. g_rcDst.top = p.y;
  379. g_rcDst.bottom += p.y;
  380. g_rcDst.right += p.x;
  381. g_rcSrc.left = 0;
  382. g_rcSrc.right = g_sizex;
  383. g_rcSrc.top = 0;
  384. g_rcSrc.bottom = g_sizey;
  385. // Here we multiply by 1000 to preserve 3 decimal places in the
  386. // division opperation (we picked 1000 to be on the same order
  387. // of magnitude as the stretch factor for easier comparisons)
  388. g_dwXRatio = (g_rcDst.right - g_rcDst.left) * 1000 /
  389. (g_rcSrc.right - g_rcSrc.left);
  390. g_dwYRatio = (g_rcDst.bottom - g_rcDst.top) * 1000 /
  391. (g_rcSrc.bottom - g_rcSrc.top);
  392. CheckBoundries();
  393. }
  394. return 0L;
  395. case WM_PAINT:
  396. BeginPaint(hwnd, &ps);
  397. // Check the primary surface to see if it's lost - if so you can
  398. // pretty much bet that the other surfaces are also lost - thus
  399. // restore EVERYTHING! If we got our surfaces stolen by a full
  400. // screen app - then we'll destroy our primary - and won't be able
  401. // to initialize it again. When we get our next paint message (the
  402. // full screen app closed for example) we'll want to try to reinit
  403. // the surfaces again - that's why there is a check for
  404. // g_pDDSPrimary == NULL. The other option, is that our program
  405. // went through this process, could init the primary again, but it
  406. // couldn't init the overlay, that's why there's a third check for
  407. // g_pDDSOverlay == NULL. Make sure that the check for
  408. // !g_pDDSPrimary is BEFORE the IsLost call - that way if the
  409. // pointer is NULL (ie. !g_pDDSPrimary is TRUE) - the compiler
  410. // won't try to evaluate the IsLost function (which, since the
  411. // g_pDDSPrimary surface is NULL, would be bad...).
  412. if (!g_pDDSPrimary || (g_pDDSPrimary->IsLost() != DD_OK) ||
  413. (g_pDDSOverlay == NULL))
  414. {
  415. DestroyOverlay();
  416. DestroyPrimary();
  417. if (DDPrimaryInit())
  418. if (DDOverlayInit())
  419. if (!DrawOverlay())
  420. DestroyOverlay();
  421. }
  422. // UpdateOverlay is how we put the overlay on the screen.
  423. if (g_pDDSOverlay && g_pDDSPrimary && g_video->updating)
  424. {
  425. hRet = g_pDDSOverlay->UpdateOverlay(&g_rcSrc, g_pDDSPrimary,
  426. &g_rcDst, g_OverlayFlags,
  427. &g_OverlayFX);
  428. #ifdef _DEBUG
  429. if(hRet != DD_OK) DisplayError("Can't update overlay", hRet);
  430. #endif
  431. }
  432. EndPaint(hwnd, &ps);
  433. return 0L;
  434. // process mouse and keyboard events
  435. case WM_LBUTTONDOWN: mouse(1, lParam); break;
  436. case WM_LBUTTONUP: mouse(-1, lParam); break;
  437. case WM_RBUTTONDOWN: mouse(2, lParam); break;
  438. case WM_RBUTTONUP: mouse(-2, lParam); break;
  439. case WM_MBUTTONDOWN: mouse(3, lParam); break;
  440. case WM_MBUTTONUP: mouse(-3, lParam); break;
  441. case WM_CHAR: g_video->on_key(wParam); break;
  442. case WM_DISPLAYCHANGE: return 0L;
  443. case WM_DESTROY:
  444. // Now, shut down the window...
  445. PostQuitMessage(0);
  446. return 0L;
  447. }
  448. return g_pUserProc? g_pUserProc(hwnd, iMsg, wParam, lParam) : DefWindowProc(hwnd, iMsg, wParam, lParam);
  449. }
  450. DWORD WINAPI thread_vsync(LPVOID lpParameter)
  451. {
  452. BOOL vblank = false;
  453. while(g_video && g_video->running) {
  454. while(!vblank && g_video && g_video->running) {
  455. YIELD_TO_THREAD();
  456. LPDIRECTDRAW7 pDD(g_pDD);
  457. if(pDD) pDD->GetVerticalBlankStatus(&vblank);
  458. }
  459. LPDIRECTDRAWSURFACE7 pDDSOverlay(g_pDDSOverlay);
  460. if(pDDSOverlay) pDDSOverlay->UpdateOverlay(&g_rcSrc, g_pDDSPrimary, &g_rcDst, g_OverlayFlags | DDOVER_REFRESHALL, &g_OverlayFX);
  461. do {
  462. Sleep(1);
  463. LPDIRECTDRAW7 pDD(g_pDD);
  464. if(pDD) pDD->GetVerticalBlankStatus(&vblank);
  465. } while(vblank && g_video && g_video->running);
  466. while(g_video && !g_video->updating && g_video->running) Sleep(10);
  467. }
  468. return 0;
  469. }
  470. ///////////////////////////////////////////// public methods of video class ///////////////////////
  471. inline void mask2bits(unsigned int mask, color_t &save, depth_t &shift)
  472. {
  473. save = mask; if(!mask) { shift = 8; return; }
  474. shift = 0; while(!(mask&1)) ++shift, mask >>= 1;
  475. int bits = 0; while(mask&1) ++bits, mask >>= 1;
  476. shift += bits - 8;
  477. }
  478. bool video::init_window(int sizex, int sizey)
  479. {
  480. assert(win_hInstance != 0);
  481. g_sizex = sizex; g_sizey = sizey;
  482. if( !WinInit(win_hInstance, win_iCmdShow, gWndClass, title, false) )
  483. return DisplayError("Unable to initialize the program's window.");
  484. running = true;
  485. if( !DDInit() ) {
  486. DestroyDDraw();
  487. goto fail;
  488. }
  489. if( !DDOverlayInit() || !DrawOverlay() ) {
  490. DestroyOverlay();
  491. DestroyDDraw();
  492. goto fail;
  493. }
  494. DDPIXELFORMAT PixelFormat; memset(&PixelFormat, 0, sizeof(PixelFormat)); PixelFormat.dwSize = sizeof(PixelFormat);
  495. g_pDDSOverlay->GetPixelFormat(&PixelFormat);
  496. mask2bits(PixelFormat.dwRBitMask, red_mask, red_shift);
  497. mask2bits(PixelFormat.dwGBitMask, green_mask, green_shift);
  498. mask2bits(PixelFormat.dwBBitMask, blue_mask, blue_shift);
  499. if(PixelFormat.dwFlags == DDPF_RGB)
  500. depth = depth_t(PixelFormat.dwRGBBitCount);
  501. else depth = -depth_t(PixelFormat.dwFourCC);
  502. for(int i = 0, e = sizex * sizey * PixelFormat.dwRGBBitCount / 32, c = get_color(0, 0, 0); i < e; i++)
  503. g_pImg[i] = c; // clear surface
  504. ShowWindow(g_hAppWnd, SW_SHOW);
  505. g_hVSync = CreateThread (
  506. NULL, // LPSECURITY_ATTRIBUTES security_attrs
  507. 0, // SIZE_T stacksize
  508. (LPTHREAD_START_ROUTINE) thread_vsync,
  509. this, // argument
  510. 0, 0);
  511. SetPriorityClass(g_hVSync, IDLE_PRIORITY_CLASS); // questionable
  512. return true;
  513. fail:
  514. g_pImg = new unsigned int[g_sizex * g_sizey];
  515. return false;
  516. }
  517. void video::terminate()
  518. {
  519. running = false;
  520. DestroyOverlay();
  521. if(WaitForSingleObject(g_hVSync, 100) == WAIT_TIMEOUT) TerminateThread(g_hVSync, 0);
  522. CloseHandle(g_hVSync);
  523. DestroyDDraw();
  524. if(g_pImg) delete[] g_pImg;
  525. g_pImg = 0; g_video = 0;
  526. }
  527. //////////// drawing area constructor & destructor /////////////
  528. drawing_area::drawing_area(int x, int y, int sizex, int sizey)
  529. : start_x(x), start_y(y), size_x(sizex), size_y(sizey), pixel_depth(g_video->depth),
  530. base_index(y*g_sizex + x), max_index(g_sizex*g_sizey), index_stride(g_sizex), ptr32(g_pImg)
  531. {
  532. assert(ptr32); assert(x < g_sizex); assert(y < g_sizey);
  533. assert(x+sizex <= g_sizex); assert(y+sizey <= g_sizey);
  534. index = base_index; // current index
  535. }
  536. void drawing_area::update()
  537. {
  538. }
  539. #endif //_DXSDK_PRODUCT_MAJOR >= 9