/*
	Ninja Library
	
	COPYRIGHT ( C ) SEGA ENTERPRISES, LTD.
*/

#include "NuMotionMake.h"



/*
	_nu_shpinfo_ptr_->int_vlist_func_p			Vlist の補完コア関数のアドレス
*/

extern NUS_CUR_MOTIONLINK_INFO			_nu_shapelink_info_;



#if 0


static void	nuShapeLinkIntLinearVlist( const NUS_MKEY_P *S1VertexKey, Uint32 S1VertexNbKeys,
									   const NUS_MKEY_P *S1NormalKey, Uint32 S1NormalNbKeys,
									   Float S1Frame,
									   const NUS_MKEY_P *S2VertexKey, Uint32 S2VertexNbKeys,
									   const NUS_MKEY_P *S2NormalKey, Uint32 S2NormalNbKeys,
									   Float S2Frame,
									   Float rate,
									   const Sint32 *SrcVlist, Sint32 **pDstVlist );
/*
	補完基本関数群
*/

/*
	func:	現在の MDATA ポインタのキーに書かれているシェープデータにより補完したデータで VLISTを作成し、
			その VLIST へのポインタを返す。
			・指定された旧 VLIST に基づいて新 VLIST が作成される。
			・補完キーが実質上存在しない場合はどんな場合でも、返されるポインタは旧 VLIST へのポインタとなり、
			  余計なコピーなどは行わない。
			・補完キーが一部存在しない部分に付いては、旧VLISTのデータがそのままコピーされる。
			・新VLIST の中のチャンクの個数とチャンクタイプはすべて、旧VLIST のものと同じに成る。
			・NUS_MDATA(n) 配列への参照ポインタが指すキーフレーム配列が参照される。
			・cnkmodel->vlist	= NULL なら何もせずに、返すポインタを NULL にして戻る。
			・NUS_MDATA(n) 配列への参照ポインタは、呼び出し側で進めること。
			・通常、cnkobj->evalflags の判定を呼び出し側で行い、フラグがセットされている場合はこの関数を呼ばないこと。
	
	in:		cnkmodel	= この中の vlist メンバがデフォルト VLIST として参照される（NULLは使用不可）。
			pVlist		= 補完後の VLIST へのポインタを格納するフォルダ
			
	out:	*pVlist		= キーが１つでもある場合は補完して作成した VLIST へのポインタ。
			*pVlist		= キーが１つもない場合は、cnkmodel->vlist。
*/
void _nuGetShapeLinkVlist( const NJS_CNK_MODEL *cnkmodel, Sint32 **pVlist )
{
	//	for shape1
	NUS_MKEY_P		*S1VertexKey;
	NUS_MKEY_P		*S1NormalKey;
	Uint32			S1VertexNbKeys;
	Uint32			S1NormalNbKeys;
	Float			S1Frame;
	//	for shape2
	NUS_MKEY_P		*S2VertexKey;
	NUS_MKEY_P		*S2NormalKey;
	Uint32			S2VertexNbKeys;
	Uint32			S2NormalNbKeys;
	Float			S2Frame;
	
	if ( cnkmodel->vlist == NULL ) {
		//	VLIST が元々存在しない場合
		*pVlist	= NULL;
		return;
	}
	
	//	for shape2
	nuSetCurShapeInfoSlot( 1 );
	if ( _nu_shpinfo_ptr_->type & NUD_MTYPE_VERT_4 ) {
		//	頂点シェープキーのフォルダがある場合
		if ( ( S2VertexKey = (NUS_MKEY_P *)_nu_shpinfo_ptr_->key[_nu_shpinfo_ptr_->cnt] ) != NULL ) {
			//	実際にある場合
			S2VertexNbKeys	= _nu_shpinfo_ptr_->nbkeys[_nu_shpinfo_ptr_->cnt];
		}
		_nu_shpinfo_ptr_->cnt++;
	}
	else {
		S2VertexKey	= NULL;
	}
	if ( _nu_shpinfo_ptr_->type & NUD_MTYPE_NORM_5 ) {
		//	法線シェープキーのフォルダがある場合
		if ( ( S2NormalKey = (NUS_MKEY_P *)_nu_shpinfo_ptr_->key[_nu_shpinfo_ptr_->cnt] ) != NULL ) {
			//	実際にある場合
			S2NormalNbKeys	= _nu_shpinfo_ptr_->nbkeys[_nu_shpinfo_ptr_->cnt];
		}
		_nu_shpinfo_ptr_->cnt++;
	}
	else {
		S2NormalKey	= NULL;
	}
	S2Frame	= _nu_shpinfo_ptr_->frame;
	
	
	//	for shape1
	nuSetCurShapeInfoSlot( 0 );
	if ( _nu_shpinfo_ptr_->type & NUD_MTYPE_VERT_4 ) {
		//	頂点シェープキーのフォルダがある場合
		if ( ( S1VertexKey = (NUS_MKEY_P *)_nu_shpinfo_ptr_->key[_nu_shpinfo_ptr_->cnt] ) != NULL ) {
			//	実際にある場合
			S1VertexNbKeys	= _nu_shpinfo_ptr_->nbkeys[_nu_shpinfo_ptr_->cnt];
		}
		_nu_shpinfo_ptr_->cnt++;
	}
	else {
		S1VertexKey	= NULL;
	}
	if ( _nu_shpinfo_ptr_->type & NUD_MTYPE_NORM_5 ) {
		//	法線シェープキーのフォルダがある場合
		if ( ( S1NormalKey = (NUS_MKEY_P *)_nu_shpinfo_ptr_->key[_nu_shpinfo_ptr_->cnt] ) != NULL ) {
			//	実際にある場合
			S1NormalNbKeys	= _nu_shpinfo_ptr_->nbkeys[_nu_shpinfo_ptr_->cnt];
		}
		_nu_shpinfo_ptr_->cnt++;
	}
	else {
		S1NormalKey	= NULL;
	}
	S1Frame	= _nu_shpinfo_ptr_->frame;
	
	if ( S1VertexKey != NULL || S1NormalKey != NULL || S2VertexKey != NULL || S2NormalKey != NULL ) {
		//	補完キーが少なくとも一つは存在する場合
		nuShapeLinkIntLinearVlist( S1VertexKey, S1VertexNbKeys, S1NormalKey, S1NormalNbKeys, S1Frame,
								   S2VertexKey, S2VertexNbKeys, S2NormalKey, S2NormalNbKeys, S2Frame,
								   _nu_shapelink_info_.rate,
								   cnkmodel->vlist, pVlist );
	}
	else {
		//	補完キーが全く存在しない場合
		*pVlist		= cnkmodel->vlist;
	}
}

