使用DirectX 9 在QtWidget中作图,绘制在自定义的Widget中。
通过继承QWidget,并且重写paintEngine函数,返回0,表示不使用QT默认的绘制引擎,使用自定义的绘制引擎。
通过设置属性WA_PaintOnScreen,表明直接绘制到屏幕上,
通过设置属性WA_OpaquePaintEvent,表明绘制时,重绘控件区域的所有像素
通过设置属性WA_NoSystemBackground,表明不需要QT默认的控件背景。
使用QTimer,定时重绘控件,即可实现帧更新效果,
自定义控件GDXWidget继承自QWidget,头文件代码如下:
#ifndef _GDXWIDGET_H_
#define _GDXWIDGET_H_
#include <QWidget>
#include <d3d9.h>
#include <d3dx9.h>
struct SCustomVertex
{
float x, y, z;
DWORD color;
};
#define D3DFVF_SCUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE)
class GDXWidget: public QWidget
{
Q_OBJECT
public:
GDXWidget(QWidget *parent = 0, Qt::WindowFlags f = 0);
~GDXWidget();
//不使用Qt默认的绘制引擎
virtual QPaintEngine* paintEngine() const { return 0; }
//初始化Direct3D
bool InitD3D();
//创建简单三角形
bool CreateTriangle();
//更新三角形
void Frame();
public slots:
//渲染
void Render();
protected:
virtual void paintEvent(QPaintEvent *event);
virtual void resizeEvent(QResizeEvent *event);
private:
LPDIRECT3D9 m_pD3D;
LPDIRECT3DDEVICE9 m_pDevice;
LPDIRECT3DVERTEXBUFFER9 m_pVB;
};
#endif //_GDXWIDGET_H_
CPP文件代码如下:
#include "GDXWidget.h"
#include "strsafe.h"
#include <QResizeEvent>
#include <QTimer>
GDXWidget::GDXWidget(QWidget *parent, Qt::WindowFlags f):
QWidget(parent, f), m_pD3D(0), m_pDevice(0), m_pVB(0)
{
//如果使用用户自定义绘制,则需要设置WA_PaintOnScreen
setAttribute(Qt::WA_PaintOnScreen, true);
//不需要默认的Qt背景
setAttribute(Qt::WA_NoSystemBackground, true);
//重绘时,绘制所有像素
setAttribute(Qt::WA_OpaquePaintEvent, true);
QTimer *pTimer = new QTimer(this);
connect(pTimer, SIGNAL(timeout()), this, SLOT(repaint()));
pTimer->start(16); //约60FPS
}
GDXWidget::~GDXWidget()
{
if(0 != m_pVB) m_pVB->Release();
if(0 != m_pDevice) m_pDevice->Release();
if(0 != m_pD3D) m_pD3D->Release();
}
void GDXWidget::paintEvent(QPaintEvent *event)
{
Render();
}
void GDXWidget::resizeEvent(QResizeEvent *event)
{}
bool GDXWidget::InitD3D()
{
if(0 == (m_pD3D = Direct3DCreate9(D3D_SDK_VERSION))) return false;
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
if(FAILED(m_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, winId(),
D3DCREATE_HARDWARE_VERTEXPROCESSING,
&d3dpp, &m_pDevice))) return false;
m_pDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
m_pDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
return true;
}
bool GDXWidget::CreateTriangle()
{
SCustomVertex vertices[] = {
{ -1.0f,-1.0f, 0.0f, 0xffff0000, },
{ 1.0f,-1.0f, 0.0f, 0xff0000ff, },
{ 0.0f, 1.0f, 0.0f, 0xffffffff, },
};
if(FAILED(m_pDevice->CreateVertexBuffer(3 * sizeof(SCustomVertex), 0, D3DFVF_SCUSTOMVERTEX,
D3DPOOL_DEFAULT, &m_pVB, 0))) return false;
void* pVertices;
if(FAILED(m_pVB->Lock(0, sizeof(vertices), (void**)&pVertices, 0))) return false;
memcpy(pVertices, vertices, sizeof(vertices));
m_pVB->Unlock();
return true;
}
void GDXWidget::Render()
{
m_pDevice->Clear(0, 0, D3DCLEAR_TARGET , D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
if(SUCCEEDED(m_pDevice->BeginScene())) {
Frame();
m_pDevice->SetStreamSource(0, m_pVB, 0, sizeof(SCustomVertex));
m_pDevice->SetFVF(D3DFVF_SCUSTOMVERTEX);
m_pDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);
m_pDevice->EndScene();
}
m_pDevice->Present(0, 0, 0, 0);
}
void GDXWidget::Frame()
{
D3DXMATRIXA16 matWorld;
UINT iTime = timeGetTime() % 1000;
FLOAT fAngle = iTime * ( 2.0f * D3DX_PI ) / 1000.0f;
D3DXMatrixRotationY( &matWorld, fAngle );
m_pDevice->SetTransform( D3DTS_WORLD, &matWorld );
D3DXVECTOR3 vEyePt( 0.0f, 3.0f,-5.0f );
D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f );
D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );
D3DXMATRIXA16 matView;
D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
m_pDevice->SetTransform( D3DTS_VIEW, &matView );
D3DXMATRIXA16 matProj;
D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI / 4, 1.0f, 1.0f, 100.0f );
m_pDevice->SetTransform( D3DTS_PROJECTION, &matProj );
}
然后通过Qt设计师,拉一个窗口框GQtDX9Dialog,将GDXWidget的一个实例放入该窗口即可。
CPP代码如下:
#include "GQtDX9Dialog.h"
#include "GDXWidget.h"
GQtDX9Dialog::GQtDX9Dialog(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
ui.setupUi(this);
resize(850, 650);
GDXWidget *pDXWidget = new GDXWidget(this);
pDXWidget->resize(800, 600);
pDXWidget->InitD3D();
pDXWidget->CreateTriangle();
pDXWidget->move(30, 30);
}
GQtDX9Dialog::~GQtDX9Dialog()
{}
而main函数很简单:
#include "GQtDX9Dialog.h"
#include <QtGui/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
GQtDX9Dialog w;
w.show();
return a.exec();
}
运行效果如下: