/*
始めは回転する立方体が表示されている
図形はマウスでクリック後ドラッグすることでカメラの位置を動かすことができる。
キーボードから1を入力すると立方体を、2を入力すると円錐を、3を入力すると球を
それぞれ表示することが出来る。
*/

#include
#include
#include 
#include
#include


#define WIDTH 560
#define HEIGHT 480

#define PAI 3.14159

//マウスドラッグ用
int Mouse_X,Mouse_Y;

//隠面消去用
float depth=-3.0f;
bool flag=false;
bool flag_m=true;

//回転用
float anglex = 0.0f;
//赤
GLfloat red[] = { 1.0, 0.1, 0.1, 1.0 };
//緑
GLfloat green[] = { 0.1, 1.0, 0.1, 1.0 };
//青
GLfloat blue[] = { 0.1, 0.1, 1.0, 1.0 };
//ライトの位置
GLfloat lightpos[] = { -50.0, 100.0, -50.0, 1.0 };
float Ambient[] = {0.8f, 0.0f, 0.2f, 1.0f};
float AmbientLight[] = { 1.0f, 1.0f, 1.0f, 1.0f};//環境光
float specular[]= { 0.4, 0.4, 0.4, 1.0};//鏡面反射
float SpecularLight[] = {1.0, 1.0, 1.0, 1.0};//鏡面光
float Diffuse[] = {1.0f, 1.0f, 1.0f, 1.0f};
float DiffuseLight[] = { 0.2f, 0.7f, 0.7f, 1.0f};//拡散光
unsigned char key;

//クォータニオン構造体
typedef struct
{
 double w;
 double x;
 double y;
 double z;
} Quaternion;
//回転マトリックス
double Rotate[16];

Quaternion Target;
Quaternion current={ 1.0, 0.0, 0.0, 0.0 };



//クォータニオンから回転行列を算出
void qtor(double *r , Quaternion q)
{
 int i;
 double xx = q.x * q.x * 2.0;
 double yy = q.y * q.y * 2.0;
 double zz = q.z * q.z * 2.0;
 double xy = q.x * q.y * 2.0;
 double yz = q.y * q.z * 2.0;
 double zx = q.z * q.x * 2.0;
 double xw = q.x * q.w * 2.0;
 double yw = q.y * q.w * 2.0;
 double zw = q.z * q.w * 2.0;
 double r1[16]={ 1.0 - yy - zz, xy + zw, zx - yw, 0.0,
  xy - zw, 1.0 - zz - xx, yz + xw, 0.0,
  zx + yw, yz - xw, 1.0 - xx - yy, 0.0,
  0.0, 0.0, 0.0, 1.0};
 for (i = 0;i < 16;i++) {
  r[i]=r1[i];
 }
}

void display(void)
{

 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 glViewport(0, 0, WIDTH, HEIGHT);
 glMatrixMode(GL_PROJECTION);
 glLoadIdentity();
 //視野角,アスペクト比(ウィンドウの幅/高さ),描画する範囲(最も近い距離,最も遠い距離)
 gluPerspective(40.0, (double)WIDTH / (double)HEIGHT, 1.0, 1000.0);
 glMatrixMode(GL_MODELVIEW);
 glLoadIdentity();
 //視点の設定
  gluLookAt(0,0,-300.0, //カメラの座標
      0.0,0.0,0.0, // 注視点の座標
     0.0,1.0,0.0); // 画面の上方向を指すベクトル
  //クォータニオンによる回転
 glMultMatrixd(Rotate);
 //ライトの設定
 glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
 glLightfv(GL_LIGHT0, GL_AMBIENT, AmbientLight);
 glLightfv(GL_LIGHT0, GL_SPECULAR, SpecularLight);

 //回転
 if(flag_m)glRotatef(anglex,1.0f,0.2f,0.0f);//X,Y軸を回転


 glMaterialfv(GL_FRONT, GL_AMBIENT, Ambient);
 glMaterialfv(GL_FRONT, GL_SPECULAR, specular);

 switch(key){
 case 49:
   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
   glutSolidCube(60.0);
 break;

 case 50:
    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
    glutSolidCone(40.0, 100.0, 8, 8);
 break;

 case 51:
    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, DiffuseLight);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, Diffuse);
    glutSolidSphere(40.0,16,16);
 break;

 default:
   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
   glutSolidCube(60.0);
   break;
 }
 glutSwapBuffers();
}

void idle(void)
{
 anglex+=0.5f;
 if(flag){depth-=0.1f;}else{depth+=0.1f;}
 if(depth>0.0f){flag=true;glEnable(GL_DEPTH_TEST);}
 if(depth<-3.0f){flag=false;glDisable(GL_DEPTH_TEST);}
 usleep(10000);
 glutPostRedisplay();
}
void Init(){
 glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
 glEnable(GL_DEPTH_TEST);
 glEnable(GL_LIGHTING);
 glEnable(GL_LIGHT0);
 glEnable(GL_CULL_FACE);
 glCullFace(GL_BACK);
 qtor(Rotate, current);
}

void keyboard(unsigned char k, int x , int y) {
  key = k;
}

void mousemove(int x, int y)
{
   flag_m = false;

  //移動量を計算
  double dx = (x - Mouse_X) * 1.33/WIDTH;
  double dy = (y - Mouse_Y) * 1.0/HEIGHT;

  //クォータニオンの長さ
  double length = sqrt(dx * dx + dy * dy);

  if (length != 0.0) {
    double radian = length * PAI;
    double theta = sin(radian) / length;
 Quaternion after={ cos(radian), dy * theta, dx * theta, 0.0};//回転後の姿勢
 Quaternion q0={
   after.w*current.w-after.x*current.x-after.y*current.y-after.z*current.z,
   after.w*current.x+after.x*current.w+after.y*current.z-after.z*current.y,
   after.w*current.y-after.x*current.z+after.y*current.w+after.z*current.x,
   after.w*current.z+after.x*current.y-after.y*current.x+after.z*current.w
 };

 Target = q0;

    qtor(Rotate, Target);
  }
}
void mouse(int button, int state, int x, int y)
{
  flag_m = true;
 if(button){
    switch(state){
    case GLUT_DOWN://マウスボタンを押した位置を記憶
      Mouse_X = x;
      Mouse_Y = y;
      break;
    case GLUT_UP://姿勢を保存
  current=Target;
      break;
    default:
      break;
    }
 }

}

int main(int argc, char *argv[])
{
 glutInitWindowPosition(100, 100);
 glutInitWindowSize(WIDTH, HEIGHT);
 glutInit(&argc, argv);
 glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
 glutCreateWindow("");
 glutDisplayFunc(display);
 glutKeyboardFunc(keyboard);
 glutMouseFunc(mouse);
 glutMotionFunc(mousemove);
 glutIdleFunc(idle);
 Init();
 glutMainLoop();
 return 0;
}
1個もどる
トップへ戻る