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
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							589 lines
						
					
					
						
							24 KiB
						
					
					
				| /* | |
|     Copyright 2005-2013 Intel Corporation.  All Rights Reserved. | |
|  | |
|     This file is part of Threading Building Blocks. | |
|  | |
|     Threading Building Blocks is free software; you can redistribute it | |
|     and/or modify it under the terms of the GNU General Public License | |
|     version 2 as published by the Free Software Foundation. | |
|  | |
|     Threading Building Blocks is distributed in the hope that it will be | |
|     useful, but WITHOUT ANY WARRANTY; without even the implied warranty | |
|     of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | |
|     GNU General Public License for more details. | |
|  | |
|     You should have received a copy of the GNU General Public License | |
|     along with Threading Building Blocks; if not, write to the Free Software | |
|     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | |
|  | |
|     As a special exception, you may use this file as part of a free software | |
|     library without restriction.  Specifically, if other files instantiate | |
|     templates or use macros or inline functions from this file, or you compile | |
|     this file and link it with other files to produce an executable, this | |
|     file does not by itself cause the resulting executable to be covered by | |
|     the GNU General Public License.  This exception does not however | |
|     invalidate any other reasons why the executable file might be covered by | |
|     the GNU General Public License. | |
| */ | |
| 
 | |
| // common Windows parts | |
| #include "winvideo.h" | |
|  | |
| #include <dxsdkver.h> | |
| #if _DXSDK_PRODUCT_MAJOR >= 9 | |
| // new implementation based on Direct2D | |
| #include "d2dvideo.cpp" | |
| #else // _DXSDK_PRODUCT_MAJOR >= 9 | |
|  | |
| // and another headers | |
| #include <cassert> | |
| #include <stdio.h> | |
| #include <ddraw.h> | |
|  | |
| #pragma comment(lib, "ddraw.lib") | |
| #pragma comment(lib, "dxguid.lib") | |
|  | |
| LPDIRECTDRAW7               g_pDD = NULL;        // DirectDraw object | |
| LPDIRECTDRAWSURFACE7        g_pDDSPrimary = NULL;// DirectDraw primary surface | |
| LPDIRECTDRAWSURFACE7        g_pDDSBack = NULL;   // DirectDraw back surface | |
| LPDIRECTDRAWSURFACE7        g_pDDSOverlay = NULL;// DirectDraw overlay surface | |
| LPDIRECTDRAWCLIPPER         g_pClipper = NULL;   // DirectDraw clipping struct | |
| DDOVERLAYFX                 g_OverlayFX;         // DirectDraw overlay effects struct | |
| DDCAPS                      g_DDCaps;            // DirectDraw hardware capabilities struct | |
| DWORD                       g_OverlayFlags = 0;  // DirectDraw overlay flags variable | |
| DWORD                       g_dwXRatio, | |
|                             g_dwYRatio;          // The ratios between the src and dst rects | |
| RECT                        g_rcSrc = {0, 0, 0, 0}, | |
|                             g_rcDst = {0, 0, 0, 0}; | |
| HANDLE                      g_hVSync; | |
| 
 | |
| // check for new DX SDK (8 & 9) | |
| #ifdef DDSCAPS_PRIMARYSURFACELEFT | |
| #include <dxerr8.h> | |
| #pragma comment(lib, "dxerr8.lib") | |
| #else | |
| // old SDK (7) | |
| #include <d3dx.h> | |
| #pragma comment(lib, "d3dx.lib") | |
| #endif | |
|  | |
| //! Create a dialog box and tell the user what went wrong | |
| bool DisplayError(LPSTR lpstrErr, HRESULT hres) | |
| { | |
|     static bool InError = false; | |
|     int retval = 0; | |
|     if (!InError) | |
|     { | |
|         InError = true; | |
| #ifdef DDSCAPS_PRIMARYSURFACELEFT | |
|         const char *message = hres?DXGetErrorString8A(hres):0; | |
| #else | |
|         char message[256]; if(hres) D3DXGetErrorString(hres, 256, message); | |
| #endif | |
|         retval = MessageBoxA(g_hAppWnd, lpstrErr, hres?message:"Error!", MB_OK|MB_ICONERROR); | |
|         InError = false; | |
|     } | |
|     return false; | |
| } | |
| 
 | |
| //! Releases the overlay surface | |
| void DestroyOverlay() | |
| { | |
|     if (g_pClipper) | |
|         g_pClipper->Release(); | |
|     if (g_pDDSOverlay) { | |
|         g_pImg = 0; LPDIRECTDRAWSURFACE7 pDDSOverlay(g_pDDSOverlay); | |
|         g_pDDSOverlay = NULL; | |
|         YIELD_TO_THREAD(); | |
|         pDDSOverlay->Release(); // be sure nobody uses old value | |
|     } | |
| } | |
| 
 | |
| //! Releases the primary surface | |
| void DestroyPrimary() | |
| { | |
|     if (g_pDDSPrimary) | |
|     { | |
|         g_pDDSPrimary->Release(); | |
|         g_pDDSPrimary = NULL; | |
|     } | |
| } | |
| 
 | |
| //! Releases core DirectDraw objects | |
| void DestroyDDraw() | |
| { | |
|     DestroyPrimary(); | |
|     // Release the DDraw object | |
|     if (g_pDD) { | |
|         LPDIRECTDRAW7 pDD(g_pDD); // be sure nobody uses old value | |
|         g_pDD = NULL; Sleep(1); pDD->Release(); | |
|     } | |
| } | |
| 
 | |
| //! Checks and corrects all boundries for alignment and stretching | |
| void CheckBoundries(void) | |
| { | |
|     // Make sure the coordinates fulfill the stretching requirements.  Often | |
|     // the hardware will require a certain ammount of stretching to do | |
|     // overlays. This stretch factor is held in dwMinOverlayStretch as the | |
|     // stretch factor multiplied by 1000 (to keep an accuracy of 3 decimal places). | |
|     if ((g_DDCaps.dwCaps & DDCAPS_OVERLAYSTRETCH) && (g_DDCaps.dwMinOverlayStretch) | |
|         && (g_dwXRatio < g_DDCaps.dwMinOverlayStretch)) | |
|     { | |
|         g_rcDst.right = 2 * GetSystemMetrics(SM_CXSIZEFRAME) + g_rcDst.left + (g_sizex | |
|                                  * (g_DDCaps.dwMinOverlayStretch + 1)) / 1000; | |
|         SetWindowTextA(g_hAppWnd, "Window is too small!"); | |
|     } | |
|     else if ((g_DDCaps.dwCaps & DDCAPS_OVERLAYSTRETCH) && (g_DDCaps.dwMaxOverlayStretch) | |
|         && (g_dwXRatio > g_DDCaps.dwMaxOverlayStretch)) | |
|     { | |
|         g_rcDst.right = 2 * GetSystemMetrics(SM_CXSIZEFRAME) + g_rcDst.left + (g_sizey | |
|                                * (g_DDCaps.dwMaxOverlayStretch + 999)) / 1000; | |
|         SetWindowTextA(g_hAppWnd, "Window is too large!"); | |
|     } | |
|     else if(!g_video->calc_fps) SetWindowText(g_hAppWnd, g_video->title); | |
| 
 | |
|     // Recalculate the ratio's for the upcoming calculations | |
|     g_dwXRatio = (g_rcDst.right - g_rcDst.left) * 1000 / (g_rcSrc.right - g_rcSrc.left); | |
|     g_dwYRatio = (g_rcDst.bottom - g_rcDst.top) * 1000 / (g_rcSrc.bottom - g_rcSrc.top); | |
| 
 | |
|     // Check to make sure we're within the screen's boundries, if not then fix | |
|     // the problem by adjusting the source rectangle which we draw from. | |
|     if (g_rcDst.left < 0) | |
|     { | |
|         g_rcSrc.left = -g_rcDst.left * 1000 / g_dwXRatio; | |
|         g_rcDst.left = 0; | |
|     } | |
|     if (g_rcDst.right > GetSystemMetrics(SM_CXSCREEN)) | |
|     { | |
|         g_rcSrc.right = g_sizex - ((g_rcDst.right - GetSystemMetrics(SM_CXSCREEN)) * 1000 / g_dwXRatio); | |
|         g_rcDst.right = GetSystemMetrics(SM_CXSCREEN); | |
|     } | |
|     if (g_rcDst.bottom > GetSystemMetrics(SM_CYSCREEN)) | |
|     { | |
|         g_rcSrc.bottom = g_sizey - ((g_rcDst.bottom - GetSystemMetrics(SM_CYSCREEN)) * 1000 / g_dwYRatio); | |
|         g_rcDst.bottom = GetSystemMetrics(SM_CYSCREEN); | |
|     } | |
|     // I don't know how useful this is... but just in case someone can do it - here's the check. | |
|     if (g_rcDst.top < 0) | |
|     { | |
|         g_rcSrc.top = -g_rcDst.top * 1000 / g_dwYRatio; | |
|         g_rcDst.top = 0; | |
|     } | |
| 
 | |
|     // Make sure the coordinates fulfill the alignment requirements | |
|     // these expressions (x & -y) just do alignment by dropping low order bits... | |
|     // so to round up, we add first, then truncate. | |
|     if ((g_DDCaps.dwCaps & DDCAPS_ALIGNBOUNDARYSRC) && g_DDCaps.dwAlignBoundarySrc) | |
|         g_rcSrc.left = (g_rcSrc.left + g_DDCaps.dwAlignBoundarySrc / 2) & -(signed) | |
|             (g_DDCaps.dwAlignBoundarySrc); | |
|     if ((g_DDCaps.dwCaps & DDCAPS_ALIGNSIZESRC) && g_DDCaps.dwAlignSizeSrc) | |
|         g_rcSrc.right = g_rcSrc.left + (g_rcSrc.right - g_rcSrc.left + g_DDCaps.dwAlignSizeSrc | |
|                                    / 2) & -(signed) (g_DDCaps.dwAlignSizeSrc); | |
|     if ((g_DDCaps.dwCaps & DDCAPS_ALIGNBOUNDARYDEST) && g_DDCaps.dwAlignBoundaryDest) | |
|         g_rcDst.left = (g_rcDst.left + g_DDCaps.dwAlignBoundaryDest / 2) & -(signed) | |
|             (g_DDCaps.dwAlignBoundaryDest); | |
|     if ((g_DDCaps.dwCaps & DDCAPS_ALIGNSIZEDEST) && g_DDCaps.dwAlignSizeDest) | |
|         g_rcDst.right = g_rcDst.left + (g_rcDst.right - g_rcDst.left) & -(signed) (g_DDCaps.dwAlignSizeDest); | |
| } | |
| 
 | |
| //! Get translated by system color value | |
| DWORD DDColorMatch(IDirectDrawSurface7 * pdds, COLORREF rgb) | |
| { | |
|     COLORREF       rgbT; | |
|     HDC            hdc; | |
|     DWORD          dw = CLR_INVALID; | |
|     DDSURFACEDESC2 ddsd; | |
|     HRESULT        hres; | |
| 
 | |
|     //  Use GDI SetPixel to color match for us | |
|     if (rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK) { | |
|         rgbT = GetPixel(hdc, 0, 0);     // Save current pixel value | |
|         SetPixel(hdc, 0, 0, rgb);       // Set our value | |
|         pdds->ReleaseDC(hdc); | |
|     } | |
|     // Now lock the surface so we can read back the converted color | |
|     ddsd.dwSize = sizeof(ddsd); | |
|     while ((hres = pdds->Lock(NULL, &ddsd, 0, NULL)) == DDERR_WASSTILLDRAWING) | |
|         YIELD_TO_THREAD(); | |
|     if (hres == DD_OK) { | |
|         dw = *(DWORD *) ddsd.lpSurface;                 // Get DWORD | |
|         if (ddsd.ddpfPixelFormat.dwRGBBitCount < 32) | |
|             dw &= (1 << ddsd.ddpfPixelFormat.dwRGBBitCount) - 1;  // Mask it to bpp | |
|         pdds->Unlock(NULL); | |
|     } | |
|     else return DisplayError("Can't lock primary surface", hres); | |
|     //  Now put the color that was there back. | |
|     if (rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK) { | |
|         SetPixel(hdc, 0, 0, rgbT); | |
|         pdds->ReleaseDC(hdc); | |
|     } | |
|     return dw; | |
| } | |
| 
 | |
