SDLでOpenGLを使う
OpenGL Exsample
VC++のプロジェクト作成
アプリケーションの設定
- アプリケーションの種類をWindowsアプリケーション
- 追加のオプションで、「空のプロジェクト」にチェック
プロジェクトにcppファイルを追加する
- ソリューションエクスプローラーのプロジェクトを右クリック⇒「新規追加」
ソースコードの入力
#include <SDL/SDL.h> #include <SDL/SDL_opengl.h> #include <gl/glu.h> #pragma comment(lib,"SDL.lib") #pragma comment(lib,"SDLmain.lib") #pragma comment(lib,"OpenGL32.Lib") #pragma comment(lib,"GlU32.Lib") //環境により適宜変更する //以下サンプルはこちらより拝借⇒http://zinnia.dyndns.org/~cvsweb/sdldoc-jp/guidevideoopengl.html#AEN192 static GLboolean should_rotate=GL_TRUE; static void draw_screen( void ); static void handle_key_down( SDL_keysym* keysym ); static void process_events( void ); static void quit_tutorial( int code ); static void setup_opengl( int width, int height ); static void quit_tutorial( int code ) { /* * SDL を終了してフルスクリーンモードを解放し、 * 以前のビデオ設定などを戻す。 */ SDL_Quit( ); /* プログラムを終了する。*/ exit( code ); } static void handle_key_down( SDL_keysym* keysym ) { /* * 興味があるのは 'ESC' が押された時だけ。 * * 練習: * 矢印キーを処理し、表示位置・角度を変更するようにせよ。 */ switch( keysym->sym ) { case SDLK_ESCAPE: quit_tutorial( 0 ); break; case SDLK_SPACE: should_rotate=!should_rotate; break; default: break; } } static void process_events( void ) { /* SDL イベントの置き場 */ SDL_Event event; /* すべてのイベントをキューからつかみ取る */ while( SDL_PollEvent( &event ) ) { switch( event.type ) { case SDL_KEYDOWN: /* キー押下を処理 */ handle_key_down( &event.key.keysym ); break; case SDL_QUIT: /* 終了要求 (Ctrl-c など) を処理 */ quit_tutorial( 0 ); break; } } } static void draw_screen( void ) { /* 回転角 */ static float angle=0.0f; /* * 練習: * このひどいごみを頂点配列で置き換え、 * glDrawElements を呼び出せ。 * * 練習: * 上を終えた後、コンパイルされた頂点配列に変更せよ。 * * 練習: * 私の螺旋形状が正しいことを確認せよ。;) */ static GLfloat v0[]={ -1.0f, -1.0f, 1.0f }; static GLfloat v1[]={ 1.0f, -1.0f, 1.0f }; static GLfloat v2[]={ 1.0f, 1.0f, 1.0f }; static GLfloat v3[]={ -1.0f, 1.0f, 1.0f }; static GLfloat v4[]={ -1.0f, -1.0f, -1.0f }; static GLfloat v5[]={ 1.0f, -1.0f, -1.0f }; static GLfloat v6[]={ 1.0f, 1.0f, -1.0f }; static GLfloat v7[]={ -1.0f, 1.0f, -1.0f }; static GLubyte red[] ={ 255, 0, 0, 255 }; static GLubyte green[]={ 0, 255, 0, 255 }; static GLubyte blue[] ={ 0, 0, 255, 255 }; static GLubyte white[]={ 255, 255, 255, 255 }; static GLubyte yellow[]={ 0, 255, 255, 255 }; static GLubyte black[]={ 0, 0, 0, 255 }; static GLubyte orange[]={ 255, 255, 0, 255 }; static GLubyte purple[]={ 255, 0, 255, 0 }; /* 色・デプスバッファを消去 */ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); /* 射影行列は変更したくない */ glMatrixMode( GL_MODELVIEW ); glLoadIdentity( ); /* z 軸の方向に下げる */ glTranslatef( 0.0, 0.0, -5.0 ); /* 回転 */ glRotatef( angle, 0.0, 1.0, 0.0 ); if( should_rotate ) { if( ++angle > 360.0f ) { angle=0.0f; } } /* 三角形データをパイプラインに送る */ glBegin( GL_TRIANGLES ); glColor4ubv( red ); glVertex3fv( v0 ); glColor4ubv( green ); glVertex3fv( v1 ); glColor4ubv( blue ); glVertex3fv( v2 ); glColor4ubv( red ); glVertex3fv( v0 ); glColor4ubv( blue ); glVertex3fv( v2 ); glColor4ubv( white ); glVertex3fv( v3 ); glColor4ubv( green ); glVertex3fv( v1 ); glColor4ubv( black ); glVertex3fv( v5 ); glColor4ubv( orange ); glVertex3fv( v6 ); glColor4ubv( green ); glVertex3fv( v1 ); glColor4ubv( orange ); glVertex3fv( v6 ); glColor4ubv( blue ); glVertex3fv( v2 ); glColor4ubv( black ); glVertex3fv( v5 ); glColor4ubv( yellow ); glVertex3fv( v4 ); glColor4ubv( purple ); glVertex3fv( v7 ); glColor4ubv( black ); glVertex3fv( v5 ); glColor4ubv( purple ); glVertex3fv( v7 ); glColor4ubv( orange ); glVertex3fv( v6 ); glColor4ubv( yellow ); glVertex3fv( v4 ); glColor4ubv( red ); glVertex3fv( v0 ); glColor4ubv( white ); glVertex3fv( v3 ); glColor4ubv( yellow ); glVertex3fv( v4 ); glColor4ubv( white ); glVertex3fv( v3 ); glColor4ubv( purple ); glVertex3fv( v7 ); glColor4ubv( white ); glVertex3fv( v3 ); glColor4ubv( blue ); glVertex3fv( v2 ); glColor4ubv( orange ); glVertex3fv( v6 ); glColor4ubv( white ); glVertex3fv( v3 ); glColor4ubv( orange ); glVertex3fv( v6 ); glColor4ubv( purple ); glVertex3fv( v7 ); glColor4ubv( green ); glVertex3fv( v1 ); glColor4ubv( red ); glVertex3fv( v0 ); glColor4ubv( yellow ); glVertex3fv( v4 ); glColor4ubv( green ); glVertex3fv( v1 ); glColor4ubv( yellow ); glVertex3fv( v4 ); glColor4ubv( black ); glVertex3fv( v5 ); glEnd( ); /* * 練習: * 'Spc' で回転停止、'Esc' で終了することを * ユーザーに教えるテキストを描画せよ。 * ベクターとテクスチャが貼られた四角形で行え。 */ /* * バッファを交換する。これはバックバッファからの * 次のフレームの描画と、 * フロントバッファであったものに起こる * すべての描画操作の設定をドライバに通知する。 * * ダブルバッファによって、 * 更新中の画面領域へアプリケーションが同時に描画することから起きる、 * 表示の乱れが防止される。 */ SDL_GL_SwapBuffers( ); } static void setup_opengl( int width, int height ) { float ratio=(float) width / (float) height; /* シェーディングモデルは Gouraud (なめらか) */ glShadeModel( GL_SMOOTH ); /* 裏面を取り除く */ glCullFace( GL_BACK ); glFrontFace( GL_CCW ); glEnable( GL_CULL_FACE ); /* 消去時の色をセット */ glClearColor( 0, 0, 0, 0 ); /* ビューポートを設定 */ glViewport( 0, 0, width, height ); /* * 射影行列を変更し、ビューボリュームにセット。 */ glMatrixMode( GL_PROJECTION ); glLoadIdentity( ); /* * 練習: * これを glFrustum の呼び出しに置き換えよ。 */ gluPerspective( 60.0, ratio, 1.0, 1024.0 ); } int main( int argc, char* argv[] ) { const SDL_VideoInfo* info=NULL; /* 現在のビデオ設定についての情報 */ int width=0; /* ウィンドウの寸法 */ int height=0; /* ウィンドウの色のピクセル深度 */ int bpp=0; /* SDL_SetVideoMode に渡すフラグ */ int flags=0; /* まず、SDL ビデオサブシステムを初期化 */ if( SDL_Init( SDL_INIT_VIDEO ) < 0 ) { /* 失敗したので終了 */ fprintf( stderr, "ビデオの初期化に失敗しました: %s\n", SDL_GetError( ) ); quit_tutorial( 1 ); } /* いくつかのビデオ情報を取得しよう */ info=SDL_GetVideoInfo( ); if( !info ) { /* おそらくこれは絶対に起きないはず */ fprintf( stderr, "ビデオの問い合わせに失敗しました: %s\n", SDL_GetError( ) ); quit_tutorial( 1 ); } /* * 横幅/高さを 640/480 にセット。 * (もちろん普通のアプリケーションにおいて * ユーザーにこれを決定してもらうだろう) * 画面から要求していたピクセル深度を取得。 * X11 では、VidMode は解像度を変えることができないため、 * これはおそらく過度安全だろう。 * Win32 では、ChangeDisplaySettings によって * ピクセル深度を変えることができる。 */ width=640; height=480; bpp=info->vfmt->BitsPerPixel; /* * ここで、OpenGL ウィンドウのために要求されたウィンドウ属性を設定したい。 * RGB 各チャンネルに *少なくとも* 5 ビット欲しい。 * また、少なくとも 16 ビットのデプスバッファも欲しい。 * * 最後にする事はダブルバッファウィンドウの要求である。 * '1' でダルバッファが有効になり、 * '0' で無効になる。 * * SDL_SetVideoMode へのフラグにおいて * SDL_DOUBLEBUF を使わない事に注意。 * それは GL アトリビュートに影響せず、 * 標準の 2D blit 転送の設定だけに影響する。 */ SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 ); SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 ); SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 ); SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 ); SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); /* * SDL がフルスクリーンビデオモードにおいて * OpenGL ウィンドウを提供してくれるよう要求したい。 * * 練習: * ウィンドウ状態で開始するオプションを作り、 * glViewPort でリサイズイベントを適切に処理せよ。 */ //flags=SDL_OPENGL | SDL_FULLSCREEN; flags=SDL_OPENGL; /* * Set the video mode */ if( SDL_SetVideoMode( width, height, bpp, flags )== 0 ) { /* * これはさまざまな理由で起き得る。 * DISPLAY が設定されていない、 * 指定された解像度が利用可能でない、など。 */ fprintf( stderr, "ビデオモードのセットに失敗しました: %s\n", SDL_GetError( ) ); quit_tutorial( 1 ); } /* * ここで、OpenGL の使用のために * ダブルバッファのウィンドウを適切に設定したはず。 */ setup_opengl( width, height ); /* * さて、通常のアプリケーション処理 -- たくさんの再描画と * イベントループを始めたい。 */ while( 1 ) { /* やってくるイベントを処理 */ process_events( ); /* 画面を表示 */ draw_screen( ); } /* * 練習: * SDL_GetTicks() を使ってタイミングを記録し、 * プログラム終了時に 1 秒間のフレームを表示せよ。 */ /* ここには届かない */ return 0; } |
ビルド設定
コンパイル・実行