/*
	func:	指定された、頂点補完キー列と、法線補完キー列に基づいて補完データを作成し、新しく VLIST を作成する。
			・VLIST は、*SrcVlist に指定された旧 VLIST に基づいて作成される。
			・この関数は、シェープバッファからデータ領域を確保し、その領域に必ず VLIST を作成する。
			・新しく作成した VLIST の先頭アドレスを *pDstVlist に返す。
			・新VLIST の中のチャンクの個数とチャンクタイプはすべて、旧VLIST のものと同じに成る。
	
	in:		S1VertexKey		= シェープ1の頂点補完キー列
			S1VertexNbKeys	= シェープ1の頂点補完キー列のキーの個数（S1VertexKey != NULL のときのみ有効）
			S1NormalKey		= シェープ1の法線補完キー列
			S1NormalNbKeys	= シェープ1の法線補完キー列のキーの個数（S1NormalKey != NULL のときのみ有効）
			S1Frame			= シェープ1の補完フレーム番号
			S2VertexKey		= シェープ2の頂点補完キー列
			S2VertexNbKeys	= シェープ2の頂点補完キー列のキーの個数（S2VertexKey != NULL のときのみ有効）
			S2NormalKey		= シェープ2の法線補完キー列
			S2NormalNbKeys	= シェープ2の法線補完キー列のキーの個数（S2NormalKey != NULL のときのみ有効）
			S2Frame			= シェープ2の補完フレーム番号
			rate			= シェープ1とシェープ2の補完内分比
			SrcVlist		= 旧VLISTの先頭アドレス（NULL であってはならない）
			pDstVlist		= 新VLISTの先頭アドレスを格納するフォルダ
	
	out:	*pDstVlist		= 新VLISTの先頭アドレス
	
	note:	VertexKey != NULL の場合、VertexKey の１つのキーに存在する頂点の個数が、旧VLIST 中の頂点
			の個数以上でなければ成らない（基本的には一致すべき）。
			NormalKey != NULL の場合、NormalKey の一つのキーに存在する法線の個数は、旧VLIST 中の法線
			の個数以上でなければ成らない（基本的には一致すべき）。
*/
static void nuShapeLinkIntLinearVlist( const NUS_MKEY_P *S1VertexKey, Uint32 S1VertexNbKeys,
									   const NUS_MKEY_P *S1NormalKey, Uint32 S1NormalNbKeys,
									   Float S1Frame,
									   const NUS_MKEY_P *S2VertexKey, Uint32 S2VertexNbKeys,
									   const NUS_MKEY_P *S2NormalKey, Uint32 S2NormalNbKeys,
									   Float S2Frame,
									   Float rate,
									   const Sint32 *SrcVlist, Sint32 **pDstVlist )
{
	Uint32		*SrcChunkTop;
	Uint32		*DstPtr;
	Uint32		ChunkHead;
	Float		rate2;
	
	//	for Shape1
	Float		S1VertexCmp1;
	Float		S1VertexCmp2;
	NUS_MKEY_P	*S1VertexKey1;
	NUS_MKEY_P	*S1VertexKey2;
	Float		S1NormalCmp1;
	Float		S1NormalCmp2;
	NUS_MKEY_P	*S1NormalKey1;
	NUS_MKEY_P	*S1NormalKey2;
	Float		*S1pKey1Vertex;
	Float		*S1pKey1Normal;
	Float		*S1pKey2Vertex;
	Float		*S1pKey2Normal;
	
	//	for Shape2
	Float		S2VertexCmp1;
	Float		S2VertexCmp2;
	NUS_MKEY_P	*S2VertexKey1;
	NUS_MKEY_P	*S2VertexKey2;
	Float		S2NormalCmp1;
	Float		S2NormalCmp2;
	NUS_MKEY_P	*S2NormalKey1;
	NUS_MKEY_P	*S2NormalKey2;
	Float		*S2pKey1Vertex;
	Float		*S2pKey1Normal;
	Float		*S2pKey2Vertex;
	Float		*S2pKey2Normal;
	
	rate2	= 1.0f - rate;
	
	//	for Shape1
	if ( S1VertexKey != NULL ) {
		_nuGetMotionLinearKeys( (void*)S1VertexKey, sizeof(NUS_MKEY_P), S1VertexNbKeys, S1Frame,
							 	(void**)&S1VertexKey1, (void**)&S1VertexKey2, &S1VertexCmp1 );
		
		S1VertexCmp2	= 1.0f - S1VertexCmp1;
		
		S1pKey1Vertex	= (Float*)S1VertexKey1->key;
		S1pKey2Vertex	= (Float*)S1VertexKey2->key;
	}
	if ( S1NormalKey != NULL ) {
		_nuGetMotionLinearKeys( (void*)S1NormalKey, sizeof(NUS_MKEY_P), S1NormalNbKeys, S1Frame,
							 	(void**)&S1NormalKey1, (void**)&S1NormalKey2, &S1NormalCmp1 );
		
		S1NormalCmp2	= 1.0f - S1NormalCmp1;
		
		S1pKey1Normal	= (Float*)S1NormalKey1->key;
		S1pKey2Normal	= (Float*)S1NormalKey2->key;
	}
	
	//	for Shape2
	if ( S2VertexKey != NULL ) {
		_nuGetMotionLinearKeys( (void*)S2VertexKey, sizeof(NUS_MKEY_P), S2VertexNbKeys, S2Frame,
							 	(void**)&S2VertexKey1, (void**)&S2VertexKey2, &S2VertexCmp1 );
		
		S2VertexCmp2	= 1.0f - S2VertexCmp1;
		
		S2pKey1Vertex	= (Float*)S2VertexKey1->key;
		S2pKey2Vertex	= (Float*)S2VertexKey2->key;
	}
	if ( S2NormalKey != NULL ) {
		_nuGetMotionLinearKeys( (void*)S2NormalKey, sizeof(NUS_MKEY_P), S2NormalNbKeys, S2Frame,
							 	(void**)&S2NormalKey1, (void**)&S2NormalKey2, &S2NormalCmp1 );
		
		S2NormalCmp2	= 1.0f - S2NormalCmp1;
		
		S2pKey1Normal	= (Float*)S2NormalKey1->key;
		S2pKey2Normal	= (Float*)S2NormalKey2->key;
	}
	
	SrcChunkTop	= (Uint32 *)SrcVlist;
	DstPtr		= (Uint32 *)_nu_shape_buf_;			//とりあえず先頭を使う（暫定）
	*pDstVlist	= (Sint32 *)DstPtr;
	
	for ( ;; ) {
		ChunkHead	= SrcChunkTop[0] & 0xff;
		
		if ( ChunkHead == NJD_CE ) {
			*DstPtr++	= *SrcChunkTop++;
			break;
		}
		else {
			Uint32		*SrcPtr;
			Uint32		ToNextChunk;
			int			VertexNum;
			int			VertexCnt;
			int			ExistVertex;
			int			ExistNormal;
			int			ExistD8888;
			int			OtherDWORDs;
			
			ToNextChunk	= SrcChunkTop[0] >> 16;
			VertexNum	= SrcChunkTop[1] >> 16;
			
			SrcPtr		= SrcChunkTop;
			
			switch( ChunkHead ) {
			case	NJD_CV:
				ExistVertex		= 1;
				ExistNormal		= 0;
				ExistD8888		= 0;
				OtherDWORDs		= 0;
				break;
			case	NJD_CV_D8:
				ExistVertex		= 1;
				ExistNormal		= 0;
				ExistD8888		= 1;
				OtherDWORDs		= 0;
				break;
			case	NJD_CV_UF:
				ExistVertex		= 1;
				ExistNormal		= 0;
				ExistD8888		= 0;
				OtherDWORDs		= 1;
				break;
			case	NJD_CV_VN:
				ExistVertex		= 1;
				ExistNormal		= 1;
				ExistD8888		= 0;
				OtherDWORDs		= 0;
				break;
			case	NJD_CV_VN_D8:
				ExistVertex		= 1;
				ExistNormal		= 1;
				ExistD8888		= 1;
				OtherDWORDs		= 0;
				break;
			case	NJD_CV_VN_UF:
				ExistVertex		= 1;
				ExistNormal		= 1;
				ExistD8888		= 0;
				OtherDWORDs		= 1;
				break;
			case	NJD_CV_VN_NF:
				ExistVertex		= 1;
				ExistNormal		= 1;
				ExistD8888		= 0;
				OtherDWORDs		= 1;
				break;
			#if 0			//まだ存在しない
			case	NJD_CV_VN_NF_D8:
				ExistVertex		= 1;
				ExistNormal		= 1;
				ExistD8888		= 1;
				OtherDWORDs		= 1;
				break;
			#endif
			default:
				ExistVertex		= 0;
				ExistNormal		= 0;
				ExistD8888		= 0;
				OtherDWORDs		= 0;
				break;
			}
			
			//	チャンクヘッダをコピーする
			DstPtr[0]	= SrcPtr[0];
			DstPtr[1]	= SrcPtr[1];
			SrcPtr	+= 2;
			DstPtr	+= 2;
			
			for ( VertexCnt = 0; VertexCnt < VertexNum; VertexCnt++ ) {
				if ( ExistVertex ) {
					Float				x1;
					Float				y1;
					Float				z1;
					Float				x2;
					Float				y2;
					Float				z2;
					
					//	for shape1
					if ( S1VertexKey != NULL ) {
						//	頂点のシェープキーがある場合
						x1	= S1pKey1Vertex[0] * S1VertexCmp2 + S1pKey2Vertex[0] * S1VertexCmp1;
						y1	= S1pKey1Vertex[1] * S1VertexCmp2 + S1pKey2Vertex[1] * S1VertexCmp1;
						z1	= S1pKey1Vertex[2] * S1VertexCmp2 + S1pKey2Vertex[2] * S1VertexCmp1;
						
						S1pKey1Vertex		+= 3;
						S1pKey2Vertex		+= 3;
					}
					else {
						//	頂点のシェープキーがない場合は、SrcVlistのデータをそのままコピーする。
						x1	= ((Float*)SrcPtr)[0];
						y1	= ((Float*)SrcPtr)[1];
						z1	= ((Float*)SrcPtr)[2];
					}
					
					//	for shape2
					if ( S2VertexKey != NULL ) {
						//	頂点のシェープキーがある場合
						x2	= S2pKey1Vertex[0] * S2VertexCmp2 + S2pKey2Vertex[0] * S2VertexCmp1;
						y2	= S2pKey1Vertex[1] * S2VertexCmp2 + S2pKey2Vertex[1] * S2VertexCmp1;
						z2	= S2pKey1Vertex[2] * S2VertexCmp2 + S2pKey2Vertex[2] * S2VertexCmp1;
						
						S2pKey1Vertex		+= 3;
						S2pKey2Vertex		+= 3;
					}
					else {
						//	頂点のシェープキーがない場合は、SrcVlistのデータをそのままコピーする。
						x2	= ((Float*)SrcPtr)[0];
						y2	= ((Float*)SrcPtr)[1];
						z2	= ((Float*)SrcPtr)[2];
					}
					
					//	両者を合成
					((Float*)DstPtr)[0]	= x1 * rate2 + x2 * rate;
					((Float*)DstPtr)[1]	= y1 * rate2 + y2 * rate;
					((Float*)DstPtr)[2]	= z1 * rate2 + z2 * rate;
					
					DstPtr	+= 3;
					SrcPtr	+= 3;
				}
				if ( ExistNormal ) {
					Float				x1;
					Float				y1;
					Float				z1;
					Float				x2;
					Float				y2;
					Float				z2;
					
					//	for shape1
					if ( S1NormalKey != NULL ) {
						//	法線のシェープキーがある場合
						x1	= S1pKey1Normal[0] * S1NormalCmp2 + S1pKey2Normal[0] * S1NormalCmp1;
						y1	= S1pKey1Normal[1] * S1NormalCmp2 + S1pKey2Normal[1] * S1NormalCmp1;
						z1	= S1pKey1Normal[2] * S1NormalCmp2 + S1pKey2Normal[2] * S1NormalCmp1;
						
						S1pKey1Normal		+= 3;
						S1pKey2Normal		+= 3;
					}
					else {
						//	法線のシェープキーがない場合は、SrcVlistのデータをそのままコピーする。
						x1	= ((Float*)SrcPtr)[0];
						y1	= ((Float*)SrcPtr)[1];
						z1	= ((Float*)SrcPtr)[2];
					}
					
					//	for shape2
					if ( S2NormalKey != NULL ) {
						//	法線のシェープキーがある場合
						x2	= S2pKey1Normal[0] * S2NormalCmp2 + S2pKey2Normal[0] * S2NormalCmp1;
						y2	= S2pKey1Normal[1] * S2NormalCmp2 + S2pKey2Normal[1] * S2NormalCmp1;
						z2	= S2pKey1Normal[2] * S2NormalCmp2 + S2pKey2Normal[2] * S2NormalCmp1;
						
						S2pKey1Normal		+= 3;
						S2pKey2Normal		+= 3;
					}
					else {
						//	法線のシェープキーがない場合は、SrcVlistのデータをそのままコピーする。
						x2	= ((Float*)SrcPtr)[0];
						y2	= ((Float*)SrcPtr)[1];
						z2	= ((Float*)SrcPtr)[2];
					}
					
					//	両者を合成
					((Float*)DstPtr)[0]	= x1 * rate2 + x2 * rate;
					((Float*)DstPtr)[1]	= y1 * rate2 + y2 * rate;
					((Float*)DstPtr)[2]	= z1 * rate2 + z2 * rate;
					
					DstPtr	+= 3;
					SrcPtr	+= 3;
				}
				
				if ( ExistD8888 ) {
					*DstPtr++	= *SrcPtr++;
				}
				
				if ( OtherDWORDs != 0 ) {
					//	現在は有ったとしても 1 DWORD である。
					*DstPtr++	= *SrcPtr++;
				}
			}
			
			//	ミスが有っても伝播しないように CHUNK の長さでスキップする。
			SrcChunkTop		+= 1 + ToNextChunk;
		}
	}
}