| //! Load the bitmap and copy it to the overlay surface | |
| bool DrawOverlay() | |
| { | |
|     HRESULT        hRet;       // This is where we put return values from DirectDraw. | |
|     DDSURFACEDESC2 surfDesc; | |
|     // Setup structure | |
|     memset(&surfDesc, 0, sizeof(surfDesc)); surfDesc.dwSize = sizeof(surfDesc); | |
| 
 | |
|     hRet = g_pDDSOverlay->Lock(NULL, &surfDesc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_NOSYSLOCK | DDLOCK_WRITEONLY, NULL); | |
|     if (hRet != DD_OK ||  surfDesc.lpSurface == NULL) | |
|         return DisplayError("Can't lock overlay surface", hRet); | |
|     else { | |
|         g_pImg = (unsigned int *)surfDesc.lpSurface; | |
|         //g_pDDSOverlay->Unlock(NULL); is not needed? | |
|     } | |
|     // Setup effects structure | |
|     memset(&g_OverlayFX, 0, sizeof(g_OverlayFX)); g_OverlayFX.dwSize = sizeof(g_OverlayFX); | |
|     // Setup overlay flags. | |
|     g_OverlayFlags = DDOVER_SHOW; | |
|     // Check for destination color keying capability | |
|     if ((g_DDCaps.dwCKeyCaps & DDCKEYCAPS_DESTOVERLAY) && ((g_DDCaps.dwCaps & DDCAPS_OVERLAYCANTCLIP) || (g_DDCaps.dwCKeyCaps & DDCKEYCAPS_NOCOSTOVERLAY) )) | |
|     { | |
|         // If so, we'll use it to clip the bitmap when other windows go on top | |
|         // of us. Just for the record - this color range for color keying (the | |
|         // high/low values) are not heavily supported right now, so for almost | |
|         // all cards, just use the same color for both. | |
|         g_OverlayFX.dckDestColorkey.dwColorSpaceLowValue = | |
|         g_OverlayFX.dckDestColorkey.dwColorSpaceHighValue = DDColorMatch(g_pDDSPrimary, RGBKEY); | |
|         g_OverlayFlags |= DDOVER_DDFX | DDOVER_KEYDESTOVERRIDE; | |
|     } else { | |
|         // If not, we'll setup a clipper for the window.  This will fix the | |
|         // problem on a few video cards - but the ones that don't shouldn't care. | |
|         hRet = g_pDD->CreateClipper(0, &g_pClipper, NULL); | |
|         if (hRet != DD_OK) | |
|             return DisplayError("Can't create clipper", hRet); | |
|         hRet = g_pClipper->SetHWnd(0, g_hAppWnd); | |
|         if (hRet != DD_OK) | |
|             return DisplayError("Can't attach clipper", hRet); | |
|         hRet = g_pDDSPrimary->SetClipper(g_pClipper); | |
|         if (hRet != DD_OK) | |
|             return DisplayError("Can't set clipper", hRet); | |
|     } | |
|     return true; | |
| } | |
| 
 | |
| //! Init the primary surface | |
| bool DDPrimaryInit() | |
| { | |
|     HRESULT        hRet; | |
|     DDSURFACEDESC2 ddsd;  // A surface description structure | |
|  | |
|     // Create the primary surface.  The primary surface is the full screen - | |
|     // since we're a windowed app - we'll just write to the portion of the | |
|     // screen within our window. | |
|     memset(&ddsd, 0, sizeof(ddsd)); // Set all fields of struct to 0 and set .dwSize to | |
|     ddsd.dwSize = sizeof(ddsd);     // Sizeof the variable - these two steps required for most DDraw structs | |
|     ddsd.dwFlags = DDSD_CAPS;       // Set flags for variables we're using... | |
|     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;  // Set the variables we said we would in dwFlags | |
|     hRet = g_pDD->CreateSurface(&ddsd, &g_pDDSPrimary, NULL); | |
|     if (hRet != DD_OK) | |
|         return DisplayError("Can't create primary surface", hRet); | |
|     return true; | |
| } | |
| 
 | |
