• Direct3D实现2D


    本文摘自百度空间-飘忽木头

    http://hi.baidu.com/357802636/blog/item/4a669ff98b29ced2b48f319c.html

    感谢原作者

           使用Direct3D实现2D功能,很简洁的方式就是用Sprite的Draw功能,将Texture装载的图片画出来。刚完成了使用Direct3D代替DirectDraw,使C2的Windows模拟器能在保证效率的情况下很好的支持图片的alpha通道具体实现如下:

    在Direct9的lib支持下,定义全局变量:

    static LPDIRECT3D9                     g_pD3D       = NULL; // Used to create the D3DDevice
    static LPDIRECT3DDEVICE9       g_pd3dDevice = NULL; // Our rendering device
    static ID3DXSprite*                       g_pd3dSprite = NULL;

    初始化windows窗口:


    HRESULT InitWindow(HWND &hWnd, WNDCLASSEX &wc)
    {
    // Register the window class
    wc.cbSize = sizeof(WNDCLASSEX);
        wc.style = CS_CLASSDC;
        wc.lpfnWndProc = MsgProc;
        wc.cbClsExtra = 0L;
        wc.cbWndExtra = 0L;
        wc.hInstance = GetModuleHandle(NULL);
        wc.hIcon = NULL;
        wc.hCursor = NULL;
        wc.hbrBackground = NULL;
        wc.lpszMenuName = NULL;
        wc.lpszClassName = CLASS_NAME;
        wc.hIconSm = NULL;

        RegisterClassEx( &wc );

        // Create the application's window
        hWnd = CreateWindow( CLASS_NAME
            ,WINDOW_NAME
            ,WS_OVERLAPPEDWINDOW
            , 0, 0
            , WIN_WIDTH, WIN_HEIGHT
            ,GetDesktopWindow()
            , NULL
            , wc.hInstance
            , NULL );
    if (!hWnd)
    {
       return S_FALSE;
    }
    return S_OK;
    }

    初始化D3D设备:

    HRESULT InitD3D( HWND hWnd )
    {
        // Create the D3D object, which is needed to create the D3DDevice.
    //这个参数告诉Direct3D使用正确的头文件,这个值会在任何时间头文件或其它改变需要重新建立工程时增加
        if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
            return E_FAIL;

        // Get the current desktop display mode
        D3DDISPLAYMODE d3ddm;
        if( FAILED( g_pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm ) ) )
            return E_FAIL;

        // Set up the structure used to create the D3DDevice. Most parameters are
        // zeroed out. We set Windowed to TRUE, since we want to do D3D in a
        // window, and then set the SwapEffect to "discard", which is the most
        // efficient method of presenting the back buffer to the display. And
        // we request a back buffer format that matches the current desktop display
        // format.
        D3DPRESENT_PARAMETERS d3dpp;
        ZeroMemory( &d3dpp, sizeof(d3dpp) );
        d3dpp.Windowed = TRUE;//窗口化
    d3dpp.BackBufferHeight = WIN_HEIGHT;
    d3dpp.BackBufferWidth = WIN_WIDTH;
    d3dpp.hDeviceWindow = hWnd;
    d3dpp.BackBufferCount = 1;
        d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;//交换缓冲支持的效果类型,每次的表面翻页后,背景表面的数据都给丢弃
        d3dpp.BackBufferFormat = d3ddm.Format;//后备缓冲的格式

        // Create the Direct3D device. Here we are using the default adapter (most
        // systems only have one, unless they have multiple graphics hardware cards
        // installed) and requesting the HAL (which is saying we want the hardware
        // device rather than a software one). Software vertex processing is
        // specified since we know it will work on all cards. On cards that support
        // hardware vertex processing, though, we would see a big performance gain
        // by specifying hardware vertex processing.
        if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT/*主显卡的ID*/
              ,D3DDEVTYPE_HAL
              , hWnd/*视窗的ID*/
              ,D3DCREATE_SOFTWARE_VERTEXPROCESSING/*3D顶点的处理方式*/
              ,&d3dpp, &g_pd3dDevice ) ) )
        {
            return E_FAIL;
        }

        // Device state would normally be set here

        return S_OK;
    }

    初始化Sprite:

    HRESULT InitD3DSprite()
    {
    return D3DXCreateSprite(g_pd3dDevice,&g_pd3dSprite);
    }

    加载图片到Texture对象中的方法:


    HRESULT LoadTextureTest()
    {
    D3DXCreateTextureFromFileEx(g_pd3dDevice
            ,"./Data.Out/SPR_76EE68075757_SPR.png"
            ,D3DX_DEFAULT_NONPOW2//215//D3DX_DEFAULT 不被拉升为2次幂
            ,D3DX_DEFAULT_NONPOW2//174//D3DX_DEFAULT
            ,1,
            0,
            D3DFMT_UNKNOWN,
            D3DPOOL_MANAGED,
            D3DX_DEFAULT,
            D3DX_DEFAULT,
            0xffff00ff,
            NULL,
            NULL,
            &g_pd3dTexture1);
    return D3DXCreateTextureFromFileEx(g_pd3dDevice
              ,"./Debug/test001.png"
              ,D3DX_DEFAULT_NONPOW2
              ,D3DX_DEFAULT_NONPOW2
              ,1,
              0,
              D3DFMT_UNKNOWN,
              D3DPOOL_MANAGED,
              D3DX_DEFAULT,
              D3DX_DEFAULT,
              0xFF000000,
              NULL,
              NULL,
              &g_pd3dTexture);
    }

    其中g_pd3dTexture和g_pd3dTexture1是两个IDirect3DTexture9指针对象,这里只是列举加载图片的方法。

    通过Sprite画图:

    void D3DDraw_SpriteTest()
    {
    if( NULL == g_pd3dDevice )
       return;
    if (NULL == g_pd3dSprite)
    {
       return;
    }
    g_pd3dDevice->Clear( 0/*多少个长方形需要清理*/
       , NULL/*指针指向一个长方体数组*/
       ,D3DCLEAR_TARGET/*清除的目标*/
       , D3DCOLOR_XRGB(0,255,0)
       , 1.0f/*Z值,0.0是深度离盯着屏幕的观众最近,1.0是最远*/
       , 0 );

    // Begin the scene
    g_pd3dDevice->BeginScene();

    //Begin参数:
    /*D3DXSPRITE_DONOTSAVESTATE 调用Begin()或End()不保存/恢复设备状态. (如pd3dDevice->SetRenderState中设置的部分状态)
     D3DXSPRITE_DONOTMODIFY_RENDERSTATE 不是很清楚, 呵呵, 表面上看好像是不改变渲染状态...
    D3DXSPRITE_OBJECTSPACE 不改变世界矩阵(WORLD)/投影矩阵(TRANSFORM)以及视点矩阵(VIEW), 使用设置在D3DDevice上的矩阵, 如果不指定这个标志, 3个矩阵自动改变为屏幕空间座标
    D3DXSPRITE_BILLBOARD BillBoard, 很清楚吧, 所有的Sprite都全部自动旋转来对着观看着
    D3DXSPRITE_ALPHABLEND 让Sprite支持AlphaBlend, 很重要, 几乎每次调用Begin都要指定此标志, 另外, D3DRS_ALPHATESTENABLE 状态必须设置为 TRUE, D3DBLEND_SRCALPHA / D3DBLEND_INVSRCALPHA 分别为源混和状态和目标很合状态
    D3DXSPRITE_SORT_TEXTURE Sprite会按照渲染先后排序, 当渲染在同一个深度的Sprite推荐使用.
    D3DXSPRITE_SORT_DEPTH_FRONTTOBACK 按照从前到后的渲染顺序对Sprite排序, 当在不同深度渲染有透明信息的Sprite时推荐使用.
    D3DXSPRITE_SORT_DEPTH_BACKTOFRONT 按照从后到前的渲染顺序对Sprite排序, 当在不同深度渲染透明Sprite时推荐使用*/
    if (FAILED(g_pd3dSprite->Begin(D3DXSPRITE_ALPHABLEND)))/*让Sprite支持AlphaBlend*/
    {
       return;
    }

    //SetupMatrices();

    D3DXVECTOR3 tex_Center,tex_Postion;
    tex_Center.x = 0;
    tex_Center.y = 0;
    tex_Center.z = 0;

    tex_Postion.x = 0;
    tex_Postion.y = 0;
    tex_Postion.z = 0;

    RECT rect = {0,0,WIN_WIDTH-5,WIN_HEIGHT-5};

    //D3DXMATRIX mat;
    //D3DXMatrixTransformation2D(&mat
    // ,&D3DXVECTOR2(0,240)/*缩放中心*/
    // ,0/*ScalingRotation*/
    // ,&D3DXVECTOR2(0.9f,0.9f)/*缩放因子*/
    // ,&D3DXVECTOR2(WIN_WIDTH/2, WIN_HEIGHT/2)/*旋转中心*/
    // , 0/*旋转因子*/
    // , &D3DXVECTOR2(0, 0));/*绘图的位置*/
    //g_pd3dSprite->SetTransform(&mat);

    g_pd3dSprite->Draw(g_pd3dTexture
           ,&rect
           ,&tex_Center /*中心默认为左上角*/
           ,&tex_Postion
           ,0xffFFffFF);

    rect.top = 0;
    rect.left = 0;
    rect.right = 215;
    rect.bottom = 174;

    tex_Postion.x = 0;
    tex_Postion.y = 240;
    tex_Postion.z = 0;
    g_pd3dSprite->Draw(g_pd3dTexture1
       ,&rect
       ,NULL /*中心默认为左上角*/
       ,&tex_Postion
       ,0xffffffff);


    g_pd3dSprite->End();
    g_pd3dDevice->EndScene();
    g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
    //ValidateRect( g_hwnd, NULL );
    }
    其他的一些方法实现如下:

    清空Texture中的某个区域

    void ClearImage(void *pSurface,void *rect)
    {
    RECT *dr = (RECT*)rect;
    LPDIRECT3DSURFACE9 pDestSurface = NULL;

    ((IDirect3DTexture9*)pSurface)->GetSurfaceLevel(0, &pDestSurface); // 纹理对应表面
    D3DSURFACE_DESC DestsurfaceDesc;
    pDestSurface->GetDesc(&DestsurfaceDesc);
    D3DLOCKED_RECT DestlockedRect;
    pDestSurface->LockRect(&DestlockedRect, 0, 0); // entire surface

    DWORD* DestimageData = (DWORD*)DestlockedRect.pBits;

    int ndest;
    for (int i=dr->top;i<dr->bottom;++i)
    {
       for (int j=dr->left;j<dr->right;++j)
       {
        ndest = i*DestlockedRect.Pitch/4+j;
        DestimageData[ndest]= 0xff000000;
       }
    }
    pDestSurface->UnlockRect();
    }

    //************************************
    // Method:    DrawImage
    // FullName: DrawImage
    // Access:    public
    // Returns:   void
    // Qualifier: Texture相互拷贝
    // Parameter: void * pDest
    // Parameter: void * pDestRect
    // Parameter: void * pSource
    // Parameter: void * pSourceRect
    // Parameter: bool bBlend
    //************************************
    void DrawImage(void *pDest,void *pDestRect,void *pSource,void *pSourceRect,bool bBlend)
    {

    RECT *dr = (RECT*)pDestRect;
    RECT *sr = (RECT*)pSourceRect;
    LPDIRECT3DSURFACE9 pDestSurface = NULL;
    LPDIRECT3DSURFACE9 pSourceSurface = NULL;

    ((IDirect3DTexture9*)pDest)->GetSurfaceLevel(0, &pDestSurface); // 纹理对应表面
    D3DSURFACE_DESC DestsurfaceDesc;
    pDestSurface->GetDesc(&DestsurfaceDesc);
    D3DLOCKED_RECT DestlockedRect;
    pDestSurface->LockRect(&DestlockedRect, 0, 0); // entire surface

    ((IDirect3DTexture9*)pSource)->GetSurfaceLevel(0, &pSourceSurface); // 纹理对应表面
    D3DSURFACE_DESC SourcesurfaceDesc;
    pSourceSurface->GetDesc(&SourcesurfaceDesc);
    D3DLOCKED_RECT SourcelockedRect;
    pSourceSurface->LockRect(&SourcelockedRect, 0, 0); // entire surface

    DWORD* DestimageData = (DWORD*)DestlockedRect.pBits;
    DWORD* SourceimageData = (DWORD*)SourcelockedRect.pBits;

    int sH = sr->top-1;
    int sW = sr->left-1;
    int ndest,nsource;
    for (int i=dr->top;i<dr->bottom;++i)
    {
       if(++sH>=sr->bottom)
       {
        sH = sr->top;
       }
       for (int j=dr->left;j<dr->right;++j)
       {
        if (++sW>=sr->right)
        {
         sW = sr->left;
        }
        ndest = i*DestlockedRect.Pitch/4+j;
        nsource = sH*SourcelockedRect.Pitch/4+sW;
        DestimageData[ndest+0]= SourceimageData[nsource+0];
       }
    }
    pDestSurface->UnlockRect();
    pSourceSurface->UnlockRect();
    }

    创建空的Texture:

    void* CreateEmemySuface(int ImageWidth,int ImageHeight)
    {
    //创建Direct3DTexture
    IDirect3DTexture9* pd3dTexture = NULL;
    if(S_OK != D3DXCreateTexture(g_pd3dDevice
           ,ImageWidth
           ,ImageHeight
           ,1
           ,0
           ,D3DFMT_A8B8G8R8
           ,D3DPOOL_MANAGED
           ,&pd3dTexture))
    {
       return NULL;
    }
    return (void *)pd3dTexture;
    }

    //************************************
    // Method:    BeginDrawSprite
    // FullName: BeginDrawSprite
    // Access:    public
    // Returns:   void
    // Qualifier: 开始画动画
    // Parameter: void
    //************************************
    void BeginDrawSprite(void)
    {
    if( NULL == g_pd3dDevice )
       return;
    if (NULL == g_pd3dSprite)
    {
       return;
    }
    if (g_bDrawSprBegin)
    {
       return;
    }
    #if USE_DIRTYRECT == 0
    //如果不用脏矩形,重绘之前需要清理所有的东西
    g_pd3dDevice->Clear( 0/*多少个长方形需要清理*/
       , NULL/*指针指向一个长方体数组*/
       ,D3DCLEAR_TARGET/*清除的目标*/
       , D3DCOLOR_XRGB(0,0,0)
       , 1.0f/*Z值,0.0是深度离盯着屏幕的观众最近,1.0是最远*/
       , 0 );
    #endif
    g_pd3dDevice->BeginScene();

    /*D3DXSPRITE_DONOTSAVESTATE 调用Begin()或End()不保存/恢复设备状态. (如pd3dDevice->SetRenderState中设置的部分状态)
     D3DXSPRITE_DONOTMODIFY_RENDERSTATE 不是很清楚, 呵呵, 表面上看好像是不改变渲染状态...
    D3DXSPRITE_OBJECTSPACE 不改变世界矩阵(WORLD)/投影矩阵(TRANSFORM)以及视点矩阵(VIEW), 使用设置在D3DDevice上的矩阵, 如果不指定这个标志, 3个矩阵自动改变为屏幕空间座标
    D3DXSPRITE_BILLBOARD BillBoard, 很清楚吧, 所有的Sprite都全部自动旋转来对着观看着
    D3DXSPRITE_ALPHABLEND 让Sprite支持AlphaBlend, 很重要, 几乎每次调用Begin都要指定此标志, 另外, D3DRS_ALPHATESTENABLE 状态必须设置为 TRUE, D3DBLEND_SRCALPHA / D3DBLEND_INVSRCALPHA 分别为源混和状态和目标很合状态
    D3DXSPRITE_SORT_TEXTURE Sprite会按照渲染先后排序, 当渲染在同一个深度的Sprite推荐使用.
    D3DXSPRITE_SORT_DEPTH_FRONTTOBACK 按照从前到后的渲染顺序对Sprite排序, 当在不同深度渲染有透明信息的Sprite时推荐使用.
    D3DXSPRITE_SORT_DEPTH_BACKTOFRONT 按照从后到前的渲染顺序对Sprite排序, 当在不同深度渲染透明Sprite时推荐使用*/
    if (FAILED(g_pd3dSprite->Begin(D3DXSPRITE_ALPHABLEND)))/*让Sprite支持AlphaBlend*/
    {
       return;
    }
    g_bDrawSprBegin = true;//标记为开启了drawSprite
    }

    void EndDrawSprite(void)
    {
    if( NULL == g_pd3dDevice )
       return;
    if (NULL == g_pd3dSprite)
    {
       return;
    }
    if (!g_bDrawSprBegin)
    {//如果drawSprite没有开启,返回,保证不被重复开启或重复关闭
       g_bReady=1;
       return;
    }
    g_bDrawSprBegin = false;
    g_pd3dSprite->End();
    g_pd3dDevice->EndScene();
    g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
    ShowGameFps();
    g_bReady=1;
    }

  • 相关阅读:
    分享:TreeFrog 1.3 发布,基于 C++/QT 的 Web 框架
    Linux环境进程间通信(五): 共享内存(上)
    TUP第二期:架构师王鹏云演讲实录 _业界_科技时代_新浪网
    发布我的倒排索引 C/C++ ChinaUnix.net
    操作系统内存管理——分区、页式、段式管理
    内存管理内幕
    IT农民工如何来美国工作
    来自 王斌 (@iwangbin) 的推文
    ScheduledExecutorService执行周期性或定时任务
    PHP XML parse error: Extra content at the end of the document
  • 原文地址:https://www.cnblogs.com/resound/p/1797607.html
Copyright © 2020-2023  润新知