#endif




void _nuSetShapeLinkVlistSub( Float *vlist, Float *vlist1, Float *vlist2, Float *lvlist1, Float *lvlist2, Sint32 flag, Float cmp1, Float lcmp1 );

#define	S_VERTEX		0x0001
#define	S_NORMAL		0x0002
#define	S_D8888			0x0004
#define	S_DWORD			0x0008
#define	S_VERTEX2		0x0010
#define	S_NORMAL2		0x0020
#define	S_D88882		0x0040

void nuSetShapeLinkVlist( Uint32 *vlist, Uint32 vtype )
{
	Sint32	bExist;
	Uint16	*vlist1,*vlist2;
	Uint16	*lvlist1,*lvlist2;
	Sint32	num;
	NUS_SHAPE_GROUP_COEFF *group;
	NUS_SHAPE_GROUP_COEFF *lgroup;

	nuSetCurShapeInfoSlot( 0 );
	group = &_nu_shape_buf_[_nu_shpinfo_ptr_->KeyGroupID];
	vlist1 = (Uint16*)(_nu_shape_list_->shapes[group->ShapeID1].cvlist[_nu_shpinfo_ptr_->group->entryId].cv);
	vlist2 = (Uint16*)(_nu_shape_list_->shapes[group->ShapeID2].cvlist[_nu_shpinfo_ptr_->group->entryId].cv);

	nuSetCurShapeInfoSlot( 1 );
	lgroup = &_nu_shape_link_buf_[_nu_shpinfo_ptr_->KeyGroupID];
	lvlist1 = (Uint16*)(_nu_shape_link_list_->shapes[lgroup->ShapeID1].cvlist[_nu_shpinfo_ptr_->group->entryId].cv);
	lvlist2 = (Uint16*)(_nu_shape_link_list_->shapes[lgroup->ShapeID2].cvlist[_nu_shpinfo_ptr_->group->entryId].cv);
	
	
	/* シェープリンクの場合、両方ともタイプが同じでなければならない */
	
	switch( vtype & 0x00ff ) {
	case	NJD_CV:
		bExist = S_VERTEX;
		break;
	case	NJD_CV_D8:
		bExist = S_VERTEX | S_D8888;
		break;
	case	NJD_CV_UF:
		bExist = S_VERTEX | S_DWORD;
		break;
	case	NJD_CV_VN:
		bExist = S_VERTEX | S_NORMAL;
		break;
	case	NJD_CV_VN_D8:
		bExist = S_VERTEX | S_NORMAL | S_D8888;
		break;
	case	NJD_CV_VN_UF:
		bExist = S_VERTEX | S_NORMAL | S_DWORD;
		break;
	case	NJD_CV_VN_NF:
		bExist = S_VERTEX | S_NORMAL | S_DWORD;
		break;
	default:
		return;
		break;
	}

	
	switch( (*vlist1++) & 0x00ff ) {
	case	NJD_CV:
		bExist |= S_VERTEX2;
		num = 3;
		break;
	case	NJD_CV_D8:
		bExist |= S_VERTEX2 | S_D88882;
		num = 4;
		break;
	case	NJD_CV_VN:
		bExist |= S_VERTEX2 | S_NORMAL2;
		num = 6;
		break;
	case	NJD_CV_VN_D8:
		bExist |= S_VERTEX2 | S_NORMAL2 | S_D88882;
		num = 7;
		break;
	case	NJD_D8:
		bExist |= S_D88882;
		num = 1;
		break;
	case	NJD_VN:
		bExist |= S_NORMAL2;
		num = 3;
		break;
	case	NJD_VN_D8:
		bExist |= S_NORMAL2 | S_D88882;
		num = 4;
		break;
	default:
		return;
		break;
	}
	

	//シェープチャンクには頂点数がないのでサイズから換算する

	num  = *vlist1++ / num;
	vlist2 += 2;

	lvlist1 += 2;
	lvlist2 += 2;
	
	_nuSetShapeLinkVlistSub( (Float *)vlist, (Float *)vlist1, (Float *)vlist2, (Float *)lvlist1, (Float *)lvlist2, num | (bExist<<16), group->rate, lgroup->rate );

}



