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も追加してみてください。