第4回 継承と階層構造
前回（2001 年 11 月号）では、三次元の物体の物体が必要になることが多くあります。また、

点3と同様に、頂点4、頂点6、頂点8、頂点10、の形状を作成する方法について説明しました。

位置や大きさ、色だけ異なる物体が必要な場合頂点 12 といった頂点で六角形を描いています。

形状を作成する上で、頂点の座標と面を登録すもあります。既存のクラスを継承して、異なるこのようにして頂点を生成すると図 3 の左側のるのは結構大変です。今回は、いろいろな形状部分だけを再定義すれば、簡単にクラスを追加ようになり、面を貼れば右側の回転体が作成でを簡単に生成できるように「回転体を生成するできます。既存のクラス（物体の定義）を再利きます。Z 軸は紙面奥が正の方向になります。

クラス」を作成します。その回転体クラスを使っ用しやすくするには、継承する場合のことを考

それでは実際にCRevolutionという名の回転て、クラスの継承の機能と物体の階層構造（多えてクラスを設計しなければなりません。

体クラスを作成します（リスト 1）。まず XY 平
面上の頂点を図 1 のように設定します。X 軸上関節オブジェクト）を利用した簡単なプログラ
ムを紹介します。物体の形状をプログラミング■回転体クラスと継承

きの3Dアニメーションを、数十キロバイト程形状の作成は、頂点と面を1つずつ指定する「vx[0],vy[0]」と頂点1「vx[1],vy[1]」に続い度のデータ（j3d ファイル）を配布するだけでのではなく、ある規則に従って頂点を生成するて、必要なだけ頂点を配列に設定します。続い済むという利点を持っています。

プログラムを作成すると楽になります。回転体てvColor配列に対応する頂点の色を指定します。

■クラスの継承66に並ぶ2つの頂点として、X座標をvx配列に、Y座標を v y 配列に分けて格納します。頂点 0する必要がある J3W ですが、複雑な形状と動とは、二次元の形状をある回転軸を中心に回転Setup メソッドに、頂点 0 と頂点 1 を除いたさせることによって生成する三次元形状です。

頂点数と回転方向の分割数をセットして呼び出

図 1 は、X 軸と Y 軸を含む平面（XY 平面）にすと、頂点と面が回転体として登録されます。

J3C言語は「同じクラスのインスタンスでも4つの頂点を置いたところを示しています。頂CRevolution クラスは、配列と変数で 100 の自分自身のデータメンバとメソッドしかアクセ

点 0 と頂点 1 は X 軸上（YZ 座標がともに 0）にデータメモリを使っています。データメモリのスできない」という特徴を持っています。別のあり、頂点 2 と頂点 3 は X 軸から離れたところ

領域はスタックとしても使いますから、インスクラスのメソッドやデータを操作することはで（Y座標が正、Z座標が0）にあるものとします。

タンスを生成する場合には「new(CRevolution,きません。C++ や Delphi では、クラスの継承

ここでX軸を中心に紙面奥に向かって回転させ200)」のように150以上のデータメモリを確保

を利用しなくても C や Pascal のプログラムとると立体ができます。この立体を「回転体」としてください。

してアプリケーションが作成できてしまいます。

呼びます。

XY 平面で与えた頂点を回転させて、X、Y、これは C や Pascal のプログラマには利点でも4つの頂点をX軸の周りに回転させると頂点3Zの座標を求めるために次の式を使っています。

ありますが、一方ではオブジェクト指向の考えの軌跡は円を描きます。これを一度に60度ずつ頂点番号 i の頂点が j 回の回転（一度に T だけ方を身に付けるには邪魔にもなります。

回転させると六角形になります。図 2 は X 軸上回転）した場合の座標を求めています。

幸か不幸か、J3Cでは継承はほとんど不可欠に視点を置いて、X が増加する方向を見た場合です。三次元の物体をプログラムしていく上で、を示しています。頂点 1 から頂点 0 の方向を見

例えば右手と左手というように、よく似た性質ていると考えてください。このとき頂点 2 も頂

