#include #include #include #include #define W 10 /* 地面の幅        */ #define D 10 /* 地面の長さ       */ #define QX 0.0 /* 球の初期位置のx座標値 */ #define QY 1.5 /* 球の初期位置のy座標値 */ #define QZ (-5.0) /* 球の初期位置のz座標値 */ #define G (-9.8) /* 重力加速度       */ #define V 20.0 /* 初速度         */ #define TSTEP 0.01 /* フレームごとの時間   */ #define R 0.1 /* ボールの半径      */ #define A 0.6 /* 反発係数 */ #define ON 1 #define OFF 0 #define FRONT 0 #define HIGHANGLE 1 #define UPSIDE 2 double vx, vy, vz; /* 速度ベクトル */ int dw, dh; /* ウィンドウサイズ(dw, dh) */ int MouseFlag = ON; int ViewPoint = FRONT; int IdleFlag = OFF; /* * 地面を描く */ static void myGround(double height) { const static GLfloat ground[][4] = { { 0.6, 0.6, 0.6, 1.0 }, { 0.3, 0.3, 0.3, 1.0 } }; int i, j; glBegin(GL_QUADS); glNormal3d(0.0, 1.0, 0.0); for (j = -D / 2; j < D / 2; ++j) { for (i = -W / 2; i < W / 2; ++i) { glMaterialfv(GL_FRONT, GL_DIFFUSE, ground[(i + j) & 1]); glVertex3d((GLdouble)i, height, (GLdouble)j); glVertex3d((GLdouble)i, height, (GLdouble)(j + 1)); glVertex3d((GLdouble)(i + 1), height, (GLdouble)(j + 1)); glVertex3d((GLdouble)(i + 1), height, (GLdouble)j); } } glEnd(); } void idle(void) { glutPostRedisplay(); } /* * 画面表示 */ static void display(void) { const static GLfloat white[] = { 0.8, 0.8, 0.8, 1.0 }; /* 球の色 */ const static GLfloat lightpos[] = { 3.0, 4.0, 5.0, 1.0 }; /* 光源の位置 */ static double px = QX, py = QY, pz = QZ; /* 球の位置 */ /* 画面クリア */ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* モデルビュー変換行列の初期化 */ glLoadIdentity(); /* 光源の位置を設定 */ glLightfv(GL_LIGHT0, GL_POSITION, lightpos); /* 視点の移動(物体の方を奥に移す)*/ glTranslated(0.0, -QY, -D); switch(ViewPoint){ case HIGHANGLE: gluLookAt(0.0, 7.0, 7.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0); break; case UPSIDE: gluLookAt(0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0); break; default: break; } /* シーンの描画 */ myGround(0.0); glTranslated(px, py, pz); glMaterialfv(GL_FRONT, GL_DIFFUSE, white); glutSolidSphere(R, 16, 8); glutSwapBuffers(); if(IdleFlag == OFF) return; usleep(15000); px += vx * TSTEP; vy += G * TSTEP; py += vy * TSTEP; pz += vz * TSTEP; /* 着地したらバウンド */ if(py-R < 0){ vy *= -A; py = R; } /* 表示範囲外に出たら初期位置に戻す */ if(pz+R >= D || px+R >= W/2){ px = QX; py = QY; pz = QZ; glutPostRedisplay(); glutIdleFunc(0); IdleFlag = OFF; MouseFlag = ON; } } static void resize(int w, int h) { /* ウィンドウ全体をビューポートにする */ glViewport(0, 0, w, h); /* 透視変換行列の指定 */ glMatrixMode(GL_PROJECTION); /* 透視変換行列の初期化 */ glLoadIdentity(); gluPerspective(30.0, (double)w / (double)h, 1.0, 100.0); dw = w; dh = h; /* モデルビュー変換行列の指定 */ glMatrixMode(GL_MODELVIEW); } static void mouse(int button, int state, int x, int y) { double theta; //x軸(横)方向角度 double phi; //y軸(縦)方向角度 switch(button){ case GLUT_LEFT_BUTTON: if(state == GLUT_DOWN && MouseFlag == ON){ theta = (double)(x-dw/2)/dw*M_PI/4.0; //x座標からthetaを決定 phi = -(double)(y-dh/2)/dh*M_PI/4.0; //y座標からphiを決定 vx = V*sin(theta)*cos(phi); vy = V*sin(phi); vz = V*cos(theta)*cos(phi); glutIdleFunc(idle); IdleFlag = ON; MouseFlag = OFF; } break; case GLUT_RIGHT_BUTTON: if(state == GLUT_DOWN){ if(ViewPoint == FRONT) ViewPoint = HIGHANGLE; else if(ViewPoint == HIGHANGLE) ViewPoint = UPSIDE; else ViewPoint = FRONT; glutPostRedisplay(); } break; defalut: break; } } static void keyboard(unsigned char key, int x, int y) { /* ESC か q をタイプしたら終了 */ if (key == '\033' || key == 'q') { exit(0); } else if(key == ' ' || key == 'p'){ if(IdleFlag == ON){ glutIdleFunc(0); IdleFlag = OFF; } else{ glutIdleFunc(idle); IdleFlag = ON; } } } static void init(void) { /* 初期設定 */ glClearColor(1.0, 1.0, 1.0, 1.0); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); } int main(int argc, char *argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE); glutCreateWindow(argv[0]); glutDisplayFunc(display); glutReshapeFunc(resize); glutMouseFunc(mouse); glutKeyboardFunc(keyboard); init(); glutMainLoop(); return 0; }