#include <stdlib.h>
#include <GL/glut.h>
#include <math.h>
#define STEPCYCLE 50 /* 手足のひと振りに要する時のフレーム数 */
#define WALKCYCLE 250 /* ロボットの移動に要するフレーム数 */
#define KICKSPEED 600 /* キックの速度に関するパラメータ */
#define M_PI 3.14
struct robotangle{
double ll1; /* ロボットの左足の股関節の角度 */
double ll2; /* ロボットの左足の膝関節の角度 */
double rl1; /* ロボットの右足の股関節の角度 */
double rl2; /* ロボットの右足の膝関節の角度 */
double la1; /* ロボットの左腕の肩関節の角度 */
double la2; /* ロボットの左腕の肘関節の角度 */
double ra1; /* ロボットの右腕の肩関節の角度 */
double ra2; /* ロボットの右腕の肘関節の角度 */
};
/* 直方体を描く */
void myBox(double x, double y, double z)
{
GLdouble hx = x * 0.5, hz = z * 0.5;
static GLfloat flesh[] = { 0.945, 0.733, 0.576, 1.0 }; /* 肌色の定義 */
int i, j;
/* 面を構成する頂点 */
GLdouble vertex[][3] = {
{ -hx, -y, -hz },
{ hx, -y, -hz },
{ hx, 0.0, -hz },
{ -hx, 0.0, -hz },
{ -hx, -y, hz },
{ hx, -y, hz },
{ hx, 0.0, hz },
{ -hx, 0.0, hz }
};
/* 面の構成 */
static int face[][4] = {
{ 0, 1, 2, 3 },
{ 1, 5, 6, 2 },
{ 5, 4, 7, 6 },
{ 4, 0, 3, 7 },
{ 4, 5, 1, 0 },
{ 3, 2, 6, 7 }
};
/* 各面の単位法線ベクトル */
static GLdouble normal[][3] = {
{ 0.0, 0.0,-1.0 },
{ 1.0, 0.0, 0.0 },
{ 0.0, 0.0, 1.0 },
{-1.0, 0.0, 0.0 },
{ 0.0,-1.0, 0.0 },
{ 0.0, 1.0, 0.0 }
};
/* 材質を設定する */
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, flesh);
/* 面の描画 */
glBegin(GL_QUADS);
for (j = 0; j < 5; j++) {
glNormal3dv(normal[j]);
for (i = 3; i >= 0;i--) {
glVertex3dv(vertex[face[j][i]]);
}
}
glEnd();
}
/* 腕/足 */
void armleg(double girth, double length, double r1, double r2)
{
glRotated(r1, 1.0, 0.0, 0.0);
myBox(girth, length, girth);
glTranslated(0.0, -0.05 - length, 0.0);
glRotated(r2, 1.0, 0.0, 0.0);
myBox(girth, length, girth);
}
/* 地面を描く */
void myGround()
{
static GLfloat ground[4] = {0.1, 1.0, 0.0, 1.0 };
glBegin(GL_QUADS);
glNormal3d(0.0, 1.0, 0.0);
glMaterialfv(GL_FRONT, GL_DIFFUSE, ground);
glVertex3f(-10, -1.8, -10);
glVertex3f(-10, -1.8, 10);
glVertex3f( 5, -1.8, 10);
glVertex3f( 5, -1.8, -10);
glEnd();
}
/* ゴールポストを描く */
void mypost()
{
/* ゴールポストの各頂点 */
static GLdouble vertex[][3] = {
{ 4.0, -1.7, -5.0 }, /* A */
{ 4.0, -1.7, 5.0 }, /* B */
{ 4.0, 1.0, 5.0 }, /* C */
{ 4.0, 1.0, -5.0 }, /* D */
{ 2.0, -1.7, -5.0 }, /* E */
{ 2.0, -1.7, 5.0 }, /* F */
{ 2.0, 1.0, 5.0 }, /* G */
{ 2.0, 1.0, -5.0 } /* H */
};
static int edge[][2] = {
{ 0, 1 }, /* ア (A-B) */
{ 1, 2 }, /* イ (B-C) */
{ 2, 3 }, /* ウ (C-D) */
{ 3, 0 }, /* エ (D-A) */
{ 5, 6 }, /* カ (F-G) */
{ 6, 7 }, /* キ (G-H) */
{ 7, 4 }, /* ク (H-E) */
{ 0, 4 }, /* ケ (A-E) */
{ 1, 5 }, /* コ (B-F) */
{ 2, 6 }, /* サ (C-G) */
{ 3, 7 } /* シ (D-H) */
};
static GLfloat black[] = { 0.0, 0.0, 0.0, 1.0 };
static GLfloat white[] = { 1.0, 1.0, 1.0, 1.0 };
int i,j,k;
glLineWidth(5);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, white); /* 材質を設定する */
glBegin(GL_LINES);
for (i = 0; i < 11; ++i) {
glVertex3dv(vertex[edge[i][0]]);
glVertex3dv(vertex[edge[i][1]]);
}
glEnd();
glMaterialfv(GL_FRONT, GL_DIFFUSE, black); /* 材質を設定する */
glLineWidth(1.0);
/* ゴールネットを描く */
glBegin(GL_LINES);
for(j=0;j<=10;j++){
for(k=0;k<=10;k++){
glVertex3f(2.0+0.2*j, -1.7, 5.0);
glVertex3f(2.0+0.2*j, 1.0, 5.0);
glVertex3f(2.0, -1.7+0.27*k, 5.0);
glVertex3f(4.0, -1.7+0.27*k, 5.0);
glVertex3f(2.0+0.2*j, -1.7, -5.0);
glVertex3f(2.0+0.2*j, 1.0, -5.0);
glVertex3f(2.0, -1.7+0.27*k, -5.0);
glVertex3f(4.0, -1.7+0.27*k,- 5.0);
glVertex3f(4.0, -1.7, 5.0-1.0*j);
glVertex3f(4.0, 1.0, 5.0-1.0*j);
glVertex3f(4.0, -1.7+0.27*k, -5.0);
glVertex3f(4.0, -1.7+0.27*k, 5.0);
glVertex3f(2.0, 1.0, 5.0-1.0*j);
glVertex3f(4.0, 1.0, 5.0-1.0*j);
glVertex3f(2.0+0.2*j, 1.0, 5.0);
glVertex3f(2.0+0.2*j, 1.0, -5.0);
}
}
glEnd();
}
/* 部位ごとに座標変換 */
void trans(struct robotangle *angle){
/* 頭 */
myBox(0.20, 0.25, 0.22);
/* 胴 */
glTranslated(0.0, -0.3, 0.0);
myBox(0.4, 0.6, 0.3);
/* 左足 */
glPushMatrix();
glTranslated(0.1, -0.65, 0.0);
armleg(0.2, 0.4, angle->ll1, angle->ll2);
glPopMatrix();
/* 右足 */
glPushMatrix();
glTranslated(-0.1, -0.65, 0.0);
armleg(0.2, 0.4, angle->rl1, angle->rl2);
glPopMatrix();
/* 左腕 */
glPushMatrix();
glTranslated(0.28, 0.0, 0.0);
armleg(0.16, 0.4, angle->la1, angle->la2);
glPopMatrix();
/* 右腕 */
glPushMatrix();
glTranslated(-0.28, 0.0, 0.0);
armleg(0.16, 0.4, angle->ra1, angle->ra2);
glPopMatrix();
}
/* 画面表示 */
void display(void)
{
static GLfloat lightpos[] = { 3.0, 4.0, 1.0, 0.0 }; /* 光源の位置 */
static int frame = 0,i=0,state=0;
static double bx=0.0;
static GLfloat white[] = { 1.0, 1.0, 1.0, 1.0 };
static struct robotangle angle;
static GLUquadricObj *sphere; /* オブジェクトポインタを準備 */
sphere = gluNewQuadric(); /* オブジェクトを生成 */
/* STEPCYCLE に指定した枚数のフレームを描画する間に 0→1 に変化 */
double t;
t = (frame % STEPCYCLE) / (double)STEPCYCLE;
/* WALKCYCLE に指定した枚数のフレームを描画する間に 0→1 に変化 */
double s;
s = (frame % WALKCYCLE) / (double)WALKCYCLE;
double px = -10+20*s, pz = 0.0; /* ロボットの位置 */
if(px >= -2.5 && state == 0){
t = 0.8;
state = 1;
}
double r = 90.0; /* ロボットの向き */
double h = 0.01*cos((360*t/360)*2*M_PI*2); /* ロボットの高さ */
angle.ll1 = 30*sin((360*t/360)*2*M_PI); /* ロボットの左足の股関節の角度 */
angle.ll2 = 30-30*cos((360*t/360)*2*M_PI); /* ロボットの左足の膝関節の角度 */
angle.rl1 = 30*cos(((360*t+60)/360)*2*M_PI); /* ロボットの右足の股関節の角度 */
angle.rl2 = 30-30*sin(((360*t+60)/360)*2*M_PI); /* ロボットの右足の膝関節の角度 */
angle.la1 = 30*cos(((360*t+60)/360)*2*M_PI); /* ロボットの左腕の肩関節の角度 */
angle.la2 = -30-30*sin(((360*t+60)/360)*2*M_PI); /* ロボットの左腕の肘関節の角度 */
angle.ra1 = 30*sin((360*t/360)*2*M_PI); /* ロボットの右腕の肩関節の角度 */
angle.ra2 = -30-30*cos((360*t/360)*2*M_PI); /* ロボットの右腕の肘関節の角度 */
if(state != 1)
++frame; /* フレーム数(画面表示を行った回数)をカウントする */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* 画面の塗りつぶし・Zバッファの設定 */
glLoadIdentity(); /* モデルビュー変換行列の初期化 */
glLightfv(GL_LIGHT0, GL_POSITION, lightpos); /* 光源の位置を設定 */
glTranslated(0.0, 0.0, -20.0); /* 視点の移動(物体の方を奥に移す)*/
myGround(); /* 地面 */
mypost(); /* ゴールポスト */
//オブジェクトの描画タイプを設定
gluQuadricDrawStyle(sphere, GLU_FILL);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, white); /* 材質を設定する */
if(state == 0) /* ドリブル */
glTranslated(px+0.45,-1.7,0);
else if(state == 1) /* ボールを蹴る動作中 */
glTranslated(-2.5+0.45,-1.7,0);
else if(state == 2){ /* 蹴った後の動作 */
if(bx==0.)
bx = px+0.45;
glTranslated(bx,bx/4-1.0,0);
bx += 0.2;
}
gluSphere(sphere, 0.1,10.0, 10.0); /* 球を描画 半径0.1,緯経それぞれ10.0分割 */
glLoadIdentity(); /* モデルビュー変換行列の初期化 */
glTranslated(0.0, 0.0, -20.0);
/* ロボットの位置と方向 */
if(state == 0)
glTranslated(px, h, pz);
else
glTranslated(-2.5, 0.0, 0.0);
glRotated(r, 0.0, 1.0, 0.0); /* ロボットの向きの変更 */
/* ボールを蹴る動作以降の右足以外の角度 */
if(state != 0){
angle.ll1=-45.;
angle.ll2=45.;
angle.la1=0.;
angle.la2=0.;
angle.ra1=0.;
angle.ra2=0.;
if(state == 2){
angle.rl1=-90;
angle.rl2=0;
}
}
/* ボールを蹴る動作 */
if(state == 1){
i++;
angle.rl1=45*sin(((double)(0.01*KICKSPEED)*i/360)*2*M_PI);
angle.rl2=45-45*cos(((double)(0.01*KICKSPEED)*i/360)*2*M_PI);
if(i==(int)(22000/KICKSPEED)){
state = 2;
i=0;
}
}
/* ゴールネットに突き刺さった場合 */
if(bx >= 4.0){
/* パラメータの初期化 */
state = 0;
frame = 0;
bx = 0.0;
}
trans(&angle); /* ロボットの手足の幾何変換 */
glutSwapBuffers();
}
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);
/* モデルビュー変換行列の指定 */
glMatrixMode(GL_MODELVIEW);
}
void keyboard(unsigned char key, int x, int y)
{
/* ESC か q をタイプしたら終了 */
if (key == '\033' || key == 'q') {
exit(0);
}
}
void init(void)
{
/* 初期設定 */
glClearColor(1.0, 1.0, 1.0, 0.0); /* 画面を塗りつぶす色の設定 */
glEnable(GL_DEPTH_TEST); /* 陰面消去処理を有効にする */
glEnable(GL_LIGHTING); /* 陰影付けを有効にする */
glEnable(GL_LIGHT0); /* 光源の0番目を有効にする */
glEnable(GL_CULL_FACE); /* カリング処理を有効にする */
glCullFace(GL_BACK); /* 裏面を表示しないようにする */
}
void idle(void)
{
glutPostRedisplay(); /* 再描画するイベント発生させる */
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv); /* GLUTおよび,OpenGL環境の初期化 */
/* GLUT_RGBA:色の指定をRGBで指定 GLUT_DEPTH:陰面消去処理を有効にする GLUT_DOUBLE:ダブルバッファリングを有効にする*/
glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE); /* 表示モードの設定 */
glutCreateWindow(argv[0]); /* ウィンドウを開く(引数はタイトルバーに表示する文字) */
glutDisplayFunc(display); /* 再描画する場合に引数の関数が実行される */
glutReshapeFunc(resize); /* ウィンドウがリサイズされたときに引数の関数を実行する */
glutIdleFunc(idle); /* 操作などが無い場合に引数の関数が実行される */
glutKeyboardFunc(keyboard); /* キーボードをタイプした時に実行される */
init(); /* 初期設定 */
glutMainLoop(); /* 無限ループ,待ち状態になる */
return 0;
}