| //! Init DirectDraw Stuff | |
| bool DDInit() | |
| { | |
|     HRESULT hRet; | |
|     g_rcSrc.right = g_sizex; | |
|     g_rcSrc.bottom = g_sizey; | |
| 
 | |
|     hRet = DirectDrawCreateEx(NULL, (VOID**)&g_pDD, IID_IDirectDraw7, NULL); | |
|     if (hRet != DD_OK) | |
|         return DisplayError("Can't create DirectDraw7 instance", hRet); | |
| 
 | |
|     // Set cooperation level with other windows to be normal (ie. not full screen) | |
|     // You MUST set the cooperation level to be SOMETHING, for windowed apps use | |
|     // DDSCL_NORMAL, for full screen use: DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN. | |
|     hRet = g_pDD->SetCooperativeLevel(g_hAppWnd, DDSCL_NORMAL); | |
|     if (hRet != DD_OK) | |
|         return DisplayError("Can't set cooperative level", hRet); | |
|     return DDPrimaryInit(); | |
| } | |
| 
 | |
| //! Setup the overlay object | |
| bool DDOverlayInit() | |
| { | |
|     // Get hardware's CAPabilitieS | |
|     memset(&g_DDCaps, 0, sizeof(g_DDCaps)); | |
|     g_DDCaps.dwSize = sizeof(g_DDCaps); | |
|     if (g_pDD->GetCaps(&g_DDCaps, 0)) | |
|         return DisplayError("Can't get capabilities"); | |
| 
 | |
|     // Make sure it supports overlays | |
|     if (!(g_DDCaps.dwCaps & DDCAPS_OVERLAY)) | |
|         return DisplayError("Hardware doesn't support overlays"); | |
| 
 | |
|     //DO NOT Make sure it supports stretching (scaling) | |
|     //if (!(g_DDCaps.dwCaps & DDCAPS_OVERLAYSTRETCH)) return false; | |
|  | |
|     DDSURFACEDESC2              ddsd;  // DirectDraw surface descriptor | |
|     HRESULT                     hRet;  // I'm not even going to try... | |
|     // The pixel formats that we want the surface to be in | |
|     DDPIXELFORMAT               ddpfOverlayFormats[] = { | |
|         {sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 32, 0xFF0000, 0x0FF00, 0x0000FF, 0}, // 32-bit RGB | |
|         {sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 16, 0x007C00, 0x003e0, 0x00001F, 0}, // 16-bit RGB 5:5:5 | |
|         {sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 16, 0x00F800, 0x007e0, 0x00001F, 0}, // 16-bit RGB 5:6:5 | |
|         {sizeof(DDPIXELFORMAT), DDPF_FOURCC, mmioFOURCC('U','Y','V','Y'), 16, 0, 0, 0, 0}, // UYVY | |
|         {sizeof(DDPIXELFORMAT), DDPF_FOURCC, mmioFOURCC('Y','4','2','2'), 16, 0, 0, 0, 0}, // the same as UYVY | |
|         {sizeof(DDPIXELFORMAT), DDPF_FOURCC, mmioFOURCC('Y','U','Y','2'), 16, 0, 0, 0, 0}, // YUY2 is unsupported color-space here | |
|         {0}}; | |
| 
 | |
|     // Setup the overlay surface's attributes in the surface descriptor | |
|     memset(&ddsd, 0, sizeof(ddsd)); | |
|     ddsd.dwSize = sizeof(ddsd); | |
|     ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY | g_DDCaps.ddsCaps.dwCaps&DDSCAPS_VIDEOMEMORY; | |
|     ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; | |
|     ddsd.dwBackBufferCount = 0; | |
|     ddsd.dwWidth = g_sizex; | |
|     ddsd.dwHeight = g_sizey; | |
|     for(int format = 0; ddpfOverlayFormats[format].dwSize; format++) { | |
|         ddsd.ddpfPixelFormat = ddpfOverlayFormats[format]; | |
|         // Attempt to create the surface with theses settings | |
|         hRet = g_pDD->CreateSurface(&ddsd, &g_pDDSOverlay, NULL); | |
|         if(hRet == DD_OK) break; | |
|     } | |
|     if (hRet != DD_OK) | |
|         return DisplayError("Can't create appropriate overlay surface", hRet); | |
|     return true; | |
| } | |
| 
 | |
