📄 mosquito.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//-----------------------------------------------------------------------------
// File: Mosquito.cpp
//
// Desc: Mosquito is a DirectDraw sample application that demonstates the
// use of video overlay. It creates a flipable overlay, loads a small
// animation into the various back buffers, then flips the buffers as
// it moves the overlay around the screen. Press F12 or ESC to quit.
//
//-----------------------------------------------------------------------------
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
//-----------------------------------------------------------------------------
// Include files
//-----------------------------------------------------------------------------
#include <windows.h>
#include <ddraw.h>
#include "resource.h"
#include "winuserm.h"
//-----------------------------------------------------------------------------
// Local definitions
//-----------------------------------------------------------------------------
#define NAME TEXT("MosquitoWndClass")
#define TITLE TEXT("Mosquito")
#define BUG_WIDTH 320
#define BUG_HEIGHT 200
#ifdef UNDER_CE
#define RAND_INT(x) (Random() % x)
#else
#define RAND_INT(x) (rand()*x/RAND_MAX)
#endif
#define RANDOM_VELOCITY() (int)(((RAND_INT(5)+3)*2))
//-----------------------------------------------------------------------------
// Default settings
//-----------------------------------------------------------------------------
#define TIMER_ID 1
#define TIMER_RATE 200
//-----------------------------------------------------------------------------
// Global data
//-----------------------------------------------------------------------------
LPDIRECTDRAW g_pDD = NULL; // DirectDraw object
LPDIRECTDRAWSURFACE g_pDDSPrimary = NULL; // Primary Surface.
LPDIRECTDRAWSURFACE g_pDDSOverlay = NULL; // The overlay primary.
BOOL g_bActive = FALSE; // Is application active?
int g_RotationAngles = 0; // Supported rotation angles.
int g_CurrentAngle = 0; // Current rotation angle.
LPCTSTR g_szErrorMessage = NULL; // Error message to display.
// Overlay position and velocity data.
int g_nOverlayXPos, g_nOverlayYPos;
int g_nOverlayXVel, g_nOverlayYVel;
int g_nOverlayWidth, g_nOverlayHeight;
DWORD g_dwOverlayXPositionAlignment;
// Our instance handle.
HINSTANCE g_hInstance;
//-----------------------------------------------------------------------------
// Local data
//-----------------------------------------------------------------------------
static TCHAR szImg1[] = TEXT("IDB_BUGIMAGE1");
static TCHAR szImg2[] = TEXT("IDB_BUGIMAGE2");
static TCHAR szImg3[] = TEXT("IDB_BUGIMAGE3");
static const TCHAR szDDrawError[] = TEXT("DirectDraw Error");
static const TCHAR szDDrawFailedMsg[] = TEXT("DirectDrawCreate failed.");
static const TCHAR szSetCooperativeFailMsg[] = TEXT("SetCooperativeLevel failed.");
static const TCHAR szNoOverlaysMsg[] = TEXT("Overlays are not supported in hardware!");
static const TCHAR szCreateOverlayFailMsg[] = TEXT("Unable to create overlay surface!");
static const TCHAR szLoadOverlayFailMsg[] = TEXT("Unable to load images to overlay surface!");
static const TCHAR szShowOverlayFailMsg[] = TEXT("Unable to show overlay surface!");
static const TCHAR szNoFlipSurfacesMsg[] =TEXT("Display driver doesn't support flipping surfaces.");
static const TCHAR szEnumAttachedSurfacesFailMsg[] = TEXT("EnumAttachedSurfaces failed.");
static const TCHAR szCreateSurfaceFailMsg[] = TEXT("CreateSurface failed.");
static const TCHAR szSetTimerFailMsg[] = TEXT("SetTimer failed.");
static const TCHAR szGetCapsFailMsg[] = TEXT("GetCaps FAILED");
// These are the pixel formats this app supports. Most display adapters
// with overlay support will recognize one or more of these formats.
// We start with YUV format, then work down to RGB. (All 16 bpp.)
static DDPIXELFORMAT ddpfOverlayFormats[] = {
//{sizeof(DDPIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('Y','U','Y','V'),0,0,0,0,0}, // YUYV
//{sizeof(DDPIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('U','Y','V','Y'),0,0,0,0,0}, // UYVY
{sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 16, 0x7C00, 0x03e0, 0x001F, 0}, // 16-bit RGB 5:5:5
{sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 16, 0xF800, 0x07e0, 0x001F, 0} // 16-bit RGB 5:6:5
};
#define PF_TABLE_SIZE (sizeof(ddpfOverlayFormats) / sizeof(ddpfOverlayFormats[0]))
static RECT rs;
static RECT rd;
//-----------------------------------------------------------------------------
// Prototypes
//-----------------------------------------------------------------------------
void ReleaseAllObjects(void);
HRESULT InitFail(HWND, HRESULT, LPCTSTR, ...);
HRESULT RestoreAllSurfaces();
void MoveOverlay();
long FAR PASCAL WindowProc(HWND, UINT, WPARAM, LPARAM);
BOOL CopyBitmapToYUVSurface(LPDIRECTDRAWSURFACE, HBITMAP);
BOOL LoadImageOntoSurface(LPDIRECTDRAWSURFACE, LPCTSTR);
HRESULT WINAPI EnumSurfacesCallback(LPDIRECTDRAWSURFACE, LPDDSURFACEDESC, LPVOID);
HRESULT LoadBugImages();
HRESULT InitApp(HINSTANCE hInstance, int nCmdShow);
//-----------------------------------------------------------------------------
// Name: ReleaseAllObjects()
// Desc: Finished with all objects we use; release them
//-----------------------------------------------------------------------------
static void
ReleaseAllObjects(void)
{
if (g_pDDSOverlay != NULL)
{
// Use UpdateOverlay() with the DDOVER_HIDE flag to remove an overlay
// from the display.
g_pDDSOverlay->UpdateOverlay(NULL, g_pDDSPrimary, NULL, DDOVER_HIDE, NULL);
g_pDDSOverlay->Release();
g_pDDSOverlay = NULL;
}
if (g_pDDSPrimary != NULL)
{
g_pDDSPrimary->Release();
g_pDDSPrimary = NULL;
}
if (g_pDD != NULL)
{
g_pDD->Release();
g_pDD = NULL;
}
}
//-----------------------------------------------------------------------------
// Name: InitFail()
// Desc: This function is called if an initialization function fails
//-----------------------------------------------------------------------------
static HRESULT
InitFail(HWND hWnd, HRESULT hRet, LPCTSTR szError,...)
{
ReleaseAllObjects();
DestroyWindow(hWnd);
g_szErrorMessage = szError;
return hRet;
}
//-----------------------------------------------------------------------------
// Name: RestoreAllSurfaces
// Desc: Called in case we lose our surface's vram.
//-----------------------------------------------------------------------------
static HRESULT
RestoreAllSurfaces()
{
HRESULT hRet;
// Try Restoring the primary surface.
hRet = g_pDDSPrimary->Restore();
if (hRet != DD_OK)
return hRet;
// Try Restoring the overlay surface.
hRet = g_pDDSOverlay->Restore();
if (hRet != DD_OK)
return hRet;
// Reload the images.
hRet = LoadBugImages();
if (hRet != DD_OK)
return hRet;
// Show the overlay.
hRet = g_pDDSOverlay->UpdateOverlay(&rs, g_pDDSPrimary, &rd, DDOVER_SHOW, NULL);
return hRet;
}
//-----------------------------------------------------------------------------
// Name: MoveOverlay()
// Desc: Called on the timer, this function moves the overlay around the
// screen, periodically calling flip to animate the mosquito.
//-----------------------------------------------------------------------------
static void
MoveOverlay()
{
HRESULT hRet;
DWORD dwXAligned;
// Add the current velocity vectors to the position.
g_nOverlayXPos += g_nOverlayXVel;
g_nOverlayYPos += g_nOverlayYVel;
// Check to see if this new position puts the overlay off the edge of the screen.
// SetOverlayPosition() won't like that.
// Have we gone off the left edge?
if (g_nOverlayXPos < 0) {
g_nOverlayXPos = 0;
g_nOverlayXVel = RANDOM_VELOCITY();
}
// Have we gone off the right edge?
if ((g_nOverlayXPos+g_nOverlayWidth) > GetSystemMetrics(SM_CXSCREEN)){
g_nOverlayXPos = GetSystemMetrics(SM_CXSCREEN) - g_nOverlayWidth;
g_nOverlayXVel = -RANDOM_VELOCITY();
}
// Have we gone off the top edge?
if (g_nOverlayYPos < 0) {
g_nOverlayYPos = 0;
g_nOverlayYVel = RANDOM_VELOCITY();
}
// Have we gone off the bottom edge?
if ( (g_nOverlayYPos+g_nOverlayHeight) > GetSystemMetrics(SM_CYSCREEN)) {
g_nOverlayYPos = GetSystemMetrics(SM_CYSCREEN) - g_nOverlayHeight;
g_nOverlayYVel = -RANDOM_VELOCITY();
}
// We need to check for any alignment restrictions on the X position.
if (g_dwOverlayXPositionAlignment)
dwXAligned = g_nOverlayXPos - g_nOverlayXPos % g_dwOverlayXPositionAlignment;
else
dwXAligned = g_nOverlayXPos;
// Set the overlay to it's new position.
hRet = g_pDDSOverlay->SetOverlayPosition(dwXAligned, g_nOverlayYPos);
if (hRet == DDERR_SURFACELOST)
{
if (FAILED(RestoreAllSurfaces()))
return;
}
// Flip.
while (TRUE)
{
hRet = g_pDDSOverlay->Flip(NULL, 0);
if (hRet == DD_OK)
break;
if (hRet == DDERR_SURFACELOST)
{
hRet = RestoreAllSurfaces();
if (hRet != DD_OK)
break;
}
if (hRet != DDERR_WASSTILLDRAWING)
break;
}
}
//-----------------------------------------------------------------------------
// Name: WindowProc()
// Desc: The Main Window Procedure
//-----------------------------------------------------------------------------
long FAR PASCAL
WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int NewAngle;
DEVMODE DevMode;
switch (message)
{
#ifdef UNDER_CE
case WM_ACTIVATE:
#else
case WM_ACTIVATEAPP:
#endif
// Pause if minimized or not the top window
g_bActive = (wParam == WA_ACTIVE) || (wParam == WA_CLICKACTIVE);
return 0L;
case WM_KILLFOCUS:
// We do not allow anyone else to have the keyboard focus until
// we are done.
SetFocus(hWnd);
return 0L;
case WM_DESTROY:
// Clean up and close the app
ReleaseAllObjects();
PostQuitMessage(0);
return 0L;
case WM_KEYDOWN:
// Handle any non-accelerated key commands
switch (wParam)
{
case VK_ACTION:
PostMessage(hWnd, WM_CLOSE, 0, 0);
return 0L;
case VK_RIGHT:
// Rotate to the "next" angle.
if (g_CurrentAngle >= 0 && g_RotationAngles >= 0) {
NewAngle = g_CurrentAngle;
do
{
NewAngle <<= 1;
if (NewAngle == DMDO_0)
{
NewAngle = DMDO_90;
}
if (NewAngle > DMDO_270)
{
NewAngle = DMDO_0;
}
} while (!(NewAngle & g_RotationAngles) && (NewAngle != DMDO_0));
memset(&DevMode, 0, sizeof (DevMode));
DevMode.dmSize = sizeof (DevMode);
DevMode.dmFields = DM_DISPLAYORIENTATION;
DevMode.dmDisplayOrientation = NewAngle;
if (DISP_CHANGE_SUCCESSFUL == ChangeDisplaySettingsEx(NULL, &DevMode, NULL, CDS_RESET, NULL)) {
g_CurrentAngle = NewAngle;
RestoreAllSurfaces();
}
}
return 0L;
}
break;
case WM_TIMER:
// Update and flip surfaces
if (g_bActive && TIMER_ID == wParam)
{
MoveOverlay();
}
break;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
//-----------------------------------------------------------------------------
// Function: CopyBitmapToYUVSurface
// Description:
// Copies an RGB GDI bitmap to a YUV surface. Both bitmap and surface
// must be a multiple of 2 pixels in width for the supported YUV formats.
// The following formats are supported:
// YUYV
// UYVY
//
// The "YUYV" YUV pixel format looks like this:
// As a series of BYTES: [Y0][U][Y1][V] (reverse it for a DWORD)
//
// The "UYVY" YUV pixel format looks like this:
// As a series of BYTES: [U][Y0][V][Y1] (reverse it for a DWORD)
//
// As you can see, both formats pack two pixels into a single DWORD. The
// pixels share U and V components and have separate Y components.
//
// Returns: TRUE if successful, otherwise FALSE.
//-----------------------------------------------------------------------------
static BOOL
CopyBitmapToYUVSurface(LPDIRECTDRAWSURFACE lpDDSurf, HBITMAP hbm)
{
HDC hdcImage;
HRESULT ddrval;
DDSURFACEDESC ddsd;
DWORD x, y, dwWidth, dwHeight;
LONG lPitch;
LPBYTE pSurf;
DWORD dwBytesInRow;
COLORREF color;
BYTE R,G,B, Y0,Y1,U,V;
BOOL bRet = FALSE;
if (hbm == NULL || lpDDSurf == NULL)
return FALSE;
//
// select bitmap into a memoryDC so we can use it.
//
hdcImage = CreateCompatibleDC(NULL);
SelectObject(hdcImage, hbm);
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
// Lock down the surface so we can modify it's contents.
ddrval=lpDDSurf->Lock( NULL, &ddsd, DDLOCK_WAITNOTBUSY, NULL);
if (FAILED(ddrval))
goto CleanUp;
dwWidth=ddsd.dwWidth;
dwHeight=ddsd.dwHeight;
lPitch=ddsd.lPitch;
pSurf=(LPBYTE)ddsd.lpSurface;
dwBytesInRow=ddsd.dwWidth*2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -