/*
 *	clipafxb.c
 *
 *	AfterEffectsアニメーションシーケンサ(バイナリ形式)
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2016 Naoyuki Sawa
 *
 *	* Thu Apr 28 21:03:22 JST 2016 Naoyuki Sawa
 *	- 1st リリース。
 *	* Sat Apr 30 21:45:42 JST 2016 Naoyuki Sawa
 *	- AfxBin_Load(),AfxBin_Draw()を追加しました。
 *	* Mon May 02 21:51:14 JST 2016 Naoyuki Sawa
 *	- バイナリ形式のアニメーションファイルでは、ST_AfxSeq.layers[],及び,ST_AfxLyr.pAfxSeqに、オフセットを格納するようにしました。
 *	  これまでは変換時のポインタをそのまま格納しており、ロード時に上書きするので動作上は問題無いものの無駄な、情報となっていました。
 *	- オフセットを格納するようにした事により、AfxBin_Load()において、上記のフィールドをポインタに書き換える必要が無くなりました。
 *	  AfxBin_Draw()では、オフセットからツリーを辿っていけるからです。
 *	- このように変更した理由は、今後、バイナリ形式のアニメーションファイルをROM化したいと思っているからです。
 *	  今はまだAfxBin_Load()がST_AfxLyr.footageを書き換えているのでROM化出来ないのですが、今後何とか工夫してみたいと思っています。
 *	  今回の変更は、そのための一歩です。
 *	* Thu May 05 21:24:20 JST 2016 Naoyuki Sawa
 *	- ROM化出来るようになりました。
 *	  AfxBin_Draw()が、ファイルイメージをそのまま処理出来るようになりました。
 *	  それに伴って、AfxBin_Load()は不要になったので、削除しました。
 *	- AfxBin_ClearFrameCache()を追加しました。
 *	  AfxBin_Load()を削除したことにより、フレームキャッシュをクリアすべきタイミングを、当モジュールが判定する事が出来なくなったからです。
 *	  詳細は、clipafxb.c内の、AfxBin_ClearFrameCache()関数内のコメントを参照して下さい。
 *	- USE_AFXBIN_COMPRESSを定義しなければ、AfxBin_Compress_*()を含めないようにしました。
 *	  USE_AFXBIN_EXPANDを定義しなければ、AfxBin_Expand()を含めないようにしました。
 *	  P/ECEではメモリ節約のために、これらの関数を含めないようにしました(含める事も可能ではあります)。
 *	- AfxBin_DrawNo()を追加しました。
 *	- 今回の変更で、当モジュールの機能はほぼ完成したと思います。
 *	  ただし、以下の問題が残っています。
 *	  ×clipafxs.hとclipafxb.hのモジュール分けが少々歪である。
 *	  ×AfxBin_Draw()がST_AfxSeq構造体をフィールドの意味を読み替えて使用しており不自然な実装である。
 *	  いずれも動作上の問題は無いのですが、少々判り辛いです。
 *	  まずは動作検証を優先して、動作が安定した後で、上記の修正を検討しようと思います。
 *	* Fri May 06 21:58:10 JST 2016 Naoyuki Sawa
 *	- AfxBin_Draw_GetFootage()を追加しました。
 *	  詳細は、「使用例」を参照して下さい。
 *	* Tue May 10 22:06:16 JST 2016 Naoyuki Sawa
 *	- 既存の関数AfxSeqNo_GetAfxSeq()を、処理内容はそのままでAfxBin_GetNo()に名前変更し、ローカル関数⇒グローバル関数に変更しました。
 *	  上記の変更を行った理由は、アプリケーションがST_AfxSeq構造体(のバイナリ形式)を参照して、直接トラバースして様々な情報を取得したいケースが有るからです。
 *	  ちなみに以前、clipanms.cモジュールやclipncss.cモジュールでも同様の要件が有り、その時は情報取得用の個別の関数(AnmSeqNo_GetLen,NcsSeqNo_GetLen)を設けたのですが、
 *	  ST_AfxSeq構造体の場合は情報の種類が多いので、情報取得用の個別の関数を沢山追加するよりも、ST_AfxSeq構造体を直接返す方が良いと思い、このように変更する事にしました。
 *	  clipanms.cモジュールやclipncss.cモジュールの対応方法と、当モジュールの対応方法に、統一性が無いのは、上記の理由によるものです。
 *	* Thu May 12 22:56:34 JST 2016 Naoyuki Sawa
 *	- ST_AfxBin_Draw_GetFootage_Param._SprNo_Maxを削除しました。
 *	  clipenm.cモジュールにEnmDef_GetMax()等を追加した事によって列挙型の最大値が実行時に取得出来るようになったので、アプリケーションから渡す必要は無くなったからです。
 *	* Tue May 17 21:36:02 JST 2016 Naoyuki Sawa
 *	- AfxBin_Draw_GetFootage()の処理を変更しました。
 *	  Windows環境ではメモリに余裕が有るので、フッテージの素材ファイル名から、スプライト(又はテクスチャ)番号への変換結果を、キャッシュする事にしました。
 *	  結果は変わりません。
 *	* Mon May 23 22:46:16 JST 2016 Naoyuki Sawa
 *	- ST_AfxSeq構造体とST_AfxLyr構造体に、nameフィールドを追加しました。
 *	  追加した理由は、今後コンポジションやレイヤの差し替えを行う場合に、実行時に名前の情報が必要になると思ったからです。
 *	  現時点ではまだ、追加したnameフィールドを利用していませんが、今後利用する予定です。	⇒{{2016/05/23追記:対応しました。}}
 *	- 上記の変更に伴い、clipafxs.c,及び,clipafxb.cのコードを、大幅に変更しました。
 *	  アプリケーションの観点で変わった点は、fnLoad関数へのコンポジション名の引き渡しが、個別の関数引数ではなく、pAfxSeq->name経由で参照するようになった点のみです。
 *	* Mon May 23 23:04:00 JST 2016 Naoyuki Sawa
 *	- 追加したnameフィールドを、アプリケーションが利用するための仕組みを追加しました。
 *	  1. 当モジュールの描画関数に、fnFilter引数を追加しました。アプリケーション定義のフィルタ関数を指定する事で、トラバース処理に割り込んでコンポジション単位の差し替えが可能です。
 *	  2. アプリケーション定義のfnDraw関数に、layerDepth,layerPath引数を追加しました。アプリケーション定義のfnDraw関数の中でこれらの情報を参照して、描画直前での差し替えが可能です。
 *	- まだ、上記の仕組みの使用例を書いていません。	←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←※TODO:
 *	* Fri May 27 23:20:42 JST 2016 Naoyuki Sawa
 *	- AfxBin_Dump()を追加しました。
 *	  USE_AFXBIN_DUMPを定義しなければ、AfxBin_Dump()を含めないようにしました。
 *	* Sat May 28 21:20:19 JST 2016 Naoyuki Sawa
 *	- AfxBin_Dump()を使って、/clip/tool/dpafxbin/ に'ダンプモード'を追加しました。
 *	  詳細は、/clip/tool/dpafxbin/app.c を参照して下さい。
 *	  当モジュールのコードには変更有りません。
 *	* Mon Aug 15 21:37:25 JST 2016 Naoyuki Sawa
 *	- clipenm.cにEnmDef_GetVal_UseCompar()を追加した事に伴い、AfxBin_Draw_GetFootage()内のフッテージの検索処理に、EnmDef_GetVal_UseCompar()を使用するように変更しました。
 *	  動作結果には変更有りません。
 *	* Fri Sep 09 20:41:26 JST 2016 Naoyuki Sawa
 *	- P/ECEに加えて、Win64でもAfxBin_Compress_*(),AfxBin_Expand()は未対応にしました。
 *	  これらの関数はポインタが32ビットである事に強く依存しており、64ビット環境でも動作するように変更する事が困難だからです。
 *	  これらの関数は32ビット環境で作成したツールでしか使用しないので、64ビット環境で使えなくても問題有りません。
 *	* Fri Sep 09 21:13:53 JST 2016 Naoyuki Sawa
 *	- 64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
 *	  変更を行った理由は、以下の通りです。
 *	- これまでは、バイナリ形式を扱う関数では、ST_AfxLyr,ST_AfxSeq構造体のポインタ型フィールドを整数フィールドと見なして使用していました。
 *	  こうなっている理由は必然ではなく、最初にclipafxs.cを実装した後で、思い付きでclipafxb.cを実装した際の成り行きでこうなっていたもので、本当は望ましくありませんでした。
 *	  望ましい実装方法ではないのですが、32ビット版では動作上は問題なかったので、そのままにしていました。
 *	- しかし、64ビット版では、ポインタ型と整数型のサイズが異なるため、『dpafxbin.exe』で作成したデータを読み込んで使用しようとすると、構造体サイズが違って使用出来ない問題が生じました。
 *	  そのため、明示的にバイナリ形式を表す構造体を定義する必要が生じました。
 *	- 上記の通り、今回の変更は、64ビット対応のために必要となったものです。
 *	  32ビット版はこれまでのままでも構わないのですが、32ビット版においても明示的にバイナリ形式を表す構造体を使用する方が望ましい事と、32ビット版と64ビット版でコードを共通化したいので、32ビット版にも今回の変更を適用する事にしました。
 *	  32ビット版の観点からは、ポインタ型フィールドを整数にキャストする処理が不要になっただけであり、内部処理としては変わっていません。
 *	- (int)値を(void*)にキャストして整数データとして使用する箇所で、64ビット版ではコンパイラの警告が出ていた問題を回避しました。
 *	  詳細は、AfxBin_Draw_GetFootage()内のコメントを参照して下さい。
 *	* Sat Sep 10 21:46:35 JST 2016 Naoyuki Sawa
 *	- ファイル名の'-'以降はテクスチャ名やスプライト名に含めないようになった事に伴い、AfxBin_Draw_GetFootage()にて'-'以降を除外してスプライト(又はテクスチャ)を検索するように変更しました。
 *	  詳細は、/clip/test.win/grp/MkTexNo.bat，及び，/clip/DxlibHelper.cpp の同日のコメントを参照して下さい。
 */
#include "clip.h"
#ifdef  USE_AFXBIN_COMPRESS
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
//■MkAfxSeqXml.jsxが出力したXML形式のアニメーションファイル(複数可)を読み込み、(複数ならば)統合して、バイナリ形式のアニメーションファイルに保存する。
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
/****************************************************************************
 *	構造体
 ****************************************************************************/
typedef struct _ST_AfxBin_Compress_Param {
	struct obstack		oTBL;		//アドレステーブル出力バッファ
	struct obstack		o;		//出力バッファ
	ght_hash_table_t*	ht_AfxSeq;	//アニメーション名⇒アニメーション
	GPtrArray*		ar_name;	//文字列を重複無く登録する配列		⇒AfxBin_Compress_v()にて、文字列テーブルを出力する時に、出力バッファ内の文字列の位置(int)に置き換える。
} ST_AfxBin_Compress_Param;
/****************************************************************************
 *	ローカル関数
 ****************************************************************************/