void _nuSetShapeLinkVlistSub( Float *vlist, Float *vlist1, Float *vlist2, Float *lvlist1, Float *lvlist2, Sint32 flag, Float cmp1, Float lcmp1 )
{
	register	Sint32	num,bExist;
	register	Float	cmp2 = 1.0f - cmp1;
	register	Float	lcmp2 = 1.0f - lcmp1;
	register	Float	rate1 = _nu_shapelink_info_.rate;
	register	Float	rate2 = 1.0f - rate1;
	
	num = flag & 0x0000ffff;
	bExist = flag >> 16;
	
	do {
		if( bExist & S_VERTEX ) {
			if( bExist & S_VERTEX2 ) {
				*vlist     = (*vlist1++ * cmp2 + *vlist2++ * cmp1) * rate2 + (*lvlist1++ * lcmp2 + *lvlist2++ * lcmp1) * rate1;
				*(vlist+1) = (*vlist1++ * cmp2 + *vlist2++ * cmp1) * rate2 + (*lvlist1++ * lcmp2 + *lvlist2++ * lcmp1) * rate1;
				*(vlist+2) = (*vlist1++ * cmp2 + *vlist2++ * cmp1) * rate2 + (*lvlist1++ * lcmp2 + *lvlist2++ * lcmp1) * rate1;
			}
			vlist += 3;
		}
		if( bExist & S_NORMAL ) {
			if( bExist & S_NORMAL2 ) {
				*vlist     = (*vlist1++ * cmp2 + *vlist2++ * cmp1) * rate2 + (*lvlist1++ * lcmp2 + *lvlist2++ * lcmp1) * rate1;
				*(vlist+1) = (*vlist1++ * cmp2 + *vlist2++ * cmp1) * rate2 + (*lvlist1++ * lcmp2 + *lvlist2++ * lcmp1) * rate1;
				*(vlist+2) = (*vlist1++ * cmp2 + *vlist2++ * cmp1) * rate2 + (*lvlist1++ * lcmp2 + *lvlist2++ * lcmp1) * rate1;
			}
			vlist += 3;
		}
		if( bExist & S_D8888 ) {
			if( bExist & S_D88882 ) {
				Uint8	*p,*p1,*p2;
				Uint8	*lp1,*lp2;

				p  = (Uint8*)vlist;
				p1 = (Uint8*)vlist1;
				p2 = (Uint8*)vlist2;
				lp1 = (Uint8*)lvlist1;
				lp2 = (Uint8*)lvlist2;

				*p     = (Uint8)( ((Float)*p1       * cmp2 + (Float)*p2       * cmp1) * rate2 + ((Float)*lp1       * lcmp2 + (Float)*lp2       * lcmp1) * rate1 );
				*(p+1) = (Uint8)( ((Float)(*p1+1))  * cmp2 + (Float)(*(p2+1)) * cmp1) * rate2 + ((Float)(*(lp1+1)) * lcmp2 + (Float)(*(lp2+1)  * lcmp1) * rate1 );
				*(p+2) = (Uint8)( ((Float)(*p1+2))  * cmp2 + (Float)(*(p2+2)) * cmp1) * rate2 + ((Float)(*(lp1+2)) * lcmp2 + (Float)(*(lp2+2)  * lcmp1) * rate1 );
				*(p+3) = (Uint8)( ((Float)(*p1+3))  * cmp2 + (Float)(*(p2+3)) * cmp1) * rate2 + ((Float)(*(lp1+3)) * lcmp2 + (Float)(*(lp2+3)  * lcmp1) * rate1 );

				vlist1 ++;
				vlist2 ++;
				lvlist1 ++;
				lvlist2 ++;
			}
			vlist ++;
		}
		if( bExist & S_DWORD ) {
			vlist ++;
		}
	} while( --num );

}


