DirectX画圆及圆角矩形的简单实现

来源:互联网 发布:编程免费学习 编辑:程序博客网 时间:2024/06/06 02:43

    讨论如何用d3d9来绘制圆及简单的圆角矩形。     

    画圆时采用Bresenham算法。不失一般性,假设圆的圆心位于坐标原点(如果圆心不在原点,可以通过坐标平移使其与原点重合),半径为R。以原点为圆心的圆C有四条对称轴:x=0,y=0,x=y和x=-y。若已知圆弧上一点P1=C(x, y),利用其对称性便可以得到关于四条对称轴的其它7个点,即: P2=C(x,-y), P3=C(-x, y), P4=C(-x,-y), P5=C(y,x), P6=C(-y,x), P7=C(y,-x), P8=C(-y,-x)。     

    这种性质称为八对称性。因此,只要扫描转换八分之一圆弧,就可以通过圆弧的八对称性得到整个圆。     

    我们以(0,0)为原点,r为半径,坐标系xy方向与屏幕坐标系一致,计算y轴正向右侧的八分之一圆弧,其它圆弧通过对称性得到。     

    顶点格式采用如下定义:

    struct SCREEN_VERTEX_UNTEX    {float x, y, z, h;D3DCOLOR color;static DWORD FVF;    };    SCREEN_VERTEX_UNTEX::FVF = D3DFVF_XYZRHW | D3DFVF_DIFFUSE
    下面是画圆函数:    
void DrawCircle( IDirect3DDevice9* pd3dDevice, int xCenter, int yCenter, int nRadius, D3DCOLOR FrameColor){SCREEN_VERTEX_UNTEX *pVertices = new SCREEN_VERTEX_UNTEX[2 * D3DX_PI * nRadius];//Bresenham algorithmint x=0, y=nRadius, d=1-nRadius, i=0;while(x <= y){//get eight points//(x,y)pVertices[i].x = x + xCenter;pVertices[i].y = y + yCenter;pVertices[i].z = 0.5f;pVertices[i].h = 1.0f;pVertices[i].color = FrameColor;//(x,-y)++i;pVertices[i].x = x + xCenter;pVertices[i].y = -y + yCenter;pVertices[i].z = 0.5f;pVertices[i].h = 1.0f;pVertices[i].color = FrameColor;//(-x, y)++i;pVertices[i].x = -x + xCenter;pVertices[i].y = y + yCenter;pVertices[i].z = 0.5f;pVertices[i].h = 1.0f;pVertices[i].color = FrameColor;//(-x, -y)++i;pVertices[i].x = -x + xCenter;pVertices[i].y = -y + yCenter;pVertices[i].z = 0.5f;pVertices[i].h = 1.0f;pVertices[i].color = FrameColor;//(y, x)++i;pVertices[i].x = y + xCenter;pVertices[i].y = x + yCenter;pVertices[i].z = 0.5f;pVertices[i].h = 1.0f;pVertices[i].color = FrameColor;//(-y, x)++i;pVertices[i].x = -y + xCenter;pVertices[i].y = x + yCenter;pVertices[i].z = 0.5f;pVertices[i].h = 1.0f;pVertices[i].color = FrameColor;//(y, -x)++i;pVertices[i].x = y + xCenter;pVertices[i].y = -x + yCenter;pVertices[i].z = 0.5f;pVertices[i].h = 1.0f;pVertices[i].color = FrameColor;//(-y,-x)++i;pVertices[i].x = -y + xCenter;pVertices[i].y = -x + yCenter;pVertices[i].z = 0.5f;pVertices[i].h = 1.0f;pVertices[i].color = FrameColor;++i;if(d>0){d+=2*(x-y)+5;--y;}else{d+=2*x+3;}++x;}pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, FALSE );pd3dDevice->SetRenderState( D3DRS_SEPARATEALPHABLENDENABLE, FALSE );pd3dDevice->SetRenderState( D3DRS_BLENDOP, D3DBLENDOP_ADD );pd3dDevice->SetRenderState( D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA|D3DCOLORWRITEENABLE_BLUE|D3DCOLORWRITEENABLE_GREEN|D3DCOLORWRITEENABLE_RED );pd3dDevice->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_GOURAUD );pd3dDevice->SetRenderState( D3DRS_FOGENABLE, FALSE );pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, FALSE );pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE);pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2 );pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE );pd3dDevice->SetFVF(SCREEN_VERTEX_UNTEX::FVF);pd3dDevice->DrawPrimitiveUP(D3DPT_POINTLIST, i, pVertices, sizeof(SCREEN_VERTEX_UNTEX));delete [] pVertices;}

    圆弧上像素点的个数为2*D3DX_PI*R,通过Bresenham算法逼近,产生的点的个数不会多于上面计算的点的个数。在得到一个点后,利用对称性,获得其它7个点。所有的点先放入顶点缓冲区,最后一次性提交。    

     画圆角矩形的方法和画圆类似,分别画四个圆弧,然后画四条线即可。为方便计算,这里只考虑圆角为四分之一圆弧的情况。

void DrawRoundRect( IDirect3DDevice9 * pd3dDevice, int nLeftRect, int nTopRect, int nRightRect, int nBottomRect, int nRadius, D3DCOLOR FrameColor ){SCREEN_VERTEX_UNTEX *pVertices = new SCREEN_VERTEX_UNTEX[2 * D3DX_PI * nRadius];//Bresenham algorithmint x=0, y=nRadius, d=1-nRadius, i=0;while(x <= y){//get eight points//right bottom//(x,y)pVertices[i].x = x + nRightRect - nRadius;pVertices[i].y = y + nBottomRect - nRadius;pVertices[i].z = 0.5f;pVertices[i].h = 1.0f;pVertices[i].color = FrameColor;//(y, x)++i;pVertices[i].x = y + nRightRect - nRadius;pVertices[i].y = x + nBottomRect - nRadius;pVertices[i].z = 0.5f;pVertices[i].h = 1.0f;pVertices[i].color = FrameColor;//right top//(x,-y)++i;pVertices[i].x = x + nRightRect - nRadius;pVertices[i].y = -y + nTopRect + nRadius;pVertices[i].z = 0.5f;pVertices[i].h = 1.0f;pVertices[i].color = FrameColor;//(y, -x)++i;pVertices[i].x = y + nRightRect - nRadius;pVertices[i].y = -x + nTopRect + nRadius;pVertices[i].z = 0.5f;pVertices[i].h = 1.0f;pVertices[i].color = FrameColor;//left bottom//(-x, y)++i;pVertices[i].x = -x + nLeftRect + nRadius;pVertices[i].y = y + nBottomRect - nRadius;pVertices[i].z = 0.5f;pVertices[i].h = 1.0f;pVertices[i].color = FrameColor;//(-y, x)++i;pVertices[i].x = -y + nLeftRect + nRadius;pVertices[i].y = x + nBottomRect - nRadius;pVertices[i].z = 0.5f;pVertices[i].h = 1.0f;pVertices[i].color = FrameColor;//left top//(-x, -y)++i;pVertices[i].x = -x + nLeftRect + nRadius;pVertices[i].y = -y + nTopRect + nRadius;pVertices[i].z = 0.5f;pVertices[i].h = 1.0f;pVertices[i].color = FrameColor;//(-y,-x)++i;pVertices[i].x = -y + nLeftRect + nRadius;pVertices[i].y = -x + nTopRect + nRadius;pVertices[i].z = 0.5f;pVertices[i].h = 1.0f;pVertices[i].color = FrameColor;++i;if(d>0){d+=2*(x-y)+5;--y;}else{d+=2*x+3;}++x;}static DXUT_SCREEN_VERTEX_UNTEX lineVertices[8] = {0};//top linelineVertices[0].x = nLeftRect + nRadius;lineVertices[0].y = nTopRect;lineVertices[0].z = 0.5f;lineVertices[0].h = 1.0f;lineVertices[0].color = FrameColor;lineVertices[1].x = nRightRect - nRadius;lineVertices[1].y = nTopRect;lineVertices[1].z = 0.5f;lineVertices[1].h = 1.0f;lineVertices[1].color = FrameColor;//right linelineVertices[2].x = nRightRect;lineVertices[2].y = nTopRect + nRadius;lineVertices[2].z = 0.5f;lineVertices[2].h = 1.0f;lineVertices[2].color = FrameColor;lineVertices[3].x = nRightRect;lineVertices[3].y = nBottomRect - nRadius;lineVertices[3].z = 0.5f;lineVertices[3].h = 1.0f;lineVertices[3].color = FrameColor;//bottom linelineVertices[4].x = nRightRect - nRadius;lineVertices[4].y = nBottomRect;lineVertices[4].z = 0.5f;lineVertices[4].h = 1.0f;lineVertices[4].color = FrameColor;lineVertices[5].x = nLeftRect + nRadius;lineVertices[5].y = nBottomRect;lineVertices[5].z = 0.5f;lineVertices[5].h = 1.0f;lineVertices[5].color = FrameColor;//left line lineVertices[6].x = nLeftRect;lineVertices[6].y = nBottomRect - nRadius;lineVertices[6].z = 0.5f;lineVertices[6].h = 1.0f;lineVertices[6].color = FrameColor;lineVertices[7].x = nLeftRect;lineVertices[7].y = nTopRect + nRadius;lineVertices[7].z = 0.5f;lineVertices[7].h = 1.0f;lineVertices[7].color = FrameColor;pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, FALSE );pd3dDevice->SetRenderState( D3DRS_SEPARATEALPHABLENDENABLE, FALSE );pd3dDevice->SetRenderState( D3DRS_BLENDOP, D3DBLENDOP_ADD );pd3dDevice->SetRenderState( D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA|D3DCOLORWRITEENABLE_BLUE|D3DCOLORWRITEENABLE_GREEN|D3DCOLORWRITEENABLE_RED );pd3dDevice->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_GOURAUD );pd3dDevice->SetRenderState( D3DRS_FOGENABLE, FALSE );pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, FALSE );pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE);pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2 );pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE );pd3dDevice->SetFVF(DXUT_SCREEN_VERTEX_UNTEX::FVF);pd3dDevice->DrawPrimitiveUP(D3DPT_POINTLIST, i, pVertices, sizeof(SCREEN_VERTEX_UNTEX));pd3dDevice->DrawPrimitiveUP(D3DPT_LINELIST, 4, lineVertices, sizeof(SCREEN_VERTEX_UNTEX));delete [] pVertices;}
    在上面的两个函数中,每画一次就new一块内存,绘制完成后释放。性能不好,可以依据需要,预先申请一块足够大的内存供使用。加入程序中可能出现的圆的半径不超过200像素,那么可以预先分配容纳2*D3DX_PI*200个SCREEN_VERTEX_UNTEX结构的内存。