//=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* // "gluthack.h" // OpenGL と glut 補助ライブラリのための追加補助ツール // XWindowシステムでも MS-Windows でもそのまま使えます。 // 製作 渡辺尚貴 変更日 2001年4月25日 //=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* #include #include #include #include #include #include #include #include //==== 利用者が用意すべき callback 関数 //---- 描画を行う callback 関数 // 利用者が glutPostRedisplay() 関数を呼ぶと実行される。 extern void myDisplay( void ); //---- Eventが無い時の作業をする callback 関数 // 計算等の主な作業を分割して進めるべき。 // 適当な間隔で glutPostRedisplay() 関数を呼ぶべき。 extern void myIdle( void ); //---- Keyboardを押した時の callback 関数 // key : キーの ASCII code もしくは glut.h で定義される特殊キーの定数 // x,y : マウスポインタのwindow上での位置 extern void myNormalKey( int key, int x, int y ); extern void mySpecialKey( int key, int x, int y ); //---- Mouseが動作した時の callback 関数 // button : 動作したボタンを表す定数 // GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON, GLUT_RIGHT_BUTTON // state : には動作したボタンの状況を表す定数 // GLUT_DOWN, GLUT_UP, GLUT_DRAG // x,y : マウスポインタのwindow上での位置 extern void myMouse( int button, int state, int x, int y ); //---- ImageMagickのconvertコマンドのpath // MS-Windows 上では使われない。 #define __PATH_OF_CONVERT "/usr/local/bin/convert" //---- glutのdefine定数に追加定義 #define GLUT_KEY_ESC 27 #define GLUT_DRAG 2 //---- 配列を引数に展開する小細工 #define Ato4d(arr) arr[0], arr[1], arr[2], arr[3] #define Ato3d(arr) arr[0], arr[1], arr[2] //---- Windowの現在の大きさを記憶する変数 static int _win_width, _win_height; //---- マウスのボタン番号を記憶する変数 static int _button; //---- Windowが表示された時と大きさが変更された時の callback関数 void __Reshape( int width, int height ) { glViewport( 0, 0, _win_width=width, _win_height=height ); glClear( GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT ); glutSwapBuffers(); } //---- 通常キーのプッシュを myKeyboard callback関数に通知する関数 void __NormalKey( unsigned char k, int x, int y ) { myNormalKey( (int)k, x, y ); } //---- 特殊キーのプッシュを myKeyboard callback関数に通知する関数 void __SpecialKey( int k, int x, int y ) { mySpecialKey( k, x, y ); } //---- マウスのクリックを myMouse callback関数に通知する関数 void __Mouse( int button, int state, int x, int y ) { myMouse( _button=button, state, x, y ); } //---- マウスのドラッグを myMouse callback関数に通知する関数 void __Motion( int x, int y ){ myMouse( _button, GLUT_DRAG, x, y ); } //---- OpenGL用のWindowを開く関数 // title : Window title // width, height : Window size // bkcolor : 背景色を表すRGBA void glutOpenWindow( int& argc, char** argv, int width, int height, const GLfloat bkcolor[] ) { glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH ); glutInitWindowSize( _win_width=width, _win_height=height ); glutInit( &argc, argv ); glutCreateWindow( argv[0] ); glClearColor( Ato4d(bkcolor) ); glEnable( GL_DEPTH_TEST ); glEnable( GL_NORMALIZE ); glutDisplayFunc ( myDisplay ); glutIdleFunc ( myIdle ); glutReshapeFunc ( __Reshape ); glutKeyboardFunc( __NormalKey ); glutSpecialFunc ( __SpecialKey ); glutMouseFunc ( __Mouse ); glutMotionFunc ( __Motion ); } //---- 視界を設定する関数 // angle : 視界角度(degree) // near : 再近接距離 // far : 再遠方距離 // eye : 目の位置 // gaze : 視点の位置 // up : 上方向 void glutSetEye( const GLdouble angle, const GLdouble near_len, const GLdouble far_len, const GLdouble eye[], const GLdouble gaze[], const GLdouble up[] ) { glMatrixMode( GL_PROJECTION ); gluPerspective( angle, (double)_win_width/_win_height, near_len, far_len ); glMatrixMode( GL_MODELVIEW ); gluLookAt( Ato3d(eye), Ato3d(gaze), Ato3d(up) ); } //---- 光源を設定する関数 // position : 光源の位置 // ambient : 環境光の成分 // diffuse : 散乱光の成分 // specular : 反射光の成分 void glutSetLight( const GLfloat position[], const GLfloat ambient[], const GLfloat diffuse[], const GLfloat specular[] ) { glLightModelfv( GL_LIGHT_MODEL_AMBIENT, ambient ); glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, 1 ); glLightModeli( GL_LIGHT_MODEL_LOCAL_VIEWER, 1 ); glLightfv( GL_LIGHT0, GL_POSITION, position ); glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuse ); glLightfv( GL_LIGHT0, GL_SPECULAR, specular ); glEnable( GL_LIGHTING ); glEnable( GL_LIGHT0 ); glShadeModel( GL_SMOOTH ); } //---- 原点に箱を描く関数 void glutBox( double dx, double dy, double dz ) { glBegin( GL_QUADS );{ glNormal3d( +1, 0, 0 ); glVertex3d( dx, 0, 0 ); glVertex3d( dx, dy, 0 ); glVertex3d( dx, dy, dz ); glVertex3d( dx, 0, dz ); glNormal3d( -1, 0, 0 ); glVertex3d( 0, 0, 0 ); glVertex3d( 0, 0, dz ); glVertex3d( 0, dy, dz ); glVertex3d( 0, dy, 0 ); glNormal3d( 0, +1, 0 ); glVertex3d( 0, dy, 0 ); glVertex3d( 0, dy, dz ); glVertex3d( dx, dy, dz ); glVertex3d( dx, dy, 0 ); glNormal3d( 0, -1, 0 ); glVertex3d( 0, 0, 0 ); glVertex3d( dx, 0, 0 ); glVertex3d( dx, 0, dz ); glVertex3d( 0, 0, dz ); glNormal3d( 0, 0, +1 ); glVertex3d( 0, 0, dz ); glVertex3d( dx, 0, dz ); glVertex3d( dx, dy, dz ); glVertex3d( 0, dy, dz ); glNormal3d( 0, 0, -1 ); glVertex3d( 0, 0, 0 ); glVertex3d( 0, dy, 0 ); glVertex3d( dx, dy, 0 ); glVertex3d( dx, 0, 0 ); }glEnd(); } void glutBoxWire( double dx, double dy, double dz ) { glBegin( GL_LINE_LOOP );{ glVertex3d( .0, .0, .0 ); glVertex3d( dx, .0, .0 ); glVertex3d( dx, dy, .0 ); glVertex3d( .0, dy, .0 ); }glEnd(); glBegin( GL_LINE_LOOP );{ glVertex3d( .0, .0, dz ); glVertex3d( dx, .0, dz ); glVertex3d( dx, dy, dz ); glVertex3d( .0, dy, dz ); }glEnd(); glBegin( GL_LINES );{ glVertex3d( .0, .0, .0 ); glVertex3d( .0, .0, dz ); glVertex3d( dx, .0, .0 ); glVertex3d( dx, .0, dz ); glVertex3d( .0, dy, .0 ); glVertex3d( .0, dy, dz ); glVertex3d( dx, dy, .0 ); glVertex3d( dx, dy, dz ); }glEnd(); } //---- 回転計算をする補助関数 inline void __RotateCS( double c, double s, double& X, double& Y ) { double T = X; X = c*X - s*Y; Y = s*T + c*Y; } //---- 左側から ModelView行列に回転変換行列を掛ける関数 void glRotateL( const double dang, const double x, const double y, const double z ) { double mat[4][4]; #ifndef M_PI #define M_PI 3.14159265358979323846 /* pi */ #endif const double s = sin(dang*M_PI/180); const double c = cos(dang*M_PI/180); glGetDoublev( GL_MODELVIEW_MATRIX, (double*)mat ); if( x!=0.0 ){ __RotateCS( c, s, mat[0][1], mat[0][2] ); __RotateCS( c, s, mat[1][1], mat[1][2] ); __RotateCS( c, s, mat[2][1], mat[2][2] ); }else if( y!=0.0 ){ __RotateCS( c, s, mat[0][2], mat[0][0] ); __RotateCS( c, s, mat[1][2], mat[1][0] ); __RotateCS( c, s, mat[2][2], mat[2][0] ); }else{ __RotateCS( c, s, mat[0][0], mat[0][1] ); __RotateCS( c, s, mat[1][0], mat[1][1] ); __RotateCS( c, s, mat[2][0], mat[2][1] ); } glLoadMatrixd((double*)mat); } //---- 左側から ModelView行列に平行移動変換行列を掛ける関数 void glTranslateL( const double dx, const double dy, const double dz ) { double mat[4][4]; glGetDoublev( GL_MODELVIEW_MATRIX, (double*)mat ); mat[3][0] += dx; mat[3][1] += dy; mat[3][2] += dz; glLoadMatrixd((double*)mat); } //---- 画面のイメージをファイルに保存する関数 #if defined(_WIN32) static FILE* __OpenConvert( const char* fname ) { if( strncmp( fname + strlen(fname) - 4, ".ppm", 4 ) ){ fprintf( stderr, "Only PPM format is available.\n"); return NULL; } return fopen( fname, "wb" ); } #else #include #include #include static void __Wait( int ) { while( waitpid(0,NULL,WNOHANG) > 0 ); signal( SIGCHLD, __Wait ); } static FILE* __OpenConvert( const char* fname ) { int pipefds[2]; pipe(pipefds); if( fork() == 0 ){ dup2( pipefds[0], 0 ); close(pipefds[0]); close(pipefds[1]); execl( __PATH_OF_CONVERT, "convert", "ppm:-", fname, 0 ); perror("execl convert"); exit(1); } signal( SIGCHLD, __Wait ); close(pipefds[0]); return fdopen( pipefds[1], "w" ); } FILE* glutBeginAnimation( const char* expression, ... ) { static char fname[64]; va_list argptr; va_start( argptr, expression ); vsnprintf( fname, sizeof(fname), expression, argptr ); int pipefds[2]; pipe(pipefds); if( fork() == 0 ){ dup2( pipefds[0], 0 ); close(pipefds[0]); close(pipefds[1]); execl( __PATH_OF_CONVERT, "convert", "-delay", "5", "ppm:-", fname, 0 ); perror("execl convert"); exit(1); } // signal( SIGCHLD, __Wait ); close(pipefds[0]); return fdopen( pipefds[1], "w" ); } void glutShotAnimation( FILE* fptr ) { if( fptr == NULL ) return; u_int bytes_per_line = _win_width*3; GLubyte* image = new GLubyte [ _win_height*bytes_per_line ]; glReadPixels( 0, 0, _win_width, _win_height, GL_RGB, GL_UNSIGNED_BYTE, image ); fprintf( fptr, "P6\n%d %d\n255\n", _win_width, _win_height ); for( int y=_win_height-1; y>=0; y-- ){ fwrite( &image[bytes_per_line*y], bytes_per_line, 1, fptr ); } delete [] image; } void glutEndAnimation( FILE* fptr ) { if( fptr ) fclose(fptr); wait(NULL); } #endif static void __CloseConvert( FILE* fptr ) { fclose(fptr); } char* glutSaveWindow( const char* expression, ... ) { static char fname[64]; va_list argptr; va_start( argptr, expression ); vsnprintf( fname, sizeof(fname), expression, argptr ); FILE* fptr = __OpenConvert(fname); GLuint bytes_per_line = _win_width*3; GLubyte* image = new GLubyte [ _win_height*bytes_per_line ]; glReadPixels( 0, 0, _win_width, _win_height, GL_RGB, GL_UNSIGNED_BYTE, image ); fprintf( fptr, "P6\n%d %d\n255\n", _win_width, _win_height ); for( int y=_win_height-1; y>=0; y-- ){ fwrite( &image[bytes_per_line*y], bytes_per_line, 1, fptr ); } fclose(fptr); delete [] image; __CloseConvert(fptr); return fname; } //---- Texture を設定して描くための関数群 struct Texture { GLubyte* image; GLuint width, height; }; int glutReadTexture( const char* ppmfname, Texture& tex ) { char buf[256]; int max=0; FILE* fptr = fopen( ppmfname, "r" ); if( fptr == NULL ){ fprintf( stderr, "Can not open %s.\n", ppmfname ); return 1; } fgets( buf, sizeof(buf), fptr ); if( strncmp( buf, "P6\n", 3 ) ){ fprintf( stderr, "Format Error!\n"); return 1; } while( fgets( buf, sizeof(buf), fptr ) ){ if( 2 == sscanf( buf, "%d %d", &tex.width, &tex.height ) ) break; } while( fgets( buf, sizeof(buf), fptr ) ){ if( 1 == sscanf( buf, "%d", &max ) ) break; } long image_size = tex.width * tex.height * 3; tex.image = new GLubyte [image_size]; fread( tex.image, image_size, 1, fptr ); fclose(fptr); glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); return 0; } void glutSetTexture( Texture& tex ) { glTexImage2D( GL_TEXTURE_2D, 0, 3, tex.width, tex.height, 0, GL_RGB, GL_UNSIGNED_BYTE, tex.image ); } #ifndef __VECTOR2_H_INCLUDE struct Vector2{ double x, y; inline Vector2( void ){} inline Vector2( const double& _x, const double& _y ) : x(_x), y(_y) {} }; #endif //---- (i,j)点での曲面の位置をGLに設定する関数 inline void __SurfaceVertex( double* Z, int N, int i, int j ) { glVertex3d( i*(1.0/N), j*(1.0/N), Z[i*N+j] ); } //---- (i,j)点での曲面の法線をGLに設定する関数 inline void __SurfaceNormal( double* Z, int N, int i, int j ) { double nx, ny, nz; // 法線ベクトルをz上向きとする nz = (1.0/N); // 法線ベクトルのx成分を計算する if( i==0 ){ // 端では片側差分で評価 nx = Z[i*N+j] - Z[i*N+j+N]; }else if( i==N-1 ){ // 端では片側差分で評価 nx = Z[i*N+j-N] - Z[i*N+j]; }else{ // 内側では中心差分で評価 nx = 0.5*( Z[i*N+j-N] - Z[i*N+j+N] ); } // 法線ベクトルのy成分を計算する if( j==0 ){ // 端では片側差分で評価 ny = Z[i*N+j] - Z[i*N+j+1]; }else if( j==N-1 ){ // 端では片側差分で評価 ny = Z[i*N+j-1] - Z[i*N+j]; }else{ // 内側では中心差分で評価 ny = 0.5*( Z[i*N+j-1] - Z[i*N+j+1] ); } // 規格化する double normalize = 1.0/sqrt( nx*nx + ny*ny + nz*nz ); nx *= normalize; ny *= normalize; nz *= normalize; // (i,j)での法線をGLに設定する glNormal3d( nx, ny, nz ); } //---- 2次元Descartes座標上に張る曲面を描く関数 void glutSurface( double* Z, int N ) { for( int i=0; ich[str[i] - fontinfo->first]; glBitmap( ch->width, ch->height, ch->xorig, ch->yorig, ch->advance, 0, ch->bitmap ); x += (int)ch->advance; } glBitmap( 0, 0, 0, 0, (float)-x, (float)-yo, 0 ); glPixelStorei( GL_UNPACK_SWAP_BYTES, swapbytes ); glPixelStorei( GL_UNPACK_LSB_FIRST, lsbfirst ); glPixelStorei( GL_UNPACK_ROW_LENGTH, rowlength ); glPixelStorei( GL_UNPACK_SKIP_ROWS, skiprows ); glPixelStorei( GL_UNPACK_SKIP_PIXELS, skippixels ); glPixelStorei( GL_UNPACK_ALIGNMENT, alignment ); }