SDL_WINDOWIDでOpenGLが動いた
いったんwxWidgets+wxGLCanvasを使うことにしたのだが、
今度はLinuxのwxGTK側でSegmentationFault発生。
じつは、うちのGentooでは動かないことが発覚した。
再考した結果、
SDL_WINDOWIDがWindowsでうまくいかないところを追求する方向に転進。
SDLのソースを入手して、
デバッグ版を作ってVCのデバッガで丹念に死亡箇所を追跡してみることにした。
死亡寸前に通るところはここ。
src/video/windib/SDL_dibevents.c:240行〜
default: { /* Only post the event if we're watching for it */ if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) { SDL_SysWMmsg wmmsg; SDL_VERSION(&wmmsg.version); wmmsg.hwnd = hwnd; wmmsg.msg = msg; wmmsg.wParam = wParam; wmmsg.lParam = lParam; posted = SDL_PrivateSysWMEvent(&wmmsg); /* DJM: If the user isn't watching for private messages in her SDL event loop, then pass it along to any win32 specific window proc. */ } else if (userWindowProc) { return CallWindowProc(userWindowProc, hwnd, msg, wParam, lParam); }
SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE
がfalseなので
return CallWindowProc(userWindowProc, hwnd, msg, wParam, lParam);
を通るが、この中で死ぬ。
でここでコールしているのはGtk::Socketが元々もっていたWindowプロシージャ
でSDLが知らないイベントが来たので元のプロシージャに渡すという動作を
しておりました。
そこで、
SDL_PrivateSysWMEventが何をしているのかは知らないが
SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE
をtrueにしてやればいいじゃないのとなり、
それは
SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
とすることでできた。
gtkmm+SDLをVCでコンパイルするというあまり需要なさそうな構成ですが
修正版のソースコード。
#include <gtkmm.h> #include <gtkmm/socket.h> #ifdef _MSC_VER #include <gdk/gdkwin32.h> #include <glib.h> #endif #include <SDL.h> #ifdef USE_OPENGL #include <SDL_opengl.h> #endif #include <sstream> #include <iostream> #include <cassert> #define WIDTH 320 #define HEIGHT 200 //------------------------------------------------------------// // use Gtk socket // // http://sdl.beuc.net/sdl.wiki/FAQ_GUI // // base from // http://lists.libsdl.org/pipermail/sdl-libsdl.org/2007-October/062896.html // http://www.devolution.com/pipermail/sdl/2005-August/069884.html //------------------------------------------------------------// class GTKSDL : public Gtk::Socket { SDL_Surface *surface_; public: GTKSDL() : surface_(NULL) { } ~GTKSDL() { if (surface_) SDL_FreeSurface(surface_); SDL_Quit(); } bool draw() { if(!surface_){ if(!initialize_()){ return true; } } assert(surface_); // SDL draw loop SDL_Event event; while ( SDL_PollEvent( &event ) ) { // Handle quit event, not sure if this will ever appear if ( event.type == SDL_QUIT ){ return false; } // Handle draw rect userevent if ( event.type == SDL_USEREVENT && event.user.code == 1 ) { #ifdef USE_OPENGL static float t=0; const int N = 500; // 頂点の数 const float PI = 3.141593f; // 円周率 glClear(GL_COLOR_BUFFER_BIT); glBegin(GL_LINE_LOOP); glColor3f(1.0f, 1.0f, 1.0f); for (int i = 0; i < N; ++i) { glVertex3f(300*cos(3*2*PI*i/N + t) + 320, 220*sin(5*2*PI*i/N - PI/4 + t) + 240, 0.0); } glEnd(); // 更新を画面に反映する SDL_GL_SwapBuffers(); t+=0.01f; #else // draw rect SDL_Rect rect; rect.x = rand() % WIDTH; rect.y = rand() % HEIGHT; rect.w = rand() % 100 + 10; rect.h = rand() % 100 + 10; SDL_FillRect(surface_, &rect, SDL_MapRGB(surface_->format, rand()%255, rand()%255, rand()%255 ) ); SDL_Flip(surface_); #endif } } // Forzar a que se dibuje un cuadrado nuevo event.type = SDL_USEREVENT; event.user.code = 1; SDL_PushEvent( &event ); return true; } private: // SDL_WINDOWID hack //------------------------------------------------------------// bool initialize_() { std::stringstream sdlhack; #ifdef _MSC_VER HWND hwnd= static_cast<HWND>(GDK_WINDOW_HWND(get_window()->gobj())); sdlhack << "SDL_WINDOWID=" << (long)hwnd << std::ends; //SDL_putenv("SDL_VIDEODRIVER=windib"); #else sdlhack << "SDL_WINDOWID=" << get_id() << std::ends; #endif char windowid[128]; sprintf(windowid, "%s", sdlhack.str().c_str()); SDL_putenv(windowid); if (SDL_Init(SDL_INIT_VIDEO)){ return false; } #ifdef USE_OPENGL #ifdef _MSC_VER // skip Gtk::Socket window procedure SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE); #endif SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); surface_ = SDL_SetVideoMode( WIDTH, HEIGHT, 0, SDL_OPENGL); #else surface_ = SDL_SetVideoMode( WIDTH, HEIGHT, 0, SDL_HWSURFACE|SDL_DOUBLEBUF); #endif if(!surface_){ return false; } #ifdef USE_OPENGL glClearColor(1.0f, 0.5f, 0.0f, 0.0f); glOrtho(0.0, WIDTH, HEIGHT, 0.0, -1.0, 1.0); #endif return true; } }; //------------------------------------------------------------// // TopWindow //------------------------------------------------------------// class TopWindow : public Gtk::Window { GTKSDL sdl_; Gtk::VBox vbox_; public: TopWindow() { set_title("Ventana SDL"); sdl_.set_size_request(WIDTH, HEIGHT); set_border_width(6); vbox_.pack_start(sdl_, false, false); add(vbox_); show_all(); // SDL draw / 5 msec Glib::signal_timeout().connect( sigc::mem_fun(sdl_ ,>KSDL::draw), 5); } }; void siginthandler(int signum) { std::cerr << "SIGINT!\n"; Gtk::Main::quit(); } //------------------------------------------------------------// int main(int argc, char ** argv) { #ifndef _MSC_VER signal(SIGINT, siginthandler); #endif Gtk::Main kit(argc, argv); TopWindow window; Gtk::Main::run(window); return 0; }
gentooとWindows XPで動作確認。
似たようなところに潜っていた
http://risky-safety.org/zinnia/sdl/sourcetour/no4/index.html
ビルド環境参考
premake.lua
project.name = "solution" -- ソリューション名になる project.configs = { "Debug", "Release" } -- コンフィグの種類を定義 project.config["Debug"].bindir = "debug" -- デバッグ実行ファイルの出力先 project.config["Debug"].libdir = "debug" -- デバッグライブラリの出力先 project.config["Release"].bindir = "release" -- リリース実行ファイルの出力先 project.config["Release"].libdir = "release" -- リリースライブラリの出力先 -- inline package package = newpackage() package.name = "sample" -- パッケージ名 package.kind = "winexe" -- 種類 package.language = "c++" -- 言語 package.target = "sample" -- 出力ファイル(拡張子やlib無し) package.config["Debug"].defines={"DEBUG"} package.config["Release"].defines={"NDEBUG"} package.config["Release"].buildflags={"optimize"} -- ソースとヘッダ package.files = { matchfiles("*.cpp", "*.h", "*.def"), } package.defines={ "USE_OPENGL" } if(windows)then package.buildoptions={ "/wd4250", "/wd4520", "/wd4819" } package.buildflags={ "no-main" } package.includepaths={ "F:/gtkmm/include/gtkmm-2.4", "F:/gtkmm/lib/gtkmm-2.4/include", "F:/gtkmm/include/glibmm-2.4", "F:/gtkmm/lib/glibmm-2.4/include", "F:/gtkmm/include/sigc++-2.0", "F:/gtkmm/lib/sigc++-2.0/include", "F:/gtkmm/include/gdkmm-2.4", "F:/gtkmm/lib/gdkmm-2.4/include", "F:/gtkmm/include/pangomm-1.4", "F:/gtkmm/include/cairomm-1.0", "F:/gtkmm/include/atkmm-1.6", "F:/gtkmm/include/giomm-2.4", "F:/gtkmm/include/glib-2.0", "F:/gtkmm/include/gtk-2.0", "F:/gtkmm/include/pango-1.0", "F:/gtkmm/include/cairo", "F:/gtkmm/include/atk-1.0", "F:/gtkmm/lib/glib-2.0/include", "F:/gtkmm/lib/gtk-2.0/include", "F:/SDL/include", } package.libpaths={ "F:/gtkmm/lib", "H:/Program Files/Microsoft Platform SDK/Lib", } package.config["Release"].libpaths={ "F:/SDL/lib", } package.config["Debug"].libpaths={ "F:/SDL/debug", } package.links={ "SDL", "SDLmain", "gdk-win32-2.0", "gtk-win32-2.0", "opengl32" } package.config["Debug"].links={ "gtkmm-vc90-d-2_4", "sigc-vc90-d-2_0", "glibmm-vc90-d-2_4", "atkmm-vc90-d-1_6", "gdkmm-vc90-d-2_4" } package.config["Release"].links={ "gtkmm-vc90-2_4", "sigc-vc90-2_0", "glibmm-vc90-2_4", "atkmm-vc90-1_6", "gdkmm-vc90-2_4" } else tinsert(package.buildoptions, { "`pkg-config --cflags gtkmm-2.4`", "`pkg-config --cflags sdl`" }) tinsert(package.config["Debug"].buildoptions, { "-g", "-Wall" }) tinsert(package.linkoptions, { "`pkg-config --libs gtkmm-2.4`", "`pkg-config --libs sdl`" }) tinsert(package.config["Debug"].linkoptions, { "-g", "-Wall" }) end