#GLUT on FLTK のサンプルコードと落とし穴の解決
##1. GLUT+FLTKでteapotを描く
GLUTを使ったOpenGL描画とFLTKを組み合わせて使いたい。
ネットに色々と記事が転がっているが、それだと上手く行かない(Segmentation Faultが出る)という事態に遭遇したので対処法を残しておく。
##2.準備
Ubuntuでのfltk開発用ライブラリのインストール
$ sudo apt install libfltk1.3-dev
でOK。
##3.参考にしたコード
こちらやこちらで紹介されているサンプルコードを参考にさせていただきました。
##4.作成したサンプルコード
サンプルコード
#include <iostream>
#include <string>
//#include <GL/glut.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <FL/glut.H>
#include <FL/Fl.H>
#include <FL/Fl_Gl_Window.H>
#include <FL/Fl_Menu_Bar.H>
using namespace std;
const GLfloat MY_LIGHT0_POS[4] = { 2.0f, 4.0f, 1.0f, 0.0f };
const GLfloat MY_LIGHT_AMBI[4] = { 0.1f, 0.1f, 0.1f, 1.0f };
const GLfloat MY_LIGHT_DIFF[4] = { 0.9f, 0.9f, 0.9f, 1.0f };
const GLfloat MY_LIGHT_SPEC[4] = { 0.2f, 0.2f, 0.2f, 1.0f };
class myFlGLWindow : public Fl_Gl_Window
{
public:
// Constructor
myFlGLWindow(int x_, int y_, int w_, int h_, const char* l=0)
: Fl_Gl_Window(x_, y_, w_, h_, l) {
}
// Destructor
virtual ~myFlGLWindow() {
}
void InitGL(void)
{
cout << "OpenGL Ver. " << glGetString(GL_VERSION) << endl;
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glEnable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
// Light setting
glLightfv(GL_LIGHT0, GL_AMBIENT, MY_LIGHT_AMBI);
glLightfv(GL_LIGHT0, GL_DIFFUSE, MY_LIGHT_DIFF);
glLightfv(GL_LIGHT0, GL_SPECULAR, MY_LIGHT_SPEC);
glLightfv(GL_LIGHT0, GL_POSITION, MY_LIGHT0_POS);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);
glShadeModel(GL_SMOOTH);
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
}
void Resize(int w, int h)
{
cout << "Resize " << w << " x " << h << endl;
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, (float)w/(float)h, 0.2f, 1000.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0f, 0.0f, -5.0f);
}
// Drawing function here..
void Display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_LIGHTING);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
// glut function for drawing here
glColor3f(0.0, 0.0, 1.0);
glutSolidTeapot(1.0);
}
private:
// for redrawing event
void draw(void)
{
if(!context_valid()){
InitGL();
}
if(!valid()){
Resize(w(), h());
}
// OpenGL
Display();
}
};
int main(int argc, char *argv[])
{
Fl::scheme("gtk+");
Fl::visual(FL_DOUBLE | FL_RGB);
Fl::get_system_colors();
//glutInit(&argc, argv);
//glutCreateWindow("hoge");
Fl_Window *flwin = new Fl_Window(480,480,"hoge");
//myFlGLWindow *window = new myFlGLWindow(100, 100, 480, 480, "FLTK + GLUT TEST");
myFlGLWindow *window = new myFlGLWindow(10, 10, flwin->w()-20, flwin->h()-20);
flwin->resizable(window);
flwin->show();
return Fl::run();
}
これを
$ g++ -O3 sample.cpp -o sample -lfltk -lfltk_gl -lGLU -lGL
とすればコンパイルされるはず。実行すると下図のようにteapotが描画される。
##5.ハマった落とし穴
以下の点でかなりハマってしまった。
当初、冒頭のインクルードファイルの指定を
#include <GL/gl.h>
#include <GL/glut.h>
としていて問題なく動いていた。但し、このままではglutSolidTeapotを呼んだ時に「先にglutInitを呼んでおけ」とエラーが出るので、glutInit関数を呼ぶようにしていた(サンプルコード下の方のglutInit行のコメントアウトを外していた)。
※なお、fltkのサイトのマニュアルにはglutInitを呼ぶな、との指示があるので、いずれにせよこの方法は非推奨と思われる。
システムアップデートに伴い上記の対応ではsegmentation faultが出るように(何かがnull pointerになっている?)。glutInitの後にglutCreateWindowを呼ぶとセグフォは回避されるが、変な空ウインドウが出来ることになってしまう(下図、teapotが描かれているウィンドウの右側)。
暫くもがいた結果、インクルードファイルをGL/glut.hでなく
#include <FL/glut.H>
とすればセグフォが出ないことに気づいた。但し、これをするとなぜかglu関連の関数がないよと言われるので、これに加えて
#include <GL/glu.h>
も加える必要があった。その結果導きだした解が上記のサンプルコードである。