Hello World / plɹoM ollǝH

Programmers Live in Vain

PySideでDirectXウインドウを表示してみる

f:id:dungeonneko:20150607133330p:plain ↑PySideで表示したWindowにDirectXの画面を表示しています。

C++
  1. pyd用のプロジェクトを作成
  2. DirectXのTutorialをコピペしてInitWindow、WinProcなどの不要な関数を削除
  3. InitDeviceでウインドウハンドルを受け取るように変更
  4. boost::pythonを使ってDirectXの処理をpythonに公開する
#define BOOST_PYTHON_STATIC_LIB
#include <boost/python.hpp>
#include <d3d11_1.h>
#include <d3dcompiler.h>
#include <directxmath.h>
#include <directxcolors.h>

HRESULT InitDevice(PyObject* hwnd, int width, int height);
void CleanupDevice();
void Render();

/* コード長いので省略 */

BOOST_PYTHON_MODULE(pydx)
{
    boost::python::def("InitDevice", &InitDevice);
    boost::python::def("CleanupDevice", &CleanupDevice);
    boost::python::def("Render", &Render);
}
Python

PySideを使ってGUIを作成する。paint系の関数をオーバーライドしてDirectXのRenderが呼ばれるようにしてあげる。

# conding: utf-8
import sys
from PySide.QtCore import *
from PySide.QtGui import *
import pydx

# dx view
class View(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setAttribute(Qt.WA_PaintOnScreen)
        self.setAttribute(Qt.WA_NoSystemBackground)
        self.setAttribute(Qt.WA_OpaquePaintEvent)
        pydx.InitDevice(self.winId(), parent.width(), parent.height())

    def __del__(self):
        pydx.CleanupDevice()

    def _render(self):
        pydx.Render()
        self.update()

    # override methods
    def paintEngine(self, *args):
        return None
    def paintEvent(self, *args):
        self._render()
    def render(self, *args):
        self._render()
    def repaint(self, *args):
        self._render()

myapp = QApplication(sys.argv)
wnd = QMainWindow()
wnd.resize(640, 480)
wnd.setCentralWidget(View(wnd))
wnd.show()
wnd.setWindowTitle('pydx')
sys.exit(myapp.exec_())
注意点

QWidgetのwinIdがPyCObjectを返すのでHWNDに変換してあげる必要があった。

g_hWnd = HWND(PyCapsule_GetPointer(hwnd, NULL));

リサイズ処理してないのでレンダリング解像度は固定。