⬆️ ⬇️

Using Direct3D with Qt

One day, I had the need to use Direct3D with Qt. After several days of searching the Internet, I found just some scraps of information. There was no complete description of the mechanism for using Direct3D anywhere. As a result, after much research, I achieved what I wanted :)

Under the cat there is an instruction “approaching“ Direct3D and Qt, as well as a widget code that can be used as is



When writing this article, the following tools were used:

  1. Qt 4.5.0
  2. VS2008 SP1
  3. DirectX SDK August 2008


If you use another. IDE, the assembly time will be slightly different. I give an example of the assembly, only for VS2008. If you are sure that your build has direct3d engine support, then skip the Qt configuration and build step.



Qt configuration and build





Widget code



Direct3DWidget.h

  1. #ifndef DIRECT3DWIDGET_H #define DIRECT3DWIDGET_H #include <QtGui/QWidget> #include <d3d9.h> #include <atlbase.h> class Direct3DWidget : public QWidget { Q_OBJECT CComPtr < IDirect3D9 > m_pD3D ; CComPtr < IDirect3DDevice9 > m_pd3dDevice ; public : Direct3DWidget ( QWidget * parent = 0 ) ; ~Direct3DWidget ( ) ; bool InitDirect3D ( ) ; public slots : bool Rendering ( ) ; private : void paintEvent ( QPaintEvent * pEvent ) ; } ; #endif
  2. #ifndef DIRECT3DWIDGET_H #define DIRECT3DWIDGET_H #include <QtGui/QWidget> #include <d3d9.h> #include <atlbase.h> class Direct3DWidget : public QWidget { Q_OBJECT CComPtr < IDirect3D9 > m_pD3D ; CComPtr < IDirect3DDevice9 > m_pd3dDevice ; public : Direct3DWidget ( QWidget * parent = 0 ) ; ~Direct3DWidget ( ) ; bool InitDirect3D ( ) ; public slots : bool Rendering ( ) ; private : void paintEvent ( QPaintEvent * pEvent ) ; } ; #endif
  3. #ifndef DIRECT3DWIDGET_H #define DIRECT3DWIDGET_H #include <QtGui/QWidget> #include <d3d9.h> #include <atlbase.h> class Direct3DWidget : public QWidget { Q_OBJECT CComPtr < IDirect3D9 > m_pD3D ; CComPtr < IDirect3DDevice9 > m_pd3dDevice ; public : Direct3DWidget ( QWidget * parent = 0 ) ; ~Direct3DWidget ( ) ; bool InitDirect3D ( ) ; public slots : bool Rendering ( ) ; private : void paintEvent ( QPaintEvent * pEvent ) ; } ; #endif
  4. #ifndef DIRECT3DWIDGET_H #define DIRECT3DWIDGET_H #include <QtGui/QWidget> #include <d3d9.h> #include <atlbase.h> class Direct3DWidget : public QWidget { Q_OBJECT CComPtr < IDirect3D9 > m_pD3D ; CComPtr < IDirect3DDevice9 > m_pd3dDevice ; public : Direct3DWidget ( QWidget * parent = 0 ) ; ~Direct3DWidget ( ) ; bool InitDirect3D ( ) ; public slots : bool Rendering ( ) ; private : void paintEvent ( QPaintEvent * pEvent ) ; } ; #endif
  5. #ifndef DIRECT3DWIDGET_H #define DIRECT3DWIDGET_H #include <QtGui/QWidget> #include <d3d9.h> #include <atlbase.h> class Direct3DWidget : public QWidget { Q_OBJECT CComPtr < IDirect3D9 > m_pD3D ; CComPtr < IDirect3DDevice9 > m_pd3dDevice ; public : Direct3DWidget ( QWidget * parent = 0 ) ; ~Direct3DWidget ( ) ; bool InitDirect3D ( ) ; public slots : bool Rendering ( ) ; private : void paintEvent ( QPaintEvent * pEvent ) ; } ; #endif
  6. #ifndef DIRECT3DWIDGET_H #define DIRECT3DWIDGET_H #include <QtGui/QWidget> #include <d3d9.h> #include <atlbase.h> class Direct3DWidget : public QWidget { Q_OBJECT CComPtr < IDirect3D9 > m_pD3D ; CComPtr < IDirect3DDevice9 > m_pd3dDevice ; public : Direct3DWidget ( QWidget * parent = 0 ) ; ~Direct3DWidget ( ) ; bool InitDirect3D ( ) ; public slots : bool Rendering ( ) ; private : void paintEvent ( QPaintEvent * pEvent ) ; } ; #endif
  7. #ifndef DIRECT3DWIDGET_H #define DIRECT3DWIDGET_H #include <QtGui/QWidget> #include <d3d9.h> #include <atlbase.h> class Direct3DWidget : public QWidget { Q_OBJECT CComPtr < IDirect3D9 > m_pD3D ; CComPtr < IDirect3DDevice9 > m_pd3dDevice ; public : Direct3DWidget ( QWidget * parent = 0 ) ; ~Direct3DWidget ( ) ; bool InitDirect3D ( ) ; public slots : bool Rendering ( ) ; private : void paintEvent ( QPaintEvent * pEvent ) ; } ; #endif
  8. #ifndef DIRECT3DWIDGET_H #define DIRECT3DWIDGET_H #include <QtGui/QWidget> #include <d3d9.h> #include <atlbase.h> class Direct3DWidget : public QWidget { Q_OBJECT CComPtr < IDirect3D9 > m_pD3D ; CComPtr < IDirect3DDevice9 > m_pd3dDevice ; public : Direct3DWidget ( QWidget * parent = 0 ) ; ~Direct3DWidget ( ) ; bool InitDirect3D ( ) ; public slots : bool Rendering ( ) ; private : void paintEvent ( QPaintEvent * pEvent ) ; } ; #endif
  9. #ifndef DIRECT3DWIDGET_H #define DIRECT3DWIDGET_H #include <QtGui/QWidget> #include <d3d9.h> #include <atlbase.h> class Direct3DWidget : public QWidget { Q_OBJECT CComPtr < IDirect3D9 > m_pD3D ; CComPtr < IDirect3DDevice9 > m_pd3dDevice ; public : Direct3DWidget ( QWidget * parent = 0 ) ; ~Direct3DWidget ( ) ; bool InitDirect3D ( ) ; public slots : bool Rendering ( ) ; private : void paintEvent ( QPaintEvent * pEvent ) ; } ; #endif
  10. #ifndef DIRECT3DWIDGET_H #define DIRECT3DWIDGET_H #include <QtGui/QWidget> #include <d3d9.h> #include <atlbase.h> class Direct3DWidget : public QWidget { Q_OBJECT CComPtr < IDirect3D9 > m_pD3D ; CComPtr < IDirect3DDevice9 > m_pd3dDevice ; public : Direct3DWidget ( QWidget * parent = 0 ) ; ~Direct3DWidget ( ) ; bool InitDirect3D ( ) ; public slots : bool Rendering ( ) ; private : void paintEvent ( QPaintEvent * pEvent ) ; } ; #endif
  11. #ifndef DIRECT3DWIDGET_H #define DIRECT3DWIDGET_H #include <QtGui/QWidget> #include <d3d9.h> #include <atlbase.h> class Direct3DWidget : public QWidget { Q_OBJECT CComPtr < IDirect3D9 > m_pD3D ; CComPtr < IDirect3DDevice9 > m_pd3dDevice ; public : Direct3DWidget ( QWidget * parent = 0 ) ; ~Direct3DWidget ( ) ; bool InitDirect3D ( ) ; public slots : bool Rendering ( ) ; private : void paintEvent ( QPaintEvent * pEvent ) ; } ; #endif
  12. #ifndef DIRECT3DWIDGET_H #define DIRECT3DWIDGET_H #include <QtGui/QWidget> #include <d3d9.h> #include <atlbase.h> class Direct3DWidget : public QWidget { Q_OBJECT CComPtr < IDirect3D9 > m_pD3D ; CComPtr < IDirect3DDevice9 > m_pd3dDevice ; public : Direct3DWidget ( QWidget * parent = 0 ) ; ~Direct3DWidget ( ) ; bool InitDirect3D ( ) ; public slots : bool Rendering ( ) ; private : void paintEvent ( QPaintEvent * pEvent ) ; } ; #endif
  13. #ifndef DIRECT3DWIDGET_H #define DIRECT3DWIDGET_H #include <QtGui/QWidget> #include <d3d9.h> #include <atlbase.h> class Direct3DWidget : public QWidget { Q_OBJECT CComPtr < IDirect3D9 > m_pD3D ; CComPtr < IDirect3DDevice9 > m_pd3dDevice ; public : Direct3DWidget ( QWidget * parent = 0 ) ; ~Direct3DWidget ( ) ; bool InitDirect3D ( ) ; public slots : bool Rendering ( ) ; private : void paintEvent ( QPaintEvent * pEvent ) ; } ; #endif
  14. #ifndef DIRECT3DWIDGET_H #define DIRECT3DWIDGET_H #include <QtGui/QWidget> #include <d3d9.h> #include <atlbase.h> class Direct3DWidget : public QWidget { Q_OBJECT CComPtr < IDirect3D9 > m_pD3D ; CComPtr < IDirect3DDevice9 > m_pd3dDevice ; public : Direct3DWidget ( QWidget * parent = 0 ) ; ~Direct3DWidget ( ) ; bool InitDirect3D ( ) ; public slots : bool Rendering ( ) ; private : void paintEvent ( QPaintEvent * pEvent ) ; } ; #endif
  15. #ifndef DIRECT3DWIDGET_H #define DIRECT3DWIDGET_H #include <QtGui/QWidget> #include <d3d9.h> #include <atlbase.h> class Direct3DWidget : public QWidget { Q_OBJECT CComPtr < IDirect3D9 > m_pD3D ; CComPtr < IDirect3DDevice9 > m_pd3dDevice ; public : Direct3DWidget ( QWidget * parent = 0 ) ; ~Direct3DWidget ( ) ; bool InitDirect3D ( ) ; public slots : bool Rendering ( ) ; private : void paintEvent ( QPaintEvent * pEvent ) ; } ; #endif
  16. #ifndef DIRECT3DWIDGET_H #define DIRECT3DWIDGET_H #include <QtGui/QWidget> #include <d3d9.h> #include <atlbase.h> class Direct3DWidget : public QWidget { Q_OBJECT CComPtr < IDirect3D9 > m_pD3D ; CComPtr < IDirect3DDevice9 > m_pd3dDevice ; public : Direct3DWidget ( QWidget * parent = 0 ) ; ~Direct3DWidget ( ) ; bool InitDirect3D ( ) ; public slots : bool Rendering ( ) ; private : void paintEvent ( QPaintEvent * pEvent ) ; } ; #endif
  17. #ifndef DIRECT3DWIDGET_H #define DIRECT3DWIDGET_H #include <QtGui/QWidget> #include <d3d9.h> #include <atlbase.h> class Direct3DWidget : public QWidget { Q_OBJECT CComPtr < IDirect3D9 > m_pD3D ; CComPtr < IDirect3DDevice9 > m_pd3dDevice ; public : Direct3DWidget ( QWidget * parent = 0 ) ; ~Direct3DWidget ( ) ; bool InitDirect3D ( ) ; public slots : bool Rendering ( ) ; private : void paintEvent ( QPaintEvent * pEvent ) ; } ; #endif
  18. #ifndef DIRECT3DWIDGET_H #define DIRECT3DWIDGET_H #include <QtGui/QWidget> #include <d3d9.h> #include <atlbase.h> class Direct3DWidget : public QWidget { Q_OBJECT CComPtr < IDirect3D9 > m_pD3D ; CComPtr < IDirect3DDevice9 > m_pd3dDevice ; public : Direct3DWidget ( QWidget * parent = 0 ) ; ~Direct3DWidget ( ) ; bool InitDirect3D ( ) ; public slots : bool Rendering ( ) ; private : void paintEvent ( QPaintEvent * pEvent ) ; } ; #endif
  19. #ifndef DIRECT3DWIDGET_H #define DIRECT3DWIDGET_H #include <QtGui/QWidget> #include <d3d9.h> #include <atlbase.h> class Direct3DWidget : public QWidget { Q_OBJECT CComPtr < IDirect3D9 > m_pD3D ; CComPtr < IDirect3DDevice9 > m_pd3dDevice ; public : Direct3DWidget ( QWidget * parent = 0 ) ; ~Direct3DWidget ( ) ; bool InitDirect3D ( ) ; public slots : bool Rendering ( ) ; private : void paintEvent ( QPaintEvent * pEvent ) ; } ; #endif
  20. #ifndef DIRECT3DWIDGET_H #define DIRECT3DWIDGET_H #include <QtGui/QWidget> #include <d3d9.h> #include <atlbase.h> class Direct3DWidget : public QWidget { Q_OBJECT CComPtr < IDirect3D9 > m_pD3D ; CComPtr < IDirect3DDevice9 > m_pd3dDevice ; public : Direct3DWidget ( QWidget * parent = 0 ) ; ~Direct3DWidget ( ) ; bool InitDirect3D ( ) ; public slots : bool Rendering ( ) ; private : void paintEvent ( QPaintEvent * pEvent ) ; } ; #endif


')





Direct3DWidget.cpp

  1. #include "Direct3DWidget.h"
  2. Direct3DWidget :: Direct3DWidget ( QWidget * parent / * = 0 * / ) : QWidget ( parent )
  3. {
  4. setAttribute ( Qt :: WA_PaintOnScreen ) ;
  5. }
  6. Direct3DWidget :: ~ Direct3DWidget ( )
  7. {
  8. }
  9. bool Direct3DWidget :: InitDirect3D ( )
  10. {
  11. m_pD3D = Direct3DCreate9 ( D3D_SDK_VERSION ) ;
  12. if ( ! m_pD3D )
  13. return false ;
  14. D3DPRESENT_PARAMETERS d3dpp = { 0 } ;
  15. d3dpp. Windowed = TRUE ;
  16. d3dpp. SwapEffect = D3DSWAPEFFECT_DISCARD ;
  17. d3dpp. BackBufferFormat = D3DFMT_UNKNOWN ;
  18. d3dpp. FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT ;
  19. d3dpp. PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE ;
  20. d3dpp. SwapEffect = D3DSWAPEFFECT_DISCARD ;
  21. d3dpp. EnableAutoDepthStencil = TRUE ;
  22. d3dpp. AutoDepthStencilFormat = D3DFMT_D16 ;
  23. HRESULT hrResult = m_pD3D -> CreateDevice ( D3DADAPTER_DEFAULT , D3DDEVTYPE_HAL , winId ( ) ,
  24. D3DCREATE_HARDWARE_VERTEXPROCESSING ,
  25. & d3dpp , & m_pd3dDevice ) ;
  26. if ( FAILED ( hrResult ) )
  27. return false ;
  28. return true ;
  29. }
  30. bool Direct3DWidget :: Rendering ( )
  31. {
  32. if ( m_pd3dDevice == 0 )
  33. return false ;
  34. m_pd3dDevice -> Clear ( 0 , 0 , D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER , D3DCOLOR_XRGB ( 255 , 255 , 0 ) , 1.0f , 0 ) ;
  35. if ( SUCCEEDED ( m_pd3dDevice -> BeginScene ( ) ) )
  36. {
  37. m_pd3dDevice -> EndScene ( ) ;
  38. }
  39. m_pd3dDevice -> Present ( 0 , 0 , 0 , 0 ) ;
  40. return true ;
  41. }
  42. void Direct3DWidget :: paintEvent ( QPaintEvent * pEvent )
  43. {
  44. Q_UNUSED ( pEvent ) ;
  45. Rendering ( ) ;
  46. }








Example of use:

  1. #include <QtGui / QWidget>
  2. #include <QtGui / QApplication>
  3. #include <QtGui / QHBoxLayout>
  4. #include "Direct3DWidget.h"
  5. int main ( int argc , char * argv [ ] )
  6. {
  7. // ------------------------------ Start initialization
  8. // Additional parameters, just add a parameter separated by comma
  9. std :: string aAdditionalParameters [ ] = { "-direct3d" } ;
  10. int iRealArgumentAmount = argc + sizeof ( aAdditionalParameters ) / sizeof ( std :: string ) ;
  11. // This double pointer will contain parameters from argv and
  12. // statical parameters which necessary for this application
  13. char ** pArguments = new char * [ iRealArgumentAmount ] ;
  14. // Copy all source (from the command line) parameters
  15. for ( int i = 0 ; i < argc ; ++ i )
  16. {
  17. * ( pArguments + i ) = new char [ strlen ( argv [ i ] ) + 1 ] ;
  18. strcpy ( * ( pArguments + i ) , argv [ i ] ) ;
  19. }
  20. // Append parameters we want to add
  21. for ( int i = argc , j = 0 ; i < iRealArgumentAmount ; ++ i , ++ j )
  22. {
  23. * ( pArguments + i ) = new char [ aAdditionalParameters [ j ] . size ( ) + 1 ] ;
  24. strcpy ( * ( pArguments + i ) , aAdditionalParameters [ j ] . c_str ( ) ) ;
  25. }
  26. QApplication xApplication ( iRealArgumentAmount , pArguments ) ;
  27. for ( int i = 0 ; i < iRealArgumentAmount ; ++ i )
  28. delete [ ] * ( pArguments + i ) ;
  29. delete [ ] pArguments ;
  30. // -------------------------------- Initialization complete
  31. QWidget xMainWindow ;
  32. Direct3DWidget * xScene = new Direct3DWidget ( & xMainWindow ) ;
  33. QHBoxLayout * xMainLayout = new QHBoxLayout ;
  34. xMainLayout -> addWidget ( xScene ) ;
  35. xMainWindow. setLayout ( xMainLayout ) ;
  36. // It is important to get the Direct3d after the widget
  37. xScene -> InitDirect3D ( ) ;
  38. xMainWindow. show ( ) ;
  39. return xApplication. exec ( ) ;
  40. }








The result of the execution of this code will be such a window (if you stretch it):

image



It would seem that now there is everything to calmly use direct3d with an excellent Qt framework, but, unfortunately, I discovered some pitfalls.

After I started using Direct3d, on some computers, instead of the picture drawn by Direct3d, there was a screen, painted with the background color. I went through all combinations of attributes, but I could not remove this defect. It was also not possible to identify the cause of the incorrect operation of the direct3d engine on some machines. Because Qt documentation states that “ This functionality is experimental. , Then we can assume that the matter is in the dampness of support direct3d.



But, this disadvantage can not be a reason for not using Direct3D :). While trolltech finishes direct3d to a stable state, you can use the following workaround:

Comment out the Rendering () call in paintEvent:

  1. void Direct3DWidget :: paintEvent ( QPaintEvent * pEvent )
  2. {
  3. Q_UNUSED ( pEvent ) ;
  4. // Rendering ();
  5. }






and add the following code to the place of use:



  1. ...
  2. // It is important to get the Direct3d after the widget
  3. xScene -> InitDirect3D ( ) ;
  4. xMainWindow. show ( ) ;
  5. QTimer xTimer ;
  6. QWidget :: connect ( & xTimer , SIGNAL ( timeout ( ) ) , xScene , SLOT ( Rendering ( ) ) ) ;
  7. xTimer. start ( 100 ) ;
  8. return xApplication. exec ( ) ;
  9. ...






I added this code to the code of the example I gave above.

Don't forget to include the QTimer header.



Enjoy your use of Direct3d API in Qt, and do not forget that the application should be launched with the -direct3d option, I have included this option in the code of my usage example.

Source: https://habr.com/ru/post/62051/



All Articles