/*
 *	clipeffg.c
 *
 *	EFFect GENerator
 *
 *	* Mon Jul 24 23:04:05 JST 2017 Naoyuki Sawa
 *	- 1st リリース。
 *	* Tue Jul 25 22:09:40 JST 2017 Naoyuki Sawa
 *	- EffGen_SawCir()をスケールを変えながら描画した時に、揺らぎが変わってしまっていたバグを修正しました。
 *	  具体的には、以下の通りです。
 *	- 例えば、以下のような拡大アニメーションを行った場合に、これまでの実装では、毎フレーム揺らぎが変わってしまっていました:
 *	  │	for(;;) {
 *	  │		schedule();
 *	  │		double d = (double)(now % SEC(3.0)) / (double)SEC(3.0);
 *	  │		EffGen_SawCir(DISP_X/2,DISP_Y/2,d*50,d*100,d*50,d*150,d*200,d*50,0,32,0,fnRenderPolygon,NULL);
 *	  │	}
 *	  バグの原因は、(指定された揺らぎ幅+1)で整数乱数値の剰余を求めて、揺らぎを決定していた事が原因でした。
 *	  拡大アニメーション時に揺らぎ幅もスケーリングされると、整数乱数値の剰余の結果はスケーリングではなく、無関係に値が変わるからです。
 *	  正しくは、指定された揺らぎ幅に0.0〜1.0の乱数値を掛けて、揺らぎを決定すべきでした。
 *	  今回、そのように修正したので、上述の問題は解決しました。
 *	- 尚、厳密には、'指定された揺らぎ幅に0.0〜1.0の乱数値を掛ける'べきなのですが、frnd()の仕様上、今回の実装では0.0以上1.0未満の乱数値を掛けています。
 *	  そのため、指定された揺らぎ幅の最大値の揺らぎが発生する事は有りません。
 *	  見た目で判る程の違いは生じないと思うので、このままとする事にしました。
 *	  もし厳密に処理するには、0.0以上1.0以下の固定小数乱数を生成する関数を作成すれば可能で、minimum_mask_greater_than_or_equal_to()を利用すればさほど手間はかからないと思います。
 *	  しかし、処理時間が増える割に、得られる利点は少ないと思うので、今回はその方法は取らない事にしました。
 *	* Thu Jul 27 22:18:31 JST 2017 Naoyuki Sawa
 *	- EffGen_DiaOva()を追加しました。
 */