【図 1】XY 平面上に 4 つの頂点を置いたところ【図 2】X 軸の周囲を回転する頂点 3 の軌跡

J3W for Linux 入門講座

X = vx[i]Y = vy[i] * cos(T*j)/10000
Z = vy[i] * sin(T*j)/10000【図 3】60 度ずつ回転してできた回転体サイン（sin）、コサイン（cos）、平方根などの算術関数では結果が 1 万倍されて返るため、それを調整するために 10000 で割る必要があります。リスト 1 では、各座標値を求める式をそのままVertexメソッドの引数として渡しています。

CRevolution クラスは、INIT() 、RUN() 、【リスト 1】回転体クラス CRevolution（c_revolv.j3c）class CRevolution {final int MAX = 30;
volatile int vx[MAX];
volatile int vy[MAX];
volatile int vColor[MAX];
volatile int vWork[6];volatile int T, m, i, j;
int Vertex(int x, int y, int z) {RX = x; RY = y; RZ = z;
Point();}EVENT()のどのメソッドも空のため、new組み込み関数でインスタンス化しても何もしないクラスとなります。具体的な形状や動作は// 頂点の登録//-------------------------------------// 面と頂点を登録// n は頂点数 -2, m は円周の分割数//-------------------------------------int Setup(int n, int m) {for(i = 0; i <= n+1; i=i+1)// 初期頂点（n+2 個）の登録
Vertex(vx[i], vy[i], 0);CRevolutionを継承するクラスで定義します。
リスト 2 は CRevolution を継承して球体を生成する sphere クラスの定義です。INIT メ
ソッドから形状定義のための sphere メソッドを呼び出して球体を生成しています。

// 頂点座標を計算して、頂点を登録
T = 2880 / m;// 1 ステップの角度
for(j=1; j<m; j=j+1)// j=0 の座標は初期値で登録済み
for(i=2; i<=n+1; i=i+1)
Vertex(vx[i], vy[i] * cos(T*j)/10000, vy[i] * sin(T*j)/10000);

NewObject(3000,3000)で 3000 頂点、3000 面を確保していますが、頂点や面の数が増えてもいいように余裕を持たせています。

CRevolutionに追加したsphereメソッドは、// 面を登録
if (n > 1) {// 上下の錐体を除いた面の定義
vWork[1] = 4;// 四角形
for(j=0; j<=m-2; j=j+1)// 経線ごとfor(i=2; i<=n; i=i+1) {// 緯線ごとvWork[0] = vColor[i];// 面の色を指定
vWork[2] = j*n+i;// 頂点番号指定
vWork[3] = j*n+i+1;
vWork[4] = (j+1)*n+i+1;
vWork[5] = (j+1)*n+i;
Plane(vWork);// 面の登録}球の半径 radius、経線の分割数 div 、球の色colorを指定して呼び出すことによって、半円上の頂点をvx、vy配列に設定します。その後、CRevolution から継承した Setup メソッドを14（＋ 2）個の頂点で、断面が 30 角形になるような回転体の頂点と面を登録します。RUNメソッドでは球体を運動をさせています。 ここでは簡単に 8 秒間で 360 度のピッチ回転と 3 秒間で 18度のヘッド回転を繰り返しています。
リスト3 で main クラスを定義します。INIT
メソッドで sphere クラスのインスタンスを生成し、 main クラスは視点となりますが、形状を持つ必要がないため NewObject(0, 0)で空}の物体を生成しています。視点のように、位置や姿勢の情報が必要なインスタンスは、頂点やfor(i=2; i<=n; i=i+1) {vWork[0] = vColor[i];vWork[2] = (m-1)*n+i;
vWork[3] = (m-1)*n+i+1;
vWork[4] = i + 1;
vWork[5] = i;Plane(vWork);}

vWork[1] = 3;
vWork[0] = vColor[0];for(j=0; j<=m-2; j=j+1) {vWork[2] = 0;vWork[3] = j*n+2;
vWork[4] = (j+1)*n+2;
Plane(vWork);}

面を登録しない場合でも NewObject の実行が必須になります。RUNメソッドでは、キー入力を調べて、ESCキーが押されるとすべてのインスタンスを終了させるようにしています。結果としてプログラムの実行が終了します。リスト
3を次のコマンドでコンパイルして実行し、動vWork[2] = 0;vWork[3] = (m-1)*n+2;
vWork[4] = 2;
Plane(vWork);

作を確認してください。

j3cc -r rv_main.j3c
さて、球体が回転しても動きが分かりづらい

vWork[0] = vColor[1];for(j=0; j<=m-2; j=j+1) {vWork[2] = 1;
vWork[3] = (j+2)*n+1;vWork[4] = (j+1)*n+1;Plane(vWork);}

ため、実行してもあまり面白くありません。そこで、CRevolution の「帯状に色が異なる回転体」を生成する機能を使い、sphere クラスを継承した sphere2 クラスで新しい球体を作成します。球体の形状は、 s p h e r e クラスのvWork[2] = 1;
vWork[3] = n +1;
vWork[4] = m*n+1;
Plane(vWork);

sphere メソッドをそのまま使うことができま
すから、INITメソッド中でsphereメソッドで指定された色を部分的に変更することにします}（リスト 4）。

int INIT() { }int RUN() { }int EVENT() { }リスト5は、リスト3が sphere2 クラスを使うように「<<<< 変更」の部分を変更したもの// 頂点の X 座標// 頂点の Y 座標// 面の色// 作業用配列// m-1 から 0 への戻り// 面の色を指定// 頂点番号指定// 面の登録// 上部（X 大）の錐体// 三角形// 面の色を指定// 頂点番号指定// 面の登録// m-1 から 0 への戻り// 頂点番号指定// 面の登録// 下部（X 小）の錐体// 面の色を指定// 頂点番号指定// m-1 から 0 への戻り// 頂点番号指定// 面の登録}2001.12 Linux Japan67

【リスト 2】球体を生成する sphere クラス（sphere.j3c）【画面 1】sphere2 クラスで色分けした球体

import "c_revolv.j3c";class sphere extends CRevolution {int sphere(int radius, int div, int color) {volatile int i;vx[ 0] = radius;//
頂点 0
vy[ 0] = 0;vx[ 1] = -radius;//
頂点 1
vy[ 1] = 0;
for (i=0; i<div-1 ; i=i+1) {vColor[i] = color;}for (i=1; i<div-1 ; i=i+1) {vx[i+1] = radius * cos(i*1440/(div-1)) / 10000;
vy[i+1] = radius * sin(i*1440/(div-1)) / 10000;}}
int INIT() {NewObject(3000,3000);
sphere(500, 16, 3);
Setup(14, 30);
ClearRegisters();
SetPosition();}int RUN() {RotPitch(8000, 2880);
RotHead(3000,144);}

る必要があります。
リスト6のプログラムは、クラスBのインスタンスを生成して、10 秒待って終了するものです。このプログラムを読んで実行結果を予想// 頂点と面を登録してみてください。J3Cのプログラムを解読す// 位置と姿勢を指定

るには、 class main の INIT から始めます。

main から生成されたクラス B のインスタン// 360 度 /8 秒でピッチ回転// 18 度 /3 秒でヘッド回転スは、クラス A から継承した INIT が再定義されていないので、クラス A の INIT を実行します。IntroduceMyself メソッドは、クラス B}で再定義されていることから、どうやらこのプです（2 行変更しています）。 このように、ログラムの作者は、継承した INIT からクラスてみてください。

B 用の IntroduceMyself メソッドが実行され

s p h e r e 2 は s p h e r e を継承し、 s p h e r e はCRevolution を継承することによって、継承■継承を利用する上での注意点
一般のオブジェクト指向言語には、実行時にIntroduceMyself メソッドは、クラス A とク

先 ほ ど と 同 様 に し て 、 リ ス ト 5

呼び出し先のメソッドを決める「動的結合ラス B のどちらの IntroduceMyself メソッド

（rv_main2.j3c）
をコンパイルして実行します。

（dynamic binding）」または「遅延結合（lateを実行するのでしょうか？

すると今度は、帯状に異なる色のある球体が表binding）」と呼ばれる機能があります（C++ の実行すると、画面には「I am A. 」と表示示されます（画面1）。リスト3のときより動き仮想関数に相当する機能）。しかし J3C 言語にされます。残念ながらプログラムの作者が期待を変更することができます。

が分かりやすくなったと思います。リスト4にはこの機能はなく、コンパイル時に呼び出すメした動作にはなってないないようです。この例

RUN メソッドを加えて、sphere クラスと異なソッドが決まります。これを「静的結合（staticから分かるように、クラスBのインスタンスがる動きをさせることもできます。いろいろ試しbinding）」または「早期結合（early binding）」

実行するクラス A の INIT は、あくまでクラスと呼びます。従って、クA の INIT です。従って、実行結果は当然クララスを継承して一部のス A の IntroduceMyself メソッドを実行するメソッドを再定義したことになります。クラス B でも INIT を再定義場合には、呼び出し元するようにすれば、期待する動作になります。のメソッドも再定義す

汎用のメソッドを作成する場合には、条件を【リスト 3】回転体の実行（rv_main.j3c）

import "sphere.j3c";class main {volatile int key;
int INIT() {new(sphere, 3000);// 球のインスタンスの生成
NewObject(0, 0);// 視点用の物体の生成
ClearRegisters();// RX - RB に 0 を代入
RX = -1000;// 位置の指定 10m 後方
SetPosition();// 位置と角度を視点に設定
See();// このオブジェクトを見る
BackgroundColor(0x000); // 背景色を設定
GraphMode();// グラフィックウインドウを開く
Zoom(0);// 視野角 53 度（2 倍ズーム）
Specular(200);}
int RUN() {key = InKey();// キーコード入力
if (key == 0x1B) Stop();// ESC キーで終了}
int EVENT() {}}68

ることを期待しているようです。クラスBのインスタンスが実行するクラス A の I N I T 中の元のクラスに手を加えずに回転体の形状や動作

J3W for Linux 入門講座

【リスト 4】回転体に色を着ける（sphere2.j3c）

import "sphere.j3c";class sphere2 extends sphere {int INIT() {NewObject(3000,3000);
sphere(500, 16, 12);vColor[0] = 8;
vColor[5] = 2;
vColor[9] = 10;
vColor[11] = 1;
vColor[1] = 14;
Setup(14, 30);
ClearRegisters();
SetPosition();}}// 部分的に色を変更// 頂点と面を登録// 位置と姿勢を指定

【リスト 6】クラス継承の実験（class.j3c）【リスト 5】rv_main.j3c の変更（rv_main2.j3c）

import "sphere2.j3c";// <<<< 変更class A {int IntroduceMyself() {String("I am A.");
Char(13);}
int INIT() {IntroduceMyself();}
int RUN(){}int EVENT(){}}

