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

原文地址:https://www.cnblogs.com/resound/p/1797607.html