情報処理U プログラム例3-5のOpenGL用プログラム


プログラム例 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 を返して終了 */
}


戻る