今日からは、具体的にプログラムの中身を見ていきます。
難しいことをくどくど書くと、興味を持ってもらえませんので、
とりあえず、前に挙げた「3つの球の重力シミュレーション」の
ソースコードを公開します。

/*************************************************/
/* Program "test.c" */
/* Jan 19 2006 Created by vine_user */ /* */
/*************************************************/
#include <stdlib.h>
#include <GL/glut.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <math.h>
#define KEY_ESC 27
#define G 9.80665
#define TICK 1.0e-4

void polarview( void );
void resetview( void );

int xBegin = 0, yBegin = 0;
int mButton;
float distance, twist, elevation, azimuth;
float nearw = 0.01, farw = 50.0, fovy = 45.0;

float redDiffuse[] = { 1.0, 0.3, 0.0, 1.0 };
float greenDiffuse[] = { 0.0, 1.0, 0.8, 1.0 };
float blueDiffuse[] = { 0.0, 0.3, 1.0, 1.0 };
float whiteSpecular[] = { 0.9, 0.9, 1.0, 1.0 };
float whiteAmbient[] = { 0.1, 0.1, 0.1, 1.0 };

float x[3] = {0.0};
float y[3] = {0.0};
float z[3] = {0.0};
float vx[3] = {0.0};
float vy[3] = {0.0};
float vz[3] = {0.0};
float r[3] = {0.0};
float dt = TICK;
float M = 0.4;

void init()
{
x[0] = 0.0; y[0] = 0.0; z[0] = 0.0;
x[1] = -0.8; y[1] = 0.0; z[1] = 0.0;
x[2] = 0.5; y[2] = 0.0; z[2] = 0.0;
vx[0] = 0.0; vy[0] = 0.0; vz[0] = 0.0;
vx[1] = 0.0; vy[1] = -2.0; vz[1] = 0.0;
vx[2] = 0.0; vy[2] = 2.0; vz[2] = 0.0;
}

void step()
{
r[0]=sqrt((x[0]-x[1])*(x[0]-x[1])+(y[0]-y[1])*(y[0]-y[1])+(z[0]-z[1])*(z[0]-z[1]));
r[1]=sqrt((x[1]-x[2])*(x[1]-x[2])+(y[1]-y[2])*(y[1]-y[2])+(z[1]-z[2])*(z[1]-z[2]));
r[2]=sqrt((x[0]-x[2])*(x[0]-x[2])+(y[0]-y[2])*(y[0]-y[2])+(z[0]-z[2])*(z[0]-z[2]));
if(r[0]>0.01) {
if(r[1]>0.01) {
if(r[2]>0.01) {
vx[0]+=-dt*G*M*(x[0]-x[1])/(r[0]*r[0]*r[0])-dt*G*M*(x[0]-x[2])/(r[2]*r[2]*r[2]);
vy[0]+=-dt*G*M*(y[0]-y[1])/(r[0]*r[0]*r[0])-dt*G*M*(y[0]-y[2])/(r[2]*r[2]*r[2]);
vz[0]+=-dt*G*M*(z[0]-z[1])/(r[0]*r[0]*r[0])-dt*G*M*(z[0]-z[2])/(r[2]*r[2]*r[2]);
vx[1]+=-dt*G*M*(x[1]-x[0])/(r[0]*r[0]*r[0])-dt*G*M*(x[1]-x[2])/(r[1]*r[1]*r[1]);
vy[1]+=-dt*G*M*(y[1]-y[0])/(r[0]*r[0]*r[0])-dt*G*M*(y[1]-y[2])/(r[1]*r[1]*r[1]);
vz[1]+=-dt*G*M*(z[1]-z[0])/(r[0]*r[0]*r[0])-dt*G*M*(z[1]-z[2])/(r[1]*r[1]*r[1]);
vx[2]+=-dt*G*M*(x[2]-x[1])/(r[1]*r[1]*r[1])-dt*G*M*(x[2]-x[0])/(r[2]*r[2]*r[2]);
vy[2]+=-dt*G*M*(y[2]-y[1])/(r[1]*r[1]*r[1])-dt*G*M*(y[2]-y[0])/(r[2]*r[2]*r[2]);
vz[2]+=-dt*G*M*(z[2]-z[1])/(r[1]*r[1]*r[1])-dt*G*M*(z[2]-z[0])/(r[2]*r[2]*r[2]);
}
}
}
int i;
for(i=0;i<3;i++) {
x[i]+=vx[i]*dt;
y[i]+=vy[i]*dt;
z[i]+=vz[i]*dt;
if(fabs(x[i])>2.0) vx[i]=-vx[i];
if(fabs(y[i])>2.0) vy[i]=-vy[i];
if(fabs(z[i])>2.0) vz[i]=-vz[i];
}

}

void draw()
{
glPushMatrix();
glDisable(GL_LIGHTING);
glColor3f(0.0,0.0,0.5);
glBegin(GL_LINE_LOOP);
int i;
int j;
for(i=0;i<30;i++) {
for(j=0;j<101;j++) {
glVertex3f(0.06*i*cos(j*M_PI/50.0),0.06*i*sin(j*M_PI/50.0),0.0);
}
}
glEnd();
glEnable(GL_LIGHTING);
glTranslatef(x[0],y[0],z[0]);
glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, redDiffuse );
glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, whiteSpecular );
glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, whiteAmbient );
glMaterialf( GL_FRONT, GL_SHININESS, 80.0 );
glutSolidSphere(0.06,30,30);
glPopMatrix();
glPushMatrix();
glTranslatef(x[1],y[1],z[1]);
glTranslatef(0.0,0.0,0.0);
glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, blueDiffuse );
glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, whiteSpecular );
glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, whiteAmbient );
glMaterialf( GL_FRONT, GL_SHININESS, 80.0 );
glutSolidSphere(0.06,30,30);
glPopMatrix();
glPushMatrix();
glTranslatef(x[2],y[2],z[2]);
glTranslatef(0.0,0.0,0.0);
glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, greenDiffuse );
glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, whiteSpecular );
glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, whiteAmbient );
glMaterialf( GL_FRONT, GL_SHININESS, 80.0 );
glutSolidSphere(0.06,30,30);
glPopMatrix();
}

void drawWorld()
{
int i;
for(i=0;i<30;i++) {
step();
}
draw();

}

void display(void)
{
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glPushMatrix();
polarview();
glEnable( GL_DEPTH_TEST );
glEnable( GL_LIGHTING );

glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, greenDiffuse );
glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, whiteSpecular );
glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, whiteAmbient );
glMaterialf( GL_FRONT, GL_SHININESS, 128.0 );

glEnable( GL_NORMALIZE);
glEnable( GL_AUTO_NORMAL);

drawWorld();

glPopMatrix();
glDisable( GL_LIGHTING );
glDisable( GL_DEPTH_TEST );
glutSwapBuffers();
}


void myKbd(unsigned char key, int x, int y)
{
switch(key) {
case KEY_ESC:
exit( 0 );
case 'R':
resetview();
break;
default:
break;
}
}

void myMouse( int button, int state, int x, int y )
{
if (state == GLUT_DOWN) {
mButton=button;
xBegin = x;
yBegin = y;
}
}


void myMotion(int x, int y)
{
int xDisp, yDisp;

xDisp = x - xBegin;
yDisp = y - yBegin;
switch(mButton){
case GLUT_LEFT_BUTTON:
azimuth += (float) xDisp/2.0;
elevation -= (float) yDisp/2.0;
break;
case GLUT_MIDDLE_BUTTON:
twist = fmod (twist + xDisp, 360.0);
break;
case GLUT_RIGHT_BUTTON:
distance -= (float) yDisp/40.0;
break;
}
xBegin = x;
yBegin = y;
glutPostRedisplay();
}

void myInit(char *progname)
{
glutInitWindowPosition(0, 0);
glutInitWindowSize( 600, 600);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutCreateWindow(progname);
glClearColor (0.0, 0.0, 0.0, 0.8);
glutKeyboardFunc(myKbd);
glutMouseFunc(myMouse);
glutMotionFunc(myMotion);
resetview();
glShadeModel( GL_SMOOTH );
glEnable( GL_LIGHT0 );
init();
}


void myReshape(int width, int height)
{
float aspect = (float)width / (float)height;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(fovy, aspect, nearw, farw);
glMatrixMode(GL_MODELVIEW);
}


void polarview( void )
{
glTranslatef( 0.0, 0.0, -distance);
glRotatef( -twist, 0.0, 0.0, 1.0);
glRotatef( -elevation, 1.0, 0.0, 0.0);
glRotatef( -azimuth, 0.0, 1.0, 0.0);
}


void resetview( void )
{
distance = 3.0;
twist = 0.0;
elevation = 0.0;
azimuth = 0.0;
}

void timer(int value)
{
if (value==1) {
glutTimerFunc(10,timer,1);
glutPostRedisplay();
}
}

int main(int argc, char** argv)
{
glutInit(&argc, argv);
myInit(argv[0]);
glutReshapeFunc (myReshape);
glutDisplayFunc(display);
glutTimerFunc(10,timer,1);
glutMainLoop();
return(0);
}


コンパイルの方法は、前回の説明の通りです。
FedoraCoreの場合、ワークステーション あるいは
フルインストールでインストール済みなら、
# yum install freeglut
# yum install freeglut-devel


これだけでOKです。

あとは、上のソースコードをtest.cの名前で保存して、
保存したディレクトリで、

# gcc -lglut test.c -o test

でコンパイルできます。

このソースコードは、いろんな本を参考にしながら作った
オリジナルのものです。こういうのは、最初にうまくいかないと
投げ出してしまうので、そこを一気にクリアーしてもらおうと
思って公開することにしました。

成功したら、是非コメント下さい!

なかなか本題に入りませんが…
上のテキストボックスの書き方を調べてたので、もうこんな時間に
なってしまいました。

次回は、プログラムの概要と初期化の部分について
書いておこうと思います。