| inline void mouse(int k, LPARAM lParam) | |
| { | |
|     int x = (int)LOWORD(lParam), y = (int)HIWORD(lParam); | |
|     g_video->on_mouse( x*g_sizex/(g_rcDst.right - g_rcDst.left), | |
|         y*g_sizey/(g_rcDst.bottom - g_rcDst.top), k); | |
| } | |
| 
 | |
| LRESULT CALLBACK InternalWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) | |
| { | |
|     PAINTSTRUCT                 ps;         // Structure for the paint message | |
|     POINT                       p = {0, 0}; // Translation point for the window's client region | |
|     HRESULT                     hRet; | |
| 
 | |
|     switch (iMsg) | |
|     { | |
|         case WM_MOVE: | |
|             // Make sure we're not moving to be minimized - because otherwise | |
|             // our ratio varialbes (g_dwXRatio and g_dwYRatio) will end up | |
|             // being 0, and once we hit CheckBoundries it divides by 0. | |
|             if (!IsIconic(hwnd)) | |
|             { | |
|                 g_rcSrc.left = 0; | |
|                 g_rcSrc.right = g_sizex; | |
|                 g_rcSrc.top = 0; | |
|                 g_rcSrc.bottom = g_sizey; | |
|                 GetClientRect(hwnd, &g_rcDst); | |
|                 g_dwXRatio = (g_rcDst.right - g_rcDst.left) * 1000 / | |
|                              (g_rcSrc.right - g_rcSrc.left); | |
|                 g_dwYRatio = (g_rcDst.bottom - g_rcDst.top) * 1000 / | |
|                              (g_rcSrc.bottom - g_rcSrc.top); | |
|                 ClientToScreen(hwnd, &p); | |
|                 g_rcDst.left = p.x; | |
|                 g_rcDst.top = p.y; | |
|                 g_rcDst.bottom += p.y; | |
|                 g_rcDst.right += p.x; | |
|                 CheckBoundries(); | |
|             } | |
|             else | |
|                 // Else, hide the overlay... just in case we can't do | |
|                 // destination color keying, this will pull the overlay | |
|                 // off of the screen for the user. | |
|                 if (g_pDDSOverlay && g_pDDSPrimary) | |
|                     g_pDDSOverlay->UpdateOverlay(NULL, g_pDDSPrimary, NULL, DDOVER_HIDE, NULL); | |
|             // Check to make sure our window exists before we tell it to | |
|             // repaint. This will fail the first time (while the window is being created). | |
|             if (hwnd) | |
|             { | |
|                 InvalidateRect(hwnd, NULL, FALSE); | |
|                 UpdateWindow(hwnd); | |
|             } | |
|             return 0L; | |
| 
 | |
|         case WM_SIZE: | |
|             // Another check for the minimization action.  This check is | |
|             // quicker though... | |
|             if (wParam != SIZE_MINIMIZED) | |
|             { | |
|                 GetClientRect(hwnd, &g_rcDst); | |
|                 ClientToScreen(hwnd, &p); | |
|                 g_rcDst.left = p.x; | |
|                 g_rcDst.top = p.y; | |
|                 g_rcDst.bottom += p.y; | |
|                 g_rcDst.right += p.x; | |
|                 g_rcSrc.left = 0; | |
|                 g_rcSrc.right = g_sizex; | |
|                 g_rcSrc.top = 0; | |
|                 g_rcSrc.bottom = g_sizey; | |
|                 // Here we multiply by 1000 to preserve 3 decimal places in the | |
|                 // division opperation (we picked 1000 to be on the same order | |
|                 // of magnitude as the stretch factor for easier comparisons) | |
|                 g_dwXRatio = (g_rcDst.right - g_rcDst.left) * 1000 / | |
|                              (g_rcSrc.right - g_rcSrc.left); | |
|                 g_dwYRatio = (g_rcDst.bottom - g_rcDst.top) * 1000 / | |
|                              (g_rcSrc.bottom - g_rcSrc.top); | |
|                 CheckBoundries(); | |
|             } | |
|             return 0L; | |
| 
 | |
|         case WM_PAINT: | |
|             BeginPaint(hwnd, &ps); | |
|             // Check the primary surface to see if it's lost - if so you can | |
|             // pretty much bet that the other surfaces are also lost - thus | |
|             // restore EVERYTHING!  If we got our surfaces stolen by a full | |
|             // screen app - then we'll destroy our primary - and won't be able | |
|             // to initialize it again. When we get our next paint message (the | |
|             // full screen app closed for example) we'll want to try to reinit | |
|             // the surfaces again - that's why there is a check for | |
|             // g_pDDSPrimary == NULL.  The other option, is that our program | |
|             // went through this process, could init the primary again, but it | |
|             // couldn't init the overlay, that's why there's a third check for | |
|             // g_pDDSOverlay == NULL.  Make sure that the check for | |
|             // !g_pDDSPrimary is BEFORE the IsLost call - that way if the | |
|             // pointer is NULL (ie. !g_pDDSPrimary is TRUE) - the compiler | |
|             // won't try to evaluate the IsLost function (which, since the | |
|             // g_pDDSPrimary surface is NULL, would be bad...). | |
|             if (!g_pDDSPrimary || (g_pDDSPrimary->IsLost() != DD_OK) || | |
|                 (g_pDDSOverlay == NULL)) | |
|             { | |
|                 DestroyOverlay(); | |
|                 DestroyPrimary(); | |
|                 if (DDPrimaryInit()) | |
|                     if (DDOverlayInit()) | |
|                         if (!DrawOverlay()) | |
|                             DestroyOverlay(); | |
|             } | |
|             // UpdateOverlay is how we put the overlay on the screen. | |
|             if (g_pDDSOverlay && g_pDDSPrimary && g_video->updating) | |
|             { | |
|                 hRet = g_pDDSOverlay->UpdateOverlay(&g_rcSrc, g_pDDSPrimary, | |
|                                                     &g_rcDst, g_OverlayFlags, | |
|                                                     &g_OverlayFX); | |
| #ifdef _DEBUG | |
|                 if(hRet != DD_OK) DisplayError("Can't update overlay", hRet); | |
| #endif | |
|             } | |
|             EndPaint(hwnd, &ps); | |
|             return 0L; | |
| 
 | |
|         // process mouse and keyboard events | |
|         case WM_LBUTTONDOWN:    mouse(1, lParam); break; | |
|         case WM_LBUTTONUP:      mouse(-1, lParam); break; | |
|         case WM_RBUTTONDOWN:    mouse(2, lParam); break; | |
|         case WM_RBUTTONUP:      mouse(-2, lParam); break; | |
|         case WM_MBUTTONDOWN:    mouse(3, lParam); break; | |
|         case WM_MBUTTONUP:      mouse(-3, lParam); break; | |
|         case WM_CHAR:           g_video->on_key(wParam); break; | |
| 
 | |
|         case WM_DISPLAYCHANGE:  return 0L; | |
| 
 | |
|         case WM_DESTROY: | |
|             // Now, shut down the window... | |
|             PostQuitMessage(0); | |
|             return 0L; | |
|     } | |
|     return g_pUserProc? g_pUserProc(hwnd, iMsg, wParam, lParam) : DefWindowProc(hwnd, iMsg, wParam, lParam); | |
| } | |
| 
 | |
