BrightObjectで使用したMTLファイルを読み込む関数を紹介します。
[ 構造体・定数定義 ]
#define BUFFER_LENGTH 200
//マテリアルデータ(Mtl形式用)
struct Mtl
{
char * name; // マテリアル名
Color ka; // 環境光
Color kd; // 拡散反射光(とりあえず拡散反射光を glColor3f() で使用する)
Color ks; // 鏡面反射光
float ns; // 鏡面反射光が働く角度
char * map_kd; // テクスチャ画像のファイル名
BMPFile * bmpData; //map_kdのファイル名のBMPファイルの実データ
};
[ 関数のソース ]
//
// Mtlファイルの読み込み(鏡面反射とか環境光などの情報)
//
int LoadMtl(const char * filename, TLO * tlo)
{
FILE * fp; //mtlファイルへのポインタ
char line[BUFFER_LENGTH]; //mtlファイルの1行分のデータを格納する(fgetsで読み込む)
char name[BUFFER_LENGTH];
Color color;
float nsData; //mtlファイルから読み込んだNsの数値
char mapName[32]; //mtlファイルから読み込んだテクスチャ画像のファイル名(拡張子含めて半角31文字まで)
Mtl * curr_mtl;
int newmtlCount = 0; //newmtlが書かれている数
// ファイルを開く
fp = fopen(filename, "r" );
if(fp == NULL)
{
//エラー処理
}
while(fgets(line, BUFFER_LENGTH, fp) != NULL)
{
if (strncmp(line, "newmtl", 6) == 0)
{
newmtlCount++;
}
}
//ファイルポインタをファイルの先頭に戻す
rewind(fp);
// Mtl配列を初期化(ひとまず固定サイズの配列を割り当てる)
tlo->num_materials = 0;
tlo->materials = (Mtl **)calloc( newmtlCount, sizeof(Mtl *) );
if(tlo->materials == NULL)
{
//エラー処理
}
// ファイルから1行ずつ読み込み
while(fgets(line, BUFFER_LENGTH, fp) != NULL)
{
// マテリアルデータの追加
if (strncmp(line, "newmtl", 6) == 0)
{
// テキストを解析
sscanf(line, "newmtl %s", name);
if (strlen(name) == 0)
continue;
// マテリアルデータの作成
curr_mtl = (Mtl *)calloc(1, sizeof(Mtl));
if(curr_mtl == NULL)
{
//エラー処理
}
curr_mtl->name = (char *)calloc(strlen(name) + 1, sizeof(char));
if(curr_mtl->name == NULL)
{
//エラー処理
}
curr_mtl->map_kd = NULL; //後の判定のためにテクスチャファイル名領域のアドレスを一応NULLで初期化
strcpy(curr_mtl->name, name);
// newmtlを読んだ時点でマテリアルデータのアドレスを配列に記録
tlo->materials[tlo->num_materials] = curr_mtl;
tlo->num_materials++;
}
//テクスチャ画像のファイル名の取得
if (strncmp(line, "map_Kd", 6) == 0)
{
sscanf(line, "map_Kd %s", mapName);
curr_mtl->map_kd = (char *)calloc(strlen(mapName) + 1, sizeof(char));
if(curr_mtl->map_kd == NULL)
{
//エラー処理
}
strcpy(curr_mtl->map_kd, mapName);
}
// 反射特性データの読み込み
if ( line[0] == 'K' )
{
//環境光(Ka)
if ( line[1] == 'a' )
{
// テキストを解析
sscanf( line, "Ka %f %f %f", &color.r, &color.g, &color.b );
//環境光(Ka)のデータを記録
if (curr_mtl)
curr_mtl->ka = color;
}
//拡散反射光(Kd)
if ( line[1] == 'd' )
{
// テキストを解析
sscanf( line, "Kd %f %f %f", &color.r, &color.g, &color.b );
// 拡散反射特性(Kd)を記録
if (curr_mtl)
curr_mtl->kd = color;
}
//鏡面反射光
if ( line[1] == 's' )
{
// テキストを解析
sscanf( line, "Ks %f %f %f", &color.r, &color.g, &color.b );
// 拡散反射特性(Kd)を記録
if (curr_mtl)
curr_mtl->ks = color;
}
}
//鏡面反射角度の読み込み
if(line[0] == 'N' && line[1] == 's')
{
sscanf(line, "Ns %f", &nsData);
if (curr_mtl)
curr_mtl->ns = nsData;
}
}
// ファイルを閉じる
fclose(fp);
return 0;
}
読み込み方はOBJファイルの読み込みと同じような形です。
つまり、while文でfgets()でファイルの1行分のデータを読み込み、
line[]配列の先頭部分でどの行を読んだのかを判断し、sscanf()で値を取得します。
上記のソースでは、Mtl構造体にデータ領域の作成・初期化をした後、
Mtl構造体のアドレスを別の配列に格納しています。こうすることで、Mtl構造体に対して操作すれば、
アドレスを代入した別の配列からも参照できる、というわけです。
|