• DDraw绘图


    微软已经提供了GDI+绘图方式,但是GDI+绘图较慢,另外微软提供了效率更高的DirectDraw绘图方式。DirectDraw提供硬件加速功能。

    首先需要确保电脑上的Ddraw硬件加速功能已经打开,安装DirectX March 2009之后,可以在【开始】菜单->运行 Dxdiag 命令,检查是否打开硬件加速。如图1:

    image_thumb5

    如果DirectDraw加速未启用,需要更新驱动。


    开始使用DirectDraw编写程序,需要引入ddraw.h头文件,并把ddraw.lib添加到工程里。

    DirectDrawCreate(NULL, &m_lpDirectDraw, NULL) 用于创建一个DirectDraw对象,通过该对象用来创建主表面和离屏表面。

    DirectDraw有两种表面,主表面和离屏表面。主表面是现实跟用户的,离屏便面相对于一个内存块,可以进行图像处理,可以将离屏表面的图像拷贝到主表面,这样就将新的图像显示给用户了。

        // 创建主表面
        DDSURFACEDESC dds;
        ZeroMemory(&dds, sizeof(DDSURFACEDESC));
        dds.dwSize = sizeof(DDSURFACEDESC);
        dds.dwFlags = DDSD_CAPS;
        dds.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
        hr = m_lpDirectDraw->CreateSurface(&dds, &m_PrimarySurface, NULL);

      以上代码用来创建一个主表面,覆盖整个屏幕,dds.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE 用来描述该表面为主表面;

    // 创建备用表面
    ZeroMemory(&dds, sizeof(DDSURFACEDESC));
    dds.dwSize = sizeof(DDSURFACEDESC);
    dds.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
    dds.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
    dds.dwWidth = m_ClientRect.Width();
    dds.dwHeight = m_ClientRect.Height();
    hr = m_lpDirectDraw->CreateSurface(&dds, &m_SecondSurface, NULL);

    dds.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN  用来创建备用表面。由于本例子中,是一个CDialog窗体,所以需要创建裁剪器,将图像区域限制在一个CStatic上。

    hr = m_lpDirectDraw->CreateClipper(0, &m_Clipper, NULL);
    if (FAILED(hr))  return FALSE;
    hr = m_Clipper->SetHWnd(NULL, m_Static.m_hWnd);
    if (FAILED(hr)) return FALSE;
    hr = m_PrimarySurface->SetClipper(m_Clipper);

    CreateClipper用于创建裁剪器,SetHWnd设置显示区域的Handle。

    备用表面创建之后需要刷一层背景色,例子中用RGB(100, 100, 100)填充背景色。然后再拷贝图像到备用表面上。
    // 填充备用表面背景色
    DDBLTFX  bltfx;
    ZeroMemory(&bltfx, sizeof(DDBLTFX));
    bltfx.dwSize = sizeof(DDBLTFX);
    bltfx.dwFillColor = RGB(100, 100, 100);
    hr = m_SecondSurface->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &bltfx);

    下面将会使用StretchBlt拷贝图像到备用表面,再用Blt把备用表面的图像拷贝到主表面上。这时候显示的图像会被更新。

        hr = m_SecondSurface->GetDC(&hdc);
        CDC*  pDC = CDC::FromHandle(hdc);
        pDC->SetStretchBltMode(COLORONCOLOR);
        ::StretchBlt(hdc, 0, 0, m_ClientRect.Width(), m_ClientRect.Height(), m_image.GetDC(), 0, 0, m_image.GetWidth(),
            m_image.GetHeight(), SRCCOPY);
        m_image.ReleaseDC();
        m_SecondSurface->ReleaseDC(hdc);
        m_PrimarySurface->Blt(m_ClientRect, m_SecondSurface, NULL, DDBLT_WAIT, NULL);

    在开发MFC客户端程序时,通常都会遇到窗体闪烁的问题,这是因为窗体先刷一层背景色(默认为白色)再刷控件图像,由于背景色和图像反差太大,所以有闪烁的感觉,如果使用备用表面绘图,再拷贝到主表面上能有效避免闪烁。因备用表面上绘图、绘背景色不会影响到主表面显示。除非把备用表面的图像拷贝到主表面上。


    如果图像缩小显示的时候需要调用SetStretchBltMode(COLORONCOLOR) 否则会像素堆积,导致图像失真。

    将图像从备用表面拷贝到主表面时需要设置显示区域的屏幕坐标。否则绘图位置会有偏差。大笑
    工程如下:https://files.cnblogs.com/ityujian/TestDDraw.zip

  • 相关阅读:
    OOm是否可以try catch ?
    Java中两个线程是否可以同时访问同一个对象的两个不同的synchronized方法?
    PHP请求ws出现的问题
    AndFix注意事项
    thinkphp 查表返回的数组,js解析有UNICode编码,解决办法
    thinkphp用ajax遇到的坑——ajax请求没有反应
    用php获取js变量的值
    android项目安装报错:INSTALL_FAILED_CONFLICTING_PROVIDER
    96
    wuti
  • 原文地址:https://www.cnblogs.com/ityujian/p/3192508.html
Copyright © 2020-2023  润新知