- MTLファイルを読み込む -
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構造体に対して操作すれば、
アドレスを代入した別の配列からも参照できる、というわけです。


inserted by FC2 system