/*
 *	clipafxs.c
 *
 *	AfterEffects傾僯儊乕僔儑儞僔乕働儞僒
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2016 Naoyuki Sawa
 *
 *	* Fri Apr 22 21:42:56 JST 2016 Naoyuki Sawa
 *	- 1st 儕儕乕僗丅
 *	  /clip/tool/MkAfxSeqXml.jsx偱弌椡偝傟偨丄AfterEffects傾僯儊乕僔儑儞僨乕僞傪撉傒崬傫偱嵞惗偟傑偡丅
 *	* Mon Apr 25 22:45:55 JST 2016 Naoyuki Sawa
 *	- /clip/tool/MkAfxSeqXml.jsx偑<layer>僞僌撪偵<blendingMode>僞僌傪弌椡偡傞傛偆偵側偭偨帠偵敽偄丄摉儌僕儏乕儖偵傕僽儗儞僪儌乕僪偺張棟傪捛壛偟傑偟偨丅
 *	* Tue Apr 26 22:39:26 JST 2016 Naoyuki Sawa
 *	- /clip/tool/MkAfxSeqXml.jsx偑'footage'僉乕偵楢斣僔乕働儞僗僼傽僀儖偺偨傔偺忣曬傕奿擺偡傞傛偆偵側偭偨帠偵敽偄丄摉儌僕儏乕儖偵傕楢斣僔乕働儞僗僼傽僀儖偺偨傔偺張棟傪捛壛偟傑偟偨丅
 *	* Wed Apr 27 21:14:58 JST 2016 Naoyuki Sawa
 *	- /clip/tool/MkAfxSeqXml.jsx偑丄慺嵽偑摦夋偐楢斣僔乕働儞僗偐傪嬫暿偟偰sequenceLength偵揔愗側抣傪奿擺偡傞傛偆偵側偭偨帠偵敽偄丄幚峴帪偵摦夋偐偳偆偐傪敾掕偟偰'footageData.sequenceLength=1'偵彂偒姺偊偰偄偨張棟偼晄梫偵側傝嶍彍偟傑偟偨丅
 *	- /clip/tool/MkAfxSeqXml.jsx偑丄'frame'僉乕偵僐乕僫乕僺儞偺忣曬傕奿擺偡傞傛偆偵側偭偨帠偵敽偄丄摉儌僕儏乕儖傕僐乕僫乕僺儞偺忣曬傪嶲徠偟偰昤夋偡傞傛偆偵曄峏偟傑偟偨丅
 *	- /clip/tool/MkAfxSeqXml.jsx偑丄僾儘僕僃僋僩僷僱儖偱慖戰偝傟偰偄傞暋悢偺僐儞億僕僔儑儞傪傑偲傔偰堦偮偺XML偵彂偒弌偡傛偆偵側偭偨帠偵敽偄丄摉儌僕儏乕儖傕AfxSeq_Load()偺娭悢巇條傪曄峏偟傑偟偨丅
 *	  曄峏慜偼<AfxSeq>僞僌撪偺堦屄栚偺<comp>傪撉傒崬傫偱曉偟偰偄傑偟偨偑丄曄峏屻偼<AfxSeq>僞僌撪偺慡偰偺<comp>傪撉傒崬傫偱丄屇傃弌偟懁偺傾僾儕働乕僔儑儞偵偼屄乆偵僐乕儖僶僢僋偱捠抦偡傞傛偆偵偟傑偟偨丅
 *	* Thu May 05 21:24:20 JST 2016 Naoyuki Sawa
 *	- AfxSeq_Draw()偺昤夋娭悢偺慺嵽ID偺堷悢傪丄偙傟傑偱偼慺嵽偺儀乕僗ID偵僔乕働儞僗抣傪壛嶼偟偨抣傪搉偟偰偄傑偟偨偑丄慺嵽偺儀乕僗ID偲僔乕働儞僗抣傪屄暿偵搉偡傛偆偵曄峏偟傑偟偨丅
 *	  曄峏偟偨棟桼偼丄AfxBin_Draw()偺昤夋娭悢偺堷悢偺宍幃傪(偍偍傛偦)崌傢偣傞偨傔偱偡丅
 *	  AfxBin_Draw()偺昤夋娭悢偼丄慺嵽傪柤慜偱搉偡偺偱丄僔乕働儞僗抣傪壛嶼偡傞帠偑弌棃側偄偐傜偱偡丅
 *	  AfxSeq_Draw()偺昤夋娭悢偵偼偦偺栤戣偼側偄偺偱丄偙傟傑偱捠傝慺嵽偺儀乕僗ID偵僔乕働儞僗抣傪壛嶼偟偨抣傪搉偟偰傕峔傢側偄偺偱偡偑丄昤夋娭悢偺堷悢偺宍幃傪(偍偍傛偦)崌傢偣傞曽偑敾傝堈偄偲巚偆偺偱丄AfxSeq_Draw()偺昤夋娭悢偺堷悢偺宍幃傕曄峏偡傞帠偵偟傑偟偨丅
 *	- USE_AFXSEQ傪掕媊偟側偗傟偽丄AfxSeq_Load(),AfxSeq_Free(),AfxSeq_Draw()傪娷傔側偄傛偆偵偟傑偟偨丅
 *	  P/ECE偱偼儊儌儕愡栺偺偨傔偵丄偙傟傜偺娭悢傪娷傔側偄傛偆偵偟傑偟偨(娷傔傞帠傕壜擻偱偼偁傝傑偡)丅
 *	* Mon May 23 22:46:16 JST 2016 Naoyuki Sawa
 *	- ST_AfxSeq峔憿懱偲ST_AfxLyr峔憿懱偵丄name僼傿乕儖僪傪捛壛偟傑偟偨丅
 *	  捛壛偟偨棟桼偼丄崱屻僐儞億僕僔儑儞傗儗僀儎偺嵎偟懼偊傪峴偆応崌偵丄幚峴帪偵柤慜偺忣曬偑昁梫偵側傞偲巚偭偨偐傜偱偡丅
 *	  尰帪揰偱偼傑偩丄捛壛偟偨name僼傿乕儖僪傪棙梡偟偰偄傑偣傫偑丄崱屻棙梡偡傞梊掕偱偡丅
 *	- 忋婰偺曄峏偵敽偄丄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:
 */
#include "clip.h"
//劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒
//仭儀僋僩儖丒曄姺峴楍
//劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒
/****************************************************************************
 *	僌儘乕僶儖掕悢
 ****************************************************************************/
const ST_AfxVec AfxVec_0 = {0.0,0.0};
const ST_AfxVec AfxVec_x = {1.0,0.0};
const ST_AfxVec AfxVec_y = {0.0,1.0};
/*--------------------------------------------------------------------------*/
const ST_AfxMat AfxMat_0 = {0.0,0.0,0.0,
                            0.0,0.0,0.0};
const ST_AfxMat AfxMat_1 = {1.0,0.0,0.0,
                            0.0,1.0,0.0};
/****************************************************************************
 *	僌儘乕僶儖娭悢
 ****************************************************************************/
void AfxVec_Transform(const ST_AfxMat* pAfxMat, ST_AfxVec* pAfxVec) {	//嵍偐傜峴楍傪妡偗偰丄塃偺儀僋僩儖傪曄姺偡傞丅
	ST_AfxVec tmp = *pAfxVec;
	pAfxVec->x = (pAfxMat->a00 * tmp.x) + (pAfxMat->a01 * tmp.y) + pAfxMat->a02;
	pAfxVec->y = (pAfxMat->a10 * tmp.x) + (pAfxMat->a11 * tmp.y) + pAfxMat->a12;
}
/*--------------------------------------------------------------------------*/
void AfxMat_Transform(ST_AfxMat* pAfxMat1, const ST_AfxMat* pAfxMat2) {	//塃偐傜峴楍傪妡偗偰丄嵍偺峴楍傪曄姺偡傞丅
	ST_AfxMat tmp = *pAfxMat1;
	pAfxMat1->a00 = (tmp.a00 * pAfxMat2->a00) + (tmp.a01 * pAfxMat2->a10);
	pAfxMat1->a01 = (tmp.a00 * pAfxMat2->a01) + (tmp.a01 * pAfxMat2->a11);
	pAfxMat1->a02 = (tmp.a00 * pAfxMat2->a02) + (tmp.a01 * pAfxMat2->a12) + tmp.a02;
	pAfxMat1->a10 = (tmp.a10 * pAfxMat2->a00) + (tmp.a11 * pAfxMat2->a10);
	pAfxMat1->a11 = (tmp.a10 * pAfxMat2->a01) + (tmp.a11 * pAfxMat2->a11);
	pAfxMat1->a12 = (tmp.a10 * pAfxMat2->a02) + (tmp.a11 * pAfxMat2->a12) + tmp.a12;
}
/*--------------------------------------------------------------------------*/
void AfxMat_AnchorPoint(ST_AfxMat* pAfxMat, double x, double y) {	//塃偐傜峴楍傪妡偗偰丄嵍偺峴楍傪曄姺偡傞丅
	AfxMat_Position(pAfxMat, -x, -y);
}
/*--------------------------------------------------------------------------*/
void AfxMat_Position(ST_AfxMat* pAfxMat, double x, double y) {	//塃偐傜峴楍傪妡偗偰丄嵍偺峴楍傪曄姺偡傞丅
	ST_AfxMat tmp = {1.0,0.0,  x,
	                 0.0,1.0,  y};
	AfxMat_Transform(pAfxMat, &tmp);
}
/*--------------------------------------------------------------------------*/
void AfxMat_Scale(ST_AfxMat* pAfxMat, double x, double y) {	//塃偐傜峴楍傪妡偗偰丄嵍偺峴楍傪曄姺偡傞丅
	ST_AfxMat tmp = {  x,0.0,0.0,
	                 0.0,  y,0.0};
	AfxMat_Transform(pAfxMat, &tmp);
}
/*--------------------------------------------------------------------------*/
void AfxMat_Rotation(ST_AfxMat* pAfxMat, double z) {	//塃偐傜峴楍傪妡偗偰丄嵍偺峴楍傪曄姺偡傞丅
	double s = sin(z);
	double c = cos(z);
	ST_AfxMat tmp = {  c, -s,0.0,
	                   s,  c,0.0};
	AfxMat_Transform(pAfxMat, &tmp);
}
#ifdef  USE_AFXSEQ
//劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒
//仭AfterEffects傾僯儊乕僔儑儞僔乕働儞僒
//劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒劒
/****************************************************************************
 *	峔憿懱
 ****************************************************************************/
typedef struct _ST_AfxSeq_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, int footage, int sequence, double opacity, int blendingMode, void* user_data);	//劉
	const ST_AfxSeq*	(*fnFilter)(int layerDepth, const char* layerPath[], const ST_AfxSeq* pAfxSeq, void* user_data);													//劌AfxSeq_Draw()偺堷悢
	void*			user_data;																								//劊
	int			layerDepth;			//劉
	const char*		layerPath[16/*挷惍壜*/];	//劏layerPath[0]乣layerPath[layerDepth-1]=儗僀儎柤,layerPath[layerDepth]=NULL	幚梡忋丄僐儞億僕僔儑儞奒憌偑15埲壓(廔抂(NULL)傪娷傔偰16埲壓)偲峫偊偰廩暘偩傠偆丅晄懌偟偨応崌偼憹傗偣丅
} ST_AfxSeq_Draw_Param;
/****************************************************************************
 *	儘乕僇儖娭悢愰尵
 ****************************************************************************/
static void AfxSeq_GetVal1(TiXmlNode* xmlNode, const char* tag, short val[/*1*/], int min, int max);
static void AfxSeq_GetVal2(TiXmlNode* xmlNode, const char* tag, short val[/*2*/], int min, int max);
static void AfxSeq_LoadFrame(TiXmlNode* xmlFrame, ST_AfxFra* pAfxFra);
static ST_AfxLyr* AfxSeq_LoadLayer(TiXmlNode* xmlLayer, int (*fnGetFootage)(const char* fileName, void* user_data), void* user_data);
static ST_AfxSeq* AfxSeq_LoadComp(TiXmlNode* xmlComp, int (*fnGetFootage)(const char* fileName, void* user_data), void* user_data);
static void AfxSeq_FreeLayer(ST_AfxLyr* pAfxLyr);
static void AfxSeq_FreeComp(ST_AfxSeq* pAfxSeq);
static void AfxSeq_DrawLayer(const ST_AfxLyr* pAfxLyr, int iFrame, int bLoop, const ST_AfxMat* pAfxMat, double opacity, int blendingMode, ST_AfxSeq_Draw_Param* param);
static void AfxSeq_DrawComp(const ST_AfxSeq* pAfxSeq, int iFrame, int bLoop, const ST_AfxMat* pAfxMat, double opacity, int blendingMode, ST_AfxSeq_Draw_Param* param);
/****************************************************************************
 *	儘乕僇儖娭悢
 ****************************************************************************/