#include "clip.h"
//*****************************************************************************
//	グローバル関数
//*****************************************************************************
//全円ギザギザエフェクトの図形を描画する。
//[in]
//	x,y			中心座標
//	radiusSunkenInner	引っ込みの内側半径		┬(radiusSunkenInner≦radiusSunkenOuter)必須　─┬──(radiusSunkenInner≦radiusRaisedInner)必須
//	radiusSunkenOuter	引っ込みの外側半径		┘───────────────────────│┐┐
//	radiusSunkenFluct	引っ込みの半径の揺らぎ幅	(radiusSunkenFluct≧0)				││├((radiusSunkenOuter+radiusSunkenFluct)≦radiusRaisedInner)が望ましいが必須ではない。
//	radiusRaisedInner	出っ張りの内側半径		┬(radiusRaisedInner≦radiusRaisedOuter)必須　─┘│┘
//	radiusRaisedOuter	出っ張りの外側半径		┘────────────────────────┴─(radiusSunkenOuter≦radiusRaisedOuter)必須
//	radiusRaisedFluct	出っ張りの半径の揺らぎ幅	(radiusRaisedFluct≧0)
//	angleOrg		基準角度			一分割目の引っ込みの頂点がどの角度から生成されるかを指定する。特に気にしないならば常に0を指定して構わない。
//	nDiv			分割数				(nDiv≧3)	引っ込みと出っ張りの組み合わせで一つと数える。
//	seed			乱数シード			エフェクトの個々のインスタンス毎に毎回同じ値を指定して下さい。特に気にしないならば常に0を指定して構わない。
//	fnRenderPolygon		アプリケーション定義のポリゴン描画関数
//	arg			アプリケーション定義のポリゴン描画関数へ引き渡す任意のデータ
//[note]
//	- ラジルギ(https://en.wikipedia.org/wiki/Radirgy)の、大型機を破壊した時のエフェクトに似たエフェクトを描画します。
//	  関数名の'SawCir'は、'SAW-toothed CIRcle effect'の略です。
//	- 当関数は、図形の描画のみを行う関数です。
//	  アニメーションを行うには、EffAnm_RadLar()等を利用するか、又は、アプリケーション自身でパラメータを計算して当関数を呼び出して下さい。
void EffGen_SawCir(int   x,			//┬中心座標
                   int   y,			//┘
                   int   radiusSunkenInner,	//引っ込みの内側半径		┬(radiusSunkenInner≦radiusSunkenOuter)必須　─┬──(radiusSunkenInner≦radiusRaisedInner)必須
                   int   radiusSunkenOuter,	//引っ込みの外側半径		┘───────────────────────│┐┐
                   int   radiusSunkenFluct,	//引っ込みの半径の揺らぎ幅	(radiusSunkenFluct≧0)				││├((radiusSunkenOuter+radiusSunkenFluct)≦radiusRaisedInner)が望ましいが必須ではない。
                   int   radiusRaisedInner,	//出っ張りの内側半径		┬(radiusRaisedInner≦radiusRaisedOuter)必須　─┘│┘
                   int   radiusRaisedOuter,	//出っ張りの外側半径		┘────────────────────────┴─(radiusSunkenOuter≦radiusRaisedOuter)必須
                   int   radiusRaisedFluct,	//出っ張りの半径の揺らぎ幅	(radiusRaisedFluct≧0)
                   fixed angleOrg,		//基準角度			一分割目の引っ込みの頂点がどの角度から生成されるかを指定する。特に気にしないならば常に0を指定して構わない。
                   int   nDiv,			//分割数			(nDiv≧3)	引っ込みと出っ張りの組み合わせで一つと数える。
                   int   seed,			//乱数シード			エフェクトの個々のインスタンス毎に毎回同じ値を指定して下さい。特に気にしないならば常に0を指定して構わない。
                   void (*fnRenderPolygon)(const int xy[/*n*/][2/*x,y*/], int n/*3or4*/, void* arg),	//アプリケーション定義のポリゴン描画関数
                   void* arg) {										//アプリケーション定義のポリゴン描画関数へ引き渡す任意のデータ
	const int save_seed = seed;	//乱数シードの初期値を保存する。
	int iDiv, xy[4/*n*/][2/*x,y*/];
	if((radiusSunkenInner < 0) ||
	   (radiusSunkenFluct < 0) ||
	   (radiusRaisedFluct < 0) ||
	   (radiusSunkenOuter < radiusSunkenInner) ||
	   (radiusRaisedOuter < radiusRaisedInner) ||
	   (radiusRaisedInner < radiusSunkenInner) ||
	   (radiusRaisedOuter < radiusSunkenOuter) ||
	   (nDiv < 3)) { DIE(); }
	//各分割について…
	for(iDiv = 0, nDiv *= 2;
	    iDiv <    nDiv;
	    iDiv           += 2) {
		int fluct, radius;
		fixed angle, cosValue, sinValue;
		//前半のポリゴンを描く。
	    if(!iDiv) {
//{{2017/07/25変更:EffGen_SawCir()をスケールを変えながら描画した時に、揺らぎが変わってしまっていたバグを修正しました。
//		fluct = (unsigned)rnd32(&seed) % (unsigned)(radiusSunkenFluct + 1);	//引っ込みの半径の揺らぎ
//↓2017/07/25変更:EffGen_SawCir()をスケールを変えながら描画した時に、揺らぎが変わってしまっていたバグを修正しました。
		fluct = fist(fimul(frnd(&seed), radiusSunkenFluct));			//引っ込みの半径の揺らぎ
//}}2017/07/25変更:EffGen_SawCir()をスケールを変えながら描画した時に、揺らぎが変わってしまっていたバグを修正しました。
		angle = fadd(angleOrg, fidiv(fimul(PI2, iDiv + 0), nDiv));		//┐
		cosValue = fcos(angle);							//├前半の引っ込みの角度
		sinValue = fsin(angle);							//┘
		radius = radiusSunkenInner + fluct;					//┐
		xy[0][0/*x*/] = x + fist(fimul(cosValue, radius));			//├前半の引っ込みの内側の頂点
		xy[0][1/*y*/] = y + fist(fimul(sinValue, radius));			//┘
		radius = radiusSunkenOuter + fluct;					//┐
		xy[1][0/*x*/] = x + fist(fimul(cosValue, radius));			//├前半の引っ込みの外側の頂点
		xy[1][1/*y*/] = y + fist(fimul(sinValue, radius));			//┘
	    } else {
		xy[0][0/*x*/] = xy[3][0/*x*/];						//┬前半の引っ込みの内側の頂点
		xy[0][1/*y*/] = xy[3][1/*y*/];						//┘
		xy[1][0/*x*/] = xy[2][0/*x*/];						//┬前半の引っ込みの外側の頂点
		xy[1][1/*y*/] = xy[2][1/*y*/];						//┘
	    }
//{{2017/07/25変更:EffGen_SawCir()をスケールを変えながら描画した時に、揺らぎが変わってしまっていたバグを修正しました。
//		fluct = (unsigned)rnd32(&seed) % (unsigned)(radiusRaisedFluct + 1);	//出っ張りの半径の揺らぎ
//↓2017/07/25変更:EffGen_SawCir()をスケールを変えながら描画した時に、揺らぎが変わってしまっていたバグを修正しました。
		fluct = fist(fimul(frnd(&seed), radiusRaisedFluct));			//出っ張りの半径の揺らぎ
//}}2017/07/25変更:EffGen_SawCir()をスケールを変えながら描画した時に、揺らぎが変わってしまっていたバグを修正しました。
		angle = fadd(angleOrg, fidiv(fimul(PI2, iDiv + 1), nDiv));		//┐
		cosValue = fcos(angle);							//├前半の引っ込みの角度
		sinValue = fsin(angle);							//┘
		radius = radiusRaisedOuter + fluct;					//┐
		xy[2][0/*x*/] = x + fist(fimul(cosValue, radius));			//├中間の出っ張りの外側の頂点
		xy[2][1/*y*/] = y + fist(fimul(sinValue, radius));			//┘
		radius = radiusRaisedInner + fluct;					//┐
		xy[3][0/*x*/] = x + fist(fimul(cosValue, radius));			//├中間の出っ張りの内側の頂点
		xy[3][1/*y*/] = y + fist(fimul(sinValue, radius));			//┘
		(*fnRenderPolygon)(xy,
		                 ((xy[0][0/*x*/] == xy[3][0/*x*/]) &&
		                  (xy[0][1/*y*/] == xy[3][1/*y*/])) ? 3 : 4,		//前半の引っ込みの内側の頂点と中間の出っ張りの内側の頂点が重なっているならば(=引っ込みの内側半径と出っ張りの内側半径が共に0,又は,0に近い値だった場合にそうなり得る)、三角形ポリゴンとして描く。そうでなければ、四角形ポリゴンとして描く。この判断は必須ではなく、三角形ポリゴンを四角形ポリゴンとして描いても同じ結果になるが、描画処理の負荷を減らすために当関数にて判断する事にした。
		                   arg);
		//後半のポリゴンを描く。
		xy[0][0/*x*/] = xy[3][0/*x*/];						//┬中間の出っ張りの内側の頂点
		xy[0][1/*y*/] = xy[3][1/*y*/];						//┘
		xy[1][0/*x*/] = xy[2][0/*x*/];						//┬中間の出っ張りの外側の頂点
		xy[1][1/*y*/] = xy[2][1/*y*/];						//┘
	    if((iDiv + 2) == nDiv) {
		seed = save_seed;	//乱数シードの初期値を復元する。一分割目の前半の引っ込みと最終分割の後半の引っ込みを、同じ揺らぎ(=同じ座標)にして連結するためです。ちなみに、EffGen_SawArc()の場合は、一分割目の前半の引っ込みと最終分割の後半の引っ込みが連結していないので、この処理は不要です。
	    }
//{{2017/07/25変更:EffGen_SawCir()をスケールを変えながら描画した時に、揺らぎが変わってしまっていたバグを修正しました。
//		fluct = (unsigned)rnd32(&seed) % (unsigned)(radiusSunkenFluct + 1);	//引っ込みの半径の揺らぎ
//↓2017/07/25変更:EffGen_SawCir()をスケールを変えながら描画した時に、揺らぎが変わってしまっていたバグを修正しました。
		fluct = fist(fimul(frnd(&seed), radiusSunkenFluct));			//引っ込みの半径の揺らぎ
//}}2017/07/25変更:EffGen_SawCir()をスケールを変えながら描画した時に、揺らぎが変わってしまっていたバグを修正しました。
		angle = fadd(angleOrg, fidiv(fimul(PI2, iDiv + 2), nDiv));		//┐
		cosValue = fcos(angle);							//├前半の引っ込みの角度
		sinValue = fsin(angle);							//┘
		radius = radiusSunkenOuter + fluct;					//┐
		xy[2][0/*x*/] = x + fist(fimul(cosValue, radius));			//├後半の引っ込みの外側の頂点
		xy[2][1/*y*/] = y + fist(fimul(sinValue, radius));			//┘
		radius = radiusSunkenInner + fluct;					//┐
		xy[3][0/*x*/] = x + fist(fimul(cosValue, radius));			//├後半の引っ込みの内側の頂点
		xy[3][1/*y*/] = y + fist(fimul(sinValue, radius));			//┘
		(*fnRenderPolygon)(xy,
		                 ((xy[0][0/*x*/] == xy[3][0/*x*/]) &&
		                  (xy[0][1/*y*/] == xy[3][1/*y*/])) ? 3 : 4,		//前半の引っ込みの内側の頂点と中間の出っ張りの内側の頂点が重なっているならば(=引っ込みの内側半径と出っ張りの内側半径が共に0,又は,0に近い値だった場合にそうなり得る)、三角形ポリゴンとして描く。そうでなければ、四角形ポリゴンとして描く。この判断は必須ではなく、三角形ポリゴンを四角形ポリゴンとして描いても同じ結果になるが、描画処理の負荷を減らすために当関数にて判断する事にした。
		                   arg);
	}
}
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#if 0
//□EffGen_SawCir()の使用例
#ifdef  PIECE
static void fnRenderPolygon(const int xy[/*n*/][2/*x,y*/], int n/*3or4*/, void* arg) {
	VERTEX v[]={{xy[0][0],xy[0][1]},{xy[1][0],xy[1][1]},{xy[2][0],xy[2][1]},{xy[3][0],xy[3][1]}};
	render_polygon(&render, v, n, 0);
}
int app_main(int argc, char* argv[]) {
	for(;;) {
		schedule();
		surface_clear(&surface, 3);
		EffGen_SawCir(
			DISP_X/2,		//x
			DISP_Y/2,		//y
			10,			//radiusSunkenInner
			20,			//radiusSunkenOuter
			10,			//radiusSunkenFluct
			30,			//radiusRaisedInner
			40,			//radiusRaisedOuter
			10,			//radiusRaisedFluct
			0,			//angleOrg
			32,			//nDiv			ラジルギの全円ギザギザエフェクトは、見た感じ128分割ぐらい(?)みたいです。完全に真似る必要は無いので、かなり少なめにしてみました。
			0,			//seed
			fnRenderPolygon,	//fnRenderPolygon
			NULL);			//arg
	}
	return 0;
}
#endif//PIECE
#ifdef  WIN32
static void fnRenderPolygon(const int xy[/*n*/][2/*x,y*/], int n/*3or4*/, void* arg) { draw_polygon_fill(xy, n); }
int cpp_main(int argc, char* argv[]) {
	if(RRS_i_job(pRRS) != (RRS_n_job(pRRS) - 1)) { DIE(); }	//最後のジョブがUIジョブである事を確認する。
	if(!setjmp(env_exit)) {
		for(;;) {
			schedule();
			EffGen_SawCir(
				DISP_X/2,		//x
				DISP_Y/2,		//y
				50,			//radiusSunkenInner
				100,			//radiusSunkenOuter
				50,			//radiusSunkenFluct
				150,			//radiusRaisedInner
				200,			//radiusRaisedOuter
				50,			//radiusRaisedFluct
				0,			//angleOrg
				32,			//nDiv			ラジルギの全円ギザギザエフェクトは、見た感じ128分割ぐらい(?)みたいです。完全に真似る必要は無いので、かなり少なめにしてみました。
				0,			//seed
				fnRenderPolygon,	//fnRenderPolygon
				NULL);			//arg
		}
	}
	return 0;
}
#endif//WIN32
#endif
//-----------------------------------------------------------------------------
//円弧ギザギザエフェクトの図形を描画する。
//[in]
//	x,y			中心座標
//	radiusSunkenInner	引っ込みの内側半径		┬(radiusSunkenInner≦radiusSunkenOuter)必須　─┬──(radiusSunkenInner≦radiusRaisedInner)必須
//	radiusSunkenOuter	引っ込みの外側半径		┘───────────────────────│┐┐
//	radiusSunkenFluct	引っ込みの半径の揺らぎ幅	(radiusSunkenFluct≧0)				││├((radiusSunkenOuter+radiusSunkenFluct)≦radiusRaisedInner)が望ましいが必須ではない。
//	radiusRaisedInner	出っ張りの内側半径		┬(radiusRaisedInner≦radiusRaisedOuter)必須　─┘│┘
//	radiusRaisedOuter	出っ張りの外側半径		┘────────────────────────┴─(radiusSunkenOuter≦radiusRaisedOuter)必須
//	radiusRaisedFluct	出っ張りの半径の揺らぎ幅	(radiusRaisedFluct≧0)
//	radiusTaper		両端の絞り半径			(radiusTaper≦radiusSunkenInner)
//	angleMin		開始角度			┬(angleMin≦angleMax)
//	angleMax		終了角度			┘
//	nDiv			分割数				(nDiv≧3)	引っ込みと出っ張りの組み合わせで一つと数える。
//	seed			乱数シード			エフェクトの個々のインスタンス毎に毎回同じ値を指定して下さい。特に気にしないならば常に0を指定して構わない。
//	fnRenderPolygon		アプリケーション定義のポリゴン描画関数
//	arg			アプリケーション定義のポリゴン描画関数へ引き渡す任意のデータ
//[note]
//	- ラジルギ(https://en.wikipedia.org/wiki/Radirgy)の、中型機を破壊した時のエフェクトに似たエフェクトを描画します。
//	  関数名の'SawArc'は、'SAW-toothed ARC effect'の略です。
//	- 正確には、ラジルギの中型機を破壊した時のエフェクトは、当エフェクトを反対方向に二つ描いたようなエフェクトです。
//	  当関数を用いて、ラジルギの中型機を破壊した時のエフェクトに似た描画を行う方法は、後述の使用例を参照して下さい。
//	- 当関数は、図形の描画のみを行う関数です。
//	  アニメーションを行うには、EffAnm_RadMed()等を利用するか、又は、アプリケーション自身でパラメータを計算して当関数を呼び出して下さい。
void EffGen_SawArc(int   x,			//┬中心座標
                   int   y,			//┘
                   int   radiusSunkenInner,	//引っ込みの内側半径		┬(radiusSunkenInner≦radiusSunkenOuter)必須　─┬──(radiusSunkenInner≦radiusRaisedInner)必須
                   int   radiusSunkenOuter,	//引っ込みの外側半径		┘───────────────────────│┐┐
                   int   radiusSunkenFluct,	//引っ込みの半径の揺らぎ幅	(radiusSunkenFluct≧0)				││├((radiusSunkenOuter+radiusSunkenFluct)≦radiusRaisedInner)が望ましいが必須ではない。
                   int   radiusRaisedInner,	//出っ張りの内側半径		┬(radiusRaisedInner≦radiusRaisedOuter)必須　─┘│┘
                   int   radiusRaisedOuter,	//出っ張りの外側半径		┘────────────────────────┴─(radiusSunkenOuter≦radiusRaisedOuter)必須
                   int   radiusRaisedFluct,	//出っ張りの半径の揺らぎ幅	(radiusRaisedFluct≧0)
                   int   radiusTaper,		//両端の絞り半径		(radiusTaper≦radiusSunkenInner)
                   fixed angleMin,		//開始角度			┬(angleMin≦angleMax)
                   fixed angleMax,		//終了角度			┘
                   int   nDiv,			//分割数			(nDiv≧3)	引っ込みと出っ張りの組み合わせで一つと数える。
                   int   seed,			//乱数シード			エフェクトの個々のインスタンス毎に毎回同じ値を指定して下さい。特に気にしないならば常に0を指定して構わない。
                   void (*fnRenderPolygon)(const int xy[/*n*/][2/*x,y*/], int n/*3or4*/, void* arg),	//アプリケーション定義のポリゴン描画関数
                   void* arg) {										//アプリケーション定義のポリゴン描画関数へ引き渡す任意のデータ
	int iDiv, xy[4/*n*/][2/*x,y*/];
	if((radiusSunkenInner < 0) ||
	   (radiusSunkenFluct < 0) ||
	   (radiusRaisedFluct < 0) ||
	   (radiusSunkenOuter < radiusSunkenInner) ||
	   (radiusRaisedOuter < radiusRaisedInner) ||
	   (radiusRaisedInner < radiusSunkenInner) ||
	   (radiusRaisedOuter < radiusSunkenOuter) ||
	   (radiusSunkenInner < radiusTaper) ||
	   fcom(angleMax, <, angleMin) ||
	   (nDiv < 3)) { DIE(); }
	//各分割について…
	for(iDiv = 0, nDiv *= 2;
	    iDiv <    nDiv;
	    iDiv           += 2) {
		int fluct, radius;
		fixed taper, angle, cosValue, sinValue;
		//前半のポリゴンを描く。
	    if(!iDiv) {
		taper = fsin(fidiv(fimul(PI, iDiv + 0), nDiv));								//両端の絞り
//{{2017/07/25変更:EffGen_SawCir()をスケールを変えながら描画した時に、揺らぎが変わってしまっていたバグを修正しました。
//		fluct = (unsigned)rnd32(&seed) % (unsigned)(radiusSunkenFluct + 1);					//引っ込みの半径の揺らぎ
//↓2017/07/25変更:EffGen_SawCir()をスケールを変えながら描画した時に、揺らぎが変わってしまっていたバグを修正しました。
		fluct = fist(fimul(frnd(&seed), radiusSunkenFluct));							//引っ込みの半径の揺らぎ
//}}2017/07/25変更:EffGen_SawCir()をスケールを変えながら描画した時に、揺らぎが変わってしまっていたバグを修正しました。
		angle = fadd(angleMin, fidiv(fimul(fsub(angleMax, angleMin), iDiv + 0), nDiv));				//┐
		cosValue = fcos(angle);											//├前半の引っ込みの角度
		sinValue = fsin(angle);											//┘
		radius = radiusTaper + fist(fimul(taper, radiusSunkenInner + fluct - radiusTaper));			//┐
		xy[0][0/*x*/] = x + fist(fimul(cosValue, radius));							//├前半の引っ込みの内側の頂点
		xy[0][1/*y*/] = y + fist(fimul(sinValue, radius));							//┘
		radius = radiusTaper + fist(fimul(taper, radiusSunkenOuter + fluct - radiusTaper));			//┐
		xy[1][0/*x*/] = x + fist(fimul(cosValue, radius));							//├前半の引っ込みの外側の頂点
		xy[1][1/*y*/] = y + fist(fimul(sinValue, radius));							//┘
	    } else {
		xy[0][0/*x*/] = xy[3][0/*x*/];										//┬前半の引っ込みの内側の頂点
		xy[0][1/*y*/] = xy[3][1/*y*/];										//┘
		xy[1][0/*x*/] = xy[2][0/*x*/];										//┬前半の引っ込みの外側の頂点
		xy[1][1/*y*/] = xy[2][1/*y*/];										//┘
	    }
		taper = fsin(fidiv(fimul(PI, iDiv + 1), nDiv));								//両端の絞り
//{{2017/07/25変更:EffGen_SawCir()をスケールを変えながら描画した時に、揺らぎが変わってしまっていたバグを修正しました。
//		fluct = (unsigned)rnd32(&seed) % (unsigned)(radiusRaisedFluct + 1);					//出っ張りの半径の揺らぎ
//↓2017/07/25変更:EffGen_SawCir()をスケールを変えながら描画した時に、揺らぎが変わってしまっていたバグを修正しました。
		fluct = fist(fimul(frnd(&seed), radiusRaisedFluct));							//出っ張りの半径の揺らぎ
//}}2017/07/25変更:EffGen_SawCir()をスケールを変えながら描画した時に、揺らぎが変わってしまっていたバグを修正しました。
		angle = fadd(angleMin, fidiv(fimul(fsub(angleMax, angleMin), iDiv + 1), nDiv));				//┐
		cosValue = fcos(angle);											//├前半の引っ込みの角度
		sinValue = fsin(angle);											//┘
		radius = radiusTaper + fist(fimul(taper, radiusRaisedOuter + fluct - radiusTaper));			//┐
		xy[2][0/*x*/] = x + fist(fimul(cosValue, radius));							//├中間の出っ張りの外側の頂点
		xy[2][1/*y*/] = y + fist(fimul(sinValue, radius));							//┘
		radius = radiusTaper + fist(fimul(taper, radiusRaisedInner + fluct - radiusTaper));			//┐
		xy[3][0/*x*/] = x + fist(fimul(cosValue, radius));							//├中間の出っ張りの内側の頂点
		xy[3][1/*y*/] = y + fist(fimul(sinValue, radius));							//┘
		(*fnRenderPolygon)(xy,
		                 ((xy[0][0/*x*/] == xy[3][0/*x*/]) &&
		                  (xy[0][1/*y*/] == xy[3][1/*y*/])) ? 3 : 4,						//前半の引っ込みの内側の頂点と中間の出っ張りの内側の頂点が重なっているならば(=引っ込みの内側半径と出っ張りの内側半径が共に0,又は,0に近い値だった場合にそうなり得る)、三角形ポリゴンとして描く。そうでなければ、四角形ポリゴンとして描く。この判断は必須ではなく、三角形ポリゴンを四角形ポリゴンとして描いても同じ結果になるが、描画処理の負荷を減らすために当関数にて判断する事にした。
		                   arg);
		//後半のポリゴンを描く。
		xy[0][0/*x*/] = xy[3][0/*x*/];										//┬中間の出っ張りの内側の頂点
		xy[0][1/*y*/] = xy[3][1/*y*/];										//┘
		xy[1][0/*x*/] = xy[2][0/*x*/];										//┬中間の出っ張りの外側の頂点
		xy[1][1/*y*/] = xy[2][1/*y*/];										//┘
		taper = fsin(fidiv(fimul(PI, iDiv + 2), nDiv));								//両端の絞り
//{{2017/07/25変更:EffGen_SawCir()をスケールを変えながら描画した時に、揺らぎが変わってしまっていたバグを修正しました。
//		fluct = (unsigned)rnd32(&seed) % (unsigned)(radiusSunkenFluct + 1);					//引っ込みの半径の揺らぎ
//↓2017/07/25変更:EffGen_SawCir()をスケールを変えながら描画した時に、揺らぎが変わってしまっていたバグを修正しました。
		fluct = fist(fimul(frnd(&seed), radiusSunkenFluct));							//引っ込みの半径の揺らぎ
//}}2017/07/25変更:EffGen_SawCir()をスケールを変えながら描画した時に、揺らぎが変わってしまっていたバグを修正しました。
		angle = fadd(angleMin, fidiv(fimul(fsub(angleMax, angleMin), iDiv + 2), nDiv));				//┐
		cosValue = fcos(angle);											//├後半の引っ込みの角度
		sinValue = fsin(angle);											//┘
		radius = radiusTaper + fist(fimul(taper, radiusSunkenOuter + fluct - radiusTaper));			//┐
		xy[2][0/*x*/] = x + fist(fimul(cosValue, radius));							//├後半の引っ込みの外側の頂点
		xy[2][1/*y*/] = y + fist(fimul(sinValue, radius));							//┘
		radius = radiusTaper + fist(fimul(taper, radiusSunkenInner + fluct - radiusTaper));			//┐
		xy[3][0/*x*/] = x + fist(fimul(cosValue, radius));							//├後半の引っ込みの内側の頂点
		xy[3][1/*y*/] = y + fist(fimul(sinValue, radius));							//┘
		(*fnRenderPolygon)(xy,
		                 ((xy[0][0/*x*/] == xy[3][0/*x*/]) &&
		                  (xy[0][1/*y*/] == xy[3][1/*y*/])) ? 3 : 4,						//前半の引っ込みの内側の頂点と中間の出っ張りの内側の頂点が重なっているならば(=引っ込みの内側半径と出っ張りの内側半径が共に0,又は,0に近い値だった場合にそうなり得る)、三角形ポリゴンとして描く。そうでなければ、四角形ポリゴンとして描く。この判断は必須ではなく、三角形ポリゴンを四角形ポリゴンとして描いても同じ結果になるが、描画処理の負荷を減らすために当関数にて判断する事にした。
		                   arg);
	}
}
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#if 0
//□EffGen_SawArc()の使用例
#ifdef  PIECE
static void fnRenderPolygon(const int xy[/*n*/][2/*x,y*/], int n/*3or4*/, void* arg) {
	VERTEX v[]={{xy[0][0],xy[0][1]},{xy[1][0],xy[1][1]},{xy[2][0],xy[2][1]},{xy[3][0],xy[3][1]}};
	render_polygon(&render, v, n, 0);
}
int app_main(int argc, char* argv[]) {
	int i;
	for(;;) {
		schedule();
		surface_clear(&surface, 3);
		for(i = 0; i < 2; i++) {
			EffGen_SawArc(
				DISP_X/2,		//x
				DISP_Y/2,		//y
				10,			//radiusSunkenInner
				20,			//radiusSunkenOuter
				10,			//radiusSunkenFluct
				30,			//radiusRaisedInner
				40,			//radiusRaisedOuter
				10,			//radiusRaisedFluct
				25,			//radiusTaper
				fld(M_PI*(i-0.1)),	//angleMin
				fld(M_PI*(i+0.5)),	//angleMax
				12,			//nDiv			ラジルギの円弧ギザギザエフェクトが、見た感じおおよそ12分割ぐらいでした。
				i,			//seed
				fnRenderPolygon,	//fnRenderPolygon
				NULL);			//arg
		}
	}
	return 0;
}
#endif//PIECE
#ifdef  WIN32
static void fnRenderPolygon(const int xy[/*n*/][2/*x,y*/], int n/*3or4*/, void* arg) { draw_polygon_fill(xy, n); }
int cpp_main(int argc, char* argv[]) {
	if(RRS_i_job(pRRS) != (RRS_n_job(pRRS) - 1)) { DIE(); }	//最後のジョブがUIジョブである事を確認する。
	if(!setjmp(env_exit)) {
		for(;;) {
			schedule();
			for(int i = 0; i < 2; i++) {
				EffGen_SawArc(
					DISP_X/2,		//x
					DISP_Y/2,		//y
					50,			//radiusSunkenInner
					100,			//radiusSunkenOuter
					50,			//radiusSunkenFluct
					150,			//radiusRaisedInner
					200,			//radiusRaisedOuter
					50,			//radiusRaisedFluct
					25,			//radiusTaper
					fld(M_PI*(i-0.1)),	//angleMin
					fld(M_PI*(i+0.5)),	//angleMax
					12,			//nDiv			ラジルギの円弧ギザギザエフェクトが、見た感じおおよそ12分割ぐらいでした。
					i,			//seed
					fnRenderPolygon,	//fnRenderPolygon
					NULL);			//arg
			}
		}
	}
	return 0;
}
#endif//WIN32
#endif
//-----------------------------------------------------------------------------
//全円エフェクトの図形を描画する。
//[in]
//	x,y			中心座標
//	radiusInner		内側半径			┬(radiusInner≦radiusOuter)必須
//	radiusOuter		外側半径			┘
//	angleOrg		基準角度			一分割目の頂点がどの角度から生成されるかを指定する。特に気にしないならば常に0を指定して構わない。
//	nDiv			分割数				(nDiv≧3)
//	fnRenderPolygon		アプリケーション定義のポリゴン描画関数
//	arg			アプリケーション定義のポリゴン描画関数へ引き渡す任意のデータ
//[note]
//	- ラジルギ(https://en.wikipedia.org/wiki/Radirgy)の、中型機を破壊した時に、円弧ギザギザエフェクト(EffGen_SawArc())に重ねて、単純な円が広がるエフェクトも描画されているようなので、それに似た描画を行うために用意した関数です。
//	  単純な円は、EffGen_SawCir()で引っ込みと出っ張りのパラメータを同じにして揺らぎ幅を0にする事でも描画出来るのですが、それでは無駄な計算が発生して無駄に負荷が高くなるので、単純な円を描画する専用の関数を用意する事にしました。
//	- 当関数は、図形の描画のみを行う関数です。
//	  アニメーションを行うには、EffAnm_RadMed()等を利用するか、又は、アプリケーション自身でパラメータを計算して当関数を呼び出して下さい。
void EffGen_Circle(int   x,			//┬中心座標
                   int   y,			//┘
                   int   radiusInner,		//内側半径			┬(radiusInner≦radiusOuter)必須
                   int   radiusOuter,		//外側半径			┘
                   fixed angleOrg,		//基準角度			一分割目の頂点がどの角度から生成されるかを指定する。特に気にしないならば常に0を指定して構わない。
                   int   nDiv,			//分割数			(nDiv≧3)	引っ込みと出っ張りの組み合わせで一つと数える。
                   void (*fnRenderPolygon)(const int xy[/*n*/][2/*x,y*/], int n/*3or4*/, void* arg),	//アプリケーション定義のポリゴン描画関数
                   void* arg) {										//アプリケーション定義のポリゴン描画関数へ引き渡す任意のデータ
	int iDiv, xy[4/*n*/][2/*x,y*/];
	if((radiusInner < 0) ||
	   (radiusOuter < radiusInner) ||
	   (nDiv < 3)) { DIE(); }
	//各分割について…
	for(iDiv = 0;
	    iDiv < nDiv;
	    iDiv++) {
		int radius;
		fixed angle, cosValue, sinValue;
	    if(!iDiv) {
		angle = fadd(angleOrg, fidiv(fimul(PI2, iDiv + 0), nDiv));	//┐
		cosValue = fcos(angle);						//├前半の角度
		sinValue = fsin(angle);						//┘
		radius = radiusInner;						//┐
		xy[0][0/*x*/] = x + fist(fimul(cosValue, radius));		//├前半の内側の頂点
		xy[0][1/*y*/] = y + fist(fimul(sinValue, radius));		//┘
		radius = radiusOuter;						//┐
		xy[1][0/*x*/] = x + fist(fimul(cosValue, radius));		//├前半の外側の頂点
		xy[1][1/*y*/] = y + fist(fimul(sinValue, radius));		//┘
	    } else {
		xy[0][0/*x*/] = xy[3][0/*x*/];					//┬前半の内側の頂点
		xy[0][1/*y*/] = xy[3][1/*y*/];					//┘
		xy[1][0/*x*/] = xy[2][0/*x*/];					//┬前半の外側の頂点
		xy[1][1/*y*/] = xy[2][1/*y*/];					//┘
	    }
		angle = fadd(angleOrg, fidiv(fimul(PI2, iDiv + 1), nDiv));	//┐
		cosValue = fcos(angle);						//├後半の角度
		sinValue = fsin(angle);						//┘
		radius = radiusOuter;						//┐
		xy[2][0/*x*/] = x + fist(fimul(cosValue, radius));		//├後半の外側の頂点
		xy[2][1/*y*/] = y + fist(fimul(sinValue, radius));		//┘
		radius = radiusInner;						//┐
		xy[3][0/*x*/] = x + fist(fimul(cosValue, radius));		//├後半の内側の頂点
		xy[3][1/*y*/] = y + fist(fimul(sinValue, radius));		//┘
		(*fnRenderPolygon)(xy,
		                 ((xy[0][0/*x*/] == xy[3][0/*x*/]) &&
		                  (xy[0][1/*y*/] == xy[3][1/*y*/])) ? 3 : 4,	//前半の内側の頂点と後半の内側の頂点が重なっているならば(=内側半径が0,又は,0に近い値だった場合にそうなり得る)、三角形ポリゴンとして描く。そうでなければ、四角形ポリゴンとして描く。この判断は必須ではなく、三角形ポリゴンを四角形ポリゴンとして描いても同じ結果になるが、描画処理の負荷を減らすために当関数にて判断する事にした。
		                   arg);
	}
}
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#if 0
//□EffGen_Circle()の使用例
#ifdef  PIECE
static void fnRenderPolygon(const int xy[/*n*/][2/*x,y*/], int n/*3or4*/, void* arg) {
	VERTEX v[]={{xy[0][0],xy[0][1]},{xy[1][0],xy[1][1]},{xy[2][0],xy[2][1]},{xy[3][0],xy[3][1]}};
	render_polygon(&render, v, n, 0);
}
int app_main(int argc, char* argv[]) {
	int i;
	for(;;) {
		schedule();
		surface_clear(&surface, 3);
		EffGen_Circle(
			DISP_X/2,		//x
			DISP_Y/2,		//y
			38,			//radiusInner
			40,			//radiusOuter
			0,			//angleOrg
			24,			//nDiv			ギザギザエフェクトと違って、単純な円は分割数を減らしてもあまり目立たないので、もっと分割数を減らしても構いません。
			fnRenderPolygon,	//fnRenderPolygon
			NULL);			//arg
	}
	return 0;
}
#endif//PIECE
#ifdef  WIN32
static void fnRenderPolygon(const int xy[/*n*/][2/*x,y*/], int n/*3or4*/, void* arg) { draw_polygon_fill(xy, n); }
int cpp_main(int argc, char* argv[]) {
	if(RRS_i_job(pRRS) != (RRS_n_job(pRRS) - 1)) { DIE(); }	//最後のジョブがUIジョブである事を確認する。
	if(!setjmp(env_exit)) {
		for(;;) {
			schedule();
			EffGen_Circle(
				DISP_X/2,		//x
				DISP_Y/2,		//y
				190,			//radiusInner
				200,			//radiusOuter
				0,			//angleOrg
				24,			//nDiv			ギザギザエフェクトと違って、単純な円は分割数を減らしてもあまり目立たないので、もっと分割数を減らしても構いません。
				fnRenderPolygon,	//fnRenderPolygon
				NULL);			//arg
		}
	}
	return 0;
}
#endif//WIN32
#endif
//-----------------------------------------------------------------------------
//斜め楕円エフェクトの図形を描画する。
//[in]
//	x,y			中心座標
//	radiusShort		短軸半径			 angleRot      で表される軸を、便宜上、短軸と呼ぶ事にします。	┬必ずしも(radiusShort≦radiusLong)でなくても構いません。(radiusShort＞radiusLong)でも問題有りません。
//	radiusLong		長軸半径			(angleRot+π/2)で表される軸を、便宜上、長軸と呼ぶ事にします。	┘
//	angleRot		回転角度
//	nDiv			分割数				(nDiv≧3)
//	fnRenderPolygon		アプリケーション定義のポリゴン描画関数		当関数からアプリケーション定義のポリゴン描画関数(fnRenderPolygon)を呼び出す場合は常に(n=3)となりますが、他の関数から呼び出さす場合の引数(n=3or4)と統一するために、当関数からも引数nを指定する事にしました。
//	arg			アプリケーション定義のポリゴン描画関数へ引き渡す任意のデータ
//[note]
//	- ラジルギ(https://en.wikipedia.org/wiki/Radirgy)の、ボスを破壊した時に、円弧ギザギザエフェクトが発生する前に、円が広がるフェクトと、塗りつぶした円が楕円に変化するフェクトが描画されているようなので、それに似た描画を行うために用意した関数です。
//	  関数名の'DiaOva'は、'DIAgonal OVAl effect'の略です。
//	- 当関数は、図形の描画のみを行う関数です。
//	  アニメーションを行うには、EffAnm_RadBo1()等を利用するか、又は、アプリケーション自身でパラメータを計算して当関数を呼び出して下さい。
void EffGen_DiaOva(int   x,			//┬中心座標
                   int   y,			//┘
                   int   radiusShort,		//短軸半径			 angleRot      で表される軸を、便宜上、短軸と呼ぶ事にします。	┬必ずしも(radiusShort≦radiusLong)でなくても構いません。(radiusShort＞radiusLong)でも問題有りません。
                   int   radiusLong,		//長軸半径			(angleRot+π/2)で表される軸を、便宜上、長軸と呼ぶ事にします。	┘
                   fixed angleRot,		//回転角度
                   int   nDiv,			//分割数			(nDiv≧3)
                   void (*fnRenderPolygon)(const int xy[/*n*/][2/*x,y*/], int n/*3*/, void* arg),	//アプリケーション定義のポリゴン描画関数	当関数からアプリケーション定義のポリゴン描画関数(fnRenderPolygon)を呼び出す場合は常に(n=3)となりますが、他の関数から呼び出さす場合の引数(n=3or4)と統一するために、当関数からも引数nを指定する事にしました。
                   void* arg) {										//アプリケーション定義のポリゴン描画関数へ引き渡す任意のデータ
	int iDiv, xy[3/*n*/][2/*x,y*/];	//他の関数では'xy[4][2]'だが、当関数では'xy[3][2]'で足りる。
	fixed cosValue, sinValue, cosShort, sinShort, cosLong, sinLong;
	if((radiusShort < 0) ||
	   (radiusLong < 0) ||
	   (nDiv < 3)) { DIE(); }
	//中心の頂点は変化しないので、予め格納しておく。
	xy[0][0/*x*/] = x;	//┬中心の頂点
	xy[0][1/*y*/] = y;	//┘
	//回転パラメータを求めておく。
	cosValue = fcos(angleRot);
	sinValue = fsin(angleRot);
	cosShort = fimul(cosValue, radiusShort);
	sinShort = fimul(sinValue, radiusShort);
	cosLong  = fimul(cosValue, radiusLong);
	sinLong  = fimul(sinValue, radiusLong);
	//各分割について…
	for(iDiv = 0;
	    iDiv < nDiv;
	    iDiv++) {
		fixed angle;
	    if(!iDiv) {
		angle = fidiv(fimul(PI2, iDiv + 0), nDiv);						//┐
		cosValue = fcos(angle);									//├前半の角度
		sinValue = fsin(angle);									//┘
		xy[1][0/*x*/] = x + fist(fsub(fmul(cosValue, cosShort), fmul(sinValue, sinLong)));	//┬前半の頂点
		xy[1][1/*y*/] = y + fist(fadd(fmul(cosValue, sinShort), fmul(sinValue, cosLong)));	//┘
	    } else {
		xy[1][0/*x*/] = xy[2][0/*x*/];								//┬前半の頂点
		xy[1][1/*y*/] = xy[2][1/*y*/];								//┘
	    }
		angle = fidiv(fimul(PI2, iDiv + 1), nDiv);						//┐
		cosValue = fcos(angle);									//├後半の角度
		sinValue = fsin(angle);									//┘
		xy[2][0/*x*/] = x + fist(fsub(fmul(cosValue, cosShort), fmul(sinValue, sinLong)));	//┬後半の頂点
		xy[2][1/*y*/] = y + fist(fadd(fmul(cosValue, sinShort), fmul(sinValue, cosLong)));	//┘
		(*fnRenderPolygon)(xy, 3, arg);								//当関数からアプリケーション定義のポリゴン描画関数(fnRenderPolygon)を呼び出す場合は常に(n=3)となりますが、他の関数から呼び出さす場合の引数(n=3or4)と統一するために、当関数からも引数nを指定する事にしました。
	}
}
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#if 0
//□EffGen_Circle()の使用例
#ifdef  PIECE
static void fnRenderPolygon(const int xy[/*n*/][2/*x,y*/], int n/*3or4*/, void* arg) {
	VERTEX v[]={{xy[0][0],xy[0][1]},{xy[1][0],xy[1][1]},{xy[2][0],xy[2][1]},{xy[3][0],xy[3][1]}};
	render_polygon(&render, v, n, 0);
}
int app_main(int argc, char* argv[]) {
	int i;
	for(;;) {
		schedule();
		surface_clear(&surface, 3);
		EffGen_DiaOva(
			DISP_X/2,		//x
			DISP_Y/2,		//y
			50,			//radiusShort
			300,			//radiusLong
			DEG(60),		//angleRot
			24,			//nDiv			ギザギザエフェクトと違って、単純な円は分割数を減らしてもあまり目立たないので、もっと分割数を減らしても構いません。
			fnRenderPolygon,	//fnRenderPolygon
			NULL);			//arg
	}
	return 0;
}
#endif//PIECE
#ifdef  WIN32
static void fnRenderPolygon(const int xy[/*n*/][2/*x,y*/], int n/*3or4*/, void* arg) { draw_polygon_fill(xy, n); }
int cpp_main(int argc, char* argv[]) {
	if(RRS_i_job(pRRS) != (RRS_n_job(pRRS) - 1)) { DIE(); }	//最後のジョブがUIジョブである事を確認する。
	if(!setjmp(env_exit)) {
		for(;;) {
			schedule();
			EffGen_DiaOva(
				DISP_X/2,		//x
				DISP_Y/2,		//y
				50,			//radiusShort
				300,			//radiusLong
				DEG(60),		//angleRot
				24,			//nDiv			ギザギザエフェクトと違って、単純な円は分割数を減らしてもあまり目立たないので、もっと分割数を減らしても構いません。
				fnRenderPolygon,	//fnRenderPolygon
				NULL);			//arg
		}
	}
	return 0;
}
#endif//WIN32
#endif
