プログラム例 3-5
#include <stdlib.h> /* C言語標準ライブラリのインクルード */ #include <GL/glut.h> /* GLUTヘッダファイルのインクルード */ #include <GL/gl.h> /* GLヘッダファイルのインクルード */ #include <math.h> #define KEY_ESC 27 /* エスケープキーの登録 */ #define PI 3.1415926 #define X0 320 /* 原点 X0 */ #define Y0 200 /* 原点 Y0 */ #define NP 20 /* 頂点数 */ #define NE 12 /* 面数 */ #define NM 10 /* 一つの面を構成する最大頂点数 */ typedef struct { float x, y, z; } point; point p[NP]={{ 0, 0, 0},{100, 0, 0},{100,100, 0},{ 80,100, 0}, {52.5, 72.5, 0},{52.5, 65, 0},{47.5, 65, 0},{47.5,72.5, 0}, {20,100, 0},{ 0,100, 0}, { 0, 0, 65},{100, 0, 65},{100,100, 65},{ 80,100, 65}, {52.5, 72.5, 65},{52.5, 65, 65},{47.5, 65, 65},{47.5,72.5, 65}, {20,100, 65},{ 0,100, 65}}; /* 頂点座標 */ int e[NE][NM]={{0,1,2,3,4,5,6,7,8,9},{0,10,11,1},{1,11,12,2},{2,12,13,3}, {3,13,14,4},{4,14,15,5},{5,15,16,6},{6,16,17,7},{7,17,18,8}, {8,18,19,9},{9,19,10,0},{19,18,17,16,15,14,13,12,11,10}}; /* 面データ */ int np[NE]={10,4,4,4,4,4,4,4,4,4,4,10}; /* 面の頂点数 */ int mButton; /* ドラッグ時に押されているマウスボタンの判別 */ int xBegin, yBegin; /* ドラッグ開始時点のマウスポインタの座標 */ float thx=0, thy=0, thz=0; /* x, y, z 軸周りの回転角度 */ float sp = 500; /* 透視変換のパラメータ */ float scal(point p1, point p2, point p3); point yrot(point p, float th); point xrot(point p, float th); point zrot(point p, float th); point tousi(point p, float sp); /* 図形の描画 */ void display(void) { point q[NP]; int i, j, k, ki, kn=0; int kashi[NE]; float zk[NE]; float s, max, min; float xg, yg; glClear(GL_COLOR_BUFFER_BIT); /* ウインドウの背景を決められた色で塗りつぶす */ glColor3f(1.0, 1.0, 1.0); /* 白色を設定 */ glBegin(GL_LINES); /* 直線の描画 */ glVertex2f(-X0, 0); /* 頂点座標の設定 */ glVertex2f( X0, 0); glVertex2f( 0, Y0); /* 頂点座標の設定 */ glVertex2f( 0,-Y0); glEnd(); /* 軸の描画終了 */ for(i = 0; i<NP; i++) { q[i] = yrot(p[i], thy); /* y軸回りの回転 */ q[i] = xrot(q[i], thx); /* x軸回りの回転 */ q[i] = zrot(q[i], thz); /* z軸回りの回転 */ q[i] = tousi(q[i], sp); /* 透視変換 */ } for (i=0; i<NE; ++i) { /* 可視面であるかの判定 */ if (scal(q[e[i][0]], q[e[i][1]], q[e[i][2]])>=0) { kashi[kn++] = i; max = q[e[i][0]].z; min = q[e[i][0]].z; for (j=1; j<np[i]; j++) { if(max < q[e[i][j]].z) max = q[e[i][j]].z; if(min > q[e[i][j]].z) min = q[e[i][j]].z; } zk[i] = (max + min) / 2; } } for (i=1; i<kn; i++) { /* 直接選択ソート法による面の並び替え */ s =zk[kashi[i]]; ki = kashi[i]; for(j=i-1; j>=0; j--) { if(zk[kashi[j]] < s) kashi[j+1] = kashi[j]; else break; } kashi[j+1] = ki; } for (i=0; i<kn; i++) { glColor3f(1.0, 1.0, 1.0); /* 描画物体に白色を設定 */ glBegin(GL_POLYGON); /* ポリゴン(多角形平面)の描画 */ for (j=0; j < np[kashi[i]]; j++) glVertex2d(q[e[kashi[i]][j]].x, q[e[kashi[i]][j]].y); /* 頂点座標の設定 */ glEnd(); glColor3f(1.0, 0, 0); /* ポリゴンの描画終了 */ glBegin(GL_LINE_LOOP); /* 輪郭の描画 */ for (j=0; j < np[kashi[i]]; j++) glVertex2d(q[e[kashi[i]][j]].x, q[e[kashi[i]][j]].y); /* 頂点座標の設定 */ glEnd(); /* 輪郭の描画終了 */ } glutSwapBuffers(); /* OpenGLのコマンドを強制的に実行 */ } /* エスケープキーを押したときの処理 */ void myKbd(unsigned char key, int x, int y) { if (key == KEY_ESC) exit(0); /* 押されたキーがエスケープキーならばプログラムを終了 */ } /* 上下矢印キーを押したときの処理 */ void mySkey(int key, int x, int y) { switch(key) { case GLUT_KEY_UP : /* 上矢印キー */ sp += 10; break; case GLUT_KEY_DOWN : /* 下矢印キー */ sp -= 10; break; } glutPostRedisplay(); } /* クリックしたときの処理 */ void myMouse(int button, int state, int x, int y) { if(state == GLUT_DOWN) { mButton = button; xBegin = x; /* マウスをクリックしたときのx座標 */ yBegin = y; /* マウスをクリックしたときのy座標 */ } } /* マウスのドラッグ時の処理 */ void myMotion(int x, int y) { int xDisp, yDisp; xDisp = x - xBegin; /* マウス移動距離の計算 */ yDisp = y - yBegin; switch(mButton) { case GLUT_LEFT_BUTTON: /* 左ボタンのドラッグで物体の姿勢を変える */ thx += (float)yDisp/2.0*PI/180.0; thy += (float)xDisp/2.0*PI/180.0; break; case GLUT_RIGHT_BUTTON: /* 右ボタンのドラッグで物体の姿勢を変える */ thz += (float)yDisp/2.0*PI/180.0; break; } xBegin = x; /* つぎのステップのマウスの出発点 */ yBegin = y; glutPostRedisplay(); /* 1ステップ分のドラッグの結果を描画に反映 */ } /* グラフィックスの初期化 */ void myInit(char *program) { int width=2*X0, height=2*Y0; glutInitWindowPosition(0, 0); /* ウィンドウの左上の位置を(0,0)とする */ glutInitWindowSize(width, height); /* ウインドウのサイズを2*X0 X 2*Y0ドットとする */ glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA ); /* 色の指定にRGBAモードを用いる */ glutCreateWindow(program); /* ウィンドウをオープンする */ glClearColor(0.0, 0.0, 0.0, 1.0); /* ウインドウの背景色の指定 */ glutKeyboardFunc(myKbd); /* 一般キーのコールバック関数の登録 */ glutSpecialFunc(mySkey); /* 特殊キーのコールバック関数の登録 */ glutMouseFunc(myMouse); /* マウスクリックに対するコールバック関数の登録 */ glutMotionFunc(myMotion); /* マウスドラッグに対するコールバック関数の登録 */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-X0, X0, -Y0, Y0, -500, 500); /* 座標系を決定(平行投影) */ } /* Sの計算 */ float scal(point p1, point p2, point p3) { float s; s = (p1.x*p2.y+p2.x*p3.y+p3.x*p1.y-p1.x*p3.y-p2.x*p1.y-p3.x*p2.y)/2.0; return s; } /* y軸回りの回転 */ point yrot(point p, float th) { point q; q.x = p.x * cos(th) - p.z * sin(th); q.y = p.y; q.z = p.x * sin(th) + p.z * cos(th); return q; } /* x軸回りの回転 */ point xrot(point p, float th) { point q; q.x = p.x; q.y = p.z * sin(th) + p.y * cos(th); q.z = p.z * cos(th) - p.y * sin(th); return q; } /* z軸回りの回転 */ point zrot(point p, float th) { point q; q.x = p.x * cos(th) + p.y * sin(th); q.y = -p.x * sin(th) + p.y * cos(th); q.z = p.z; return q; } /* 透視変換 */ point tousi(point p, float sp) { point q; q.x = sp * p.x / (sp+p.z); q.y = sp * p.y / (sp+p.z); q.z = p.z; return q; } int main(int argc, char **argv) { int i; float th, sp; glutInit(&argc, argv); /* glutの初期化 */ myInit(argv[0]); glutDisplayFunc(display); /* ディスプレイコールバック関数の指定 */ glutMainLoop(); /* イベント待ちの無限ループに入る */ return(0); /* 0 を返して終了 */ }