📄 ddvideo.cpp
字号:
// 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 objectbool 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) { Sleep(0); 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, char &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 = char(PixelFormat.dwRGBBitCount); else depth = -char(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}drawing_area::~drawing_area(){}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -