Pull to refresh

Использование Direct3D совместно с Qt

Reading time 7 min
Views 7.2K
Однажды, у меня появилась необходимость использования Direct3D совместно с Qt. После нескольких дней поисков в интернете, я нашел всего лишь какие-то обрывки информации. Полноценного описания механизма использования Direct3D не было нигде. В результате, после долгих изысканий я добился того, чего хотел:)
Под катом находится инструкция «сближения“ Direct3D и Qt, а так же код виджета, который можно использовать as is

При написании данной статьи использовались следующие средства:
  1. Qt 4.5.0
  2. VS2008 SP1
  3. DirectX SDK August 2008

Если Вы используете другую. IDE, то момент сборки будет несколько отличаться. Я привожу пример сборки, только для VS2008. Если вы уверены, что в вашей сборке присутствует поддержка direct3d engine, тогда пропустите шаг конфигурирования и сборки Qt.

Конфигурирование и сборка Qt


  • Первым шагом необходимо настроить переменные окружения для DirectX, для этого в консоли выполняем следующую команду:
    > "%DXSDK_DIR%\Utilities\Bin\dx_setenv.cmd“

  • Переходим в каталог Qt и конфигурируем его. В моем случае это выглядело так > configure -direct3d -platform win32-msvc2008
    -direct3d можно опустить, этот параметр должен быть вычислен конфигуратором.
    Если все прошло нормально, то в появившемся выводе конфигуратора будет: Direct3D support…yes

  • Делаем nmake, и если не будет проблем то дожидаемся конца сборки. Я столкнулся с проблемой, при сборке была ошибка unresolved external связанная с Direct3D. Чтобы ее исправить, идем в %QTDIR%\src\gui\ и в обоих Makefile’ах(release и debug) меняем dxguid.lib на "%DXSDK_DIR%\Lib\x86\dxguid.lib»(или x64 в зависимости от того, под какую платформу вы собираете). После этого проблема должна исчезнуть так что дожидаемся окончания сборки.

Код виджета


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




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




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




Результатом выполнения это кода будет вот такое окно(если его растянуть):
image

Казалось бы теперь есть все, чтобы спокойно использовать direct3d с отличным фреймворком Qt, но, к сожалению, мною были обнаружены некоторые подводные камни.
После того, как я стал использовать Direct3d, на некоторых компьютерах, вместо картинки отрисованной Direct3d был экран, зарисованный цветом фона. Я перебрал все комбинации аттрибутов, но убрать данный дефект так и не смог. Так же не удалось выявить причину неправильной работы direct3d engine на некоторых машинах. Т.к документация по Qt утверждает, что «This functionality is experimental.», то можно предположить, что дело в сыроватости поддержки direct3d.

Но, данный недостаток не может быть причиной не использования Direct3D:). Пока trolltech допиливает direct3d до stable state можно воспользоваться следующим workaround’ом:
Закомментируем вызов Rendering () в paintEvent:
  1. void Direct3DWidget::paintEvent(QPaintEvent *pEvent)
  2. {
  3.         Q_UNUSED(pEvent);
  4.         //Rendering();
  5. }



и в место использования добавим следующий код:

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



я добавил этот код в код примера, приведенного мною выше.
Так же не забудьте включить заголовок QTimer

Приятного Вам использования Direct3d API в Qt, и не забывайте, что приложение, должно быть запущено с опцией -direct3d, я включил эту опцию в код моего примера использования.
Tags:
Hubs:
+12
Comments 10
Comments Comments 10

Articles