//乽<tag>[[:blank:]]*[[:digit:]]+[[:blank:]]*</tag>乿宍幃偺抣傪庢摼偡傞丅
static void AfxSeq_GetVal1(TiXmlNode* xmlNode, const char* tag, short val[/*1*/], int min, int max) {
	TiXmlElement* xmlElem;
	TiXmlText* xmlText;
	const char* text;
	int x, dummy;
	xmlElem = TiXmlNode_FirstChildElement(xmlNode, tag);
	if(!xmlElem) { DIE(); }
	xmlText = TiXmlNode_ToText(TiXmlNode_FirstChild(TiXmlElement_super(xmlElem), NULL));
	if(!xmlText) { DIE(); }
	text = TiXmlNode_Value(TiXmlText_super(xmlText));
	if(sscanf(text, "%d %c", &x, (char*)&dummy) != 1) { DIE(); }	//'(char*)'僉儍僗僩偼GCC偑sscanf偺彂幃暥帤楍傪棟夝偟偰寈崘傪昞帵偡傞偺傪梷惂偡傞偨傔偱偡丅
	//                 |++-------+++++++++++++--- '%*c'偱側偔'%c'昁恵偱偡丅'%*c'偱偼栠傝抣偵悢偊傜傟側偄偺偱晄壜偱偡丅僟儈乕曄悢偵奿擺偡傞昁梫偑桳傝傑偡丅
	//                 +------------------------- 偙偺嬻敀偼昁梫偱偡丅'%c'偼埫栙揑偵嬻敀傪撉傒旘偽偝側偄偺偱丄愭偵柧帵揑偵嬻敀傪撉傒旘偽偟偰偍偔偨傔偱偡丅
	if((x < min) || (x > max)) { DIE(); }
	val[0] = x;
}
/*--------------------------------------------------------------------------*/
//乽<tag>[[:blank:]]*[[:digit:]]+[[:blank:]]*,[[:blank:]]*[[:digit:]]+[[:blank:]]*</tag>乿宍幃偺抣傪庢摼偡傞丅
static void AfxSeq_GetVal2(TiXmlNode* xmlNode, const char* tag, short val[/*2*/], int min, int max) {
	TiXmlElement* xmlElem;
	TiXmlText* xmlText;
	const char* text;
	int x, y, dummy;
	xmlElem = TiXmlNode_FirstChildElement(xmlNode, tag);
	if(!xmlElem) { DIE(); }
	xmlText = TiXmlNode_ToText(TiXmlNode_FirstChild(TiXmlElement_super(xmlElem), NULL));
	if(!xmlText) { DIE(); }
	text = TiXmlNode_Value(TiXmlText_super(xmlText));
	if(sscanf(text, "%d,%d %c", &x, &y, (char*)&dummy) != 2) { DIE(); }	//'(char*)'僉儍僗僩偼GCC偑sscanf偺彂幃暥帤楍傪棟夝偟偰寈崘傪昞帵偡傞偺傪梷惂偡傞偨傔偱偡丅
	//                    |++-----------+++++++++++++--- '%*c'偱側偔'%c'昁恵偱偡丅'%*c'偱偼栠傝抣偵悢偊傜傟側偄偺偱晄壜偱偡丅僟儈乕曄悢偵奿擺偡傞昁梫偑桳傝傑偡丅
	//                    +----------------------------- 偙偺嬻敀偼昁梫偱偡丅'%c'偼埫栙揑偵嬻敀傪撉傒旘偽偝側偄偺偱丄愭偵柧帵揑偵嬻敀傪撉傒旘偽偟偰偍偔偨傔偱偡丅
	if(((x < min) || (x > max)) ||
	   ((y < min) || (y > max))) { DIE(); }
	val[0] = x;
	val[1] = y;
}
/*--------------------------------------------------------------------------*/
//<frame>乣</frame>傪撉傒崬傓丅
static void AfxSeq_LoadFrame(TiXmlNode* xmlFrame, ST_AfxFra* pAfxFra) {
	AfxSeq_GetVal2(xmlFrame, "anchorPoint", pAfxFra->anchorPoint, SHRT_MIN,  SHRT_MAX);
	AfxSeq_GetVal2(xmlFrame, "position",    pAfxFra->position,    SHRT_MIN,  SHRT_MAX);
	AfxSeq_GetVal2(xmlFrame, "scale",       pAfxFra->scale,       SHRT_MIN,  SHRT_MAX);
	AfxSeq_GetVal1(xmlFrame, "rotation",   &pAfxFra->rotation,    SHRT_MIN,  SHRT_MAX);
	AfxSeq_GetVal1(xmlFrame, "opacity",    &pAfxFra->opacity,            0, USHRT_MAX);
	{//<cornerPin>
		TiXmlElement* xmlCornerPin = TiXmlNode_FirstChildElement(xmlFrame, "cornerPin");
		if(!xmlCornerPin) { DIE(); }
		AfxSeq_GetVal2(TiXmlElement_super(xmlCornerPin), "topLeft",     pAfxFra->cornerPin[0], SHRT_MIN, SHRT_MAX);
		AfxSeq_GetVal2(TiXmlElement_super(xmlCornerPin), "topRight",    pAfxFra->cornerPin[1], SHRT_MIN, SHRT_MAX);
		AfxSeq_GetVal2(TiXmlElement_super(xmlCornerPin), "bottomRight", pAfxFra->cornerPin[2], SHRT_MIN, SHRT_MAX);	//劍TriangleFan偺暲傃
		AfxSeq_GetVal2(TiXmlElement_super(xmlCornerPin), "bottomLeft",  pAfxFra->cornerPin[3], SHRT_MIN, SHRT_MAX);	//劊
	}//</frames>
}
/*--------------------------------------------------------------------------*/
//<layer>乣</layer>傪撉傒崬傓丅
static ST_AfxLyr* AfxSeq_LoadLayer(TiXmlNode* xmlLayer, int (*fnGetFootage)(const char* fileName, void* user_data), void* user_data) {
	ST_AfxLyr* pAfxLyr;
	TiXmlText* xmlText;
	const char* name = TiXmlElement_Attribute(TiXmlNode_ToElement(xmlLayer), "name");
	if(!name) { DIE(); }
#ifdef  _DEBUG
	syslog(LOG_DEBUG, "AfxSeq_LoadLayer: name='%s'", name);
#endif//_DEBUG
	{
		GArray* arFrame = g_array_new(0, 0, sizeof(ST_AfxFra));
		{//<frames>
			TiXmlElement* xmlFrames = TiXmlNode_FirstChildElement(xmlLayer, "frames");
			if(!xmlFrames) { DIE(); }
			{//<frame>
				TiXmlElement* xmlFrame;
				for(xmlFrame = TiXmlNode_FirstChildElement(TiXmlElement_super(xmlFrames), "frame");
				    xmlFrame;
				    xmlFrame = TiXmlNode_NextSiblingElement(TiXmlElement_super(xmlFrame), "frame")) {
					ST_AfxFra afxFra;
					AfxSeq_LoadFrame(TiXmlElement_super(xmlFrame), &afxFra);
					g_array_append_val(arFrame, afxFra);
				}
			}//</frame>
		}//</frames>
		if(!arFrame->len || (arFrame->len > USHRT_MAX)) { DIE(); }
		pAfxLyr = malloc(sizeof(ST_AfxLyr) +
		                (sizeof(ST_AfxFra) * arFrame->len) +
		                (strlen(name) + 1/*nul*/));				//ST_AfxLyr.name偑巜偡暥帤楍偼丄屄暿偵strdup()偡傞偺偱偼側偔丄ST_AfxLyr.frames[nFrames]偺屻偵傑偲傔偰妋曐偡傞帠偵偟偨丅
		memcpy(pAfxLyr->frames, arFrame->data, sizeof(ST_AfxFra) * arFrame->len);
		pAfxLyr->nFrames = arFrame->len;
		g_array_unref(arFrame);
	}
	pAfxLyr->name = strcpy((char*)&pAfxLyr->frames[pAfxLyr->nFrames], name);	//ST_AfxLyr.name偑巜偡暥帤楍偼丄屄暿偵strdup()偡傞偺偱偼側偔丄ST_AfxLyr.frames[nFrames]偺屻偵傑偲傔偰妋曐偡傞帠偵偟偨丅
	AfxSeq_GetVal1(xmlLayer, "startFrame", &pAfxLyr->startFrame, 0, USHRT_MAX);
	{//<blendingMode>
		TiXmlElement* xmlBlendingMode = TiXmlNode_FirstChildElement(xmlLayer, "blendingMode");
		if(!xmlBlendingMode) { DIE(); }
		xmlText = TiXmlNode_ToText(TiXmlNode_FirstChild(TiXmlElement_super(xmlBlendingMode), NULL));
		if(!xmlText) { DIE(); }
		name = TiXmlNode_Value(TiXmlText_super(xmlText));
		if(!strcasecmp(name, "NORMAL")) {
			pAfxLyr->blendingMode	= 0;	//0:NORMAL
		} else if(!strcasecmp(name, "ADD")) {
			pAfxLyr->blendingMode	= 1;	//1:ADD
    //仸TODO:	} else if(!strcasecmp(name, "...")) {			劍崱屻丄AfterEffects忋偺懠偺僽儗儞僪儌乕僪偵傕懳墳偟偨傜丄偙偙偵僐乕僪傪捛壛偟偰壓偝偄丅
    //仸TODO:		pAfxLyr->blendingMode	= ?;	//?:...		劊
		} else {
			DIE();
		}
	}//</blendingMode>
	{//<footage>
		TiXmlElement* xmlFootage = TiXmlNode_FirstChildElement(xmlLayer, "footage");
		//偙偺儗僀儎偵<footage>乣</footage>偑桳傟偽乧
		if(xmlFootage) {
			TiXmlElement* xmlFileName;
			const char* fileName;
			xmlFileName = TiXmlNode_FirstChildElement(TiXmlElement_super(xmlFootage), "fileName");
			if(!xmlFileName) { DIE(); }
			xmlText = TiXmlNode_ToText(TiXmlNode_FirstChild(TiXmlElement_super(xmlFileName), NULL));
			if(!xmlText) { DIE(); }
			fileName = TiXmlNode_Value(TiXmlText_super(xmlText));
			AfxSeq_GetVal1(TiXmlElement_super(xmlFootage), "sequenceLength", &pAfxLyr->sequenceLength, 1, USHRT_MAX);
#ifdef  _DEBUG
			syslog(LOG_DEBUG, "AfxSeq_LoadLayer: footage fileName='%s', sequenceLength = %d", fileName, pAfxLyr->sequenceLength);
#endif//_DEBUG
			pAfxLyr->footage = (*fnGetFootage)(fileName, user_data);
		//偙偺儗僀儎偵<footage>乣</footage>偑柍偗傟偽乧
		} else {
			pAfxLyr->footage = -1;		//(sequenceLength=0)側傜偽(footage=晄掕抣)偱峔傢側偄偺偱偙偺峴偼徣棯壜擻偩偑丄僨僶僢僌偟堈偝偺偨傔偵(footage=-1)傪奿擺偟偰偍偔帠偵偟偨丅
			pAfxLyr->sequenceLength = 0;
		}
	}//</footage>
	{//<comp>
		TiXmlElement* xmlComp = TiXmlNode_FirstChildElement(xmlLayer, "comp");
		//偙偺儗僀儎偵<comp>乣</comp>偑桳傟偽乧
		if(xmlComp) {
			pAfxLyr->pAfxSeq = AfxSeq_LoadComp(TiXmlElement_super(xmlComp), fnGetFootage, user_data);
		//偙偺儗僀儎偵<comp>乣</comp>偑柍偗傟偽乧
		} else {
			pAfxLyr->pAfxSeq = NULL;
		}
	}//</comp>
	return pAfxLyr;
}
/*--------------------------------------------------------------------------*/
//<comp>乣</comp>傪撉傒崬傓丅
static ST_AfxSeq* AfxSeq_LoadComp(TiXmlNode* xmlComp, int (*fnGetFootage)(const char* fileName, void* user_data), void* user_data) {
	ST_AfxSeq* pAfxSeq;
	const char* name = TiXmlElement_Attribute(TiXmlNode_ToElement(xmlComp), "name");
	if(!name) { DIE(); }
#ifdef  _DEBUG
	syslog(LOG_DEBUG, "AfxSeq_LoadComp: name='%s'", name);
#endif//_DEBUG
	{
		GPtrArray* arLayer = g_ptr_array_new();
		{//<layers>
			TiXmlElement* xmlLayers = TiXmlNode_FirstChildElement(xmlComp, "layers");
			if(!xmlLayers) { DIE(); }
			{//<layer>
				TiXmlElement* xmlLayer;
				for(xmlLayer = TiXmlNode_FirstChildElement(TiXmlElement_super(xmlLayers), "layer");
				    xmlLayer;
				    xmlLayer = TiXmlNode_NextSiblingElement(TiXmlElement_super(xmlLayer), "layer")) {
					ST_AfxLyr* pAfxLyr = AfxSeq_LoadLayer(TiXmlElement_super(xmlLayer), fnGetFootage, user_data);
					g_ptr_array_add(arLayer, pAfxLyr);
				}
			}//</layer>
		}//</layers>
		if(!arLayer->len || (arLayer->len > USHRT_MAX)) { DIE(); }
		pAfxSeq = malloc(sizeof(ST_AfxSeq) +
		                (sizeof(ST_AfxLyr*) * arLayer->len) +
		                (strlen(name) + 1/*nul*/));				//ST_AfxSeq.name偑巜偡暥帤楍偼丄屄暿偵strdup()偡傞偺偱偼側偔丄ST_AfxSeq.layers[nLayers]偺屻偵傑偲傔偰妋曐偡傞帠偵偟偨丅
		memcpy(pAfxSeq->layers, arLayer->pdata, sizeof(ST_AfxLyr*) * arLayer->len);
		pAfxSeq->nLayers = arLayer->len;
		g_ptr_array_unref(arLayer);
	}
	pAfxSeq->name = strcpy((char*)&pAfxSeq->layers[pAfxSeq->nLayers], name);	//ST_AfxSeq.name偑巜偡暥帤楍偼丄屄暿偵strdup()偡傞偺偱偼側偔丄ST_AfxSeq.layers[nLayers]偺屻偵傑偲傔偰妋曐偡傞帠偵偟偨丅
	AfxSeq_GetVal1(xmlComp, "totalFrame", &pAfxSeq->totalFrame, 1, USHRT_MAX);
	return pAfxSeq;
}
/*--------------------------------------------------------------------------*/
static void AfxSeq_FreeLayer(ST_AfxLyr* pAfxLyr) {
	if(pAfxLyr->pAfxSeq) {
		AfxSeq_FreeComp(pAfxLyr->pAfxSeq);
	}
	free(pAfxLyr);									//ST_AfxLyr.name偑巜偡暥帤楍偼丄ST_AfxLyr.frames[nFrames]偺屻偵傑偲傔偰妋曐偟偰偄傞偺偱丄偙偺free()偱堦弿偵奐曻弌棃傞丅
}
/*--------------------------------------------------------------------------*/
static void AfxSeq_FreeComp(ST_AfxSeq* pAfxSeq) {
	int iLayer;
	for(iLayer = 0; iLayer < pAfxSeq->nLayers; iLayer++) {
		AfxSeq_FreeLayer(pAfxSeq->layers[iLayer]);
	}
	free(pAfxSeq);									//ST_AfxSeq.name偑巜偡暥帤楍偼丄ST_AfxSeq.layers[nLayers]偺屻偵傑偲傔偰妋曐偟偰偄傞偺偱丄偙偺free()偱堦弿偵奐曻弌棃傞丅
}
/*--------------------------------------------------------------------------*/
static void AfxSeq_DrawLayer(const ST_AfxLyr* pAfxLyr, int iFrame, int bLoop, const ST_AfxMat* pAfxMat, double opacity, int blendingMode, ST_AfxSeq_Draw_Param* param) {
	iFrame -= pAfxLyr->startFrame;
	if((unsigned)iFrame < pAfxLyr->nFrames) {
		const ST_AfxFra* pAfxFra = &pAfxLyr->frames[iFrame];
		ST_AfxMat tmp = *pAfxMat;
		AfxMat_Position(&tmp, pAfxFra->position[0], pAfxFra->position[1]);
		AfxMat_Rotation(&tmp, (pAfxFra->rotation * (M_PI / 180.0)));
		AfxMat_Scale(&tmp, (pAfxFra->scale[0] / 100.0), (pAfxFra->scale[1] / 100.0));
		AfxMat_AnchorPoint(&tmp, pAfxFra->anchorPoint[0], pAfxFra->anchorPoint[1]);
		opacity *= (pAfxFra->opacity / 100.0);
		if(pAfxLyr->blendingMode) { blendingMode = pAfxLyr->blendingMode; }
		if(pAfxLyr->sequenceLength) {
			ST_AfxVec v[4] = {{pAfxFra->cornerPin[0][0],pAfxFra->cornerPin[0][1]},	//topLeft
			                  {pAfxFra->cornerPin[1][0],pAfxFra->cornerPin[1][1]},	//topRight
			                  {pAfxFra->cornerPin[2][0],pAfxFra->cornerPin[2][1]},	//bottomRight	//劍TriangleFan偺暲傃
			                  {pAfxFra->cornerPin[3][0],pAfxFra->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	//劊
				pAfxLyr->footage,
				iFrame % pAfxLyr->sequenceLength,	//楢斣僔乕働儞僗僼傽僀儖懳墳
				opacity,
				blendingMode,
				param->user_data);
		}
		if(pAfxLyr->pAfxSeq) {
			AfxSeq_DrawComp(
				pAfxLyr->pAfxSeq,
				iFrame, bLoop,
				&tmp,
				opacity,
				blendingMode,
				param);
		}
	}
}
/*--------------------------------------------------------------------------*/
#undef  USE_CLAMP
#define USE_CLAMP	//偙偺僔儞儃儖傪掕媊偡傞偐偟側偄偐偵傛偭偰丄(bLoop=0)偑巜掕偝傟偨帪偺嫇摦偑曄傢傝傑偡丅iFrame傪[0,totalFrame-1]偺斖埻偵僋儔儞僾偟偰昤夋偡傞応崌偼丄偙偺峴傪桳岠偵偟偰壓偝偄丅iFrame偑斖埻奜側傜偽偙偺僐儞億僕僔儑儞傪昤夋偟側偄応崌偼丄偙偺峴傪僐儊儞僩傾僂僩偟偰壓偝偄丅
static void AfxSeq_DrawComp(const ST_AfxSeq* pAfxSeq, int iFrame, int bLoop, const ST_AfxMat* pAfxMat, double opacity, int blendingMode, ST_AfxSeq_Draw_Param* param) {
	pAfxSeq = (*param->fnFilter)(param->layerDepth, param->layerPath, pAfxSeq, param->user_data);
	if(pAfxSeq) {	//傾僾儕働乕僔儑儞掕媊偺僼傿儖僞娭悢偑NULL傪曉偟偨応崌偼丄偙偺僐儞億僕僔儑儞奒憌埲壓偺張棟傪峴傢側偄丅
		int iLayer;
		if(bLoop) {
			iFrame %= pAfxSeq->totalFrame;
			if(iFrame < 0) { iFrame += pAfxSeq->totalFrame; }
#ifdef  USE_CLAMP
		} else {
			iFrame = clamp(iFrame, 0, (pAfxSeq->totalFrame - 1));
#endif//USE_CLAMP
		}
#ifndef USE_CLAMP
		if((unsigned)iFrame < pAfxSeq->totalFrame) {
#endif//USE_CLAMP
			if(++param->layerDepth >= ARRAY_SIZE(param->layerPath)) { DIE(); }	//偙偙偱掆巭偟偨傜丄ST_AfxSeq_Draw_Param.layerPath[]偺梫慺悢傪憹傗偟偰壓偝偄丅
			for(iLayer = pAfxSeq->nLayers - 1; iLayer >= 0; iLayer--) {	//AfterEffects偼僞僀儉儔僀儞僷僱儖偱忋偵桳傞儗僀儎傎偳庤慜偵昤夋偡傞傛偆偱偡丅偮傑傝僾儘僌儔儉張棟偱偼昤夋弴彉傪媡偵偡傟偽AfterEffects偲摨偠偵側傝傑偡丅
				ST_AfxLyr* pAfxLyr = pAfxSeq->layers[iLayer];
				param->layerPath[param->layerDepth - 1] = pAfxLyr->name;
			//晄梫	param->layerPath[param->layerDepth] = NULL;	//layerPath[]偺弶婜抣偼慡梫慺NULL偱偁傝丄偐偮丄奒憌偺張棟偑廔傢偭偨帪偵億僀儞僞傪NULL偵栠偟偰偄傞偺偱丄偙偙偱廔抂偺NULL傪奿擺偡傞昁梫偼桳傝傑偣傫丅
				AfxSeq_DrawLayer(pAfxLyr, iFrame, bLoop, pAfxMat, opacity, blendingMode, param);	//     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			}												//				劆
			param->layerPath[--param->layerDepth] = NULL;	//昁梫	//仼劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劊
#ifndef USE_CLAMP
		}
#endif//USE_CLAMP
	}
}
#undef  USE_CLAMP
/****************************************************************************
 *	僌儘乕僶儖娭悢
 ****************************************************************************/
void AfxSeq_Load(const char* path, void (*fnLoad)(ST_AfxSeq* pAfxSeq, void* user_data), int (*fnGetFootage)(const char* fileName, void* user_data), void* user_data) {
	TiXmlDocument* xmlDoc = TiXmlDocument_new(NULL);
	TiXmlDocument_LoadFile(xmlDoc, path);
	{//<AfxSeq>
		TiXmlElement* xmlAfxSeq = TiXmlNode_FirstChildElement(TiXmlDocument_super(xmlDoc), "AfxSeq");
		if(!xmlAfxSeq) { DIE(); }
		{//<comp>
			TiXmlElement* xmlComp;
			for(xmlComp = TiXmlNode_FirstChildElement(TiXmlElement_super(xmlAfxSeq), "comp");
			    xmlComp;
			    xmlComp = TiXmlNode_NextSiblingElement(TiXmlElement_super(xmlComp), "comp")) {
				ST_AfxSeq* pAfxSeq = AfxSeq_LoadComp(TiXmlElement_super(xmlComp), fnGetFootage, user_data);
				(*fnLoad)(pAfxSeq, user_data);
			}
		}//</comp>
	}//</AfxSeq>
	TiXmlDocument_delete(xmlDoc);
}
/*--------------------------------------------------------------------------*/
void AfxSeq_Free(ST_AfxSeq* pAfxSeq) {
	AfxSeq_FreeComp(pAfxSeq);
}
/*--------------------------------------------------------------------------*/
static void AfxSeq_Draw_fnDraw(int layerDepth, const char* layerPath[], int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, int footage, int sequence, double opacity, int blendingMode, void* user_data) { /** no job **/ }
static const ST_AfxSeq* AfxSeq_Draw_fnFilter(int layerDepth, const char* layerPath[], const ST_AfxSeq* pAfxSeq, void* user_data) { return pAfxSeq; }
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void AfxSeq_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, int 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) {
	ST_AfxSeq_Draw_Param param;
	memset(&param, 0, sizeof param);	//layerDepth,媦傃,layerPath偺慡梫慺傪NULL偲偡傞偨傔偵僋儕傾昁梫丅徻嵶偼AfxSeq_DrawComp()撪偺僐儊儞僩傪嶲徠偟偰壓偝偄丅
	param.fnDraw    = fnDraw   ? fnDraw   : AfxSeq_Draw_fnDraw;
	param.fnFilter  = fnFilter ? fnFilter : AfxSeq_Draw_fnFilter;
	param.user_data = user_data;
	AfxSeq_DrawComp(pAfxSeq, iFrame, bLoop, pAfxMat, opacity, blendingMode, &param);
}
#endif//USE_AFXSEQ