| DWORD WINAPI thread_vsync(LPVOID lpParameter) | |
| { | |
|     BOOL vblank = false; | |
|     while(g_video && g_video->running) { | |
|         while(!vblank && g_video && g_video->running) { | |
|             YIELD_TO_THREAD(); | |
|             LPDIRECTDRAW7 pDD(g_pDD); | |
|             if(pDD) pDD->GetVerticalBlankStatus(&vblank); | |
|         } | |
|         LPDIRECTDRAWSURFACE7 pDDSOverlay(g_pDDSOverlay); | |
|         if(pDDSOverlay) pDDSOverlay->UpdateOverlay(&g_rcSrc, g_pDDSPrimary, &g_rcDst, g_OverlayFlags | DDOVER_REFRESHALL, &g_OverlayFX); | |
|         do { | |
|             Sleep(1); | |
|             LPDIRECTDRAW7 pDD(g_pDD); | |
|             if(pDD) pDD->GetVerticalBlankStatus(&vblank); | |
|         } while(vblank && g_video && g_video->running); | |
|         while(g_video && !g_video->updating && g_video->running) Sleep(10); | |
|     } | |
|     return 0; | |
| } | |
| 
 | |
| ///////////////////////////////////////////// public methods of video class /////////////////////// | |
|  | |
| inline void mask2bits(unsigned int mask, color_t &save, depth_t &shift) | |
| { | |
|     save  = mask; if(!mask) { shift = 8; return; } | |
|     shift = 0; while(!(mask&1)) ++shift, mask >>= 1; | |
|     int bits = 0; while(mask&1) ++bits,  mask >>= 1; | |
|     shift += bits - 8; | |
| } | |
| 
 | |
