Qt中使用DirectX

使用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();
}

运行效果如下:

qtdx

猜你喜欢

转载自my.oschina.net/u/146803/blog/545822