OpenGLをC++11でラップしてみんとてするなり 番外編:Qt5+OpenGLの落とし穴
先日、ひょんな事からglutで作ったライブラリをQt5に移植してみることになりました。
作業自体は大変なことではなく、glutのラッパーとして作った各種のクラス群を、QGLWidgetのラッパーとして作り変えてやるだけです。当然、理想的な設計がされたライブラリであれば、インスタンス化するウィンドウクラスを差し替えてやるだけで、他は一切弄らずとも今まで通り動いてくれることでしょう[1]。
……が。今回はそんなウィンドウクラスの作り方ではなく、Qt5でのOpenGLの使い方について。
Qt CreatorでOpenGLを使う
Qt CreatorでOpenGLを有効化するためには、まず、QtのOpenGLモジュールを利用できるよう設定せねばなりません。
まず、*.proファイルに以下の行を追加します。
QT += opengl
はい終わり。これで、QGLWidgetが使えるようになりました。
後は、QGLWidgetを継承して、initializeGL()やらpaintGL()やらresizeGL()やらを適切に設定してやれば十分です。glutDisplayFunc()等に渡していた関数を、これらのメンバー関数の中から呼び出してやれば、とりあえず表示だけはできるに違いありません。マウスとかキーボード関連は少々厄介ですが。
……そのはずが
ところが実際にビルドしてみると、壁に行き当たる場合があります。
QGLWidget::paintGL()中で以前作ったOpenGLのライブラリを呼び出すため、ヘッダーをインクルードした瞬間、唐突にerror: conflicting declaration 'typedef double GLdouble'とか言われます。
きっと、QtのOpenGLのインクルードとgl/OpenGL.hが競合してるんだろうなぁ、と思って全部Qtのに統一すると、今度は逆にいろいろ定義されてないと怒られる。
だいたいこの辺で、じゃあどうすればいいのかと途方にくれることとなるでしょう。
実は、Qtはデフォルトで、OpenGLではなくOpenGL ES 2.0を使っているようです。このため、OpenGL ESで定義したものとOpenGLで定義したものが競合し、上記のエラーとなっていました。
QtがターゲットとしているのはPCにとどまらず、Android等のモバイル環境も視野に入れています。モバイル環境ではOpenGLではなくサブセット[2]のOpenGL ESのみが実装されていることが多いため、QtではデフォルトでOpenGL ESを使うようになっているのでしょう。
Qtで、OpenGL ESを使わずOpenGLを使うためには、*.proに以下の一行を付け加えます。
QMAKE_CXXFLAGS += -DQT_NO_OPENGL_ES_2
この設定により、QtはOpenGL ESのインクルードを無効化し、OpenGLを利用するようになりました[3]。
※1 はい、もちろんそんな設計になどなっていませんでした……慌てて、そうなるように微調整。
※2 厳密には、OpenGL ESではglDepthRange()の代わりにglDepthRangef()を使うなど、微妙にOpenGLにはない関数があったりしますが。
※3 これでもダメなら、試しに-DQT_OPENGL_ESと-DQT_NO_OPENGL_ESも追加してみてください。