static int AfxBin_Compress_AddName(ST_AfxBin_Compress_Param* param, const char* name) {
	int i;
	//文字列を重複無く登録する。
	for(i = 0; i < param->ar_name->len; i++) {
		if(!strcmp(g_ptr_array_index(param->ar_name, i), name)) { break; }
	}
	if(i == param->ar_name->len) {
		name = strdup(name);	//引数nameが指す文字列を複製して格納する必要が有ります。引数nameが指す文字列は、AfxBin_Compress_v()内のAfxSeq_Load()が処理を返した時点で消えるからです。
		if(!name) { DIE(); }
		g_ptr_array_add(param->ar_name, (void*)name);	//キャストはconst警告抑制のため。
	}
	//この文字列が登録されている、配列インデクスを返す。
	return i;
}
/*--------------------------------------------------------------------------*/
static void AfxBin_Compress_AddLyrName(ST_AfxLyr* pAfxLyr, ST_AfxBin_Compress_Param* param);	//前方参照
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static void AfxBin_Compress_AddSeqName(ST_AfxSeq* pAfxSeq, ST_AfxBin_Compress_Param* param) {
	int iLayer;
	//コンポジション名の文字列を重複無く登録し、このコンポジション名が登録された配列インデクスを格納する。
	pAfxSeq->name = (char*)AfxBin_Compress_AddName(param, pAfxSeq->name);	//(char*)型のフィールドに(int)型の値を書き込む。同じサイズなので問題無い。	pAfxSeq->nameが指していた文字列を開放する必要は無い。pAfxSeq->nameはpAfxSeqと一緒にメモリ確保されているからです。詳細はclipafxs.cのAfxSeq_LoadComp()の実装を参照せよ。
	//各レイヤについて…
	for(iLayer = 0; iLayer < pAfxSeq->nLayers; iLayer++) {
		ST_AfxLyr* pAfxLyr = pAfxSeq->layers[iLayer];
		//各レイヤについても同様に、レイヤ名の文字列を配列インデクスに変換する処理を行う。
		AfxBin_Compress_AddLyrName(pAfxLyr, param);
	}
}
/*--------------------------------------------------------------------------*/
static void AfxBin_Compress_AddLyrName(ST_AfxLyr* pAfxLyr, ST_AfxBin_Compress_Param* param) {
	//レイヤ名の文字列を重複無く登録し、このレイヤ名が登録された配列インデクスを格納する。
	pAfxLyr->name = (char*)AfxBin_Compress_AddName(param, pAfxLyr->name);	//(char*)型のフィールドに(int)型の値を書き込む。同じサイズなので問題無い。	pAfxLyr->nameが指していた文字列を開放する必要は無い。pAfxLyr->nameはpAfxLyrと一緒にメモリ確保されているからです。詳細はclipafxs.cのAfxSeq_LoadLayer()の実装を参照せよ。
	//子階層のコンポジションが有れば…
	if(pAfxLyr->pAfxSeq) {
		//子階層のコンポジションについても同様に、コンポジション名の文字列を配列インデクスに変換する処理を行う。
		AfxBin_Compress_AddSeqName(pAfxLyr->pAfxSeq, param);
	}
}
/*--------------------------------------------------------------------------*/
static void AfxBin_Compress_fnLoad(ST_AfxSeq* pAfxSeq, void* user_data) {
	ST_AfxBin_Compress_Param* param = user_data;
	//アニメーション名⇒アニメーションを登録する。
	if(ght_insert(param->ht_AfxSeq,
	                     pAfxSeq,
	              strlen(pAfxSeq->name) + 1/*nul*/,
	                     pAfxSeq->name)) {
		error(EXIT_FAILURE, 0, "アニメーション名が重複しています。(%s)", pAfxSeq->name);
	}
	//コンポジション名とレイヤ名の文字列を重複無く登録し、名前が登録された配列インデクスを格納する。
	AfxBin_Compress_AddSeqName(pAfxSeq, param);
}
/*--------------------------------------------------------------------------*/
static int AfxBin_Compress_fnGetFootage(const char* fileName, void* user_data) {
	ST_AfxBin_Compress_Param* param = user_data;
	//素材のファイル名の文字列を重複無く登録し、この素材のファイル名が登録された配列インデクスを返す。
	return AfxBin_Compress_AddName(param, fileName);
}
/*--------------------------------------------------------------------------*/
static int AfxBin_Compress_Align(ST_AfxBin_Compress_Param* param) {
	//ワード境界まで進めて、ワード境界まで進めた結果のバッファ位置を返す。
	for(;;) {
		int pos = obstack_object_size(&param->o);	//現在のバッファ位置を取得する。
		if(!(pos & 3)) { return pos; }			//ワード境界ならば、ワード境界まで進めた結果のバッファ位置を返す。
		obstack_1grow(&param->o, 0);			//パディングを出力する。
	}
}
/*--------------------------------------------------------------------------*/
static int AfxBin_Compress_WriteAfxLyr(ST_AfxLyr* pAfxLyr, ST_AfxBin_Compress_Param* param);	//前方参照
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int AfxBin_Compress_WriteAfxSeq(ST_AfxSeq* pAfxSeq, ST_AfxBin_Compress_Param* param) {
	int posComp, iLayer;
	//ワード境界まで進めて、コンポジションの開始位置を取得する。
	posComp = AfxBin_Compress_Align(param);
	{
		//コンポジション名の出力バッファ内の文字列の位置(int)を取得し、コンポジションの開始位置からコンポジション名の文字列の位置へのオフセットを求める。	//param->ar_nameは、当関数が呼び出される前に、AfxBin_Compress_v()にて、文字列テーブルを出力する時に、出力バッファ内の文字列の位置(int)に置き換えられている。
		int ofsName = (int)g_ptr_array_index(param->ar_name, (int)pAfxSeq->name) - posComp;
		//                                                   ~~~~~~~~~~~~~~~~~~pAfxSeq->nameは、AfxBin_Compress_AddSeqName()にて、コンポジション名が登録された配列インデクス(int)に置き換えられている。
		//このコンポジション名が登録された配列インデクスを、コンポジションの開始位置からコンポジション名の文字列の位置へのオフセットで上書きする。
		pAfxSeq->name = (char*)ofsName;		//(char*)型のフィールドに(int)型の値を書き込む。同じサイズなので問題無い。
	}
	//コンポジション構造体のヘッダ部分を出力する。
	obstack_grow(&param->o, pAfxSeq, sizeof(ST_AfxSeq));
	//レイヤのオフセット配列のプレースホルダを出力する。
	obstack_blank(&param->o, sizeof(ST_AfxLyr*) * pAfxSeq->nLayers);	//この下の処理で各レイヤのオフセット値で上書きする。
	//各レイヤについて…
	for(iLayer = 0; iLayer < pAfxSeq->nLayers; iLayer++) {
		ST_AfxLyr* pAfxLyr = pAfxSeq->layers[iLayer];
		//レイヤを出力し、コンポジションの開始位置からレイヤの開始位置へのオフセットを求める。
		int ofsLayer = AfxBin_Compress_WriteAfxLyr(pAfxLyr, param) - posComp;
		if(ofsLayer <= 0) { DIE(); }	//0以下になる事は有り得ないはず。
		{
			//バッファ内の、コンポジションの位置を取得する。
			ST_AfxSeq* pAfxSeq2 = (ST_AfxSeq*)((char*)obstack_base(&param->o) + posComp);	//当関数の最初に取得しておいてはいけない。値を書き込む直前に取得する必要が有る。obstack_grow()によってバッファアドレスが変わる可能性が有るからです。
			//バッファ内のコンポジションの、レイヤのオフセットを上書きする。
			pAfxSeq2->layers[iLayer] = (ST_AfxLyr*)ofsLayer;	//(ST_AfxLyr*)型のフィールドに(int)型の値を書き込む。同じサイズなので問題無い。
		}
	}
	//コンポジションの開始位置を返す。
	return posComp;
}
/*--------------------------------------------------------------------------*/
static int AfxBin_Compress_WriteAfxLyr(ST_AfxLyr* pAfxLyr, ST_AfxBin_Compress_Param* param) {
	static void* buf;	//┬このバッファは開放されません。
	static int   buf_size;	//┘当関数は主に「XML形式のアニメーションファイルをバイナリ形式のアニメーションファイルに変換するPC上のツール」から使用する関数なので問題無いと思いますが、万一メモリの少ない実行環境でも使用する場合は注意して下さい。
	//
	int posLayer, size;
	char* p;
	//ワード境界まで進めて、レイヤの開始位置を取得する。
	posLayer = AfxBin_Compress_Align(param);
	{
		//レイヤ名の出力バッファ内の文字列の位置(int)を取得し、レイヤの開始位置からレイヤ名の文字列の位置へのオフセットを求める。				//param->ar_nameは、当関数が呼び出される前に、AfxBin_Compress_v()にて、文字列テーブルを出力する時に、出力バッファ内の文字列の位置(int)に置き換えられている。
		int ofsName = (int)g_ptr_array_index(param->ar_name, (int)pAfxLyr->name) - posLayer;
		//                                                   ~~~~~~~~~~~~~~~~~~pAfxLyr->nameは、AfxBin_Compress_AddLyrName()にて、レイヤ名が登録された配列インデクス(int)に置き換えられている。
		//このレイヤ名が登録された配列インデクスを、レイヤの開始位置からレイヤ名の文字列の位置へのオフセットで上書きする。
		pAfxLyr->name = (char*)ofsName;		//(char*)型のフィールドに(int)型の値を書き込む。同じサイズなので問題無い。
	}
	//レイヤ構造体のヘッダ部分を出力する。
	obstack_grow(&param->o, pAfxLyr, sizeof(ST_AfxLyr));
	//フレーム配列の圧縮効率を良くするために、各フレームの値を、前のフレームからの差分とする。
	//こうすると、(アニメーションデータの値によっても変わるが)、圧縮効率が二倍近く良くなるようだ。
	//多分、変化が少ないフィールドの値が、差分を取らなければ'0'固定だったり'100'固定だったりするところ、差分を取れば'0'固定に統一されるからだと思う。
	// - 本当は各フィールドのサイズ(short)単位で差分を取る方が自然なのだが、実装の都合のために(char)単位で差分を取る事にした。
	//   展開ストリームの展開単位が(char)なので、(char)単位の方が再生時に足し戻す処理が行い易いからです。
	//   また、実際に試した所、(short)単位で差分を取っても(char)単位で差分を取っても、圧縮効率の改善効果はほぼ同じようでした。
	p = (char*)&pAfxLyr->frames[pAfxLyr->nFrames - 1];	//最終フレームの1バイト目へのポインタ
	while(--p >= (char*)pAfxLyr->frames) {			//初回にプレインクリメントして最終フレームの手前のフレームの最後のバイトへのポインタになる。このポインタがフレーム配列の先頭アドレス以上である間…
		*(p + sizeof(ST_AfxFra)) -= *p;			//次のフレームの値を、前のフレームの値からの差分とする。
	}
	//フレーム配列を圧縮する。
	size = BytePairEncodingEncoder_Encode(pAfxLyr->frames, sizeof(ST_AfxFra) * pAfxLyr->nFrames, buf, buf_size);	//1st try
	if(size > buf_size) {
		buf = realloc(buf, size);
		if(!buf) { DIE(); }
		buf_size = size;
		BytePairEncodingEncoder_Encode(pAfxLyr->frames, sizeof(ST_AfxFra) * pAfxLyr->nFrames, buf, buf_size);	//2nd try
	}
	//圧縮したフレーム配列を出力する。
	obstack_grow(&param->o, buf, size);
	//子階層のコンポジションが有れば…
	if(pAfxLyr->pAfxSeq) {
		//コンポジションを出力し、レイヤの開始位置からコンポジションの開始位置へのオフセットを求める。
		int ofsComp = AfxBin_Compress_WriteAfxSeq(pAfxLyr->pAfxSeq, param) - posLayer;
		if(ofsComp <= 0) { DIE(); }	//0以下になる事は有り得ないはず。
		{
			//バッファ内の、レイヤの位置を取得する。
			ST_AfxLyr* pAfxLyr2 = (ST_AfxLyr*)((char*)obstack_base(&param->o) + posLayer);	//当関数の最初に取得しておいてはいけない。値を書き込む直前に取得する必要が有る。obstack_grow()によってバッファアドレスが変わる可能性が有るからです。
			//バッファ内のレイヤの、コンポジションのオフセットを上書きする。
			pAfxLyr2->pAfxSeq = (ST_AfxSeq*)ofsComp;	//(ST_AfxSeq*)型のフィールドに(int)型の値を書き込む。同じサイズなので問題無い。
		}
	}
	//このレイヤで描画する素材が有れば…
	if(pAfxLyr->sequenceLength) {
		//素材のファイル名の出力バッファ内の文字列の位置(int)を取得し、レイヤの開始位置から素材ファイル名の文字列の位置へのオフセットを求める。			//param->ar_nameは、当関数が呼び出される前に、AfxBin_Compress_v()にて、文字列テーブルを出力する時に、出力バッファ内の文字列の位置(int)に置き換えられている。
		int ofsName = (int)g_ptr_array_index(param->ar_name, pAfxLyr->footage) - posLayer;
		if(ofsName >= 0) { DIE(); }	//0以上になる事は有り得ないはず。
		{
			//バッファ内の、レイヤの位置を取得する。
			ST_AfxLyr* pAfxLyr2 = (ST_AfxLyr*)((char*)obstack_base(&param->o) + posLayer);	//当関数の最初に取得しておいてはいけない。値を書き込む直前に取得する必要が有る。obstack_grow()によってバッファアドレスが変わる可能性が有るからです。
			//バッファ内のレイヤの、このレイヤで描画する素材のベースIDを上書きする。
			pAfxLyr2->footage = ofsName;
		}
	}
	//レイヤの開始位置を返す。
	return posLayer;
}
/****************************************************************************
 *	グローバル関数
 ****************************************************************************/