| bool video::init_window(int sizex, int sizey) | |
| { | |
|     assert(win_hInstance != 0); | |
|     g_sizex = sizex; g_sizey = sizey; | |
|     if( !WinInit(win_hInstance, win_iCmdShow, gWndClass, title, false) ) | |
|         return DisplayError("Unable to initialize the program's window."); | |
|     running = true; | |
|     if( !DDInit() ) { | |
|         DestroyDDraw(); | |
|         goto fail; | |
|     } | |
|     if( !DDOverlayInit() || !DrawOverlay() ) { | |
|         DestroyOverlay(); | |
|         DestroyDDraw(); | |
|         goto fail; | |
|     } | |
|     DDPIXELFORMAT PixelFormat; memset(&PixelFormat, 0, sizeof(PixelFormat)); PixelFormat.dwSize = sizeof(PixelFormat); | |
|     g_pDDSOverlay->GetPixelFormat(&PixelFormat); | |
|     mask2bits(PixelFormat.dwRBitMask, red_mask, red_shift); | |
|     mask2bits(PixelFormat.dwGBitMask, green_mask, green_shift); | |
|     mask2bits(PixelFormat.dwBBitMask, blue_mask, blue_shift); | |
|     if(PixelFormat.dwFlags == DDPF_RGB) | |
|          depth = depth_t(PixelFormat.dwRGBBitCount); | |
|     else depth = -depth_t(PixelFormat.dwFourCC); | |
|     for(int i = 0, e = sizex * sizey * PixelFormat.dwRGBBitCount / 32, c = get_color(0, 0, 0); i < e; i++) | |
|         g_pImg[i] = c; // clear surface | |
|     ShowWindow(g_hAppWnd, SW_SHOW); | |
|     g_hVSync = CreateThread ( | |
|         NULL,          // LPSECURITY_ATTRIBUTES security_attrs | |
|         0,             // SIZE_T stacksize | |
|         (LPTHREAD_START_ROUTINE) thread_vsync, | |
|         this,               // argument | |
|         0, 0); | |
|     SetPriorityClass(g_hVSync, IDLE_PRIORITY_CLASS); // questionable | |
|     return true; | |
| fail: | |
|     g_pImg = new unsigned int[g_sizex * g_sizey]; | |
|     return false; | |
| } | |
| 
 | |
| void video::terminate() | |
| { | |
|     running = false; | |
|     DestroyOverlay(); | |
|     if(WaitForSingleObject(g_hVSync, 100) == WAIT_TIMEOUT) TerminateThread(g_hVSync, 0); | |
|     CloseHandle(g_hVSync); | |
|     DestroyDDraw(); | |
|     if(g_pImg) delete[] g_pImg; | |
|     g_pImg = 0; g_video = 0; | |
| } | |
| //////////// drawing area constructor & destructor ///////////// | |
|  | |
| drawing_area::drawing_area(int x, int y, int sizex, int sizey) | |
| : start_x(x), start_y(y), size_x(sizex), size_y(sizey), pixel_depth(g_video->depth), | |
|     base_index(y*g_sizex + x), max_index(g_sizex*g_sizey), index_stride(g_sizex), ptr32(g_pImg) | |
| { | |
|     assert(ptr32); assert(x < g_sizex); assert(y < g_sizey); | |
|     assert(x+sizex <= g_sizex); assert(y+sizey <= g_sizey); | |
| 
 | |
|     index = base_index; // current index | |
| } | |
| 
 | |
| void drawing_area::update() | |
| { | |
| } | |
| 
 | |
| #endif //_DXSDK_PRODUCT_MAJOR >= 9
 |