WinCE Overlay - 示例:mosquito

在代码中增加了很多对代码的注释。

同时,对在不同平台(Telechips,MStar)的测试效果也做了说明。

虽然代码是 Overlay 示例,但还是增加了一些东东,对 Overlay 有兴趣的童鞋可以看看。  


// mosquito.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include <windows.h>
#include <commctrl.h>
#include "Resource.h"
//-----------------------------------------------------------------------------
// Include files
//-----------------------------------------------------------------------------
#include <ddraw.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.

// 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");//TEXT("IDB_BUGIMAGE1");
static TCHAR                szImg2[] = TEXT("IDB_BUGIMAGE2");
static TCHAR                szImg3[] = TEXT("IDB_BUGIMAGE3");

// 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.)

/*
 * Telechips 8902 支持 2 层 overlay
 * 只能创建一层 YUV 的 overlay (可以再创建一层 RGB overlay)
 * RGB 模式可以创建多个,模式与顺序没有不影响创建
*/
static DDPIXELFORMAT ddpfOverlayFormats[] = {
    //{sizeof(DDPIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('Y','U','Y','V'),0,0,0,0,0},  // YUYV - Leo.Zheng Telechips 8902 可以支持
    //{sizeof(DDPIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('U','Y','V','Y'),0,0,0,0,0},  // UYVY - Leo.Zheng Telechips 8902:Create No.1 surface return: 0x88760218
    // {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, UINT);
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)
    {
                // 如果不再需要一个覆盖表面或只想不让覆盖可见, 就可以设定适当的标志调用 UpdateOverlay 方法来隐藏该覆盖表面
        // 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
//-----------------------------------------------------------------------------
#define PREFIX      TEXT("MOSQUITO: ")
#define PREFIX_LEN  10

static HRESULT InitFail(HWND hWnd, HRESULT hRet, LPCTSTR szError,...)
{
    TCHAR szBuff[128] = PREFIX;
    va_list vl;

    va_start(vl, szError);
    StringCchVPrintf(szBuff + PREFIX_LEN, (128-PREFIX_LEN), szError, vl);    
    size_t len = wcslen(szBuff);
    StringCchPrintf(szBuff + len, 128 - len, TEXT("\r\n"));
    ReleaseAllObjects();
    OutputDebugString(szBuff);
    DestroyWindow(hWnd);
    va_end(vl);
    return hRet;
}

#undef PREFIX_LEN
#undef PREFIX

//-----------------------------------------------------------------------------
// Name: RestoreAllSurfaces
// Desc: Called in case we lose our surface's vram.
//-----------------------------------------------------------------------------
static HRESULT RestoreAllSurfaces()
{
    HRESULT hRet = 0;

    // 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 = 0;
    DWORD dwXAligned = 0;

    // 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;
    }

        // 注意, 不要使用太靠近目标表面的右/下边界的坐标. 因为 SetOverlayPosition 方法并不执行剪切功能,
        // 所以使用那些可能导致覆盖超出目标表面边界的坐标会引起调用的失败, 并返回 DDERR_INVALIDPOSITION.

    // Flip.
    while(TRUE)
    {
        hRet = g_pDDSOverlay->Flip(NULL, 0);
        if(hRet == DD_OK)
            break;
        if(hRet == DDERR_SURFACELOST)           // 正常情况下,不执行此 if 语句
        {
            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
                        RETAILMSG(1,(L"[mosquito]overlay test - release overlay objects.\r\n"));
            ReleaseAllObjects();
            PostQuitMessage(0);
                        return 0L;

                case WM_LBUTTONDOWN:            // Leo.Zheng 没有窗体,无法响应 MOUSE 消息
                        PostMessage(hWnd, WM_CLOSE, 0, 0);
                        break;

        case WM_KEYDOWN:
            // Handle any non-accelerated key commands
            switch (wParam)
            {
                case VK_ESCAPE:
                case VK_F12:
                    PostMessage(hWnd, WM_CLOSE, 0, 0);
                    return 0L;

                case VK_SPACE:
                    // 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();
                                Sleep(100);
                                LoadBugImages();
            }
            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;
    DWORD               dwPitch;
    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;
    dwPitch=ddsd.lPitch;
    pSurf=(LPBYTE)ddsd.lpSurface;
        dwBytesInRow=ddsd.dwWidth*2;

    // Go through the image 2 pixels at a time and convert to YUV
    for(y=0; y<dwHeight; y++)
    {
                for(x=0; x<dwWidth; x+=2)
                {
                        // The equations for color conversion used here, probably aren't 
                        // exact, but they seem to do an OK job.
                        color=GetPixel(hdcImage, x,y);
                        R=GetRValue(color);
                        G=GetGValue(color);
                        B=GetBValue(color);
                    Y0= (BYTE)(0.29*R + 0.59*G + 0.14*B);
                        U= (BYTE)(128.0 - 0.14*R - 0.29*G + 0.43*B);

                        color=GetPixel(hdcImage, x+1,y);
                        R=GetRValue(color);
                        G=GetGValue(color);
                        B=GetBValue(color);
                        Y1= (BYTE)(0.29*R + 0.57*G + 0.14*B);
                        V= (BYTE)(128.0 + 0.36*R - 0.29*G - 0.07*B);

                        switch (ddsd.ddpfPixelFormat.dwFourCC)
                        {
                                case MAKEFOURCC('Y','U','Y','V'): 
                                        *(pSurf++) = Y0;
                                        *(pSurf++) = U;
                                        *(pSurf++) = Y1;
                                        *(pSurf++) = V;
                                        break;
                                case MAKEFOURCC('U','Y','V','Y'): 
                                        *(pSurf++) = U;
                                        *(pSurf++) = Y0;
                                        *(pSurf++) = V;
                                        *(pSurf++) = Y1;
                                        break;
                        }                       
                }
                pSurf+=(dwPitch-dwBytesInRow);
    }

    lpDDSurf->Unlock(NULL);     

CleanUp:
    if(hdcImage)
        DeleteDC(hdcImage);

        return TRUE;
}

//-----------------------------------------------------------------------------
//  Function: LoadImageOnToSurface
//  Description:
//      Loads a resource based bitmap image onto a DirectDraw surface.  Can
//      covert the bitmap to all RGB formats, plus a couple YUV formats.
//-----------------------------------------------------------------------------
static BOOL LoadImageOntoSurface(LPDIRECTDRAWSURFACE lpdds, UINT lpstrResID)
{
    HBITMAP hbm = NULL;
    HDC     hdcImage = NULL;
    HDC     hdcSurf = NULL;
    BOOL bRetVal = FALSE;
    HRESULT ddrval;
    DDSURFACEDESC ddsd;

    if(!lpdds)
                return FALSE;

    // get surface size and format.
    memset(&ddsd, 0, sizeof(ddsd));
    ddsd.dwSize = sizeof(ddsd);
    ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH;
    ddrval = lpdds->GetSurfaceDesc(&ddsd);
    if(FAILED(ddrval))
            goto Exit;

        // Load the bitmap resource.  We'll use LoadImage() since it'll scale the 
    // image to fit our surface, and maintain the color information in the bitmap.
    hbm = (HBITMAP)LoadImage(g_hInstance, MAKEINTRESOURCE(lpstrResID), IMAGE_BITMAP, 0, 0, 0);
        if(hbm == NULL)
            goto Exit;

    // If our surface is a FOURCC YUV format, we need to do a little work to convert
    // our RGB resource bitmap into the appropriate YUV format.
    if(ddsd.ddpfPixelFormat.dwFlags == DDPF_FOURCC)
    {
                if(!CopyBitmapToYUVSurface(lpdds, hbm))
                        goto Exit;
    }
    else  //Looks like we're just using a standard RGB surface format, let GDI do the work.
    {
            // Create a DC and associate the bitmap with it.
            hdcImage = CreateCompatibleDC(NULL);
            SelectObject(hdcImage, hbm);
   
            ddrval = lpdds->GetDC(&hdcSurf);
            if(FAILED(ddrval))
                goto Exit;
    
            if(BitBlt(hdcSurf, 0, 0, ddsd.dwWidth, ddsd.dwHeight, hdcImage, 0, 0, SRCCOPY) == FALSE)
                goto Exit;

                ::SetBkMode(hdcSurf,TRANSPARENT);
                ::SetTextColor(hdcSurf,RGB(255,0,0));
                RECT Rect={0,0,100,50};
                ::DrawText(hdcSurf,_T("ABCD"),4,&Rect,DT_SINGLELINE|DT_LEFT);
    }

    bRetVal = TRUE;
    
Exit:
    if(hdcSurf)
            lpdds->ReleaseDC(hdcSurf);
    if(hdcImage)
            DeleteDC(hdcImage);
    if(hbm)
            DeleteObject(hbm);

    return bRetVal;
}

//-----------------------------------------------------------------------------
// Name: EnumSurfacesCallback()
// Desc: Used by LoadBugImages to aid it loading all three bug images.
//-----------------------------------------------------------------------------
static HRESULT WINAPI EnumSurfacesCallback(LPDIRECTDRAWSURFACE lpDDSurface,  
                     LPDDSURFACEDESC lpDDSurfaceDesc,  
                     LPVOID lpContext)
{
    int *CallCount = (int *)lpContext;
    HRESULT hr = (HRESULT)DDENUMRET_OK;
    UINT ResName;

    // Load the Bug Image appropriate...
    if(*CallCount == 0)
        {
        ResName = IDB_BUGIMAGE2;
    }
    else if(*CallCount == 1)
        {
        ResName = IDB_BUGIMAGE3;
    }
    else
        {
        hr = (HRESULT)DDENUMRET_CANCEL;
        goto exit;
    }

    if(!LoadImageOntoSurface(lpDDSurface, ResName))
        {
        hr = (HRESULT)DDENUMRET_CANCEL;
        goto exit;
    }

    // Bump the count.
    (*CallCount)++;
        if(*CallCount >= 2)
        {
                *CallCount = 0;
        }

exit:
    lpDDSurface->Release();
    return hr;
}

//-----------------------------------------------------------------------------
// Name: LoadBugImages()
// Desc: Load the bug resource images into our various flipping surfaces.
//-----------------------------------------------------------------------------
static HRESULT LoadBugImages()
{
    HRESULT hRet;
    static int CallCount = 0;

    // Put the first bug image onto the first buffer of our complex surface.
        if(0 == CallCount)
        {
                if(!LoadImageOntoSurface(g_pDDSOverlay, IDB_BUGIMAGE1))
                        return (E_FAIL);
        }

    // Use the enumeration attachment function to load the other images.
    hRet = g_pDDSOverlay->EnumAttachedSurfaces((LPVOID)&CallCount,EnumSurfacesCallback);

    return (hRet);
}

//-----------------------------------------------------------------------------
// Name: InitApp()
// Desc: Do work required for every instance of the application:
//          Create the window, initialize data
//-----------------------------------------------------------------------------
static HRESULT InitApp(HINSTANCE hInstance, int nCmdShow)
{
    HWND          hWnd;
    WNDCLASS      wc;
    DDSURFACEDESC ddsd;
    DDCAPS        ddcaps;
    HRESULT       hRet;
    DWORD         dwUpdateFlags = 0;
    DDOVERLAYFX   ovfx;
    DEVMODE       DevMode;

    // Check for rotation support by getting the rotation angles supported.
    memset(&DevMode, 0, sizeof(DevMode));
    DevMode.dmSize = sizeof(DevMode);
    DevMode.dmFields = DM_DISPLAYQUERYORIENTATION;
    if(DISP_CHANGE_SUCCESSFUL == ChangeDisplaySettingsEx(NULL, &DevMode, NULL, CDS_TEST, NULL))
        {
        g_RotationAngles = DevMode.dmDisplayOrientation;
    }
    else
        {
        OutputDebugString(L"MOSQUITO: Device does not support any rotation modes. Rotation disabled.");
        g_RotationAngles = -1;
    }

    // Get the current rotation angle.
    memset(&DevMode, 0, sizeof (DevMode));
    DevMode.dmSize = sizeof (DevMode);
    DevMode.dmFields = DM_DISPLAYORIENTATION;
    if(DISP_CHANGE_SUCCESSFUL == ChangeDisplaySettingsEx(NULL, &DevMode, NULL, CDS_TEST, NULL))
        {
        g_CurrentAngle = DevMode.dmDisplayOrientation;
    }
    else
        {
        OutputDebugString(L"MOSQUITO: Unable to read current rotation. Rotation disabled.");
        g_CurrentAngle = -1;
    }

    // Set up and register window class.
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WindowProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MOSQUITO));
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH )GetStockObject(BLACK_BRUSH);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = NAME;
    RegisterClass(&wc);

    // Create a window.
    hWnd = CreateWindowEx(WS_EX_TOPMOST,
      NAME,
      TITLE,
      WS_POPUP,
      0,
      0,
      GetSystemMetrics(SM_CXSCREEN),
      GetSystemMetrics(SM_CYSCREEN),
      NULL,
      NULL,
      hInstance,
      NULL);
    if(!hWnd)
        return FALSE;
    // We never show the window, only set focus to it.
    SetFocus(hWnd);

    // Create the main DirectDraw object
    hRet = DirectDrawCreate(NULL, &g_pDD, NULL);
    if(hRet != DD_OK)
        return InitFail(hWnd, hRet, TEXT("DirectDrawCreate FAILED"));

    // Get normal mode.
    hRet = g_pDD->SetCooperativeLevel(hWnd, DDSCL_NORMAL);
    if(hRet != DD_OK)
        return InitFail(hWnd, hRet, TEXT("SetCooperativeLevel FAILED"));

    // Get a primary surface interface pointer (only needed for init.)
        // 要使用覆盖表面, 必须先要初始化一个主表面, 覆盖表面将显示在该主表面上
    memset(&ddsd, 0, sizeof(ddsd));
    ddsd.dwSize = sizeof(ddsd);
    ddsd.dwFlags = DDSD_CAPS;
    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
    hRet = g_pDD->CreateSurface(&ddsd, &g_pDDSPrimary, NULL);
    if(hRet != DD_OK)
        return InitFail(hWnd, hRet, TEXT("CreateSurface FAILED"));

    // See if we can support overlays.
        // 初始化 DirectDraw 后, 需要检测设备是否支持覆盖表面
        // 因为 DirectDraw 不能仿真覆盖, 所以如果硬件不支持覆盖, 就不能继续下面的工作
    memset(&ddcaps, 0, sizeof(ddcaps));
    ddcaps.dwSize = sizeof(ddcaps);
    hRet = g_pDD->GetCaps(&ddcaps, NULL);
    if(hRet != DD_OK)
        return InitFail(hWnd, hRet, TEXT("GetCaps FAILED"));

    if(ddcaps.dwOverlayCaps == 0)
        return InitFail(hWnd, hRet, TEXT("Overlays are not supported in hardware!"));
        /* // Leo.Zheng Add
        if(!(capsDrv.dwCaps & DDCAPS_OVERLAY))
                return FALSE;
        */

    // Get alignment info to compute our overlay surface size.
    rs.left = 0;
    rs.top = 0;
    rs.right = BUG_WIDTH;
    rs.bottom = BUG_HEIGHT;
    if(ddcaps.dwAlignSizeSrc != 0)
            rs.right += rs.right % ddcaps.dwAlignSizeSrc;
    
    // Create the overlay flipping surface. We will attempt the pixel formats
        // in our table one at a time until we find one that jives.
        // 如果知道显示设备支持覆盖表面, 就可以创建一个. 因为没有指明设备怎样支持覆盖表面的标准, 所以不能够期望创建任意大小的像素格式的表面.
        // 另外, 也不要期望第一次创建覆盖表面就会成功. 因此, 必须作好准备进行多次创建的尝试, 直到有一个能够工作为止.
        int i = 0;
    memset(&ddsd, 0, sizeof(ddsd));
    ddsd.dwSize = sizeof(ddsd);
    ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY | DDSCAPS_FLIP;
    ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_BACKBUFFERCOUNT | DDSD_PIXELFORMAT;
        ddsd.dwWidth = rs.right;
        ddsd.dwHeight = rs.bottom;
    ddsd.dwBackBufferCount = 1;
    do
        {       // Leo.Zheng MStar 2521 只创建 16-bit RGB 5:6:5 成功; 创建 16-bit RGB 5:5:5 失败.
            ddsd.ddpfPixelFormat = ddpfOverlayFormats[i];
            hRet = g_pDD->CreateSurface(&ddsd, &g_pDDSOverlay, NULL);                   // Leo.Zheng 此处调用后引起使用 IOCtrl 显示在 LCD 上的消失
                RETAILMSG(1,(L"[mosquito]Create No.%d surface return: 0x%X\r\n",i + 1,hRet));
    }while(hRet != DD_OK && (++i < PF_TABLE_SIZE));
    if(hRet != DD_OK)
        return InitFail(hWnd, hRet, TEXT("Unable to create overlay surface!"));

    // Load the images.
    if(LoadBugImages() != DD_OK)
        return InitFail(hWnd, hRet, TEXT("Unable to load images to overlay surface!"));

    // Finish setting up the overlay.
    int StretchFactor1000 = ddcaps.dwMinOverlayStretch > 1000 ? ddcaps.dwMinOverlayStretch : 1000;

    rd.left=0; 
    rd.top=0;
    // Adding 999 takes care of integer truncation problems.
    rd.right  = (rs.right * StretchFactor1000 + 999) / 1000;
    rd.bottom = rs.bottom * StretchFactor1000 / 1000;
    if (ddcaps.dwAlignSizeDest != 0)
            rd.right = (int)((rd.right + ddcaps.dwAlignSizeDest - 1)/ ddcaps.dwAlignSizeDest) * ddcaps.dwAlignSizeDest;

        // 显示覆盖表面: 在设置了源矩形和目的矩形后, 就可以显示覆盖了.
        // 程序开始在临时变量 dwUpdateFlags 中设定了 DDOVER_SHOW 和 DDOVER_DDFX 标志, 指明该覆盖是第一次显示, 
        // 硬件应该使用包含在 DDOVERLAYFX 结构中的效果信息完成这一工作.
        // UpdateOverlay 用于重新定位一个覆盖页面, 或修改其视觉属性.
    // Set the flags we'll send to UpdateOverlay
    dwUpdateFlags = DDOVER_SHOW;
        // dwUpdateFlags = DDOVER_SHOW | DDOVER_DDFX;                   // Leo.Zheng DDOVER_DDFX WinCE 不支持

        // 检查 DDCAPS 结构确定覆盖是否支持源 Color Key
    // Does the overlay hardware support source color keying?
    // If so, we can hide the black background around the image.
    // This probably won't work with YUV formats
    memset(&ovfx, 0, sizeof(ovfx));
    ovfx.dwSize = sizeof(ovfx);
    if(ddcaps.dwOverlayCaps & DDOVERLAYCAPS_CKEYSRC)                    // MStar2521 不支持 color key
    {
        dwUpdateFlags |= DDOVER_KEYSRCOVERRIDE;

        // Create an overlay FX structure so we can specify a source color key.
        // This information is ignored if the DDOVER_SRCKEYOVERRIDE flag 
        // isn't set.
        ovfx.dckSrcColorkey.dwColorSpaceLowValue=0; // black as the color key
        ovfx.dckSrcColorkey.dwColorSpaceHighValue=0;
    }
        else
        {
                RETAILMSG(1,(L"[mosquito]cannot support color key: 0x%X(0x%x)\r\n",ddcaps.dwOverlayCaps,DDOVERLAYCAPS_CKEYSRC));
        }

    // Update the overlay parameters.
        // 调用 IDirectDrawSurface::UpdateOverlay 方法来显示覆盖
    hRet = g_pDDSOverlay->UpdateOverlay(&rs, g_pDDSPrimary, &rd, dwUpdateFlags, &ovfx);
    if(hRet != DD_OK)
        {
                // 在 MStar 2521 设备上运行第二个此程序实例时出错。
                // 在 TeleChips 8902 设备上运行第三个此程序实例时出错。
                return InitFail(hWnd, hRet, TEXT("Unable to show overlay surface: 0x%x!"),hRet);
        }

    // Set a bunch of position and velocity module vars.
    g_nOverlayXPos = 0;
    g_nOverlayYPos = 0;
    g_nOverlayXVel = RANDOM_VELOCITY();
    g_nOverlayYVel = RANDOM_VELOCITY();
    g_nOverlayWidth = rd.right - rd.left;
    g_nOverlayHeight = rd.bottom - rd.top;
    
    // Set the "destination position alignment" global so we won't have to
    // keep calling GetCaps() everytime we move the overlay surface.
    g_dwOverlayXPositionAlignment = ddcaps.dwAlignBoundaryDest;

    // Create a timer to flip the pages.
    if(TIMER_ID != SetTimer(hWnd, TIMER_ID, TIMER_RATE, NULL))
        return InitFail(hWnd, hRet, TEXT("SetTimer FAILED"));

    return DD_OK;
}

//-----------------------------------------------------------------------------
// Name: WinMain()
// Desc: Initialization, message loop
//-----------------------------------------------------------------------------
int PASCAL WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
#ifdef UNDER_CE
        LPWSTR lpCmdLine,
#else
        LPSTR lpCmdLine,
#endif
        int nCmdShow)
{
    MSG msg;

    g_hInstance = hInstance;
    if(InitApp(hInstance, nCmdShow) != DD_OK)
        return FALSE;

    while(GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return msg.wParam;
}


你可能感兴趣的:(WinCE Overlay - 示例:mosquito)