class main {volatile int key;
int INIT() {new(sphere2, 3000);// 球のインスタンスの生成 <<<< 変更
NewObject(0, 0);// 視点用の物体の生成
ClearRegisters();// RX - RB に 0 を代入
RX = -1000;// 位置の指定 10m 後方
SetPosition();// 位置と角度を視点に設定
See();// このオブジェクトが見る
BackgroundColor(0x000); // 背景色を設定
GraphMode();// グラフィックウインドウを開く
Zoom(0);// 視野角 53 度(2 倍ズーム)
Specular(200);}class B extends A {int IntroduceMyself() {String("I am B.");
Char(13);}}

int RUN() {key = InKey();// キ−コ−ド入力
if (key == 0x1B) Stop(); // ESC キーで終了}
int EVENT() {}}承元（基底）クラスでは、与える引数の値で動ラ ス は リ ス ト 1

作が変わるようなメソッドを用意し、派生クラ

CRevolution クラスを継スでは、位置や姿勢の指定、色の設定、大きさ承して回転体を生成しまの指定などを INIT や RUN から引数で指定してす。Parent クラスのイン呼び出すようにします。のclass main {int INIT() {new(B);Pause(1000);Stop();}int RUN(){}int EVENT(){}}

スタンスは、階層構造の下位に5個の Child ク

childだけです。childは、インスタンスを生

なお、EVENTメソッドは内部でRUN メソッド

ラスのインスタンスを持ち、Child クラスは成するnewと、インスタンスが物体として存在から呼び出されるため、EVENTを再定義した場

GrandChild クラスのインスタンスを 1 つ持っするための NewObject という 2 つの組み込み合は、 RUN も再定義するようにしてください。ています。リスト7を実行すると画面3のよう関数の機能を持つ関数です。ただし「生成されEVENT だけの再定義はできません。になります。誌面がモノクロなので分かりにくるインスタンスがchild組み込み関数を実行しいですが、実際にはクラスごとに色が変えてあたインスタンスのオブジェクト（の座標系）にります。中心部がParentクラスで、Parentク属している」という点が異なります（図 4）。

ラスの動きに合わせてすぐ外側の Child クラ

childで生成されたインスタンスは、座標系ス、その外側のGrandChildクラスが連動してが親オブジェクトの局所座標系に属している以動きます。

外は、全く独立した物体として動作します。親■物体の階層構造
人体のように関節を持つ物体を表現するためには、階層構造を持つオブジェクトが必要になります。腰をひねれば肩も腕も頭も動きます。

リスト7は、約500の面で構成された物体が、となる物体が先に消滅した場合は、その子供たつまり、肩、腕、首の関節を動かさなくても、10 関節、60 自由度で動作します。これは ESC

ちはそれぞれ空間内で独立した（ワールド座標

地面に対する物体の位置や角度は変化します（画キーが押されるまで動き続けます。どの関節も系に存在する）物体になります。

面 2）。これは、腰の座標系（フレームと呼ぶ

rod クラスの RUN メソッドで定義された 7 つのここで注意しておきたいことがあります。ク場合もある）
上に肩の座標系が固定され、肩の回転命令で同じ動きをしていますが、全体としラスの継承による階層と、物体の座標系の親子座標系に頭の座標系が固定され、という具合にては、かなり複雑な動きをしていると思いませ関係による階層構造を混同しないようしてくだ

親子関係が形作られているからです。

んか？ それぞれのクラスの動きをRUNメソッ

さい。未定義クラスエラーが発生する場合には

リスト 7 は、rod クラスを継承した Parent（親）、Child（子）、GrandChild（孫）クラスが3層の階層構造になっている例です。rod ク

ドで別に定義すれば、いろいろな動きを試すこ混同している可能性があります。リスト7でrodとができます。

クラスはインスタンス化されていません。継承

階層構造の物体を実現する組み込み関数はされてParent、Child、GrandChildという派生クラスのインスタンスが作られています。従っ【画面 2】関節を持つ物体は「腰の座標系」を持つ【画面 3】リスト 7 を実行した様子て、Parent、Child、GrandChildの各クラス間に継承関係はありません。これを例えば、「Parent からChild を派生させて、 Child から【図 4】child 組み込み関数の役割

2001.12 Linux Japan69

GrandChild を派生させて……」とすると、物J3C の仕様です。

ことを実行する効率的なプログラムを作るための強力な武器になると思います。

体の親子関係を定義する child 組み込み関数
でクラス間に相互参照が発生し、クラス宣言■終わりに

次回は、物体を外部からコントロールするメッ
セージの送信とメッセージを処理するEVENTメ時またはインスタンス生成時に「クラスが未定義」というエラーが発生します。すでに宣クラスの継承と物体の階層構造の実現方法をソッドの使い方、そしてグラフィックウィンド

言された識別子（クラス名、メソッド名、変一気に紹介しました。クラスの継承関係を上手ウに文字や線分を重ね書きする方法を解説する

数名などの名前）だけしか参照できないのはに設計すると、少ないコーディング量で多くの予定です。

【リスト 7】階層構造の例（hierarch.j3c）→

import "c_revolv.j3c";class rod extends CRevolution {int rod(int length, int radius, int color) {volatile int i;vx[ 0] = length;vy[ 0] = 0;vx[ 1] = 0;vy[ 1] = 0;vx[ 2] = length - radius;vy[ 2] = radius;vx[ 3] = radius;vy[ 3] = radius;for (i=0; i < 4; i=i+1) vColor[i] = color;}
int def_shape(int color) {rod(250, 80, color);
Setup(2, 16);}
int INIT() {NewObject(3000,3000);
def_shape(5);ClearRegisters();
SetPosition();}int RUN() {RotPitch(1000, 176);
RotPitch(1000, -352);
RotPitch(1000, 176);
RotHead(2000, 240);
RotHead(2000, -480);
RotHead(2000, 240);
RotBank(1000, 1440);}// 22 度 / 秒でピッチ回転// 44 度 / 秒でピッチ回転// 22 度 / 秒でピッチ回転// 15 度 / 秒でヘッド回転// 30 度 / 秒でヘッド回転// 15 度 / 秒でヘッド回転// 18 度 / 秒でヘッド回転}
class GrandChild extends rod {int INIT () {def_shape(2);ClearRegisters();
RX = 250;
SetPosition();}}// RX - RB に 0 を代入// 初期位置と角度の設定→

class Child extends rod {int INIT () {SetPosition(); // 親から RX-RB で渡される初期位置と角度
def_shape(3);child(GrandChild, 150, 3000, 3000);}}

70

J3W for Linux 入門講座

class Parent extends rod {int INIT () {NewObject(3000, 3000);
def_shape(15);ClearRegisters();
RZ = 150;
RP = 720;
SetPosition();
ClearRegisters();
RX=250;child(Child, 150, 3000, 3000);
RX=250;
RY=50;
RH=720;child(Child, 150, 3000, 3000);
RY=-50;
RH=-720;child(Child, 150, 3000, 3000);
ClearRegisters();
RX=-50;
RY= 50;
RH=1080;child(Child, 150, 3000, 3000);
RY= -50;
RH=-1080;
child(Child, 150, 3000, 3000);}}// RX - RB に 0 を代入// 初期位置と角度の設定// RX - RB に 0 を代入// 子オブジェクト 1// 子オブジェクト 2// 子オブジェクト 3// RX - RB に 0 を代入// 子オブジェクト 4// 子オブジェクト 5class main {int INIT () {new(Parent, 150);// 共通の親を生成
NewObject(0, 0);// 視点用の物体の生成
ClearRegisters();// RX - RB に 0 を代入
RX = -900;// 位置の指定 9m 後方
SetPosition();// 位置と角度を視点に設定
See();// このオブジェクトが見る
BackgroundColor(0x844); // 背景色を設定
GraphMode();// グラフィックウインドウを開く}
int RUN() {volatile int key;
key = InKey();// キ−コ−ド入力
if (key == 0x1B) Stop(); // ESC キーで終了}
int EVENT() {}}j3w の内部構造の解説■ j3w の 3D エンジンの使用法
これまでj3wの3Dエンジン部分の概要を説明して【リスト A】3D アニメーションプログラム（my_3d.cpp）#include "scrnx.h"#include "spaceh3d.h"

きましたが、今回はj3wのソースを使って独自の3Dアニメーションのプログラムを作成してみましょう。

j3w-643/source/j3w/以下のファイルのうち、表Aの19ファイルを使用します。これらのファイルがj3wの 3D エンジンとなっています。

const int COLOR = 3;
TSpaceH3D sp(2, 50, 4000000);
ScrnX sc;
int tmp[16];THObj3D *eye, *p;// 物体の色// 空間生成// ウィンドウ生成// 頂点指定用// 物体のポインタ

リストA のプログラム my_3d.cpp と表A のファイルを作業用のディレクトリにコピーしてください。また、gccコマンドでコンパイルしようとすると、コマンドラインで指定するファイルが多く面倒ですから、Makefile（リストB）も用意します。リスト中の「⇒」は TAB を表します。空白（スペース）ではエラーになります。TAB を使う必要があるのは make コマン
ドの仕様です。作業用のディレクトリで次のように実行すると、my_3d という実行ファイルが作成されます。

make -f Makefile.my_3d
次のコマンドを入力すると実行できます。

./my_3d
単に3角形が回転するだけのプログラムです（画面A）。回転速度はCPUの速度で決まります。forルー
プ中の「p->Axis.rotate(3, 1, 2)」で回転を行っていますが、この部分を「p->Axis.move(Vector(x,y,z)) 」とすると、三角形は表示されるたびに「(x,y,z)」で指定した方向に平行移動します。
「eye->Axis.rotate(..)」、「eye->Axis.move(..)」とす
れば視点が移動します。

（水谷純）

int main() {sc.set_mode(1);sc.SetPaletteEntry(255, 60<<8, 40<<8, 90<<8);
sp.set_screen(&sc);
int n = sp.append_object(0, 0);eye = sp.get_object(n);eye->Axis.set_origin(-400, 0, 0);eye->Axis.attitude(0, 0, 0);
sp.set_eye(eye);n = sp.append_object(20, 10);p = sp.get_object(n);p->Axis.set_origin(0, 0, 0);p->Axis.attitude(0, 0, 0);
p->Polygon.Vertex.Add(Vector(0,0,200));
p->Polygon.Vertex.Add(Vector(0,200,-200));
p->Polygon.Vertex.Add(Vector(0,-200,-200));
tmp[0] = 0; tmp[1] = 1; tmp[2] = 2;
p->Polygon.Add(3, COLOR, tmp);
tmp[0] = 2; tmp[1] = 1; tmp[2] = 0;
p->Polygon.Add(3, COLOR-1, tmp);for(int i=0; i<10000; i++) {p->Axis.rotate(3, 1, 2);
sp.display(0);sc.update();}}// 背景色の指定// スクリーンの登録// 視点の生成// 視点の取得// 視点の位置// 視点の姿勢// 視点の登録// 物体の生成// 物体の取得// 物体の位置// 物体の姿勢// 物体の頂点登録// 物体の頂点登録// 物体の頂点登録// ポリゴン頂点指定// ポリゴン登録// ポリゴン頂点指定// ポリゴン登録// 物体の回転// 3D 空間の構築// 表示【リスト B】Makefile（Makefile.my_3d）【表 A】使用する関数

TARGETNAME = my_3d

ヘッダファイルC++ ファイル

axis.haxis.cpp

hobj3d.hhobj3d.cpp

misc3d.hmisc3d.cpp

object3d.hobject3d.cpp

pal256.hpal256.cpp

SRCS = axis.cpp hobj3d.cpp \scrnx.cpp misc3d.cpp object3d.cpp spaceh3d.cpp \tpolygon.cpp vertex.cpp pal256.cpp my_3d.cpp

scrnx.hscrnx.cpp

LIBS = -lm -lX11

spaceh3d.hspaceh3d.cpp

OBJS = $(SRCS:.cpp=.o)tpolygon.htpolygon.cpp

vertex.h

vertex.cpp

screen.h【画面 A】リスト A の実行例

CC= g++CFLAGS = -O2 -Wall -DLINUXCFLAGS += -I/usr/X11R6/include -L/usr/X11R6/lib.SUFFIXES: .c .cpp .o.cpp.o :⇒${CC} ${CFLAGS} -c $<all : ${TARGETNAME} ${TARGETNAME_ASM}${TARGETNAME} : $(OBJS)⇒$(CC) ${CFLAGS} -o ${TARGETNAME} $(OBJS) $(LIBS)
clean:⇒⇒⇒

rm -f corerm -f *.orm -f ${TARGETNAME}

注）⇒ は TAB を表します。空白（スペース）ではエラーになります。

2001.12 Linux Japan71