使用DirectX 9 在QtWidget中做圖,繪製在自定義的Widget中。html
經過繼承QWidget,而且重寫paintEngine函數,返回0,表示不使用QT默認的繪製引擎,使用自定義的繪製引擎。函數
經過設置屬性WA_PaintOnScreen,代表直接繪製到屏幕上,ui
經過設置屬性WA_OpaquePaintEvent,代表繪製時,重繪控件區域的全部像素this
經過設置屬性WA_NoSystemBackground,代表不須要QT默認的控件背景。.net
使用QTimer,定時重繪控件,便可實現幀更新效果,設計
自定義控件GDXWidget繼承自QWidget,頭文件代碼以下:3d
#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函數很簡單:code
#include "GQtDX9Dialog.h" #include <QtGui/QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); GQtDX9Dialog w; w.show(); return a.exec(); }
運行效果以下:orm