Skip to content

Instantly share code, notes, and snippets.

@peccu
Created June 11, 2010 08:44
Show Gist options
  • Select an option

  • Save peccu/434255 to your computer and use it in GitHub Desktop.

Select an option

Save peccu/434255 to your computer and use it in GitHub Desktop.
#include <stdlib.h>
#include <math.h>
#include <GLUT/glut.h>
#define PX 0.0 /* 初期位置      */
#define PZ 0.0 /* 初期位置      */
#define W 4 /* 台の幅の2分の1  */
#define D 6 /* 台の長さの2分の1 */
#define H 0.5 /* 壁の高さ      */
#define R 0.3 /* パックの半径    */
#define TIMESCALE 0.01 /* フレームごとの時間 */
#define SPEED 30.0 /* パックの初速度   */
#define MU 0.5 /* 台との摩擦係数   */
#define WEIGHT 1.0 /* パックの質量    */
static int ww; /* ウィンドウの幅  */
static int wh; /* ウィンドウの高さ  */
static int frame = 0; /* 現在のフレーム数  */
static double vx0, vz0; /* パックの初速度   */
static double px0 = PX, pz0 = PZ; /* パックの初期位置  */
static double px = 0, pz = 0; /* パックの現在位置 */
static double pvx = 0, pvz = 0; /* パックの現在の速度 */
static double mx = PX, mz = PZ; /* マウスの位置 */
/*
* 台を描く
*/
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 }
};
const static GLfloat wall[] = { /* 壁の色    */
0.8, 0.8, 0.8, 1.0
};
const static GLdouble panel[][9] = { /* 壁の形状データ */
{ 0.0, 0.0, 1.0, -W, 0.0, -D, -W, H, -D },
{ -1.0, 0.0, 0.0, W, 0.0, -D, W, H, -D },
{ 0.0, 0.0, -1.0, W, 0.0, D, W, H, D },
{ 1.0, 0.0, 0.0, -W, 0.0, D, -W, H, D },
{ 0.0, 0.0, 1.0, -W, 0.0, -D, -W, H, -D },
};
int i, j;
glBegin(GL_QUADS);
/* 床を描く */
glNormal3d(0.0, 1.0, 0.0);
for (j = -D; j < D; ++j) {
for (i = -W; i < W; ++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);
}
}
/* 壁を描く */
glMaterialfv(GL_FRONT, GL_DIFFUSE, wall);
for (i = 0; i < 4; ++i) {
glNormal3dv(panel[ i ]);
glVertex3dv(panel[ i ] + 3);
glVertex3dv(panel[i + 1] + 3);
glVertex3dv(panel[i + 1] + 6);
glVertex3dv(panel[ i ] + 6);
}
glEnd();
}
/*
* 円柱を描く(パック)
* radius:半径か直径
* height:円柱の高さ
* sides: 側面の面の数(多いほど円に近づく.3なら三角柱)
*/
static void myCylinder(double radius, double height, int sides)
{
double step = 6.2831853072 / (double)sides;
int i = 0;
/* 上面 */
glNormal3d(0.0, 1.0, 0.0);
glBegin(GL_TRIANGLE_FAN);
while (i < sides) {
double t = step * (double)i++;
glVertex3d(radius * sin(t), height, radius * cos(t));
}
glEnd();
/* 底面 */
glNormal3d(0.0, -1.0, 0.0);
glBegin(GL_TRIANGLE_FAN);
while (--i >= 0) {
double t = step * (double)i;
glVertex3d(radius * sin(t), -height, radius * cos(t));
}
glEnd();
/* 側面 */
glBegin(GL_QUAD_STRIP);
while (i <= sides) {
double t = step * (double)i++;
double x = sin(t);
double z = cos(t);
glNormal3d(x, 0.0, z);
glVertex3f(radius * x, height, radius * z);
glVertex3f(radius * x, -height, radius * z);
}
glEnd();
}
/*
* 画面表示
*/
static void display(void)
{
const static GLfloat lightpos[] = { 3.0, 4.0, 5.0, 1.0 }; /* 光源の位置 */
const static GLfloat yellow[] = { 0.9, 0.9, 0.2, 1.0 }; /* パックの色 */
const static GLfloat red[] = { 1.0, 0.0, 0.0, 1.0 }; /* マウスの色 */
/* double t = TIMESCALE * frame; /\* フレーム数から現在時刻を求める *\/ */
/* double v = exp(-MU * t / WEIGHT); /\* パックの速度比 *\/ */
/* double p = WEIGHT * (1.0 - v) / MU; /\* パックの相対位置 *\/ */
/* double px = vx0 * p + px0; /\* パックの現在位置 *\/ */
/* double pz = vz0 * p + pz0; /\* パックの現在位置 *\/ */
/* /\* */
/* ** パックが台の壁に当たったら初期位置と初速度を変更する */
/* ** 速度(比)が一定以下になったら現在位置を初期位置にして */
/* ** アニメーションを止める */
/* ** (ここは自分で考えてください) */
/* *\/ */
/* if(v<=0.1){ */
/* px0 = px; */
/* pz0 = pz; */
/* frame = 500; */
/* } */
pvx *= 0.5;
pvz *= 0.5;
px += pvx;
pz += pvz;
if(abs(px)+R >= W ){
pvx *= -1;
}
/* if(pzが壁に接した){ */
/* pvz *= -1; */
/* } */
/* double */
/* if(v<=0.1){ */
/* px0 = px; */
/* pz0 = pz; */
/* frame = 500; */
/* } */
/* フレーム数(画面表示を行った回数)をカウントする */
++frame;
/* 画面クリア */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/* モデルビュー変換行列の初期化 */
glLoadIdentity();
/* 光源の位置を設定 */
glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
/* 視点の移動(物体の方を奥に移す)*/
glTranslated(0.0, 0.0, -30.0);
glRotated(90.0, 1.0, 0.0, 0.0);
/* シーンの描画 */
myGround(0.0);
/* パックの描画 */
glPushMatrix();
glTranslated(px, 0.0, pz);
glMaterialfv(GL_FRONT, GL_DIFFUSE, yellow);
myCylinder(0.3, 0.1, 8);
glPopMatrix();
/* /\* マウスの描画 *\/ */
/* glPushMatrix(); */
/* glTranslated(mx, 0.0, mz); */
/* glMaterialfv(GL_FRONT, GL_DIFFUSE, red); */
/* myCylinder(1.0, 0.8, 4); */
/* glPopMatrix(); */
glFlush();
}
static void resize(int w, int h)
{
/* ウィンドウ全体をビューポートにする */
glViewport(0, 0, ww = w, wh = h);
/* 透視変換行列の指定 */
glMatrixMode(GL_PROJECTION);
/* 透視変換行列の初期化 */
glLoadIdentity();
/* gluPerspective(30.0, (double)w / (double)h, 1.0, 100.0); */
/* 平行投影 */
/* left,right,bottom,top,near,far */
glOrtho(-4, 4, -6, 6, -9999, 9999);
/* モデルビュー変換行列の指定 */
glMatrixMode(GL_MODELVIEW);
}
static void keyboard(unsigned char key, int x, int y)
{
/* ESC か q をタイプしたら終了 */
if (key == '\033' || key == 'q') {
exit(0);
}
}
static void mouse(int button, int state, int x, int y)
{
switch (button) {
case GLUT_LEFT_BUTTON:
/*
** マウスをクリックしたウィンドウ上の座標から
** 表示されている台の表面の空間位置を求める
*/
if (state == GLUT_DOWN) {
GLdouble model[16], proj[16];
GLint view[4];
GLfloat z;
GLdouble ox, oy, oz;
/* クリックした時にフレーム数を 0(すなわち時間を 0)にする */
frame = 0;
/*
** モデルビュー変換行列・透視変換行列・ビューポート変換行列を取り出す
*/
glGetDoublev(GL_MODELVIEW_MATRIX, model);
glGetDoublev(GL_PROJECTION_MATRIX, proj);
glGetIntegerv(GL_VIEWPORT, view);
/*
** クリックした位置の奥行きを z に取り出す
** (台の外をクリックするとまずいけどもういいや)
*/
glReadPixels(x, wh - y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &z);
/* クリックしたところの台の上の位置を求める */
gluUnProject(x, wh - y, z, model, proj, view, &ox, &oy, &oz);
/*
** (px0, pz0) と (ox, oz) を使ってパックを打ち出す方向を決め,
** パックの初速度 (vx0, vz0) を決めて,アニメーションを開始する.
** (ここは自分で考えて下さい)
*/
/* ここの符号とか,向きを変えることでカーソルに向かってくるか跳ね返るか決められる */
pvx = -(ox-px0)/sqrt(pow((ox-px0),2)+pow((oz-pz0),2));
pvz = -(oz-pz0)/sqrt(pow((ox-px0),2)+pow((oz-pz0),2));
/* vx0 = -(ox-px0)/sqrt(pow((ox-px0),2)+pow((oz-pz0),2)); */
/* vz0 = -(oz-pz0)/sqrt(pow((ox-px0),2)+pow((oz-pz0),2)); */
/* while(frame<500){ */
/* display(); */
/* } */
break;
case GLUT_MIDDLE_BUTTON:
break;
case GLUT_RIGHT_BUTTON:
break;
default:
break;
}
}
}
static void mousemove(int x, int y)
{
printf("X = %d->%d : Y = %d->%d\n",x,mx,y,mz);
mx = W*(x*2/ww - 1);
mz = H*(y*2/wh - 1);
/* ディスプレイの絶対座標が帰ってくる */
printf(" X= %d->%d : Y = %d->%d\n",x,mx,y,mz);
display();
}
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);
glutCreateWindow(argv[0]); /* ウィンドウ作成 */
glutDisplayFunc(display); /* 描画関数 */
glutReshapeFunc(resize); /* ウィンドウのリサイズ */
glutKeyboardFunc(keyboard); /* キーボードのイベントで呼ばれる */
glutMouseFunc(mouse); /* マウスのイベントで呼ばれる */
//glutPassiveMotionFunc(mousemove); /* マウスが動いた時に呼ばれる */
init(); /* 初期化 */
glutMainLoop(); /* GLのメインのループ.上で指定した関数が適宜呼ばれる */
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment