Shadowrun: Awakened 29 September 2011 - Build 871
ddvideo.cpp
Go to the documentation of this file.
00001 /*
00002     Copyright 2005-2010 Intel Corporation.  All Rights Reserved.
00003 
00004     This file is part of Threading Building Blocks.
00005 
00006     Threading Building Blocks is free software; you can redistribute it
00007     and/or modify it under the terms of the GNU General Public License
00008     version 2 as published by the Free Software Foundation.
00009 
00010     Threading Building Blocks is distributed in the hope that it will be
00011     useful, but WITHOUT ANY WARRANTY; without even the implied warranty
00012     of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013     GNU General Public License for more details.
00014 
00015     You should have received a copy of the GNU General Public License
00016     along with Threading Building Blocks; if not, write to the Free Software
00017     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018 
00019     As a special exception, you may use this file as part of a free software
00020     library without restriction.  Specifically, if other files instantiate
00021     templates or use macros or inline functions from this file, or you compile
00022     this file and link it with other files to produce an executable, this
00023     file does not by itself cause the resulting executable to be covered by
00024     the GNU General Public License.  This exception does not however
00025     invalidate any other reasons why the executable file might be covered by
00026     the GNU General Public License.
00027 */
00028 
00029 // common Windows parts
00030 #include "winvideo.h"
00031 // and another headers
00032 #include <cassert>
00033 #include <stdio.h>
00034 #include <ddraw.h>
00035 
00036 #pragma comment(lib, "ddraw.lib")
00037 #pragma comment(lib, "dxguid.lib")
00038 
00039 LPDIRECTDRAW7               g_pDD = NULL;        // DirectDraw object
00040 LPDIRECTDRAWSURFACE7        g_pDDSPrimary = NULL;// DirectDraw primary surface
00041 LPDIRECTDRAWSURFACE7        g_pDDSBack = NULL;   // DirectDraw back surface
00042 LPDIRECTDRAWSURFACE7        g_pDDSOverlay = NULL;// DirectDraw overlay surface
00043 LPDIRECTDRAWCLIPPER         g_pClipper = NULL;   // DirectDraw clipping struct
00044 DDOVERLAYFX                 g_OverlayFX;         // DirectDraw overlay effects struct
00045 DDCAPS                      g_DDCaps;            // DirectDraw hardware capabilities struct
00046 DWORD                       g_OverlayFlags = 0;  // DirectDraw overlay flags variable
00047 DWORD                       g_dwXRatio,
00048                             g_dwYRatio;          // The ratios between the src and dst rects
00049 RECT                        g_rcSrc = {0, 0, 0, 0},
00050                             g_rcDst = {0, 0, 0, 0};
00051 HANDLE                      g_hVSync;
00052 
00053 // check for new DX SDK (8 & 9)
00054 #ifdef DDSCAPS_PRIMARYSURFACELEFT
00055 #include <dxerr8.h>
00056 #pragma comment(lib, "dxerr8.lib")
00057 #else
00058 // old SDK (7)
00059 #include <d3dx.h>
00060 #pragma comment(lib, "d3dx.lib")
00061 #endif
00062 
00064 bool DisplayError(LPSTR lpstrErr, HRESULT hres)
00065 {
00066     static bool InError = false;
00067     int retval = 0;
00068     if (!InError)
00069     {
00070         InError = true;
00071 #ifdef DDSCAPS_PRIMARYSURFACELEFT
00072         const char *message = hres?DXGetErrorString8A(hres):0;
00073 #else
00074         char message[256]; if(hres) D3DXGetErrorString(hres, 256, message);
00075 #endif
00076         retval = MessageBoxA(g_hAppWnd, lpstrErr, hres?message:"Error!", MB_OK|MB_ICONERROR);
00077         InError = false;
00078     }
00079     return false;
00080 }
00081 
00083 void DestroyOverlay()
00084 {
00085     if (g_pClipper)
00086         g_pClipper->Release();
00087     if (g_pDDSOverlay) {
00088         g_pImg = 0; LPDIRECTDRAWSURFACE7 pDDSOverlay(g_pDDSOverlay);
00089         g_pDDSOverlay = NULL;
00090         YIELD_TO_THREAD();
00091         pDDSOverlay->Release(); // be sure nobody uses old value
00092     }
00093 }
00094 
00096 void DestroyPrimary()
00097 {
00098     if (g_pDDSPrimary)
00099     {
00100         g_pDDSPrimary->Release();
00101         g_pDDSPrimary = NULL;
00102     }
00103 }
00104 
00106 void DestroyDDraw()
00107 {
00108     DestroyPrimary();
00109     // Release the DDraw object
00110     if (g_pDD) {
00111         LPDIRECTDRAW7 pDD(g_pDD); // be sure nobody uses old value
00112         g_pDD = NULL; Sleep(1); pDD->Release();
00113     }
00114 }
00115 
00117 void CheckBoundries(void)
00118 {
00119     // Make sure the coordinates fulfill the stretching requirements.  Often
00120     // the hardware will require a certain ammount of stretching to do
00121     // overlays. This stretch factor is held in dwMinOverlayStretch as the
00122     // stretch factor multiplied by 1000 (to keep an accuracy of 3 decimal places).
00123     if ((g_DDCaps.dwCaps & DDCAPS_OVERLAYSTRETCH) && (g_DDCaps.dwMinOverlayStretch)
00124         && (g_dwXRatio < g_DDCaps.dwMinOverlayStretch))
00125     {
00126         g_rcDst.right = 2 * GetSystemMetrics(SM_CXSIZEFRAME) + g_rcDst.left + (g_sizex
00127                                  * (g_DDCaps.dwMinOverlayStretch + 1)) / 1000;
00128         SetWindowTextA(g_hAppWnd, "Window is too small!");
00129     }
00130     else if ((g_DDCaps.dwCaps & DDCAPS_OVERLAYSTRETCH) && (g_DDCaps.dwMaxOverlayStretch)
00131         && (g_dwXRatio > g_DDCaps.dwMaxOverlayStretch))
00132     {
00133         g_rcDst.right = 2 * GetSystemMetrics(SM_CXSIZEFRAME) + g_rcDst.left + (g_sizey
00134                                * (g_DDCaps.dwMaxOverlayStretch + 999)) / 1000;
00135         SetWindowTextA(g_hAppWnd, "Window is too large!");
00136     }
00137     else if(!g_video->calc_fps) SetWindowText(g_hAppWnd, g_video->title);
00138 
00139     // Recalculate the ratio's for the upcoming calculations
00140     g_dwXRatio = (g_rcDst.right - g_rcDst.left) * 1000 / (g_rcSrc.right - g_rcSrc.left);
00141     g_dwYRatio = (g_rcDst.bottom - g_rcDst.top) * 1000 / (g_rcSrc.bottom - g_rcSrc.top);
00142 
00143     // Check to make sure we're within the screen's boundries, if not then fix
00144     // the problem by adjusting the source rectangle which we draw from.
00145     if (g_rcDst.left < 0)
00146     {
00147         g_rcSrc.left = -g_rcDst.left * 1000 / g_dwXRatio;
00148         g_rcDst.left = 0;
00149     }
00150     if (g_rcDst.right > GetSystemMetrics(SM_CXSCREEN))
00151     {
00152         g_rcSrc.right = g_sizex - ((g_rcDst.right - GetSystemMetrics(SM_CXSCREEN)) * 1000 / g_dwXRatio);
00153         g_rcDst.right = GetSystemMetrics(SM_CXSCREEN);
00154     }
00155     if (g_rcDst.bottom > GetSystemMetrics(SM_CYSCREEN))
00156     {
00157         g_rcSrc.bottom = g_sizey - ((g_rcDst.bottom - GetSystemMetrics(SM_CYSCREEN)) * 1000 / g_dwYRatio);
00158         g_rcDst.bottom = GetSystemMetrics(SM_CYSCREEN);
00159     }
00160     // I don't know how useful this is... but just in case someone can do it - here's the check.
00161     if (g_rcDst.top < 0)
00162     {
00163         g_rcSrc.top = -g_rcDst.top * 1000 / g_dwYRatio;
00164         g_rcDst.top = 0;
00165     }
00166 
00167     // Make sure the coordinates fulfill the alignment requirements
00168     // these expressions (x & -y) just do alignment by dropping low order bits...
00169     // so to round up, we add first, then truncate.
00170     if ((g_DDCaps.dwCaps & DDCAPS_ALIGNBOUNDARYSRC) && g_DDCaps.dwAlignBoundarySrc)
00171         g_rcSrc.left = (g_rcSrc.left + g_DDCaps.dwAlignBoundarySrc / 2) & -(signed)
00172             (g_DDCaps.dwAlignBoundarySrc);
00173     if ((g_DDCaps.dwCaps & DDCAPS_ALIGNSIZESRC) && g_DDCaps.dwAlignSizeSrc)
00174         g_rcSrc.right = g_rcSrc.left + (g_rcSrc.right - g_rcSrc.left + g_DDCaps.dwAlignSizeSrc
00175                                    / 2) & -(signed) (g_DDCaps.dwAlignSizeSrc);
00176     if ((g_DDCaps.dwCaps & DDCAPS_ALIGNBOUNDARYDEST) && g_DDCaps.dwAlignBoundaryDest)
00177         g_rcDst.left = (g_rcDst.left + g_DDCaps.dwAlignBoundaryDest / 2) & -(signed)
00178             (g_DDCaps.dwAlignBoundaryDest);
00179     if ((g_DDCaps.dwCaps & DDCAPS_ALIGNSIZEDEST) && g_DDCaps.dwAlignSizeDest)
00180         g_rcDst.right = g_rcDst.left + (g_rcDst.right - g_rcDst.left) & -(signed) (g_DDCaps.dwAlignSizeDest);
00181 }
00182 
00184 DWORD DDColorMatch(IDirectDrawSurface7 * pdds, COLORREF rgb)
00185 {
00186     COLORREF       rgbT;
00187     HDC            hdc;
00188     DWORD          dw = CLR_INVALID;
00189     DDSURFACEDESC2 ddsd;
00190     HRESULT        hres;
00191 
00192     //  Use GDI SetPixel to color match for us
00193     if (rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK) {
00194         rgbT = GetPixel(hdc, 0, 0);     // Save current pixel value
00195         SetPixel(hdc, 0, 0, rgb);       // Set our value
00196         pdds->ReleaseDC(hdc);
00197     }
00198     // Now lock the surface so we can read back the converted color
00199     ddsd.dwSize = sizeof(ddsd);
00200     while ((hres = pdds->Lock(NULL, &ddsd, 0, NULL)) == DDERR_WASSTILLDRAWING)
00201         YIELD_TO_THREAD();
00202     if (hres == DD_OK) {
00203         dw = *(DWORD *) ddsd.lpSurface;                 // Get DWORD
00204         if (ddsd.ddpfPixelFormat.dwRGBBitCount < 32)
00205             dw &= (1 << ddsd.ddpfPixelFormat.dwRGBBitCount) - 1;  // Mask it to bpp
00206         pdds->Unlock(NULL);
00207     }
00208     else return DisplayError("Can't lock primary surface", hres);
00209     //  Now put the color that was there back.
00210     if (rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK) {
00211         SetPixel(hdc, 0, 0, rgbT);
00212         pdds->ReleaseDC(hdc);
00213     }
00214     return dw;
00215 }
00216 
00218 bool DrawOverlay()
00219 {
00220     HRESULT        hRet;       // This is where we put return values from DirectDraw.
00221     DDSURFACEDESC2 surfDesc;
00222     // Setup structure
00223     memset(&surfDesc, 0, sizeof(surfDesc)); surfDesc.dwSize = sizeof(surfDesc);
00224 
00225     hRet = g_pDDSOverlay->Lock(NULL, &surfDesc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_NOSYSLOCK | DDLOCK_WRITEONLY, NULL);
00226     if (hRet != DD_OK ||  surfDesc.lpSurface == NULL)
00227         return DisplayError("Can't lock overlay surface", hRet);
00228     else {
00229         g_pImg = (unsigned int *)surfDesc.lpSurface;
00230         //g_pDDSOverlay->Unlock(NULL); is not needed?
00231     }
00232     // Setup effects structure
00233     memset(&g_OverlayFX, 0, sizeof(g_OverlayFX)); g_OverlayFX.dwSize = sizeof(g_OverlayFX);
00234     // Setup overlay flags.
00235     g_OverlayFlags = DDOVER_SHOW;
00236     // Check for destination color keying capability
00237     if ((g_DDCaps.dwCKeyCaps & DDCKEYCAPS_DESTOVERLAY) && ((g_DDCaps.dwCaps & DDCAPS_OVERLAYCANTCLIP) || (g_DDCaps.dwCKeyCaps & DDCKEYCAPS_NOCOSTOVERLAY) ))
00238     {
00239         // If so, we'll use it to clip the bitmap when other windows go on top
00240         // of us. Just for the record - this color range for color keying (the
00241         // high/low values) are not heavily supported right now, so for almost
00242         // all cards, just use the same color for both.
00243         g_OverlayFX.dckDestColorkey.dwColorSpaceLowValue =
00244         g_OverlayFX.dckDestColorkey.dwColorSpaceHighValue = DDColorMatch(g_pDDSPrimary, RGBKEY);
00245         g_OverlayFlags |= DDOVER_DDFX | DDOVER_KEYDESTOVERRIDE;
00246     } else {
00247         // If not, we'll setup a clipper for the window.  This will fix the
00248         // problem on a few video cards - but the ones that don't shouldn't care.
00249         hRet = g_pDD->CreateClipper(0, &g_pClipper, NULL);
00250         if (hRet != DD_OK)
00251             return DisplayError("Can't create clipper", hRet);
00252         hRet = g_pClipper->SetHWnd(0, g_hAppWnd);
00253         if (hRet != DD_OK)
00254             return DisplayError("Can't attach clipper", hRet);
00255         hRet = g_pDDSPrimary->SetClipper(g_pClipper);
00256         if (hRet != DD_OK)
00257             return DisplayError("Can't set clipper", hRet);
00258     }
00259     return true;
00260 }
00261 
00263 bool DDPrimaryInit()
00264 {
00265     HRESULT        hRet;
00266     DDSURFACEDESC2 ddsd;  // A surface description structure
00267 
00268     // Create the primary surface.  The primary surface is the full screen -
00269     // since we're a windowed app - we'll just write to the portion of the
00270     // screen within our window.
00271     memset(&ddsd, 0, sizeof(ddsd)); // Set all fields of struct to 0 and set .dwSize to
00272     ddsd.dwSize = sizeof(ddsd);     // Sizeof the variable - these two steps required for most DDraw structs
00273     ddsd.dwFlags = DDSD_CAPS;       // Set flags for variables we're using...
00274     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;  // Set the variables we said we would in dwFlags
00275     hRet = g_pDD->CreateSurface(&ddsd, &g_pDDSPrimary, NULL);
00276     if (hRet != DD_OK)
00277         return DisplayError("Can't create primary surface", hRet);
00278     return true;
00279 }
00280 
00282 bool DDInit()
00283 {
00284     HRESULT hRet;
00285     g_rcSrc.right = g_sizex;
00286     g_rcSrc.bottom = g_sizey;
00287 
00288     hRet = DirectDrawCreateEx(NULL, (VOID**)&g_pDD, IID_IDirectDraw7, NULL);
00289     if (hRet != DD_OK)
00290         return DisplayError("Can't create DirectDraw7 instance", hRet);
00291 
00292     // Set cooperation level with other windows to be normal (ie. not full screen)
00293     // You MUST set the cooperation level to be SOMETHING, for windowed apps use
00294     // DDSCL_NORMAL, for full screen use: DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN.
00295     hRet = g_pDD->SetCooperativeLevel(g_hAppWnd, DDSCL_NORMAL);
00296     if (hRet != DD_OK)
00297         return DisplayError("Can't set cooperative level", hRet);
00298     return DDPrimaryInit();
00299 }
00300 
00302 bool DDOverlayInit()
00303 {
00304     // Get hardware's CAPabilitieS
00305     memset(&g_DDCaps, 0, sizeof(g_DDCaps));
00306     g_DDCaps.dwSize = sizeof(g_DDCaps);
00307     if (g_pDD->GetCaps(&g_DDCaps, 0))
00308         return DisplayError("Can't get capabilities");
00309 
00310     // Make sure it supports overlays
00311     if (!(g_DDCaps.dwCaps & DDCAPS_OVERLAY))
00312         return DisplayError("Hardware doesn't support overlays");
00313 
00314     //DO NOT Make sure it supports stretching (scaling)
00315     //if (!(g_DDCaps.dwCaps & DDCAPS_OVERLAYSTRETCH)) return false;
00316 
00317     DDSURFACEDESC2              ddsd;  // DirectDraw surface descriptor
00318     HRESULT                     hRet;  // I'm not even going to try...
00319     // The pixel formats that we want the surface to be in
00320     DDPIXELFORMAT               ddpfOverlayFormats[] = {
00321         {sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 32, 0xFF0000, 0x0FF00, 0x0000FF, 0}, // 32-bit RGB
00322         {sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 16, 0x007C00, 0x003e0, 0x00001F, 0}, // 16-bit RGB 5:5:5
00323         {sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 16, 0x00F800, 0x007e0, 0x00001F, 0}, // 16-bit RGB 5:6:5
00324         {sizeof(DDPIXELFORMAT), DDPF_FOURCC, mmioFOURCC('U','Y','V','Y'), 16, 0, 0, 0, 0}, // UYVY
00325         {sizeof(DDPIXELFORMAT), DDPF_FOURCC, mmioFOURCC('Y','4','2','2'), 16, 0, 0, 0, 0}, // the same as UYVY
00326         {sizeof(DDPIXELFORMAT), DDPF_FOURCC, mmioFOURCC('Y','U','Y','2'), 16, 0, 0, 0, 0}, // YUY2 is unsupported color-space here
00327         {0}};
00328 
00329     // Setup the overlay surface's attributes in the surface descriptor
00330     memset(&ddsd, 0, sizeof(ddsd));
00331     ddsd.dwSize = sizeof(ddsd);
00332     ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY | g_DDCaps.ddsCaps.dwCaps&DDSCAPS_VIDEOMEMORY;
00333     ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
00334     ddsd.dwBackBufferCount = 0;
00335     ddsd.dwWidth = g_sizex;
00336     ddsd.dwHeight = g_sizey;
00337     for(int format = 0; ddpfOverlayFormats[format].dwSize; format++) {
00338         ddsd.ddpfPixelFormat = ddpfOverlayFormats[format];
00339         // Attempt to create the surface with theses settings
00340         hRet = g_pDD->CreateSurface(&ddsd, &g_pDDSOverlay, NULL);
00341         if(hRet == DD_OK) break;
00342     }
00343     if (hRet != DD_OK)
00344         return DisplayError("Can't create appropriate overlay surface", hRet);
00345     return true;
00346 }
00347 
00348 inline void mouse(int k, LPARAM lParam)
00349 {
00350     int x = (int)LOWORD(lParam), y = (int)HIWORD(lParam);
00351     g_video->on_mouse( x*g_sizex/(g_rcDst.right - g_rcDst.left),
00352         y*g_sizey/(g_rcDst.bottom - g_rcDst.top), k);
00353 }
00354 
00355 LRESULT CALLBACK InternalWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
00356 {
00357     PAINTSTRUCT                 ps;         // Structure for the paint message
00358     POINT                       p = {0, 0}; // Translation point for the window's client region
00359     HRESULT                     hRet;
00360 
00361     switch (iMsg)
00362     {
00363         case WM_MOVE:
00364             // Make sure we're not moving to be minimized - because otherwise
00365             // our ratio varialbes (g_dwXRatio and g_dwYRatio) will end up
00366             // being 0, and once we hit CheckBoundries it divides by 0.
00367             if (!IsIconic(hwnd))
00368             {
00369                 g_rcSrc.left = 0;
00370                 g_rcSrc.right = g_sizex;
00371                 g_rcSrc.top = 0;
00372                 g_rcSrc.bottom = g_sizey;
00373                 GetClientRect(hwnd, &g_rcDst);
00374                 g_dwXRatio = (g_rcDst.right - g_rcDst.left) * 1000 /
00375                              (g_rcSrc.right - g_rcSrc.left);
00376                 g_dwYRatio = (g_rcDst.bottom - g_rcDst.top) * 1000 /
00377                              (g_rcSrc.bottom - g_rcSrc.top);
00378                 ClientToScreen(hwnd, &p);
00379                 g_rcDst.left = p.x;
00380                 g_rcDst.top = p.y;
00381                 g_rcDst.bottom += p.y;
00382                 g_rcDst.right += p.x;
00383                 CheckBoundries();
00384             }
00385             else
00386                 // Else, hide the overlay... just in case we can't do
00387                 // destination color keying, this will pull the overlay
00388                 // off of the screen for the user.
00389                 if (g_pDDSOverlay && g_pDDSPrimary)
00390                     g_pDDSOverlay->UpdateOverlay(NULL, g_pDDSPrimary, NULL, DDOVER_HIDE, NULL);
00391             // Check to make sure our window exists before we tell it to
00392             // repaint. This will fail the first time (while the window is being created).
00393             if (hwnd)
00394             {
00395                 InvalidateRect(hwnd, NULL, FALSE);
00396                 UpdateWindow(hwnd);
00397             }
00398             return 0L;
00399 
00400         case WM_SIZE:
00401             // Another check for the minimization action.  This check is
00402             // quicker though...
00403             if (wParam != SIZE_MINIMIZED)
00404             {
00405                 GetClientRect(hwnd, &g_rcDst);
00406                 ClientToScreen(hwnd, &p);
00407                 g_rcDst.left = p.x;
00408                 g_rcDst.top = p.y;
00409                 g_rcDst.bottom += p.y;
00410                 g_rcDst.right += p.x;
00411                 g_rcSrc.left = 0;
00412                 g_rcSrc.right = g_sizex;
00413                 g_rcSrc.top = 0;
00414                 g_rcSrc.bottom = g_sizey;
00415                 // Here we multiply by 1000 to preserve 3 decimal places in the
00416                 // division opperation (we picked 1000 to be on the same order
00417                 // of magnitude as the stretch factor for easier comparisons)
00418                 g_dwXRatio = (g_rcDst.right - g_rcDst.left) * 1000 /
00419                              (g_rcSrc.right - g_rcSrc.left);
00420                 g_dwYRatio = (g_rcDst.bottom - g_rcDst.top) * 1000 /
00421                              (g_rcSrc.bottom - g_rcSrc.top);
00422                 CheckBoundries();
00423             }
00424             return 0L;
00425 
00426         case WM_PAINT:
00427             BeginPaint(hwnd, &ps);
00428             // Check the primary surface to see if it's lost - if so you can
00429             // pretty much bet that the other surfaces are also lost - thus
00430             // restore EVERYTHING!  If we got our surfaces stolen by a full
00431             // screen app - then we'll destroy our primary - and won't be able
00432             // to initialize it again. When we get our next paint message (the
00433             // full screen app closed for example) we'll want to try to reinit
00434             // the surfaces again - that's why there is a check for
00435             // g_pDDSPrimary == NULL.  The other option, is that our program
00436             // went through this process, could init the primary again, but it
00437             // couldn't init the overlay, that's why there's a third check for
00438             // g_pDDSOverlay == NULL.  Make sure that the check for
00439             // !g_pDDSPrimary is BEFORE the IsLost call - that way if the
00440             // pointer is NULL (ie. !g_pDDSPrimary is TRUE) - the compiler
00441             // won't try to evaluate the IsLost function (which, since the
00442             // g_pDDSPrimary surface is NULL, would be bad...).
00443             if (!g_pDDSPrimary || (g_pDDSPrimary->IsLost() != DD_OK) ||
00444                 (g_pDDSOverlay == NULL))
00445             {
00446                 DestroyOverlay();
00447                 DestroyPrimary();
00448                 if (DDPrimaryInit())
00449                     if (DDOverlayInit())
00450                         if (!DrawOverlay())
00451                             DestroyOverlay();
00452             }
00453             // UpdateOverlay is how we put the overlay on the screen.
00454             if (g_pDDSOverlay && g_pDDSPrimary && g_video->updating)
00455             {
00456                 hRet = g_pDDSOverlay->UpdateOverlay(&g_rcSrc, g_pDDSPrimary,
00457                                                     &g_rcDst, g_OverlayFlags,
00458                                                     &g_OverlayFX);
00459 #ifdef _DEBUG
00460                 if(hRet != DD_OK) DisplayError("Can't update overlay", hRet);
00461 #endif
00462             }
00463             EndPaint(hwnd, &ps);
00464             return 0L;
00465 
00466         // process mouse and keyboard events
00467         case WM_LBUTTONDOWN:    mouse(1, lParam); break;
00468         case WM_LBUTTONUP:      mouse(-1, lParam); break;
00469         case WM_RBUTTONDOWN:    mouse(2, lParam); break;
00470         case WM_RBUTTONUP:      mouse(-2, lParam); break;
00471         case WM_MBUTTONDOWN:    mouse(3, lParam); break;
00472         case WM_MBUTTONUP:      mouse(-3, lParam); break;
00473         case WM_CHAR:           g_video->on_key(wParam); break;
00474 
00475         case WM_DISPLAYCHANGE:  return 0L;
00476 
00477         case WM_DESTROY:
00478             // Now, shut down the window...
00479             PostQuitMessage(0);
00480             return 0L;
00481     }
00482     return g_pUserProc? g_pUserProc(hwnd, iMsg, wParam, lParam) : DefWindowProc(hwnd, iMsg, wParam, lParam);
00483 }
00484 
00485 DWORD WINAPI thread_vsync(LPVOID lpParameter)
00486 {
00487     BOOL vblank = false;
00488     while(g_video && g_video->running) {
00489         while(!vblank && g_video && g_video->running) {
00490             YIELD_TO_THREAD();
00491             LPDIRECTDRAW7 pDD(g_pDD);
00492             if(pDD) pDD->GetVerticalBlankStatus(&vblank);
00493         }
00494         LPDIRECTDRAWSURFACE7 pDDSOverlay(g_pDDSOverlay);
00495         if(pDDSOverlay) pDDSOverlay->UpdateOverlay(&g_rcSrc, g_pDDSPrimary, &g_rcDst, g_OverlayFlags | DDOVER_REFRESHALL, &g_OverlayFX);
00496         do {
00497             Sleep(1);
00498             LPDIRECTDRAW7 pDD(g_pDD);
00499             if(pDD) pDD->GetVerticalBlankStatus(&vblank);
00500         } while(vblank && g_video && g_video->running);
00501         while(g_video && !g_video->updating && g_video->running) Sleep(10);
00502     }
00503     return 0;
00504 }
00505 
00507 
00508 inline void mask2bits(unsigned int mask, color_t &save, char &shift)
00509 {
00510     save  = mask; if(!mask) { shift = 8; return; }
00511     shift = 0; while(!(mask&1)) ++shift, mask >>= 1;
00512     int bits = 0; while(mask&1) ++bits,  mask >>= 1;
00513     shift += bits - 8;
00514 }
00515 
00516 bool video::init_window(int sizex, int sizey)
00517 {
00518     assert(win_hInstance != 0);
00519     g_sizex = sizex; g_sizey = sizey;
00520     if( !WinInit(win_hInstance, win_iCmdShow, gWndClass, title, false) )
00521         return DisplayError("Unable to initialize the program's window.");
00522     running = true;
00523     if( !DDInit() ) {
00524         DestroyDDraw();
00525         goto fail;
00526     }
00527     if( !DDOverlayInit() || !DrawOverlay() ) {
00528         DestroyOverlay();
00529         DestroyDDraw();
00530         goto fail;
00531     }
00532     DDPIXELFORMAT PixelFormat; memset(&PixelFormat, 0, sizeof(PixelFormat)); PixelFormat.dwSize = sizeof(PixelFormat);
00533     g_pDDSOverlay->GetPixelFormat(&PixelFormat);
00534     mask2bits(PixelFormat.dwRBitMask, red_mask, red_shift);
00535     mask2bits(PixelFormat.dwGBitMask, green_mask, green_shift);
00536     mask2bits(PixelFormat.dwBBitMask, blue_mask, blue_shift);
00537     if(PixelFormat.dwFlags == DDPF_RGB)
00538          depth = char(PixelFormat.dwRGBBitCount);
00539     else depth = -char(PixelFormat.dwFourCC);
00540     for(int i = 0, e = sizex * sizey * PixelFormat.dwRGBBitCount / 32, c = get_color(0, 0, 0); i < e; i++)
00541         g_pImg[i] = c; // clear surface
00542     ShowWindow(g_hAppWnd, SW_SHOW);
00543     g_hVSync = CreateThread (
00544         NULL,          // LPSECURITY_ATTRIBUTES security_attrs
00545         0,             // SIZE_T stacksize
00546         (LPTHREAD_START_ROUTINE) thread_vsync,
00547         this,               // argument
00548         0, 0);
00549     SetPriorityClass(g_hVSync, IDLE_PRIORITY_CLASS); // questionable
00550     return true;
00551 fail:
00552     g_pImg = new unsigned int[g_sizex * g_sizey];
00553     return false;
00554 }
00555 
00556 void video::terminate()
00557 {
00558     running = false;
00559     DestroyOverlay();
00560     if(WaitForSingleObject(g_hVSync, 100) == WAIT_TIMEOUT) TerminateThread(g_hVSync, 0);
00561     CloseHandle(g_hVSync);
00562     DestroyDDraw();
00563     if(g_pImg) delete[] g_pImg;
00564     g_pImg = 0; g_video = 0;
00565 }
00567 
00568 drawing_area::drawing_area(int x, int y, int sizex, int sizey)
00569 : start_x(x), start_y(y), size_x(sizex), size_y(sizey), pixel_depth(g_video->depth),
00570     base_index(y*g_sizex + x), max_index(g_sizex*g_sizey), index_stride(g_sizex), ptr32(g_pImg)
00571 {
00572     assert(ptr32); assert(x < g_sizex); assert(y < g_sizey);
00573     assert(x+sizex <= g_sizex); assert(y+sizey <= g_sizey);
00574 
00575     index = base_index; // current index
00576 }
00577 
00578 drawing_area::~drawing_area()
00579 {
00580 }

Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.

GNU Lesser General Public License 3 Sourceforge.net