void AfxBin_Compress_l(const char* binPath/*NULL可*/, const char* enmPath/*NULL可*/, ...) {	//引数=(binPath,enmPath,xmlPath,xmlPath,...,xmlPath,NULL)。最小は(binPath,enmPath,NULL)でも良い(無意味だが)。
	va_list ap;
	va_start(ap, enmPath);
	AfxBin_Compress_a(binPath, enmPath, ap);
	va_end(ap);
}
/*--------------------------------------------------------------------------*/
void AfxBin_Compress_a(const char* binPath/*NULL可*/, const char* enmPath/*NULL可*/, va_list ap) {	//ap={xmlPath,xmlPath,...,xmlPath,NULL}。最小はap={NULL}でも良い(無意味だが)。
	GPtrArray* ar_xmlPath = g_ptr_array_new();
	const char* xmlPath;
	do {
		xmlPath = va_arg(ap, const char*);
		g_ptr_array_add(ar_xmlPath, (void*)xmlPath);	//ここでは文字列を複製する必要は有りません。	//終端のNULLも追加します。	//キャストはconst警告抑制のため。
	} while(xmlPath);
	AfxBin_Compress_v(binPath, enmPath, (const char**)ar_xmlPath->pdata);
	g_ptr_array_unref(ar_xmlPath);
}
/*--------------------------------------------------------------------------*/
static int Label_compar(LIST_ENTRY* _x, LIST_ENTRY* _y) {
	//当関数の処理は、ght_hash_table.h/cモジュールの動作に依存しています。
	//外部からght_hash_table_t.le_iteratorの順番を並び替えても、動作上問題有りません。
	ght_hash_entry_t* x = CONTAINING_RECORD(_x, ght_hash_entry_t, le_iterator);
	ght_hash_entry_t* y = CONTAINING_RECORD(_y, ght_hash_entry_t, le_iterator);
//	return strcmp(   x->key_data, y->key_data);	//┬どちらか一方を選択して下さい。
	return strnatcmp(x->key_data, y->key_data);	//┘
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
void AfxBin_Compress_v(const char* binPath/*NULL可*/, const char* enmPath/*NULL可*/, const char* aXmlPath[]) {	//aXmlPath={xmlPath,xmlPath,...,xmlPath,NULL}。最小はaXmlPath={NULL}でも良い(無意味だが)。
	ST_AfxBin_Compress_Param param;
	const char* xmlPath;
	int i;
	ght_iterator_t it;
	ST_AfxSeq* pAfxSeq;
	char* name;
	//アドレステーブル出力バッファを作成する。
	obstack_init(&param.oTBL);
	//出力バッファを作成する。
	obstack_init(&param.o);
	//ハッシュテーブルを作成する。
	ght_set_rehash((param.ht_AfxSeq = ght_create(0)), 1);
	//配列を作成する。
	param.ar_name = g_ptr_array_new();
	//各XMLファイルについて…
	while((xmlPath = *aXmlPath++)) {
		struct stat buf;
		//AfxSeq_Load()はファイルが開けない時にDIE()して判り辛いので、先にファイルが存在するかどうかを確認して、存在しなければエラーメッセージを表示して終了する事にした。
		if(stat(xmlPath, &buf) || !(buf.st_mode & S_IFREG)) {	//VC++にはS_ISREG()マクロが無いので、直接S_IFREGを使って判定する必要が有ります。
			error(EXIT_FAILURE, errno, "%sが存在しません。", xmlPath);
		}
		//XMLファイルをロードする。
		AfxSeq_Load(xmlPath, AfxBin_Compress_fnLoad, AfxBin_Compress_fnGetFootage, &param);
	}
	//アニメーションを名前の昇順にソートする。					//■■■注意：ght_hash_table_tの実装依存の処理です。■■■
	SortList(&param.ht_AfxSeq->le_iterator, Label_compar);
	//アドレステーブルの先頭に、(アニメーションの数+1)を格納する。
	obstack_int_grow(&param.oTBL, ght_size(param.ht_AfxSeq) + 1/*忘れないで!!*/);	//TBL_AfxSeqNo[0]=(アニメーションの数+1)
	//文字列テーブルを出力する。
	for(i = 0; i < param.ar_name->len; i++) {
		//配列から、文字列ポインタを取り出す。
		name = g_ptr_array_index(param.ar_name, i);
		//配列内の文字列ポインタを、出力バッファ内の文字列の位置(int)に置き換える。	//┬この順序必須です。文字列の位置は、文字列を出力する前のバッファ位置だからです。
		g_ptr_array_index(param.ar_name, i) = (void*)obstack_object_size(&param.o);	//│
		//出力バッファに、文字列を出力する。						//│
		obstack_grow(&param.o, name, strlen(name) + 1/*nul*/);				//┘
		//これ以降、もうこの文字列は参照しないいので、ここで開放しておく。	AfxBin_Compress_AddName()内の'strdup(name)'に対応しています。
		free(name);
	}
	//文字列テーブルの終端を出力する。
	obstack_1grow(&param.o, 0);	//文字列テーブルの終端
	//各アニメーションについて…
	for(pAfxSeq = ght_first(param.ht_AfxSeq, &it, (const void**)&name);
	    pAfxSeq;
	    pAfxSeq = ght_next( param.ht_AfxSeq, &it, (const void**)&name)) {
		int posComp;
		//アニメーション名を出力する。
		obstack_grow(&param.o, name, strlen(name) + 1/*nul*/);
		//コンポジションを出力し、アドレステーブルにコンポジションの開始位置を追加する。
		posComp = AfxBin_Compress_WriteAfxSeq(pAfxSeq, &param);
		if(posComp % sizeof(int)) { DIE(); }	//コンポジションはワード境界から開始しているはず。
		posComp /= sizeof(int);			//コンポジションの開始位置をワード単位に変換する。
		obstack_int_grow(&param.oTBL, posComp);
		//これ以降、もうこのアニメーションは参照しないので、ここで開放しておく。
		AfxSeq_Free(pAfxSeq);
	}
	//アニメーションの終端を出力する。
	obstack_1grow(&param.o, 0);	//アニメーションの終端
	//バイナリファイルを出力する。
	if(binPath) {
		FILE* fp = fopen(binPath, "wb");	//バイナリ形式
		if(!fp) { error(EXIT_FAILURE, errno, "%sが作成出来ません。", binPath); }
		fwrite(obstack_base(&param.oTBL), 1, obstack_object_size(&param.oTBL), fp);	//アドレステーブル出力バッファ
		fwrite(obstack_base(&param.o   ), 1, obstack_object_size(&param.o   ), fp);	//出力バッファ
		fclose(fp);
	}
	//列挙定義スクリプトを出力する。
	if(enmPath) {
		const char* suffix = "\t1\n";	//アニメーション番号は1ベース
		FILE* fp = fopen(enmPath, "w");	//テキスト形式
		if(!fp) { error(EXIT_FAILURE, errno, "%sが作成出来ません。", enmPath); }
		fprintf(fp, "AfxSeq\n");
		//各アニメーションについて…
		for(pAfxSeq = ght_first(param.ht_AfxSeq, &it, (const void**)&name);
		    pAfxSeq;
		    pAfxSeq = ght_next( param.ht_AfxSeq, &it, (const void**)&name)) {
			//アニメーション名を大文字化する。
			// - 列挙定義スクリプトに出力する時だけ、アニメーション名を大文字化する事にしました。
			//   そうした理由は、プログラムから使用するシンボルは大文字小文字が混在していると紛らわしいので大文字に統一する方が良いと思うからです。
			//   また、既存の他のツール(dTexDefCやdPhrDefC)もシンボル名は大文字化しているので、それらに合わせる方が良いと思いました。
			// - バイナリ形式ファイル内に含まれるアニメーション名は、大文字化せずに、XMLファイルに格納されているアニメーション名のままとしました。
			//   そうした理由は、バイナリ形式ファイル内に含まれるアニメーション名は、(実質)参照する事は無いと思うのでプログラミングに影響しないと思うからです。
			//   また、もし参照する場合に、元のXMLファイルに格納されているアニメーション名と厳密に一致する方が、デバッグに役立つと思いました。
			// - ここでアニメーション名を大文字化する事によって、複数のアニメーションの名前が重複してしまう可能性が有ります。
			//   AfxBin_Compress_fnLoad()では、大文字小文字を区別しての重複検査しか行っていないので、上記の重複は検出出来ません。
			//   ここでアニメーション名を大文字化する事によって生じる重複は、列挙定義スクリプトコンパイラに通すまで発見出来ない事に注意して下さい。
			name = strdup(name);	//この複製は必須です。ght_first(),又は,ght_next()で取得したnameを直接変更してはいけません。ght_first(),又は,ght_next()で取得したnameはハッシュテーブル内のキーを指しており、直接変更するとハッシュテーブルが壊れてしまうからです。
			if(!name) { DIE(); }
			strupr(name);
			//アニメーション名の一文字目がCシンボルの一文字目として有効な文字ならば…
			if(iscsymf(*name)) {
				fprintf(fp, "\t%s", name);
			//アニメーション名の一文字目がCシンボルの一文字目として無効な文字(多分数字)ならば…
			} else {
				fprintf(fp, "\t`%s", name);	//アニメーション名の先頭に「`」を付与する。dEnmDefC.exeのためです。
			}
			fputs(suffix, fp);	//┬1行目のみ"\t1\n"で改行する。
			suffix = "\n";		//┘2行目以降は "\n"で改行する。
			//大文字化したアニメーション名を開放する。
			free(name);
		}
		fprintf(fp, "end\n");
		fclose(fp);
	}
	//配列を削除する。
	g_ptr_array_unref(param.ar_name);	//文字列は上の処理で開放済みです。
	//ハッシュテーブルを削除する。
	ght_finalize(param.ht_AfxSeq);	//アニメーションは上の処理で開放済みです。
	//出力バッファを削除する。
	obstack_free(&param.o, NULL);
	//アドレステーブル出力バッファを削除する。
	obstack_free(&param.oTBL, NULL);
}
#endif//USE_AFXBIN_COMPRESS
#ifdef  USE_AFXBIN_EXPAND
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
//■AfxBin_Compress_*()が出力したバイナリ形式のアニメーションファイルを読み込み、メモリ上にST_AfxSeq非圧縮形式のツリーを作成する。ST_AfxSeq非圧縮形式のツリーは、clipafxs.cの関数で扱える。
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
/****************************************************************************
 *	構造体
 ****************************************************************************/
typedef struct _ST_AfxBin_Expand_Param {
	uint8_t*		pos;		//ファイル全体を読み込んだバッファ内の走査位置
	GPtrArray*		ar_name;	//文字列テーブルを読み込む配列
//不要	void			(*fnLoad)(const char* name, ST_AfxSeq* pAfxSeq, void* user_data);	//┐
	int			(*fnGetFootage)(const char* fileName, void* user_data);			//├AfxBin_Expand()の引数
	void*			user_data;								//┘
} ST_AfxBin_Expand_Param;
/****************************************************************************
 *	ローカル関数
 ****************************************************************************/
static void AfxBin_Expand_Align(ST_AfxBin_Expand_Param* param) {
	//ワード境界まで進める。
	while((int)param->pos & 3) { param->pos++; }
}
/*--------------------------------------------------------------------------*/
static ST_AfxLyr* AfxBin_Expand_ReadAfxLyr(ST_AfxBin_Expand_Param* param);	//前方参照
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static ST_AfxSeq* AfxBin_Expand_ReadAfxSeq(ST_AfxBin_Expand_Param* param) {
	ST_AfxSeq* pAfxSeq;
	const char* name;
	int iLayer;
	//ワード境界まで進める。
	AfxBin_Expand_Align(param);
	//コンポジション構造体のヘッダ部分を参照する。
	pAfxSeq = (ST_AfxSeq*)param->pos;
	//コンポジション名を取得する。
	name = (char*)pAfxSeq + (int)pAfxSeq->name;	//バイナリ形式ファイルではpAfxSeq->nameは、'コンポジション名へのポインタ'ではなく、'コンポジションの開始位置からコンポジション名の文字列の位置へのオフセット'として、格納されている。
	//コンポジション構造体全体のメモリを確保する。
	pAfxSeq = malloc(sizeof(ST_AfxSeq) +
	                (sizeof(ST_AfxLyr*) * pAfxSeq->nLayers) +
	                (strlen(name) + 1/*nul*/));					//AfxSeq_LoadComp()と同じメモリレイアウトにするために、ST_AfxSeq.nameが指す文字列は、個別にstrdup()するのではなく、ST_AfxSeq.layers[nLayers]の後にまとめて確保する必要が有る。
	if(!pAfxSeq) { DIE(); }
	//コンポジション構造体のヘッダ部分をコピーする。
	memcpy(pAfxSeq, param->pos, sizeof(ST_AfxSeq));
	param->pos += sizeof(ST_AfxSeq);
	//バイナリから、コンポジション構造体全体のメモリへ、コンポジション名をコピーし、コンポジション名へのポインタを設定する。
	pAfxSeq->name = strcpy((char*)&pAfxSeq->layers[pAfxSeq->nLayers], name);	//AfxSeq_LoadComp()と同じメモリレイアウトにするために、ST_AfxSeq.nameが指す文字列は、個別にstrdup()するのではなく、ST_AfxSeq.layers[nLayers]の後にまとめて確保する必要が有る。
	//レイヤのオフセット配列を読み飛ばす。
	param->pos += sizeof(ST_AfxLyr*) * pAfxSeq->nLayers;
	//各レイヤについて…
	for(iLayer = 0; iLayer < pAfxSeq->nLayers; iLayer++) {
		//レイヤを読み込む。
		pAfxSeq->layers[iLayer] = AfxBin_Expand_ReadAfxLyr(param);
	}
	return pAfxSeq;
}
/*--------------------------------------------------------------------------*/
static ST_AfxLyr* AfxBin_Expand_ReadAfxLyr(ST_AfxBin_Expand_Param* param) {
	ST_AfxLyr* pAfxLyr;
	uint8_t* posAfxLyr;
	const char* name;
	char* p;
	int i;
	//ワード境界まで進める。
	AfxBin_Expand_Align(param);
	//レイヤの開始位置のポインタを保存しておく。
	posAfxLyr = param->pos;
	//レイヤ構造体のヘッダ部分を参照する。
	pAfxLyr = (ST_AfxLyr*)param->pos;
	//レイヤ名を取得する。
	name = (char*)pAfxLyr + (int)pAfxLyr->name;	//バイナリ形式ファイルではpAfxLyr->nameは、'レイヤ名へのポインタ'ではなく、'レイヤの開始位置からレイヤ名の文字列の位置へのオフセット'として、格納されている。
	//レイヤ構造体全体のメモリを確保する。
	pAfxLyr = malloc(sizeof(ST_AfxLyr) + 
	                (sizeof(ST_AfxFra) * pAfxLyr->nFrames) +
	                (strlen(name) + 1/*nul*/));					//AfxSeq_LoadLayer()と同じメモリレイアウトにするために、ST_AfxLyr.nameが指す文字列は、個別にstrdup()するのではなく、ST_AfxLyr.frames[nFrames]の後にまとめて確保する必要が有る。
	if(!pAfxLyr) { DIE(); }
	//レイヤ構造体のヘッダ部分をコピーする。
	memcpy(pAfxLyr, param->pos, sizeof(ST_AfxLyr));
	param->pos += sizeof(ST_AfxLyr);
	//バイナリから、レイヤ構造体全体のメモリへ、レイヤ名をコピーし、レイヤ名へのポインタを設定する。
	pAfxLyr->name = strcpy((char*)&pAfxLyr->frames[pAfxLyr->nFrames], name);	//AfxSeq_LoadLayer()と同じメモリレイアウトにするために、ST_AfxLyr.nameが指す文字列は、個別にstrdup()するのではなく、ST_AfxLyr.frames[nFrames]の後にまとめて確保する必要が有る。
	//フレーム配列を展開する。
	if(BytePairEncodingDecoder_Decode(
		param->pos,
		pAfxLyr->frames,
		sizeof(ST_AfxFra) * pAfxLyr->nFrames,
		(void**)&param->pos) != (int)(sizeof(ST_AfxFra) * pAfxLyr->nFrames)) { DIE(); }
	//各フレームの値は前のフレームからの差分なので、各フレームの値に前のフレームの値を足し戻す。
	p = (char*)&pAfxLyr->frames;			//1フレーム目の1バイト目へのポインタ
	for(i = 0; i < (int)(sizeof(ST_AfxFra) * (pAfxLyr->nFrames - 1/*忘れないで!!*/)); i++) {
		*(p + sizeof(ST_AfxFra)) += *p;		//次のフレームの値に、前のフレームの値を足し戻す。
		p++;
	}
	//素材が有れば…
	if(pAfxLyr->sequenceLength) {
		//素材のファイル名を取得する。
		const char* fileName = posAfxLyr + pAfxLyr->footage;	//バイナリ形式ファイルではpAfxLyr->footageは、'このレイヤで描画する素材のベースID'ではなく、'レイヤの開始位置から素材ファイル名の文字列の位置へのオフセット'として、格納されている。
		//素材のIDを取得する。
		pAfxLyr->footage = (*param->fnGetFootage)(fileName, param->user_data);
	}
	//子階層のコンポジションが有れば…
	if(pAfxLyr->pAfxSeq) {
		//コンポジションを読み込む。
		pAfxLyr->pAfxSeq = AfxBin_Expand_ReadAfxSeq(param);
	}
	return pAfxLyr;
}
/****************************************************************************
 *	グローバル関数
 ****************************************************************************/
void AfxBin_Expand(const char* path, void (*fnLoad)(ST_AfxSeq* pAfxSeq, void* user_data), int (*fnGetFootage)(const char* fileName, void* user_data), void* user_data) {
	ST_AfxBin_Expand_Param param;
	uint8_t* buf;
	//AfxBin_Expand()の引数を格納する。
//不要	param.fnLoad = fnLoad;
	param.fnGetFootage = fnGetFootage;
	param.user_data = user_data;
	//配列を作成する。
	param.ar_name = g_ptr_array_new();
	//ファイル全体を読み込む。
	{
		FILE* fp;
		int size;
		fp = fopen(path, "rb");	//バイナリ形式
		if(!fp) { DIE(); }
		if(fseek(fp, 0, SEEK_END)) { DIE(); }
		if((size = ftell(fp)) < 0) { DIE(); }
		rewind(fp);
		buf = malloc(size);
		if(!buf) { DIE(); }
		if((int)fread(buf, 1, size, fp) != size) { DIE(); }
		fclose(fp);
	}
	//走査開始位置を設定する。
	param.pos = buf;
	//アドレステーブルを読み飛ばす。
	param.pos += sizeof(int) * *(int*)param.pos;	//TBL_AfxSeqNo[0]=(アニメーションの数+1)
	//文字列テーブルの終端に到達するまで…
	while(*param.pos) {
		//文字列ポインタを配列に追加する。
		g_ptr_array_add(param.ar_name, param.pos);	//ここでは文字列を複製する必要は有りません。
		//走査位置を文字列の次へ進める。
		param.pos = strchr(param.pos, '\0') + 1/*nul*/;
	}
	//文字列テーブルの終端の'\0'を読み飛ばす。
	param.pos++;
	//アニメーションテーブルの終端に到達するまで…
	while(*param.pos) {
		const char* name;
		ST_AfxSeq* pAfxSeq;
		//アニメーション名のポインタを取得する。
		name = param.pos;
		//走査位置をアニメーション名の次へ進める。
		param.pos = strchr(param.pos, '\0') + 1/*nul*/;
		//アニメーションを読み込む。
		pAfxSeq = AfxBin_Expand_ReadAfxSeq(&param);
		//アプリケーションに通知する。
		(*fnLoad)(pAfxSeq, user_data);
	}
	//配列を削除する。
	g_ptr_array_unref(param.ar_name);
	//バッファを開放する。
	free(buf);
	//■AfxBin_Expand()で読み込んだST_AfxSeq非圧縮形式のツリーの操作について
	//│AfxBin_Expand()で読み込んだST_AfxSeq非圧縮形式のツリーは、AfxSeq_Load()で読み込んだツリーと、全く同じものになります。
	//│これ以降の操作は、clipafxs.cモジュールの関数を使って使用して下さい。
	//│ツリーが不要になったら、(*fnLoad)()に対して通知された(ST_AfxSeq*)を、個別にAfxSeq_Free()を呼び出して開放する必要が有る事も、AfxSeq_Load()と同様です。
}
#endif//USE_AFXBIN_EXPAND
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
//■AfxBin_Compress_*()が出力したバイナリ形式のアニメーションファイルを読み込み、メモリ上にST_AfxSeq圧縮形式のツリーを作成する。ST_AfxSeq圧縮形式のツリーは、AfxBin_Draw()で描画する。
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
#undef  USE_POOL
#define USE_POOL				//このシンボルを定義するかしないかによって、フレームキャッシュのメモリ操作に、メモリプールを使用するか,普通のmalloc()/free()を使用するかを選択出来ます。
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#undef  CACHE_TABLE_SIZE
#undef  CACHE_BUCKET_LIMIT
#ifdef  PIECE
  #define CACHE_TABLE_SIZE	 17/*調整可*/	//バケット数は素数にする方が性能が良くなります(必須ではない)。	┬高速化するにはバケット数を増やしてバケットリミットを減らして下さい。
  #define CACHE_BUCKET_LIMIT	  4/*調整可*/	//バケットリミットは素数でも素数でなくても性能に影響しません。	┘ただし(バケット数×バケットリミット)に比例してメモリ消費量が増えます。
#else //PIECE
  #define CACHE_TABLE_SIZE	257/*調整可*/	//バケット数は素数にする方が性能が良くなります(必須ではない)。	┬高速化するにはバケット数を増やしてバケットリミットを減らして下さい。
  #define CACHE_BUCKET_LIMIT	  8/*調整可*/	//バケットリミットは素数でも素数でなくても性能に影響しません。	┘ただし(バケット数×バケットリミット)に比例してメモリ消費量が増えます。
#endif//PIECE
/****************************************************************************
 *	フレームキャッシュ
 ****************************************************************************/
//フレームキャッシュのキー
typedef struct _ST_AfxFra_CacheKey {
//{{2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
//	const ST_AfxLyr*		pAfxLyr;	//対象とするレイヤへのポインタ
//↓2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
	const ST_AfxBinLyr*		pAfxBinLyr;	//対象とするレイヤへのポインタ
//}}2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
	int				iFrame;		//ST_AfxFra_CacheData.stAfxFraが保持している値のフレーム番号
} ST_AfxFra_CacheKey;
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//フレームキャッシュのデータ
typedef struct _ST_AfxFra_CacheData {
	ST_BytePairEncodingDecoder	stDecoder;	//ST_AfxFra_CacheKey.iFrameフレーム目まで展開した直後のストリーム
	ST_AfxFra			stAfxFra;	//ST_AfxFra_CacheKey.iFrameフレーム目の値
} ST_AfxFra_CacheData;
/*--------------------------------------------------------------------------*/
//フレームキャッシュ
static ght_hash_table_t* ht_AfxFra_Cache;		//ST_AfxFra_CacheKey⇒(ST_AfxFra_CacheData*)
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifdef  USE_POOL
//フレームキャッシュのデータのメモリプール
static POOL pool_AfxFra_CacheData={sizeof(ST_AfxFra_CacheData)};
//フレームキャッシュのハッシュテーブルのエントリのメモリプール
static POOL pool_AfxFra_CacheEntry={sizeof(ght_hash_entry_t)+sizeof(ST_AfxFra_CacheKey)};
#endif//USE_POOL
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifdef  USE_AFXBIN_DRAW_STATISTICS
ST_AfxBin_Draw_Statistics st_AfxBin_Draw_Statistics;	//描画統計情報。アプリケーションから直接参照して下さい。
#endif//USE_AFXBIN_DRAW_STATISTICS
/*--------------------------------------------------------------------------*/
//フレームキャッシュのデータが自動削除される時に呼び出される関数
static void AfxFra_CacheData_Free(void* data, const void* key) {
#ifdef  USE_POOL
	pool_free(data);	//AfxBin_DrawLayer()の'pool_alloc(&pool_AfxFra_CacheData)'に対応しています。
#else //USE_POOL
	free(data);		//AfxBin_DrawLayer()の'calloc(1,sizeof(ST_AfxFra_CacheData))',及び,'memdup(data,sizeof(ST_AfxFra_CacheData))'に対応しています。
#endif//USE_POOL
}
#ifdef  USE_POOL
//フレームキャッシュのハッシュテーブルのエントリのメモリアロケータ
static void* AfxFra_CacheEntry_Alloc(size_t size) {
	if((int)size != pool_AfxFra_CacheEntry.size) { DIE(); }
	return pool_alloc(&pool_AfxFra_CacheEntry);
}
static void AfxFra_CacheEntry_Free(void* ptr) {
	pool_free(ptr);
}
#endif//USE_POOL
/****************************************************************************
 *	構造体
 ****************************************************************************/
typedef struct _ST_AfxBin_Draw_Param {
	void			(*fnDraw)(int layerDepth, const char* layerPath[], int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, const char* _footage, int sequence, double opacity, int blendingMode, void* user_data);	//┐
//{{2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
//	const ST_AfxSeq*	(*fnFilter)(int layerDepth, const char* layerPath[], const ST_AfxSeq* pAfxSeq, void* user_data);														//├AfxBin_Draw()の引数
//↓2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
	const ST_AfxBin*	(*fnFilter)(int layerDepth, const char* layerPath[], const ST_AfxBin* pAfxBin, void* user_data);														//├AfxBin_Draw()の引数
//}}2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
	void*			user_data;																									//┘
	int			layerDepth;			//┐
	const char*		layerPath[16/*調整可*/];	//┴layerPath[0]〜layerPath[layerDepth-1]=レイヤ名,layerPath[layerDepth]=NULL	実用上、コンポジション階層が15以下(終端(NULL)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
} ST_AfxBin_Draw_Param;
/****************************************************************************
 *	ローカル関数
 ****************************************************************************/
//{{2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
//static void AfxBin_DrawComp(const ST_AfxSeq* pAfxSeq, int iFrame, int bLoop, const ST_AfxMat* pAfxMat, double opacity, int blendingMode, ST_AfxBin_Draw_Param* param);	//前方参照
//↓2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
static void AfxBin_DrawComp(const ST_AfxBin* pAfxBin, int iFrame, int bLoop, const ST_AfxMat* pAfxMat, double opacity, int blendingMode, ST_AfxBin_Draw_Param* param);	//前方参照
//}}2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//{{2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
//static void AfxBin_DrawLayer(const ST_AfxLyr* pAfxLyr, int iFrame, int bLoop, const ST_AfxMat* pAfxMat, double opacity, int blendingMode, ST_AfxBin_Draw_Param* param) {
//	iFrame -= pAfxLyr->startFrame;
//	if((unsigned)iFrame < pAfxLyr->nFrames) {
//↓2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
static void AfxBin_DrawLayer(const ST_AfxBinLyr* pAfxBinLyr, int iFrame, int bLoop, const ST_AfxMat* pAfxMat, double opacity, int blendingMode, ST_AfxBin_Draw_Param* param) {
	iFrame -= pAfxBinLyr->startFrame;
	if((unsigned)iFrame < pAfxBinLyr->nFrames) {
//}}2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
		ST_AfxFra stAfxFra;
		//フレームキャッシュが作成されていなければ、フレームキャッシュを作成する。
		if(!ht_AfxFra_Cache) {
			ht_AfxFra_Cache = ght_create(CACHE_TABLE_SIZE);
			ght_set_bounded_buckets(ht_AfxFra_Cache, CACHE_BUCKET_LIMIT, AfxFra_CacheData_Free);
#ifdef  USE_POOL
			ght_set_alloc(ht_AfxFra_Cache, AfxFra_CacheEntry_Alloc, AfxFra_CacheEntry_Free);
#endif//USE_POOL
		}
		{
			ST_AfxFra_CacheKey key;
			ST_AfxFra_CacheData* data;
			char* p;
			int c, i;
			//当該フレーム〜3/*調整可*/フレーム前まで、キャッシュを検索する。	ステイ,1倍速再生,2倍速再生,3倍速再生ぐらいまでが一般的に使用されると想定して、3フレーム前までキャッシュを検索する事にしました。逆再生や4倍速再生以上も可能ではありますが、毎回先頭から展開し直すので処理速度が低下します。もし4倍速再生以上を頻繁に使う場合は、この値を変更して下さい。
//{{2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
//			key.pAfxLyr = pAfxLyr;																																							//│
//↓2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
			key.pAfxBinLyr = pAfxBinLyr;																																						//│
//}}2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
			key.iFrame = iFrame;	//当該フレーム																																					//│
			for(i = 0; i <= 3/*調整可*/; i++) {	//←───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
				data = ght_get(ht_AfxFra_Cache, sizeof(ST_AfxFra_CacheKey), &key);
				if(data) { break; }		//キャッシュヒットしたらループを抜ける。
				if(--key.iFrame < 0) { break; }	//検索キーを一つ前のフレームへ戻す。マイナスになったら明らかにキャッシュミスなのですぐに打ち切る。(ループを継続しても動作結果は同じですが無駄です。)	←┐
			}																								//│
#ifdef  USE_AFXBIN_DRAW_STATISTICS																							//│
			//描画統計情報を格納する。																					//│
			if(data) {																							//│
				if((unsigned)i >= (unsigned)ARRAY_SIZE(st_AfxBin_Draw_Statistics.nCacheHit)) { DIE(); }													//│
				st_AfxBin_Draw_Statistics.nCacheHit[i]++;	//キャッシュヒット回数															//│
			} else {																							//│
				st_AfxBin_Draw_Statistics.nCacheMiss++;		//キャッシュミス回数															//│
			}																								//│
#endif//USE_AFXBIN_DRAW_STATISTICS																							//│
			//当該フレームのキャッシュヒット以外ならば…																			//│
			if(key.iFrame != iFrame) {		//'if(i)'で判断しないように注意せよ。'if(--key.iFrame<0)'の条件で上のループを抜けた場合、(i=0)のままキャッシュミスで上のループを抜ける可能性が有る。	─┘
				//キャッシュヒットしたら…
				if(data) {
					//フレームキャッシュのデータを複製する。			//フレームキャッシュのデータを直接変更しないように注意せよ。
#ifdef  USE_POOL	
					ST_AfxFra_CacheData *dupData = pool_alloc(&pool_AfxFra_CacheData);
					                    *dupData = *data;
					                                data = dupData;
#else //USE_POOL	
					data = memdup(data, sizeof(ST_AfxFra_CacheData));
					if(!data) { DIE(); }
#endif//USE_POOL	
				//キャッシュミスならば…
				} else {
					//フレームキャッシュのデータを作成する。
#ifdef  USE_POOL	
					data = pool_alloc(&pool_AfxFra_CacheData);
				//不要	memset(&data->stAfxFra, 0, sizeof(ST_AfxFra_CacheData));	//返されたメモリブロックは、pool_alloc()によってゼロクリアされています。
#else //USE_POOL	
					data = calloc(1, sizeof(ST_AfxFra_CacheData));			//data->stAfxFraの初期値を0とするために、calloc()必須です。
					if(!data) { DIE(); }
#endif//USE_POOL	
//{{2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
//					BytePairEncodingDecoder_Init(&data->stDecoder, pAfxLyr->frames);
//↓2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
					BytePairEncodingDecoder_Init(&data->stDecoder, pAfxBinLyr->frames);
//}}2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
					//この下の処理で0フレーム目から展開するために、キャッシュのフレームを(-1)としておく。
					key.iFrame = -1;
				}
				//キャッシュのフレームから、当該フレームまで展開する。
				do {
					p = (char*)&data->stAfxFra;
					for(i = 0; i < sizeof(ST_AfxFra); i++) {
						c = BytePairEncodingDecoder_Getc(&data->stDecoder);
						if(c == -1) { DIE(); }
						*p++ += c;
					}
				} while(++key.iFrame != iFrame);
				//当該フレームのデータをキャッシュに登録する。
				if(ght_insert(ht_AfxFra_Cache, data, sizeof(ST_AfxFra_CacheKey), &key)) { DIE(); }
			}
			//当該フレームの値を取得する。
			stAfxFra = data->stAfxFra;
		}
		{
			ST_AfxMat tmp = *pAfxMat;
			AfxMat_Position(&tmp, stAfxFra.position[0], stAfxFra.position[1]);
			AfxMat_Rotation(&tmp, (stAfxFra.rotation * (M_PI / 180.0)));
			AfxMat_Scale(&tmp, (stAfxFra.scale[0] / 100.0), (stAfxFra.scale[1] / 100.0));
			AfxMat_AnchorPoint(&tmp, stAfxFra.anchorPoint[0], stAfxFra.anchorPoint[1]);
			opacity *= (stAfxFra.opacity / 100.0);
//{{2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
//			if(pAfxLyr->blendingMode) { blendingMode = pAfxLyr->blendingMode; }
//			if(pAfxLyr->sequenceLength) {
//↓2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
			if(pAfxBinLyr->blendingMode) { blendingMode = pAfxBinLyr->blendingMode; }
			if(pAfxBinLyr->sequenceLength) {
//}}2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
				ST_AfxVec v[4] = {{stAfxFra.cornerPin[0][0],stAfxFra.cornerPin[0][1]},	//topLeft
				                  {stAfxFra.cornerPin[1][0],stAfxFra.cornerPin[1][1]},	//topRight
				                  {stAfxFra.cornerPin[2][0],stAfxFra.cornerPin[2][1]},	//bottomRight	//┬TriangleFanの並び
				                  {stAfxFra.cornerPin[3][0],stAfxFra.cornerPin[3][1]}};	//bottomLeft	//┘
				int i;
				for(i = 0; i < 4; i++) {
					AfxVec_Transform(&tmp, &v[i]);
				}
				(*param->fnDraw)(
					param->layerDepth,
					param->layerPath,
					v[0].x, v[0].y,	//topLeft
					v[1].x, v[1].y,	//topRight
					v[2].x, v[2].y,	//bottomRight	//┬TriangleFanの並び
					v[3].x, v[3].y,	//bottomLeft	//┘
//{{2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
//					(char*)pAfxLyr + pAfxLyr->footage,	//バイナリ形式ファイルではpAfxLyr->footageは、'このレイヤで描画する素材のベースID'ではなく、'レイヤの開始位置から素材ファイル名の文字列の位置へのオフセット'として、格納されている。
//					iFrame % pAfxLyr->sequenceLength,	//連番シーケンスファイル対応
//↓2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
					(char*)pAfxBinLyr + pAfxBinLyr->footage,	//バイナリ形式ファイルではpAfxBinLyr->footageは、'このレイヤで描画する素材のベースID'ではなく、'レイヤの開始位置から素材ファイル名の文字列の位置へのオフセット'として、格納されている。
					iFrame % pAfxBinLyr->sequenceLength,		//連番シーケンスファイル対応
//}}2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
					opacity,
					blendingMode,
					param->user_data);
			}
//{{2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
//			if(pAfxLyr->pAfxSeq) {
//				ST_AfxSeq* pAfxSeq = (ST_AfxSeq*)((char*)pAfxLyr + (int)pAfxLyr->pAfxSeq);	//オフセット⇒ポインタ変換
//				AfxBin_DrawComp(pAfxSeq, iFrame, bLoop, &tmp, opacity, blendingMode, param);
//			}
//↓2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
			if(pAfxBinLyr->pAfxBin) {
				ST_AfxBin* pAfxBin = (ST_AfxBin*)((char*)pAfxBinLyr + pAfxBinLyr->pAfxBin);	//オフセット⇒ポインタ変換
				AfxBin_DrawComp(pAfxBin, iFrame, bLoop, &tmp, opacity, blendingMode, param);
			}
//}}2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
		}
	}
}
/*--------------------------------------------------------------------------*/
#undef  USE_CLAMP
#define USE_CLAMP	//このシンボルを定義するかしないかによって、(bLoop=0)が指定された時の挙動が変わります。iFrameを[0,totalFrame-1]の範囲にクランプして描画する場合は、この行を有効にして下さい。iFrameが範囲外ならばこのコンポジションを描画しない場合は、この行をコメントアウトして下さい。
//{{2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
//static void AfxBin_DrawComp(const ST_AfxSeq* pAfxSeq, int iFrame, int bLoop, const ST_AfxMat* pAfxMat, double opacity, int blendingMode, ST_AfxBin_Draw_Param* param) {
//	pAfxSeq = (*param->fnFilter)(param->layerDepth, param->layerPath, pAfxSeq, param->user_data);	//【要注意】【要注意】【要注意】【要注意】【要注意】ここから呼び出されたアプリケーション定義のフィルタ関数が、コンポジション名を参照する場合は、pAfxSeq->nameでは参照出来ない事に注意して下さい。((char*)pAfxSeq + pAfxSeq->name)とする必要が有ります。【要注意】【要注意】【要注意】【要注意】【要注意】
//	if(pAfxSeq) {	//アプリケーション定義のフィルタ関数がNULLを返した場合は、このコンポジション階層以下の処理を行わない。
//↓2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
static void AfxBin_DrawComp(const ST_AfxBin* pAfxBin, int iFrame, int bLoop, const ST_AfxMat* pAfxMat, double opacity, int blendingMode, ST_AfxBin_Draw_Param* param) {
	pAfxBin = (*param->fnFilter)(param->layerDepth, param->layerPath, pAfxBin, param->user_data);	//【要注意】【要注意】【要注意】【要注意】【要注意】ここから呼び出されたアプリケーション定義のフィルタ関数が、コンポジション名を参照する場合は、pAfxBin->nameでは参照出来ない事に注意して下さい。((char*)pAfxBin + pAfxBin->name)とする必要が有ります。【要注意】【要注意】【要注意】【要注意】【要注意】
	if(pAfxBin) {	//アプリケーション定義のフィルタ関数がNULLを返した場合は、このコンポジション階層以下の処理を行わない。
//}}2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
		int iLayer;
		if(bLoop) {
//{{2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
//			iFrame %= pAfxSeq->totalFrame;
//			if(iFrame < 0) { iFrame += pAfxSeq->totalFrame; }
//↓2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
			iFrame %= pAfxBin->totalFrame;
			if(iFrame < 0) { iFrame += pAfxBin->totalFrame; }
//}}2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
#ifdef  USE_CLAMP
		} else {
//{{2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
//			iFrame = clamp(iFrame, 0, (pAfxSeq->totalFrame - 1));
//↓2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
			iFrame = clamp(iFrame, 0, (pAfxBin->totalFrame - 1));
//}}2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
#endif//USE_CLAMP
		}
#ifndef USE_CLAMP
		if((unsigned)iFrame < pAfxSeq->totalFrame) {
#endif//USE_CLAMP
			if(++param->layerDepth >= ARRAY_SIZE(param->layerPath)) { DIE(); }	//ここで停止したら、AfxSeq_Draw_Param.layerPath[]の要素数を増やして下さい。
//{{2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
//			for(iLayer = pAfxSeq->nLayers - 1; iLayer >= 0; iLayer--) {	//AfterEffectsはタイムラインパネルで上に有るレイヤほど手前に描画するようです。つまりプログラム処理では描画順序を逆にすればAfterEffectsと同じになります。
//				ST_AfxLyr* pAfxLyr = (ST_AfxLyr*)((char*)pAfxSeq + (int)pAfxSeq->layers[iLayer]);	//オフセット⇒ポインタ変換
//				param->layerPath[param->layerDepth - 1] = (char*)pAfxLyr + (int)pAfxLyr->name;		//オフセット⇒ポインタ変換
//			//不要	param->layerPath[param->layerDepth] = NULL;	//layerPath[]の初期値は全要素NULLであり、かつ、階層の処理が終わった時にポインタをNULLに戻しているので、ここで終端のNULLを格納する必要は有りません。
//				AfxBin_DrawLayer(pAfxLyr, iFrame, bLoop, pAfxMat, opacity, blendingMode, param);	//     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//			}												//				│
//↓2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
			for(iLayer = pAfxBin->nLayers - 1; iLayer >= 0; iLayer--) {	//AfterEffectsはタイムラインパネルで上に有るレイヤほど手前に描画するようです。つまりプログラム処理では描画順序を逆にすればAfterEffectsと同じになります。
				ST_AfxBinLyr* pAfxBinLyr = (ST_AfxBinLyr*)((char*)pAfxBin + pAfxBin->layers[iLayer]);	//オフセット⇒ポインタ変換
				param->layerPath[param->layerDepth - 1] = (char*)pAfxBinLyr + pAfxBinLyr->name;		//オフセット⇒ポインタ変換
			//不要	param->layerPath[param->layerDepth] = NULL;	//layerPath[]の初期値は全要素NULLであり、かつ、階層の処理が終わった時にポインタをNULLに戻しているので、ここで終端のNULLを格納する必要は有りません。
				AfxBin_DrawLayer(pAfxBinLyr, iFrame, bLoop, pAfxMat, opacity, blendingMode, param);	//     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			}												//				│
//}}2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
			param->layerPath[--param->layerDepth] = NULL;	//必要	//←──────────────────────────────────┘
#ifndef USE_CLAMP
		}
#endif//USE_CLAMP
	}
}
#undef  USE_CLAMP
/****************************************************************************
 *	グローバル関数
 ****************************************************************************/
static void AfxBin_Draw_fnDraw(int layerDepth, const char* layerPath[], int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, const char* _footage, int sequence, double opacity, int blendingMode, void* user_data) { /** no job **/ }
//{{2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
//static const ST_AfxSeq* AfxBin_Draw_fnFilter(int layerDepth, const char* layerPath[], const ST_AfxSeq* pAfxSeq, void* user_data) { return pAfxSeq; }
//↓2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
static const ST_AfxBin* AfxBin_Draw_fnFilter(int layerDepth, const char* layerPath[], const ST_AfxBin* pAfxBin, void* user_data) { return pAfxBin; }
//}}2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//{{2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
//void AfxBin_Draw(const ST_AfxSeq* pAfxSeq, int iFrame, int bLoop, const ST_AfxMat* pAfxMat, double opacity, int blendingMode,
//                 void (*fnDraw/*NULL可*/)(int layerDepth, const char* layerPath[], int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, const char* _footage, int sequence, double opacity, int blendingMode, void* user_data),
//                 const ST_AfxSeq* (*fnFilter/*NULL可*/)(int layerDepth, const char* layerPath[], const ST_AfxSeq* pAfxSeq, void* user_data),
//                 void* user_data) {
//↓2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
void AfxBin_Draw(const ST_AfxBin* pAfxBin, int iFrame, int bLoop, const ST_AfxMat* pAfxMat, double opacity, int blendingMode,
                 void (*fnDraw/*NULL可*/)(int layerDepth, const char* layerPath[], int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, const char* _footage, int sequence, double opacity, int blendingMode, void* user_data),
                 const ST_AfxBin* (*fnFilter/*NULL可*/)(int layerDepth, const char* layerPath[], const ST_AfxBin* pAfxBin, void* user_data),
                 void* user_data) {
//}}2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
	ST_AfxBin_Draw_Param param;
	memset(&param, 0, sizeof param);	//layerDepth,及び,layerPathの全要素をNULLとするためにクリア必要。詳細はAfxBin_DrawComp()内のコメントを参照して下さい。
	param.fnDraw    = fnDraw   ? fnDraw   : AfxBin_Draw_fnDraw;
	param.fnFilter  = fnFilter ? fnFilter : AfxBin_Draw_fnFilter;
	param.user_data = user_data;
//{{2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
//	AfxBin_DrawComp(pAfxSeq, iFrame, bLoop, pAfxMat, opacity, blendingMode, &param);
//↓2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
	AfxBin_DrawComp(pAfxBin, iFrame, bLoop, pAfxMat, opacity, blendingMode, &param);
//}}2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
}
/*--------------------------------------------------------------------------*/
void AfxBin_ClearFrameCache() {
	//フレームキャッシュが作成されていたら、フレームキャッシュを削除する。
	// - 次にAfxBin_Draw()が呼び出された時に、フレームキャッシュが再作成される。
	// - バイナリ形式のアニメーションファイルをROM化せずに,かつ,何度もファイルからメモリに読み込んだり開放したりする場合、フレームキャッシュのキーの(ST_AfxLyr*)が偶然古いポインタに一致する可能性が有る。
	//   この問題を防ぐために、バイナリ形式のアニメーションファイルのデータをメモリから開放する時に、フレームキャッシュを削除すべきである。
	//   アプリケーションは、バイナリ形式のアニメーションファイルのデータを「free(buf)」等の方法で開放する直前又は直後(どちらでも良い)に、当関数を呼び出してフレームキャッシュを削除して下さい。
	//   尚、それ以外の任意タイミングで当関数を呼び出しても、動作上は問題ありません。
	//   例えば、複数のバイナリ形式ファイルを読み込んで、その一部だけを開放する場合も、当関数を呼び出すのが適切です。
	// - 当関数が必要になるのは、「バイナリ形式ファイルをROM化せずに,かつ,何度もファイルからメモリに読み込んだり開放したりする場合」だけです。
	//   一般的にはそのような使い方はしないと思うので、実際には当関数を呼び出す事は無いでしょう。
	//   なぜならば、組み込み用のアプリケーションならばROM化すると思いますし、(P/ECEの場合もROM化して実行ファイルに埋め込むと思いますし、)
	//   Windows用のアプリケーションならば、バイナリ形式のアニメーションファイルはさほど大きくないので、起動時に読み込んで終了するまで開放しない使い方で十分だと思うからです。
	if(ht_AfxFra_Cache) {
		ght_iterator_t it;
		ST_AfxFra_CacheKey key;
		ST_AfxFra_CacheData* data;
		for(data = ght_first(ht_AfxFra_Cache, &it, (const void**)&key);
		    data;
		    data = ght_next( ht_AfxFra_Cache, &it, (const void**)&key)) {
			AfxFra_CacheData_Free(data, &key);
		}
		ght_finalize(ht_AfxFra_Cache);
		ht_AfxFra_Cache = NULL;	//忘れないで!!
	}
}
/*--------------------------------------------------------------------------*/
//AfxBin_Draw()から呼び出された(*fnDraw)()が、素材IDを検索するために利用出来るユーティリティ関数
//{{2016/08/15削除:clipenm.cにEnmDef_GetVal_UseCompar()を追加した事に伴い、AfxBin_Draw_GetFootage()内のフッテージの検索処理に、EnmDef_GetVal_UseCompar()を使用するように変更しました。
//static int AfxBin_Draw_GetFootage_compar(const void* key, const void* data, void* arg) {
//	ST_AfxBin_Draw_GetFootage_Param* param = arg;
//	const char* fname = key;
//	const char* pName = EnmDef_GetName(param->pEnmKey, param->_RegKey_SprNo, (int)data);
//	return (*param->fnNamCmp)(fname, pName);
//}
///*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//}}2016/08/15削除:clipenm.cにEnmDef_GetVal_UseCompar()を追加した事に伴い、AfxBin_Draw_GetFootage()内のフッテージの検索処理に、EnmDef_GetVal_UseCompar()を使用するように変更しました。
int AfxBin_Draw_GetFootage(const char* fileName, ST_AfxBin_Draw_GetFootage_Param* param) {
	char fname[MAX_FNAME];
	int iSprNo;
#ifdef  WIN32
	//Windows環境ではメモリに余裕が有るので、フッテージの素材ファイル名から、スプライト(又はテクスチャ)番号への変換結果を、キャッシュする事にしました。
	//ここでキャッシュヒットすれば、この後のsplitpath()や、bsearch_r()を行わなくて済むので、高速化が期待出来ます。
	static ght_hash_table_t* ht_cache; /* ＳＴＡＴＩＣです！ */
	int fileNameLen;
	if(!ht_cache) {	//キャッシュがまだ作成されていなければ、作成する。
		ht_cache = ght_create(127/*調整可*/);			//┬キャッシュサイズは、中ぐらいとしました。実際に使ってみて、調整して下さい。
		ght_set_bounded_buckets(ht_cache, 4/*調整可*/, NULL);	//┘
	}
	fileNameLen = strlen(fileName);	//終端のヌル文字は不要
//{{2016/09/09変更:(int)値を(void*)にキャストして整数データとして使用する箇所で、64ビット版ではコンパイラの警告が出ていた問題を回避しました。
//	iSprNo = (int)ght_get(ht_cache, fileNameLen, fileName);
//↓2016/09/09変更:(int)値を(void*)にキャストして整数データとして使用する箇所で、64ビット版ではコンパイラの警告が出ていた問題を回避しました。
#ifndef _WIN64
	iSprNo = (int)ght_get(ht_cache, fileNameLen, fileName);		//32ビット版は、これまでと変更有りません。32ビット版も64ビット版と同じ書き方にしても動作は変わらないのですが、簡潔さを優先してこれまでのままとする事にしました。
#else //_WIN64
	iSprNo = (intptr_t)ght_get(ht_cache, fileNameLen, fileName);	//64ビット版は、(void*)(64ビット)⇒(int)(32ビット)にキャストしようとすると警告が出ます。元の値が32ビットの整数パラメータなので(int)にキャストしても安全ではあるのですが、警告を回避するために(void*)(64ビット)⇒(intptr_t)(64ビット)⇒暗黙の(int)(32ビット)へのキャスト、という手順を取る事にしました。
#endif//_WIN64
//}}2016/09/09変更:(int)値を(void*)にキャストして整数データとして使用する箇所で、64ビット版ではコンパイラの警告が出ていた問題を回避しました。
	if(iSprNo) { return iSprNo; }	//キャッシュヒットしたらここまで。
#endif//WIN32
//{{2016/08/15変更:clipenm.cにEnmDef_GetVal_UseCompar()を追加した事に伴い、AfxBin_Draw_GetFootage()内のフッテージの検索処理に、EnmDef_GetVal_UseCompar()を使用するように変更しました。
//	int iSprNo_Max = EnmDef_GetMax(param->pEnmKey, param->_RegKey_SprNo);
//	//列挙定義名を比較する関数が初期化されていなければ、strcasecmpとstrnatcasecmpのどちらを使うかを自動的に判定する。
//	// - 自動判定の結果は必ずしも、dTexDefC.exeに'-n'オプションを指定したかどうかに一致するとは限らない。
//	//   dTexDefC.exeに'-n'オプションを指定した場合、本来strnatcasecmpを使うのが適切だが、自然順比較に依存する名前が無ければ、当関数はstrcasecmpを選択してしまう可能性も有るからである。
//	//   実際に使用する列挙定義名の並びに対して、正しく昇順と判定できれば良いのだから、上記の動作は問題にはならない。
//	//   strnatcasecmpよりもstrcasecmpの方が高速なので、strnatcasecmpよりもstrcasecmpを優先して選択する事は、むしろ望ましい動作であると言える。
//	//   従って、初回のオーバーヘッドが許容できるならば、アプリケーションがparam->fnNamCmpを静的に初期化せずに、NULLのままにしてAfxBin_Draw_GetFootage()の自動判定に任せるのが望ましい。
//	if(!param->fnNamCmp) {
//		static int (* const TBL_fnNamCmp[2])(const char*, const char*) = { strcasecmp, strnatcasecmp };	//順序を逆にしてはいけない。より厳密に比較する方から先に試す必要が有ります。
//		int i;
//#ifdef  _DEBUG
//		syslog(LOG_DEBUG, "AfxBin_Draw_GetFootage: 比較関数の自動判定を開始します。");
//#endif//_DEBUG
//		for(i = 0; i < 2; i++) {
//			const char* s1 = NULL;
//			param->fnNamCmp = TBL_fnNamCmp[i];
//			for(iSprNo = 1; iSprNo <= iSprNo_Max; iSprNo++) {
//				const char* s2 = EnmDef_GetName(param->pEnmKey, param->_RegKey_SprNo, iSprNo);
//				if(s1 && ((*param->fnNamCmp)(s1, s2) >= 0)) { break; }	//この比較関数を使うと昇順と判定できない箇所が有れば、ループを途中で抜ける。
//				s1 = s2;
//			}
//			if(iSprNo > iSprNo_Max) { break; }	//ループを途中で抜けなければ、この比較関数を使う事に決定する。
//		}
//		if(i >= 2) { DIE(); }	//どちらの比較関数を使っても昇順と判定できない箇所が有れば、エラー停止する。恐らく、列挙定義のレジストリデータが壊れている。
//#ifdef  _DEBUG
//		syslog(LOG_DEBUG, "AfxBin_Draw_GetFootage: 比較関数を'%s'に決定しました。", (i ? "strnatcasecmp" : "strcasecmp"));
//#endif//_DEBUG
//	}
//	//フッテージの素材ファイル名(〜/〜/foobar.png)から、ベース名(foobar)だけを取り出す。
//	splitpath(fileName, NULL, NULL, fname, NULL);
//	//スプライト(又はテクスチャ)の列挙定義名が、ベース名に一致していると仮定して、スプライト(又はテクスチャ)を検索する。
//	iSprNo = (int)bsearch_r(fname, (void*)1, iSprNo_Max, 1, AfxBin_Draw_GetFootage_compar, param);
//	//       ~~~~~                 ~~~~~~~~~~~~~~~~~~~~~~~bsearch()を番号に対して使用するテクニックです。アドレスを番号と見なして(iSprNo=1〜SprNo_Max(又はTexNo_Max))に対して検索を行います。
//	if(!iSprNo) { DIE(); }	//スプライト(又はテクスチャ)が見つからなければ、エラー停止する。
//↓2016/08/15変更:clipenm.cにEnmDef_GetVal_UseCompar()を追加した事に伴い、AfxBin_Draw_GetFootage()内のフッテージの検索処理に、EnmDef_GetVal_UseCompar()を使用するように変更しました。
	//列挙定義名を比較する関数が初期化されていなければ…
	if(!param->fnNamCmp) {
		//列挙定義名を比較する関数を決定する。
		param->fnNamCmp = EnmDef_GetCanonicalNameCompar(param->pEnmKey, param->_RegKey_SprNo);
		if(!param->fnNamCmp) { DIE(); }	//dTexDefC.exeで生成した列挙定義名ならば、EnmDef_GetCanonicalNameCompar()で関数を決定出来ない事は無いはず。
	}
	//フッテージの素材ファイル名(〜/〜/foobar.png)から、ベース名(foobar)だけを取り出す。
	splitpath(fileName, NULL, NULL, fname, NULL);
    //{{2016/09/10追加:ファイル名の'-'以降はテクスチャ名やスプライト名に含めないようになった事に伴い、AfxBin_Draw_GetFootage()にて'-'以降を除外してスプライト(又はテクスチャ)を検索するように変更しました。
	{
		char* hyphen = strchr(fname, '-');	//ベース名が'-'を含んでいたら…
		if(hyphen) { *hyphen = '\0'; }		//ベース名の'-'以降を削除する。
	}
    //}}2016/09/10追加:ファイル名の'-'以降はテクスチャ名やスプライト名に含めないようになった事に伴い、AfxBin_Draw_GetFootage()にて'-'以降を除外してスプライト(又はテクスチャ)を検索するように変更しました。
	//ベース名を大文字化する。
	strupr(fname);
	//スプライト(又はテクスチャ)の列挙定義名が、ベース名を大文字化した文字列に一致していると仮定して、スプライト(又はテクスチャ)を検索する。
	iSprNo = EnmDef_GetVal_UseCompar(param->pEnmKey, param->_RegKey_SprNo, fname, param->fnNamCmp);
	if(!iSprNo) { DIE(); }	//スプライト(又はテクスチャ)が見つからなければ、エラー停止する。
//}}2016/08/15変更:clipenm.cにEnmDef_GetVal_UseCompar()を追加した事に伴い、AfxBin_Draw_GetFootage()内のフッテージの検索処理に、EnmDef_GetVal_UseCompar()を使用するように変更しました。
#ifdef  WIN32
	//次回以降のために、フッテージの素材ファイル名から、スプライト(又はテクスチャ)番号への変換結果を、キャッシュに格納しておく。
//{{2016/09/09変更:(int)値を(void*)にキャストして整数データとして使用する箇所で、64ビット版ではコンパイラの警告が出ていた問題を回避しました。
//	if(ght_insert(ht_cache, (void*)iSprNo, fileNameLen, fileName)) { DIE(); }	//終端のヌル文字は不要
//↓2016/09/09変更:(int)値を(void*)にキャストして整数データとして使用する箇所で、64ビット版ではコンパイラの警告が出ていた問題を回避しました。
#ifndef _WIN64
	if(ght_insert(ht_cache, (void*)iSprNo, fileNameLen, fileName)) { DIE(); }	//終端のヌル文字は不要		//32ビット版は、これまでと変更有りません。32ビット版も64ビット版と同じ書き方にしても動作は変わらないのですが、簡潔さを優先してこれまでのままとする事にしました。
#else //_WIN64
	if(ght_insert(ht_cache, (void*)(intptr_t)iSprNo, fileNameLen, fileName)) { DIE(); }	//終端のヌル文字は不要	//64ビット版は、(int)(32ビット)⇒(void*)(64ビット)に直接キャストしようとすると警告が出ます。(int)(32ビット)⇒(intptr_t)(64ビット)⇒(void*)(64ビット)の順でキャストすれば警告は出ません。
#endif//_WIN64
//}}2016/09/09変更:(int)値を(void*)にキャストして整数データとして使用する箇所で、64ビット版ではコンパイラの警告が出ていた問題を回避しました。
#endif//WIN32
	return iSprNo;
}
/****************************************************************************
 *	dpafxbin.exeが出力したバイナリ形式を扱うためのユーティリティ関数
 ****************************************************************************/
#ifdef  USE_AFXSEQ_BIN
//{{2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
//const ST_AfxSeq* AfxBin_GetNo(const void* pAfxSeqBin, int iAfxSeqNo) {
//↓2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
const ST_AfxBin* AfxBin_GetNo(const void* pAfxSeqBin, int iAfxSeqNo) {
//}}2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
	const int* const TBL_AfxSeqNo = pAfxSeqBin;				//バイナリの先頭にアドレステーブルが有る。アドレスはデータ本体(WORD配列)のインデクスである。
	const int nAfxSeqNo = TBL_AfxSeqNo[0];					//アドレステーブルの先頭[0]に要素数が入っている。要素数はそれ自身([0])も含む。
	const int* const TBL_AfxSeq = (const int*)&TBL_AfxSeqNo[nAfxSeqNo];	//アドレステーブルの直後からデータ本体(WORD配列)が開始する。
	if((iAfxSeqNo <= 0) || (iAfxSeqNo >= nAfxSeqNo)) { DIE(); }
//{{2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
//	return (const ST_AfxSeq*)&TBL_AfxSeq[TBL_AfxSeqNo[iAfxSeqNo]];
//↓2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
	return (const ST_AfxBin*)&TBL_AfxSeq[TBL_AfxSeqNo[iAfxSeqNo]];
//}}2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
}
//{{2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
//void AfxBin_DrawNo(const void* pAfxSeqBin, int iAfxSeqNo, int iFrame, int bLoop, const ST_AfxMat* pAfxMat, double opacity, int blendingMode,
//                   void (*fnDraw/*NULL可*/)(int layerDepth, const char* layerPath[], int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, const char* _footage, int sequence, double opacity, int blendingMode, void* user_data),
//                   const ST_AfxSeq* (*fnFilter/*NULL可*/)(int layerDepth, const char* layerPath[], const ST_AfxSeq* pAfxSeq, void* user_data),
//                   void* user_data) {
//	const ST_AfxSeq* pAfxSeq = AfxBin_GetNo(pAfxSeqBin, iAfxSeqNo);
//	AfxBin_Draw(pAfxSeq, iFrame, bLoop, pAfxMat, opacity, blendingMode, fnDraw, fnFilter, user_data);
//}
//↓2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
void AfxBin_DrawNo(const void* pAfxSeqBin, int iAfxSeqNo, int iFrame, int bLoop, const ST_AfxMat* pAfxMat, double opacity, int blendingMode,
                   void (*fnDraw/*NULL可*/)(int layerDepth, const char* layerPath[], int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, const char* _footage, int sequence, double opacity, int blendingMode, void* user_data),
                   const ST_AfxBin* (*fnFilter/*NULL可*/)(int layerDepth, const char* layerPath[], const ST_AfxBin* pAfxBin, void* user_data),
                   void* user_data) {
	const ST_AfxBin* pAfxBin = AfxBin_GetNo(pAfxSeqBin, iAfxSeqNo);
	AfxBin_Draw(pAfxBin, iFrame, bLoop, pAfxMat, opacity, blendingMode, fnDraw, fnFilter, user_data);
}
//}}2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
/*--------------------------------------------------------------------------*/
#ifdef  USE_AFXBIN_DUMP
//{{2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
//static void AfxBin_DumpAfxLyr(const ST_AfxLyr* pAfxLyr, yaml_document_t* d, const char* path);	//前方参照
//↓2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
static void AfxBin_DumpAfxLyr(const ST_AfxBinLyr* pAfxBinLyr, yaml_document_t* d, const char* path);	//前方参照
//}}2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//{{2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
//static void AfxBin_DumpAfxSeq(const ST_AfxSeq* pAfxSeq, yaml_document_t* d, const char* path) {
//↓2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
static void AfxBin_DumpAfxSeq(const ST_AfxBin* pAfxBin, yaml_document_t* d, const char* path) {
//}}2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
	GString* s = g_string_new(NULL);
	{
//{{2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
//		const char* name = (char*)pAfxSeq + (int)pAfxSeq->name;						//オフセット⇒ポインタ変換
//↓2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
		const char* name = (char*)pAfxBin + pAfxBin->name;						//オフセット⇒ポインタ変換
//}}2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
		yaml_path_set_string_f(d, name, "%s.name", path);
	}
//{{2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
//	yaml_path_set_number_f(d, pAfxSeq->totalFrame, "%s.totalFrame", path);
//↓2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
	yaml_path_set_number_f(d, pAfxBin->totalFrame, "%s.totalFrame", path);
//}}2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
	{
		int iLayer;
//{{2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
//		for(iLayer = 0; iLayer < pAfxSeq->nLayers; iLayer++) {
//			ST_AfxLyr* pAfxLyr = (ST_AfxLyr*)((char*)pAfxSeq + (int)pAfxSeq->layers[iLayer]);	//オフセット⇒ポインタ変換
//			g_string_printf(s, "%s.layers[%d]", path, iLayer);
//			AfxBin_DumpAfxLyr(pAfxLyr, d, s->str);
//		}
//↓2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
		for(iLayer = 0; iLayer < pAfxBin->nLayers; iLayer++) {
			ST_AfxBinLyr* pAfxBinLyr = (ST_AfxBinLyr*)((char*)pAfxBin + pAfxBin->layers[iLayer]);	//オフセット⇒ポインタ変換
			g_string_printf(s, "%s.layers[%d]", path, iLayer);
			AfxBin_DumpAfxLyr(pAfxBinLyr, d, s->str);
		}
//}}2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
	}
	g_string_free(s, 1/*free_segment*/);
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//{{2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
//static void AfxBin_DumpAfxLyr(const ST_AfxLyr* pAfxLyr, yaml_document_t* d, const char* path) {
//↓2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
static void AfxBin_DumpAfxLyr(const ST_AfxBinLyr* pAfxBinLyr, yaml_document_t* d, const char* path) {
//}}2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
	GString* s = g_string_new(NULL);
	{
//{{2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
//		const char* name = (char*)pAfxLyr + (int)pAfxLyr->name;						//オフセット⇒ポインタ変換
//↓2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
		const char* name = (char*)pAfxBinLyr + pAfxBinLyr->name;					//オフセット⇒ポインタ変換
//}}2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
		yaml_path_set_string_f(d, name, "%s.name", path);
	}
//{{2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
//	yaml_path_set_number_f(d, pAfxLyr->startFrame, "%s.startFrame", path);
//	yaml_path_set_number_f(d, pAfxLyr->nFrames, "%s.nFrames", path);
//↓2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
	yaml_path_set_number_f(d, pAfxBinLyr->startFrame, "%s.startFrame", path);
	yaml_path_set_number_f(d, pAfxBinLyr->nFrames, "%s.nFrames", path);
//}}2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
	//〜個々のフレーム情報は多過ぎるので出力しない事にしました。もし出力する場合はここに追加して下さい。〜
//{{2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
//	if(pAfxLyr->sequenceLength) {
//		const char* footage = (char*)pAfxLyr + pAfxLyr->footage;					//オフセット⇒ポインタ変換
//↓2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
	if(pAfxBinLyr->sequenceLength) {
		const char* footage = (char*)pAfxBinLyr + pAfxBinLyr->footage;					//オフセット⇒ポインタ変換
//}}2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
		yaml_path_set_string_f(d, footage, "%s.footage", path);
//{{2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
//		yaml_path_set_number_f(d, pAfxLyr->sequenceLength, "%s.sequenceLength", path);
//↓2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
		yaml_path_set_number_f(d, pAfxBinLyr->sequenceLength, "%s.sequenceLength", path);
//}}2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
	}
//{{2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
//	if(pAfxLyr->pAfxSeq) {
//		ST_AfxSeq* pAfxSeq = (ST_AfxSeq*)((char*)pAfxLyr + (int)pAfxLyr->pAfxSeq);			//オフセット⇒ポインタ変換
//↓2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
	if(pAfxBinLyr->pAfxBin) {
		ST_AfxBin* pAfxBin = (ST_AfxBin*)((char*)pAfxBinLyr + pAfxBinLyr->pAfxBin);			//オフセット⇒ポインタ変換
//}}2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
		g_string_printf(s, "%s.comp", path);
//{{2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
//		AfxBin_DumpAfxSeq(pAfxSeq, d, s->str);
//↓2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
		AfxBin_DumpAfxSeq(pAfxBin, d, s->str);
//}}2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
	}
	g_string_free(s, 1/*free_segment*/);
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//バイナリ形式ファイルイメージの内容を、YAML形式でテキスト出力します。
//□使用例
//│void test() {
//│  void* pAfxSeqBin;
//│  int size;
//│  FILE* fp = fopen("AfxBin.bin", "rb");
//│  fseek(fp, 0, SEEK_END);
//│  size = ftell(fp);
//│  rewind(fp);
//│  pAfxSeqBin = malloc(size);
//│  fread(pAfxSeqBin, 1, size, fp);
//│  fclose(fp);
//│  AfxBin_Dump(stdout, pAfxSeqBin);
//│  free(pAfxSeqBin);
//│}
void AfxBin_Dump(FILE* fp, const void* pAfxSeqBin) {
	const int* const TBL_AfxSeqNo = pAfxSeqBin;
	yaml_document_t* d = yaml_document_new();
	{
		GString* s = g_string_new(NULL);
		int iAfxSeqNo;
		for(iAfxSeqNo = 0; iAfxSeqNo < TBL_AfxSeqNo[0]; iAfxSeqNo++) {
			g_string_printf(s, "[%d]", iAfxSeqNo);
			if(iAfxSeqNo) {
//{{2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
//				const ST_AfxSeq* pAfxSeq = AfxBin_GetNo(TBL_AfxSeqNo, iAfxSeqNo);
//				AfxBin_DumpAfxSeq(pAfxSeq, d, s->str);
//↓2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
				const ST_AfxBin* pAfxBin = AfxBin_GetNo(TBL_AfxSeqNo, iAfxSeqNo);
				AfxBin_DumpAfxSeq(pAfxBin, d, s->str);
//}}2016/09/09変更:64ビット環境でAfxBin_Draw()を使用出来るようにするために、32ビット版のST_AfxLyr,ST_AfxSeqにバイナリレイアウト互換な構造体としてST_AfxBinLyr,ST_AfxBinを追加しました。
			} else {
				yaml_path_set_string(d, "null", s->str);
			}
		}
		g_string_free(s, 1/*free_segment*/);
	}
	{
		char* t = yaml_document_dump(d);	//yaml_document_dump(d)はdの開放も兼ねています。
		fputs(t, fp);
		free(t);
	}
}
#endif//USE_AFXBIN_DUMP
/*--------------------------------------------------------------------------*/
#endif//USE_AFXSEQ_BIN
