読者です 読者をやめる 読者になる 読者になる

Crosswalk sdk サンプル - XSIDump

crosswalk sdk付属サンプルのXSIDumpを見ていく。

開始〜引数チェック

int main(int argc, char *argv[])
{

#ifdef CODEWARRIOR
	mwInit();    /* To initialize the C++ runtime */
#endif

#ifdef _PSX2

	//
	// Initialize file IO layer
	//
	
	// Use Soft's file io lib (SIPS2Comm)
	// PS2InitFileIO_Softimage();
	
	// Use sce Native file io
	 	PS2InitFileIO_Native();
	
#endif

    CXSIParser		*parser = new CXSIParser;
    int				mode = FORMAT_TEXT;
    SI_Error		result = SI_SUCCESS;

    using namespace std;
    
    // Argument checking
	
    if(argc < 2)
    {
        fprintf(stderr,"Wrong number of arguments : %s <input file> [-s|-i]\n\n-s : short information\n-i : file information only\n", argv[0]);
				getchar();
        exit(0);
    }

	if((argc > 2) && (strcmp(argv[2], "-s") == 0))
	{
		info = 1;
	}

	if((argc > 2) && (strcmp(argv[2], "-i") == 0))
	{
		info = 2;
	}

最初の2つのifdefで区切られた場所はそれぞれの環境化で必要な初期化。
vc++でやる分には無関係なので気にしなくていい。
ちなみに両方とも家庭用ゲーム機ソフトの開発環境関連のもの。

次にdotXSIファイルのパーサインスタンスの作成と引数チェック。
引数の数が足らないと使用方法を出力するが、それを見てみると

 -i dotXSIファイル でdotXSIファイルのフォーマットやバージョン
 -s dotXSIファイル で上記+簡易的なオブジェクト構造
(オプションなし) dotXSIファイル で上記+詳細なオブジェクト構造

という情報を標準出力に表示する。

ファイルの解析、読み込み、片付けの流れ

    // let's open the file using CXSIParser::Open

	
    parser->SetOpenMode(OPEN_READ);

    CSIBCString l_lFilename;
    l_lFilename = _SI_TEXT(argv[1]);
    
    _SI_CALL(parser->Open(l_lFilename), "CXSIParser::Open");
    if(result == SI_SUCCESS)
    {
        _SI_CALL(parser->Read(), "CXSIParser::Read");
        if(result == SI_SUCCESS)
        {
            _SI_CALL(parser->Close(), "CXSIParser::Close");
			
			// let's dump the .XSI file information
			_SI_CALL(dumpXSIFileInformation(*parser), "dumpXSIFileInformation");
        }
        else
        {
            fprintf(stderr, "Error reading the file\n");
            // let's attempt to close the file
            parser->Close();
        }
    }
    else
    {
        fprintf(stderr, "%s could not be open for reading \n", argv[1]);
    }
	
	delete parser;

パーサインスタンスのファイル操作モードの設定。
ファイル名の設定。CSIBCStringは可変長文字列。
マクロを使った関数呼び出しと返り値チェック。
マクロ内部は以下のとおり。

//_SI_CALLの中身。引数xは関数名、yはエラー時のエラーメッセージ。
#define _SI_CALL(x,y) { if (result==SI_SUCCESS)	{ result = x;if(result != SI_SUCCESS){_ERRMSG(y);}}}

ファイルオープン(ファイル名)。
ファイル読み込み。
ファイル閉じる。ファイルのデータは読み込んだら、いつでもファイルを閉じられる。
ファイル情報出力。詳細は後述。
パーサオブジェクト削除。

ファイルフォーマット情報出力と詳細オブジェクト構造呼び出し

SI_Error dumpXSIFileInformation(CXSIParser &in_Parser)
{
	SI_Error	result = SI_SUCCESS;

	// first we dump the file information (header)

	fprintf(stderr, "=============================================================\n");
	fprintf(stderr, "%s header information \n", in_Parser.FileName().GetText());
	fprintf(stderr, "File version : %d.%d\n", in_Parser.GetdotXSIFileVersionMajor(), in_Parser.GetdotXSIFileVersionMinor());

	if(in_Parser.GetdotXSIFormat() == FORMAT_TEXT)
	{
		fprintf(stderr, "Format       : TEXT\n");
	}
	else if(in_Parser.GetdotXSIFormat() == FORMAT_BINARY)
	{
		fprintf(stderr, "Format       : BINARY\n");
	}

	if(info < 2)
	{
		fprintf(stderr, "=============================================================\n");
		fprintf(stderr, "dumping templates and parameters \n");
		fprintf(stderr, "=============================================================\n");

		_SI_CALL(dumpXSITemplatesInformation(in_Parser, in_Parser.dotXSITemplate(), 0), "dumpXSITemplatesInformation");
	}

	return result;
}

main関数で呼ばれるファイル情報出力部分の詳細処理。
ファイル名とdotXSIフォーマットのバージョン出力。
ファイルがテキスト形式かバイナリ形式か出力。
最初のオプションでオプションなし、または-sをつけた場合はオブジェクト構造出力処理に入る。

オブジェクト構造出力

SI_Error dumpXSITemplatesInformation(CXSIParser &in_Parser, CdotXSITemplates *in_Templates, int spaces)
{
	SI_Error			result = SI_SUCCESS;
	SI_Int				loop, paramLoop, arrayLoop;
	CdotXSITemplate		*pTemplate;
	CdotXSIParam		*pParam;
	SI_TinyVariant		pValue;
	CSIBCString			tmpString;

	for(loop = 0; loop < in_Templates->GetCount(); loop++)
	{
		in_Templates->Item(loop, &pTemplate);

		if(pTemplate != NULL)
		{
			INDENT;			
			fprintf(stderr, "--------------------------------------------------------\n");
			INDENT;
			fprintf(stderr, "Template name   : %s \n", pTemplate->Name().GetText());
			INDENT;
			fprintf(stderr, "Instance name   : %s \n\n", pTemplate->InstanceName().GetText());


			if(info == 0)
			{
				// now we dump the parameters information

				for(paramLoop = 0; paramLoop < pTemplate->Params().GetCount(); paramLoop ++)
				{
					pTemplate->Params().Item(paramLoop, &pParam);
					INDENT;
					fprintf(stderr, "(");
					pParam->GetValue(&pValue);

					switch(pValue.variantType)
					{
						case SI_VT_BOOL		: fprintf(stderr,"BOOL"); tmpString.SetText(pValue.boolVal); break;
						case SI_VT_BYTE		: fprintf(stderr,"BYTE"); tmpString.SetText(pValue.bVal); break;
						case SI_VT_UBYTE	: fprintf(stderr,"UBYTE"); tmpString.SetText(pValue.ubVal); break;
						case SI_VT_SHORT	: fprintf(stderr,"SHORT"); tmpString.SetText(pValue.sVal); break;
						case SI_VT_USHORT	: fprintf(stderr,"USHORT"); tmpString.SetText(pValue.usVal); break;
						case SI_VT_INT		: fprintf(stderr,"INT"); tmpString.SetText(pValue.nVal); break;
						case SI_VT_UINT		: fprintf(stderr,"UINT"); tmpString.SetText((SI_Int) pValue.unVal); break;
						case SI_VT_FLOAT	: fprintf(stderr,"FLOAT"); tmpString.SetText((SI_Float)pValue.fVal); break;
						case SI_VT_DOUBLE	: fprintf(stderr,"DOUBLE"); tmpString.SetText((SI_Float) pValue.dVal); break;
						case SI_VT_LONG		: fprintf(stderr,"LONG"); tmpString.SetText((SI_Int)pValue.lVal); break;
						case SI_VT_ULONG	: fprintf(stderr,"ULONG"); tmpString.SetText((SI_Int) pValue.ulVal); break;

						case SI_VT_PBOOL	: fprintf(stderr,"PBOOL"); break;
						case SI_VT_PBYTE	: fprintf(stderr,"PBYTE"); break;
						case SI_VT_PUBYTE	: fprintf(stderr,"PUBYTE"); break;
						case SI_VT_PSHORT	: fprintf(stderr,"PSHORT"); break;
						case SI_VT_PUSHORT	: fprintf(stderr,"PUSHORT"); break;
						case SI_VT_PINT		: fprintf(stderr,"PINT"); break;
						case SI_VT_PUINT	: fprintf(stderr,"PUINT"); break;
						case SI_VT_PFLOAT	: fprintf(stderr,"PFLOAT"); break;
						case SI_VT_PDOUBLE	: fprintf(stderr,"PDOUBLE"); break;
						case SI_VT_PLONG	: fprintf(stderr,"PLONG"); break;
						case SI_VT_PULONG	: fprintf(stderr,"PULONG"); break;
						case SI_VT_PCHAR	: fprintf(stderr,"PCHAR"); tmpString.SetText(pValue.p_cVal); break;
						case SI_VT_PPCHAR	: fprintf(stderr,"PPCHAR"); break;
						case SI_VT_PVOID	: fprintf(stderr,"PVOID"); break;	
					}
					fprintf(stderr,")");

					fprintf(stderr, " %s	: ", pParam->Name().GetText());

					switch(pValue.variantType)
					{
						case SI_VT_BOOL		: 
						case SI_VT_BYTE		: 
						case SI_VT_UBYTE	: 
						case SI_VT_SHORT	: 
						case SI_VT_USHORT	: 
						case SI_VT_INT		: 
						case SI_VT_UINT		: 
						case SI_VT_FLOAT	: 
						case SI_VT_DOUBLE	: 
						case SI_VT_LONG		: 
						case SI_VT_ULONG	: 
						case SI_VT_PCHAR	: 
							fprintf(stderr, "%s\n", tmpString.GetText()); break;

						case SI_VT_PBOOL	: 
						case SI_VT_PBYTE	: 
						case SI_VT_PUBYTE	: 
						case SI_VT_PSHORT	: 
						case SI_VT_PUSHORT	: 
						case SI_VT_PINT		: 
						case SI_VT_PUINT	: 
						case SI_VT_PFLOAT	: 
						case SI_VT_PDOUBLE	: 
						case SI_VT_PLONG	: 
						case SI_VT_PULONG	: 
						case SI_VT_PPCHAR	: 
							fprintf(stderr, "\n");
							for(arrayLoop = 0; arrayLoop < pValue.numElems; arrayLoop ++)
							{
								INDENT;
								switch(pValue.variantType)
								{
									case SI_VT_PBOOL	: tmpString.SetText(pValue.p_boolVal[arrayLoop]); break;
									case SI_VT_PBYTE	: tmpString.SetText(pValue.p_bVal[arrayLoop]); break;
									case SI_VT_PUBYTE	: tmpString.SetText(pValue.p_ubVal[arrayLoop]); break;
									case SI_VT_PSHORT	: tmpString.SetText(pValue.p_sVal[arrayLoop]); break;
									case SI_VT_PUSHORT	: tmpString.SetText(pValue.p_usVal[arrayLoop]); break;
									case SI_VT_PINT		: tmpString.SetText(pValue.p_nVal[arrayLoop]); break;
									case SI_VT_PUINT	: tmpString.SetText((SI_Int) pValue.p_unVal[arrayLoop]); break;
									case SI_VT_PFLOAT	: tmpString.SetText(pValue.p_fVal[arrayLoop]); break;
									case SI_VT_PDOUBLE	: tmpString.SetText((SI_Float) pValue.p_dVal[arrayLoop]); break;
									case SI_VT_PLONG	: tmpString.SetText((SI_Int)pValue.p_lVal[arrayLoop]); break;
									case SI_VT_PULONG	: tmpString.SetText((SI_Int) pValue.p_ulVal[arrayLoop]); break;
									case SI_VT_PPCHAR	: tmpString.SetText(pValue.pp_cVal[arrayLoop]); break;
								}

								fprintf(stderr, "%s\t", tmpString.GetText());
								if((arrayLoop % 3) == 2)
									fprintf(stderr, "\n");
							}
							fprintf(stderr, "\n");
							break;
						case SI_VT_PVOID	: INDENT; fprintf(stderr, "VOID values \n"); break;
							break;

					}
				}
			}

			fprintf(stderr, "\n");

		}
		else
		{
			fprintf(stderr, "Problematic template \n");
		}

		_SI_CALL(dumpXSITemplatesInformation(in_Parser, &pTemplate->Children(), spaces + 1), "dumpXSITemplatesInformation");
	}

	return result;
}

深くネストした構造は、

  • 各データを定義した手プレート数ループ
    • テンプレートが存在したら
      • 実行時のオプションで-sオプションをつけなかったら(つけるとここより深い部分には入らない)
        • テンプレートに含まれる値の数ループ
          • 値の型出力
          • 値の出力
            • 値が配列系だったら配列数ループ
              • 値の出力
    • 現在のテンプレートをルートとして同じ関数に渡し、再帰的にオブジェクト構造を出力する

という構造になっている。
再帰的に呼び出す場所のネスト上の階層が間違っている気がするが、まあdotXSIファイルが正しいファイルならうまく動くので気にしない。

まとめ

このサンプルはXSIファイルをXMLのような構造で保持するクラスを使ってdotXSIファイルをダンプする。
実際にdotXSI形式から使いやすい形式にコンバートする際には、各テンプレートごとのデータを扱うクラスがあるので、
あまり使用する機会はないかもしれないが、もしそのクラス群で満足できなかったらこのXSIParserを使って自作したらいいでしょう。


次回は2つ目のサンプルSLTestを見る。
ソースが4500行もあるので、最初の初期化と3Dオブジェクトの頂点データ付近の場所だけ見る。